はじめに
前回の記事では、URLエンコードされた文字列を元に戻す urldecode() を紹介しました。今回はその逆、つまり文字列をURLの中で安全に使える形式に変換する urlencode() 関数を解説します。
URLには使用できる文字に制限があり、日本語などのマルチバイト文字や、& = + ? といった特殊な意味を持つ記号、あるいは半角スペースなどは、そのままURLに含めると意図しない解釈をされたり、通信エラーの原因になったりします。urlencode() はこうした文字を %XX 形式のパーセントエンコーディングに変換し、URLの中で安全に扱えるようにしてくれる関数です。クエリパラメータの組み立てやフォームデータの送信準備など、Web開発の現場で頻繁に登場する関数なので、しっかり押さえておきましょう。
関数概要
| 項目 | 内容 |
|---|---|
| 関数名 | urlencode() |
| 所属拡張 | コア関数(標準で常に利用可能) |
| シグネチャ | urlencode(string $string): string |
| 引数 | $string — エンコード対象の文字列 |
| 戻り値 | URLエンコードされた文字列 |
| 対応バージョン | PHP 4以降 |
| 対になる関数 | urldecode() |
| 類似関数 | rawurlencode()(スペースを+ではなく%20に変換する点が異なる) |
| OOP版の有無 | なし。手続き型関数のみ |
エンコードの流れ(イメージ図)
元の文字列
"こんにちは PHP&友達"
│
▼
urlencode()
│
┌──────────┴──────────────────┐
│ 1. 英数字と "-_." 以外をエンコード │
│ 2. 半角スペースは "+" に変換 │
│ 3. それ以外は "%XX" 形式に変換 │
└──────────┬──────────────────┘
▼
"%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF+PHP%26%E5%8F%8B%E9%81%94"
ポイントは、urlencode() が 半角スペースを + に変換する という挙動です。これは application/x-www-form-urlencoded(HTMLフォーム送信時に使われる形式)の仕様に沿ったものであり、後述する rawurlencode()(RFC 3986準拠でスペースを%20にする)とは明確に異なります。この違いを理解しておくことが、正しい使い分けの第一歩です。
実践サンプル7選
例1:基本的なエンコード
<?php
class BasicUrlEncoder
{
public function encode(string $string): string
{
// 英数字と一部の記号以外をパーセントエンコードする
return urlencode($string);
}
}
$encoder = new BasicUrlEncoder();
echo $encoder->encode('こんにちは') . PHP_EOL; // "%E3%81%93%E3%82%93..."
echo $encoder->encode('hello world') . PHP_EOL; // "hello+world"
例2:クエリ文字列を組み立てるクラス
<?php
class QueryStringBuilder
{
/**
* 連想配列から "key1=value1&key2=value2" 形式の
* クエリ文字列を安全に組み立てる
*/
public function build(array $params): string
{
$pairs = [];
foreach ($params as $key => $value) {
// キーと値それぞれをurlencode()でエンコードしてから連結
$pairs[] = urlencode((string) $key) . '=' . urlencode((string) $value);
}
return implode('&', $pairs);
}
}
$builder = new QueryStringBuilder();
echo $builder->build(['name' => '太郎', 'hobby' => 'tennis & golf']);
// 出力例: "name=%E5%A4%AA%E9%83%8E&hobby=tennis+%26+golf"
例3:外部APIへのリクエストURLを安全に生成する
<?php
class ApiUrlBuilder
{
public function __construct(private string $baseUrl)
{
}
/**
* ベースURLに検索キーワードなどのパラメータを
* 安全にエンコードして付与する
*/
public function buildSearchUrl(string $keyword, int $page = 1): string
{
$query = http_build_query([
'q' => $keyword,
'page' => $page,
]);
// http_build_query()内部でもurlencode相当の処理が行われるが、
// 個別にエンコードしたい場合は直接urlencode()を使う
return $this->baseUrl . '?' . $query;
}
public function buildManually(string $keyword): string
{
return $this->baseUrl . '?q=' . urlencode($keyword);
}
}
$apiBuilder = new ApiUrlBuilder('https://example.com/search');
echo $apiBuilder->buildManually('東京 カフェ') . PHP_EOL;
// "https://example.com/search?q=%E6%9D%B1%E4%BA%AC+%E3%82%AB%E3%83%95%E3%82%A7"
例4:urlencodeとrawurlencodeの挙動比較
<?php
class EncodeComparator
{
/**
* urlencode()とrawurlencode()の違いを
* スペースの扱いに注目して比較する
*/
public function compare(string $string): array
{
return [
'urlencode' => urlencode($string),
'rawurlencode' => rawurlencode($string),
];
}
}
$comparator = new EncodeComparator();
print_r($comparator->compare('a b+c'));
// urlencode: "a+b%2Bc" ← スペースは "+"、元の"+"は"%2B"に変換
// rawurlencode: "a%20b%2Bc" ← スペースは "%20" に変換
例5:Cookieに保存する値を安全にエンコードする
<?php
class CookiePayloadWriter
{
/**
* JSON形式のデータをCookieに保存できる形にエンコードする
*/
public function writeJsonPayload(array $data): string
{
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
// Cookie値に "=" や ";" などが含まれないよう安全にエンコード
return urlencode($json);
}
}
$writer = new CookiePayloadWriter();
$encoded = $writer->writeJsonPayload(['theme' => 'dark', 'lang' => 'ja']);
echo $encoded . PHP_EOL;
setcookie('preferences', $encoded, time() + 3600);
例6:メールのmailtoリンクを安全に生成する
<?php
class MailtoLinkBuilder
{
/**
* 件名や本文に日本語や記号が含まれていても
* 安全なmailtoリンクを生成する
*/
public function build(string $to, string $subject, string $body): string
{
$params = urlencode($subject) . '&body=' . urlencode($body);
// mailtoリンクではsubject/bodyのみクエリ形式で付与するのが一般的
return 'mailto:' . $to . '?subject=' . $params;
}
}
$builder = new MailtoLinkBuilder();
echo $builder->build('info@example.com', 'お問い合わせ', 'こんにちは、質問があります。');
例7:SNSシェア用URLを組み立てるクラス
<?php
class SnsShareUrlBuilder
{
/**
* 記事タイトルとURLをエンコードして
* SNSシェア用のリンクを生成する
*/
public function buildShareUrl(string $baseShareUrl, string $pageUrl, string $title): string
{
return sprintf(
'%s?url=%s&text=%s',
$baseShareUrl,
urlencode($pageUrl),
urlencode($title)
);
}
}
$sns = new SnsShareUrlBuilder();
echo $sns->buildShareUrl(
'https://sns.example.com/share',
'https://myblog.example.com/php-urlencode',
'[PHP]urlencodeとは?徹底解説'
);
関連関数との比較
| 関数 | 役割 | urlencodeとの違い |
|---|---|---|
urlencode() | 文字列をURLエンコードする | 本記事の対象。半角スペースを+に変換する |
urldecode() | URLエンコードされた文字列をデコード | urlencode() の対になるデコード関数 |
rawurlencode() | RFC 3986準拠のエンコード | スペースを%20にエンコードする(+にはしない) |
rawurldecode() | RFC 3986準拠のデコード | + をスペースに変換せず、そのまま+として扱う |
http_build_query() | 配列からクエリ文字列を一括生成 | 内部で自動的にエンコード処理を行う、より高レベルな関数 |
よくある落とし穴(注意点)
- スペースが
+になることを忘れる URLのパス部分(クエリ文字列より前の部分)をエンコードする場合、+は本来のスペースとして正しく解釈されないことがあります。パス部分にはrawurlencode()を使うのが適切です。 http_build_query()との使い分けが曖昧になる 複数のパラメータを持つクエリ文字列を組み立てる場合、urlencode()を個別に呼び出すよりもhttp_build_query()を使った方がコードがシンプルになり、エンコード漏れも防げます。- 既にエンコード済みの文字列を再度エンコードしてしまう 二重エンコードは典型的なバグの一つです。エンコード済みかどうかが不明な文字列を扱う場合は、処理フローの中でどの段階でエンコードするかを明確にルール化しておく必要があります。
- 日本語などマルチバイト文字のエンコーディング
urlencode()はバイト単位でエンコードするため、文字列のエンコーディングがUTF-8であることを前提にしています。Shift_JISなど他のエンコーディングの文字列を渡すと、意図しないバイト列としてエンコードされてしまいます。 - URLの長さ制限に注意する 大量のデータをエンコードしてクエリパラメータに含めると、ブラウザやサーバーのURL長制限に抵触することがあります。大きなデータはPOSTボディで送る、あるいは一意なIDに置き換えるなどの設計を検討しましょう。
まとめ
| 観点 | まとめ |
|---|---|
| 何をする関数か | 文字列をURLの中で安全に使えるパーセントエンコード形式に変換する |
| 主な用途 | クエリ文字列の組み立て、APIリクエストURLの生成、Cookie値の保存、mailtoリンクの生成など |
| 特徴的な挙動 | 半角スペースを + に変換する(rawurlencode()との最大の違い) |
| 対になる関数 | urldecode()(デコード)、rawurlencode()(RFC 3986準拠のエンコード) |
| 注意点 | パス部分への使用は不適切、二重エンコードのリスク、文字エンコーディングの前提を揃えること |
urlencode() はURLを安全に組み立てるための基本中の基本といえる関数です。rawurlencode() との違いを正しく理解し、用途(クエリ文字列かパスか)に応じて適切に使い分けることで、思わぬバグを未然に防ぐことができます。
