CakePHPでAmazon Web Service

Posted by joeartsea on 2009-02-08

CakephpでAmazon Web Serviceを利用するためにモデルをうまく使います。今回はPEARのServices_Amazonは使いません。賛否両論あるかもしれませんが、依存しまくりのライブラリを安易に使うと運用上ダルくなるので僕はなるべく使いません。ネット上にはPEARを使う方法のほうが多いし。

では、まずはデータベースを使用しないようにモデルを書きます。

/app/models/test.php

1
2
3
4
5
class Test extends AppModel
{
var $name = 'Test';
var $useTable = false;
}

次にAmazon Web Serviceへアクセスするメソッドを実装します。

/cake/libs/model/app_model.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class AppModel extends Model
{
var $xml;
var $host = "ecs.amazonaws.jp";
var $base_path = "/onca/xml?Service=AWSECommerceService";
var $sub_id = "_自分のアクセスID_";
var $aid = "_自分のアソシエイトID_";
var $version = "2007-10-29";
var $contentType= "text/xml";
var $path = "";
function setKeyword($keyword, $index, $page)
{
$this->path = $this->base_path
. "&AWSAccessKeyId=" . $this->sub_id
. "&AssociateTag=" . $this->aid
. "&Version=" . $this->version
. "&ContentType=" . $this->contentType;
$this->path .= "&Operation=ItemSearch"
. "&ResponseGroup=Small,Offers,Images,BrowseNodes,SalesRank"
. "&Keywords=" . $keyword
. "&SearchIndex=" . $index
. "&Page=" . $page;
return true;
}
function loadXml()
{
$doc = $this->connect();
if(!$doc) return false;
if(substr($doc,0,5) != "<?xml") return false;
$this->xml = simplexml_load_string($doc);
return $this->xml;
}
function connect()
{
$sockPointer = fsockopen($this->host, 80, $errno, $errstr, 6);
if(!$sockPointer)
{
return false;
}
else
{
stream_set_timeout($sockPointer, 6, 0);
fputs ($sockPointer, "GET $this->path HTTP/1.0rnHost: $this->hostrnrn");
fputs ($sockPointer, "User-Agent: AwsDataSourcenn");
fputs ($sockPointer, "Keep-Alive: 300nn");
fputs ($sockPointer, "Connection: Keep-Alivenn");
fputs ($sockPointer, "Referer: http://www.artsnet.jp/nn");
$buf = "";
$response = fgets($sockPointer);
if(substr_count($response, "200 OK") > 0)
{
while(!feof($sockPointer))
{
$buf = $buf . fread($sockPointer,4096);
}
}
else
{
$result = false;
}
$result = true;
}
fclose($sockPointer);
if($result)
{
$doc = substr($buf, strpos($buf,"rnrn")+4);
return $doc;
}
else
{
return false;
}
}
}

ちなみにこのコードはWebサービスをAmazonで知る――PHPでECS 4.0を使うテクニックそのまんまです。

最後にコントロールで使います。

/app/model/controllers/tests_controller.php

1
2
3
4
5
6
7
8
9
10
11
class TestsController extends AppController
{
var $name = &#39;Tests&#39;;
function index()
{
$this->Test->setKeyword(&#39;PHP&#39;, &#39;Books&#39;, &#39;1&#39;);
$this->Test->loadXml();
print_r($this->Test->xml);
}
}

ちなみにCakePHPで楽天WEBサービスを使うのコメント欄でCakePHPのdatasourceをうまく使うヒントが書かれていました。これはデータ操作の全てをdatasourceに追いやることで、データ自体がRDBだろうがXMLだろうがJSONだろうが同じように使うためのものです。逆に言えばCakePHPでRDBを扱ってきたsetとかfindとか全てのメソッドが通るように実装しなければならないことを意味します。

今回はそんな必要も時間もないのでApp_modelで実装するだけにしました。