2

ちょっとしたパズルがありますが、ないかもしれません。この作品をチェックしてください:

$query = ' SELECT account.account_no,
       account.accountname,
       accountbillads.bill_city,
       account.website,
       account.phone,
       CASE
         WHEN ( users.user_name NOT LIKE "" ) THEN users.user_name
         ELSE groups.groupname
       END AS user_name,
       entity.crmid,
       account.accountid,
       account.parentid,
       partner.partnerid      
FROM   account
       INNER JOIN entity
               ON entity.crmid = account.accountid
       INNER JOIN currency_info AS CurrencyInfoTable
               ON CurrencyInfoTable.id =
                  entity.record_currency_id
WHERE  entity.deleted = 0   ';

$query = ltrim($query);

preg_match("/^select ((.|\n)*?)\bfrom\b((.|\n)*?)\bselect\b/i", $query, $matches);

print('finito');
print_r($matches);

私のサーバーでは、これはクラッシュし、どこにもエラーはありません。

驚くべきことに、トリッキーな行は $query = ltrim($query); です。 この行がなければ、すべて正常に動作します。

これにはさらにいくつかのことがあります: 正規表現の機密部分は、'select' の最後の貪欲でない検索です。2 番目の選択が見つからない場合は、クラッシュします。クエリの長​​さが重要です。また、同じマシンで phpunits を実行すると、この問題は発生しないことに注意してください。

私の収集は、ltrimが文字列に対して何かを行うということですが、私にはわかりません。

誰かがこれを説明できますか?

編集。よし、ltrim は問題ないようだ。最初の空白なしで文字列を指定すると、クラッシュします。pcre.backtrack_limit と pcre.recursion_limit の設定が関係しているのかもしれませんが、試してみましたが変わりませんでした。

編集2。クラッシュはブラウザで「接続が中断されました」です。完全なサーバー クラッシュは発生しませんが、スクリプトの実行は停止します。繰り返しますが、ログにエラーはありません。

問題が解決しました。最後に (.|\n) を /s に置き換える必要がありました。どうもありがとう!

4

2 に答える 2

2

PHP 正規表現テスターでこれをテストしても問題は発生しませんが、式の作成方法が原因でクラッシュする可能性があると思います。次の構成を検討してください。

(.|\n)*?

潜在的な問題は、|と組み合わされた演算子*です。これは、一致しない場合に可能性の巨大なツリーを作成する可能性があります。

                    first character matches .
                               |
                          yes------no
                           |        |
         2nd character matches .    first character matches \n
                 |                                 |
            yes-----no                       yes--------no
             |       |                        |          |
      3rd char .    2nd char \n     2nd char matches .  2nd char matches .

正規表現エンジンは 2^n の可能性をチェックする必要があります。n は文字列に残っている文字数です。

/s解決策は、コメントで提案されているように、スイッチを使用することです。.次に、改行を含むすべてのものと一致させるために単純に使用できます。2^n の可能性の代わりに、n の可能性のみをチェックする必要があります。

注: 一部の正規表現エンジンは、この落とし穴を回避するのに十分なほどスマートです。理論的には、2 番目の「選択」が存在しない場合、エンジンはそれが決して一致しないことを認識できるほどスマートである必要があり、したがってあきらめます。たとえばPerlでテストすると、問題はありません。そして、上記の PHP 正規表現テスターに​​は問題はありません。しかし、使用している PHP のバージョンが古く、最適化されていない可能性があります。

于 2012-12-13T09:25:20.777 に答える
0

本当にクラッシュする場合は、少なくともいくつかのメッセージが表示されます。出力がまったく表示されないと思います。これは、正規表現が機能しないためです。

\bselect\b正規表現の末尾を削除するか、に追加することで修正できselectます$query。次に、いくつかの一致を出力します。

于 2012-12-13T09:08:12.653 に答える