記事一覧はこちら

phpのCURLOPT_POSTFIELDSに配列を渡すと@から始まるテキストをファイル名として読み込む事について

$ch = curl_init("http://...");
curl_setopt($ch,CURLOPT_POSTFIELDS,["message"=>$_POST["msg"]]);

この場合、$POST["msg"]が"@/etc/passwd"等@から始まる文字列だった場合、サーバー内の任意のファイルが送信されるから注意。"@/etc/passwdhoge"でも通る。 受け取る時$POST["message"]ではなく$FILES["message"]になるからそのまま表示されるみたいな事はまずないと思うけど。 受け取る側がphp以外だったら知らない。自動的に$FILESの中身も展開しちゃう言語ってあるんだろうか。

が、本来$_POST["message"]で受け取れるはずのメッセージが受け取れなくなってしまう事に変わりはない。 twitter等@が文字列の一文字目に来る可能性が高いシステムは注意。 twitterOAuthはテキストのpost時、http_build_queryしているから大丈夫だけどupdate_with_media対応版や、update_with_media phpググると最初に出てくるページtmhOAuthを使う例では、そのまま配列を渡しているからstatusの一文字目に@が入っている=誰かの返信であるツイートは送信に失敗してしまう。

じゃあどうすればいいのかって言うと、自作のpict3dsというサービスではメッセージの先頭に半角スペースを入れています。 twitterではstatusがtrim()されるからとりあえずOK。

もう少し掘り下げると、上記の通り、@から始まる文字列は強制的にファイル名として読み込まれるので、あえて先頭に@から始まる文字を送る事が出来ない。 具体的に言うと、CURLOPT_POSTFIELDSで設定する値が配列の場合 ファイル名扱いになるからbuild_http_queryで文字列にしてしまえば問題無い。 が、CURLOPT_POSTFIELDSに文字列で渡してしまうとリクエストのContentTypeがapplication/x-www-form-urlencodedになってしまうから ContentTypeをmultipart/form-data;で送る必要がある場合はやっぱり不可能になってしまう。

じゃあCURLOPT_HTTPHEADERで強制的ヘッダを指定すればいいんじゃね?と思ったけど

curl_setopt($ch,CURLOPT_POSTFIELDS,<<


ContentTypeが二つ送信されるからやっぱり無理。 ContentType: multipart/form-data;boundary=key; ContentType: application/x-www-form-urlencoded

phpの仕様ミスだと思うんだけど。

http_build_queryで文字列化して回避 と書いてあるけど、twitterに限るなら半角スペースの方がグッドじゃないかなーと。 cURLのツイッター殺しの奇妙な仕様 | gdgdな人がgdgdに書く、gdgdな皆様のためのブログ > Programing