header()関数を使ってわざわざSet-Cookieヘッダーを書き出すのでなく、それを一発でやってくれるsetcookie()という便利な関数がありますが、これの挙動にはまってしまいました。
ある値をBase64エンコードした値を、cookieに吐き出したいと思っていました。
setcookie.php
<?php
$value = 'some value';
$encoded = base64_encode($value);
setcookie('key', $encoded);
echo $encoded, PHP_EOL;
これは期待した結果になりません。
$ curl -i localhost/setcookie.php
HTTP/1.1 200 OK
Date: Wed, 01 May 2013 14:41:54 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.4.9-4ubuntu2
Set-Cookie: key=c29tZSB2YWx1ZQ%3D%3D
Vary: Accept-Encoding
Content-Length: 17
Content-Type: text/html
c29tZSB2YWx1ZQ==
よおく見ると、Set-Cookieヘッダーの最後が==ではなくて%3D%3Dになってる、パーセントエンコードされちゃっています。
パーセントエンコードしないsetrawcookie()関数というのがあるみたいです。
setrawcookie.php
<?php
$value = 'some value';
$encoded = base64_encode($value);
setrawcookie('key', $encoded);
echo $encoded, PHP_EOL;
$ curl -i localhost/setcookie.php
HTTP/1.1 200 OK
Date: Wed, 01 May 2013 14:41:54 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.4.9-4ubuntu2
Set-Cookie: key=c29tZSB2YWx1ZQ==
Vary: Accept-Encoding
Content-Length: 17
Content-Type: text/html
c29tZSB2YWx1ZQ==
めでたしめでたし。
しかしなんでこんな仕様なんだろう……HTTPヘッダーインジェクション対策とかですかね。
逆に言うとsetrawcookie()に不用意にユーザー入力の文字列を渡すと、危険なので、そこは充分注意しましょう。