2016/10/18 20:39:32

PHPで特殊文字をエスケープ(クオート)するpreg_quote関数

php-logo
目次(クリックするとジャンプします)
  • 1:使い道あるの?
  • 2:preg_quote関数を使ってみる
  • 2.1:preg_replace関数
  • 2.2:preg_quote関数の真価
  • 3:補足・ハマったポイント
  • 3.1:preg_quote関数の第二引数
  • 4:まとめ

使い道あるの?

正確性を期すと、PHPマニュアルには「正規表現構文をクオートする」とあります。なので厳密には正規表現用の関数ですが、正規表現構文の特殊文字は「. \ + * ? [ ^ ] $ ( ) { } = ! < > | : -」の記号のことなので、正規表現構文の特殊文字≒記号という大まかな捉え方でも大きな問題はありません。

この関数は単体ではあまり使い道がなさそうですが、preg_match関数、preg_match_all関数、preg_replace関数等と組み合わせると威力を発揮します。

具体的にはhtmlタグの差し替えを容易にしてくれます。

PHPマニュアル preg_quote

preg_quote関数を使ってみる

例えば下記のhtmlファイルのimgタグの内容を変更したいとします。imgタグの内容がすべて同じであれば、変更は容易いのですが、多くの場合でそうであるように画像URLの内容はURLなどがそれぞれ違います。

<!-- img.html -->
<img src="http://hoge.hoge.com/?image=sky_image.jpeg">
<img src="http://hoge.hoge.com/?image=ground-12_image.png"> 
<img src="http://hoge.hoge.com/?image=sea_image.bmp">
<img src="http://hoge.hoge.com/?image=road.svg">

このhtmlに「拡張子ごとに画像URL構造の変更」を行いたい場合を考えてみます。

元の動的URL構造から

http://hoge.hoge.com/?image=sky_image.jpeg 

こうした拡張子ごとのディレクトリの静的URL構造に変えたいのです。

http://hoge.hoge.com/jpeg/sky_image.jpeg

これを実現させるためには全体のimgタグに一つ一つに処理をするため、 preg_match_all関数をつかってタグをマッチさせていくことになるかと思いマス。

下記の正規表現でマッチさせられるはず。(サブグループで拡張子、ファイル名を取得しています)

$html  = file_get_contents("img.html");
$regEx = "/<img\ssrc=\"http:\/\/hoge\.hoge\.com\/\?image=([_\-a-z0-9]+\.([jpegbmnsv]{3,4}))\">/"; 
preg_match_all($regEx, $html, $match, PREG_SET_ORDER);

さてpreg_match_all関数で無事imgタグをマッチさせることができたのですが、こんどはこれらのマッチしたimgタグを正規表現として使って、preg_replace関数にて元のimgタグを新しいタグに差し替えを行います。

preg_replace関数

preg_replace関数は正規表現にて、マッチした部分を指定した文字列で差し替えます。

しかしhtmlタグは上記で説明したとおり正規表現構文の特殊文字である「. \ + * ? [ ^ ] $ ( ) { } = ! < > | : -」のほとんどを含みます。マッチしたままの状態でのimgタグはこれらの特殊文字をふんだんに含んでいます。

もしこのままpreg_replace関数に与えてしまうとそれらの特殊文字は正規表現構文の特殊文字であると認識され、期待した動作にはなりません。

preg_quote関数の真価

そんな時の為に役立つのがpreg_quote関数です。

preg_quote関数は特殊文字をバックスラッシュ(\ )でクオートします。これは「エスケープする」と言う言い方と同義です。

特殊文字はエスケープされると「その字面どおりの文字」として認識されます。

例えば「*」は正規表現では「0回以上の繰り返し」という意味になりますが、バックスラッシュでエスケープ「 \* 」すると単に「文字としてのアスタリスク」と認識されます。

imgタグを例にしてみます。

<img src="http://hoge.hoge.com/?image=sky-image.jpeg"> 

このタグには「0回または1回の出現」を意味する「 ? 」や「改行以外の1文字」と意味する「 . 」があるので、このままの形で正規表現として使うとこのタグの字面通りの文字列にはマッチしません。

それをpreg_quote関数でクオートしてあげるとこのようになります。

\<img src\="http\:\/\/hoge\.hoge\.com\/\?image\=image\.jpeg"\>

特殊文字はすべてクオートされ、「 ?」や「 .」もその字面通りの文字として認識されるようになりました。

では実際に一連の処理をコードにしてみました。

string(209) "<img src="http://hoge.hoge.com/jpeg/sky_image.jpeg"> 
<img src="http://hoge.hoge.com/png/ground-12_image.png">
<img src="http://hoge.hoge.com/bmp/sea_image.bmp">
<img src="http://hoge.hoge.com/svg/road.svg">

ちゃんとURLが期待通りに差し替わっています。わ〜い。

preg_quote関数が無いと、自分でエスケープをする関数なりを作らなくてはならないので不便ですがpreg_quote関数なら一発でエスケープをしてくれます。

便利デス。

補足・ハマったポイント

preg_quote関数の第二引数

preg_quote関数の第二引数で/を指定しているのは、デフォルトではエスケープされないからです。

本来はデリミタをエスケープするためにの引数なのですが、URLの/をエスケープするにも使えるので、指定しておきます。指定しないと/がエスケープさせずエラーが出ます。

PHP Warning:  preg_replace(): Unknown modifier '/' in /home/mino/php_quoet.php on line 31
PHP Warning:  preg_replace(): Unknown modifier '/' in /home/mino/php_quoet.php on line 31
PHP Warning:  preg_replace(): Unknown modifier '/' in /home/mino/php_quoet.php on line 31
PHP Warning:  preg_replace(): Unknown modifier '/' in /home/mino/php_quoet.php on line 31
NULL

まとめ

  • preg_quote関数は正規表現構文の特殊文字をクオート(エスケープ)する
  • 単体ではちょっとアレだが、他のpreg系関数と併用すると真価を発揮する
  • 正規表現を用いたhtml変更をしやすくしてくれる関数