[PHP]urlencodeとは?文字列をURLセーフな形式に変換する方法を徹底解説

PHP

はじめに

前回の記事では、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()配列からクエリ文字列を一括生成内部で自動的にエンコード処理を行う、より高レベルな関数

よくある落とし穴(注意点)

  1. スペースが+になることを忘れる URLのパス部分(クエリ文字列より前の部分)をエンコードする場合、+ は本来のスペースとして正しく解釈されないことがあります。パス部分には rawurlencode() を使うのが適切です。
  2. http_build_query()との使い分けが曖昧になる 複数のパラメータを持つクエリ文字列を組み立てる場合、urlencode() を個別に呼び出すよりも http_build_query() を使った方がコードがシンプルになり、エンコード漏れも防げます。
  3. 既にエンコード済みの文字列を再度エンコードしてしまう 二重エンコードは典型的なバグの一つです。エンコード済みかどうかが不明な文字列を扱う場合は、処理フローの中でどの段階でエンコードするかを明確にルール化しておく必要があります。
  4. 日本語などマルチバイト文字のエンコーディング urlencode() はバイト単位でエンコードするため、文字列のエンコーディングがUTF-8であることを前提にしています。Shift_JISなど他のエンコーディングの文字列を渡すと、意図しないバイト列としてエンコードされてしまいます。
  5. URLの長さ制限に注意する 大量のデータをエンコードしてクエリパラメータに含めると、ブラウザやサーバーのURL長制限に抵触することがあります。大きなデータはPOSTボディで送る、あるいは一意なIDに置き換えるなどの設計を検討しましょう。

まとめ

観点まとめ
何をする関数か文字列をURLの中で安全に使えるパーセントエンコード形式に変換する
主な用途クエリ文字列の組み立て、APIリクエストURLの生成、Cookie値の保存、mailtoリンクの生成など
特徴的な挙動半角スペースを + に変換する(rawurlencode()との最大の違い)
対になる関数urldecode()(デコード)、rawurlencode()(RFC 3986準拠のエンコード)
注意点パス部分への使用は不適切、二重エンコードのリスク、文字エンコーディングの前提を揃えること

urlencode() はURLを安全に組み立てるための基本中の基本といえる関数です。rawurlencode() との違いを正しく理解し、用途(クエリ文字列かパスか)に応じて適切に使い分けることで、思わぬバグを未然に防ぐことができます。

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