ひらい ぶらり Hi-Library

ぷろぐらみんぐについて。ときどきどうでもいいことについて。

PHPでmemcacheのkeyに制御文字(コントロールコード)を使う場合の注意

PHPでmemcache関数でセットして、取り出すときはtelnet接続するという奇特なことをしている時にはまったのでメモ。
こんなことする人他に居るんだろうか・・・

現象

<?php
memcache_set($memcache_obj, "hoge^A6", "huga", 0 ,30);
?>

としてセット。^Aは制御文字。

<?php
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
?>

で接続。

<?php
fwrite($fp, "get hoge^A6\r\n");
?>

で取得しようとすると「hoge^A6」というkeyにデータは存在しないことになっていて、ENDだけが帰ってくる。
実際にtelnetで接続して同様の記述をしても同じ。そんなkeyのvalueはねぇぜといわれる。

制御文字とかは弾かれるのかな?とか思って消してみても駄目。
ただしmemcache_getでは取得できるので、格納はされている。

どうもsetするときに何らかの処理をされているっぽいのでソースを見てみる

wget http://pecl.php.net/get/memcache-2.2.1.tgz
tar xvzf memcache-2.2.1.tgz
cd memcache-2.2.1
vi memcache.c

発見

memcache.c 528行目あたり

 516 int mmc_prepare_key_ex(const char *key, unsigned int key_len, char *result, unsigned int *result_len TSRMLS_DC)  /* {{{ */
 517 {
 518     unsigned int i;
 519     if (key_len == 0) {
 520         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key cannot be empty");
 521         return MMC_REQUEST_FAILURE;
 522     }
 523
 524     *result_len = key_len < MMC_KEY_MAX_SIZE ? key_len : MMC_KEY_MAX_SIZE;
 525     result[*result_len] = '\0';
 526
 527     for (i=0; i<*result_len; i++) {
 528         result[i] = key[i] > ' ' ? key[i] : '_';
 529     }
 530
 531     return MMC_OK;
 532 }

アンダースコア[_]に置き換えられてる・・・orz
つまり直にたたく場合はkeyは"hoge_6"となる・・・
なので変な文字(0x1f以下)を使うとアンダースコアに置き換えられるので、まったく同じ文字列でtelnetでgetしようとしても駄目なんですねー。書いとけちくしょう。