2006-12-26
くもり

RFC2822 に沿ったアドレス抽出

yuriko による 20:24:11 の投稿
カテゴリー: WordPressハック
タグ: ,

wp-mta ベータ版 0.20 では、メールアドレスの抽出が完全に RFC2822 に準拠してないバグがありましたが、かっこの入れ子を正しく判別するよう修正してみました。かっこの前後が atom の区切りであるかの判別はサボっていますので、「hoge(comment)hoge@example.jp」というメールアドレスを不正とは判定できず「hogehoge@example.jp」と抽出していまいます。

修正したメールアドレス抽出関数は以下の通りです。wp-mta 自体の配布はしばらくお待ちください。

// Substitue mail address along RFC2822
function pickup_address($addr, $include_bad = FALSE) {
  $valid   = array();
  $bad     = array();
  $quoted  = array();
  // ----- save quoted text -----
  while (preg_match('/(^|[^\\\\\\\\])("([^\\\\\\\\"]|\\\\\\\\.)*")/', $addr, $matches)) {
    $addr = preg_replace('/' . preg_quote($matches[1] . $matches[2]) . '/', 
      $matches[1] . "\\376\\376\\376" . count($quoted) . "\\376\\376\\376", 
      $addr, 1, $count);
    if ($count < 1) {
      break; // avoid infinite loop
    }
    $quoted[] = $matches[2];
  }
  // ---- remove comments -----
  $count = 1;
  while ($count) {
    $addr = preg_replace('/\\(([^\\\\\\\\()]|\\\\\\\\.)*\\)/', '', $addr, -1, $count);
  }
  // ----- remove group name -----
  $addr = preg_replace('/[-\\w ]+:([^;]*);/', '$1', $addr);
  // ----- split into each address -----
  foreach (explode(',', $addr) as $a) {
    $a = str_replace(' ', '', $a);
    if (preg_match('/<([^>]*)>/', $a, $matches)) {
      $a = $matches[1];
    }
    // ----- got address -----
    if (empty($a)) {
      continue;
    }
    // ----- restore quoted text -----
    if (preg_match('/(^|[^\\\\\\\\])[()]/', $a)) {
      $bad[] = preg_replace('/\\376\\376\\376(\\d+)\\376\\376\\376/e', '$quoted[$1]', $a);
    } else {
      $valid[] = preg_replace('/\\376\\376\\376(\\d+)\\376\\376\\376/e', '$quoted[$1]', $a);
    }
  }
  if ($include_bad) {
    return array($valid, $bad);
  } else {
    return $valid;
  }
}

ちなみに、コメントの処理が不正なことに目をつぶれば正規表現による処理も可能です。リンク先は Perl によるコードとなっていますが、PHP に移植してみると以下のようになります。

function pickup_addr_regex($addr) {
  // Refer to http://www.din.or.jp/~ohzaki/perl.htm#Mail
  $mail_regex = '(?:[^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff]+(?![^(\\040)<>@,;:".\\\\\\\\}\\[\\]\\000-\\037\\x80-\\xff])|"[^\\\\\\\\\\x80-\\xff\\n\\015"]*(?:\\\\\\\\[^\\x80-\\xff][^\\\\\\\\\\x80-\\xff\\n\\015"]*)*")(?:\\.(?:[^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff]+(?![^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff])|"[^\\\\\\\\\\x80-\\xff\\n\\015"]*(?:\\\\\\\\[^\\x80-\\xff][^\\\\\\\\\\x80-\\xff\\n\\015"]*)*"))*@(?:[^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff]+(?![^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff])|\\[(?:[^\\\\\\\\\\x80-\\xff\\n\\015\\[\\]]|\\\\\\\\[^\\x80-\\xff])*\\])(?:\\.(?:[^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff]+(?![^(\\040)<>@,;:".\\\\\\\\\\[\\]\\000-\\037\\x80-\\xff])|\\[(?:[^\\\\\\\\\\x80-\\xff\\n\\015\\[\\]]|\\\\\\\\[^\\x80-\\xff])*\\]))*';
  if (preg_match_all("/$mail_regex/", $addr, $matches)) {
    return $matches[0];
  } else {
    return array();
  }
}

コメント・ピン通知 »

トラックバック・コメントはありません。
※スパム対策プラグインの影響により、すぐにトラックバックが反映されない場合があります。お手数ですが、半日ほど待ってみてください。

上に戻る

コメント投稿

※発言の責任を明確にするため「名無し」「通りすがり」「匿名希望」等の匿名は不可とします。捨てハンドルでもいいので必ず名乗ってください。
XHTML (使えるタグ): <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <img localsrc="" alt=""> .
※スパム対策プラグインの影響により、すぐにコメント内容が表示されない場合があります。お手数ですが、半日ほど待ってみてください。

上に戻る