preg_matchが文字数によってマッチしたりしなかったりする(Last RSS)

技術関係

Last RSSを使ってRSSを取得する際に正常に取得できない(0件になってしまう)現象があったので追いかけていったところ気がついた問題

概要

PHPの正規表現で最小マッチをある程度以上の長さの文字列に使用した場合、マッチング自体が失敗する
※ 正確に言うと文字数ではないのだけど、そういうイメージ

どうやらPHPというより正規表現で使われるPCREライブラリの制限に引っかかって失敗する様子
マッチするはずの正規表現がマッチしない現象 – T.Teradaの日記
pxt | 【PHP】 preg_match() の最小マッチに容量制限がある?

件のLast RSSでは、RSSのパースに正規表現を使っており、そこでパース自体がコケていた
preg_match(“‘<channel.?>(.?)‘si”, $rss_content, $out_channel);

解決策

おすすめは「正規表現の見直し」。

制限を緩和する

PCREライブラリの持っている制限を以下の設定で緩和できる。
ただし、根本的な解決にならないので注意

ini_set("pcrh.backtrack_limit", 100000); // デフォルトは100000
ini_set("pcrh.recursion_limit", 100000); // デフォルトは100000

pcrh.backtrack_limit integer
: PCRE のバックトラック処理の制限値。 PHP < 5.3.7 ではデフォルトが 100000 でした。

pcrh.recursion_limit integer
: PCRE の再帰処理の制限値です。この値を大きくすると、 使用可能なプロセススタックを使い切ってしまい、 (OS のスタックサイズの制限値に達して) PHP をクラッシュさせてしまうことに注意しましょう。

301 Moved Permanently

正規表現を見直す

そもそも、そんな長い文字列を切りだそうとする方が間違っているので正規表現自体を見直す
どう見なおすかはケースバイケース

元になるテキストを見直す

そもそも、そんな長い文字列を切りだそうとする方が間違っているのでテキスト自体を見直す
どう見なおすかはケースバイケース

LastRSSを使わない

今回の問題に対する対応策。これ以外で問題になった場合は別案へ

タイトルとURLをコピーしました