ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

PHP, urlencode() は rawurlencode() に変えるべき?

php
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

PHPには、URLのエンコード / デコードの関数が2種類あります。urlencode() / urldecode() と rawurlencode() / rawurldecode()。

使う目的は同じなんですが、じゃあどっちを使うの? という話です。

エンコードとは何か? デコードとは何か?

エンコードはプログラミングだけで使う言葉ではありません。通信分野でもよく使います。

ざっくりとかんたんに言えば、エンコードはデータを別のデータに変換することでデコードは復元すること。

URLのエンコードとは、URLをHTMLに埋め込むときに正しくURLとして認識される文字列へ変換することを言います。

(ブラウザの上部に表示されるURLもエンコードされた文字列。)

HTMLにあるURLは、画像を表示したり別ページへ移動したりするのに使いますが、そのためにはURLでは使っちゃいけない文字があり、それを別の文字へ変換しなければなりません。

(たとえば半角スペースや日本語のような全角文字など。)

そのためにエンコード処理を行います。

エンコードとデコード

エンコード(encode)

通信データなどをある規則にしたがって符号化する。

デコード(decode)

エンコード(符号化)されたデータを復元する。

urlencode() / urldecode()

urlencode() は、半角英数と半角記号の3つ(.-_)はそのままにして、それ以外の文字はすべて2桁の16進数表記に変換します。その16進表記には先頭に%を付けて。

ただしひとつ特長があって、半角スペースはプラス(+)に変換します。

なんで + なのか? と言われれば、昔からそうなってるとしか言いようがありません。ルールというより慣習が広まって一般化したといったところでしょう。

PHPの公式ドキュメントでも『歴史的背景により』という言葉で表現されています。

<?php

$url = "https://sample.test/?q='サンプル'";
echo urlencode($url) . PHP_EOL;

$url = "https://sample.test/?q='_-+*'";
echo urlencode($url) . PHP_EOL;

$url = "https://sample.test/?q='sample sample'";
echo urlencode($url) . PHP_EOL;
結果
https%3A%2F%2Fsample.test%2F%3Fq%3D%27%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%27
https%3A%2F%2Fsample.test%2F%3Fq%3D%27_-%2B%2A%27
https%3A%2F%2Fsample.test%2F%3Fq%3D%27sample+sample%27

rawurlencode() / rawurldecode()

一方、rawurlencode() は、RFCが策定した仕様文書に基づいた変換方式です。半角スペース以外はurlencode() と同じ。

半角スペースは16進数表記で '%20' に変換します。

あっ、もうひとつあった。そのまま表示する半角記号(.-_)にチルダ(~)が追加されています。

ちがいはこの2つだけ。

RFC (Request for Comments)

IETFが標準化を推し進めるために公開している仕様の文書のこと。

日本語訳文書は、企業や社団法人などの団体が公開しているが、全網羅されたものはない。

また、訳の正確性も担保されてないので、原文(英語)を読むことが推奨されている。

和訳を参考する分には構わないが、そのときは原文のチェックも忘れずに。ただ、今の翻訳機能はかなりのものなので原文を読むほうが早い。

IETF(Internet Engineering Task Force, インターネット技術特別調査委員会)

インターネットに関する仕様の標準化を推し進めているNPO。

Internet Engineering Task Force - Wikipedia

urlencode と rawurlencode の比較
<?php

$url = "https://sample.test/?q='サンプル'";
echo urlencode($url) . PHP_EOL;
echo rawurlencode($url) . PHP_EOL . PHP_EOL;

$url = "https://sample.test/?q='_-~+*'";
echo urlencode($url) . PHP_EOL;
echo rawurlencode($url) . PHP_EOL . PHP_EOL;

$url = "https://sample.test/?q='sample sample'";
echo urlencode($url) . PHP_EOL;
echo rawurlencode($url) . PHP_EOL . PHP_EOL;
結果
https%3A%2F%2Fsample.test%2F%3Fq%3D%27%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%27
https%3A%2F%2Fsample.test%2F%3Fq%3D%27%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%27

https%3A%2F%2Fsample.test%2F%3Fq%3D%27_-%7E%2B%2A%27
https%3A%2F%2Fsample.test%2F%3Fq%3D%27_-~%2B%2A%27

https%3A%2F%2Fsample.test%2F%3Fq%3D%27sample+sample%27
https%3A%2F%2Fsample.test%2F%3Fq%3D%27sample%20sample%27

RFCには仕様によって番号が振られており、URLエンコードの仕様はRFC3986です。

RFC3986はURIの一般的な構文に関する仕様。

どっちを使うべきか?

じゃあどっちを使えばいいんだという話ですが、どっちでもいい。エンコードしたデータを全く同じルールでデコードすれば問題ありません。

答えになってませんか?

一般的には rawurlencode() がいいでしょう。きちんと仕様策定されたものがベターです。

慣習はルールじゃないので守らない自由がありますが、仕様から外れるには確たる理由が必要です。

仕事でも、urlencode() を使うと怒られることはあっても、rawurlencode() で怒られることはないでしょう。

『urlencode() を使って』と言われてないかぎりは。

そうはいってもurlencode() の廃止はなかなか難しいです。世界中にあまたあるサイトのリンクが壊れるのは非現実的なので。

静的コードチェックでは警告が出ることも

PHP_CodeSniffer(phpcs)を使ってWordPressコーディング規約でチェックをするとこのような警告が出ます。

urlencode() should only be used when dealing with legacy applications rawurlencode() should now be used instead. See http://php.net/manual/en/function.rawurlencode.php and http://www.faqs.org/rfcs/rfc3986.html

訳)

urlencode()はレガシーアプリケーションを扱う場合にのみにすべきで、代わりにrawurlencode()を使うべきです。

http://php.net/manual/en/function.rawurlencode.php および http://www.faqs.org/rfcs/rfc3986.html を参照してください。

筆者訳

レガシーアプリケーションとは、遺跡と呼ぶくらい古いということで、もうこれ以上進化はないと意味。

わざわざ、urlencode() を使う理由はないと言ってるのも同然です。

ボクは積極的に警告を消す作業をしています。自分が作ってるものがレガシーではないので。

もちろん、変更による影響はないことの確認は必要です。

urlencode() は非推奨じゃない

WordPressコーディング規約ではエラーではなく警告です。絶対に使っちゃダメにはなっていません。

PHP公式ドキュメントでも、urlencode() に非推奨のメッセージはありません。それだけレガシーコードが世の中に残ってるんでしょう。

最後に大事なことを忘れてました。urlencode() / rawurlencode() でエンコードしたデータの復元関数は対になっているものを使わないといけません。

変換方式がちがうんだから、使い方を間違えると復元コードがおかしくなります。

エンコード
(変換)
デコード
(復元)
urlencode()urldecode()
rawurlencode()rawurldecode()
前の投稿
PHP, エラー制御演算子(@)でエラー出力を抑えられる。しかし、使うのはやめよう!
PHP8, 関数のパラメータ順が関係なくなる。名前付きパラメータの追加。
次の投稿

コメントを残す