<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Liner Note &#187; プログラミング技術絡み</title>
	<atom:link href="http://note.openvista.jp/tag/programming-technics/feed/" rel="self" type="application/rss+xml" />
	<link>http://note.openvista.jp</link>
	<description>情報（ユーザー中心デザイン・ユーザビリティ）と技術（ウェブプログラミング・ウェブサービス）についてのメモ書き</description>
	<lastBuildDate>Mon, 12 Sep 2011 15:12:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>RDBが扱いづらい問題はO/Rマッパーで解決できる？</title>
		<link>http://note.openvista.jp/2008/problems-about-relational-database/</link>
		<comments>http://note.openvista.jp/2008/problems-about-relational-database/#comments</comments>
		<pubDate>Sat, 01 Nov 2008 19:03:17 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ウェブはこうあってほしい論]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=986</guid>
		<description><![CDATA[リレーショナル・データベースが扱いづらい問題について、RDB初心者が思案を巡らしてみた記事]]></description>
			<content:encoded><![CDATA[<p class="information">
この記事は書いている内に、問題解決の糸口が見えてきたけど、問題だと思っているところをはっきりさせるために、そのまま書いた記事です。
</p>
<p>以下に、その思考ログを書いておきます。</p>
<div class="toc">
<ol>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#t1e55ca">RDBが使いづらい理由</a></p>
<ol>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#t4dea13">スキーマを事前に定義しておかないといけない</a></li>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#tf49f29">データ型として配列が使えない</a></li>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#t874012">プログラミング言語との連携が弱い</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#t2e2bef">O/Rマッパーがいいらしい?</a>
<ol>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#t132443">O/Rマッパーは問題を解決する?</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/problems-about-relational-database/#tdc352b">言及されたURL</a></li>
</ol>
</div>
<h3 id="t1e55ca">RDBが使いづらい理由</h3>
<p>最近、MySQLやSQLiteなどのリレーショナル・データベースを使い始めたのですが、XMLをどうにも使いづらいという感は抜けません。そんなこともあって先日は<a href="http://note.openvista.jp/2008/xml-like-database-using-sqlite/">擬似XMLデータベース</a>なんてへんてこなものを作ったりしたのですが、気がついてみればその理由をあんまり書いてなかったので、使いづらさに慣れちゃう前に理由を整理してみました。</p>
<h4 id="t4dea13">スキーマを事前に定義しておかないといけない</h4>
<p>開発中にはデータベースのデータ構造が変化すると言うことは良くあります。そのたびに、スキーマ定義をカリカリ書き換えているのは面倒ですから、データベースには速度だけでなく、<em>柔軟性・拡張性</em>が求められることになります<span class="weaken">（これはリレーショナルデータベースとXMLデータベースとの対比で良く言われます）</span></p>
<h4 id="tf49f29">データ型として配列が使えない</h4>
<p>簡単に言えば、一つのレコードに複数の値を設定できないということです。ブログのタイトルのようにキーと値が1:1で対応している場合は問題ないのですが、例えばこの記事のカテゴリのように、<em>あるキーに複数の値が対応する</em><span class="weaken">（1:n）</span>ということはよくあることです。しかし、どうも<a href="http://dev.mysql.com/doc/refman/4.1/ja/column-types.html" title="MySQL :: MySQL 4.1 リファレンスマニュアル :: 6.2 カラム型">マニュアル</a>を見る限りは、MySQLに複数の値を格納できる型、つまりは配列型はないようなのです。</p>
<p>この場合、一般的には<a href="http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=27319&amp;forum=26&amp;2">シリアル化（serialize関数）して文字列として処理→DBから取り出した後に復元（unserialize関数）</a><span class="weaken">（PC用語で言うと圧縮、解凍みたいなものですね、サイズは変わりませんが）</span>という方法が採られているようですが、一手間かけさせられているというか、言語側の仕様に依存しているようでどうにも納得いきません。</p>
<p class="information">この項、シリアライズが一般的と書きましたが、いくつかご指摘をいただきまして、標準的には<a href="http://sql.main.jp/cont/norm/nto1.html">第一正規化</a>（つまり別テーブル化）するのが一般的だそうです。まぁ、どちらにしても一手間かけなければいけないことに代わりはないようなのですが、勉強になりました。</p>
<p>ちなみに、この手順をコードにしてみるとこんな感じ<span class="weaken">（例：商品の名前・価格・カテゴリについて書いてあるデータベース）</span></p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-comment">/** データを挿入するとき **/</span>
<span class="codes-var">$category</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span>
<span class="codes-code">  </span><span class="codes-quotes">&quot;</span><span class="codes-string">音楽再生機器</span><span class="codes-quotes">&quot;</span><span class="codes-code"> =&gt; </span><span class="codes-quotes">&quot;</span><span class="codes-string">MP3プレイヤー</span><span class="codes-quotes">&quot;</span><span class="codes-code">,</span>
<span class="codes-code">  </span><span class="codes-quotes">&quot;</span><span class="codes-string">iPod</span><span class="codes-quotes">&quot;</span><span class="codes-code"> =&gt; </span><span class="codes-quotes">&quot;</span><span class="codes-string">本体</span><span class="codes-quotes">&quot;</span><span class="codes-code">,</span>
<span class="codes-code">  </span><span class="codes-quotes">&quot;</span><span class="codes-string">スマートフォン</span><span class="codes-quotes">&quot;</span><span class="codes-code"> =&gt; </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">Apple</span><span class="codes-quotes">&quot;</span><span class="codes-code">,</span><span class="codes-quotes">&quot;</span><span class="codes-string">ソフトバンクモバイル</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span>
<span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$vars</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">:id</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-number">10</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">:name</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-quotes">&quot;</span><span class="codes-string">iPhone</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">:price</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-number">200000</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">:category</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-identifier">serialize</span><span class="codes-brackets">(</span><span class="codes-var">$category</span><span class="codes-brackets">))</span><span class="codes-code">;</span>
<span class="codes-var">$sql</span><span class="codes-code"> = </span><span class="codes-quotes">&quot;</span><span class="codes-string">INSERT INTO 'mytable' (id, name, price) VALUES (:id, :name, :price)</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-var">$request</span><span class="codes-code"> = </span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">prepare</span><span class="codes-brackets">(</span><span class="codes-var">$sql</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$request</span><span class="codes-code">-&gt;</span><span class="codes-identifier">execute</span><span class="codes-brackets">(</span><span class="codes-var">$vars</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-comment">// （中略） </span>
<span class="codes-code"> </span>
<span class="codes-comment">/** データを取り出すとき **/</span>
<span class="codes-code"> </span>
<span class="codes-comment">// SELECT文の発行とかはすっとばします</span>
<span class="codes-var">$names</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">id</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">name</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">price</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">category</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-reserved">while</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$row</span><span class="codes-code"> = </span><span class="codes-var">$request</span><span class="codes-code">-&gt;</span><span class="codes-identifier">fetch</span><span class="codes-brackets">(</span><span class="codes-identifier">PDO</span><span class="codes-code">::</span><span class="codes-identifier">FETCH_ASSOC</span><span class="codes-brackets">)){</span>
<span class="codes-code">  </span><span class="codes-reserved">foreach</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$names</span><span class="codes-code"> </span><span class="codes-reserved">as</span><span class="codes-code"> </span><span class="codes-var">$name</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-var">$v</span><span class="codes-code"> = </span><span class="codes-var">$row</span><span class="codes-brackets">[</span><span class="codes-var">$name</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-comment">// gettype関数先生は全部stringと仰るので</span>
<span class="codes-code">    </span><span class="codes-comment">// 泥臭く文字列としてシリアライズされているか判定</span>
<span class="codes-code">    </span><span class="codes-var">$results</span><span class="codes-brackets">[</span><span class="codes-var">$i</span><span class="codes-brackets">][</span><span class="codes-var">$name</span><span class="codes-brackets">]</span><span class="codes-code"> = </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/^a:[0-9]+:{/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$v</span><span class="codes-brackets">))</span><span class="codes-code"> ? </span><span class="codes-identifier">unserialize</span><span class="codes-brackets">(</span><span class="codes-var">$v</span><span class="codes-brackets">)</span><span class="codes-code"> : </span><span class="codes-var">$v</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span><span class="codes-var">$i</span><span class="codes-code">++;</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-comment">/*</span>
<span class="codes-comment">  $results = array(</span>
<span class="codes-comment">    [0] =&gt; array(</span>
<span class="codes-comment">      &quot;id&quot;=&gt;10,</span>
<span class="codes-comment">      &quot;name&quot;=&gt;&quot;iPhone&quot;,</span>
<span class="codes-comment">      &quot;price&quot;=&gt; 200000,</span>
<span class="codes-comment">      &quot;category&quot;=&gt;array(</span>
<span class="codes-comment">        &quot;音楽再生機器&quot; =&gt; &quot;MP3プレイヤー&quot;,</span>
<span class="codes-comment">        &quot;iPod&quot; =&gt; &quot;本体&quot;,</span>
<span class="codes-comment">        &quot;スマートフォン&quot; =&gt; array(&quot;Apple&quot;,&quot;ソフトバンクモバイル&quot;)</span>
<span class="codes-comment">      )</span>
<span class="codes-comment">    ),</span>
<span class="codes-comment">    [1] =&gt; array(</span>
<span class="codes-comment">    ...</span>
<span class="codes-comment">    )</span>
<span class="codes-comment">  );</span>
<span class="codes-comment">*/</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p class="information">ちなみに、<a href="http://q.hatena.ne.jp/1194630646" title="MySQLのSETとENUMについて。 MYSQLで配列のような使い方のできるのデータ型を探したところ、SETとENUMがそれっぽいことは分かりましたが、いまいち理解し切れません。 配列.. - 人力検索はてな">SET型はユーザ定義型</a><span class="weaken">（あらかじめ入る内容を定義しておかないと行けない）</span>なので、配列的に使うには無理がありますし、join関数を用いた単純結合は多次元配列を処理できません。</p>
<h4 id="t874012">プログラミング言語との連携が弱い</h4>
<p>データベースはプログラムとセットにして使うものなのに、その連携が弱いんじゃないかなと思うのです。</p>
<p>例えば、先の例で商品データベースを使いましたよね。再掲すると…</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-var">$category</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-code">**省略**</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$vars</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">:id</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-number">10</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">:name</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-quotes">&quot;</span><span class="codes-string">iPhone</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">:price</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-number">200000</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">:category</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-identifier">serialize</span><span class="codes-brackets">(</span><span class="codes-var">$category</span><span class="codes-brackets">))</span><span class="codes-code">;</span>
<span class="codes-var">$sql</span><span class="codes-code"> = </span><span class="codes-quotes">&quot;</span><span class="codes-string">INSERT INTO 'mytable' (id, name, price) VALUES (:id, :name, :price)</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-var">$request</span><span class="codes-code"> = </span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">prepare</span><span class="codes-brackets">(</span><span class="codes-var">$sql</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$request</span><span class="codes-code">-&gt;</span><span class="codes-identifier">execute</span><span class="codes-brackets">(</span><span class="codes-var">$vars</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>これ、個人的にはこう書きたいんですね（連想配列を投げる）</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-var">$vars</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">id</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt; </span><span class="codes-number">10</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">name</span><span class="codes-quotes">&quot;</span><span class="codes-code"> =&gt; </span><span class="codes-quotes">&quot;</span><span class="codes-string">iPod nano</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">price</span><span class="codes-quotes">&quot;</span><span class="codes-code"> =&gt; </span><span class="codes-number">200000</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">category</span><span class="codes-quotes">&quot;</span><span class="codes-code">=&gt;</span><span class="codes-var">$category</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$request</span><span class="codes-code"> = </span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">insert</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">mytable</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$vars</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>今回は後者を前者に置換するラッパ関数を書けば良い話ですが、さきほどの配列型の問題と絡めて、こういうのがデフォルトになってくれるといいなと。</p>
<p>まぁ、あと細かいことを挙げれば</p>
<ul>
<li>データの挿入（INSERT）と更新（UPDATE）でクエリの書式が違う</li>
<li>SQLインジェクションが構造的に発生する</li>
<li>データがバイナリファイルである<span class="weaken">（これはちょっとイチャモンぽいですが）</span></li>
</ul>
<p>とありますが、冗長になるので深くはつっこまないことにします。</p>
<h3 id="t2e2bef">O/Rマッパーがいいらしい?</h3>
<p>検索していると、連携問題はどうやら<a href="http://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E9%96%A2%E4%BF%82%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0" title="オブジェクト関係マッピング - Wikipedia">オブジェクト関係マッパー（O/Rマッパー）</a>と呼ばれるもので解決できそうな感じです。</p>
<p>このO/Rマッパーというのは、要するに<em>人間がデータベースを触りやすくなるように、プログラミング言語のお作法で違和感なくデータベースがいじれるようにするような仕組み</em>のようです。PHPのフレームワークの一つであるCakePHPでは、ActiveRecordという考え方<span class="weaken">（デザイン・パターンとか言うらしい）</span>を基にしたO/Rマッパーが実装されている模様。</p>
<p>配列型問題はどうだろう…定義からして解決できるぽい感じはするのですが、具体的な記述が見つけられません。あと、<a href="http://gihyo.jp/dev/serial/01/cakephp/0005" title="CakePHPで高速Webアプリ開発：第5回　CakePHPで作るToDoアプリ（1）|gihyo.jp … 技術評論社">最初にデータベース定義が必要なところ</a>はどうも解決してないっぽいですね。むー</p>
<h4 id="t132443">O/Rマッパーは問題を解決する?</h4>
<p>じゃあ、O/Rマッパーを使えばいいのかというとそれもちょっと疑問なんですよね。僕が抱えてる問題はちょっとは解決するんですが、別に思うこともありまして…。で、これには2つの理由があります。</p>
<ol>
<li>初心者は結局、SQLを学ばないといけない</li>
<li>O/Rマッパは対処療法である</li>
</ol>
<p>まず、「じゃあ初心者ってO/Rマッパ使うのか」という疑問です。<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4798020826/openvista-22/ref=nosim/">PHPの入門書</a>でも、だいたいPEAR::MDB2の使い方を解説するか、PDOの使い方を解説するくらいが現状なわけで、結局はSQLの書き方やお作法を学ぶことになるでしょう。</p>
<p>Wikipediaの「O/Rマッパー」の項には<q cite="http://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E9%96%A2%E4%BF%82%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0">オブジェクト関係マッピングは、オブジェクト指向と関係モデルのインピーダンス・ミスマッチ問題の対症療法にすぎないとも言われている</q>と書かれていますが、これはその通りで、上記の問題が起こるのもこの問題があるからでしょう。</p>
<p>つまり、O/Rマッパーはプログラム言語とSQL言語の翻訳者でしかないわけで<span class="weaken">（断言してますけど、自信はないです）</span>、SQL自身が関係モデルを取り、SQL言語を話している限りは、その問題の根本が解決したとは言えないのです。とはいえ、オブジェクトデータベースやXMLデータベースは、PerlやPHPなどプログラム初心者が手を出しやすい軽量言語では実質使えない状況です。</p>
<p>初心者にとって、<em>プログラム言語とSQL言語のバイリンガルにならざるを得ない状況</em>があって、それがプログラミングの壁を厚くしているような感じがします。まぁ、現状はO/Rマッパー（を搭載したフレームワーク）が最適解ぽいので、この問題は、「現状は初心者こそCakePHPを使うべき」が落としどころになりそうです。しかし、入門書にフレームワークの記述は難しいだろうなぁ。</p>
<h3 id="tdc352b">言及されたURL</h3>
<p>以下で言及されました<span class="weaken">（ありがとうございます）</span>。<br />
<a href="http://www.developer0000.jp/2008/11/02/3112/" title="ORマッパーとか | 眠る開発屋blog">ORマッパーとか | 眠る開発屋blog</a></p>
<p>SQLのコストについて。確かにSQL学習上のコストはそれほど高く付くわけではないのですしこの先数年も流通している知識だとは思うのですが、それが本来必要なコストなのかどうかということをSQL初学者として書いておきたかったのでした<span class="weaken">（できるならデータベースのお作法を気にせずに＝透過的に、扱えるようになるべきでしょうし）</span>。</p>
<p><amazon>9784839924317</amazon></p>
<img src="http://note.openvista.jp/?ak_action=api_record_view&id=986&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/problems-about-relational-database/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHPでのセキュリティ施策についてのメモ</title>
		<link>http://note.openvista.jp/2008/php-security-memo/</link>
		<comments>http://note.openvista.jp/2008/php-security-memo/#comments</comments>
		<pubDate>Sun, 26 Oct 2008 10:17:02 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=931</guid>
		<description><![CDATA[PHPで脆弱なアプリを作らないために、どのようなことを考えておけばよいかできる範囲でまとめました。間違い・補足があればご指摘いただければ幸いです。]]></description>
			<content:encoded><![CDATA[<p>PHPでのセキュリティ施策については前々からいささかながら気を払っていました。ただ、本を読んで体系だって勉強したわけではないので、調べてまとめたことを晒しておいて、みなさんのご指摘をいただこうかと思います。</p>
<p class="caution">以下の内容が正しいとは限らないこと、かつ、対策を実行しても未知の事象で脆弱性が生じうる可能性があることをご了承の上、お読みください。より詳細な内容を得たい場合は<a href="#tdefc9a">参考リンク先の文書</a>を辿ってみてください。</p>
<div class="toc">
<ol>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t12ba8e">脆弱性と対策方法</a></p>
<ol>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t72ff27">SQLインジェクション</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t4e835e">クロスサイトスクリプティング<span class="weaken">（略称：XSS）</span></a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t254cc2">クロスサイトリクエストフォージェリ<span class="weaken">（略称：CSRF）</span></a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t3e4cb3">ディレクトリトラバーサル</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t6be0e9">サーバリソースを浪費させてしまう脆弱性</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t95a9f7">いつ対策するか</a>
<ol>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t9dff36">処理の最初期に処理する</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t8257b2">問題が起こりうる場所<span class="weaken">（出力時やクエリ発行時など）</span>に処理する</a>
<ol>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#tff9709">許可した文字のみを通過させる</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t2afd2b">エスケープ出力をデフォルトにする</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#ta4a27b">設定の確認と入力時検証を行う</a></li>
</ol>
</li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#tdefc9a">参考にしたURL</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t3a284a">読者のコメントとご返信</a></li>
<li><a href="http://note.openvista.jp/2008/php-security-memo/#t5edd4e">更新履歴</a></li>
</ol>
</div>
<h3 id="t12ba8e">脆弱性と対策方法</h3>
<p>まず、具体的に気をつけているのは以下の5つの脆弱性についてです。むろん、まだまだあるかと思いますが最善より次善の策ということで代表的そうな例を考えておきます。</p>
<p>これらは、いずれもユーザ入力に対して適切に対処できていなかった場合に起こる脆弱性です。が、だからといって<a href="http://takagi-hiromitsu.jp/diary/20051231.html#p02">ユーザ入力値部分だけ対策しておこうという方法では対策漏れが生じる</a><span class="weaken">（User-Agent文字列をそのまま出力してしまうなど）</span>可能性があるため、<em>全ての変数出力箇所に対して検証を行うべき</em>でしょう。</p>
<ol class="titlize">
<li><a href="http://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3">SQLインジェクション</a></li>
<li><a href="http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0">クロスサイトスクリプティング</a><span class="weaken">（略称：XSS）</span></li>
<li><a href="http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA">クロスサイトリクエストフォージェリ</a><span class="weaken">（略称：CSRF）</span></li>
<li><a href="http://ja.wikipedia.org/wiki/%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%83%88%E3%83%A9%E3%83%90%E3%83%BC%E3%82%B5%E3%83%AB">ディレクトリトラバーサル</a></li>
<li>サーバリソースを浪費させる脆弱性</li>
</ol>
<p>以下で一つずつ説明していきます。あ、その前に<a href="http://wiki.ohgaki.net/index.php?PHP%2F%E8%84%86%E5%BC%B1%E6%80%A7%E3%83%AA%E3%82%B9%E3%83%88">PHP自体の脆弱性</a>を防ぐためにPHPは利用できる最新版を利用するということで。</p>
<h4 id="t72ff27"><a href="http://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3">SQLインジェクション</a></h4>
<p><img src="http://note.openvista.jp/download/2008/10/sql_injection.png" alt="SQLインジェクション" title="SQLインジェクション" /></p>
<dl>
<dt>どんな脆弱性?</dt>
<dd>管理者側が実行する予定だったSQL文を終了させ、攻撃者側が用意したSQL文を挿入することで、例えばデータベースを破壊したりすることが出来る脆弱性</dd>
<dt>どう対策する?</dt>
<dd>
<ul>
<li>SQL文を発行する際は<a href="http://www.phpbook.jp/pear/pear_db/index12.html" title="プリペアドステートメント - データベース接続(PEAR::DB) - PEAR入門">準備済みのクエリ文</a> (prepared statement)を用いる<sup><a href="http://note.openvista.jp/2008/php-security-memo/#footnote_0_931" id="identifier_0_931" class="footnote-link footnote-identifier-link" title="一般には「準備された文」と言われるみたいです。これを使う際は、DBのバインド機構を使うことになります（バインド機構はこちらで解説されてます。ただし、準備済みのクエリ文を用いてもクエリが安全でない環境があるので注意">1</a></sup> か、<a href="http://gihyo.jp/dev/serial/01/php-security/0005?page=2" title="なぜPHPアプリにセキュリティホールが多いのか?：第5回　まだまだ残っているSQLインジェクション|gihyo.jp … 技術評論社">DBのAPI関数を用いて、全ての変数をエスケープする</a><span class="weaken">（例えばPHP::PDOなら<a href="http://jp2.php.net/manual/ja/pdo.quote.php" title="PHP: PDO::quote - Manual">PDO::quote</a>を用いる。しかし、なぜ準備済みの文を使わないとエスケープが行われないんでしょうか?）</span></li>
<li>エスケープで防ぎきれないインジェクションについては<a href="http://gihyo.jp/dev/serial/01/php-security/0014?page=2">全ての変数を文字列として処理</a>するという方法もありますが、これだと数値が数値として評価されなくなるので、<a href="http://jp.php.net/manual/ja/function.is-numeric.php" title="PHP: is_numeric - Manual">is_numeric関数</a>などを用いて型を検証するか、許可した文字だけ通るようにするとよいでしょう。</li>
<li>壊れた文字エンコーディングによっても攻撃が可能なので、エスケープをするだけでは不十分。<a href="http://gihyo.jp/dev/serial/01/php-security/extra/001206" title="なぜPHPアプリにセキュリティホールが多いのか?：【スクリプトインジェクション対策06】入力文字列の文字エンコーディングを検証する|gihyo.jp … 技術評論社">入力文字列の文字エンコーディングが正しいものかチェック</a>を忘れないこと。なお、これは他の脆弱性でも同じ。</li>
</ul>
</dd>
<dt>IPAによる解説</dt>
<dd>
<ul>
<li><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/sql.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)/1. SQLインジェクション">IPA &#8211; 知っていますか?脆弱性：SQLインジェクション</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p7-10/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、SQLインジェクションの解説</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p51-56/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、SQLインジェクション対策の失敗例</a></li>
</ul>
</dd>
</dl>
<h4 id="t4e835e"><a href="http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0">クロスサイトスクリプティング</a><span class="weaken">（略称：XSS）</span></h4>
<p><img src="http://note.openvista.jp/download/2008/10/cross_site_scripting.png" alt="クロスサイト・スクリプティング" title="クロスサイト・スクリプティング" /></p>
<dl>
<dt>どんな脆弱性?</dt>
<dd>入力された文字列がHTML中に出力され、かつ文字参照に変換されない場合はHTMLとして解釈されるので、結果として任意のタグが出力可能（=任意の javascript が実行可能）になる脆弱性</dd>
<dt>どう対策する?</dt>
<dd>
<ul>
<li>全ての変数をエスケープする（<a href="http://jp.php.net/manual/ja/function.htmlspecialchars.php">htmlspecialchars関数</a>）</li>
<li>HTMLタグ中の属性値を<code>"</code><span class="weaken">（ダブルクオート）</span>で適切に囲む<span class="weaken">（セキュリティ以前の問題ですが）</span></li>
<li>文字エンコーディングが正しいものかチェックする。また<code>header("Content-type:text/html; charset=utf-8");</code>などとしてサーバ側で文字エンコーディングを確定させておく</li>
</ul>
</dd>
<dt>IPAによる解説</dt>
<dd>
<ul>
<li><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/xss.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)/2. クロスサイト・スクリプティング">IPA &#8211; 知っていますか?脆弱性：クロスサイト・スクリプティング</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p23-29/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、クロスサイト・スクリプティングの解説</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p57-67/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、クロスサイト・スクリプティング対策の失敗例</a></li>
</ul>
</dd>
</dl>
<h4 id="t254cc2"><a href="http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA">クロスサイトリクエストフォージェリ</a><span class="weaken">（略称：CSRF）</span></h4>
<p><img src="http://note.openvista.jp/download/2008/10/cross_site_request_forgeries.png" alt="クロスサイト・リクエスト・フォージュリ" title="クロスサイト・リクエスト・フォージュリ" /></p>
<dl>
<dt>どんな脆弱性?</dt>
<dd>あらかじめ特定のフォームにアクセスするように設定されたページをインラインフレームなどで読み込ませることで、掲示板に意図せず書き込ませることが出来るなど利用者の意図しないところでフォームが実行されてしまう脆弱性</dd>
<dt>どう対策する?</dt>
<dd>
<ul>
<li>第三者が知り得ない文字列<span class="weaken">（安全な乱数、詳細は<a href="http://d.hatena.ne.jp/leva/20081028/1225190931" title="安全な乱数とは何か on Hatena">こちらのご返信を書いたページ</a>を参照のこと）</span>をフォームに埋め込んでおき、サーバ側で照合することで、リクエストが利用者の意図した動作かどうかをチェックする</li>
<li>リファラをチェックし、空だったり、想定されうるページと違う場合エラーを返す<span class="weaken">（ただし、リファラは容易に偽装されうること、ファイアーウォールソフトなどでリファラが空になっている場合があることを考慮すること）</span></li>
</ul>
</dd>
<dt>IPAによる解説</dt>
<dd>
<ul>
<li><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/csrf.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)/3. CSRF (クロスサイト・リクエスト・フォージェリ)">IPA &#8211; 知っていますか?脆弱性：CSRF (クロスサイト・リクエスト・フォージェリ)</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p30-33/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、クロスサイト・リクエスト・フォージェリの解説</a></li>
</ul>
</dd>
</dl>
<h4 id="t3e4cb3"><a href="http://ja.wikipedia.org/wiki/%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%83%88%E3%83%A9%E3%83%90%E3%83%BC%E3%82%B5%E3%83%AB">ディレクトリトラバーサル</a></h4>
<p><img src="http://note.openvista.jp/download/2008/10/directory_traversal.png" alt="ディレクトリトラバーサル" title="ディレクトリトラバーサル" /></p>
<dl>
<dt>どんな脆弱性?</dt>
<dd>ファイルの要求にユーザ入力値が混じっている場合、例えば <code>../</code>などの入力値を混ぜることで、サーバ上の任意のファイル<span class="weaken">（パスワードファイルなど）</span>を閲覧できてしまう脆弱性。なお、ユーザ入力値を元にファイルを読み込んでいる場合、外部の攻撃用コードを読み込まれる<a href="http://gihyo.jp/dev/serial/01/php-security/0001">リモートファイル・インクルード脆弱性</a>も起こりうる</dd>
<dt>どう対策する?</dt>
<dd>
<ul>
<li>避けられる場合は、ファイルの読み込みにCGI入力値を含めることを避ける</li>
<li>そうでない場合は、まずパスを相対パスから絶対パスに変換 (<a href="http://jp.php.net/manual/ja/function.realpath.php">realpath関数</a>) し、そのパスが外部に公開してもよいフォルダかどうかを判定した上で、出力する<span class="weaken">（詳しくは<a href="http://labs.unoh.net/2007/11/post_108.html">ウノウラボ Unoh Labs: いまさら、ディレクトリトラバーサルについて語ってみる</a>を参照ください）</span></li>
</ul>
</dd>
<dt>IPAによる解説</dt>
<dd>
<ul>
<li><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/dt.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)/4. パス名パラメータの未チェック/ディレクトリ・トラバーサル">IPA &#8211; 知っていますか?脆弱性：パス名パラメータの未チェック/ディレクトリ・トラバーサル</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p14-16/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、パス名パラメータの未チェック/ディレクトリ・トラバーサルの解説</a></li>
<li><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/oscmd.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)/5. OS コマンド・インジェクション">IPA &#8211; 知っていますか?脆弱性：OS コマンド・インジェクション</a>（類似事例）</li>
<li><a href="http://pdf.openvista.jp/view/medium/p11-13/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">IPA『安全なウェブサイトの作り方』内、OS コマンド・インジェクションの解説</a></li>
</ul>
</dd>
</dl>
<h4 id="t6be0e9">サーバリソースを浪費させてしまう脆弱性</h4>
<p><img src="http://note.openvista.jp/download/2008/10/server_overflow.png" alt="サーバの処理増大" title="サーバの処理増大" /></p>
<dl>
<dt>どんな脆弱性?</dt>
<dd>異常な数値や異常に大きな外部データを読み込ませる（ループ回数を半無限に設定したり）ことで、処理を半無限に実行させることでサーバに大きな負荷をかける脆弱性<span class="weaken">（<a href="http://kaede.to/~canada/doc/never-say-sanitize#comment-398">おさかなラボ &#8211; サニタイズ言うなキャンペーン</a>参照のこと）</span></dd>
<dt>どう対策する?</dt>
<dd>
<ul>
<li>入力値が一定の範囲内に収まっているか検証する</li>
<li>外部のデータ（URL）を読み込む場合、上限のファイルサイズを常識的な値に設定する</li>
</ul>
</dd>
<dt>IPAによる解説</dt>
<dd><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/dos.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)/9. サービス運用妨害 (DoS)">IPA &#8211; 知っていますか?脆弱性：サービス運用妨害 (DoS)</a>
</dd>
</dl>
<h3 id="t95a9f7">いつ対策するか</h3>
<p><img src="http://note.openvista.jp/download/2008/10/http_request.png" alt="HTTPリクエストにおける変数の処理時期を示した図" title="HTTPリクエストにおける変数の処理時期を示した図" /></p>
<p>大きく、処理の最初期に値を処理する方法と問題が起こりうるとき<span class="weaken">（出力時やSQL文発行時）</span>に値を処理する方法があると思います。</p>
<h4 id="t9dff36">処理の最初期に処理する</h4>
<p>出力時に値を処理するという方法では、検証忘れによって抜け漏れが生じる可能性があり、脆弱性が生じる可能性を否定しきれません。ですので、入力値を処理の最初期で全てエスケープ<span class="weaken">（文字参照に変換）</span>し、HTMLとして出力する場合のみ文字参照を展開するという方法があり、具体的な方法は<a href="http://blog.webcreativepark.net/2008/10/24-201629.html">XSSの脆弱性を限りなくなくす方法：to-R</a>で紹介されています。</p>
<p>一方でこの方法に問題がないわけではありません。例えば、<a href="http://kaede.to/~canada/doc/never-say-sanitize">サニタイズ言うなキャンペーン：おさかなラボ</a>ではHTML出力やSQL文発行など脆弱性が発生しうる環境には様々なものがあることが挙げられており、<a href="http://gihyo.jp/dev/serial/01/php-security/0014?page=2">SQL文の扱いなど</a>単に入力値をエスケープしただけでは脆弱性を防げない事例も存在します。この方法は、入力時に処理を行ったことにより、出力時はあまり手をかけなくてよいと思いこんでしまう危険があり、結果として別の対策漏れを生んでしまう可能性があります。よって、この方法を用いるときは、単に文字エスケープしたことで安全と思いこむのではなく、<em>本当に用いる環境で安全になっているかどうか確認する</em>必要があります<sup><a href="http://note.openvista.jp/2008/php-security-memo/#footnote_1_931" id="identifier_1_931" class="footnote-link footnote-identifier-link" title="念のため。リンク先ではXSSを限りなく無くすことに言及しているのであって、他の脆弱性については何も言ってないわけですから、XSS対策においてリンク先に誤りがあるわけではないことを強調しておきます">2</a></sup> 。</p>
<p>また、リンク先でも言及されていますがscript要素やstyle要素内などの<a href="http://www.atmarkit.co.jp/aig/01xml/cdata.html">CDATA区間内</a>に出力した場合は脆弱性につながりますし、$_REQUESTグローバル変数は変換されていないのでこちらも注意が必要です。</p>
<p>その他、<a href="http://bakera.jp/ebi/topic/2986">「入力時に文字参照に変換するのがよろしくない理由」：水無月ばけらのえび日記</a>では、エスケープされた文字は処理に手間取ることも指摘されており、結果として二重手間となるのであれば、問題が起こる場所で適宜処理する方法が良いのではないかと思います。</p>
<h4 id="t8257b2">問題が起こりうる場所<span class="weaken">（出力時やクエリ発行時など）</span>に処理する</h4>
<p>ということで、次善の策としては、入力時にエスケープ処理を行うよりは、入力時に値の検証<span class="weaken">（<a href="http://gihyo.jp/dev/serial/01/php-security/extra/001214">ホワイトリスト方式を利用して必要な文字だけ許可する</a>といったような）</span>を行った上で、HTML出力時やSQLクエリ発行時など全ての問題が起こりうる箇所で対処するというのが次善の策となりそうです。もちろん、対処とはエスケープだけではなく<span class="weaken">（それでは防げない場合もあるので）</span><a href="http://gihyo.jp/dev/serial/01/php-security">環境に合わせた対策</a>も併せて行っていく必要があります。</p>
<p>以下では、その方法について簡単なものではありますが具体的なコードを示しておこうと思います。</p>
<h5 id="tff9709">許可した文字のみを通過させる</h5>
<p>以下は代表的な正規表現の例を示したものです。数字に関しては<a href="http://jp.php.net/manual/ja/function.is-numeric.php">is_numeric関数</a>を用いても良いと思います。</p>
<p>数字だけ許可する式</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span><span class="codes-code"> </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/^([0-9]+)$/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$user_input</span><span class="codes-code">, </span><span class="codes-var">$match</span><span class="codes-brackets">)){</span>
<span class="codes-code">  </span><span class="codes-var">$my_var</span><span class="codes-code"> = </span><span class="codes-var">$match</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">  </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">入力値は数字だけで構成してくださるようお願いいたします</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>英数字だけ許可する式</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span><span class="codes-code"> </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/^([a-zA-Z0-9]+)$/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$user_input</span><span class="codes-code">, </span><span class="codes-var">$match</span><span class="codes-brackets">)){</span>
<span class="codes-code">  </span><span class="codes-var">$my_var</span><span class="codes-code"> = </span><span class="codes-var">$match</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">  </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">入力値は英数字だけで構成してくださるようお願いいたします</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>英字だけ許可する式</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span><span class="codes-code"> </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/^([a-zA-Z]+)$/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$user_input</span><span class="codes-code">, </span><span class="codes-var">$match</span><span class="codes-brackets">)){</span>
<span class="codes-code">  </span><span class="codes-var">$my_var</span><span class="codes-code"> = </span><span class="codes-var">$match</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">  </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">入力値は英字だけで構成してくださるようお願いいたします</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>緯度・経度だけ許可する式</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span><span class="codes-code"> </span>
<span class="codes-comment">// 百分率形式。できれば度分秒形式との変換も行っておくこと</span>
<span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/^([0-9\.]+)$/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$user_input</span><span class="codes-code">, </span><span class="codes-var">$match</span><span class="codes-brackets">)){</span>
<span class="codes-code">  </span><span class="codes-var">$my_var</span><span class="codes-code"> = </span><span class="codes-var">$match</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">  </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">緯度・経度の値がおかしいです</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>【実践例】 URLで指定された範囲の価格に収まる商品データを取り出す例</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-comment">// PDOによるデータベース（price,dataの2カラム構成）の接続と</span>
<span class="codes-comment">// インスタンスの生成ができていると仮定</span>
<span class="codes-code"> </span>
<span class="codes-comment">// 価格の範囲を設定</span>
<span class="codes-reserved">foreach</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">low</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">high</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code"> </span><span class="codes-reserved">as</span><span class="codes-code"> </span><span class="codes-var">$range</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/^([0-9+])$/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$_GET</span><span class="codes-brackets">[</span><span class="codes-var">$range</span><span class="codes-brackets">]</span><span class="codes-code">, </span><span class="codes-var">$match</span><span class="codes-brackets">)){</span>
<span class="codes-code">    </span><span class="codes-var">$prices</span><span class="codes-brackets">[</span><span class="codes-var">$range</span><span class="codes-brackets">]</span><span class="codes-code"> = </span><span class="codes-var">$match</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-comment">// 数値かどうか検証</span>
<span class="codes-reserved">foreach</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$prices</span><span class="codes-code"> </span><span class="codes-reserved">as</span><span class="codes-code"> </span><span class="codes-var">$price</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">is_numeric</span><span class="codes-brackets">(</span><span class="codes-var">$price</span><span class="codes-brackets">)</span><span class="codes-code"> === </span><span class="codes-reserved">false</span><span class="codes-brackets">){</span>
<span class="codes-code">     </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">価格の設定がおかしいです</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-comment">// クエリを設定</span>
<span class="codes-var">$sql</span><span class="codes-code"> = </span><span class="codes-quotes">&quot;</span><span class="codes-string">SELECT * FROM '</span><span class="codes-var">{$dbName}</span><span class="codes-string">' WHERE </span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span>
<span class="codes-code">       </span><span class="codes-quotes">&quot;</span><span class="codes-string">price &gt; </span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">quote</span><span class="codes-brackets">(</span><span class="codes-var">$prices</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">low</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])</span><span class="codes-code">.</span><span class="codes-quotes">&quot;</span><span class="codes-string"> AND </span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span>
<span class="codes-code">       </span><span class="codes-quotes">&quot;</span><span class="codes-string">price &lt; </span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">quote</span><span class="codes-brackets">(</span><span class="codes-var">$prices</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">high</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-comment">// クエリを実行</span>
<span class="codes-reserved">try</span><span class="codes-brackets">{</span>
<span class="codes-code">  </span><span class="codes-var">$request</span><span class="codes-code"> = </span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">query</span><span class="codes-brackets">(</span><span class="codes-var">$sql</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">catch</span><span class="codes-brackets">(</span><span class="codes-identifier">PDOException</span><span class="codes-code"> </span><span class="codes-var">$exception</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">エラー（クエリ発行時）：</span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$exception</span><span class="codes-code">-&gt;</span><span class="codes-identifier">getMessage</span><span class="codes-brackets">())</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-var">$i</span><span class="codes-code"> = </span><span class="codes-number">0</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-comment">// データを取得して配列に格納</span>
<span class="codes-reserved">while</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$row</span><span class="codes-code"> = </span><span class="codes-var">$request</span><span class="codes-code">-&gt;</span><span class="codes-identifier">fetch</span><span class="codes-brackets">(</span><span class="codes-identifier">PDO</span><span class="codes-code">::</span><span class="codes-identifier">FETCH_ASSOC</span><span class="codes-brackets">)){</span>
<span class="codes-code">  </span><span class="codes-var">$results</span><span class="codes-brackets">[</span><span class="codes-var">$i</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">data</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code">  = </span><span class="codes-var">$row</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">data</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-var">$results</span><span class="codes-brackets">[</span><span class="codes-var">$i</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">price</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code"> = </span><span class="codes-var">$row</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">price</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-var">$i</span><span class="codes-code">++;</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-var">$results</span><span class="codes-code">;</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<h5 id="t2afd2b">エスケープ出力をデフォルトにする</h5>
<p>特別な場所だけ<a href="http://jp.php.net/manual/ja/function.htmlspecialchars.php">htmlspecialchars関数</a>を使い、そうでない場所にはecho や print_rなどの関数を使うという方法では抜け漏れが生じてしまうので、デフォルトでエスケープしたラッパー関数を使うとよいでしょう<span class="weaken">（エスケープする場合はshow関数、HTMLタグを出力したい場合はshow_tag関数を用いる）</span></p>
<p>つきつめるならば<span class="weaken">（どうしても使い慣れたechoを使ってしまうので）</span><a href="http://jp.php.net/manual/ja/function.echo.php">echo</a>や<a href="http://jp.php.net/manual/ja/function.print-r.php">print_r関数</a>を禁止できればいいのですが、どうもその方法が見つかりません。レンタルサーバでは難しいかもしれませんが、<a href="http://www.phppro.jp/phptips/archives/vol50/1">PHP組み込み関数を上書きする方法もあります</a>ので、こちらを用いてもよいかもしれません<sup><a href="http://note.openvista.jp/2008/php-security-memo/#footnote_2_931" id="identifier_2_931" class="footnote-link footnote-identifier-link" title="echoは関数ではなく言語構造なので、変更できないようですが">3</a></sup> 。</p>
<p>いずれにしろ、うっかり抜け漏れることをどう減らすかが焦点になりそうです。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-code"> </span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">encode</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">=</span><span class="codes-quotes">&quot;&quot;</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">is_array</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">)){</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-identifier">array_map</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">encode</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$str</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">elseif</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-identifier">htmlspecialchars</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">, </span><span class="codes-identifier">ENT_QUOTES</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">UTF-8</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-reserved">false</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">decode</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">=</span><span class="codes-quotes">&quot;&quot;</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">is_array</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">)){</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-identifier">array_map</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">decode</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$str</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">elseif</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-identifier">htmlspecialchars_decode</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">, </span><span class="codes-identifier">ENT_QUOTES</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">UTF-8</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-reserved">false</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">show_dump</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">=</span><span class="codes-quotes">&quot;&quot;</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-identifier">var_dump</span><span class="codes-brackets">(</span><span class="codes-identifier">encode</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">))</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-reserved">false</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">show_tag</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">=</span><span class="codes-quotes">&quot;&quot;</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-identifier">print_r</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-reserved">false</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">show</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-code">=</span><span class="codes-quotes">&quot;&quot;</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-identifier">print_r</span><span class="codes-brackets">(</span><span class="codes-identifier">encode</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">))</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-reserved">false</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<h5 id="ta4a27b">設定の確認と入力時検証を行う</h5>
<p><a href="http://gihyo.jp/dev/serial/01/php-security/0001">resiger_globals</a>の設定は有効になっている時に脆弱性になり得ますので、その場合はスクリプトを停止するように設定しておきます。また、<a href="http://d.hatena.ne.jp/teracc/20070125/1169722643">magic_quotes_gpcはエスケープが不完全</a>なので、これも同様に処置することにします。</p>
<p>加えて、壊れたShift_JISの文字によって起こる問題を防ぐため、文字エンコーディングが壊れたものになっていないかチェックします<span class="weaken">（出典：<a href="http://gihyo.jp/dev/serial/01/php-security/extra/001206" title="なぜPHPアプリにセキュリティホールが多いのか?：【スクリプトインジェクション対策06】入力文字列の文字エンコーディングを検証する|gihyo.jp … 技術評論社">gihyo.jp：なぜPHPアプリにセキュリティホールが多いのか?：【スクリプトインジェクション対策06】入力文字列の文字エンコーディングを検証する</a>）</span></p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-comment">/*** コンストラクタ ***/</span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">__construct</span><span class="codes-brackets">(){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-var">$inis</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span>
<span class="codes-code">    </span><span class="codes-quotes">&quot;</span><span class="codes-string">register_globals</span><span class="codes-quotes">&quot;</span><span class="codes-code">,</span>
<span class="codes-code">    </span><span class="codes-quotes">&quot;</span><span class="codes-string">magic_quotes_gpc</span><span class="codes-quotes">&quot;</span><span class="codes-code">,</span>
<span class="codes-code">  </span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-var">$user_inputs</span><span class="codes-code"> = </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-var">$_GET</span><span class="codes-code">, </span><span class="codes-var">$_POST</span><span class="codes-code">, </span><span class="codes-var">$_COOKIE</span><span class="codes-code">, </span><span class="codes-var">$_FILES</span><span class="codes-code">, </span><span class="codes-var">$_SERVER</span><span class="codes-code">, </span><span class="codes-var">$_SESSION</span><span class="codes-code">, </span><span class="codes-var">$_ENV</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">foreach</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$inis</span><span class="codes-code"> </span><span class="codes-reserved">as</span><span class="codes-code"> </span><span class="codes-var">$ini</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">ini_get</span><span class="codes-brackets">(</span><span class="codes-var">$ini</span><span class="codes-brackets">)){</span>
<span class="codes-code">      </span><span class="codes-identifier">trigger_error</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">このアプリケーションは</span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$ini</span><span class="codes-code">.</span><span class="codes-quotes">&quot;</span><span class="codes-string">=onの環境では動作しません</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-identifier">E_USER_ERROR</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">      </span><span class="codes-reserved">exit</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">foreach</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$user_inputs</span><span class="codes-code"> </span><span class="codes-reserved">as</span><span class="codes-code"> </span><span class="codes-var">$inputs</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$inputs</span><span class="codes-brackets">){</span>
<span class="codes-code">      </span><span class="codes-identifier">parent</span><span class="codes-code">::</span><span class="codes-identifier">input_encoding_check</span><span class="codes-brackets">(</span><span class="codes-var">$inputs</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-comment">/*** input_encoding_checkのコールバック関数 ***/</span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">input_encoding_check_cb</span><span class="codes-brackets">(</span><span class="codes-var">$k</span><span class="codes-code">, </span><span class="codes-var">$v</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-code">!</span><span class="codes-identifier">mb_check_encoding</span><span class="codes-brackets">(</span><span class="codes-var">$k</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">utf-8</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code"> || !</span><span class="codes-identifier">mb_check_encoding</span><span class="codes-brackets">(</span><span class="codes-var">$v</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">utf-8</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)){</span>
<span class="codes-code">    </span><span class="codes-identifier">trigger_error</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">不正な文字エンコーディングを検出しました</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-reserved">die</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">System detected some errors</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-comment">/*** ユーザ入力値のチェック ***/</span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">input_encoding_check</span><span class="codes-brackets">(</span><span class="codes-var">$v</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-identifier">array_walk_recursive</span><span class="codes-brackets">(</span><span class="codes-var">$v</span><span class="codes-code">, </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-var">$this</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">input_encoding_check_cb</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">))</span><span class="codes-code">;</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p><a href="http://www.phppro.jp/qa/detail.php?id=123" title="allow_url_include - PHPプロ!Q&amp;A掲示板">allow_url_include</a>,<a href="http://blog.ohgaki.net/allow_url_fopen" title="allow_url_fopen">allow_url_fopen</a>も脆弱性（リモートファイル・インクルード脆弱性）になりえますので無効にした方がよいのですが、こちらはユーザレベル（.htaccess）で無効に出来ないことも多いので、こちらは外しておきました。</p>
<p>なお、最初に挙げた2つの設定を無効にするには以下のような記述を.htaccessファイルに書いてください。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>ソースコード</em></div><pre class="source-code"><code>php_flag magic_quotes_gpc Off
php_flag register_globals Off</code></pre></div>
<h3 id="tdefc9a">参考にしたURL</h3>
<dl>
<dt>IPAのページ</dt>
<dd>
<ul>
<li><a href="http://www.ipa.go.jp/security/vuln/vuln_contents/index.html" title="情報処理推進機構：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)">情報処理推進機構（IPA）：セキュリティセンター：知っていますか?脆弱性 (ぜいじゃくせい)</a></li>
<li><a href="http://pdf.openvista.jp/view/medium/p1-5/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">情報処理推進機構（IPA）『安全なウェブサイトの作り方』</a></li>
</ul>
</dd>
<dt>コーディングやセキュリティ施策に対する認識を批判した一連の記事</dt>
<dd>なお、これについては<a href="http://journal.mycom.co.jp/articles/2005/07/12/wasf/" title="【レポート】セキュアなWebアプリ実現のために本来やるべきことは? - 高木浩光氏 | エンタープライズ | マイコミジャーナル">マイコミジャーナルの記事<span class="weaken">（の後半）</span></a>や以下の記事を読む限り、高木さんは脆弱性対策以前に、安全に処理が進むために本来されるべき検証作業が、「サニタイズせよ」という言葉が大きくなることで認識されにくくなっていることを批判しているのだとおおまかに理解しています。</dd>
<dd>
<ul>
<li><a href="http://takagi-hiromitsu.jp/diary/20051227.html#p02" title="高木浩光@自宅の日記 - プログラミング解説書籍の脆弱性をどうするか, 「サニタイズ言うなキャンペーン」とは何か, ASPとかJSPとかPHPとかERBとか、逆だ..">高木浩光@自宅の日記：「サニタイズ言うなキャンペーン」とは何か</a></li>
<li><a href="http://takagi-hiromitsu.jp/diary/20051231.html#p02" title="高木浩光@自宅の日記 - 「逆」にしたERBが登場, 要約版：「サニタイズ言うなキャンペーン」とは, 既にここまで来ている――サニタイズ症候群の末期的惨..">高木浩光@自宅の日記：要約版「サニタイズ言うなキャンペーン」とは</a></li>
<li><a href="http://takagi-hiromitsu.jp/diary/20060115.html" title="高木浩光@自宅の日記 - 続・「サニタイズ言うなキャンペーン」とは">高木浩光@自宅の日記：続・「サニタイズ言うなキャンペーン」とは</a></li>
<li><a href="http://bakera.jp/ebi/topic/2473" title="「サニタイズ言うなキャンペーンがわかりにくい理由」@水無月ばけらのえび日記">水無月ばけらのえび日記：「サニタイズ言うなキャンペーンがわかりにくい理由」</a></li>
<li><a href="http://kaede.to/~canada/doc/never-say-sanitize" title="おさかなラボ - サニタイズ言うなキャンペーン">おさかなラボ：サニタイズ言うなキャンペーン</a></li>
</ul>
</dd>
<dt>入力時エスケープ処理に対する方法と是非</dt>
<dd>
<ul>
<li><a href="http://blog.webcreativepark.net/2008/10/24-201629.html" title="XSSの脆弱性を限りなくなくす方法[to-R]">to-R：XSSの脆弱性を限りなくなくす方法</a></li>
<li><a href="http://bakera.jp/ebi/topic/2986" title="「入力時に文字参照に変換するのがよろしくない理由」@水無月ばけらのえび日記">水無月ばけらのえび日記：「入力時に文字参照に変換するのがよろしくない理由」</a></li>
<li><a href="http://ukstudio.jp/2008/10/27/xss/" title="UK STUDIO - XSS対策に入力時エスケープは非常にややこしい">UK STUDIO：XSS対策に入力時エスケープは非常にややこしい</a></li>
</ul>
</dd>
<dt>その他セキュリティ施策関連の記事</dt>
<dd>
<ul>
<li><a href="http://www.e-3lab.com/security_guideline/" title="セキュリティガイドライン">イースリーラボ：セキュリティガイドライン</a></li>
<li><a href="http://d.hatena.ne.jp/rytich/20071017/1192603380" title="SQLインジェクション,XSS対策 - [foool]丘の上">[foool]丘の上：SQLインジェクション,XSS対策</a></li>
<li><a href="http://gihyo.jp/dev/serial/01/php-security" title="連載：なぜPHPアプリにセキュリティホールが多いのか?|gihyo.jp … 技術評論社">gihyo.jp：連載ーなぜPHPアプリにセキュリティホールが多いのか?</a></li>
</ul>
</dd>
</dl>
<h3 id="t3a284a">読者のコメントとご返信</h3>
<blockquote cite="http://b.hatena.ne.jp/HiromitsuTakagi/20081027#bookmark-10564691" title="id:HiromitsuTakagiさんのブックマーク">
<p>「というわけでHTML出力時やSQLクエリ発行時など全ての問題が起こりうる箇所で対処するというのが次善の策」< 逆。入力でも何かする策の方が「次善」。IPAの「安全なウェブサイトの作り方」を読んでないと思われる。</p>
<p class="citation"><a href="http://b.hatena.ne.jp/HiromitsuTakagi/20081027#bookmark-10564691"><cite>id:HiromitsuTakagiさんのブックマーク</cite></a></p>
</blockquote>
<p>はい、読んでないというか知らなかったので早速<a href="http://pdf.openvista.jp/view/medium/p1-5/http://www.ipa.go.jp/security/vuln/documents/website_security.pdf" title="PDFリーダ（website_security.pdf）">読ませていただきました</a>。<q>入力でも何かする策</q>というのはこちらでは具体的に値が想定されうる物かチェックする（ホワイトリスト）くらいしか思い浮かばないのですが、ほかにやるべき検証方法がありましたら教えてください。</p>
<blockquote cite="http://b.hatena.ne.jp/jukuin2000/20081027#bookmark-10564691" title="id:jukuin2000さんのブックマーク">
<p>高木先生も仰っているが、XSS対策に関しては出力時に処理するのが最善の策。最初期にやるのが次善の策。手前味噌で恐縮ですが、こちらも参考にどうぞ → 「http://www.e-3lab.com/security_guideline/」</p>
<p class="citation"><a href="http://b.hatena.ne.jp/jukuin2000/20081027#bookmark-10564691"><cite>id:jukuin2000さんのブックマーク</cite></a></p>
</blockquote>
<p>ありがとうございます。IPAのもそうですが、私のより数段詳しくて信頼がおけますね。</p>
<blockquote cite="http://b.hatena.ne.jp/shinpei0213/20081027#bookmark-10564691" title="id:shinpei0213さんのブックマーク">
<p>「第三者が知り得ない文字列（ID・パスワードやワンタイムトークンなど）をフォームに埋め込んでおき」!? id/passをフォームに埋め込むってあんた!有害記事。</p>
<p class="citation"><a href="http://b.hatena.ne.jp/shinpei0213/20081027#bookmark-10564691"><cite>id:shinpei0213さんのブックマーク</cite></a></p>
</blockquote>
<p>うーん、確かになんでこんなこと書いちゃったのか。ありがとうございます、ハッシュ関数を用いて擬似乱数化するよう訂正しました。</p>
<blockquote cite="http://b.hatena.ne.jp/courant/20081027#bookmark-10564691" title="id:courantさんのブックマーク">
<p>文字エンコーディングの検証もいれておいたいいかもset names問題。</p>
<p class="citation"><a href="http://b.hatena.ne.jp/courant/20081027#bookmark-10564691"><cite>id:courantさんのブックマーク</cite></a></p>
</blockquote>
<p><a href="http://nonn-et-twk.net/twk/why-set-names-in-php-is-bad">PHPからSET NAMESを使わない方が良い理由と対策まとめ：twk @ ふらっと</a>というページを見つけました。最初に行っている文字エンコーディングチェックで問題ないように思うのですが、不十分でしょうか。</p>
<blockquote cite="http://b.hatena.ne.jp/h_narazaki/20081027#bookmark-10564691" title="id:h_narazakiさんのブックマーク">
<p>入力時のエスケープはやめたほうがいいです。全てにおいて出力の直前にやるのが基本。</p>
<p class="citation"><a href="http://b.hatena.ne.jp/h_narazaki/20081027#bookmark-10564691"><cite>id:h_narazakiさんのブックマーク</cite></a></p>
</blockquote>
<p>それは皆さんご指摘いただくことなのですが、決まって理由は一緒に書かれていなかったりする<span class="weaken">（探した中では<a href="http://bakera.jp/ebi/topic/2986" title="「入力時に文字参照に変換するのがよろしくない理由」@水無月ばけらのえび日記">水無月ばけらさんのページ</a>くらいしかみつかりませんでした、結論だけ一人歩きしているような感じすらします）</span>ので、理由が書かれたURLを示していただけると助かります。<ins>→だいたい、示した内容で理由として問題なさそうですね。</ins></p>
<blockquote cite="http://b.hatena.ne.jp/at_yasu/20081027#bookmark-10564691" title="id:at_yasuさんのブックマーク">
<p> $_POST|GETだけじゃなくて、$_SESSION|COOKIEも組み合わせて話せばもっと良い鴨</p>
<p class="citation"><a href="http://b.hatena.ne.jp/at_yasu/20081027#bookmark-10564691"><cite>id:at_yasuさんのブックマーク</cite></a></p>
</blockquote>
<p>ですね。追記しておきます。</p>
<blockquote cite="http://b.hatena.ne.jp/HiromitsuTakagi/20081028#bookmark-10584483" title="はてなブックマーク - HiromitsuTakagiのブックマーク / 2008年10月28日">
<p><q>第三者が知り得ない文字列（ユーザIDやワンタイムトークンなど）を ハッシュ関数（md5関数やsha1関数）を複数回用いて擬似乱数化</q>&lt; 安全な乱数を理解していない。/ わからないことは「わからない」と書いた方が良い。</p>
<p class="citation"><a href="http://b.hatena.ne.jp/HiromitsuTakagi/20081028#bookmark-10584483"><cite>id:HiromitsuTakagiさんのブックマーク</cite></a></p>
</blockquote>
<p>お返事が長くなったので、<a href="http://d.hatena.ne.jp/leva/20081028/1225190931" title="安全な乱数とは何か on Hatena">はてなダイアリーに書きました</a>。結論から言えば<code>&lt;?php $var = bin2hex(mhash(MHASH_SHA512, 'hoge hoge')); ?&gt;</code>で、だいたい安全な乱数が生成できるのではないかと。</p>
<blockquote cite="http://b.hatena.ne.jp/HiromitsuTakagi/20081028#bookmark-10584414" title="id:HiromitsuTakagiさんのブックマーク"><p>
まだサニタイズ脳の呪縛から解かれていないもよう。たとえば <a href="http://note.openvista.jp/?s=%3Cs%3E" target="_blank">http://note.openvista.jp/?s=%3Cs%3E</a> で「この検索結果の続きを見る」のリンク先がおかしくなるのはなぜか。</p>
<p class="citation"><a href="http://b.hatena.ne.jp/HiromitsuTakagi/20081028#bookmark-10584414" title="id:HiromitsuTakagiさんのブックマーク"><cite>id:HiromitsuTakagiさんのブックマーク</cite></a></p>
</blockquote>
<p>この記事を書いて勉強したので、これ以前に書いたコードのうちで正しくない箇所もありましょうが、それもまぁぼちぼち再点検していこうと思います。ありがとうございます。</p>
<h3 id="t5edd4e">更新履歴</h3>
<p>この記事は、読者のフィードバックにより内容を大幅に加筆修正する可能性があるため、更新履歴を附記しておきます。</p>
<dl class="update">
<dt>2008-10-28</dt>
<dd>CSRF対策としての乱数生成過程を修正</dd>
<dd>タイトルを修正</dd>
<dt>2008-10-27</dt>
<dd>CSRFに関するトークン埋め込み対策に追記</dd>
<dd>問題が起こりうる場所での対策方法を修正</dd>
<dd>文字エンコーディングのチェック方法を示したコードを修正</dd>
<dd>それぞれの脆弱性にIPAの解説ページを附記</dd>
<dd>読者の反応とそれに対する返信を追記</dd>
<dt>2008-10-26</dt>
<dd>初版公開</dd>
</dl>
<ol class="footnotes"><li id="footnote_0_931" class="footnote">一般には「準備された文」と言われるみたいです。これを使う際は、DBのバインド機構を使うことになります（<a href="http://www.thinkit.co.jp/cert/trend/24/1/2.htm">バインド機構はこちらで解説されてます</a>。ただし、準備済みのクエリ文を用いてもクエリが安全でない環境があるので注意</li><li id="footnote_1_931" class="footnote">念のため。リンク先では<em>XSSを</em>限りなく無くすことに言及しているのであって、他の脆弱性については何も言ってないわけですから、XSS対策においてリンク先に誤りがあるわけではないことを強調しておきます</li><li id="footnote_2_931" class="footnote">echoは関数ではなく言語構造なので、変更できないようですが</li></ol><img src="http://note.openvista.jp/?ak_action=api_record_view&id=931&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/php-security-memo/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PDFをウェブページとしてチェックできるようにして離脱を減らそう</title>
		<link>http://note.openvista.jp/2008/online-pdf-reader/</link>
		<comments>http://note.openvista.jp/2008/online-pdf-reader/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 20:44:56 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ウェブサービスの制作]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>
		<category><![CDATA[ユーザビリティ]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=883</guid>
		<description><![CDATA[PDFをウェブページ上に表示できるようにするサービスを利用して、閲覧者がページから離脱するのをなんとか減らしていこうという試み]]></description>
			<content:encoded><![CDATA[<p><amazon>4903065065, caption</amazon></p>
<p>PDFファイルは昔からブラウザ上の表示には難がありました。動作が重く、ブラウザを固まらせたり、ブラウザ側のコントロールGUIを全く別のものにすげ替えてしまったり…。詳しいところは<a href="http://www.usability.gr.jp/alertbox/20030714.html">ニールセン氏のコラム</a>に譲りますが、そのせいでPDFファイルにリンクを張るのをためらうこともあります。読み手としても「詳細はPDFで」なんて言われたら面倒くさくなってタブを閉じる人もいるでしょう。</p>
<p>これに対する対策として、ニールセン氏は<a href="http://www.usability.gr.jp/alertbox/20030728.html">要約を記したゲートウェイ・ページを用意しておこう</a>と仰っているのですが、これでは不十分でしょう。というのは、これはあくまで「ショック」を和らげるだけでしかなく、先のリンク先で挙げたユーザビリティ問題が棚上げされているからです<sup><a href="http://note.openvista.jp/2008/online-pdf-reader/#footnote_0_883" id="identifier_0_883" class="footnote-link footnote-identifier-link" title="「最善は善の敵」という現場のコストを考えた彼の主張の一貫性には納得していますが">1</a></sup></p>
<p>彼の言うようにPDFが<q>印刷物に合わせたテキスト</q>である以上、問題の完全な解決は難しいかと思いますが、一方で解決できる問題も結構あるんじゃないか、ということで今回試しに作ってみたのが<a href="http://pdf.openvista.jp/">オンラインPDFリーダ</a>です。</p>
<p>えっと、じゃデモとして試しに適当なPDFを表示してみましょう…。最近読んだ<a href="http://egamiday3.seesaa.net/article/107645749.html">図書館蔵書検索の論文PDF</a>にしましょうか。</p>
<p class="center"><a href="http://pdf.openvista.jp/view/medium/p1-19/http://www.jstage.jst.go.jp/article/johokanri/51/7/480/_pdf/-char/ja/"><img src="http://note.openvista.jp/download/2008/10/pdfviewer-screenshot.png" alt="オンラインPDFリーダのスクリーンショット" title="オンラインPDFリーダのスクリーンショット" /></a></p>
<p>ウェブページを普通に表示するときほど可読性は良くないのですが、それでもいくつかの問題は解決できてるんじゃないでしょうか。</p>
<dl>
<dt>ブラウザが固まってしまう問題</dt>
<dd>変換に時間がかかることはあっても、固まることはないでしょう(巨大なファイルを一気に変換しようとしない限り)</dd>
<dt>ブラウザ側のコントロールをすげ替えられてしまう問題</dt>
<dd>言うに及ばず。</dd>
<dt>検索できない問題</dt>
<dd>内容からテキストを抜き出して掲載しているので、ブラウザ標準の検索機能で検索できるようになっています。試しに<a href="http://pdf.openvista.jp/view/medium/p1-19/http://www.jstage.jst.go.jp/article/johokanri/51/7/480/_pdf/-char/ja/">先のPDF</a>で「とりすぎず」で検索してみてください。</dd>
<dt>コンテンツの単位が大きすぎて、部分部分にリンクを張れない問題</dt>
<dd>ページ指定が出来るので、ページの一部分だけをウェブページとして抽出することが出来ます。例えば、<a href="http://pdf.openvista.jp/view/medium/p3/http://www.jstage.jst.go.jp/article/johokanri/51/7/480/_pdf/-char/ja/">3ページ目だけ</a>とか<a href="http://pdf.openvista.jp/view/medium/p3-10/http://www.jstage.jst.go.jp/article/johokanri/51/7/480/_pdf/-char/ja/">3ページ目から10ページ目まで</a>という表示方法ができます。</dd>
</dl>
<p>大きさも3段階で変えることができます。「小さい」はざっと全体を眺める場合、「普通」は通常のプレビューとして、「大きい」はPDFをブラウザ上で全部読みたい場合に向いています。</p>
<div class="aside">
<p>本当はサムネイルを動的に生成するプログラムを併用して、このサイトで使っているスライダーコントロールのように画像の大きさを動的に変えるのが、一番直感的で望ましいかと思います<span class="weaken">(大きな画像を出力しておいてそのサイズを切り替える)</span>。が、実際に試してみたところ以下のように文字がぼやけてしまって、可読性がさらに悪くなるみたいで本末転倒になりそうなのでやめておきました。</p>
<p><img src="http://note.openvista.jp/download/2008/10/comparison.png" alt="表示画像の比較" title="表示画像の比較" /></p>
</div>
<p>なお、動作としてページ指定が無い場合は最初の5ページ<span class="weaken">(PDFが5ページ未満の場合、そのページ数だけ)</span>だけ表示しています。これは全ページを変換してしまうと処理時間がかかりすぎてしまうためです。これについては、今後ページを少し読み込んでおいて、後から動的に追加していくことで、体感速度を早くしていこうと思っています。</p>
<h3 id="t9728fa">汎用PDFゲートウェイとしてオンラインPDFリーダを使う</h3>
<p>と、ここまで書いてから<a href="http://pdfmenot.com/">PdfMeNot.com</a>というほとんど同じサービスがあることに気づきましたorz<span class="weaken">(ただ、こちらはFlashを使っていて検索ができないほか、拡張子にPDFが付いていない場合はPDFとして認識されないようです)</span></p>
<p>さて、こちらのサービスではブックマークレットやブロガー向けのPDFリンク書き換えスクリプトなど<a href="http://pdfmenot.com/tools/">サービスを汎用PDFゲートウェイとして使えるようなツールを提供している</a>ようなのですが、私もそれに倣ってみることにします<span class="weaken">(コードが短いので、ある程度参考にさせていただきました)</span></p>
<h4 id="te4fbce">ウェブ利用者向け</h4>
<h5 id="t432d0b">GreaseMonkeyスクリプト</h5>
<p>Firefoxブラウザで<a href="http://ja.wikipedia.org/wiki/Greasemonkey">Greasemonkey</a>アドオンがインストールされている場合、以下のスクリプトをインストールすることで、リンク先末尾に「.pdf」が付くリンクを自動的にオンラインPDFリーダーへのそれに変換します。</p>
<p class="center"><a href="http://pdf.openvista.jp/redirect_pdf_gateway.user.js">GreaseMonkeyスクリプト</a></p>
<h5 id="tbff7be">ブックマークレット</h5>
<p>リンク先末尾に「.pdf」が付くリンクをオンラインPDFリーダーへのそれに変換します。ご使用の際は、まず以下のリンクをブックマークに入れてください。その後は、そのブックマークをクリックするとご使用いただけます。</p>
<p class="center"><a href="javascript:(function(){var%20l=document.getElementsByTagName('a'),%20r%20=%20new%20RegExp('\\.pdf$','i');for%20(var%20i=0;%20i<l.length;%20i++)%20if%20(r.test(l[i].getAttribute('href')))%20{%20l[i].href='http://pdf.openvista.jp/view/'+l[i].href;}%20})()" onclick="alert('ご使用の際は、まずこのリンクをブックマークに入れてください');">ブックマークレット</a></p>
<h4 id="t330255">ウェブ制作者向け</h4>
<p>以下のタグを &lt;head&gt;タグ内に書き込むことで、リンク先末尾に「.pdf」が付くリンクをオンラインPDFリーダーへのそれに自動的に変換します。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>HTMLソースコード</em></div><pre class="source-code"><code><span class="codes-brackets">&lt;</span><span class="codes-reserved">script</span><span class="codes-code"> </span><span class="codes-var">src</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">http://pdf.openvista.jp/pdfconvert.js</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-var">type</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">text/javascript</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-var">charset</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">utf-8</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;&lt;/</span><span class="codes-reserved">script</span><span class="codes-brackets">&gt;</span></code></pre></div>
<h3 id="tcb9632">その他の情報</h3>
<h4 id="t1e20f5">URLの構成</h4>
<p>オンラインPDFリーダのURLは以下のようなルールで出来ています。</p>
<p class="titlize">http://pdf.openvista.jp/[サイズ]/[ページ指定]/[PDFのURL]</p>
<dl>
<dt>サイズ</dt>
<dd>省略可。<var>small</var>(小さい), <var>medium</var>(普通), <var>large</var>(大きい)のいずれか</dd>
<dt>ページ指定</dt>
<dd>省略可<span class="weaken">(その場合は最初の5ページを表示)</span>。<var>p1</var>のような感じでページを表示ページを指定できる。<var>p1-5</var>といったように複数ページを指定することも出来る。</dd>
<dt>PDFのURL</dt>
<dd>必須。PDFのURLを指定してください。</dd>
</dl>
<h4 id="t887ba8">更新履歴</h4>
<dl class="update">
<dt>2009-01-20</dt>
<dd>最新のPDFファイルを取得し直す機能を追加</dd>
<dd>キャッシュしたPDFを検索エンジンが取得しないように設定</dd>
<dt>2008-10-20</dt>
<dd>フォントをより美しいものに差し替えました</dd>
<dd>表示サイズをより大きくしました</dd>
<dt>2008-10-18</dt>
<dd>一部のPDFにおいて文字が表示できない問題を解消しました</dd>
<dt>2008-10-12</dt>
<dd>使用するPDF表示ライブラリを変更の副作用で、一部のPDFファイルが検索できるようになりました</dd>
<dt>2008-10-11</dt>
<dd>初リリース</dd>
</dl>
<h4 id="t582839">実装予定の機能</h4>
<ul>
<li>Googleブック検索ライクな埋め込みプレーヤーの提供</li>
<li>ページの動的追加</li>
</ul>
<h4 id="t2e639c">参考にしたリンク</h4>
<p>今回のサービスは<del><a href="http://ja.wikipedia.org/wiki/Xpdf">Xpdf</a></del><ins><a href="http://ja.wikipedia.org/wiki/Poppler">Poppler</a></ins>というオープンソースのPDFリーダライブラリを利用させていただきました。素晴らしいライブラリを作られた作者さんに感謝。</p>
<p><ins datetime="2008-10-12T23:30:56+09:00" class="block"></p>
<blockquote cite="http://b.hatena.ne.jp/ttamo/20081011#bookmark-10358811" title="id:ttamoさんのブックマーク">
<p>いいかも。ただpopplerじゃなくてxpdfなのは何故なんだぜまあxpdfも「終わった」わけじゃないのかもしらんが</p>
<p class="citation"><a href="http://b.hatena.ne.jp/ttamo/20081011#bookmark-10358811"><cite>id:ttamoさんのブックマーク</cite></a></p>
</blockquote>
<p>それは単に知らなかっただけですよ。試しに変えてみたら、コピー不可のPDFファイルも表示できるようになったのでこちらにしておきます。<br />
</ins></p>
<ul class="links">
<li><a href="http://mytexpert.sourceforge.jp/index.php?%A5%C1%A5%E5%A1%BC%A5%C8%A5%EA%A5%A2%A5%EB%2FPDF%A4%CE%C1%E0%BA%EE">チュートリアル/PDFの操作 &#8211; MyTeXpert</a></li>
<li><a href="http://mytexpert.sourceforge.jp/index.php?pdftoppm">pdftoppm &#8211; MyTeXpert</a></li>
<li><a href="http://bakera.jp/ebi/topic/739">「PDF をダウンロードさせる」@水無月ばけらのえび日記</a></li>
<li><a href="http://blog.firstlife.jp/2008/05/18/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E4%B8%8A%E3%81%A7pdf%E3%82%92html%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B/">渋谷でサボるエンジニアの日記» ブログアーカイブ » サーバー上でPDFをHTMLに変換する</a></li>
</ul>
<h4 id="te4a162">謝辞</h4>
<p>以下のサイトからアイコンをお借りしました</p>
<ul>
<li><a href="http://mayosoft.net/studio/">Mayosoft® Studios</a></li>
<li><a href="http://dryicons.com/free-icons/preview/aesthetica-version-2/">DryIcons | Free Icons | Aesthetica 2.0 Icon Set</a></li>
</ul>
<ol class="footnotes"><li id="footnote_0_883" class="footnote">「最善は善の敵」という現場のコストを考えた彼の主張の一貫性には納得していますが</li></ol><img src="http://note.openvista.jp/?ak_action=api_record_view&id=883&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/online-pdf-reader/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>新しいGoogle Book Search（ブック検索） APIを試してみる</title>
		<link>http://note.openvista.jp/2008/trying-google-book-search-api/</link>
		<comments>http://note.openvista.jp/2008/trying-google-book-search-api/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 21:05:20 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=822</guid>
		<description><![CDATA[新しくなったGoogleブック検索APIを一通り触ってみました]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.itmedia.co.jp/news/articles/0809/23/news005.html" title="Google、書籍検索結果や書評をサイトに組み込めるAPIを公開 - ITmedia News">Google ブック検索に検索結果や書評をサイト上に組み込めるAPIが新たに追加</a>されました。まず、このAPIなんですが、以下のように3つのAPIから構成されています。</p>
<blockquote cite="http://current.ndl.go.jp/node/8877" title="Google Book Searchに新API－ウェブサイト内での表示や全文検索、データ収集・更新も可能に | カレントアウェアネス・ポータル">
<ul>
<li>ISBN、OCLC番号、LC番号等で特定した書籍のGoogle Book Search内データを、自分のウェブサイトに取り込んで（embed）表示できる&#8221;Embedded Viewer API&#8221;</li>
<li>Google Book Search内のデータの全文検索、書誌データやユーザが付与したレビュー・レイティング・タグ等のデータの収集、自分が付与したデータの編集ができる&#8221;Data API&#8221;</li>
<li>従来は&#8221;Book Viewability API&#8221;と呼ばれていた、Google Book Searchのデータにリンクを貼ることができる&#8221;Dynamic Links&#8221;（<a href="http://current.ndl.go.jp/e764">E764</a>参照）</li>
</ul>
<p class="citation"><a href="http://current.ndl.go.jp/node/8877" title="Google Book Searchに新API－ウェブサイト内での表示や全文検索、データ収集・更新も可能に | カレントアウェアネス・ポータル"><cite>Google Book Searchに新API－ウェブサイト内での表示や全文検索、データ収集・更新も可能に | カレントアウェアネス・ポータル</cite></a></p>
</blockquote>
<p>以前から書籍の公開レベルが取得できるAPIを公開していたようなんですが、今回埋め込みビューワのAPIが公開されたことで、格段に利用しやすくなったと思います<span class="weaken">（いずれもAPIキーが必要ないので、とても手軽に利用できます）</span></p>
<p><a href="http://code.google.com/apis/books/docs/getting-started.html" title="Getting Started Guide - Google Book Search APIs - Google Code">API利用ドキュメント</a>は平易かつ簡潔に書かれているので、あえて解説する必要はないと思うのですが、学習がてらにちょっと書いてみましょうか。</p>
<div class="toc">
<ol>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#t07d517">動的リンク（&#8221;Dynamic Links&#8221;）</a></p>
<ol>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#tecbae4">コード例</a></li>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#tb67983">実行例</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#t8fea43">ブックビューワ埋め込みAPI （&#8221;Embedded Viewer API&#8221;）</a>
<ol>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#te08620">コード例</a></li>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#tb19e86">実行例</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#ta316cf">全文検索 &amp; メタデータ編集API（&#8221;Data API&#8221;）</a>
<ol>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#t6af9a5">コード例</a></li>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#t1828f3">実行例</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#t5edab3">感想</a></li>
</ol>
</div>
<h3 id="t07d517">動的リンク（&#8221;Dynamic Links&#8221;）</h3>
<p><a href="http://code.google.com/apis/books/docs/dynamic-links.html" title="Dynamic Links - Google Book Search APIs - Google Code">Google Codeでの仕様解説ページ</a></p>
<p>書籍のプレビューは著作権や出版社との交渉によりできたり、できなかったりします。</p>
<p>単にハイパーリンクを用いて書籍の詳細ページに（詳細の有無にかかわらず）リンクする静的リンク（&#8221;Static Links&#8221;）では、いざプレビュー出来なかったときに閲覧者をがっかりさせてしまいますが、動的リンク（&#8221;Dynamic Links&#8221;）ではその公開レベルなどの情報が入手できるので、例えば「全文公開されている書籍のみGoogle Booksにリンクする」など柔軟にリンクを生成できます。</p>
<p>公開レベルは以下の3つが設定されています。なお、アメリカでは見られるのに日本では見られないといったように、アクセス元の位置により別々の公開レベルが設定されることもあるようです。</p>
<dl>
<dt>全文公開（full）</dt>
<dd>パブリック・ドメインの書籍など全文が公開されている書籍を指します</dd>
<dt>部分プレビュー(partial)</dt>
<dd>スキャンがされた書籍で、その一部分をプレビューすることが出来ます</dd>
<dt>スニペットビューあるいはプレビューなし(noview)</dt>
<dd>&#8220;snippets&#8221;とは切り取られた断片という意味で、これはスキャンがなされていないか著作元からの許可が得られないなどの関係で、これらの書籍には解説くらいしか載せられていません</dd>
</dl>
<p>方法としてはJavascriptを使って、書籍の情報を以下のようにJSONオブジェクトで受け取ります。その際、コールバック関数を呼ぶことも出来ます。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>JAVASCRIPTソースコード</em></div><pre class="source-code"><code><span class="codes-identifier">JsonSearchResult</span><span class="codes-code"> </span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-comment">// ※書籍の識別子。大抵はISBNが設定されているようです</span>
<span class="codes-code">    </span><span class="codes-identifier">string</span><span class="codes-code"> </span><span class="codes-identifier">bib_key</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-comment">// ※Google Books上の詳細ページのURL</span>
<span class="codes-code">    </span><span class="codes-identifier">string</span><span class="codes-code"> </span><span class="codes-identifier">info_url</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-comment">// ※書籍がプレビューできるページのURL。無いときもあるようです</span>
<span class="codes-code">    </span><span class="codes-identifier">string</span><span class="codes-code"> </span><span class="codes-identifier">preview_url</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-comment">// ※書籍カバー画像のURL</span>
<span class="codes-code">    </span><span class="codes-identifier">string</span><span class="codes-code"> </span><span class="codes-identifier">thumbnail_url</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-comment">// ※公開レベル、full / partial / noview の三段階</span>
<span class="codes-code">    </span><span class="codes-identifier">string</span><span class="codes-code"> </span><span class="codes-identifier">preview</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-comment">// ※ 書籍が外部に埋め込み可能であれば true となる</span>
<span class="codes-code">    </span><span class="codes-reserved">boolean</span><span class="codes-code"> </span><span class="codes-identifier">embeddable</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span><span class="codes-code">;</span></code></pre></div>
<p>Javascriptは以下のようなURLで呼び出します。こちらが指定する部分はbibkeysパラメータとcallbackパラメータ（コールバック関数）くらいですね。</p>
<p class="titlize">&lt;script src=&#8221;http://books.google.com/books?bibkeys=ISBN:4873112834&amp;jscmd=viewapi&amp;callback=mycallback&#8221;&gt;&lt;/script&gt;</p>
<p>動的リンクはもちろん、Javascriptで処理するのが筋かと思いまし、ドキュメント中でもサーバサイドでの処理を考えてデザインしていないと書かれていますが、PHPでは json_decode という関数があるので、これを用いて結果のJSON形式をオブジェクトか連想配列で受け取ることが出来ます。</p>
<p>ちなみに、このAPIには<a href="http://code.google.com/apis/books/branding.html">ブランディングガイドライン</a>があり、<a href="http://code.google.com/apis/books/examples/translated-branding-elements.html">指定された用語</a>を使わないといけないようです。例えば、書籍のプレビューを「ダウンロード」や「立ち読み」などと言うのはNGのようです。</p>
<h4 id="tecbae4">コード例</h4>
<p>少し例を書いてみると以下のようになります。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-var">$isbn</span><span class="codes-code"> = </span><span class="codes-quotes">&quot;</span><span class="codes-string">4873112834</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-var">$json</span><span class="codes-code"> = </span><span class="codes-identifier">file_get_contents</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">http://books.google.com/books?bibkeys=ISBN:</span><span class="codes-var">{$isbn}</span><span class="codes-string">&amp;jscmd=viewapi</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-comment">// json_decodeに仕事させるために必要な処理</span>
<span class="codes-var">$json</span><span class="codes-code"> = </span><span class="codes-identifier">str_replace</span><span class="codes-brackets">(</span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-special">\\</span><span class="codes-string">x26</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">;</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">var _GBSBookInfo = </span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">, </span><span class="codes-reserved">array</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">&amp;</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;&quot;</span><span class="codes-brackets">)</span><span class="codes-code">, </span><span class="codes-var">$json</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-comment">// オブジェクトに変換</span>
<span class="codes-var">$book</span><span class="codes-code"> = </span><span class="codes-identifier">json_decode</span><span class="codes-brackets">(</span><span class="codes-var">$json</span><span class="codes-code">, </span><span class="codes-reserved">true</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$book</span><span class="codes-code"> = </span><span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">ISBN:</span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$isbn</span><span class="codes-brackets">]</span><span class="codes-code">;</span>
<span class="codes-comment">// サムネイルのサイズを大きくする</span>
<span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">thumbnail_url</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code"> = </span><span class="codes-identifier">preg_replace</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/zoom=\d/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">zoom=1</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">thumbnail_url</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])</span><span class="codes-code">;</span>
<span class="codes-comment">// 書き出し</span>
<span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;p&gt;&lt;a href=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">info_url</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot;&gt;&lt;img src=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">thumbnail_url</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot; alt=&quot;書影画像&quot; style=&quot;border: 1px solid #333;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">preview</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code"> != </span><span class="codes-quotes">&quot;</span><span class="codes-string">noview</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">){</span>
<span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;p&gt;&lt;a href=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-var">$book</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">preview_url</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot;&gt;&lt;img src=&quot;http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<h4 id="tb67983">実行例</h4>
<p><a href="http://books.google.com/books?id=X7ENMVTe1qkC&#038;ie=ISO-8859-1&#038;source=gbs_ViewAPI"><img src="http://bks2.books.google.com/books?id=X7ENMVTe1qkC&#038;printsec=frontcover&#038;img=1&#038;zoom=1&#038;edge=curl" alt="書影画像" style="border: 1px solid #333;" /></a></p>
<p><a href="http://books.google.com/books?id=X7ENMVTe1qkC&#038;printsec=frontcover&#038;ie=ISO-8859-1&#038;source=gbs_ViewAPI"><img src="http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif" /></a></p>
<h3 id="t8fea43">ブックビューワ埋め込みAPI （&#8221;Embedded Viewer API&#8221;）</h3>
<p><a href="http://code.google.com/apis/books/docs/dynamic-links.html" title="Dynamic Links - Google Book Search APIs - Google Code">Google Codeでの仕様解説ページ</a></p>
<p>ブックビューワ埋め込みAPIは書籍のプレビューが可能な場合に、そのビューワを呼び出してウェブページ中に埋め込めるAPIです。ビューワではPDFビューワのようで、ページ内容を検索したり、ズームしたりといったコントロールが設けられています。触った印象や呼びだし方はGoogle Mapsに似ています。</p>
<p>コードが不得手な人は英語ですが<a href="http://code.google.com/apis/books/docs/preview-wizard.html" title="Preview Wizard - Google Book Search APIs - Google Code">コード作成フォーム</a>も用意してくれているので、利用してみてください。</p>
<h4 id="te08620">コード例</h4>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>HTMLソースコード</em></div><pre class="source-code"><code><span class="codes-brackets">&lt;</span><span class="codes-code">!</span><span class="codes-var">DOCTYPE</span><span class="codes-code"> </span><span class="codes-var">html</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">-//W3C//DTD XHTML 1.0 Strict//EN</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">html</span><span class="codes-code"> </span><span class="codes-var">xmlns</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">http://www.w3.org/1999/xhtml</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">head</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">meta</span><span class="codes-code"> </span><span class="codes-var">http-equiv</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">content-type</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-var">content</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">text/html; charset=utf-8</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-brackets">/&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">title</span><span class="codes-brackets">&gt;</span><span class="codes-code">Google Book Search Embedded Viewer API Example</span><span class="codes-brackets">&lt;/</span><span class="codes-reserved">title</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">script</span><span class="codes-code"> </span><span class="codes-var">type</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">text/javascript</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-var">src</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">http://www.google.com/jsapi</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;&lt;/</span><span class="codes-reserved">script</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">script</span><span class="codes-code"> </span><span class="codes-var">type</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">text/javascript</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;</span>
<span class="codes-code">google.load(&quot;books&quot;, &quot;0&quot;, {&quot;language&quot;: &quot;ja&quot;});</span>
<span class="codes-code">google.setOnLoadCallback(initialize);</span>
<span class="codes-code"> </span>
<span class="codes-code">function initialize() {</span>
<span class="codes-code">  var viewer = new google.books.DefaultViewer(document.getElementById('viewerCanvas'));</span>
<span class="codes-code">  viewer.load('ISBN:4569635458', notFound, Found);</span>
<span class="codes-code">}</span>
<span class="codes-code"> </span>
<span class="codes-code">function Found(){</span>
<span class="codes-code">  // alert(&quot;指定された書籍がありました&quot;);</span>
<span class="codes-code">}</span>
<span class="codes-code"> </span>
<span class="codes-code">function notFound(){</span>
<span class="codes-code">  alert(&quot;指定された書籍は見つかりませんでした&quot;);</span>
<span class="codes-code">}</span>
<span class="codes-brackets">&lt;/</span><span class="codes-reserved">script</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;/</span><span class="codes-reserved">head</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">body</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;</span><span class="codes-reserved">div</span><span class="codes-code"> </span><span class="codes-var">id</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">viewerCanvas</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-var">style</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">width: 600px; height: 500px</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;&lt;/</span><span class="codes-reserved">div</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;/</span><span class="codes-reserved">body</span><span class="codes-brackets">&gt;</span>
<span class="codes-brackets">&lt;/</span><span class="codes-reserved">html</span><span class="codes-brackets">&gt;</span></code></pre></div>
<p>では、主要な部分を見ていきましょう。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>HTMLソースコード</em></div><pre class="source-code"><code><span class="codes-brackets">&lt;</span><span class="codes-reserved">script</span><span class="codes-code"> </span><span class="codes-var">type</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">text/javascript</span><span class="codes-quotes">&quot;</span><span class="codes-code"> </span><span class="codes-var">src</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">http://www.google.com/jsapi</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;&lt;/</span><span class="codes-reserved">script</span><span class="codes-brackets">&gt;</span></code></pre></div>
<p>ブックビューワ埋め込みAPIではGoogle Maps APIのように空のブロック要素の中に、javascriptで内容を挿入していく方法を採っています。そして、その基礎となるGoogle AJAX APIスクリプトをまず読み込んでいます。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>HTMLソースコード</em></div><pre class="source-code"><code><span class="codes-brackets">&lt;</span><span class="codes-reserved">script</span><span class="codes-code"> </span><span class="codes-var">type</span><span class="codes-code">=</span><span class="codes-quotes">&quot;</span><span class="codes-string">text/javascript</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">&gt;</span>
<span class="codes-code">google.load(&quot;books&quot;, &quot;0&quot;, {&quot;language&quot;: &quot;ja&quot;});</span>
<span class="codes-code">google.setOnLoadCallback(initialize);</span>
<span class="codes-code"> </span>
<span class="codes-code">function initialize() {</span>
<span class="codes-code">  var viewer = new google.books.DefaultViewer(document.getElementById('viewerCanvas'));</span>
<span class="codes-code">  viewer.load('ISBN:4873112834', notFound, Found);</span>
<span class="codes-code">}</span>
<span class="codes-code">// （略）</span>
<span class="codes-brackets">&lt;/</span><span class="codes-reserved">script</span><span class="codes-brackets">&gt;</span></code></pre></div>
<p>次に、google.loadメソッドでブックビューワ埋め込みAPIを呼び出しています。3つめの引数は任意で表示言語を指定することができます。</p>
<p>最後に、google.setOnLoadCallbackメソッドを介してinitializeメソッドを呼び出します。google.setOnLoadCallbackメソッドはブラウザ上でスクリプトが確実に実行されるように、DOMツリーが構築されるのを待ってメソッドを実行する関数です。</p>
<p>そのinitializeメソッドですが、Google Mapsのようにまずgoogle.books.DefaultViewerメソッドでビューワを呼び出すブロック要素を指定して初期化し、次にloadメソッドで識別子（ISBNなど）を指定して、ビューワを呼び出します。2つ目の引数に指定したメソッドはビューワが利用できない場合に、3つ目の引数に指定したメソッドはビューワの呼び出しに成功した時にそれぞれ呼び出されます。</p>
<p>ちなみに、呼び出す前にプレビューがそもそも利用できるかどうか確認したい場合は動的リンクの embeddable の返り値を利用してください。</p>
<h4 id="tb19e86">実行例</h4>
<p><script type="text/javascript" src="http://www.google.com/jsapi"></script><br />
<script type="text/javascript">
google.load("books", "0", {"language": "ja"});
google.setOnLoadCallback(initialize);
function initialize() {
  var viewer = new google.books.DefaultViewer(document.getElementById('viewerCanvas'));
  viewer.load('ISBN:4873112834');
}
</script></p>
<div id="viewerCanvas" style="width: 600px; height: 500px; margin-bottom: 30px;"></div>
<h3 id="ta316cf">全文検索 &amp; メタデータ編集API（&#8221;Data API&#8221;）</h3>
<p><a href="http://code.google.com/apis/books/docs/gdata/developers_guide_protocol.html#SearchingForBooks" title="Data API: Developer's Guide, Protocol - Google Book Search APIs - Google Code">Google Codeでの仕様解説ページ</a></p>
<p>全文検索APIは文字通り書籍のタイトル、目次、説明、内容などから書籍の検索が出来るAPIで、認証無しで利用できます。一方、メタデータ編集APIは利用情報とのひも付けが必要なのでGoogleアカウントでの認証が必要で、認証後は利用者独自の本棚の内容を取得・編集したり、本のレビューやタグに変更を加えたり出来ます。後者を解説すると長くなるので今回は割愛しましょう。</p>
<p>全文検索APIはRESTでデータを渡せばATOMフォーマットでデータが返ってくるというものです。以下は、<a href="http://www.google.com/books/feeds/volumes?q=%E3%82%AA%E3%83%A9%E3%82%A4%E3%83%AA%E3%83%BC+inauthor%3AAsano">「オライリー」が含まれており、かつAsanoという方が書かれた本のフィード</a>のURLです。</p>
<p class="titlize">http://www.google.com/books/feeds/volumes?q=%E3%82%AA%E3%83%A9%E3%82%A4%E3%83%AA%E3%83%BC+inauthor%3AAsano</p>
<dl>
<dt>ベースURL</dt>
<dd>http://books.google.com/books/feeds/volumes</dd>
<dt>qパラメータ</dt>
<dd>
<p>検索クエリを指定します。検索対象はタイトル、キーワード、説明、著者名、主題です。&amp;で複数のクエリをくっつけて、検索語の頭に &#8211; を付けると、その後を除いた検索が出来ます。また、同じく以下のように接頭辞をつけることで検索語の検索対象を絞ることが出来ます</p>
<dl>
<dt>inauthor:</dt>
<dd>検索対象：著者名</dd>
<dt>intitle:</dt>
<dd>検索対象：タイトル</dd>
<dt>inpublisher:</dt>
<dd>検索対象：出版社</dd>
<dt>date:</dt>
<dd>検索対象：出版年。<var>date:1990-2001</var>のように指定する</dd>
<dt>isbn:</dt>
<dd>検索対象：ISBN</dd>
</dl>
</dd>
<dt>start-indexパラメータ</dt>
<dd>検索を開始する件数（＝オフセット数）。max-resultsパラメータと組み合わせて使う。</dd>
<dt>max-resultsパラメータ</dt>
<dd>1回の検索に含める件数。デフォルト値は<var>10</var>で最大値は<var>20</var>。</dd>
<dt>min-viewabilityパラメータ</dt>
<dd>検索結果を公開レベルに応じて絞り込みたいときに使用します。値に<var>full</var>を指定すると全文公開のアイテムのみ、<var>partial</var>を指定すると一部公開と全文公開のアイテムのみ結果に出力されます。</dd>
</dl>
<h4 id="t6af9a5">コード例</h4>
<p>コード例は「オライリー」を検索語にして得られた検索結果を書きだしてみたものです。Amazonと違ってモノそのものは売っていないので、価格を出したり入手できるようにしたい場合はAmazonアソシエイトと組み合わせる必要があります。</p>
<p>それにしても対象書籍の言語を指定する方法がどうにも見つかないのが気になりますね。<a href="http://books.google.com/advanced_book_search" title="検索オプション">検索オプション</a>にはきちんとオプションが存在しますので、ないことはないのでしょうが…。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-code"> </span>
<span class="codes-var">$url</span><span class="codes-code"> = </span><span class="codes-quotes">&quot;</span><span class="codes-string">http://books.google.com/books/feeds/volumes?hl=ja&amp;q=</span><span class="codes-quotes">&quot;</span><span class="codes-code">. </span><span class="codes-identifier">urlencode</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">オライリー</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code"> .</span><span class="codes-quotes">&quot;</span><span class="codes-string">&amp;max-results=5</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-var">$str</span><span class="codes-code"> = </span><span class="codes-identifier">file_get_contents</span><span class="codes-brackets">(</span><span class="codes-var">$url</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$str</span><span class="codes-code"> = </span><span class="codes-identifier">str_replace</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">dc:</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;&quot;</span><span class="codes-code">, </span><span class="codes-var">$str</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-var">$xml</span><span class="codes-code"> = </span><span class="codes-identifier">simplexml_load_string</span><span class="codes-brackets">(</span><span class="codes-var">$str</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-reserved">foreach</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$xml</span><span class="codes-code">-&gt;</span><span class="codes-identifier">entry</span><span class="codes-code"> </span><span class="codes-reserved">as</span><span class="codes-code"> </span><span class="codes-var">$item</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">strpos</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">link</span><span class="codes-brackets">[</span><span class="codes-number">0</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">type</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">image</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code"> !== </span><span class="codes-reserved">false</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-var">$cover</span><span class="codes-code"> = </span><span class="codes-identifier">preg_replace</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/zoom=\d/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">zoom=1</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">link</span><span class="codes-brackets">[</span><span class="codes-number">0</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">href</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]))</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;p&gt;&lt;a href=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">link</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">href</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot;&gt;&lt;img src=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-var">$cover</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot; alt=&quot;書影画像&quot; style=&quot;border: 1px solid #333;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;p&gt;&lt;a href=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">link</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">href</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot;&gt;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">title</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&lt;/a&gt;&lt;/p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">strpos</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">link</span><span class="codes-brackets">[</span><span class="codes-number">2</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">rel</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">preview</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code"> !== </span><span class="codes-reserved">false</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;p&gt;&lt;a href=&quot;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">link</span><span class="codes-brackets">[</span><span class="codes-number">2</span><span class="codes-brackets">][</span><span class="codes-quotes">&quot;</span><span class="codes-string">href</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&quot;&gt;&lt;img src=&quot;http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif&quot; alt=&quot;この書籍内を検索&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">description</span><span class="codes-brackets">)</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&lt;/p&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;table&gt;&lt;tbody&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">creator</span><span class="codes-brackets">)</span><span class="codes-code"> ? </span><span class="codes-quotes">'</span><span class="codes-string">&lt;tr&gt;&lt;th&gt;著者&lt;/th&gt;&lt;td&gt;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">creator</span><span class="codes-brackets">)</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&lt;/td&gt;&lt;/tr&gt;</span><span class="codes-quotes">'</span><span class="codes-code"> : </span><span class="codes-quotes">&quot;&quot;</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">publisher</span><span class="codes-brackets">)</span><span class="codes-code"> ? </span><span class="codes-quotes">'</span><span class="codes-string">&lt;tr&gt;&lt;th&gt;出版社&lt;/th&gt;&lt;td&gt;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">publisher</span><span class="codes-brackets">)</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">&lt;/td&gt;&lt;/tr&gt;</span><span class="codes-quotes">'</span><span class="codes-code"> : </span><span class="codes-quotes">&quot;&quot;</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">date</span><span class="codes-brackets">)</span><span class="codes-code"> ? </span><span class="codes-quotes">'</span><span class="codes-string">&lt;tr&gt;&lt;th&gt;出版年&lt;/th&gt;&lt;td&gt;</span><span class="codes-quotes">'</span><span class="codes-code">. </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$item</span><span class="codes-code">-&gt;</span><span class="codes-identifier">date</span><span class="codes-brackets">)</span><span class="codes-code"> .</span><span class="codes-quotes">'</span><span class="codes-string">年&lt;/td&gt;&lt;/tr&gt;</span><span class="codes-quotes">'</span><span class="codes-code"> : </span><span class="codes-quotes">&quot;&quot;</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">'</span><span class="codes-string">&lt;/tbody&gt;&lt;/table&gt;</span><span class="codes-quotes">'</span><span class="codes-code">;</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">function</span><span class="codes-code"> </span><span class="codes-identifier">h</span><span class="codes-brackets">(</span><span class="codes-var">$s</span><span class="codes-brackets">){</span>
<span class="codes-code">  </span><span class="codes-reserved">return</span><span class="codes-code"> </span><span class="codes-identifier">htmlspecialchars</span><span class="codes-brackets">(</span><span class="codes-var">$s</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<h4 id="t1828f3">実行例</h4>
<p><a href="http://books.google.com/books?id=3-ngyI_qMM8C&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata"><img src="http://bks7.books.google.com/books?id=3-ngyI_qMM8C&amp;printsec=frontcover&amp;img=1&amp;zoom=1&amp;edge=curl&amp;source=gbs_gdata" alt="書影画像" style="border: 1px solid #333;" /></a></p>
<p><a href="http://books.google.com/books?id=3-ngyI_qMM8C&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata">Satistics Hacks</a></p>
<p><a href="http://books.google.com/books?id=3-ngyI_qMM8C&amp;pg=PA143&amp;dq=+++++&amp;ie=ISO-8859-1&amp;cd=1&amp;source=gbs_gdata"><img src="http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif" alt="この書籍内を検索" /></a></p>
<p>上場はされてないが、本書の出版社であるオライリー・メディア社を例に考えてみよう。  もちろん、ランダムにオライリー・メディア社を選んだわけではない。企業の存続期間  については、その傾向を示す歴史的情報もいろいろと入手できるが、とにかくGottの &#8230;</p>
<table>
<tbody>
<tr>
<th>出版社</th>
<td>O&#8217;Reilly Japan</td>
</tr>
<tr>
<th>出版年</th>
<td>2007-12年</td>
</tr>
</tbody>
</table>
<p><a href="http://books.google.com/books?id=Qj2phAVWHrsC&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata"><img src="http://bks2.books.google.com/books?id=Qj2phAVWHrsC&amp;printsec=frontcover&amp;img=1&amp;zoom=1&amp;edge=curl&amp;source=gbs_gdata" alt="書影画像" style="border: 1px solid #333;" /></a></p>
<p><a href="http://books.google.com/books?id=Qj2phAVWHrsC&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata">Running Linux</a></p>
<p><a href="http://books.google.com/books?id=Qj2phAVWHrsC&amp;pg=PA777&amp;dq=+++++&amp;ie=ISO-8859-1&amp;cd=2&amp;source=gbs_gdata"><img src="http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif" alt="この書籍内を検索" /></a></p>
<p>八ひ 1 は 5 者、「 9 丁\ 1 し&amp;amp; X ョ丁? 4 し一 7116 00^011^6 0 ^ ( 16 』、( :ヒ化  レ\ 111301300 ^ 8111 に 6110 おゲ共著、 0 , ! ^出) ^ &amp;amp;八お 0013 お 5 (「ョ丁! ^  し&amp;amp; X 9 丁^し第 5 版」、原隆文訳、オライリー&amp;quot;ジャパン)「II 丁\ 1 し?</p>
<table>
<tbody>
<tr>
<th>出版社</th>
<td>O&#8217;Reilly Japan</td>
</tr>
<tr>
<th>出版年</th>
<td>2003-06年</td>
</tr>
</tbody>
</table>
<p><a href="http://books.google.com/books?id=LlXxPAAACAAJ&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata"><img src="http://bks4.books.google.com/books?id=LlXxPAAACAAJ&amp;printsec=frontcover&amp;img=1&amp;zoom=1&amp;source=gbs_gdata" alt="書影画像" style="border: 1px solid #333;" /></a></p>
<p><a href="http://books.google.com/books?id=LlXxPAAACAAJ&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata">Veronica Guerin</a></p>
<p><a href="http://books.google.com/books?id=LlXxPAAACAAJ&amp;dq=+++++&amp;ie=ISO-8859-1&amp;cd=3&amp;source=gbs_gdata"><img src="http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif" alt="この書籍内を検索" /></a></p>
<p>1996年、アイルランド共和国の首都ダブリン―大手新聞記者、ヴェロニカ・ゲリンは凶弾に倒れた。タブーを恐れず、麻薬犯罪の実態を暴く記事を書いたがために。やがて、その &#8230;</p>
<table>
<tbody>
<tr>
<th>著者</th>
<td>エミリー オライリー</td>
</tr>
<tr>
<th>出版年</th>
<td>2004-06-30年</td>
</tr>
</tbody>
</table>
<p><a href="http://books.google.com/books?id=6E--AAAACAAJ&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata"><img src="http://bks8.books.google.com/books?id=6E--AAAACAAJ&amp;printsec=frontcover&amp;img=1&amp;zoom=1&amp;source=gbs_gdata" alt="書影画像" style="border: 1px solid #333;" /></a></p>
<p><a href="http://books.google.com/books?id=6E--AAAACAAJ&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata">「老い」とアメリカ文化</a></p>
<p><a href="http://books.google.com/books?id=6E--AAAACAAJ&amp;dq=+++++&amp;ie=ISO-8859-1&amp;cd=4&amp;source=gbs_gdata"><img src="http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif" alt="この書籍内を検索" /></a></p>
</p>
<table>
<tbody>
<tr>
<th>著者</th>
<td>イヴリン・M・オライリー</td>
</tr>
<tr>
<th>出版年</th>
<td>2004-04年</td>
</tr>
</tbody>
</table>
<p><a href="http://books.google.com/books?id=rD9FItngADgC&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata"><img src="http://bks4.books.google.com/books?id=rD9FItngADgC&amp;printsec=frontcover&amp;img=1&amp;zoom=1&amp;edge=curl&amp;source=gbs_gdata" alt="書影画像" style="border: 1px solid #333;" /></a></p>
<p><a href="http://books.google.com/books?id=rD9FItngADgC&amp;dq=+++++&amp;ie=ISO-8859-1&amp;source=gbs_gdata">sendmail Volume 2 設定編</a></p>
<p><a href="http://books.google.com/books?id=rD9FItngADgC&amp;pg=PA617&amp;dq=+++++&amp;ie=ISO-8859-1&amp;cd=5&amp;source=gbs_gdata"><img src="http://books.google.com/intl/ja/googlebooks/images/gbs_preview_button1.gif" alt="この書籍内を検索" /></a></p>
<p>オライリーの新刊请報や購読特典などを、いち早く统若の皆様へお知らせするオライリー  ブッククラブのメンバ一を募集しています。 &#8230; オライリー特製グッズのプレゼント  情報.技術セミナ—など各種ィベント惰铕参加费:無料参加資格:電子メールァドレスをお &#8230;</p>
<table>
<tbody>
<tr>
<th>著者</th>
<td>エリックオールマン</td>
</tr>
<tr>
<th>出版社</th>
<td>O&#8217;Reilly Japan</td>
</tr>
<tr>
<th>出版年</th>
<td>2004-04年</td>
</tr>
</tbody>
</table>
<h3 id="t5edab3">感想</h3>
<p>現在の所、<a href="http://books.google.com/books?lr=lang_ja&amp;q=date:0-99999&amp;as_brr=0&amp;hl=ja">日本語での登録書籍数は約95,000件</a>、うちプレビュー可能な書籍は<a href="http://books.google.com/books?lr=lang_ja&amp;q=date:0-99999&amp;hl=ja&amp;as_brr=3">16,800件</a>（17.6%）とまだまだ心許ない状況<sup><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#footnote_0_822" id="identifier_0_822" class="footnote-link footnote-identifier-link" title="参考までに、2007年の出版点数は約77,000件です">1</a></sup> ですが、ビューワはうまく作られていますので、プレビューがある場合は本を買うかどうかの参考材料にできますね。</p>
<p>早速、<a href="http://note.openvista.jp/2008/new-opac-vision/">OPAC</a>にも取り込もうと思います<sup><a href="http://note.openvista.jp/2008/trying-google-book-search-api/#footnote_1_822" id="identifier_1_822" class="footnote-link footnote-identifier-link" title="OPACの利用者は資料選定の際には、書籍の説明など参考材料を必ずチェック行動が見て取れますので">2</a></sup> が、一般的にはAmazonアソシエイトと動的リンクを組み合わせて、プレビューボタンを出すのが無難な使い方かと思います。</p>
<p>Amazonも黙ってみているわけはないでしょうから、Amazon側のAPIがより充実していくことも期待してます。</p>
<p>ちなみに、一見慈善事業のようなAPIですが、そこはGoogle Mapsと違って、こちらはビューワに広告が付くことでマネタイズしているようです。</p>
<ol class="footnotes"><li id="footnote_0_822" class="footnote">参考までに、<a href="http://www.1book.co.jp/001274.html">2007年の出版点数は約77,000件</a>です</li><li id="footnote_1_822" class="footnote">OPACの利用者は資料選定の際には、書籍の説明など参考材料を必ずチェック行動が見て取れますので</li></ol><img src="http://note.openvista.jp/?ak_action=api_record_view&id=822&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/trying-google-book-search-api/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>RDBMSが扱いづらいのでSQliteを簡易XMLデータベースぽく使えるようにしてみた</title>
		<link>http://note.openvista.jp/2008/xml-like-database-using-sqlite/</link>
		<comments>http://note.openvista.jp/2008/xml-like-database-using-sqlite/#comments</comments>
		<pubDate>Mon, 22 Sep 2008 20:43:18 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ツールの制作]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=793</guid>
		<description><![CDATA[伝統的なRDBMSのレコードにXMLファイルを突っ込んで、XMLデータベースチックに扱えるようなライブラリを使って楽してみます]]></description>
			<content:encoded><![CDATA[<p>最近大量の情報を扱うようになってから、MySQLやらSQLiteなどのRDBMSを触っているのですが、どうにも慣れません。</p>
<p>以前から小規模な設定は、SimpleXMLで書いたり読んだりしていまして、データベースなぞに触らなかったものですから、その直感的な操作性に味を占めてしまうと、前時代的なSQLのクエリをちくちく発行する気にはどうにもなりません<sup><a href="http://note.openvista.jp/2008/xml-like-database-using-sqlite/#footnote_0_793" id="identifier_0_793" class="footnote-link footnote-identifier-link" title="なにしろPHP5だと simplexml_load_file で設定を読み込んで、目的の項目を選ぶという2行のコードですむわけですから。RDBMSもフレームワーク附属のライブラリを使えば楽になるのかもしれませんけどフレームワークを使わない場合もあるわけで">1</a></sup> 。それにバイナリで中身が見られないというのは、全てがテキストエディタで覗けてなんとかなるというのに慣れた身にはどうにも不安すぎます。</p>
<p>何年か前からXMLでデータを管理する<a href="http://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%A4%E3%83%86%E3%82%A3%E3%83%96XML%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9">XMLデータベース</a>というのも出ていて、<a href="http://xml.apache.org/xindice/">Apache Xindice</a>なんかはオープンソースでの開発が進んでいるそうですが、一般的なレンタルサーバにおいてPHPで扱えるとなると、選択肢はどうもないようです。</p>
<p>そこで、SQLiteを使ってXMLデータベース的な事をやってみました<sup><a href="http://note.openvista.jp/2008/xml-like-database-using-sqlite/#footnote_1_793" id="identifier_1_793" class="footnote-link footnote-identifier-link" title="SQliteにしたのは必要なファイルが1つにまとめられていて環境移行がやりやすいためです">2</a></sup> 。方法はまぁ誰もが思い<br />
つくとは思いますが、BLOB型のレコードにXMLファイル文字列をそのまま突っ込んでIDつけてるだけです。それをクラスライブラリを介して、透過的に扱おうという案配です。</p>
<h3 id="t5cac26">パフォーマンステスト</h3>
<p>で、とりあえず、パフォーマンステストとして定番らしい郵便番号→住所変換で実行時間を測定してみます（元データは<a href="http://www.post.japanpost.jp/zipcode/download.html">郵便事業会社で公開</a>されています）</p>
<dl>
<dt>実験内容</dt>
<dd>Aにはデータを郵便番号、地名、番地名など細かい住所をそのままRDBの構造として格納、BにはこれらをXMLとして表現したものをそのまま挿入したものを挿入します。それぞれ郵便番号を指定して住所に変換する時間を測定します<span class="weaken">（レコード数は118,576件）</span></dd>
<dt>Aの方法</dt>
<dd>実行時間：0.04671秒<span class="weaken">（5回実行平均）</span></dd>
<dd>メモリ最大使用量：約995KB</dd>
<dt>Bの方法</dt>
<dd>実行時間：0.17422秒<span class="weaken">（5回実行平均）</span></dd>
<dd>メモリ最大使用量：約1009KB</dd>
</dl>
<p>標準的なRDBに比べ4倍遅いという結果になりましたが、個人的には許容量なので今後はこれで開発していこうかなと思います。今のところは10万件レベルのデータを扱うことはそんなにないですし、数千件程度の小規模な場合ならBの方法でも0.01秒程度で実行できます。</p>
<p>生のXMLファイルをずらっと並べた上で、ファイル読み込み→SimpleXMLを使って検索なんかすると、メモリをバンバン食う上にスケーラビリティが皆無に等しいのですが、この方法だとある程度は持ちこたえられます。パフォーマンスやスケーラビリティを気にする人は間違っても使ってはいけません。加えてテーブルを1個しか持てませんが、増やしたい場合はデータベースファイルを増やせば良いだけなので特に気にしてません。</p>
<h3 id="t540a05">取扱説明書</h3>
<dl>
<dt>初期データ入力</dt>
<dd>コントローラ側で、データ元のXMLがあるフォルダとDBのファイル名を指定します。DBファイルは事前に空ファイルを&#8221;ファイル名.db&#8221;という名前で作っておき、XMLがあるフォルダと共に書き込み可能にしておきます。コントローラのURIに construct というクエリを付けて実行するとデータ入力が始まります。</dd>
<dt>データ取得</dt>
<dd>
<p>searchメソッドで検索結果を取得を取得できます。引数は3つあり、順に&#8221;検索語&#8221;, &#8220;検索方法&#8221;, &#8220;検索対象の要素がある場所&#8221;です。</p>
<p>検索方法が取る値はall（全文検索）, parts（部分一致）, full（完全一致）, prefix（前方一致）, suffix（後方一致）の4つです。検索対象の要素がある場所はSimpleXMLを使うときのようにノードのパスを指定します、全文検索の際はこの引数は無視されます。</p>
<p>正常にデータが取得できれば、XMLの配列でデータが帰ってきます<span class="weaken">（SimpleXMLElement Object型になってます）</span></p>
</dd>
<dd>
<p><em>サンプルコード</em>（郵便番号→住所の変換）</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-var">$db</span><span class="codes-code"> = </span><span class="codes-reserved">new</span><span class="codes-code"> </span><span class="codes-identifier">XSQLiteManager</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-comment">// データベースのファイル名とXMLがあるフォルダを指定して読み込む</span>
<span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">simplexml_load_db</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">zipcode</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">./data</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$_GET</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">zip</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]){</span>
<span class="codes-code">  </span><span class="codes-var">$zip</span><span class="codes-code"> = </span><span class="codes-identifier">mb_convert_kana</span><span class="codes-brackets">(</span><span class="codes-var">$_GET</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">zip</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">a</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-identifier">preg_match</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">/(\d{3})\-?(\d{4})/</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-var">$zip</span><span class="codes-code">, </span><span class="codes-var">$q</span><span class="codes-brackets">)){</span>
<span class="codes-code">    </span><span class="codes-comment">// 検索を実行してXMLの配列形式で結果を受け取る</span>
<span class="codes-code">    </span><span class="codes-var">$results</span><span class="codes-code"> = </span><span class="codes-var">$db</span><span class="codes-code">-&gt;</span><span class="codes-identifier">search</span><span class="codes-brackets">(</span><span class="codes-var">$q</span><span class="codes-brackets">[</span><span class="codes-number">1</span><span class="codes-brackets">]</span><span class="codes-code">.</span><span class="codes-var">$q</span><span class="codes-brackets">[</span><span class="codes-number">2</span><span class="codes-brackets">]</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">full</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">zip</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$results</span><span class="codes-brackets">){</span>
<span class="codes-code">      </span><span class="codes-var">$address</span><span class="codes-code"> = </span><span class="codes-var">$results</span><span class="codes-brackets">[</span><span class="codes-number">0</span><span class="codes-brackets">]</span><span class="codes-code">-&gt;</span><span class="codes-identifier">name</span><span class="codes-code">. </span><span class="codes-var">$results</span><span class="codes-brackets">[</span><span class="codes-number">0</span><span class="codes-brackets">]</span><span class="codes-code">-&gt;</span><span class="codes-identifier">local</span><span class="codes-code">;</span>
<span class="codes-code">      </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">郵便番号（</span><span class="codes-quotes">&quot;</span><span class="codes-code">. </span><span class="codes-identifier">htmlspecialchars</span><span class="codes-brackets">(</span><span class="codes-var">$zip</span><span class="codes-brackets">)</span><span class="codes-code"> .</span><span class="codes-quotes">&quot;</span><span class="codes-string">）の住所は</span><span class="codes-quotes">&quot;</span><span class="codes-code">. </span><span class="codes-var">$address</span><span class="codes-code"> .</span><span class="codes-quotes">&quot;</span><span class="codes-string">です</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">      </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">検索語に当てはまる検索結果が見つかりません</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-brackets">}</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">正しい郵便番号（数字7桁）を入力してください</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-code"> </span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
</dd>
<dt>データ追加</dt>
<dd>XMLデータ文字列を引数にして insertXML メソッドを実行してください。データベースの最後尾に追加されます。</dd>
<dt>データ更新</dt>
<dd>IDとXMLデータ文字列を引数にして updateXML メソッドを実行してください。IDはデータベース上のレコード番号のことで search メソッドを実行したときに帰ってくる結果の配列のキーに書いてあります。</dd>
<dt>データ削除</dt>
<dd>IDを引数にして deleteXML メソッドを実行してください。</dd>
</dl>
<h3 id="t3fded1">デモとダウンロード</h3>
<p><a href="http://tech.openvista.jp/tmp/zip/">郵便番号検索デモサイト</a></p>
<dl class="download">
<dt>ダウンロード</dt>
<dd><a href="http://tech.openvista.jp/tmp/zip/zip.zip">データベース一式</a> (20MB)</dd>
<dt>ライセンス</dt>
<dd><a rel="license" href="http://ja.wikipedia.org/wiki/GNU_General_Public_License">GNU General Public License</a><span class="weaken">（郵便番号データの著作権は郵便事業会社にあると思うので除外）</span></dd>
</dl>
<ol class="footnotes"><li id="footnote_0_793" class="footnote">なにしろPHP5だと simplexml_load_file で設定を読み込んで、目的の項目を選ぶという2行のコードですむわけですから。RDBMSもフレームワーク附属のライブラリを使えば楽になるのかもしれませんけどフレームワークを使わない場合もあるわけで</li><li id="footnote_1_793" class="footnote">SQliteにしたのは必要なファイルが1つにまとめられていて環境移行がやりやすいためです</li></ol><img src="http://note.openvista.jp/?ak_action=api_record_view&id=793&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/xml-like-database-using-sqlite/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>このサイト上で使っているWordPress用テーマ &#8220;cielo&#8221; を公開するよ</title>
		<link>http://note.openvista.jp/2008/wordpress-theme-cielo/</link>
		<comments>http://note.openvista.jp/2008/wordpress-theme-cielo/#comments</comments>
		<pubDate>Sat, 13 Sep 2008 18:28:18 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ウェブサービス論]]></category>
		<category><![CDATA[ウェブデザイン]]></category>
		<category><![CDATA[ウェブログツール]]></category>
		<category><![CDATA[ツールの制作]]></category>
		<category><![CDATA[ビジネス]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>
		<category><![CDATA[情報の設計]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=626</guid>
		<description><![CDATA[このサイト上で使用しているブログツール「WordPress」用の1カラムのテーマ "cielo" を公開します]]></description>
			<content:encoded><![CDATA[<p>前々からこのサイトのテーマの配布準備作業を進めていましたが、ようやく形になったので一般公開します。ちなみに &#8220;cielo&#8221; とはイタリア語で空という意味です。</p>
<dl>
<dt>デモサイト</dt>
<dd>
<p><a href="http://tech.openvista.jp/demo/wordpress/"><img src="http://note.openvista.jp/download/2008/09/screenshot.png" alt="スクリーンショット" title="スクリーンショット" /></a></p>
</dd>
</dl>
<dl class="download">
<dt>ダウンロード</dt>
<dd><a href="http://tech.openvista.jp/demo/wordpress/wp-content/themes/cielo.zip">cieloテーマ</a>(約1.2MB)</dd>
<dt>最終更新日</dt>
<dd>2011年9月13日 08時05分 </dd>
<dt>動作環境</dt>
<dd>PHP5.2.0以上、WordPress 2.5以上</dd>
<dt>ライセンス</dt>
<dd><a href="#copyright">ライセンスが設定されているリソース</a>はそのライセンスに従ってください。その他は<a rel="license" href="http://tech.openvista.jp/demo/wordpress/wp-content/themes/cielo/COPYRIGHT.txt">修正BSDライセンス</a>とします</dd>
</dl>
<div class="toc">
<ol>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#ta6a9ed">使い方</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t39b886">特徴</a>
<ol>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t0db1e1">快適に読むための環境</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t0ad310">各種ウェブサービスとの連携</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t0d2dcc">ウェブアプリケーションを簡単に使える内蔵機能</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#tc9af8c">モバイルにも対応</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t69462c">その他にも</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#tdd43ee">サポートしないもの</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#tf3fb28">導入を推奨するプラグイン</a>
<ol>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t8cb654">依存しているプラグイン</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#tfe6807">入れたら便利なプラグイン</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#td00e26">スパム防止に役立つプラグイン</a></li>
</ol>
</li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t2be41b">仕様・技術情報</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#ta2bb6a">謝辞 &amp; 著作権表記</a></li>
<li><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/#t5edd4e">更新履歴</a></li>
</ol>
</div>
<h3 id="ta6a9ed">使い方</h3>
<ol>
<li>ファイルをダウンロードしたら解凍してください</li>
<li>中に入っている<var>/module/config.php</var>ファイルがテーマの設定ファイルですので、指示に従って設定してください</li>
<li>サーバの<var>/wp-content/themes/</var>フォルダに(2)をアップロードしてください</li>
<li>サーバの<var>/wp-content/themes/cielo/cache/</var>フォルダを書き込み可能な状態<span class="weaken">(パーミッションを0777&lt;rwxrwxrwx&gt;)</span>にしてください</li>
<li><a href="#required-plugin">必須プラグイン一式</a>をダウンロードし、解凍します</li>
<li>サーバの<var>/wp-content/plugins/</var>フォルダに(4)をアップロードしてください</li>
<li>管理画面からプラグインを有効化します</li>
<li>管理画面からテーマを有効化します</li>
<li>記事一覧ページなど特殊なページを作成します。投稿 → ページ から以下のページを作成してください。中身はテンプレートから自動的に読み込まれます
<ul>
<li>ポストスラグ名:<em>webmemo</em>のページを作成。タイトルはご自由に、中身は空でOK</li>
<li>ポストスラグ名:<em>archives</em>のページを作成。タイトルはご自由に、中身は空でOK</li>
<li>ポストスラグ名:<em>all</em>のページを作成。タイトルはご自由に、中身は空でOK</li>
<li>ポストスラグ名:<em>readmore</em>のページを作成。タイトルはご自由に、中身は空でOK</li>
</ul>
</li>
</ol>
<h3 id="t39b886">特徴</h3>
<h4 id="t0db1e1">快適に読むための環境</h4>
<p><img src="http://note.openvista.jp/download/2008/09/cielo-webdesign.png" alt="ウェブデザイン" title="ウェブデザイン" /></p>
<p>ブログは読者あってこそ。できるだけ多くの人に快適にブログを見てもらえるよう、多すぎず、少なすぎず必要な機能を配置しました</p>
<dl>
<dt>1カラム</dt>
<dd><a href="http://note.openvista.jp/2007/side-bar-skeptics/">本文のレイアウトが崩れにくく、本文を一番読んでもらえる1カラム</a>を採用しました</dd>
<dt>本文検索機能</dt>
<dd>並び替え機能、<a href="http://note.openvista.jp/2008/autopagerize-without-greasemonkey/">検索結果の自動継ぎ足し</a>をサポート</dd>
<dt>次の記事へ</dt>
<dd>関連記事、人気の記事(自動取得&amp;手動設定)で次の記事へ読者を案内します</dd>
</dl>
<h4 id="t0ad310">各種ウェブサービスとの連携</h4>
<p><img src="http://note.openvista.jp/download/2008/09/cielo-webmemo.png" alt="ウェブメモ" title="ウェブメモ" /></p>
<p>ブログサイトを運営する上で欠かせないネット上のサービスも簡単に利用できます。</p>
<dl>
<dt>Google Analytics</dt>
<dd>Googleのアクセス解析サービスも設定画面から認証キーを入力すれば利用できます</dd>
<dt>はてなブックマーク</dt>
<dd>エントリーページにはてなブックマークへのリンクを自動的に表示します</dd>
<dd>コメント欄には、はてなブックマークのコメントがシームレスに表示されるよう組み込みました</dd>
<dt>ウェブメモ機能</dt>
<dd>twitter, tumblr, はてなブックマーク上での最新の更新をウェブメモコーナーとして表示できます。表示した各記事には、はてなスターをつけることができます<span class="weaken">(はてなスターのトークンの発行が必要です)</span></dd>
</dl>
<h4 id="t0d2dcc">ウェブアプリケーションを簡単に使える内蔵機能</h4>
<p><img src="http://note.openvista.jp/download/2008/09/cielo-built-in-function.png" alt="内蔵機能" title="内蔵機能" /></p>
<p>便利なウェブアプリケーションが記事中で簡単に呼び出せます</p>
<dl>
<dt>Googleマップを1行で</dt>
<dd>住所を指定するだけでその周辺の2D地図や風景を表示できます(Googleマップ APIの発行が必要です)</dd>
<dt>動画の貼り付けも1行で</dt>
<dd>動画共有サイト(Youtube, Googleビデオ)上の動画や自作動画をコードを考えることなく簡単に公開できます</dd>
</dl>
<h4 id="tc9af8c">モバイルにも対応</h4>
<p><img src="http://note.openvista.jp/download/2008/09/cielo-formobile.png" alt="モバイル向けの表示" title="モバイル向けの表示" /></p>
<p>もちろん、携帯電話やiPhoneなどのモバイル機器にも対応します</p>
<dl>
<dt>携帯電話にもプラグイン使用で対応</dt>
<dd>餅は餅屋…ということで動きの速い携帯電話向けの最適化は<a href="http://wppluginsj.sourceforge.jp/ktai_style/">Ktai Style</a>を使うことで対応することにしました</dd>
<dt>iPhone / iPod touchに標準対応</dt>
<dd>ビジュアルデザインはiPhoneのSafariでも読みやすくなるよう最適化しています</dd>
<dd>呼び出した動画や地図は、iPhone / iPod touch内蔵アプリでも再生できるように工夫しています</dd>
</dl>
<h4 id="t69462c">その他にも</h4>
<dl>
<dt>XHTML1.1 + CSSで書いています</dt>
<dd>Web標準に準拠した、できるだけシンプルな文書構造を心がけました。現在使われているほとんどのウェブブラウザに対応しています。</dd>
<dt>SEOにも配慮</dt>
<dd>metaタグの自動生成、XHTMLでの構造化、わかりやすいページタイトルとテーマ側で出来ることはやっておきました。</dd>
<dt>間違ってると思ったらすぐ編集</dt>
<dd>ログインしている間は記事画面からワンクリックで編集画面に移動できます。</dd>
<dt>エフェクトでおめかし</dt>
<dd><a href="http://www.remus.dti.ne.jp/~a-satomi/bunsyorou/ArekorePopup.html">あれこれポップアップ</a><span class="weaken">(リンク先・引用元のタイトルなどをちょっとリッチにポップアップするスクリプト)</span>や<a href="http://leandrovieira.com/projects/jquery/lightbox/">jQuery lightbox プラグイン</a><span class="weaken">(写真のポップアップをエフェクトを付けて表示するスクリプト)</span>を標準で導入しています</dd>
<dt>ページ毎のCSSデザインも簡単に</dt>
<dd><a href="http://ideasilo.wordpress.com/2006/08/17/sandbox-theme/">Sandbox テーマ</a>は主要な要素に現在の状態を示すクラス名をつける機能がありますが、cieloはこの機能を取り込んでいます</dd>
<dt>ダウンロードは高速に</dt>
<dd>一部のファイルをGZIPという形式で圧縮しており、サーバとブラウザが対応していれば落とすファイルサイズが小さくなり、高速にページが表示できるようになります(<a href="http://tech.openvista.jp/demo/wordpress/2008/faq/#t674e6e">方法</a>)</dd>
<dt>続き物の記事はまとめよう</dt>
<dd>記事は独立したものだけではなく、何回かに分けて書いた続き物の記事もあるでしょう。cieloテーマではそうした記事を半自動的にまとめあげ、シリーズのRSSフィードを発行することも出来ます(<a href="http://tech.openvista.jp/demo/wordpress/2008/faq/#t5b9ec7">方法</a>)</dd>
</dl>
<h4 id="tdd43ee">サポートしないもの</h4>
<p>このテーマは次の機能をサポートしません</p>
<ul>
<li>可変1カラムデザイン以外の表示方法</li>
<li>コメント欄でのアバターの表示</li>
<li>UTF-8以外の文字コードでの運用</li>
</ul>
<h3 id="tf3fb28">導入を推奨するプラグイン<a id="required-plugin"></a></h3>
<h4 id="t8cb654">依存しているプラグイン</h4>
<p>推奨というより、このプラグインを入れていないと動かないので必ず入れておいてください</p>
<dl class="download">
<dt>ダウンロード</dt>
<dd><a href="http://note.openvista.jp/download/2008/09/wp-plugins-required.zip">必須プラグイン一式をダウンロード</a></dd>
<dt>ライセンス</dt>
<dd><a rel="license" href="http://ja.wikipedia.org/wiki/GNU_General_Public_License">GNU General Public License</a></dd>
</dl>
<dl>
<dt><a href="http://bono.s201.xrea.com/2006/03/112-runphp/">runPHP</a></dt>
<dd>記事中でPHPコードを使うプラグインです。内蔵の動画共有サイトのコード呼び出し機能などを使ったり、記事一覧ページ中で記述しているPHPコードを実行するのに必要です。<q>「ビジュアルリッチエディタ」「XHTML 構文の自動修正」とは同時使用できない</q>ようですが、同種のプラグインは多くあるようなのでそちらを使っていただいても構いません。</dd>
<dt><a href="http://wordpress.org/extend/plugins/similar-posts/">Similar Posts</a></dt>
<dd>関連記事を表示させるためのプラグイン</dd>
<dt><a href="http://wordpress.org/extend/plugins/post-plugin-library/">Post-Plugin Library</a></dt>
<dd>上記プラグインを利用するために必要なプラグイン。これを利用したプラグインとして、上記意外にも人気記事を表示する<a href="http://wordpress.org/extend/plugins/popular-posts-plugin/">Popular Posts</a>などがあるので、余裕があれば試してみては。</dd>
</dl>
<h4 id="tfe6807">入れたら便利なプラグイン<a id="optional-plugin"></a></h4>
<p>入れなくても良いけど、実害はあまりないし便利なので入れておくことをオススメするプラグインです。</p>
<dl>
<dt><a href="http://elvery.net/drzax/more-things/wordpress-footnotes-plugin/">WP-Footnotes</a></dt>
<dd>本文中に<code>&#x28;&#x28;脚注の内容&#x29;&#x29;</code>と書くだけで脚注を生成してくれるプラグインです、ちょっとした余談で話の腰を折らずにすみます</dd>
<dt><a href="http://scott.yang.id.au/code/toc-generator/">Table of Contents Generator</a></dt>
<dd>本文中に<code>&lt;!--TOC--%gt;</code>と書くだけで見出しを拾って、目次を生成してくれるプラグインです、長めの記事を書くときは読者のことを考えてできるだけ使った方がよいでしょう</dd>
<dt><a href="http://note.openvista.jp/2007/amazon-linkage-plugin/">Amazon Linkage</a></dt>
<dd>本文中に<code>&lt;amazon&gt;ASIN&lt;/amazon&gt;</code>と書くだけで<span class="weaken">(ワンパターンですいません)</span>、ジャケット画像付きでAmazonへのリンクを貼れるプラグインです。</dd>
<dt><a href="http://wppluginsj.sourceforge.jp/ktai_style/">Ktai Style</a></dt>
<dd>携帯電話のアクセス時にコンテンツを読みやすいように最適化してくれるプラグインです。</dd>
</dl>
<h4 id="td00e26">スパム防止に役立つプラグイン</h4>
<p>入れておくと、スパム対策にてきめんの効果を発揮するプラグインです</p>
<dl>
<dt><a href="http://wp.somy.jp/spam-block-jp/">SOMY SpamBlock JP スパム対策プラグイン</a></dt>
<dd>コメントやトラックバックの内容にひらがなやカタカナが指定回数以上ない場合、該当のコメント等をスパム扱いするか、あるいは削除してくれるプラグインです。このプラグインを使って以来、半年に一回スパムが来るか来ないかという程度になりました。<ins><a href="http://note.openvista.jp/2008/wordpress-theme-cielo/comment-page-1/#comment-4853">セキュリティ上の懸念が残る</a>とご指摘を頂きました（今すぐに危険なわけではないようですが）。利用にあたっては、</ins></dd>
<dt><a href="http://sw-guide.de/wordpress/plugins/simple-trackback-validation/">Simple Trackback Validation</a></dt>
<dd>トラックバックが指定した条件に沿っていない場合、スパム扱いするか削除できるプラグインです。<a href="http://note.openvista.jp/profile/#trackback-policy">トラックバックポリシー</a>にも書いてありますが、記事のURLを含まないトラックバックは拒否するようにしています。</dd>
</dl>
<h3 id="t2be41b">仕様・技術情報</h3>
<p><a href="http://tech.openvista.jp/demo/wordpress/">デモサイト</a>にて技術情報を公開しています。</p>
<ul>
<li><a href="http://tech.openvista.jp/demo/wordpress/2008/html-expression/">cieloテーマで使えるHTMLコードの一覧</a></li>
<li><a href="http://tech.openvista.jp/demo/wordpress/2008/built-in-function/">cieloテーマ内蔵機能について</a></li>
<li><a href="http://tech.openvista.jp/demo/wordpress/2008/xhtml/">cieloテーマのXHTML構造について</a></li>
<li><a href="http://tech.openvista.jp/demo/wordpress/2008/faq/">cieloテーマのその他よくある質問</a></li>
</ul>
<h3 id="ta2bb6a">謝辞 &amp; 著作権表記<a id="copyright"></a></h3>
<p>このテーマは以下のリソースが無ければできていません。オープンなライセンスでいいものづくりをしてくれた皆さんに感謝。We&#8217;re standing on the shoulders of Giants!<span class="weaken">(お名前の敬称は略しています)</span></p>
<dl class="links">
<dt>Javascriptライブラリ</dt>
<dd><a href="http://jquery.com/">jQuery</a> by John Resig and the jQuery Team(GPL &amp; MIT License)</dd>
<dd><a href="http://leandrovieira.com/projects/jquery/lightbox/">jQuery lightbox plugin</a>(クリエイティブコモンズ 2.5 ブラジル 表示・改変禁止)</dd>
<dd><a href="http://webfx.eae.net/">WebFX</a> by Erik Arvidsson &amp; Emil A Eklund(Apache Software License 2.0)</dd>
<dd><a href="http://www.remus.dti.ne.jp/~a-satomi/bunsyorou/ArekorePopup.html">あれこれポップアップ</a> by ありみかさとみ(BSD License)</dd>
<dd><a href="http://www.twinhelix.com/css/iepngfix/">IE PNG Fix</a> by Angus Turnbull(GNU LGPL)</dd>
<dd><a href="http://www.xs4all.nl/~peterned/csshover.html">Whatever:hover</a> by Peter Nederiof(GNU LGPL)</dd>
<dt>アイコン</dt>
<dd><a href="http://www.famfamfam.com/lab/icons/silk/" title="famfamfam.com: Silk Icons">famfamfam.com: Silk Icons</a> by Mark James(クリエイティブコモンズ 2.5 表示)</dd>
<dd><a href="http://mayosoft.deviantart.com/art/AeroVista-for-Mac-28788188">AeroVista for Mac</a> by Mayosoft(クリエイティブコモンズ 3.0 表示・非営利・改変禁止)</dd>
<dd><a href="http://www.iconarchive.com/category/folder/aqua-blend-icons-by-laurent-baumann.html">Aqua Blend Icons</a> by Laurent Baumann(クリエイティブコモンズ 3.0 表示・非営利・継承)</dd>
<dd><a href="http://susumu.seph.ws/?page_id=11">McDo DESIGN &#8211; Icons</a> by Susumu Yoshida(クリエイティブコモンズ 2.5 日本 表示・改変禁止)</dd>
<dt>Flashプレイヤー</dt>
<dd><a href="http://www.jeroenwijering.com/?item=JW_FLV_Player">JW FLV Media Player</a> by Jeroen Wijering(クリエイティブコモンズ 3.0 表示・非営利・継承)</dd>
<dt>WordPressテーマ</dt>
<dd><a href="http://www.plaintxt.org/themes/sandbox/">Sandbox</a> by Scott Allan Wallick(GNU GPL)</dd>
</dl>
<p>ライセンスとかあまり関係ないけどこちらの方々にも感謝。</p>
<ul class="links">
<li>株式会社はてな<span class="weaken">(はてなブックマークAPIの提供元)</span></li>
<li>WordPress開発者の皆さん</li>
</ul>
<h3 id="t5edd4e">更新履歴</h3>
<div class="update">
<dl>
<dt>最終更新日</dt>
<dd>2011年9月13日 08時05分 </dd>
<dt>2008-10-28</dt>
<dd>検索結果の処理を修正</dd>
<dd>ボックスシャドウの生成順序を変更して、体感速度を向上させた</dd>
<dt>2008-10-26</dt>
<dd>一部ページで編集リンクが正常に機能していなかった問題を解消しました</dd>
<dd>脚注の表示方法を変更しました</dd>
<dt>2008-10-19</dt>
<dd>記事一覧ページの表示方法を変更しました</dd>
<dd>WordPress標準の回り込みの記述をサポートしました</dd>
<dd>ソーシャルブックマークのキャッシュを扱いを変更して、読み込み失敗を減らしました</dd>
<dd>関連URLの表示を変更しました</dd>
<dd>その他いくつかの細かい問題を解消しました</dd>
<dt>2008-10-11</dt>
<dd><a href="http://note.openvista.jp/2008/online-pdf-reader/">オンラインPDFリーダ</a>のリリースにあわせて、PDFと思われるリンクをそちらに向けて書き換えるようにしました</dd>
</dl>
<input type="button" value="全ての更新履歴を表示する" onclick="hideShow('more_updates', this);" onkeypress="hideShow('more_updates', this);" />
<dl id="more_updates" style="display:none;">
<dt>2008-09-23</dt>
<dd>mp4動画も再生できるのにshowFLVメソッド名はどうかと思うので、showMovieメソッドに変更</dd>
<dd>自作動画がフルスクリーン表示できなかった問題を解消</dd>
<dt>2008-09-22</dt>
<dd>サイト外関連記事が少ないときの表示上の問題を解消</dd>
<dt>2008-09-21</dt>
<dd>ウェブメモでのはてなブックマークデータはキャッシュしないようにした</dd>
<dt>2008-09-20</dt>
<dd>付随サービスのURL変更に伴う更新</dd>
<dd>検索結果や時期別・カテゴリ別・タグ別など場面に合わせたフィードを追加しました</dd>
<dt>2008-09-19</dt>
<dd>iPhone向けにYoutube動画を提供する際、YoutubeアプリではなくSafari内蔵動画プレイヤーで見てもらうことにした<span class="weaken">(Youtubeアプリは縦画面での閲覧が出来ないなど使い勝手に問題があるため)</span></dd>
<dd>著者別記事一覧が正常に表示されない問題を解消</dd>
<dd>地図が表示されない問題を解消</dd>
<dd>重複コードを削除</dd>
<dt>2008-09-18</dt>
<dd>IE6/7以外のブラウザ向けのスタイルを更新</dd>
<dd>ウェブメモにおける表示の問題を解消</dd>
<dd>トップページに表示した記事の続きを非同期で読み込めるようにした</dd>
<dd>必須プラグインのインストールやキャッシュフォルダのパーミッションなど動作要件のチェックを厳しく行うようにした</dd>
<dt>2008-09-17</dt>
<dd>関連記事表示の位置を変更した</dd>
<dd>記事一覧ページの表示内容を変更した</dd>
<dd>はてなブックマークのデータをキャッシュし、はてなのサーバにあんまり話しかけすぎないようにした</dd>
<dd>依存しているプラグインを1つ減らした<span class="weaken">(正確には3つ減らして2つ増やした)</span></dd>
<dd>PEARパッケージを使わないようにした</dd>
<dd>その他細々とした修正</dd>
<dt>2008-09-16</dt>
<dd>記事中でカテゴリおよびタグを両方表示できるようにした</dd>
<dd>カテゴリおよびタグ一覧がうまく表示されなかった問題を修正</dd>
<dd>記事の一覧表示時、うまく表示されなかった問題を修正</dd>
<dt>2008-09-15</dt>
<dd>PEARファイルに依存せず、自前のファイルで処理を行うように修正</dd>
<dt>2008-09-14</dt>
<dd>初回リリース</dd>
</dl>
</div>
<p><amazon>4839929548</amazon></p>
<img src="http://note.openvista.jp/?ak_action=api_record_view&id=626&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/wordpress-theme-cielo/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Googleストリートビューで道案内</title>
		<link>http://note.openvista.jp/2008/directions-by-google-street-view/</link>
		<comments>http://note.openvista.jp/2008/directions-by-google-street-view/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 17:29:08 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ツールの制作]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=598</guid>
		<description><![CDATA[Googleストリートビューで決められた経路を自動で案内するプログラムを書いてみました]]></description>
			<content:encoded><![CDATA[<p><a href="http://note.openvista.jp/2008/streetview-maps-for-real-estate-rental-website/">前</a>に続いて、今回はGoogleストリートビューを道案内に使ってみようと思います。あらかじめ指定した経路をボタン操作で行ったり来たりします、自動案内（3秒ごとに移動）も可能です。<a href="http://video.alpslab.jp/">ALPSLAB video</a>に少し似ているかも。</p>
<p>あまりJavascriptに理解していないところもあるので、ちょっとレガシーなブラウザだと動作速度が気になるくらいの出来です。画像を読み込まないうちにずんずん先に行っちゃうと、ブラウザがたまに固まっちゃいます…。</p>
<p>ではとりあえず、例として京都の烏丸御池駅から（株）はてな京都本社までの道案内を。徒歩2-3分くらいでしょうか。</p>
<p class="maps-wide"><object data="http://note.openvista.jp/wp-content/themes/cielo/module/map.php?type=navigation&amp;fName=map/hatena.json" type="text/html" width="100%" height="350"><a href="http://note.openvista.jp/wp-content/themes/cielo/module/map.php?type=navigation&amp;fName=map/hatena.json">拡大地図を表示</a></object></p>
<p>こちらは東京。西新宿駅から（株）ミツエーリンクスまで。徒歩8分くらいですが、かなり長く感じます。移動速度がそれほど速くないので、徒歩6分くらいまでが使っていて耐えられるくらいの時間でしょうか。</p>
<p class="maps-wide"><object data="http://note.openvista.jp/wp-content/themes/cielo/module/map.php?type=navigation&amp;fName=map/mitsue.json" type="text/html" width="100%" height="350"><a href="http://note.openvista.jp/wp-content/themes/cielo/module/map.php?type=navigation&amp;fName=map/mitsue.json">拡大地図を表示</a></object></p>
<h3 id="t709fcf">技術的な話</h3>
<p>前回とほぼ同じ感じで全画面ストリートビューをobject要素<sup><a href="http://note.openvista.jp/2008/directions-by-google-street-view/#footnote_0_598" id="identifier_0_598" class="footnote-link footnote-identifier-link" title="iframe要素にしないのはXHTML1.1に適合させるため">1</a></sup> で読み込んでいます。</p>
<p>経路データはJSONで記述していて、fNameというクエリで指定します<span class="weaken">（はてなの例だと<a href="http://note.openvista.jp/wp-content/themes/cielo/module/map.php?type=navigation&amp;fName=map/hatena.json">http://note.openvista.jp/..（中略）..&amp;fName=map/hatena.json</a>）</span>。</p>
<p>JSON経路データは大きくstart, goal, pointsと3つのキー群があって、それぞれ始点の緯度経度、終点の緯度経度、そして行動になります。行動には5つのパラメータがあり、それぞれ行動の種類（type）・進行方向（dir）・左右向き（yaw）・上下向き（pit）、コメント（com）が指定できます。行動の種類は視点の変更のみ（pan）と移動（walk）が指定できます。</p>
<p>移動の場合、進行方向が必須オプションになっており、0～360度<sup><a href="http://note.openvista.jp/2008/directions-by-google-street-view/#footnote_1_598" id="identifier_1_598" class="footnote-link footnote-identifier-link" title="北:0, 東:90, 南:180, 西:270">2</a></sup> で指定します。視点変更の場合は、左右・上下の向きが必須で左右向きは0～360度で、上下向きは-90～90度<sup><a href="http://note.openvista.jp/2008/directions-by-google-street-view/#footnote_2_598" id="identifier_2_598" class="footnote-link footnote-identifier-link" title="真上が-90, 水平が0, 地上が90">3</a></sup> で指定が必須になります。</p>
<p>debugクエリをつけると、緯度・経度、向きが出るようになっているので、始点位置を探す場合などはこれを利用すると探しやすいです。</p>
<p>やっていて困った点はinitializedイベントで呼び出すGmap#panToイベントがかなり重いのか、画像が読み込まないうちに次々と移動された場合、panToイベントがブラウザを固まらせてしまうところです。結局毎回の移動時に呼ぶのではなく、5回に1回呼ぶようにしています。</p>
<p>あー、しかし、つくづくiPhoneがFlashに対応していないのが悔やまれます。</p>
<dl class="download">
<dt>ダウンロード</dt>
<dd><a href="http://note.openvista.jp/download/2008/08/map.zip">ストリートビュー道案内作成スクリプト</a></dd>
<dt>ライセンス</dt>
<dd><a rel="license" href="http://ja.wikipedia.org/wiki/GNU_General_Public_License">GNU General Public License</a></dd>
</dl>
<p>以下、参考にしたリンク先です。</p>
<ul class="links">
<li>Google
<ul>
<li><a href="http://code.google.com/apis/maps/documentation/services.html#Streetview">Services &#8211; Google Maps API &#8211; Google Code</a></li>
<li><a href="http://code.google.com/intl/en/apis/maps/documentation/reference.html#GStreetviewLocation">Google Maps API Reference &#8211; Google Maps API &#8211; Google Code</a></li>
</ul>
</li>
<li><a href="http://d.hatena.ne.jp/Kappuccino/20080807/1218110189">ストリートビューのAPI（京都散策のサンプル） &#8211; プログラマはサイコロを振らない</a></li>
<li><a href="http://d.hatena.ne.jp/tek_koc/20080808/1218181787">Google Map APIを使ったことがない人でもわかるストリートビューの使い方 &#8211; 遥か彼方の彼方から</a></li>
<li>AjaxTower
<ul>
<li><a href="http://www.ajaxtower.jp/googlemaps/gstreetviewpanorama/index.html">ストリートビュー(GStreetviewPanorama) &#8211; Google Maps入門</a></li>
<li><a href="http://www.ajaxtower.jp/googlemaps/gdownloadurl/index4.html">JSON形式のファイルの取得 &#8211; 外部ファイルの読み込み &#8211; Google Maps入門</a></li>
</ul>
</li>
<li>parpue.net
<ul>
<li><a href="http://parpue.net/?p=249">parpue.net &#8211; ストリートビューと地図の連携</a></li>
<li><a href="http://parpue.net/?p=196">parpue.net &#8211; Googleストリートビューで勝手に下北沢周辺を散歩するやつ作ってみた</a></li>
</ul>
</li>
</ul>
<p><ins datetime="2008-08-16T13:00:07+09:00" class="block"><br />
Internet Explorer で表示されなかった問題を解消しました<br />
</ins></p>
<ol class="footnotes"><li id="footnote_0_598" class="footnote">iframe要素にしないのはXHTML1.1に適合させるため</li><li id="footnote_1_598" class="footnote">北:0, 東:90, 南:180, 西:270</li><li id="footnote_2_598" class="footnote">真上が-90, 水平が0, 地上が90</li></ol><img src="http://note.openvista.jp/?ak_action=api_record_view&id=598&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/directions-by-google-street-view/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>はてなブックマークのサイト移転対応への解決策を考える</title>
		<link>http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/</link>
		<comments>http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#comments</comments>
		<pubDate>Sat, 17 May 2008 12:35:23 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/?p=431</guid>
		<description><![CDATA[はてなブックマークがサイトの移転レスポンス（HTTP301レスポンス）に対応してブックマークデータを移動するようにしてほしいのですが、そのために、はてな側にどういう対応を取ってほしいのか考えてみます]]></description>
			<content:encoded><![CDATA[<p><a href="http://note.openvista.jp/2008/change-of-uri/" title="URI構造を変更しました - Liner Note">URI構造変更のお知らせ</a>を書いてからだいぶ経ってしまいましたが、続きです。サイト移転をはてブ側に対応してもらえればいいわけですが、そのためにどうすればよいのかちょっと考えます。</p>
<div class="toc">
<ol>
<li><a href="http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#t84222a">はてなアイデアでは</a></li>
<li><a href="http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#t59f2f2">どうやって移転を検知するか</a></li>
<li><a href="http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#tc06fc8">レンタル型ブログサービスをどうするか</a></li>
<li><a href="http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#t54351b">移転先のURLが既にブックマークされていたらどうするか</a></li>
<li><a href="http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#te85bb8">まとめ</a></li>
</ol>
</div>
<h3 id="t84222a">はてなアイデアでは</h3>
<p>まず<a href="http://i.hatena.ne.jp/" title="はてなアイデア">はてなアイデア</a>では、これに関して次の3つが要望として出ているようです。</p>
<ol>
<li><a href="http://i.hatena.ne.jp/idea/5732" title="はてなアイデア - 登録日時やコメントなどの情報を保ったまま、ブックマークしたURLを変更したい。（ページ移転時など）">はてなアイデア &#8211; 登録日時やコメントなどの情報を保ったまま、ブックマークしたURLを変更したい。（ページ移転時など）</a></li>
<li><a href="http://i.hatena.ne.jp/idea/12238" title="はてなアイデア - 被ブックマークされたURLが移転した時に、新しいURLに自動で変更する機能、または変更申し込み用フォーム。（301リダイレクトやポイント送信用のFOAF情報で移転を判断）">はてなアイデア &#8211; 被ブックマークされたURLが移転した時に、新しいURLに自動で変更する機能、または変更申し込み用フォーム。（301リダイレクトやポイント送信用のFOAF情報で移転を判断）</a></li>
<li><a href="http://i.hatena.ne.jp/idea/13918" title="はてなアイデア - 301 Permanent redirectに対応し、URLを自動変更する。あるいは何らかのトリガーで301を検知し、URLを更新可能にする。">はてなアイデア &#8211; 301 Permanent redirectに対応し、URLを自動変更する。あるいは何らかのトリガーで301を検知し、URLを更新可能にする。</a></li>
</ol>
<p>2番目のアイデアでは<a href="http://i.hatena.ne.jp/naoya/" title="はてなアイデア">id:noya</a>さんは<q cite="http://i.hatena.ne.jp/idea/12238" title="はてなアイデア - 被ブックマークされたURLが移転した時に、新しいURLに自動で変更する機能、または変更申し込み用フォーム。（301リダイレクトやポイント送信用のFOAF情報で移転を判断）">ブックマークされた全エントリーを定期的に観測するのは実装コスト上高くなりすぎるので現時点では難しいです。URL 編集は、URL は全ユーザーで共通で悪意のある操作をされた場合に非常にクリティカルなので、これも難しいかもしれません。</q>と言ってまして、まぁこれは確かにその通りです。</p>
<p>かといって、<a href="http://www.blogpeople.net/" title="BlogPeople - ブログ情報ポータル・ブログランキング">BlogPeople</a>のように寄せられたサイト移転申請の判断・確認を人手でするのは<span class="weaken">（ユーザが技術的作業をしないのでユーザには優しいですが）</span>、運営側の人的コストがかかりすぎます。ということでユーザ側がフォームなどから変更するのではなく、サーバ側で移転を検知する方がよさそうです。</p>
<h3 id="t59f2f2">どうやって移転を検知するか</h3>
<p>定期的に観測するのは確かにコストが高いので、<a href="http://i.hatena.ne.jp/idea/13918" title="はてなアイデア - 301 Permanent redirectに対応し、URLを自動変更する。あるいは何らかのトリガーで301を検知し、URLを更新可能にする。">idea:13918のように何らかのトリガーで301を検知し、URLを更新可能にする</a>のが現実的でしょう。で、何がトリガーになりうるかを少し考えてみると以下のような物が挙げられます。</p>
<dl>
<dt>(1) ブックマークページを登録しようとした際にページのサーバ側でステータスコードをチェックする</dt>
<dd>登録処理はリクエスト数が多く、その度にチェック作業を入れていては、レスポンスが低下しかねない。また、対象のURLが多い場合はユーザ側の負担が多すぎる。よってこれは却下。</dd>
<dt></dt>
<dt>(2) はてな側にサイトマップファイルを送信して（もしくはトップページに配置してフォームから告知→クロール）ファイルに書かれているURLのステータスコードをチェックする</dt>
<dd>サイトマップファイルとは、<a href="https://www.google.com/webmasters/tools/docs/ja/protocol.html" title="Google ウェブマスター ツール">サイトマッププロトコル準拠のXML</a>です。作成には<a href="http://crawler.google-sitemaps.jp/crawler/" title="URL収集機能付きバージョン - サイトマップXML自動生成ツール">Google謹製の自動作成ツール</a>や<a href="http://code.google.com/sm_thirdparty.html" title="Sitemaps Third Party Programs &#038; Websites - Google Code">サードパーティの製品</a>があるので、ユーザコスト的にも技術的にもそれほど難しくないだろうと思います。しかし、既に移転が終わってURLが変わってしまった場合は旧URLの一覧を出すのは難しいケースもあるのが、難点ですね。</dd>
<dt>(3) はてな側に対象となるサイトのトップページURLを送信し、そのサイト以下の全てのブックマーク済URLのステータスコードをチェックする</dt>
<dd>ユーザのコストは低いですし、ブックマークされていないURLまでクロールしなくて良いので効率性は良さそうですが、悪意あるユーザーに例えば http://d.hatena.ne.jp みたいな直下のブックマーク記事が極端に多いURLを指定されると、クローラがムダに汗をかく羽目になります。この場合は http://d.hatena.ne.jp/ID/ まで設定するようフィルタを設定する事になるのでしょうが、それはそれでURL設定の手間がかかりそうです。</dd>
</dl>
<p>ということで、(2)の方法がベターかなと思います。</p>
<p>ただ、この場合においても移転先が本当に移転URLなのかどうかはわかりませんので、必要に応じて、例えば指定されたHTMLファイルを置くなどして本人認証するという手もあります。が、そもそも移転先URLを偽装して得られるメリットはほとんど無いと思われるので問題はないでしょう。</p>
<h3 id="tc06fc8">レンタル型ブログサービスをどうするか</h3>
<p>しかし、.htaccessがそもそも置けない、つまりHTTPヘッダをいじれない環境下にあるレンタル型ブログサービス（例えばはてなダイアリー）は移転告知が出来ないので、こうした措置があっても受けることが出来ません。</p>
<p>これは機械的に対処が出来ないと言うことですからセキュリティと天秤にかけて対処できないという手もあるかとは思います。</p>
<p>が、あえて対処策を考えるなら例えば旧サイトに移転先URLを記したmetaタグを配置してもらい、新サイトURLにも指定したmetaタグを配置してもらう等といった方法でしょうか。</p>
<p>もちろん、移転元・移転先が同内容でなければならないので、本文の一致率なども求めるなどの照合作業もしなければならず、なかなか一筋縄ではいきそうにない感じです。</p>
<h3 id="t54351b">移転先のURLが既にブックマークされていたらどうするか</h3>
<p>移転元・移転先、いずれかだけブックマークされている状況ならブックマークがある方に統一すればいいわけで、それほど問題はないかと思います。が、移転元のURLと移転先のURLが既に同ユーザによってブックマークされていた場合は少し考える必要があると思います。</p>
<p>私は、新サイト側でつけられているブックマークの方がより最新のページ内容を<sup><a href="http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/#footnote_0_431" id="identifier_0_431" class="footnote-link footnote-identifier-link" title="移転先だけ更新が進んでいるケースなど">1</a></sup> ブックマークしていることが多いと思われるので、新サイト側のブックマークを優先する（同ユーザの旧サイト側ブックマークは破棄する）のが良いかと思います。</p>
<h3 id="te85bb8">まとめ</h3>
<p>案外きちんと考えて直してみると、セキュリティ対策などなかなか難しいなと思わされます。ブックマークデータの移動という一歩間違えばサービスにかなりのダメージが来ることなので、はてなの中の人が動いてくれるのを期待するのはちょっと難しいかなとも思います。</p>
<p>さて、一応それはおいといてここで対応策をまとめておきます。まずユーザ側にサイトマップファイルを送信してもらい、はてな側がその一覧（のうち、ブックマークが付いているURL）をクロール。HTTPレスポンス<code>301 Moved Permanently</code>を受け取ったら、移転先のURLにブックマークデータを移動します。</p>
<p>もし、移転元・移転先のURLに同ユーザがブックマークをつけていた場合は、移転先URLのブックマークを優先しつつ、マージします。</p>
<ol class="footnotes"><li id="footnote_0_431" class="footnote">移転先だけ更新が進んでいるケースなど</li></ol><img src="http://note.openvista.jp/?ak_action=api_record_view&id=431&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/hatena-bookmark-how-to-redirect/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP汎用スクレイピングライブラリを作ってみた</title>
		<link>http://note.openvista.jp/2008/php-scraing-library/</link>
		<comments>http://note.openvista.jp/2008/php-scraing-library/#comments</comments>
		<pubDate>Sun, 10 Feb 2008 08:50:55 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ウェブデザイン]]></category>
		<category><![CDATA[ツールの制作]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/251/</guid>
		<description><![CDATA[ページから必要な部分だけをXPath式で抽出するPHP製汎用スクレイピングライブラリを作った]]></description>
			<content:encoded><![CDATA[<p>いままでスクレイピングを使ったサービス（<a href="http://note.openvista.jp/249/" title="Liner Note - iPod touch専用 料理レシピ検索サービスを作った">レシピ検索</a>、<a href="http://note.openvista.jp/241/" title="Liner Note - 書籍在庫一括検索サービス ver 0.2ーMaking OPAC 2.0 (2)">書籍在庫一括検索</a>）を作ってきましたが、そこで使ったものを簡単に再利用できるように、PHP5で使える汎用スクレイピングライブラリを作ってみました。</p>
<p>スクレイピング結果の表示はHTMLとXMLとRSS 2.0に対応しています。動作させるにはPEAR::HTTP Clientが必要です。</p>
<dl>
<dt>表示サンプル</dt>
<dd><a href="http://tech.openvista.jp/scraping/PHP.html" title="PHP - Google 検索">PHPをGoogleで検索した結果</a>（HTML）</dd>
<dd><a href="http://tech.openvista.jp/scraping/PHP.xml" title="PHP - Google 検索">PHPをGoogleで検索した結果</a>（XML）</dd>
<dd><a href="http://tech.openvista.jp/scraping/PHP.rss" title="PHP - Google 検索">PHPをGoogleで検索した結果</a>（RSS 2.0）</dd>
</dl>
<p>サンプルではGoogleの検索結果のタイトルと説明を拾って表示する処理をしています。コントローラー部分はこんな感じ。</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-reserved">require_once</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">HTTP/Client.php</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-reserved">require_once</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">scraper.Class.php</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-comment">// インスタンスを生成</span>
<span class="codes-var">$scraper</span><span class="codes-code"> = </span><span class="codes-reserved">new</span><span class="codes-code"> </span><span class="codes-identifier">WebScraper</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">http://www.google.co.jp/search?q=</span><span class="codes-quotes">&quot;</span><span class="codes-code">, </span><span class="codes-quotes">&quot;</span><span class="codes-string">UTF-8</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code"> </span>
<span class="codes-comment">// キーワードが入力されている場合はゲット</span>
<span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-code">!</span><span class="codes-reserved">empty</span><span class="codes-brackets">(</span><span class="codes-var">$_GET</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">q</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">])){</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-comment">// XMLに変換して格納</span>
<span class="codes-code">  </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">retrieve</span><span class="codes-brackets">()</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-comment">// 要素を抽出して、変数に代入</span>
<span class="codes-code">  </span><span class="codes-var">$titles</span><span class="codes-code"> = </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">pickUpElement</span><span class="codes-brackets">(</span><span class="codes-quotes">'</span><span class="codes-string">//a[@class=&quot;l&quot;]</span><span class="codes-quotes">'</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-var">$links</span><span class="codes-code">  = </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">pickUpElement</span><span class="codes-brackets">(</span><span class="codes-quotes">'</span><span class="codes-string">//a[@class=&quot;l&quot;]/@href</span><span class="codes-quotes">'</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-var">$descs</span><span class="codes-code">  = </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">pickUpElement</span><span class="codes-brackets">(</span><span class="codes-quotes">'</span><span class="codes-string">//div[@class=&quot;std&quot;]</span><span class="codes-quotes">'</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-var">$count</span><span class="codes-code">  = </span><span class="codes-identifier">count</span><span class="codes-brackets">(</span><span class="codes-var">$titles</span><span class="codes-brackets">)</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-comment">// キーワードをUTF-8に戻す</span>
<span class="codes-code">  </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">keyword</span><span class="codes-code"> = </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">convertKeyword</span><span class="codes-brackets">()</span><span class="codes-code">;</span>
<span class="codes-code">  </span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-reserved">switch</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$_GET</span><span class="codes-brackets">[</span><span class="codes-quotes">&quot;</span><span class="codes-string">type</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">]){</span>
<span class="codes-code">  </span><span class="codes-reserved">case</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">html</span><span class="codes-quotes">&quot;</span><span class="codes-code">: </span><span class="codes-reserved">require</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">template.html.php</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">; </span><span class="codes-reserved">break</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">case</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">xml</span><span class="codes-quotes">&quot;</span><span class="codes-code"> : </span><span class="codes-reserved">require</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">template.xml.php</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;  </span><span class="codes-reserved">break</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">case</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">rss</span><span class="codes-quotes">&quot;</span><span class="codes-code"> : </span><span class="codes-reserved">require</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">template.rss.php</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">;  </span><span class="codes-reserved">break</span><span class="codes-code">;</span>
<span class="codes-code">  </span><span class="codes-reserved">default</span><span class="codes-code">    : </span><span class="codes-reserved">require</span><span class="codes-brackets">(</span><span class="codes-quotes">&quot;</span><span class="codes-string">template.html.php</span><span class="codes-quotes">&quot;</span><span class="codes-brackets">)</span><span class="codes-code">; </span><span class="codes-reserved">break</span><span class="codes-code">;</span>
<span class="codes-brackets">}</span>
<span class="codes-code"> </span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>スクレイピングするURLは動的なもの（検索語などクエリが混ざっているもの）と静的なものに分かれると思います。このライブラリでは、動的なURLの場合にフォームから検索できるようにするため、これらを別々に処理しています。</p>
<pre class="command">
// インスタンスを生成
$scraper = new WebScraper("http://www.google.co.jp/search?q=", "UTF-8");
</pre>
<p>今回はGoogleに検索語を投げる処理なので、動的なURLにあたります。もし、静的なURLであれば、インスタンスを生成する際の3番目の引数に<code>true</code>を指定してください。</p>
<p>インスタンスを生成する際に、検索語を投げるURL（もしくは静的なURL）とその文字エンコーディングを指定します。</p>
<pre class="command">
// XMLに変換して格納（その際に不必要なタグを除去）
$scraper->retrieve("<\/?b>");
</pre>
<p>指定されたURLをゲットしてSimpleXML Objectに変換します。</p>
<p><ins datetime="2008-03-12T17:26:49+09:00" class="block"><br />
以下の手順は、バージョンアップにより不要になりました。<br />
</ins></p>
<p><del datetime="2008-03-12T17:26:49+09:00" class="block"><br />
その際、タグがネストしているとうまくいかない場合があるので、不必要な要素を消去します。</p>
<p>たとえば、<code>&lt;a href="http://example.com"&gt;あれこれ&lt;em&gt;に加えて&lt;/em&gt;どれこれ&lt;/a&gt;</code>というコードだとa要素の中身を指定しても、<samp>あれこれどれこれ</samp>という風に、em要素の中身がすっ飛んでしまうため、em要素を消しておく必要があります。</p>
<p>よって、ここでHTMLから消去する要素を正規表現で指定しておきます。<br />
</del></p>
<pre class="command">
// 要素を抽出して、変数に代入
$titles = $scraper->pickUpElement('//a[@class="l"]');
$links  = $scraper->pickUpElement('//a[@class="l"]/@href');
$descs  = $scraper->pickUpElement('//div[@class="std"]');
$count  = count($titles);
</pre>
<p>さきほど、ゲットしたXMLからゲットしたい部分を抽出して変数に格納します。抽出する部分はXPath式で指定してください。ゲットに成功していれば、文字列が配列で格納されます（CSSはわかるけど、XPathシラネって人は<a href="http://piro.sakura.ne.jp/latest/blosxom/mozilla/xul/2007-09-13_selector-to-xpath.htm" title="Latest topics &gt; CSS3セレクタとXPathでの表現の対応表 - outsider reflex">Latest topics &gt; CSS3セレクタとXPathでの表現の対応表 &#8211; outsider reflex</a>を参照してみてください）。</p>
<p>格納された文字列は、ビュー部分でたとえば以下のように出力します（例はHTML）</p>
<div class="source-code"><div><img src="http://note.openvista.jp/wp-content/plugins/coolcode/code.png" width="16" height="16" alt="" /> <em>PHPソースコード</em></div><pre class="source-code"><code><span class="codes-inlinetags">&lt;?php</span>
<span class="codes-code">  </span>
<span class="codes-code">  </span><span class="codes-comment">// 設定に失敗していたら離脱</span>
<span class="codes-code">  </span><span class="codes-reserved">if</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">isError</span><span class="codes-brackets">()</span><span class="codes-code"> != </span><span class="codes-reserved">false</span><span class="codes-brackets">){</span>
<span class="codes-code">    </span>
<span class="codes-code">    </span><span class="codes-var">$scraper</span><span class="codes-code">-&gt;</span><span class="codes-identifier">isError</span><span class="codes-brackets">()</span><span class="codes-code">;</span>
<span class="codes-code">    </span>
<span class="codes-code">  </span><span class="codes-brackets">}</span><span class="codes-code"> </span><span class="codes-reserved">else</span><span class="codes-brackets">{</span>
<span class="codes-code">    </span>
<span class="codes-code">    </span><span class="codes-reserved">for</span><span class="codes-code"> </span><span class="codes-brackets">(</span><span class="codes-var">$i</span><span class="codes-code">=</span><span class="codes-number">0</span><span class="codes-code">; </span><span class="codes-var">$i</span><span class="codes-code">&lt;</span><span class="codes-var">$count</span><span class="codes-code">; </span><span class="codes-var">$i</span><span class="codes-code">++</span><span class="codes-brackets">){</span>
<span class="codes-code">      </span><span class="codes-var">$msg</span><span class="codes-code"> .= </span><span class="codes-quotes">&quot;</span><span class="codes-string">&lt;dt&gt;</span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$titles</span><span class="codes-brackets">[</span><span class="codes-var">$i</span><span class="codes-brackets">]</span><span class="codes-code">.</span><span class="codes-quotes">&quot;</span><span class="codes-string">&lt;/dt&gt;</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code">      </span><span class="codes-var">$msg</span><span class="codes-code"> .= </span><span class="codes-quotes">&quot;</span><span class="codes-string">&lt;dd&gt;</span><span class="codes-quotes">&quot;</span><span class="codes-code">.</span><span class="codes-var">$descs</span><span class="codes-brackets">[</span><span class="codes-var">$i</span><span class="codes-brackets">]</span><span class="codes-code">.</span><span class="codes-quotes">&quot;</span><span class="codes-string">&lt;/dd&gt;</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code">    </span><span class="codes-brackets">}</span>
<span class="codes-code">    </span>
<span class="codes-code">    </span><span class="codes-reserved">echo</span><span class="codes-code"> </span><span class="codes-quotes">&quot;</span><span class="codes-string">&lt;dl&gt;</span><span class="codes-quotes">&quot;</span><span class="codes-code">. </span><span class="codes-var">$msg</span><span class="codes-code"> .</span><span class="codes-quotes">&quot;</span><span class="codes-string">&lt;/dl&gt;</span><span class="codes-quotes">&quot;</span><span class="codes-code">;</span>
<span class="codes-code">    </span>
<span class="codes-code">  </span><span class="codes-brackets">}</span>
<span class="codes-inlinetags">?&gt;</span></code></pre></div>
<p>PHPフレームワーク（rhacoとか）にはスクレイピングライブラリがくっついているし、マイナーだけど<a href="http://www.gac.jp/article/index.php?stats=question&amp;category=11&amp;id=9181&amp;command=msg" title="GAC なぜなにGAC-&gt;PHP">SNOOPYというスクレイピングライブラリ</a>もありますから、車輪の再発明には違いないんですけどね。perlやrubyみたいにもうちょっとこの手のライブラリが充実していってほしいもんです。</p>
<h3 id="t63271b">ダウンロード</h3>
<dl class="download">
<dt>ダウンロード</dt>
<dd><a href="http://tech.openvista.jp/scraping/scraping.zip">汎用スクレイピングライブラリ</a></dd>
<dt>ライセンス</dt>
<dd><a href="http://ja.wikipedia.org/wiki/BSD%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9" rel="copyright">修正BSDライセンス</a></dd>
<dd>HTMLParser.Class.php, xhtml1-transitional_dtd.inc.php, XMLフォルダ以下のファイルについてはGNU LGPLライセンス</dd>
</dl>
<h3 id="t2b61fc">更新履歴</h3>
<div class="update">
<dl>
<dt>v0.2.3 (20080322)</dt>
<dd>検索ワードが変わってしまう問題を解消</dd>
<dd>フォームページの記述ミスによりうまく検索できなくなっていた問題を解消</dd>
<dd>（ライブラリそのものとはあまり関係ないですが）Google側の仕様変更により、再度検索説明が拾えなくなっていた問題を解消</dd>
<dt>v0.2.2 (20080312)</dt>
<dd>要素がうまく拾えない問題を解決しました（Thanks! Phizeさん）</dd>
<dd>これに伴い、特定のタグを消去する作業が不要になりました</dd>
<dt>v0.2.1 (20080217)</dt>
<dd>トップ画面がうまく表示されない問題を修正しました</dd>
<dd>文字エンコーディングの処理を改善しました</dd>
<dd>XMLやRSSにおいてパースエラーが発生する可能性がある問題を修正しました</dd>
<dd><a href="http://www.rcdtokyo.com/ucb/contents/i000799.php" title="HTMLを整形式のXML文書に修正するPHPクラス : Under Construction, Baby">HTMLを整形式のXML文書に修正するPHPクラス</a>は併用した場合、処理に失敗するケースもあったので、いったん使用しないようにしました</dd>
<dt>v0.2 (20080214)</dt>
<dd>RSS 2.0での出力を加えました</dd>
<dd><a href="http://www.rcdtokyo.com/ucb/contents/i000799.php" title="HTMLを整形式のXML文書に修正するPHPクラス : Under Construction, Baby">HTMLを整形式のXML文書に修正するPHPクラス</a>での処理を挟みこむようにした</dd>
<dt>v0.1</dt>
<dd>初リリース</dd>
</div>
<h3 id="t129f04">既知の問題点</h3>
<dl>
<dt>POSTで取得するリソースを取得できない</dt>
<dd>実装自体は簡単ですが、どう実装するかという話です。あんまりオプションを増やしたくないので</dd>
<dt>認証がかかったりソースを取得できない</dt>
<dd>これも上記に同じ。このニーズも大きいと思います。</dd>
</dl>
<h3 id="t7c0384">参考にしたURL</h3>
<ul>
<li><a href="http://goungoun.dip.jp/app/fswiki/wiki.cgi/devnotebook?page=PHP5%A1%A2%CC%A4%C0%B0%B7%C1HTML%A4%F2SimpleXML%A4%D8%CA%D1%B4%B9" title="PHP5、未整形HTMLをSimpleXMLへ変換 - goungoun技術系雑記帳">PHP5、未整形HTMLをSimpleXMLへ変換 &#8211; goungoun技術系雑記帳</a></li>
</ul>
<p><ins datetime="2008-03-12T17:31:35+09:00" class="block"><br />
Phizeさんが<a href="http://dxd8.com/archives/85/" title="PHPでのスクレイピングに役立つライブラリ - (DxD)∞">このスクリプトも含めてPHPのスクレイピングに役立つライブラリをまとめてくださって</a>います。このスクリプトでできないこともありますので、参考にしてください。<br />
</ins></p>
<img src="http://note.openvista.jp/?ak_action=api_record_view&id=348&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/php-scraing-library/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>本のサイズ比較をAmazon APIで</title>
		<link>http://note.openvista.jp/2008/book-size-comparison-with-amazon/</link>
		<comments>http://note.openvista.jp/2008/book-size-comparison-with-amazon/#comments</comments>
		<pubDate>Sat, 09 Feb 2008 17:20:15 +0000</pubDate>
		<dc:creator>hash</dc:creator>
				<category><![CDATA[ウェブ標準技術絡み]]></category>
		<category><![CDATA[ツールの制作]]></category>
		<category><![CDATA[プログラミング技術絡み]]></category>

		<guid isPermaLink="false">http://note.openvista.jp/250/</guid>
		<description><![CDATA[Amazon APIを使って書籍のサイズ比較をしてみる]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.itmedia.co.jp/bizid/articles/0802/05/news087.html" title="3分LifeHacking：「通販で本を買ったら予想より大きかった」を解決する - ITmedia Biz.ID">3分LifeHacking：「通販で本を買ったら予想より大きかった」を解決する &#8211; ITmedia Biz.ID</a></p>
<p>本の大きさを比較するWindowsのソフトウェアがあるよという話。</p>
<p><q cite="http://b.hatena.ne.jp/Kmusiclife/20080206#bookmark-7370218">amazon api使ってwebで実装すると面白そう。</q>というコメントもあるし、「それCSSでできるよ！」と思ったので作ろうと思ったんだけど、どこかにしまった記憶を引っ張り出してみれば、CSSで使える絶対単位というのはどの環境でも同じサイズで表示されるわけではない、つまり絶対単位じゃないんですよね。</p>
<div style="width: 5cm; height: 5cm; background-color: gray; color: white; font-size: 80%;">この図形は5cm×5cmの正方形として描かれているかな？</div>
<p>サーバサイド言語あるいはJavascriptか何かでユーザの出力解像度（DPI）と表示解像度（1024&#215;768とか）と画面サイズ（cm単位）が取れればなんとかなるんでしょうが、そんなことができるというのは聞いたことがありません（ご存じでしたら教えてください）。まぁ、この話は以下のリソースに譲ります。</p>
<ul>
<li><a href="http://www.web-mame.net/css_course/css_size.html" title="WEB作成の豆知識 -CSS講座 CSSで使用する単位-">WEB作成の豆知識 -CSS講座 CSSで使用する単位-</a></li>
<li><a href="http://www.phoenix-c.or.jp/~zspc/cgi-bin/wwwlng.cgi?print+2000-07/00070099.txt" title="絶対指定は解像度に左右されず同サイズで表示されるのは本当？">絶対指定は解像度に左右されず同サイズで表示されるのは本当？</a></li>
<li><a href="http://www.phoenix-c.or.jp/~zspc/cgi-bin/wwwlng.cgi?print+2000-03/00030026.txt" title="サイズの絶対指定">サイズの絶対指定</a></li>
</ul>
<p>また、上記ソフトのようにあらかじめ定規でもって実測してもらって調整する（調整値をCookieとして食わせる）という手もありますが、面倒なのは変わりません。</p>
<p>ところで、ここでやりたいのは実際の書籍のサイズを表示することではなく、書籍がどれくらいのサイズがイメージをつかむことです。だとすれば、タバコとのサイズ比較みたいに新書とかを横に置いて比較できればいいわけです。</p>
<p>ということで、<a href="http://tech.openvista.jp/amazon/" title="Amazon.co.jp 非公式アイテム検索">Amazon.co.jp 非公式検索</a>にサイズ比較機能をつけてみました。ちなみに<a href="http://www.itmedia.co.jp/bizid/articles/0611/14/news029.html" title="ITmedia Biz.ID：モノの重さをわかりやすく例える">ITmedia Biz.ID：モノの重さをわかりやすく例える</a>を参考にして重さを自動的に例える機能もつけてみたよ。</p>
<p>サンプルは以下で。</p>
<p><a href="http://tech.openvista.jp/amazon/978-4873113296" title="David Flanagan, 村上 列『JavaScript 第5版』：Amazon.co.jp 非公式検索">David Flanagan, 村上 列『JavaScript 第5版』：Amazon.co.jp 非公式検索</a></p>
<p>…とりあえず、オライリーの本はデカくて重いということはわかりました。</p>
<img src="http://note.openvista.jp/?ak_action=api_record_view&id=347&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://note.openvista.jp/2008/book-size-comparison-with-amazon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

