4 posts tagged “php”
PHP の curl 関数で POST メソッドを使いたい場合に CURLOPT_POSTFIELDS のお世話になるのだが,巷で見掛けるコードで,CURLOPT_POSTFIELDS に対して連想配列を渡しているものがある.
$params = array('a' => $value1, 'b' => $value2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
PHP マニュアルには「CURLOPT_POSTFIELDS には文字列を与える必要がある」と書かれているのだが,もし連想配列渡しが期待通りに処理されるのであれば便利だ.Query String を自前で生成するのは面倒臭い (PHP5 であれば http_build_query 関数を利用できるが).
というわけで,何となく動くようだし手抜きもできるし,CURLOPT_POSTFIELDS への連想配列渡しを愛用していたのだが,Twitter API で @ 記法の文字列を投稿する際にハマった.
$params = array('status' => $_REQUEST['status']); // '@foo 腹減ったー'
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
これがエラーコード 26: 'failed creating formpost data' で失敗する.どうやら,値の先頭が '@' の場合に失敗するらしい.
はて,コマンドライン版の curl ではどうなんだろう.以下を実行することで 'failed creating formpost data' エラーを再現できた.
/usr/bin/curl --form 'a=@' 'http://www.yahoo.co.jp'
コマンドライン版のマニュアルを読んでみると,どうやら --form オプションはファイルアップロードのために '@' で始まる値を特別扱いするらしい.PHP の curl 関数でも --form オプション相当の処理を行っているのか!? だとすればひどい設計だ.--form オプションでの '@' はエスケープすることができない.curl 関数では正規のファイルアップロード手段が別に用意されているのだから '@' 記法は必要ない.'@' を特別扱いしない --form-string オプション相当の処理を行えば良いハズなのだ.
何とか抜け道はないものかと,藁にもすがる思いで ext/curl/interface.c を読んでみたら,奇妙な事実が….
case CURLOPT_POSTFIELDS:
if (Z_TYPE_PP(zvalue) == IS_ARRAY || Z_TYPE_PP(zvalue) == IS_OBJECT) {
/* 略 */
for (/* 略 */) {
if (*postval == '@') {
++postval;
/* 略 */
error = curl_formadd(&first, &last,
CURLFORM_COPYNAME, string_key,
CURLFORM_NAMELENGTH, (long)string_key_len - 1,
CURLFORM_FILE, postval,
CURLFORM_END);
はて,'@' 付きの値を curl に渡すのではなく,自前で「ファイル」として処理している….しかも '@' を特別扱いするのは,CURLOPT_POSTFIELDS に連想配列が渡された時だけのようだ.つまり,連想配列ではなく文字列を渡せばエラーは起きないのか!?
$query = sprintf('%s=%s', rawurlencode('status'), rawurlencode($_REQUEST['status'])); // '@foo 腹減ったー'
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
うまくいった….そもそもマニュアルには「文字列を渡せ」と書いてあるのだし,連想配列用の処理は内部的な何かであって,今まで動いていたように見えたのはたまたまだった,ということだろう.何の事はない.
むきー.
Twitter が流行っている.
自分も ID を取ってみたが,こーゆーものはケータイから更新したいと思うのが人情だ (そうか?).やはりというか,Twitter が提供する API を利用して,強者たちがケータイ版を数々と世に送り出し既に群雄割拠の体を成していたので,これらを利用すれば万々歳だ.
はて,本当にそうか!?
人様のサーバに別サービスの認証情報を預けるのって恐くね!?
あー,そういえば昔 mixi のケータイ版が提供されてなかったころに似たような話があったような (記憶不明瞭).ケータイの場合,アプリ版ブラウザとかみたいに通信を肩代わりせざるを得ない場合もあって,実はみんなそんな文化に慣れきっているとか?
まぁ,すぐにパスワード変えればいいやと思い,幾つか試しているうちに,「はー,へー,ほう…」と思い,気が付いたら自分で作っていた (意味不明).
迂闊にも PHP5 で書いてしまったらレンサバで動かなかったので,自宅サーバで公開してみるテスト.
http://phoneme.homelinux.org/twitter/
「人様のサーバに別サービスの認証情報を預けるのって恐くね!?」とか言った舌の根も乾かぬうちにナニなのだが,作ったら公開してみたくなるのが人情なので,きっと既存サイトもそういうメンタリティの元に放たれているのだろう.
一応,セッション ID の Referer 漏れや認証情報の扱いには気を遣っているので,そういう文化に慣れきっている人は利用されたい.
あー,なんか常体だと不自然になるな,こーゆー内容の場合….
昨日の続き.
うまくいったと思ったら,同一鍵によるエンコーダを二回以上生成するとコケるようになった.むぅ.
$bf = new Crypt_Blowfish('A');
var_dump($bf->encrypt('B')); // string(8)$bf = new Crypt_Blowfish('A');
var_dump($bf->encrypt('B')); // PEAR_Error (The key is not initialized.)
単に前回のインスタンスを保持しておけば良いだけだし,こんな使い方するほうが悪いような気もするけど,挙動としては適切でないような気がする.前バージョンと挙動違うし.生成コストはさておき,同じ結果にならないとおかしいだろう.
とある PHP4 用のコードを PHP5 で動かしてみたら,なにやら結果がおかしい.コードを追ってみると,PEAR の Crypt_Blowfish の出力が PHP4 の時と異なっているようだ.まじですか.
Crypt_Blowfish 自体は両方とも stable の最新バージョン (1.0.1) でファイルの内容 (Blowfish.php, DefaultKey.php) も同じだし,なんで変わるかなぁ.同じ入力で違う結果を返されたら使い物にならんよ….とブーたれつつも何かヒントがないかと Google 様に尋ねてみると,それっぽい事例が引っかかった.
これは「Linux と Windows で結果が異なる」というものだが,どうやら次バージョンのベータ版で修正されているようなので,試しに PHP5 環境の Crypt_Blowfish を 1.1.0RC1 に入れ替えてみた.
すんなり一致した.
試しに PHP4 環境の方もバージョンを合わせてみたが,こちらは結果が変わることはなかった.