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:  

Singleton(dispatch_once版)

On 2011年12月1日, in Objective-C, by タカ

Objective-Cのシングルトンは以前書いたけど、

dispatch_onceを使うとより簡単に書けるのでメモ。


Singleton.h

#import <Foundation/Foundation.h>

@interface Singleton : NSObject
+ (Singleton *)instance;
@end

Singleton.m

#import "Singleton.h"

@implementation Singleton

+ (Singleton *)instance {
  static Singleton *instance_ = nil;
  static dispatch_once_t predicate;
  dispatch_once(&predicate, ^{
    instance_ = [[self alloc] init];
  });
  return instance_;
}

@end

fullScreenImageメソッドで取得できる画像がちょっとおかしい。

initWithCGImage:scale:orientation:

でUIImage作って表示させると右に90度回転してる。

iOS4だとこの問題は起きない。

initWithCGImage

にすると、ちゃんと表示される。

でも、今度はiOS4系だと回転している。

iTunesで同期した画像はiOS5でもこの問題は起きない。

クラスリファレンスみるとiOS5で修正が入ったぽいが…。

まぁ、iOS4とiOS5の時で使い分ければいいんだけど何か釈然としない…。

Tagged with:  

Capistranoの例

On 2011年9月17日, in Capistrano, Ruby, by タカ

目次


前職ではこんな感じにしていたなぁというネタ。

下書き状態で残っていてもったいなかったので公開。

ディレクトリ構成

以下のようなディレクトリ構成

$CAP_HOME
- Capfile => config配下のXXX.rbをloadする
- config
  - deploy.rb
  - deploy
    - production.rb => 本番用環境情報
    - test.rb => テスト用環境情報
  - XXX.rb => 各種レシピ

deploy.rbは以下の通り。

require 'capistrano/ext/multistage'

set :default_run_options, :max_hosts => 20
set :user, 'cap'
ssh_options[:keys] = '/home/user/.ssh/id_rsa'
  • 同時20サーバで実行
  • 実行ユーザはcap
  • sshの秘密鍵は /home/user/.ssh/id_rsa

環境設定

$CAP_HOME/config/deploy/XXX.rb に設置。

server 'srv1.example.com', :web
server 'srv2.example.com', :web
server 'srv3.example.com', :web, :ap
server 'db1.example.com', :db
server 'db2.example.com', :db

みたいな形で、1サーバずつロールを設定。

レシピ

namespaceを使ってある程度グルーピングする。

namespace :group do
  task :task1, :roles => :web do
    ここでごにょごにょする
  end

  task :task2, :roles => :db do
    ここでごにょごにょする
  end
end

といった形。

$ cap production group:task1

とか

$ cap test group:task1

のように呼び出す。

引数を受け取る

たまに、外部から引数を受け取りたい時がある。

例えば、Capistrano実行サーバにあるファイルを各サーバへscpしたい時は、

namespace :fileup do
  task :upload_txt, :roles => :web do
    upload filename, '/tmp', :via => :scp
  end
end

というレシピを書いて、

$ cap test -S filename=/tmp/text.txt fileup:upload_txt

と呼び出す。

シェルスクリプトからCapistranoを呼ぶ

cronなどにシェルを登録して、内部でCapistranoを実行したい。

そんな時の例。

#!/bin/sh
CAP_HOME="/home/user/cap"
CAP="/usr/local/bin/ruby /usr/local/bin/cap"

cd $CAP_HOME
$CAP production group:task1
Tagged with:  

Apacheを使ったリバースプロキシ

On 2011年9月17日, in Apache, by タカ

目次


構成

以下のような構成の想定。

  • ドメインはexample.com
  • 同一サーバ内
  • 画像, CSS, JavaScriptはリバースプロキシ側で担当
  • それ以外はAPサーバ
サーバ ポート インストール先
リバースプロキシ 80 /usr/local/apache_proxy
APサーバ 20080 /usr/local/apache

インストール【APサーバ】

以下のモジュールが入っていない場合は、追加でインストールする。

アクセスしてきたユーザのIPをAPサーバ側へ渡すモジュール。

IPベースでアクセス制限をかける場合とかに必要になる。

mod_extract_forwarded

下記のサイトからダウンロードする。
http://www.openinfo.co.uk/apache/index.html

# cd /usr/local/src
# tar -zxvf extract_forwarded-2.0.2.tar.gz
# cd extract_forwarded/
# /usr/local/apache/bin/apxs -c -i -a mod_extract_forwarded.c

インストール【リバースプロキシ】

# cd /usr/local/src
# tar zxf httpd-2.2.14.tar.gz
# cd httpd-2.2.14
# ./configure --prefix=/usr/local/apache_proxy \
 --with-mpm=worker \
 --enable-mods-shared=all \
 --enable-proxy \
 --enable-cache \
 --enable-mem-cache \
 --enable-disk-cache \
 --with-suexec-caller=www \
 --with-expat=builtin
# make
# make install

設定【リバースプロキシ】

リバースプロキシ側の設定をする。

/usr/local/apache_proxy/conf/httpd.conf
ServerRoot "/usr/local/apache_proxy"
Listen 80

User www
Group www

LoadModule setenvif_module modules/mod_setenvif.so
LoadModule mime_module modules/mod_mime.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule vhost_alias_module modules/mod_vhost_alias.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule dir_module modules/mod_dir.so

<IfModule worker.c>
StartServers         2
ServerLimit         16
ThreadLimit         64
MaxClients         512
MinSpareThreads     25
MaxSpareThreads     75
ThreadsPerChild     32
MaxRequestsPerChild  0
</IfModule>

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

ServerAdmin admin@example.com

DocumentRoot "/usr/local/apache_proxy/htdocs"

ErrorLog "logs/error_log"
LogLevel warn

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

CustomLog "logs/access_log" common

DirectoryIndex index.html

Include conf/extra/httpd-vhosts.conf
/usr/local/apache_proxy/conf/extra/httpd-vhosts.conf
NameVirtualHost *

<VirtualHost *>
  ServerName example.com

  SetEnvIfNoCase Request_URI "^/(img|css|js)" nolog
  SetEnvIfNoCase Request_URI "^/favicon.ico" nolog

  DocumentRoot /var/www/html

  RewriteEngine On
  RewriteRule ^/(img|css|js)/ - [L]
  RewriteRule ^/(.*) http://localhost:20080/$1 [P,L,QSA]
  ProxyRequests Off
  ProxyPreserveHost On
  ProxyPassReverse / http://localhost:20080/
</VirtualHost>

設定【APサーバ】

/usr/local/apache/conf/httpd.conf
#Listen 80
Listen 20080

#KeepAlive On
KeepAlive Off

LoadModule extract_forwarded_module modules/mod_extract_forwarded.so

MEForder refuse,accept
MEFrefuse all
MEFaccept 192.0.2.1
MEFaccept 127.0.0.1

192.0.2.1の部分は、リバースプロキシのグローバルIPに置き換える。

再起動

リバースプロキシ・APサーバのApacheを再起動すれば変更完了。
Tagged with:  

転職しました

On 2011年7月1日, in 未分類, by タカ

本日、7月1日よりミツバチワークスという会社で働く事となりました。

デコログというブログサービスを運営してます。

65億PVという国内のブログではトップレベルの規模のサービスです。

アーキテクチャや負荷との戦いなど得る物が多そうだなぁと感じてます。

とても刺激的な人達と働けそうでワクワクしてます!

でも、俺はそのデコログすら超えるようなサービスをいつか作ってやる!と思ってます!

そんなこんなで、これからもWEBの業界で頑張っていきまーす。

 

退職時に頂いた餞別

On 2011年6月12日, in 未分類, by タカ

色々と頂いたのでご報告とお礼を兼ねてのエントリ。

ScanSnap S1100

FUJITSU ScanSnap S1100 FI-S1100

B004COKSSE
富士通 2010-11-22
売り上げランキング : 255

Amazonで詳しく見る by G-Tools

↑を頂きました。

ひとまず、家にあった

  • 名刺
  • 給与明細
  • 源泉徴収票
  • 取説

などを、スキャンしてEvernoteへ送りました。

使い心地はとてもいいです!楽しくスイスイスキャンできます。

Windows Vista マシンよりMacBook Proからやった方が早く取り込めました。

Windowsマシンの方がCPUとかHDDいいはずなのに…。

紙の書類をPDF化して保存しておけるのはとても助かります。

文字列をコピー出来ることに今更感動しました(笑)

今後は
  1. ノートはルーズリーフにする
  2. 書いたらすぐにスキャンしておく
  3. 頂いた名刺もPDFにして取り込む
  4. レシートなどは取り込むか悩み中
  5. 本の裁断はまだしない

という感じで、運用していくつもりです。

図書カード1万円分

4冊本を買いました。

うち2冊は子供用なので省略。

残りの2冊は以下の通り。共に今後の仕事に役に立ちそうなものと判断して買いました。

ウェブオペレーション ―サイト運用管理の実践テクニック
John Allspaw
4873114934

レガシーコード改善ガイド (Object Oriented SELECTION)
マイケル・C・フェザーズ ウルシステムズ株式会社
4798116831

ウェブオペレーション ―サイト運用管理の実践テクニック

Webサイトの運用に関して書かれている本。

実は、この辺りは今までの経験でなんとなーくやっていた範囲。
ちょっとモヤモヤした感じではあった。

この分野を体系だてて進められたらいいなぁという期待を込めて購入。

レガシーコード改善ガイド

これは、色々な方面より鉄板だとお墨付きの本。

「テストのないコード=レガシーコード」

こいつとの戦いは次の会社でも起こると思っている。

それに備えて学びたいなぁと思ったので購入。

iTunes Card 1500円分

これはまだ使い道決めていません。

iPad2とかを買った時に、アプリを買うかもしれないです。

寄せ書き

沢山のメッセージありがとうございます。

みんなの印象が割と一致していたのは面白かったです。

そういう意味ではきっと裏表のない人間なんですよ。俺は(笑)

まとめ

というわけで、退職する人間にこんな素敵な物をありがとうございます。

しっかりと自分に投資してさせて頂きました。

 

Redmine 1.1.3をインストールした時のまとめ。

色々とバージョン指定が多いので大変だった…。

前提条件

  • MySQLはすでに構築済み
  • example.comというドメインでアクセス
  • nginxというユーザで実行

以下、

# は rootユーザ
$ は nginxユーザ

として記述。

nginxのインストール

実行用ユーザ作成

# useradd nginx

作業が楽なので一旦nginxユーザはログイン可能にしておく。

全部終わったら、nologinに切り替える。

インストール

必要なライブラリを事前にインストール
# yum install gcc openssl-devel pcre-devel zlib-devel mysql-devel
nginxダウンロード&インストール
# cd /usr/local/src
# wget http://nginx.org/download/nginx-1.0.4.tar.gz
# tar -zxvf nginx-1.0.4.tar.gz
# cd nginx-1.0.4
# mkdir -p /usr/local/nginx-1.0.4
# ./configure --prefix=/usr/local/nginx-1.0.4 --user=nginx --group=nginx
# make
# make install
# chown -R nginx:nginx /usr/local/nginx-1.0.4
# ln -fns /usr/local/nginx-1.0.4 /usr/local/nginx

起動テスト

# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

ブラウザからアクセスしてみて、

Welcome to nginx!

と出ていればひとまずOK。

nginxを止める。

# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf -s stop

rvmのインストール

nginxの実行ユーザの環境にrvmを導入する

gitインストール

開発する時に使うし、rvmインストールも楽になるのでgitを入れてしまう。

# cd /usr/local/src
# wget http://kernel.org/pub/software/scm/git/git-1.7.5.4.tar.bz2
# tar -jxvf git-1.7.5.4.tar.bz2
# cd git-1.7.5.4.tar.bz2
# ./configure
# make
# make install

rvmインストール

# su - nginx
$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
$ source ~/.bash_profile
$ rvm -v

rvm 1.6.18 by Wayne E. Seguin (wayneeseguin@gmail.com) [https://rvm.beginrescueend.com/]

rails環境構築

Redmineはrails3では動かないみたいなので、rails2の環境を作る。

色んなサイトを見ると結構バージョンも低めでないといけないみたい。

ruby 1.8.7のインストール

$ rvm install 1.8.7
$ rvm use 1.8.7 --default

RubyGems 1.4.2のインストール

$ rvm rubygems 1.4.2
$ gem -v
1.4.2

※Errorという文字が見えたが動いているみたいなので先に進んでしまう。

rails2のインストール

$ gem install rails -v=2.3.11

unicornのインストール

gem経由で簡単インストール。

$ gem install unicorn

Redmineの構築

必要なGEMの導入

$ gem install rack -v=1.0.1
$ gem uninstall rack

1.0.1以外のrackを削除

$ gem install i18n -v=0.4.2
$ gem install mysql

Redmineの設置

$ cd /home/nginx
$ wget http://rubyforge.org/frs/download.php/74722/redmine-1.1.3.tar.gz
$ tar -zxvf redmine-1.1.3.tar.gz
$ ln -fns /home/nginx/redmine-1.1.3 /home/nginx/redmine

設定

$ cd /home/nginx/redmine/config
$ cp -p database.yml.example database.yml
$ cp -p email.yml.example email.yml

DB設定やメール設定は環境に合わせて変更。

公式ページに設定例は書いてある。

http://blog.redmine.jp/articles/redmine-1_1-installation_centos/

その後、rake

$ rake generate_session_store
$ rake db:migrate RAILS_ENV=production

unicorn起動

$ unicorn_rails -c config/unicorn.rb -E production -D

各種設定

nginx設定

/usr/local/nginx/conf/nginx.conf
# vim /usr/local/nginx/conf/nginx.conf
http {
…
  include /usr/local/nginx/conf.d/*.conf;
}
/usr/local/nginx/conf.d/redmine.conf
# mkdir -p /usr/local/nginx/conf.d
# vim /usr/local/nginx/conf.d/redmine.conf

upstream unicorn {
  server unix:/tmp/.unicorn.sock;
}

server {
  listen 80;
  server_name example.com;
  root /home/nginx/redmine/public;
  access_log logs/example.com.access_log;
  error_log logs/example.com.error_log;

  location / {
    if (-f $request_filename) { break; }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://unicorn;
  }
}

# chown -R nginx:nginx /usr/local/nginx/conf.d

Redmine向けunicorn設定

/home/nginx/redmine/config/unicorn.rb
worker_processes 2

listen '/tmp/.unicorn.sock'

stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])

preload_app true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  old_pid = &quot;#{ server.config[:pid] }.oldbin&quot;
  unless old_pid == server.pid
    begin
      Process.kill :QUIT, File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
参考

http://d.hatena.ne.jp/milk1000cc/20100804/1280893810

http://www.bpsinc.jp/blog/archives/2208

nginx起動&確認

# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

その後、http://example.com にアクセスして動いていれば終わり。

動いていない場合は、

/home/nginx/redmine/log

にログファイルができるので確認してみましょう。

Tagged with:  

辞めようと思った時に自分の気持ちを落ち着かせる為に自分が実践した事の振り返り。

とある人に書いて欲しいと言われたので書くことに。

退職を助長する意味合いは全くありません!

勘違いすんなよ!!
いいか!絶対だぞ!

では、スタート!

辞める事で自分に生じるメリットを考える

退職の意志を伝えるのは結構、緊張するもの。

ネガティブな気持ちでぶつかっても互いに嫌な気持ちになるだけ。

だから、ポジティブな気持ちで心を満たそう!

  • 〇〇ができる!
  • 年収が上がる!
  • 嫌いなあの人とお別れできる!

などなど。

でも、口に出して良い事と悪い事は整理しておこうね!(笑)

不要な書類をシュレッダーにかける

ちょっと早い??でも、以下の3つのメリットがあります。(超個人的な考え)

  1. 身辺整理が進むと勇気が出る
  2. 退職日当日に慌てないで済む
    結構、高い確率でシュレッダーをオーバーヒートさせてます。
  3. あれ!?あの人もしかして辞めるのか…と匂わせる事ができる(笑)

行動を変える事で意識を変えようという意味合いで実施しました。

あと、

名刺

もしっかりとシュレッダーにかけましょうね。

10枚くらいを並べて手動でかけるとサクサク進んで楽しいです(笑)

誰かに話してみる

予行練習です(笑)

もしかしたら、いいアドバイスがもらえるかもしれません。

(このタイミングだと〇〇だと思うよとか)

まとめ

いかがだったでしょうか?

退職は(疎まれていなければ…)会社側に迷惑をかける事になります。

せめてできる事は、

  • しっかりと引継ぎを行なう
  • 残った人達の為にできる事をする
  • 明るく立ち去る

だと思いました。

その為にも、自分を奮い立たせて下さいね!

 

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: