<?xml version="1.0" encoding="UTF-8"?>

<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:admin="http://webns.net/mvcb/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns="http://purl.org/rss/1.0/"
>

<channel rdf:about="http://blog.trend-antenna.com/">
<title>Trend Antenna 開発日記</title>
<link>http://blog.trend-antenna.com/</link>
<description>Trend Antennaの開発日記です。環境構築、PHPプログラミングなどについて書きつづります</description>
<dc:language>ja</dc:language>
<admin:errorReportsTo rdf:resource="mailto:info@blog.sakura.ne.jp" />
<admin:generatorAgent rdf:resource="http://blog.sakura.ne.jp" />
<items>
<rdf:Seq>
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/39539718.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/35610255.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/33833075.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/33492984.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/33445421.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/32280405.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/30750546.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/28988538.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/28517214.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/25729592.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/24040746.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/23154583.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/22787792.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/22349895.html" />
<rdf:li rdf:resource="http://blog.trend-antenna.com/article/22194566.html" />
</rdf:Seq>
</items>
</channel>

<item rdf:about="http://blog.trend-antenna.com/article/39539718.html">
<title>Naver の Yeti を追い出す</title>
<link>http://blog.trend-antenna.com/article/39539718.html</link>
<description> この10日ほど、Trend Antenna にアクセスしにくい状況が続いています。データベースサーバに負荷がかかっているために、PHP の実行に制限がかかっているようです。 エラーが出始めてから、データベースの構造を改善したり、SQL文の書き方を工夫してみたりしました。しかし、好転の兆しが見えず、かえって状況は悪化…。 そんなときに、アクセス解析を眺めていたら、Naver のロボット、Yeti が大量にアクセスしてきていることが判明しました。普段、ロボットを除いたアクセス解...</description>
<dc:subject>その他</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2010-07-09T14:51:25+09:00</dc:date>
<content:encoded><![CDATA[
<p>　この10日ほど、<a href="http://www.trend-antenna.com/" target="_blank">Trend Antenna</a> にアクセスしにくい状況が続いています。データベースサーバに負荷がかかっているために、PHP の実行に制限がかかっているようです。</p>
<p>　エラーが出始めてから、データベースの構造を改善したり、SQL文の書き方を工夫してみたりしました。しかし、好転の兆しが見えず、かえって状況は悪化…。</p>
<p>　そんなときに、アクセス解析を眺めていたら、Naver のロボット、Yeti が大量にアクセスしてきていることが判明しました。普段、ロボットを除いたアクセス解析しか見ていなかったので気付かなかったのですが、改めて見てみると、全体の転送量の60％以上が Yeti によるアクセス。他の検索エンジンのロボットがせいぜい5～6％なのに比べると、大きな違いです（ちなみに、Googlebot によるアクセスは、訪問回数こそ多いものの、転送量は非常に小さく、同じ内容のデータを読まないような配慮がされているように思います）。</p>
<p>　Naver 経由のアクセスもありませんし、人間のアクセスに支障が生じてまでロボットに配慮する必要はありませんから、Yeti を追い出すことにしました。</p>
<p>　方法としては、.htaccess と、robots.txt を併用することにしました。単にアクセス禁止にするだけだと、リソースの無駄遣いは減らせるものの、アクセス数そのものは減らせないからです。</p>
<p>　まず、.htaccess によるアクセス制限ですが、こちらは IPアドレスベースの制限をかけることにします。私のページにアクセスしてきたロボットの IPアドレスを <a href="http://whois.nic.ad.jp/cgi-bin/whois_gw" target="_blank">JPNIC の Whois</a> にかけて調べると、運営者である NHN Japan 株式会社が使用している IPアドレスが確認できます（<a href="http://whois.nic.ad.jp/cgi-bin/whois_gw?key=119.235.224.0/20" target="_blank">結果</a>）。これをすべてアクセス禁止にしてもよいのですが、それも気の毒なので、今回は 119.235.237.0/24 だけを制限することにしました（成果が出なければ拡大します）。また、後で述べるように robots.txt を読ませたいので、.htaccess に追加した記述は最終的に以下のようになります。</p>
<p>
Order allow,deny<br />
Allow from all<br />
Deny from 119.235.237.0/24<br />
<br />
&lt;Files robots.txt&gt;<br />
order deny,allow<br />
allow from all<br />
&lt;/Files&gt;
</p>
<p>　次に、robots.txt の記述ですが、こちらは簡単で、</p>
<pre>
User-agent: Yeti
Disallow: /
</pre>
<p>これだけ。これで、robots.txt 以外へのアクセスを遮断したうえで、robots.txt を解釈してくれるのであれば、私のサイトに来てはいけないということを認識してくれるはずです。</p>
<p>　早く成果が挙がることを祈ってます。</p>
<p>　Baidu の BaiduMobaider もお行儀が悪いので、追い出すことにしました。こちらについては、IPアドレスの範囲が、119.63.195.0/24 なので（<a href="http://www.baidu.jp/spider/" target="_blank">Baidu のクローラー情報ページ</a>）、.htaccess に<br />
Deny from 119.63.195.0/24<br />
を追加しました。大量のアクセスでリソースを食いつぶされてしまうのは、本当につらい…（2010年7月22日：追記）</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/35610255.html">
<title>PEAR Services_Amazon を使ってみる</title>
<link>http://blog.trend-antenna.com/article/35610255.html</link>
<description> 楽天ウェブサービスが安定しないこともあり（新規デベロッパーIDの発行を停止したようですね）、Amazon を併用するようにしたのですが、せっかくなので、新しいことを試してみようと、PEAR Services_Amazon を使ってみることにしました。書籍検索の場合は、以下のような感じです。require_once 'Services/Amazon.php';require_once 'Cache.php';$access_key_id = '(公開アクセスキー)';$sec...</description>
<dc:subject>PHP</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2010-02-26T01:46:44+09:00</dc:date>
<content:encoded><![CDATA[
<p>　楽天ウェブサービスが安定しないこともあり（<a href="http://webservice.rakuten.co.jp/blog/2010/02/25/20100225_info/" target="_blank">新規デベロッパーIDの発行を停止した</a>ようですね）、Amazon を併用するようにしたのですが、せっかくなので、新しいことを試してみようと、PEAR Services_Amazon を使ってみることにしました。書籍検索の場合は、以下のような感じです。

<pre name="code" class="php">
require_once 'Services/Amazon.php';
require_once 'Cache.php';

$access_key_id = '(公開アクセスキー)';
$secret_access_key = '(秘密アクセスキー)';
$associate_tag = '（アソシエイトタグ）';
    
$amazon = new Services_Amazon($access_key_id, $secret_access_key, $associate_tag);
$amazon->setCache('file', array('cache_dir' => '（キャッシュの保存先）'));
$amazon->setCacheExpire(3600); // 秒数で指定
$amazon->setLocale('JP');

$options = array();
    
$options['ResponseGroup']  = 'Medium'; //取得したい情報
$options['Keywords']       = '検索したいキーワード';
$options['Sort']           = 'salesrank';

$result = $amazon->ItemSearch('Books', $options);

if (PEAR::isError($result)) {
        echo $result->message;
} else {
    foreach($result['Item'] as $item) {
        $ItemData[] = array(
            'ImageURL' => $item["SmallImage"]["URL"],    
            'DetailPageURL' => $item["DetailPageURL"],
            'Title' => $item["ItemAttributes"]["Title"],
            'Price' => $item["ItemAttributes"]["ListPrice"]["FormattedPrice"]
        );
    }
}
</pre>
<p>　これで、$ItemData の中に商品データが入るので、適宜加工して表示するような形になります。ちょっと変わったこととしては、キャッシュを使うことによって、同じリクエストを連続して行わないように工夫をしています。この機能を使うためには、Services_Amazon のほかに、Cache のパッケージも必要となります（Cache_Lite ではないので注意）。</p>
<p>　<a href="http://pear.php.net/package/Services_Amazon/docs/latest/Services_Amazon/Services_Amazon.html" target="_blank">パッケージのドキュメント</a>もクラスのリファレンスしかないため、取っつきにくいですが、電子署名認証を自動でやってくれたり、結果を連想配列で返してくれたりと、かなり使い勝手がよいので、おすすめです。他にも、複数のキーワードについてひとつのリクエストで処理する doBatch メソッドや、複数の操作をひとつのリクエストで処理する doMultiOperation メソッドなども便利だと思います。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/33833075.html">
<title>モバイル版 Google Analytics を PHP4 で動かす</title>
<link>http://blog.trend-antenna.com/article/33833075.html</link>
<description> 先日からサービスの提供が始まったモバイル版の Google Analytics ですが、アクセス解析用の PHP スクリプトである ga.php は PHP4 では動きません。PHP4 のアップデートはすでに終わっているので、PHP5 にアップグレードするべきなのですが、レンタルサーバなどで PHP のアップグレードをしてくれないところもあると思います。そこで、PHP4 でも動くように、ga.php を修正してみました（ライセンス的な問題がちょっと気になりますが…）。 準備...</description>
<dc:subject>PHP</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-11-24T12:32:31+09:00</dc:date>
<content:encoded><![CDATA[
<p>　先日からサービスの提供が始まったモバイル版の Google Analytics ですが、アクセス解析用の PHP スクリプトである ga.php は PHP4 では動きません。PHP4 のアップデートはすでに終わっているので、PHP5 にアップグレードするべきなのですが、レンタルサーバなどで PHP のアップグレードをしてくれないところもあると思います。そこで、PHP4 でも動くように、ga.php を修正してみました（ライセンス的な問題がちょっと気になりますが…）。</p>
<p>　準備として、PEAR の <a href="http://pear.php.net/package/PHP_Compat" target="_blank">PHP_Compat</a> をインストールします（stable版の1.5.0ではなく、alpha版の1.6.0a2が必要）。</p>
<p>　次に、ga.php の先頭部分に</p>
<pre name="code" class="php">
require_once 'PHP/Compat/Function/setrawcookie.php';
require_once 'PHP/Compat/Function/file_get_contents.php';
</pre>
<p>を追加します。そして、97行目と100行目にある file_get_contents を php_compat_file_get_contents に書き換えます。さらに、144行目以降を</p>
<pre name="code" class="php">
    setrawcookie(
        COOKIE_NAME,
        $visitorId,
        $timeStamp + COOKIE_USER_PERSISTENCE,
        COOKIE_PATH);
</pre>
<p>から</p>
<pre name="code" class="php">
    setrawcookie(
        COOKIE_NAME,
        $visitorId,
        $timeStamp + COOKIE_USER_PERSISTENCE,
        COOKIE_PATH,
        '',
        false,
        false);
</pre>
<p>に変更します。</p>
<p>　これで動くようになるはずです（PHP4.4.9 の環境で確認）。</p>
<p>　種明かしをすると、setrawcookie は PHP5 から新たに登場した関数です。また、file_get_contents のコンテキストサポート（第3引数）も PHP5 以降にサポートされたものです。このため、これらを使えるようにしなければなりません。setrawcookie は、PHP4 にもともとない関数ですので、それほど問題ない（せいぜい 1.6.0a2 をインストールすることと、引数を省略せずに記載することくらい）のですが、file_get_contents は、PHP4.3.0 以降ではすでに登場しているため、PHP_Compat::loadFunction を使う PEAR PHP_Compat の通常の使い方だと、PHP ネイティブの関数が優先されてしまいます。そこで、上記のように個別の関数を手動で読み込んだうえで、PHP_Compat 側の関数を使うようにしているのです。</p>
<p>　不具合等があれば、コメント欄などでご指摘ください。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/33492984.html">
<title>Amazon の書籍を楽天ブックスで買うためのブックマークレット（続き）</title>
<link>http://blog.trend-antenna.com/article/33492984.html</link>
<description> 前回のエントリーで書いたAmazon の書籍を楽天ブックスで買うためのブックマークレットですが、処理の流れとしては、javascript で表示中の Amazon の URL から ASIN を取得取得した ASIN を Amazon の API に渡して ISBN を取得取得した ISBN を楽天の楽天ブックス書籍API に渡して楽天ブックスの商品ページを取得ということをやっています。 書籍の場合はこれでうまくいくのですが、雑誌の場合はうまくいきません。雑誌には ISBN...</description>
<dc:subject>その他</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-11-08T00:51:57+09:00</dc:date>
<content:encoded><![CDATA[
<p>　<a href="http://blog.trend-antenna.com/article/33445421.html" target="_blank">前回のエントリー</a>で書いたAmazon の書籍を楽天ブックスで買うためのブックマークレットですが、処理の流れとしては、<br />
<ol>
<li>javascript で表示中の Amazon の URL から ASIN を取得</li>
<li>取得した ASIN を Amazon の API に渡して ISBN を取得</li>
<li>取得した ISBN を楽天の楽天ブックス書籍API に渡して楽天ブックスの商品ページを取得</li>
</ol>
ということをやっています。
</p>
<p>　書籍の場合はこれでうまくいくのですが、雑誌の場合はうまくいきません。雑誌には ISBN ではなく、JANコードが付けられており、ASIN→ISBN変換では値を返さないからです。</p>
<p>　いろいろ調べてみると、Amazon API の ItemAttributes レスポンスグループの中にある EAN が日本の雑誌の場合には JANコードになっていることがわかりました。そこで、ASIN→ISBN変換で値を返さない場合は、EAN を取得し、これを楽天ブックス雑誌検索API に渡すことで、雑誌でも楽天ブックスの商品ページを取得できるようになりました。</p>
<p>　これを応用すれば、CD や DVD でも Amazon→楽天の検索ができるかもしれません（未検証ですが）。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/33445421.html">
<title>Amazon の書籍を楽天ブックスで買うためのブックマークレット</title>
<link>http://blog.trend-antenna.com/article/33445421.html</link>
<description> 厳密にいうと、Trend Antenna の開発とは直接関係がないのですが、ちょっとしたツールを作りましたので、ご報告。 API の使い勝手の良さもあって、Webサービスで書籍を紹介する場合、大概のサービスは Amazon へのリンクを張っています。私がよく使うはてなもメディアマーカーも同様です。レビューの充実度をみても、確かに便利なのですが、実際に買う段になると、個人的にはポイントがたまっている楽天ブックスで買いたいのです。そこで、Amazon の商品紹介ページから楽天ブ...</description>
<dc:subject>その他</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-11-05T13:11:26+09:00</dc:date>
<content:encoded><![CDATA[
<p>　厳密にいうと、Trend Antenna の開発とは直接関係がないのですが、ちょっとしたツールを作りましたので、ご報告。</p>
<p>　API の使い勝手の良さもあって、Webサービスで書籍を紹介する場合、大概のサービスは Amazon へのリンクを張っています。私がよく使うはてなもメディアマーカーも同様です。レビューの充実度をみても、確かに便利なのですが、実際に買う段になると、個人的にはポイントがたまっている楽天ブックスで買いたいのです。そこで、Amazon の商品紹介ページから楽天ブックスの商品紹介ページに橋渡しをするブックマークレットを作ってみました（下のリンクをブックマークに保存すれば利用できます）。私個人で使う分には、直接飛ばしてもよさそうな感じですが、一応確認ページをはさんでいます。</p>
<p>　<a href="javascript:var%20u=document.location.href;var%20di=u.indexOf('/dp/');var%20ai=u.indexOf('ASIN');if(ai==-1){var%20asin=u.substring(di+4,di+14);}else{var%20asin=u.substring(ai+5,ai+15);}void(window.open('http://www.trend-antenna.com/amazon2rakuten.php?asin='+asin));">Amazon to Rakuten</a></p>
<p>　Amazon の URL に ASIN または dp が含まれている場合のみに対応しています。それ以外の場合には、うまく動きませんので、ご了承ください。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/32280405.html">
<title>関連キーワードを表示するようにしました</title>
<link>http://blog.trend-antenna.com/article/32280405.html</link>
<description> 「アイフル 倒産」で盛り上がった今週末。これまでにも「春日電機 倒産」がアクセスを集めたりしていましたが、こうなってくると次の倒産が気になります。そこで、これまでに「倒産」とともにどんな企業が検索されていたかがわかるようにしてみました（別に倒産だけに限った話ではありませんが）。 仕様としては、スペースで区切られていない一つのキーワードで検索されたときに、そのキーワードを含む検索キーワードを表示するようにしてみました（表示は過去の検索回数が多い順に最大10件まで）。 これまで...</description>
<dc:subject>機能追加</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-09-20T23:20:25+09:00</dc:date>
<content:encoded><![CDATA[
<p>　「<a href="http://www.trend-antenna.com/archive/%E3%82%A2%E3%82%A4%E3%83%95%E3%83%AB%20%E5%80%92%E7%94%A3.html" target="_blank">アイフル 倒産</a>」で盛り上がった今週末。これまでにも「春日電機 倒産」がアクセスを集めたりしていましたが、こうなってくると次の倒産が気になります。そこで、これまでに「倒産」とともにどんな企業が検索されていたかがわかるようにしてみました（別に倒産だけに限った話ではありませんが）。</p>
<p>　仕様としては、スペースで区切られていない一つのキーワードで検索されたときに、そのキーワードを含む検索キーワードを表示するようにしてみました（表示は過去の検索回数が多い順に最大10件まで）。</p>
<p>　これまでもはてなや Yahoo! の API を利用して関連キーワードの表示を行ってきましたが、それらとはまたひと味違ったキーワードが表示されますので、試してみてください。</p>
<p>　で、当サイトで「倒産」とともに検索されている企業ですが、「ダヴィンチホールディングス」「青山メインランド」など不動産業が多いようです。どうなるのでしょう…。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/30750546.html">
<title>Twitter 始めてみました</title>
<link>http://blog.trend-antenna.com/article/30750546.html</link>
<description> 何となく飛びついてみました（笑）。肩肘張らずに書けるのがいいのかもしれません。ただ、無意識につぶやいていると、プライバシーが漏れまくってしまいそうな予感。 アカウントは、mikenews123 ですので、よろしければフォローよろしくお願いします。</description>
<dc:subject>その他</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-07-23T00:13:16+09:00</dc:date>
<content:encoded><![CDATA[
<p>　何となく飛びついてみました（笑）。肩肘張らずに書けるのがいいのかもしれません。ただ、無意識につぶやいていると、プライバシーが漏れまくってしまいそうな予感。</p>
<p>　アカウントは、<a href="http://twitter.com/mikenews123" target="_blank">mikenews123</a> ですので、よろしければフォローよろしくお願いします。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/28988538.html">
<title>MySQL を 5.1 にアップグレード</title>
<link>http://blog.trend-antenna.com/article/28988538.html</link>
<description> さくらインターネットで MySQL の 5.1 が利用できるようになったので、切り替えてみました。既存のデータベースを削除しなければならないので、いったんデータをバックアップしなければならないのが面倒でしたが、移行作業はそれほど手間ではありませんでした（容量が大きかったので、phpMyAdmin からインポートできず、エクスポートしたデータをサーバにアップロードした後、SSH でサーバに接続し、そこから MySQL サーバに接続、mysql コマンドでインポートしたことくら...</description>
<dc:subject>MySQL</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-05-09T22:21:49+09:00</dc:date>
<content:encoded><![CDATA[
<p>　<a href="http://px.a8.net/svt/ejp?a8mat=1BXX87+DGMV76+D8Y+65U42" target="_blank">さくらインターネット</a><img border="0" width="1" height="1" src="http://www15.a8.net/0.gif?a8mat=1BXX87+DGMV76+D8Y+65U42" alt="" />で MySQL の 5.1 が利用できるようになったので、切り替えてみました。既存のデータベースを削除しなければならないので、いったんデータをバックアップしなければならないのが面倒でしたが、移行作業はそれほど手間ではありませんでした（容量が大きかったので、phpMyAdmin からインポートできず、エクスポートしたデータをサーバにアップロードした後、SSH でサーバに接続し、そこから MySQL サーバに接続、mysql コマンドでインポートしたことくらい）。</p>

<p>　作業は順調に進んだように見えたのですが、実際に動かしてみるとうまくいきません。日本語を含むキーワードを入れると、データベースのエラーが出ます。この症状は、4.0系から4.1系以上に上げるときによく起こる現象で、PHP に組み込まれている MySQL のライブラリのキャラクターセットと MySQL サーバの設定が一致していないことが原因。<br />
　対処方法としては、PHP の再コンパイル（これはかなり面倒）か、MySQL の設定ファイル my.ini に
<blockquote>skip-character-set-client-handshake</blockquote>
を追加することなのですが、レンタルサーバではどちらも不可能です。<br />
　この場合、
<blockquote>SET NAMES utf8</blockquote>
を MySQL 接続後に実行することで回避することができますが、この方法にはセキュリティ上の問題が指摘されており、危険性を把握した上でご利用ください。</p>
<p>　PEAR の MDB2 を利用している場合、DSN の設定時に
<blockquote>'option' => 'charset=utf8'</blockquote>
を指定することで、PHP 側の MySQL の文字コードを変更することができるので、上記の問題を回避することができます。</p>

<h3>参考リンク</h3>
<ul>
<li><a href="http://www.mysql.gr.jp/frame/modules/bwiki/index.php?cmd=read&page=FAQ#content_1_40" target="_blank">4.1以上の壁 (日本語の扱いの違い、文字化け等/含む5.0以上)</a> - MyNA Web Site内</li>
<li><a href="http://nonn-et-twk.net/twk/why-set-names-in-php-is-bad" target="_blank">PHPからSET NAMESを使わない方が良い理由と対策まとめ</a></li>
<li><a href="http://dozo.matrix.jp/pear/index.php/PEAR/MDB2/mysqli.html" target="_blank">mysqliをPEAR::MDB2で利用する</a></li>
</ul>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/28517214.html">
<title>「なかのひと」で利用者を分析してみた</title>
<link>http://blog.trend-antenna.com/article/28517214.html</link>
<description> 「なかのひと」で Trend Antenna の利用者を分析してみました。結果は下の通り。男女比年齢分布 よく見られるキーワードから、男女比は男性のほうが多いと予想できましたが、年齢層が思ったよりも高くてびっくり。女性アイドルの画像を探している人が多いので、20代から30代の人が中心かと思ってました。 もちろん、「なかのひと」は企業などからのアクセスのみを集計して年齢構成を推測しているので、うちのように企業外ユーザーが多いサイトではサンプルが偏っているのだと思うのですが。</description>
<dc:subject>その他</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-04-16T23:15:07+09:00</dc:date>
<content:encoded><![CDATA[
<p>　「<a href="http://nakanohito.jp/" target="_blank" rel="nofollow">なかのひと</a>」で Trend Antenna の利用者を分析してみました。結果は下の通り。</p>
<h3>男女比</h3>
<img src="http://trend-antenna.sakura.ne.jp/sblo_files/trend-antenna/image/23.png" width="300" height="48" border="0" align="" alt="23.png" />
<h3>年齢分布</h3>
<img src="http://trend-antenna.sakura.ne.jp/sblo_files/trend-antenna/image/age.png" width="360" height="280" border="0" align="" alt="age.png" />
<p>　よく見られるキーワードから、男女比は男性のほうが多いと予想できましたが、年齢層が思ったよりも高くてびっくり。女性アイドルの画像を探している人が多いので、20代から30代の人が中心かと思ってました。<br />
　もちろん、「なかのひと」は企業などからのアクセスのみを集計して年齢構成を推測しているので、うちのように企業外ユーザーが多いサイトではサンプルが偏っているのだと思うのですが。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/25729592.html">
<title>XML_RPC2を使ってみる</title>
<link>http://blog.trend-antenna.com/article/25729592.html</link>
<description> どういうわけか、インストールされていたはずの PEAR XML_RPC が削除されてしまっていたので、代わりに後継といわれる XML_RPC2 を使ってみました。XML_RPC2 は PHP5 専用ですが、PHP4 のサポートも終了しましたし、今後こちらが使われることが増えていくでしょう。 XML_RPC2 の特徴として、サーバからのレスポンスをキャッシュすることができるというものがあります。これまで、XML_RPC と Cache_Lite を組み合わせて使っていた人から...</description>
<dc:subject>PHP</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2009-01-21T08:33:35+09:00</dc:date>
<content:encoded><![CDATA[
<p>　どういうわけか、インストールされていたはずの PEAR XML_RPC が削除されてしまっていたので、代わりに後継といわれる <a href="http://pear.php.net/manual/ja/package.webservices.xml-rpc2.php" target="_blank">XML_RPC2</a> を使ってみました。XML_RPC2 は PHP5 専用ですが、PHP4 のサポートも終了しましたし、今後こちらが使われることが増えていくでしょう。</p>
<p>　XML_RPC2 の特徴として、サーバからのレスポンスをキャッシュすることができるというものがあります。これまで、XML_RPC と Cache_Lite を組み合わせて使っていた人からすると、一つで済むので手間がだいぶ省けると思います。</p>
<p>　サンプルとして、Trend Antenna でも使っている<a href="http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%C0%A5%A4%A5%A2%A5%EA%A1%BC%A5%AD%A1%BC%A5%EF%A1%BC%A5%C9%CF%A2%C1%DB%B8%ECAPI" target="_blank">はてなダイアリーキーワード連想語API</a>のサンプルを XML_RPC2 で書いてみようと思います（キャッシュ付き）。</p>
<pre name="code" class="php">
require_once 'XML/RPC2/CachedClient.php';

$options = array(
    'prefix' => 'hatena.',
    'encoding' => 'utf-8',
    'cacheDebug' => false,
    'cacheOptions' => array(
        'cacheDir' => '/tmp/',
        'lifetime' => 21600,
        'automaticCleaningFactor' => 20,
        'hashedDirectoryLevel' => 1,
        'cacheByDefault' => true
    )
);

// XML_RPC2_CachedClient オブジェクトを作成します
$client = XML_RPC2_CachedClient::create('http://d.hatena.ne.jp/xmlrpc', $options);

try {
    $result = $client->getSimilarWord(array('wordlist' => array('Hatena', 'PHP')));
    $ret_val = array_values($result['wordlist']);
} catch (XML_RPC2_FaultException $e) {
    // XMLRPC サーバが XMLRPC のエラーを返しました
    die('Exception #' . $e->getFaultCode() . ' : ' . $e->getFaultString());
} catch (Exception $e) {
    // その他のエラー (HTTP あるいはネットワークの問題など...)
    die('Exception : ' . $e->getMessage());
}

foreach($ret_val as $word) {
    echo $word['word'] . ', ';
}
</pre>
<p>　こんな感じです。XML_RPC と比べると、XMLRPC の型を意識せずに使えることと、サーバのメソッドをクライアントオブジェクト（例の $client）のメソッドとして呼び出して使うので、スクリプトが見やすいという点が便利だと思います。なお、cacheOptions の中身は、Cache_Lite と同じ部分もあるので、それほど難しくないと思います。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/24040746.html">
<title>docomoの仕様に頭を抱える</title>
<link>http://blog.trend-antenna.com/article/24040746.html</link>
<description> おかげさまで PC 版と同じくらいのアクセスをいただいている Trend Antenna のモバイル版ですが、悩ましかったのはアクセス解析。携帯の場合、JavaScript が使えないので、PC 版で使っている Google Analytics は使えません。いくつか公開されているモバイル用のアクセス解析スクリプトを眺めてみましたが、しっくりきません。仕方がないので、自分で作ることにしたのですが、これが意外に面倒だったのです。 一番悩ましかったのは、docomo の仕様。携...</description>
<dc:subject>機能追加</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2008-12-08T23:10:18+09:00</dc:date>
<content:encoded><![CDATA[
<p>　おかげさまで PC 版と同じくらいのアクセスをいただいている Trend Antenna のモバイル版ですが、悩ましかったのはアクセス解析。携帯の場合、JavaScript が使えないので、PC 版で使っている Google Analytics は使えません。いくつか公開されているモバイル用のアクセス解析スクリプトを眺めてみましたが、しっくりきません。仕方がないので、自分で作ることにしたのですが、これが意外に面倒だったのです。</p>
<p>　一番悩ましかったのは、docomo の仕様。携帯の場合、cookie も使えないことが多いので、同一ユーザーからのアクセスであることを識別するには、セッションを URL に埋め込むか、端末識別番号を取得することになります。セッションを URL に埋め込む方法は、セキュリティ的にどうかと思ったので、端末識別番号を利用する方法を採用することにしました。<br />
　幸い、端末識別番号の取得自体は、PEAR の Net_UserAgent_Mobile を使えば、<br />
<pre name="code" class="php">
require_once 'Net/UserAgent/Mobile.php';

$agent = &Net_UserAgent_Mobile::factory();
$uid = $agent->getUID();
</pre>
で取得できるのですが、docomo の場合、URL に guid=ON を埋め込んでおかないと端末識別番号（docomo の場合はiモードID）が取得できません。おまけに、mod_rewrite で URL の書き換えは NG。つまり、<br />
RewriteRule ^m/archive/(.+).html$ m/index.php?guid=ON&amp;keyword=$1 [L]<br />
では、取得できないのです。このため、モバイル版では、URL の書き換えをせずに、引数をつけたそのままの形で記述しています（これに伴う問題が別のところで発生したのですが、それはまた別の機会に）。このほかに、フォームで投げるときにも注意すべき点があるのですが、このあたりの詳細については、<a href="http://blog.promob.jp/fri/2008/10/iid.html" target="_blank">Tech [Friday] プロモバイルエンジニアブログさんの記事</a>によくまとまっています。</p>
<p>　docomo は、リファラは返さないし、アクセスのたびごとに IPアドレスは変わるしで、アクセス解析を行ううえでは、非常に困った仕様です。iモード開始時にはインターネットへの接続を想定していなかったのでしょうし、セッションが終わるまで一つの端末がIPアドレスを固定で持ってしまうとネットワークを有効活用できないという事情はあるのだと思うのですが、モバイルサイトを作るうえで、docomo なかりせば、と思うことが多いのも事実です（外部スタイルシートも使えないですしね）。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/23154583.html">
<title>モバイル版始めました</title>
<link>http://blog.trend-antenna.com/article/23154583.html</link>
<description> ふと思い立って、モバイル版を作ってみました。携帯電話からTrend Antennaにアクセスしていただくと表示されると思います。 モバイル版ということで、表示内容は絞ってありますが、PC版にはない動画検索の機能を追加しました。移動中の時間つぶしに使っていただければ幸いです。</description>
<dc:subject>機能追加</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2008-11-20T23:24:34+09:00</dc:date>
<content:encoded><![CDATA[
<p>　ふと思い立って、モバイル版を作ってみました。携帯電話から<a href="http://www.trend-antenna.com/">Trend Antenna</a>にアクセスしていただくと表示されると思います。</p>
<p>　モバイル版ということで、表示内容は絞ってありますが、PC版にはない動画検索の機能を追加しました。移動中の時間つぶしに使っていただければ幸いです。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/22787792.html">
<title>波ダッシュ問題 on XML_RPC</title>
<link>http://blog.trend-antenna.com/article/22787792.html</link>
<description> PEAR の XML_RPC には UTF-8 の文字列の取扱いに不具合があるようで、UTF-8 固有の文字を送信すると文字化けします。例えば、タイトルに挙げた波ダッシュや単位記号（cmやkg）などがこれにあたります（波ダッシュについては、Wikipedia の記事が参考になります）。 解決方法としては、文字列を渡す前にあらかじめ別の文字列に置換しておき、返ってきた結果に対して、逆の置換を行うことが考えられます。例えば、require_once 'XML/RPC.php';...</description>
<dc:subject>PHP</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2008-11-12T18:30:48+09:00</dc:date>
<content:encoded><![CDATA[
<p>　PEAR の <a href="http://pear.php.net/package/XML_RPC" target="_blank">XML_RPC</a> には UTF-8 の文字列の取扱いに不具合があるようで、UTF-8 固有の文字を送信すると文字化けします。例えば、タイトルに挙げた波ダッシュや単位記号（cmやkg）などがこれにあたります（波ダッシュについては、<a href="http://ja.wikipedia.org/wiki/%E6%B3%A2%E3%83%80%E3%83%83%E3%82%B7%E3%83%A5" target="_blank">Wikipedia</a> の記事が参考になります）。</p>
<p>　解決方法としては、文字列を渡す前にあらかじめ別の文字列に置換しておき、返ってきた結果に対して、逆の置換を行うことが考えられます。例えば、<br />
<pre name="code" class="php">
require_once 'XML/RPC.php';

$str = (XML_RPCに渡す文字列)

// 以下の部分で全角チルダと波ダッシュをいったん naminamimoji に置換
$str = preg_replace('#\xEF\xBD\x9E#i', 'naminamimoji', $str);
$str = preg_replace('#\xE3\x80\x9C#i', 'naminamimoji', $str);

$params = new XML_RPC_Value(
    array(
        'body' => new XML_RPC_Value($str, 'string'),
        'score' => new XML_RPC_Value(50, 'int'),
    ),
    'struct'
);
    
$msg = new XML_RPC_Message('hatena.setKeywordLink', array($params));

$cli = new XML_RPC_Client('/xmlrpc', 'd.hatena.ne.jp');

$resp = $cli->send($msg);

if (!$resp) {
    echo 'Communication error: ' . $cli->errstr;
    exit;
}

if (!$resp->faultCode()) {
    $val = $resp->value();
    $data = XML_RPC_decode($val);
    $ret_val = $data;
        
} else {
    /*
     * xmlrpc.php スクリプトが遭遇した問題を
     * 報告する
     */
    echo 'Fault Code: ' . $resp->faultCode() . "\n";
    echo 'Fault Reason: ' . $resp->faultString() . "\n";
    $ret_val = $data;
}

// 置換していた文字を元に戻す
$ret_val = str_replace('naminamimoji', '～', $ret_val);
</pre>
　ただ、この方法は例で挙げた<a href="http://d.hatena.ne.jp/keyword/%a4%cf%a4%c6%a4%ca%a5%ad%a1%bc%a5%ef%a1%bc%a5%c9%bc%ab%c6%b0%a5%ea%a5%f3%a5%afAPI" target="_blank">はてなキーワード自動リンクAPI</a>のように、入力される一部の文字を無視しても実用上問題がない場合には効果的ですが、入力される文字列自体が重要な場合（検索など）の場合にはうまくいきません。</p>
<p>　おそらく内部でエンコードの変換を行っていることが原因だと思うのですが、ちょっと困りものです。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/22349895.html">
<title>関連商品情報を変更しました</title>
<link>http://blog.trend-antenna.com/article/22349895.html</link>
<description> キーワード検索した際にサイドに表示される関連商品情報を変更しました。これまで Amazon と楽天を併用していましたが、楽天のみに変更するとともに、評価の件数と平均点を表示するようにしました。アフィリエイトの点で Amazon のクリックの有効期間が1日と短いのに対して、楽天が1か月あるというのが変更の大きな理由ではあるのですが、API の使い勝手が楽天のほうがよいというのも変更の理由です（Amazon は、商品写真がきれいというメリットがあるので、個別商品の紹介では引き続...</description>
<dc:subject>機能追加</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2008-11-03T11:58:38+09:00</dc:date>
<content:encoded><![CDATA[
<p>　キーワード検索した際にサイドに表示される関連商品情報を変更しました。これまで Amazon と楽天を併用していましたが、楽天のみに変更するとともに、評価の件数と平均点を表示するようにしました。アフィリエイトの点で Amazon のクリックの有効期間が1日と短いのに対して、楽天が1か月あるというのが変更の大きな理由ではあるのですが、API の使い勝手が楽天のほうがよいというのも変更の理由です（Amazon は、商品写真がきれいというメリットがあるので、個別商品の紹介では引き続き使用しています）。</p>
<p>　Amazon の API(AWS)は、きっちり作り込めばできることは多いのですが、出力される内容が細分化されているため、若干敷居が高い気がします（ドキュメントも英語ですしね）。それに比べると、楽天はカスタマイズの点では不十分なところもありますが、扱いやすいと思います。</p>
<p>　使い方としては、リクエスト用のURLを<br />
<pre name="code" class="php">
$developerId  = '(ディベロッパーID)';
$affiliateId  = '(アフィリエイトID)';
$operation    = 'ItemSearch';
$keyword      = rawurlencode('(検索したいキーワード)');
$version      = '2008-09-01';
$hits         = 10;
$page         = 1;
$sort         = rawurlencode('-reviewCount');
$availability = 1;
$field        = 0;
$imageFlag    = 1;
$request_url = "<a href="http://api.rakuten.co.jp/rws/1.12/rest?developerId=" target="_blank">http://api.rakuten.co.jp/rws/1.12/rest?developerId=</a>{$developerId}&affiliateId={$affiliateId}&operation={$operation}&keyword={$keyword}&version={$version}&hits={$hits}&page={$page}&sort={$sort}&availability={$availability}&field={$field}&imageFlag={$imageFlag}";
</pre>
みたいな感じで作ったら、<br />
<pre name="code" class="php">
$xml = file_get_contents($request_url);
require_once 'XML/Unserializer.php';

$options = array(
    "parseAttributes" => true
);
$unserializer =& new XML_Unserializer( $options );
$unserializer->unserialize( $xml, FALSE );
$res = $unserializer->getUnserializedData();
</pre>
のようにすれば、結果を配列に入れることができます。あとは、<a href="http://webservice.rakuten.co.jp/api/itemsearch/" target="_blank">ドキュメント</a>と結果の配列を見比べながら、必要なデータを抽出すればOKです（例ではキーワードに関連する、画像があり、入手可能な商品を評価数の多い方から10件取得しています）。</p>
]]></content:encoded>
</item>
<item rdf:about="http://blog.trend-antenna.com/article/22194566.html">
<title>イメージ検索を追加しました</title>
<link>http://blog.trend-antenna.com/article/22194566.html</link>
<description> ずいぶん久しぶりの投稿になってしまいました（気になるキーワードのほうはけっこう頻繁に更新してますので、興味のある方はぜひ）。 で、本題ですが、Trend Antenna に関連イメージを表示するようにしました。これは、Google AJAX Search APIを利用して作成したもので、関連する画像を検索して表示しています。画像が表示されることで、画面が少しにぎやかになったと思います。 具体的な実装方法ですが、私の場合は、JavaScript を利用しない方法でこの API...</description>
<dc:subject>機能追加</dc:subject>
<dc:creator>まいける</dc:creator>
<dc:date>2008-10-31T18:28:34+09:00</dc:date>
<content:encoded><![CDATA[
<p>　ずいぶん久しぶりの投稿になってしまいました（<a href="http://trend-antenna.seesaa.net/" target="_blank">気になるキーワード</a>のほうはけっこう頻繁に更新してますので、興味のある方はぜひ）。</p>
<p>　で、本題ですが、<a href="http://www.trend-antenna.com/" target="_blank">Trend Antenna</a> に関連イメージを表示するようにしました。これは、<a href="http://code.google.com/intl/ja/apis/ajaxsearch/" target="_blank">Google AJAX Search API</a>を利用して作成したもので、関連する画像を検索して表示しています。画像が表示されることで、画面が少しにぎやかになったと思います。</p>
<p>　具体的な実装方法ですが、私の場合は、JavaScript を利用しない方法でこの API を利用しています。詳しくは、<a href="http://code.google.com/intl/ja/apis/ajaxsearch/documentation/#fonje" target="_blank">ディベロッパーズガイド</a>や<a href="http://code.google.com/intl/ja/apis/ajaxsearch/documentation/reference.html#_intro_fonje" target="_blank">クラスリファレンス</a>の該当箇所を読んでもらいたいのですが、PHP の場合は、<br />
<pre name="code" class="php">
$json = file_get_contents($googleSearchURL);
$resAry = json_decode($json, TRUE);
</pre>
で、取得した JSON オブジェクトを配列に入れることができますので、後は煮るなり焼くなり（笑）。</p>
]]></content:encoded>
</item>
</rdf:RDF>

