Amazon S3のワンタイムURLを作成

Amazon S3のワンタイムURLを作成するPHPコードです。
生成された時間から一定の期間が経つとリンクは無効になります。

<?php 
  
class S3Download { 
  
    public function generateOnetimeURL($bucketName, $objectName) { 
  
        if (empty($bucketName)) { 
            die("バケット名が空です"); 
        } 
  
        if (empty($objectName)) { 
            die("ダウンロードするファイル名が空です"); 
        } 
  
        // AWSのACCESSKEY 
        $keyId = 'AWS_ACCESS_KEY'; 
        // AWSのSECRETKEY 
        $secretKey = 'AWS_SECRET_KEY'; 
        $request = $this->_makeRequestHeader($bucketName, "/".$bucketName."/".$objectName, $keyId, $secretKey); 
        $qs = http_build_query($request["header"]); 
        $url = sprintf('https://%s.s3.amazonaws.com/%s', $bucketName, $objectName); 
  
        return $url."?".$qs;
    } 
  
    private function _makeRequestHeader($bucketName, $resource, $accessKey="", $secretKey="") { 
  
        $httpVerb = 'GET' . "\n"; 
        $contentMd5 = "\n"; 
        $contentType = "\n"; 
  
        // Expireする分設定 
        // 5分を設定した 
  
        $expires = time() + intval(5) * 60; 
        $expires_str = $expires . "\n";
        $canonicalizedAmzHeaders = '';  
        $canonicalizedResource = $resource; 
        $stringToSign = $httpVerb . $contentMd5 . $contentType . $expires_str
                . $canonicalizedAmzHeaders . $canonicalizedResource;
        $hash = hash_hmac('sha1', $stringToSign, $secretKey, true); 
        $signature = base64_encode($hash); 
  
        $request = array("header" => 
            array( 
                "Expires" => $expires, 
                "AWSAccessKeyId" => $accessKey, 
                "Signature" => $signature, 
            ), 
        ); 
  
        return $request; 
    } 
  
} 
  
$s3obj = new S3Download(); 
// s3testhogeバケット直下のhoge.zipをダウンロードするURL生成 
$s3obj->generateOnetimeURL('s3testhoge','hoge.zip'); 
// ファイルがサブディレクトリ(正確には違うが…)に入ってる場合 
$s3obj->generateOnetimeURL('s3testhoge','hoge/fuga/foobar.zip'); 

SMTP Authなしでgmailを設定

zabbix設定のメディアタイプでgmailsmtp-authを支援しなくて苦労。
メディアタイプでカスタムスクリプトを設定する方法もありますがかなり面倒です。
で、実はsmtp-authなしでgmailを送信できる方法がありました。

SMTPサーバ
aspmx.l.google.com

SMTP helo
aspmx.l.google.com

にして送信できるようになりました。

Apacheの1プロセスのプライベートメモリを計算する

[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)

[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)

「24時間365日サーバ/インフラを支える技術」を参考にしてApacheのチューニングをやっていた時の話。
4・2に出ているコピーオンライトのメモリの計測なんですが、perlスクリプトを使っています。
しかし作成から時間が経っているのでCPANなどがちゃんと管理されていない模様。
そこでこんなものがありました。

https://github.com/pixelb/ps_mem

実行結果はこのようになっていて

Private Shared All
121.9 MiB + 17.5 MiB = 139.4 MiB httpd (43)

121.9(プライベートなメモリ)/43(Apacheプロセスの数)で = 2.83488

つまり1プロセスあたり約3Mを使っていることがわかりました。

VagrantでApache+PHP5.2環境の設置

Vagrant

Vitualbox、Vmwareなどをコマンドで操作して簡単に仮想の開発環境を作成できるツールです。
仮想環境の立ち上げ設定はVagrantfileというスクリプト(中身はruby)に書かれていて完全に同一な開発環境をどのPCでも立ち上げることができます。
つまり開発の現場でいつも聞こえる「俺の開発環境では問題ないけど他のところでは動かない」という開発環境依存の問題を解決できるというわけですね。

  1. まずはVagrantのインストール。MacもWinにも対応しているので合っているものをダウンロードしてインストールします。
  2. 適当なディレクトリを作ります。そして予め準備したVagrantfileと環境の自動設定のため作ったprovision.sh、そしてダンプsqlstg-hoge.sqlをコピーします。
  3. 仮想環境の初期設定は「vagrant init」と入力します。初めての起動の場合はサーバイメージ(今回はcentos6.3)をダウンロードするところから始まるので結構時間がかかります。ちなみにvagrantコマンドはVagantfileがあるディレクトリの上ではないと起動しません。
  4. 仮想環境の起動は「vagrant up」と入力します。仮想環境が立ち上がってPHPApacheMysqlのインストールから環境ファイルの設定までをすべて自動で行います。
  5. vagrant up」が無事終了したらVagrantfileを編集して最後の「config.vm.provision…」の行をコメントアウトもしくは削除してください。こちらを無効化しないと毎回vagrant upを実行する時にこれが実行されて環境設定が走ってしまいます。
  6. 仮想環境が立ち上がったのでsshで中に入ってみます。「vagrant ssh」では入ります。ただしWindowsローカルではこのコマンドが機能しませんのでコマンド警告文を見てTeratermなどを利用して指示通りに設定して入ってください。
  7. 仮想環境の停止は「vagrant halt」です。

次は設定ファイルの中身を解説します。
Vagrantfileを開きます。中身はこんな感じ。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  # All Vagrant configuration is done here. The most common configuration
  # options are documented and commented below. For a complete reference,
  # please see the online documentation at vagrantup.com.

  # Every Vagrant virtual environment requires a box to build off of.
  config.vm.box = "centos63_x86_64_minimal"

  # The url from where the 'config.vm.box' box will be fetched if it
  # doesn't already exist on the user's system.
  # config.vm.box_url = "http://domain.com/path/to/above.box"

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # config.vm.network :forwarded_port, guest: 80, host: 8080
  config.vm.network :forwarded_port, guest: 3306, host: 33060

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  config.vm.network :private_network, ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network :public_network

  # If true, then any SSH connections made will enable agent forwarding.
  # Default value: false
  # config.ssh.forward_agent = true

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  config.vm.synced_folder "../hoge_prj", "/vagrant_data", :nfs => { :mount_options => ["dmode=777","fmode=666"] }


  # 以下Chef設定などは省略しました。

  #
  # If you're using the Opscode platform, your validator client is
  # ORGNAME-validator, replacing ORGNAME with your organization name.
  #
  # If you have your own Chef Server, the default validation client name is
  # chef-validator, unless you changed the configuration.
  #
  #   chef.validation_client_name = "ORGNAME-validator"
  config.vm.provision :shell, :path => "provision.sh"
end

「config.vm.network :port_forwarding」はローカルから仮想環境のDB、WEBサーバなどに接続するためのポートフォワーディング設定です。
ここはローカルの33060ポートで仮想サーバの3306ポートに接続するようにしました。
ローカルからSequal ProなどのMysqlクライアントプログラムを開いてlocalhost:33060で接続すると仮想環境のMysqlDBを見ることができます。ちなみにsshは自動的に2222→22で設定されるのでここで記述する必要はありません。

「config.vm.network :private_network」は仮想環境にPrivateIPを指定します。複数のVagrant環境を同時に上げて使う時に環境ごと別のIPを宣言すればいいです。

「config.vm.synced_folder」はローカルと仮想環境の共有フォルダの指定です。
共有フォルダの指定→/vagrant_dataを仮想環境上のWEBサーバのDocumentRootにする→ローカル上の修正がすぐさま仮想環境のWEBサーバに反映される。という仕組みになりますね。
ただし、注意することは最後の:nfsオプションはWindowsローカル環境では機能しません。Windowsではこのオプションは使わないでください。

※synced_folderの:extraオプションはVagrant1.3から:mount_optionsに変わりました。そして記述方法も"dmode=777,fmode=666"から配列の["dmode=777","fmode=666"]になっています。

最後に「config.vm.provision」はVagrant起動後、環境設定のため自動に実行したいジェルを指定しました。
本来ならChefなどを使ってかっこ良く行きたいところなんですが…

次はprovision.shの内容です。ごく普通のシェルです。
PHPの場合、普通にyum installでもよかったけれど特殊な事情(?)でわざわざソースビルドになりました。

#!/bin/bash

yum install -y httpd
yum install -y gcc make httpd-devel libxml2-devel openssl-devel curl-devel gd gd-devel gmp-devel libtool-ltdl libtool-ltdl-devel mysql-devel libxslt-devel

#libmcrypt
wget http://elders.princeton.edu/data/puias/unsupported/6/x86_64/libmcrypt-2.5.8-9.puias6.x86_64.rpm
wget http://elders.princeton.edu/data/puias/unsupported/6/x86_64/libmcrypt-devel-2.5.8-9.puias6.x86_64.rpm
rpm -ivh libmcrypt-2.5.8-9.puias6.x86_64.rpm
rpm -ivh libmcrypt-devel-2.5.8-9.puias6.x86_64.rpm

#PHP5.2.17
wget http://museum.php.net/php5/php-5.2.17.tar.gz
tar zxvf php-5.2.17.tar.gz
cd php-5.2.17
./configure --with-apxs2 --enable-calendar --with-curl --with-gd \
--with-gettext --with-gmp --with-ldap --enable-mbstring --with-mcrypt \
--with-mysql --with-mysqli --with-openssl --with-pdo-mysql \
--enable-shmop --enable-soap --enable-sockets --enable-sysvmsg \
--enable-wddx --enable-xml --with-xsl --with-zlib \
--with-config-file-path=/etc --with-zlib-dir --enable-mbregex \
--with-pcre-regex --with-libdir=lib64 --with-pear --enable-bcmath \
--enable-zip --with-mysqli --enable-sockets
make
make install
cd ..
yum install -y mysql mysql-server
/etc/init.d/mysqld start

#iptables
/sbin/iptables -F
/etc/init.d/iptables save

#httpd.conf
echo "AddType application/x-httpd-php .php" >> /etc/httpd/conf/httpd.conf
echo "<IfModule dir_module>" >> /etc/httpd/conf/httpd.conf
echo -e "\tDirectoryIndex index.php index.php4 index.php3 index.cgi index.pl index.html index.htm index.shtml index.phtml" >> /etc/httpd/conf/httpd.conf
echo "</IfModule>" >> /etc/httpd/conf/httpd.conf

#vhost.conf
touch /etc/httpd/conf.d/vhost.conf
echo "NameVirtualHost *:80" >> /etc/httpd/conf.d/vhost.conf

echo "<VirtualHost *:80>" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tServerName hogeadmin.localhost.hoge" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tErrorLog logs/hg-error.log" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tCustomLog logs/hg-access.log common" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tDocumentRoot /vagrant_data/hogeadmin/webroot/hoge" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t<Directory /vagrant_data/hogeadmin/webroot/hoge>" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tOptions Indexes FollowSymLinks Includes ExecCGI" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tAllowOverride All" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tOrder allow,deny" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tAllow from all" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t</Directory>" >> /etc/httpd/conf.d/vhost.conf
echo "</VirtualHost>" >> /etc/httpd/conf.d/vhost.conf

echo "<VirtualHost *:80>" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tServerName hogestore.localhost.hoge" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tErrorLog logs/hg-error.log" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tCustomLog logs/hg-access.log common" >> /etc/httpd/conf.d/vhost.conf
echo -e "\tDocumentRoot /vagrant_data/store/webroot/hoge" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t<Directory /vagrant_data/store/webroot/hoge>" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tOptions Indexes FollowSymLinks Includes ExecCGI" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tAllowOverride All" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tOrder allow,deny" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t\tAllow from all" >> /etc/httpd/conf.d/vhost.conf
echo -e "\t</Directory>" >> /etc/httpd/conf.d/vhost.conf
echo "</VirtualHost>" >> /etc/httpd/conf.d/vhost.conf

#mysql
mysql -u root mysql -e "GRANT ALL PRIVILEGES ON *.* TO root@'%';"
echo "[client]" >> /etc/my.cnf
echo "default-character-set = utf8" >> /etc/my.cnf
echo "[mysqld]" >> /etc/my.cnf
echo "character-set-server = utf8" >> /etc/my.cnf

#etc/hosts
echo "127.0.0.1   hogeadmin.localhost.hoge hogestore.localhost.hoge" >> /etc/hosts

#apache etc.
cp /usr/share/zoneinfo/Japan /etc/localtime
echo "TZ=Japan" >> /etc/sysconfig/httpd
echo "export TZ" >> /etc/sysconfig/httpd

#service
chkconfig --add mysqld
chkconfig --level 345 mysqld on
chkconfig --level 345 httpd on

#daemon restart
/etc/init.d/httpd restart
/etc/init.d/mysqld restart

#importing test dump
mysql -u root -e 'create database `stg-hoge` DEFAULT CHARACTER SET utf8;'
mysql -u root stg-hoge < /vagrant/stg-hoge.sql

普通のシェルですが注意して見るのは最後の行。「/vagrant」はどこ?
実はVagrant起動で共有されるフォルダはさっき説明した「/vagrant_data」と「/vagrant」です。
「/vagrant」の共有先は「Vagrantfileがあるそのディレクトリ」なんです。
なので別途の設定なしでもローカルに置いてるはずのstg-hoge.sqlが仮想環境で見れるわけですね。