プロジェクト

全般

プロフィール

Bug(バグ) #3931

Youichi Kimura約7年前に更新

h3. Overview (現象)

Zend_Validate_Hostname を使用する機能で .com, .biz, .cn ドメインのホスト名または URL がエラーになる。
この不具合は OpenPNE *3.4.x* および *3.6.x* のみで発生する。

具体的には、下記の機能で問題が発生する。

* OpenPNE.yml の @mail_smtp_host@
** 例: @smtp.gmail.com@ を使用したメール送信が行えない<pre><code class="yaml">
mail_smtp_host: "smtp.gmail.com"
mail_smtp_config:
auth: "login"
username: "*****@gmail.com"
password: "*****"
ssl: "tls"
port: 587
</code></pre>
** 発生するエラーの例: {{collapse(詳細を表示...)
<pre>
$ ./symfony openpne:send-daily-news --app=pc_frontend --trace


[Zend_Validate_Exception]
Internal error: DNS validation failed


Exception trace:
at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Validate/Hostname.php:365
Zend_Validate_Hostname->isValid at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Validate.php:94
Zend_Validate->isValid at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Mail/Protocol/Abstract.php:133
Zend_Mail_Protocol_Abstract->__construct at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Mail/Protocol/Smtp.php:156
Zend_Mail_Protocol_Smtp->__construct at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Mail/Protocol/Smtp/Auth/Login.php:76
Zend_Mail_Protocol_Smtp_Auth_Login->__construct at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Mail/Transport/Smtp.php:196
Zend_Mail_Transport_Smtp->_sendMail at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Mail/Transport/Abstract.php:348
Zend_Mail_Transport_Abstract->send at /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Mail.php:936
Zend_Mail->send at /home/upsilon/git/openpne3/v3.6/lib/util/opMailSend.class.php:218
opMailSend::execute at /home/upsilon/git/openpne3/v3.6/lib/util/opMailSend.class.php:156
opMailSend::sendTemplateMail at /home/upsilon/git/openpne3/v3.6/lib/task/openpneSendDailyNewsTask.class.php:112
openpneSendDailyNewsTask->sendDailyNews at /home/upsilon/git/openpne3/v3.6/lib/task/openpneSendDailyNewsTask.class.php:43
openpneSendDailyNewsTask->execute at /home/upsilon/git/openpne3/v3.6/lib/vendor/symfony/lib/task/sfBaseTask.class.php:68
sfBaseTask->doRun at /home/upsilon/git/openpne3/v3.6/lib/vendor/symfony/lib/task/sfTask.class.php:97
sfTask->runFromCLI at /home/upsilon/git/openpne3/v3.6/lib/vendor/symfony/lib/command/sfSymfonyCommandApplication.class.php:76
sfSymfonyCommandApplication->run at /home/upsilon/git/openpne3/v3.6/lib/vendor/symfony/lib/command/cli.php:20
include at /home/upsilon/git/openpne3/v3.6/symfony:14
</pre>
}}
* opOpenSocialPlugin のアプリ追加
** 例: 管理画面の「アプリ追加」(/pc_backend_dev.php/opOpenSocialPlugin/add) で @Gadget XML URL@ に @gist.github.com@ などのドメインの URL を指定するとエラーになる

h3. Causes (原因)

#205 で起きた問題の修正のために、@Zend_Validate_Hostname@ に対して master ブランチと安定版ブランチで異なる修正が行われた。 @3.7.0@ 以降とそれ以前で異なる修正が行われた。
この修正により OpenPNE 3.6.x には commit:fbdbb216 の修正が行われたが、「最新の安定版で配布されている Zend/Validate/Hostname/*.php とほぼ近い挙動になるようなクラスファイル」が正しく機能しなかったため今回の不具合が起きた。


#205-6 より引用:
> 次の方針で実装します。
>
> * OpenPNE 3.7.0 : 同梱する ZendFramework の最新の安定版にアップデートします
> * OpenPNE 3.6 以前 : ZendFramework の最新の安定版に存在する Zend/Validate/Hostname/*.php に対応するファイルが同梱している ZendFramework に存在していなければ、最新の安定版で配布されている Zend/Validate/Hostname/*.php とほぼ近い挙動になるようなクラスファイルを追加するという暫定的な対処をおこないます

この修正により OpenPNE 3.6.x には commit:fbdbb216 の修正が行われたが、「最新の安定版で配布されている Zend/Validate/Hostname/*.php とほぼ近い挙動になるようなクラスファイル」が正しく機能しなかったため今回の不具合が起きた。


h4. *.biz, *.cn ドメインの場合に発生するエラー

<pre>
PHP Warning: preg_match(): Compilation failed: regular expression is too large at offset 156194 in /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Validate/Hostname.php on line 358
</pre>

source:lib/vendor/Zend/Validate/Hostname/Biz.php@fbdbb216 のパターンは 207,460 文字、 source:lib/vendor/Zend/Validate/Hostname/Cn.php@fbdbb216 のパターンは 156,176 文字と非常に巨大な正規表現パターンとなっており、このことがエラーの原因であると考えられる。

3.7.0 以降に対して修正された source:lib/vendor/Zend/Validate/Hostname/Biz.php@821abff4 は複数に分割された正規表現パターンを使用してドメイン名をチェックしているため今回のような問題は発生していない。

h4. *.com ドメインの場合に発生するエラー

<pre>
PHP Warning: preg_match(): Compilation failed: disallowed Unicode code point (>= 0xd800 && <= 0xdfff) at offset 9800 in /home/upsilon/git/openpne3/v3.6/lib/vendor/Zend/Validate/Hostname.php on line 358
</pre>

source:lib/vendor/Zend/Validate/Hostname/Com.php@fbdbb216 の正規表現パターンには @\x{D800}-\x{DB7F}\x{DC00}-\x{DFFF}@ が含まれており、この部分がサロゲートペアで使用する領域に該当するため上記のエラーが発生したと考えられる。
実際にこの部分を除去すると *.com ドメインのホスト名でエラーになる現象は起きなくなった。
(サロゲートペアを含むドメインは @Zend_Validate_Hostname::isValid()@ で false になるが、これは #205 の対応前および OpenPNE 3.7.0 以降の動作と同じである)

コードポイント U+D800 から U+DFFF までの範囲は UTF-16 でサロゲートペアの high surrogates および low surrogates のために確保された領域であり、これらの領域では high surrogates と low surrogates の 2 つの符号で 1 文字として扱うためいずれか単体が正規表現パターンにマッチすることはない。
例えば、*.com ドメインでの使用が認められている "リュキア文字":http://www.unicode.org/charts/PDF/U10280.pdf はサロゲートペアで表される領域の文字であり、「&#x10280;」(@LYCIAN LETTER A@) であれば UTF-16 では 0xD800 0xDE80 の組で 1 文字として扱われるが @/[\x{D800}-\x{DFFF}]/u@ のような正規表現パターンを用いてもどちらの符号にもマッチしない(サロゲートペアは U+10000 以降のコードポイントで表され、@LYCIAN LETTER A@ の場合は U+10280 であるため @/\x{10280}/u@ であればマッチする)

<pre>
$ cat hoge.php
<?php
$str = mb_convert_encoding(pack('H*', 'D800DE80'), 'UTF-8', 'UTF-16BE');

var_dump(preg_match('/[\x{D800}-\x{DFFF}]/u', $str));
var_dump(preg_match('/\x{10280}/u', $str));

$ php hoge.php
PHP Warning: preg_match(): Compilation failed: disallowed Unicode code point (>= 0xd800 && <= 0xdfff) at offset 7 in /home/upsilon/git/openpne3/master/hoge.php on line 4

Warning: preg_match(): Compilation failed: disallowed Unicode code point (>= 0xd800 && <= 0xdfff) at offset 7 in /home/upsilon/git/openpne3/master/hoge.php on line 4
bool(false)
int(1)
</pre>

h3. Way to fix (修正内容)

修正内容を記入

戻る