久しぶりにハマってしまいましたorz

調べても情報が少なくて少なくて。

「どうがんばっても動かない」なんてタイトルを付けましたが、最終的には動くようになったんだけど(๑´ڡ`๑)

ハマった時は一旦別なことをリフレッシュするのがいいね♪

半日はかかったかな、翌日に持ち越さなかったのは救い。

もしかしたら同じように困る人がいるかも知れない、と思いましたのでメモしておきます。

症状

トップページのみ、preg_match_all が動かない。

動かないというか、結果が表示されません。

特にエラーコードなどは出てないです。

1つのコードで全ページに適用されるものなのに、トップページだけ表示されない・・・。

という状態でした。

▼該当コード

preg_match_all('/<img [^>]*?src=(.+?).*?>/iu', $content, $imgs);

$content の中からimgタグを全て抽出してクラスを付与をさせるための preg_match_all です。

実はこのコードの中に問題があったんだけど、この時点で気付いたかな?

preg_match_all を preg_match に変えてもNG。

str_replace は問題なく動きました。

サーバー側の問題ではないのか?

調べると、そもそもサーバー側で preg_match を制御されることもあるらしい。

この記事によると、「pcre.backtrack_limit」というものでメモリに制限がかかっていたとあります。

なんだ、サーバーの問題だったのか、とわたしも pcre.backtrack_limit の値を上げてみたものの変化なし。

書き方や設置場所が悪いのかなと試行錯誤しましたが、よくよく考えるとトップページ以外では問題なく動作しているわけで。

なぜだ・・・、なぜトップページだけなんだ・・・。

preg_last_error() でエラーチェック

上述した記事でも試されていた方法です。

以下丸々使わせていただきました。

感謝。

if (preg_last_error() == PREG_NO_ERROR) {
    print 'There is no error.';
}
else if (preg_last_error() == PREG_INTERNAL_ERROR) {
    print 'There is an internal error!';
}
else if (preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR) {
    print 'Backtrack limit was exhausted!';
}
else if (preg_last_error() == PREG_RECURSION_LIMIT_ERROR) {
    print 'Recursion limit was exhausted!';
}
else if (preg_last_error() == PREG_BAD_UTF8_ERROR) {
    print 'Bad UTF8 error!';
}
else if (preg_last_error() == PREG_BAD_UTF8_ERROR) {
    print 'Bad UTF8 offset error!';
}

結果はというと・・・。

Bad UTF8 error!

えっ!文字コード!?

原因は修飾子だった

そうです、原因は文字コードで、preg_match_all の中で使用していた修飾子です。

修飾子とは、正規表現のデミリタの後に付ける、

  • i
  • u
  • s
  • m

とかです。

他にもいろいろあるので「正規表現 修飾子」などで検索してみてください。

で、上のコードに戻ります。

preg_match_all('/<img [^>]*?src=(.+?).*?>/iu', $content, $imgs);

ここで使われている修飾子の「u」は UTF-8 の「u」だったのです。

今までおまじないのように修飾子を付けていましたが、そのツケがここで回ってきたようです(*´ω`*)

なんで「u」を付けていたのか

う~ん、なんでだろ、PHPコードって毎回手打ちしないよね?

ある程度は過去に書いたコードを元に書き直したりするのが多いんだけど、それでかな。

修飾子は他にも「i」や「s」など、とりあえず付けてることも多かったり(汗

正規表現の文字コードについては、特に指定が無ければソース中の文字コードが適応されるらしい。

ってことは「u」を付けることの方がイレギュラーってことになるのか( ..)φ

トップページだけ動かなかったのは、トップページ文字コードがおかしなことになっていたんだろうね。

あとがき

preg_last_error() でエラーチェックをした時、最初は「There is no error.」でエラーは出ませんでした。

何でかというと、preg_last_error() を書く位置が悪かったので(>_<)

該当の preg_match_all の下に書かなければならないのに、上の方に書いてた。

あ、今更だけど、preg_last_error() は preg_match でも preg_match_all でもチェックできます。

あとあれだね、ハマった時は一旦別のことした方がいいね。

お風呂入ったり昼寝したり。

経験上の話だけど、PCの前で考えるよりも寝たり湯船につかったりしながら考えた方が、気付けることが多いと思う。