cakePHPemailバリデーションの不具合

December 2, 2009,
tags: cakephp php validation


このエントリーをはてなブックマークに追加

久しぶりにcakePHPネタです。
今回はcakePHP1.2.3.8166を使っているときのお話です。

メールアドレスの妥当性検証でなぜかi.softbank.jpのドメインを入力すると入力エラーになってしまいました。
他のドメインでもおkだったりダメだったり文字列で見る限り統一性がなくエラーを返していました。

とりあえず、ソースコードを呼んでみる。
cake/libs/validation.php

function email($check, $deep = false, $regex = null) {
		$_this =& Validation::getInstance();
		$_this->__reset();
		$_this->check = $check;
		$_this->regex = $regex;
		$_this->deep = $deep;

		if (is_array($check)) {
			$_this->_extract($check);
		}

		if (is_null($_this->regex)) {
			$_this->regex = '/^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@' . $_this->__pattern['hostname'] . '$/i';
		}
		$return = $_this->_check();

		if ($_this->deep === false || $_this->deep === null) {
			return $return;
		}

		if ($return === true && preg_match('/@(' . $_this->__pattern['hostname'] . ')$/i', $_this->check, $regs)) {
			$host = gethostbynamel($regs[1]);
			return is_array($host);
		}
		return false;
	}

どうやらcakePHPのemailチェックは次のような順番で行われていました。

  1. 1番目の引数($check)が配列の場合は配列を分解(どうやら、要素名がcheck、regex、country、deep、typeの値しか取れない。)$_thisのインスタンス変数として値がセットされる。

    • 正規表現を用いて妥当性の検証をする、3番目の引数($regex)に正規表現パターンを指定すれば、そのパターンで正規表現が行われる
      デフォルトの正規表現は以下のとおり /^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9][-a-z0-9]*\.)*(?:[a-z0-9][-a-z0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,4}|museum|travel)$/i

    • 2番目の引数($deep)がfalseもしくはnullの場合はそこで終了

    • 2番目の引数($deep)がtrueの場合は、正規表現でドメイン名だけを切り出して、gethostbynamel関数でドメインが存在するかチェックする。正規表現のパターンは以下のとおり ```

    って感じだと思います。
    間違っていたら指摘してください。

    で今回のvalidationの設定には以下のように書いてあったわけです。

    <?php
    class Hogemail extends AppModel{
    public $useTable = false;
    public $validate = array(
        'address' => array(
            'rule' => array('email',true),
            'message' => 'メールアドレスをご入力ください。',
        ),
    );
    }
    ?>
    

    最初はcakePHPの正規表現が間違っているんじゃないかと思い、いろいろと検証してみましたが、正規表現は間違っていない。
    よーくみると2番目の引数が有効なとき「gethostbynamel($regs[1]);」とかやってる!!なんだこの関数・・・初めてみた(;´Д`)

    さっそく大好きなPHPマニュアルで無駄にコナミコマンド打ってから調べてみると、「gethostbynamel — 指定したインターネットホスト名に対応するIPv4アドレスのリストを取得する 」と書いてある。
    実際この関数がどういう動きするかよくわからないのですが、とりあえずdigか何かと同じような感じで名前解決できたらtrueでも返すのではないでしょうか?詳しい人いたら教えてください・・・
    たぶんこの関数のせいで、i.softbank.jpとか一部のドメインがエラーになるのかなぁとおもいます。

    とりあえず、ためしにdig i.softbank.jpってみる

    ``` ; (1 server found) ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7423 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION: ;i.softbank.jp. IN A

;; AUTHORITY SECTION: softbank.jp. 7161 IN SOA dns03.bbtec.net. noc.bbtec.net. 2009111101 10800 3600 604800 86400

;; Query time: 1 msec ;; WHEN: Wed Dec 2 01:03:46 2009 ;; MSG SIZE rcvd: 86

    
    ANSWERは帰ってこない。AUTHORITY: 1は帰ってくる。  
    dig i.softbank.jp MXってやれば普通にかえってくるんですが・・・。
    
    予想として、digでANSWERが帰ってこないからi.softbank.jpとかエラーになるんではないのでしょうか?  
    どうなんだろう。。
    
    よくわからないけど、ちゃんとした原因等がわからない今のところはドメイン名のチェックははずしておこうと思います。
    
    ```
<?php
class Hogemail extends AppModel{
    public $useTable = false;
    public $validate = array(
        'address' => array(
            'rule' => array('email'),
            'message' => 'メールアドレスをご入力ください。',
        ),
    );
}
?>
このようにしておけば、メールアドレスは文字列のチェックのみとなります。
comments powered by Disqus