それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

PearのServices_Amazonの親切なのか不親切なのか分からない機能

URL組み立てるだけなので使ってなかったが、カートを扱いたいのでServices_AmazonECS4を入れました。キャッシュ機能がついているのでキャッシュを使うことにしました。キャッシュ周りはパフォーマンスにすごく影響するのでコードを確認してきました。

キャッシュはAWSのトークンを複数使うよう前提で親切に設計されているようだ。

    /**
    function _generateCacheId($params)
    {
        unset($params['AWSAccessKeyId']);
        unset($params['AssociateTag']);
        $str = '';
        foreach ($params as $k => $v) {
            $str .= $k . $v;
        }
        return md5($str);
    }

AWSのトークンやアソシエイトIDを変更したリクエストでも、以前のキャッシュが使えますよ。ってことだ。親切だ。アソシエイトIDをトラッキングIDにしている場合は便利なんだろう。

ところが、キャッシュIDじゃなくて、キャッシュのコンテンツ保存と取り出し部分を読んでいて問題に気づく。状況に応じてアソシエイトIDを切り替えても、キャッシュ側には反映されない。

        // Return cached data if available
        $cache_id = false;
        if (isset($this->_cache) && !$this->_ignoreCache($params['Operation'])) {
            $cache_id = $this->_generateCacheId($params);
            $cache = $this->_cache->get($cache_id);
            if (!is_null($cache)) {
                $this->_processing_time = 0;
                return $cache;
            }
        }
    

キャッシュのコンテンツをそのままReturnしちゃうので Item->DetailPageURL に埋め込まれたアソシエイトIDがそのままになっちゃう。

_generateCacheIdでAssociateTagをunsetしてる意味がない。


コメントアウトで乗り切ってみる。

    /**
    function _generateCacheId($params)
    {
        unset($params['AWSAccessKeyId']);
        //unset($params['AssociateTag']);
        $str = http_build_query($params);
        $str = str_replace("&", "", $str);
        $str = str_replace("=", "", $str);
        return md5($str);
    }


かなり場当たり的に、アソシエイトIDを書き換えるパッチを試してみた。

....
#@989行
            if (!is_null($cache)) {
                $this->_processing_time = 0;
                return $this->afterCache($cache, $this->_associd);
            }
....
#@1047行
        if ($cache_id) {
            $this->_cache->save( $cache_id, 
                                 $this->beforeCache($contents, $this->_associd ),
                                 $this->_cache_expire);
        }
....
#追記
    function beforeCache($data, $AA_TAG){
        $str = serialize($data);
        $str = str_replace($AA_TAG, "__THIS_IS_AA_TAG_PLACE__", $str);
        return $str;
        }
    function afterCache($str, $AA_TAG){
        $str = str_replace("__THIS_IS_AA_TAG_PLACE__",$AA_TAG, $str);
        $data = unserialize($str);#ここでエラー
        return $data;
    }

serializeは文字長を変えるとエラーになるので使えなかった。残念。array_walk_recursive()で書き換えるかYAMLにして一括置換しかないかも。PEARのAmazonパッケージをキャッシュして使うとき、アソシエイトIDの切り替えはDetailURLの利用前にGET文字列を書き換えるしかないっぽい。親切なんだか不親切なんだか。よく分かんない。


AmazonECS4をextendsしてパッチClassを作ろうとしたけれど、_sendRequest()メソッドを全てコピー&ペーストで持ってくる必要があるので継承できない。*1キャッシュ&リクエスト&XMLパースがそれぞれ独立した別メソッドであれば簡単にパッチができたのに残念。。

*1:コピペすると親クラスの_sendRequest()が変更される都度パッチ側もコピペにする羽目に。