プロジェクト

全般

プロフィール

Bug(バグ) #4035

メールアドレスの登録がなく,同時にregister_tokenの登録が無いメンバーがmember_configテーブルに存在するとopAuthMailAddressPluginによる新規登録がおこなえない

Yuya Kanai7年以上前に追加.

ステータス:
New(新規)
優先度:
Normal(通常)
担当者:
-
対象バージョン:
開始日:
2016-10-23
期日:
進捗率:

0%

3.6 で発生するか:
Unknown (未調査)
3.8 で発生するか:
Yes (はい)

説明

Overview (現象)

OpenPNE 3.8.21 において,「member_config」テーブル上に,下記条件を同時に満たすメンバーが存在すると,招待メールのURLをクリックしても,500エラーとなり,メンバー登録を完了できない。

【条件】*1
・member_configテーブル上にname=pc_addressのレコードが空である(メールアドレスが登録されていない)
・member_configテーブル上にname=register_tokenのレコードを持たない(opAuthMailAddressPluginによる仮登録状態ではない)

*1) opAuthSocialPlugin使用時等,メールアドレスの登録が必須でない場合に,このようなメンバーが作成されます。
  そのため,opAuthSocialPluginとopAuthMailAddressPluginを同時に有効にすると,opAuthSocialPluginは正常に機能しますが,opAuthMailAddressPluginは新規登録できない状態になります。

Causes (原因)

以下,エラー発生箇所のコード追跡。

file: lib/action/opMemberAction.class.php
line: 174
method: opMemberAction::executeRegisterInput(opWebRequest $request)
$member = $this->getUser()->setRegisterToken($this->token);

file: lib/user/opSecurityUser.class.php
line: 431
method: opSecurityUser::setRegisterToken($token)
$member = Doctrine::getTable('Member')->findByValidRegisterToken($token, $mailTypes);

file: lib/model/doctrine/MemberTable.class.php
line: 156
method: MemberTable::findByValidRegisterToken($token, $configNames)

  public function findByValidRegisterToken($token, $configNames)
  {
    $member = $this->findByRegisterToken($token);
    if (!$member)
    {
      return false;
    }
    $configTable = Doctrine::getTable('MemberConfig');

    $query = $configTable->createQuery('m');
    foreach ($configNames as $configName)
    {
      $hash = $configTable->generateNameValueHash($configName, $member->getConfig($configName));
      $query->orWhere('m.name_value_hash = ?', $hash);
    }
    $configs = $query->fetchArray();

    $memberIds = array();
    $updateTimes = array();
    foreach ($configs as $config)
    {
      $memberIds[] = $memberId = $config['member_id'];
      $updateTimes[] = $configTable
        ->createQuery('m')
        ->where('m.member_id = ?', $memberId)
        ->AndWhere('m.name = "register_token"')
        ->fetchOne()
        ->getUpdatedAt();
    }
    array_multisort($updateTimes, $memberIds);

    if ($member->getId() !== $memberIds[count($memberIds)-1])
    {
      return false;
    }

    return $member;
  }

エラー発生箇所

file: lib/model/doctorine/MemberTable.class.php
line: 182
method: MemberTable::findByValidRegisterToken($token, $configNames)
$updateTimes[] = $configTable->createQuery('m')->where('m.member_id = ?', $memberId)->AndWhere('m.name = "register_token"')->fetchOne()->getUpdatedAt();

エラー発生理由

'm.name = "register_token"'の条件に合致するレコードが存在しないため,fetchOne()にて500エラーとなる。

Way to fix (修正内容) [DRAFT] 【案】

【注】当方,PHP,SQLおよびsymfonyに疎いため,Doctrineにおけるレコード存在の確認の方法が分からず,とりあえずこれで動いたという方法を記しています。
   そのため,本来のこの関数の在り方に沿った修正であるか不明です。関数の在り方や呼び出し方等含め,再確認いただければと思います。
   (なお,現行のコードでは169行目で$query->orWhereで繋いでいるためにname=pc_addressが空欄のレコードは無条件に含まれることとなっています。)

下記部分を以下のように修正
file: lib/model/doctorine/MemberTable.class.php
line: 175-184
method: MemberTable::findByValidRegisterToken($token, $configNames)

    foreach ($configs as $config)
    {
      $memberIds[] = $memberId = $config['member_id'];
      $m_rt = $configTable
        ->createQuery('m')
        ->where('m.member_id = ?', $memberId)
        ->AndWhere('m.name = "register_token"')->fetchArray();
      if ($m_rt){
        $updateTimes[] = $configTable
          ->createQuery('m')
          ->where('m.member_id = ?', $memberId)
          ->AndWhere('m.name = "register_token"')
          ->fetchOne()
          ->getUpdatedAt();
      } else {
        array_pop($memberIds);
      }
    }

関連するチケット

https://redmine.openpne.jp/issues/2588

他の形式にエクスポート: Atom PDF