AWSのAPIを叩く(PHP 5)

On 2011年12月10日, in AWS, PHP, by タカ

PHPからAWS(EC2)のAPIを叩いてみたので書いてみる。

AWSの公式SDKがあるけど勉強がてらやってみた。

仕様は、

http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/

に書いてある。



準備

まずは、以下の二つを発行する。(AWSの管理コンソールの右上の「Security Credentials」から)

  1. アクセスキーID
  2. シークレットアクセスキー

すでに発行しているならばそれでもOK

Endpointを決める

リージョンによって叩く場所が異なる。

http://docs.amazonwebservices.com/general/latest/gr/index.html?rande.html#ec2_region

東京リージョンの場合はec2.ap-northeast-1.amazonaws.com

叩くAPI(Action)を決める

次に叩くAPIを決める。
インスタンスを起動したい!とかタグを打ちたい!とか。

http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?OperationList-query.html

今回は、インスタンス一覧取得(DescribeInstances)を選択したみる。

Action固有のパラメータを決める

Actionによって色んなパラメータがあるので、それぞれの仕様をみて決める。

DescribeInstancesはパラメータなしでも叩ける。

今回は、マイクロインスタンスで絞ってみる。

Key Value
Filter.1.Name instance-type
Filter.1.Value.1 t1.micro

必須パラメータを追加

EC2のAPIの場合、幾つか必須のパラメータがあるのでそれを追加。

http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?Query-Common-Parameters.html

Key Value
Action アクション名(今回は、DescribeInstances)
Version APIのバージョン(今回は、2011-11-01)
AWSAccessKeyId アクセスキーID
Timestamp YYYY-MM-DDThh:mm:ssZ(date(‘c’)で取得できる)
Signature 後述する方法で生成
SignatureMethod HmacSHA256 or HMacSHA1
SignatureVersion 2

これに、Action固有のパラメータを足したものが最終的に送るパラメータ。

Signatureの生成

オープンソーシャルなAPIも似たような方法で署名してた気がする。

手順は、

  1. 各Keyを元にソート(ksort)
  2. Key,ValueをURLEncode(RFC 3986)して&で連結
  3. 署名に使う文字列を生成(HTTPメソッド名+EndPoint+path+連結したパラメータ)
  4. 上記文字列とシークレットアクセスキーを使ってハッシュ生成(HMAC-SHA256 or HMAC-SHA1)
  5. base64エンコード

コードにすると以下のような感じ。
(HTTPメソッドとかベタ書きだけど…)

<?php
class Signer
{
    function sign($params, $secretAccessKey)
    {
        $params = $this->sortByKey($params);
        $string = $this->buildCanonicalString($params);
        $stringToSign = $this->buildStringToSign($string);
        $signature = base64_encode($this->hash($stringToSign, $secretAccessKey));
        return $signature;
    }

    private function sortByKey($params)
    {
        ksort($params);
        return $params;
    }

    private function buildCanonicalString($params)
    {
        $strings = array();
        foreach ($params as $key => $value) {
            $strings[] = $this->urlencode($key) . '=' . $this->urlencode($value);
        }
        return implode('&', $strings);
    }

    private function buildStringToSign($string)
    {
        $stringToSign = "GET\n"
                      . "ec2.ap-northeast-1.amazonaws.com\n"
                      . "/\n"
                      . $string;
        return $stringToSign;
    }

    private function hash($stringToSign, $secretAccessKey)
    {
        return hash_hmac('sha256', $stringToSign, $secretAccessKey, true);
    }

    // PHP 5.2.X系はチルダもエンコードするので元に戻す
    private function urlencode($value)
    {
        return str_replace('%7E', '~', rawurlencode($value));
    }
}

※PHP5.2系の環境はなかったので、PHP5.3でしか動作確認していない。

HTTPリクエスト送信

この時点で送信するパラメータはすべて揃ったので、file_get_contentsなりCurlなりお好きなようにどうぞ。

結果はXMLとして帰ってくるので、これもまたお好きなように。

まとめ

Signatureの生成がちょっと面倒だけど、そこ以外は特にハマるところはないと思う。

Signature生成/Httpリクエスト送信/EndPoint/ハッシュアルゴリズム

辺りを分離したクラスを作れば立派な簡易クライアントの出来上がり!

それは、また時間のある時にでも…。

Tagged with:  

PHPのXXXはRubyのYYYでPythonのZZZ

On 2011年5月31日, in PHP, Python, Ruby, by タカ

結構前に書いて下書きで眠ってた…。

せっかくなので、公開。

PHP, Ruby, Pythonの比較。

PHPで(個人的に)良く使う関数は他の言語ではどうすればいいんだろう?

という趣旨のエントリー。

ちょこちょこっとググったモノを使っているので、もっといいやり方をご存知の方は教えて下さい。


GET

PHP
<?php
$url = 'http://google.co.jp';
$string = file_get_contents($url);
echo $string;
Ruby
require 'open-uri'
url = 'http://google.co.jp'
results = ''open(url) {|f| results = f.read}
puts results
Python
import urllib
url = 'http://google.co.jp'
d = urllib.urlopen(url)
results = d.read()
d.close()

print results

URL encode/decode

PHP
<?php
$url = 'http://example.com/';
echo urlencode($url)."\n";
echo urldecode(urlencode($url))."\n";
Ruby
require 'cgi'
url = 'http://example.com/'
puts CGI::escape(url)
puts CGI::unescape(CGI::escape(url))
Python
import urllib
url = 'http://example.com/'
print urllib.quote(url, '')
print urllib.unquote(urllib.quote(url, ''))

HTMLのescape/unescape

PHP
<?php
$html = <<<EOD
<html>
<body>
body
</body>
</html>
EOD;

echo htmlspecialchars($html);
echo htmlspecialchars_decode(htmlspecialchars($html));
Ruby
require 'cgi'

html = <<EOD
<html>
<body>
body
</body>
</html>
EOD

puts CGI.escapeHTML(html)
puts CGI.unescapeHTML(CGI.escapeHTML(html))
Python
from xml.sax.saxutils import *

html = """
<html>
<body>
body
</body>
</html>
"""

print escape(html)
print unescape(escape(html))
Tagged with:  

CentOS 5.5にdotcloudの開発環境を作る

On 2011年5月13日, in dotcloud, by タカ

目次


意外とハマったのでメモ。

まだ、dotcloudのアカウントを持っていない人は、

http://www.dotcloud.com/

から。

ちょっと待っててな!的なメールがすぐに来て、2日もすればアカウント作れるよ!的なメールが届く。

さてさて、環境構築の流れは以下の通り。

  1. python 2.6.6のインストール
  2. easy_installのインストール
  3. dotcloudコマンドのインストール
  4. 開発用ユーザでいじってみる

ハマった点は

CentOS 5.5デフォルトのpythonのバージョンが低くてeasy_installでdotcloudが入らない

という点。

さくらのVPSで作業した。(sudo面倒だからrootで…)

python 2.6.6のインストール

python 2.6.6用ディレクトリ作成
# mkdir /usr/local/python266
# ln -fns /usr/local/python266 /usr/local/python
インストール
# cd /usr/local/src
# wget http://www.python.org/ftp/python/2.6.6/Python-2.6.6.tgz
# tar -zxvf Python-2.6.6.tgz
# cd Python-2.6.6
# ./configure --with-threads --enable-shared --prefix=/usr/local/python
# vim Modules/Setup
zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
# make
# make install
共有ライブラリ設定
# vim /etc/ld.so.conf.d/python2.6.6.conf
/usr/local/python266/lib
# ldconfig
動作確認
# /usr/local/python/bin/python
Python 2.6.6 (r266:84292, May 13 2011, 10:45:20)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
.bashrc設定

すでに入っているpythonとの共存の為にaliasにしておく

# vim ~/.bashrc
PATH=$PATH:/usr/local/python/bin
alias python='python2.6'
確認
# . ~/.bashrc
# python
Python 2.6.6 (r266:84292, May 13 2011, 10:45:20)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()

easy_installのインストール

# cd /usr/local/src
# wget http://peak.telecommunity.com/dist/ez_setup.py
# python ez_setup.py
# easy_install-2.6

dotcloudコマンドのインストール

# easy_install-2.6 dotcloud

開発用ユーザでいじってみる

さすがにrootで開発するのは嫌なので、一般ユーザに設定を入れていじってみる。

.bashrc設定
$ vim ~/.bashrc
PATH=$PATH:/usr/local/python/bin
alias python='python2.6'
確認
$ . ~/.bashrc
$ python
Python 2.6.6 (r266:84292, May 13 2011, 10:45:20)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
作業用ディレクトリ作成
$ mkdir -p ~/work/dotcloud/
アプリケーション作成

※testの部分には自分の好きな名前を入れる。すでに使われているとエラーになる。

$ dotcloud create test

※初回はAPIキーを聞かれる。これは、dotcloudのWebにログインして、Settingsページを見ると書いてある。

PHPのアプリケーションを作ってみる
$ dotcloud deploy --type php test.php
デプロイするソースコードの作成
$ mkdir -p ~/work/dotcloud/test/php
$ cd ~/work/dotcloud/test/php
$ vim index.php
<?php
phpinfo();
デプロイ
$ dotcloud push test.php ~/work/dotcloud/test/php

デプロイは、

~/work/dotcloud/test/php

のディレクトリをrsyncしてるみたい。

確認

http://php.test.dotcloud.com/

にアクセス。

独自ドメインの割り当て

dotcloud alias add test.php ドメイン

で割り振れるらしい。

CNAMEはgateway.dotcloud.com。

まとめ

独自ドメインを割り振れるみたいだし、結構お手軽にデプロイもできる。

何よりも、PHPだけじゃなくてRubyやPythonの環境もデプロイできるのは凄い!

次はSinatraでもデプロイしてみようかなぁ。

Tagged with:  

Singleton(PHP版)

On 2010年9月14日, in PHP, by タカ

こちらもたまーに使うのでメモエントリー。


Singleton.class.php

<?php
class Singleton
{
    static private $instance = null;

    private function __construct()
    {
    }

    static function instance()
    {
        if (!is_null(self::$instance)) return self::$instance;
        self::$instance = new self();
        return self::$instance;
    }
}

test.php

<?php
require_once 'Singleton.class.php';

$obj1 = Singleton::instance();
$obj2 = Singleton::instance();

var_dump($obj1);
var_dump($obj2);

サンプル実行

$ php test.php
object(Singleton)#1 (0) {
}
object(Singleton)#1 (0) {
}
Tagged with:  

OpnePNE 3.4

On 2010年3月3日, in オープンソース, by タカ

インストールして試してみました。

手順的には、
http://github.com/openpne/OpenPNE3/raw/OpenPNE-3.4.1/doc/ja/OpenPNE3_Setup_Guide.txt
の通りで9割OK。

一点だけハマったと点は

ブラウザからアクセス(PC)
------------------------

(1) http://example.com/index.php にアクセス
(2) ログインフォームに sns@example.com / password と入力し、ログインできるかどうか確認

のところで、

[DocumentRoot]/member/login/authMode/MailAddress

がNot Foundになってしまう点。

いくつかググってみると、.htaccessの設置を許可していないと起こるらしい。
AllowOverride all
をhttpd.confに追加すればOK。(Directory設定でも可)

Tagged with:  

PHP(5.2.x)のイケてない不具合

On 2010年2月25日, in PHP, Ruby, by タカ

Rubyだと普通にできる事が、PHPだとできないという事に最近ぶつかる。

class A
  def self.create
    return self.new
  end
end

class B < A
end

puts A.create # Aクラスのオブジェクトを返す
puts B.create # Bクラスのオブジェクトを返す

とか書くと、createは期待した通りのオブジェクトを返してくれる。
でも、PHP(5.2.x)だと…

<?php
class A
{
    static function create() { return new self(); }
}

class B extends A
{

}

var_dump(A::create()); // Aクラスのオブジェクトを返す
var_dump(B::create()); // これもAクラスのオブジェクトを返す

となってしまう…。

PHP 5.3系だと直ってるらしいけど…。
なんとイケてない言語…。

Tagged with:  

On 2010年2月16日, in 未分類, by タカ
abstract final class God
{

}

と昔、知り合いが書いていました。

PHPだとParse errorです(笑)

Tagged with:  

クローラ

On 2010年2月14日, in 未分類, by タカ

作成中です。

Storategyパターンで使用するコマンドは切り替えられるようにする予定。

そうすると、コマンド引数によってそれぞれ条件が変わるから
そこをある程度吸収できる仕組みは必要。

Facadeパターンとかで吸収できるかなぁと思ってる。
でも、最大公約か最小公倍かで悩み中。

取り急ぎ、Webクローラを作ります。

Tagged with:  

再びOSS

On 2010年1月24日, in PHP, by タカ

というわけで、この時間までコーディングしていました。

データ変換(PDFからテキストなど)とhttpリクエストのライブラリ作ってました。

あらかた出来上がった(コメント入れとかは全然していないが…)ので
オープンソースとして公開しようと思ってます。

ニーズがあるかどうかはわからないけど、自分は使いたいから作った。
同じ思いの人もいるから公開しておく。

こんな活動できるのも今の会社に入れたおかげだなぁー。

次は、クローラを作る予定。(内部でwgetするだけなんだけどね…)

Tagged with:  

pdftotextとかwvHtmlとか使えば、テキストにできる!
という事で、PHPからどうやって呼ぼうかなぁと検討してみました。
※オブジェクト指向はまだまだ勉強中なので中途半端だけど…。

まず、各コンバータのテンプレートとなる抽象クラスを作る。

<?php
abstract class Converter_Template
{
    abstract function toText($string);
    abstract function toHtml($string);
    abstract protected function isInstalledUseCommand();
}

次に、各ファイルのコンバータは、拡張子毎にオブジェクト化。
Word(doc)を例にとると

class Converter_Doc extends Converter_Template
{
    function toText($string)
    {
        ごにょごにょ
    }

    function toHtml($string)
    {
        ごにょごにょ
    }

    protected function isInstalledUseCommand()
    {
        return true;
    }
}

Excel(xls)を例にとると

class Converter_Xls extends Converter_Template
{
    function toText($string)
    {
        ごにょごにょ
    }

    function toHtml($string)
    {
        ごにょごにょ
    }

    protected function isInstalledUseCommand()
    {
        return true;
    }
}

このままだと、扱えるファイルが増えるとオブジェクトがどんどん増えるので
Factoryパターンを適用し、ここにお任せする。

class Converter_Factory
{
    static function create($extension)
    {
        if ($extension === 'doc') return new Converter_Doc();
        if ($extension === 'xls') return new Converter_Xls();
        throw new Exception("Converterer not found. [extension = $extension]");
    }
}

こんな感じで、「ごにょごにょ」部分を実装すればOK。
実際には、コマンド実行とかは各コンバータで共有できそう。
内容が見えたら、適切な名前を付けてオブジェクト化。(Converter_Commandとか??)

呼び出しとしては、

$data = file_get_contents('xxxxx.doc');
$converter = Converter_Factory::create('doc');
var_dump($converter->toText($data));
var_dump($converter->toHtml($data));

createに渡す値をxlsにすれば、エクセルに適用できる。

こんな感じでどうだろう?

Tagged with: