Home > PHP

PHP Archive

Twilio と ChatWork を使って、電話のメッセージをチャットで受け取る

この記事の所要時間: 221

Shin x blog Advent Calendar 2013 の 18 日目です。

ChatWork API のプレビュートークンを頂いたので、早速使ってみました。

今回作ったのは、電話をかけて音声で伝えたい人と、電話はかけて欲しくない、チャットで要件伝えて下さい、という人を繋ぐものです。

Twilio と ChatWork を使って留守番電話

これは、Twilio と ChatWork を使い、電話がかかってきたら、チャットで着信を知り、録音された音声が聞けるというものです。いわば留守番電話をチャットから聞くという感じですね。

全体の流れは下記の図になります。

twilio-chatwork

ソースコードは GitHub にて公開しています。

shin1x1/twilio-chatwork-voice-message

Twilio との連携

まず、かかってきた電話を Twilio で受けます。Twilio では、着信した電話番号に対して、あらかじめ登録した URL へ HTTP リクエストを投げるので、これをこのアプリケーションで受けます。

下記が Twilio からのリクエストを処理するコードです。Twilio へは、TwiML という XML を返すことで、電話に対する操作を指定します。このコードでは、音声メッセージを流して、録音を行うことを Twilio へ指示しています。また、録音が完了すると、recoreder.php へリクエストを投げるようにしています。

ChatWork との連携

Twilio での録音が完了すると下記のコードへリクエストが来ます。このリクエストでは、録音された音声ファイルの URL が送信されてくるので、これを ChatWork API を使って、チャットメッセージとして送信します。

動かしてみる

実際に動かしてみます。Twilio で取得した電話番号に電話をかけます。

call-twilio

録音を促す音声が流れるので、メッセージを電話で話します。伝えたい内容を言い終わったら、# を押して下さい。

push-button

すると、着信があったことを伝えるチャットメッセージが、ChatWork へ送信されます。チャットメッセージには、URL が付いているので、これをクリックすると、録音された音声を聞くことができます。

chatwork-voice-message

さいごに

Twilio も ChatWork も API が公開されており、連携も簡単でした。

これならば、電話で要件を伝えたい人は電話をかけられ、聞く側は ChatWork で着信を知って、要件を音声で聞くことができます。電話を置かない会社さんでも電話番号を公開できますね;-p

  • コメント (Close): 0
  • トラックバック (Close): 0

開発現場で Docker をどこで使うか考えてみた

この記事の所要時間: 657

Shin x blog Advent Calendar 2013 の 16 日目です。

docker

最近話題の Docker 色々と触っています。

触ってみる中で、普段の開発現場でどのような用途に使えそうなのかを考えています。こうだ!という結論が出ているわけではないのですが、一度書き出してみます。

前提

  • Webシステムの開発現場を想定しています。
  • 言語は普段使っている PHP ですが、内容にはあまり関係無いです。
  • 開発機には Mac OSX を使っています。

検証環境(サンドボックス)

まず一番に思いつくのが、検証環境としての利用です。Docker を使えば、OS のみがインストールされている状態のコンテナを手軽に作成できるので、そこでミドルウェアのインストール、設定などを自由に行い、検証が済んだら、破棄します。

OSX 環境では Docker は動かないので、Vagrant + VirtualBox 上の VM に Linux 環境を構築して、その上で、Docker を動かします。

Docker のインストールは、Vagrantfile に仕込んでおき、vagrant up すれば、Docker デーモンが起動している状態にします。

SSH でログインして、docker run してコンテナを起動するイメージです。dockerui を VM or docker コンテナで動かして、OSX のブラウザからコンテナする方法もありますね。

例えば、先日のエントリでは、下記のコマンドで CentOS の Docker コンテナを使って、コンテナ作成、yum インストール、コンテナ破棄を繰り返しました。vagrant up & destory を繰り返すより、圧倒的に速いので、かなり効率が良いです。

$ sudo docker run -i -t centos /bin/bash
# yum -y install php
# exit

開発環境

Web システムの開発環境としての利用です。

Vagrant と用途としては似ており、環境構築の自動化、VCS でのバージョン管理、共有などが可能です。

OSX で開発を行う場合、開発ツールは OSX のものを使い、コードの実行をコンテナ内にしたいと思うのですが、ファイル共有は Vagrant の synced_folder と docker run の -v オプションを、OSX のブラウザからコンテナ内へのアクセス(通信)も Vagrant の ポートフォワーディングや private_network と docker run の -p オプションを組み合わせることで可能です。

ただ、実用では考えないといけない点が、2 点あります。

まず、プロジェクトごとに VM を作って、そこに Docker コンテナを作るか、ひとつの VM に複数プロジェクトの Docker コンテナを集積させるかについてです。

前者の場合は、従来プロジェクトごとに Vagrantfile を作っていたのと同じ感覚で Dockerfile を管理できるので管理は楽です。こうなると VM は Docker を動かすだけのプラットフォームに過ぎないようになります。つまり VM の OS は Docker さえ動けばどれでも良く、CoreOS などの軽量な OS を使う方向に進みそうです。ただ、プロジェクトごとに VM が起動するので、Vagrant で VM を作って、プロビジョニングするのとそれほど変わらないといえば、そうかもしれません。

後者の場合、一つの VM 上でプロジェクト毎の Docker コンテナを起動するので、OSX 上で動かす VM は一つだけで良くなります。モバイルなどバッテリ駆動での作業を考えると、起動する VM は少ない方が良さそうです。また、一つの VM を共有するので、Docker イメージのキャッシュを生かすことができます。いつも同じイメージをベースにするのなら、キャシュ済イメージからコンテナを生成できるので、高速に起動することができます。

次に、これは開発環境に限らずですが、Web システムを構成するコンポーネント(Web / App / DB等)をそれぞれ独立したコンテナにするか、一つのコンテナに入れてしまうかです。

前者の場合、それぞれのコンテナを部品として扱いやすく、再利用性は高まります。docker run を複数回実行する必要はありますが、Vagrantfile に記述しておけば良いので、それはあまり問題にならないです。本番環境にて、各コンポーネントを分離している場合や、外部サービス(RDSなど)を利用する場合は、そもそも別ノードにあるコンポーネントと協調して動くことが想定されているので、この方がより稼働環境に近くなるとも言えます。

ただ、上述したように、もし一つの VM で複数プロジェクトのコンテナを動かす場合、どのプロジェクトのコンテナなのかを判別して、起動ポートなども調整する必要があり、このあたりの管理が煩雑になりそうです。

後者の場合、プロジェクトで利用するコンポーネントを全て一つのコンテナに収容するので、見た目として分かりやすいです。一つの Dockerfile で収まるので、コンテナ構築のコードも見通しは良いです。(ただ複数コンポーネントをプロビジョニングするコードが内包するので複雑になりがちです。各コンポーネンのコードは別ファイルにするなどが必要。)ただ、本番環境では、多くの場合、何でも入りコンテナ一つで動かすのではなく、少なくとも DB は別ノードになるなど分離することが多いので、そうなるとアプリケーション以外のコンポーネントは不要になるかもしれません。

まだ全てが Docker コンテナで完結するわけではないので、開発環境と割り切れば、一つのコンテナにまとめるのは悪くないと思います。

CI 環境

CI において、テストを実行する環境としての利用です。

ここでも Docker コンテナの起動の速さは生きてきますね。これも構成の悩みは、開発環境と同じですが、いずれにせよ、 コンテナ構築からテスト実行、コンテナ破棄まで自動実行するので、開発環境に合わせた構成で良いと思います。

できれば、CI でテスト実行したコンテナを、そのまま本番環境へデプロイできたりすると美しいです。

コンテナビルド、テスト実行、テスト完了なら、ビルドしたコンテナをそのまま本番環境へデプロイという流れです。CI サーバがアプリケーションを生成して出荷する工場になるイメージですね。

本番環境

CI 環境でも書きましたが、Docker コンテナを利用している PaaS はありますが、Docker コンテナをそのままデプロイする環境というのはまだ無いように思います。(あったら教えて下さいm(_ _)m)

CI 環境で構築したコンテナをどうデプロイするかですが、直接コンテナを送信するのがまず一つです。ただ、できれば docker push で、コンテナリポジトリに push するとそれが本番環境へデプロイされたりすると良いですね。現在は index.docker.io へ push するのみで、さらに index.docker.io では公開コンテナした置けないのですが、外部リポジトリに push できたり、index.docker.io にプライベートなコンテナを置けたりするようになると利便性が上がります。

今のところは、Dockerfile を送信して、本番環境でコンテナをビルドするという形が現実的ですね。

さいごに

Docker をどう使うかを考えてみました。といってもまだアイデアレベルなのですが、試しながら、もやもやと考えている日々です。

まだ模索中なので、こうしてるよ、こうした方が良いよなどアドバイスあれば、教えて頂けると嬉しいです 😀

これから触ってみようという方は、入り口として、検証を行うサンドボックスとして使ってみるのがおすすめです。

  • コメント (Close): 0
  • トラックバック (Close): 0

CentOS 5, 6 / Amazon Linux で PHP をパッケージインストールする方法まとめ

この記事の所要時間: 1251

Shin x blog Advent Calendar 2013 の 15 日目です。

php-logo

Cent OS 5, 6 / Amazon Linux にて、PHP の各バージョンを yum でインストールする方法をまとめてみました。

CentOS 6

PHP 5.3

CentOS 6 では、公式パッケージが PHP 5.3.3 なので、公式のリポジトリからインストールできます。

$ sudo yum -y install php
(snip)

$ php -v
PHP 5.3.3 (cli) (built: Dec 11 2013 03:29:57)

パッケージバージョンは 5.3.3–27 となっています。これは主にセキュリティ上の問題が発生した場合にパッチが提供されているためで、最新のビルドは、2013/12/10 になっています。

$ sudo rpm -qi php
Name        : php                          Relocations: (not relocatable)
  Version     : 5.3.3                             Vendor: CentOS
  Release     : 27.el6_5                      Build Date: Tue Dec 10 22:38:18 2013
  Install Date: Sat Dec 14 22:01:49 2013         Build Host: c6b10.bsys.dev.centos.org
  Group       : Development/Languages         Source RPM: php-5.3.3-27.el6_5.src.rpm
  Size        : 3702221                          License: PHP
  Signature   : RSA/SHA1, Wed Dec 11 04:24:11 2013, Key ID 0946fca2c105b9de
  Packager    : CentOS BuildSystem 
  URL         : http://www.php.net/
  Summary     : PHP scripting language for creating dynamic web sites

PHP 5.4

CentOS のリポジトリでは PHP 5.4 は提供されていないので、外部のリポジトリからインストールします。

ここでは、PHP 5.4 を提供しているリポジトリのうち、remi / IUS を利用します。

remi

remi リポジトリは、Fedora プロジェクトのコントリビュータでもある Remi Collet 氏が運営しているリポジトリです。

PHP の新バージョンがリリースされるごとに該当バージョンの RPM を作成し、配布しています。旧 php.net サイトから、外部リポジトリとしてリンクされていたので、PHP ユーザにはお馴染みですね。

まず、remi リポジトリを有効にするために RPM をインストールします。remi リポジトリには epel リポジトリが必要なので、こちらもインストールしておきます。

$ sudo rpm -Uvh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/i386/epel-release-6-8.noarch.rpm
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

PHP 5.4 を remi リポジトリからインストールします。パッケージ名は php です。remi リポジトリはデフォルトでは有効にならないので、–enablerepo オプションで指定します。

リリースされたばかりの PHP 5.4.23 がインストールされました。ビルド日時は、2013/12/11 となっています。

$ sudo yum -y install php --enablerepo=remi
(snip)

$ php -v
PHP 5.4.23 (cli) (built: Dec 11 2013 06:48:07)

IUS

IUS は、Rackspace が運営しているリポジトリです。

「Rackspace RPM の Fedora」と書かれているとおり、新しいパッケージは、まず IUS で公開し、プロダクション環境での利用が検証できた後に、Rackspace 顧客用のエンタープライズパッケージとして提供しているようです。

IUS リポジトリを利用するために ius-releaseepel-release パッケージをインストールします。

$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/epel-release-6-5.noarch.rpm
$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/ius-release-1.0-11.ius.centos6.noarch.rpm

PHP 5.4 を IUS リポジトリからインストールします。パッケージ名は php54 です。IUS リポジトリはデフォルトでは有効にならないので、–enablerepo オプションで指定します。

最新版の 5.4.23 ではなく、5.4.22 がインストールされました。ビルド日時は、2013/11/15 となっています。

$ yum -y install php54 --enablerepo=ius
(snip)

$ php -v
PHP 5.4.22 (cli) (built: Nov 15 2013 10:13:25)

IUS では、新しいパッケージは、まず ius-testing リポジトリで検証を行い、その後 ius リポジトリへ展開される流れになっているので、isu-testing リポジトリを見てみると、最新の 5.4.23 が公開されていました。検証環境などで、すぐに新しいバージョンを使いたい場合は、ius-testing を利用すると良いでしょう。

$ sudo yum info php54 --enablerepo=ius-testing
(snip)
Available Packages
Name        : php54
Arch        : x86_64
Version     : 5.4.23
Release     : 3.ius.centos6
Size        : 2.7 M
Repo        : ius-testing
(snip)

PHP 5.5

PHP 5.5 も公式リポジトリでは提供されていないので、remi / IUS からインストールします。

remi

remi の PHP 5.5 は、remi-php55 というリポジトリにて提供されていますので、–enablerepo では、remi-php55 を指定します。パッケージ名は php になります。

最新版の 5.5.7 がインストールされました。ビルド日時は、2013/12/11 です。

$ sudo yum -y install php --enablerepo=remi-php55
(snip)

$ php -v
PHP 5.5.7 (cli) (built: Dec 11 2013 07:13:20)

IUS

IUS では、ius リポジトリにて PHP 5.5 が提供されているので、パッケージ名を php55u に変更します。

最新版から一つ前の 5.5.6 がインストールされました。ビルド日時は、2013/12/04 です。

$ sudo yum -y isntall php55u --enablerepo=ius
(snip)

$ php -v
PHP 5.5.6 (cli) (built: Dec  4 2013 17:19:08)

なお、5.4 と同じく ius-testing リポジトリを見ると、最新版の 5.5.7 が提供されていました。

$ sudo yum info php55u --enablerepo=ius-testing
(snip)
Name        : php55u
Arch        : x86_64
Version     : 5.5.7
Release     : 1.ius.centos6
Size        : 2.6 M
Repo        : ius-testing
(snip)

CentOS 5

PHP 5.1

CentOS 5 では、ベンダー提供の標準 RPM が、PHP 5.1.6 なので、公式 yum リポジトリから yum install でインストールできます。

5.1.6 はかなり古いバージョンですが、現在もパッチの提供が続けられています。最新ビルドは、2013/12/10 となっていました。

$ sudo yum -y install php
(snip)

$ php -v
PHP 5.1.6 (cli) (built: Dec 10 2013 22:08:48)

PHP 5.3

公式リポジトリにて PHP 5.3 パッケージも配布されています。パッケージ名は php53 となっています。

CentOS 6 と同じく、PHP 5.3.3 がインストールされます。ビルド日時は、2013/12/10 です。

$ sudo yum -y install php53
(snip)

$ php -v
PHP 5.3.3 (cli) (built: Dec 10 2013 22:12:52)

PHP 5.4, 5.5

CentOS 6 と同じく、外部リポジトリを利用してインストールします。

remi / IUS 共に、CentOS 5 用の release パッケージが提供されていますので、こちらをインストールします。各 PHP のインストールは、CentOS 6 と同じです。

remi

epel-releaseremi-release パッケージをインストールします。

$ sudo rpm -Uvh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/i386/epel-release-6-8.noarch.rpm
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm

IUS

epel-releaseius-release パッケージをインストールします。なお IUS では、PHP 5.4 は提供されていますが、PHP 5.5 は提供されていませんでした。

$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/5/x86_64/epel-release-5-4.noarch.rpm
$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/5/x86_64/ius-release-1.0-11.ius.centos5.noarch.rpm

Amazon Linux

Amazon Linux では、公式リポジトリにて、PHP 5.3, 5.4, 5.5 が提供されています。

同じリポジトリで提供されているので、パッケージ名にてインストールするバージョンを指定します。

PHP 5.3

パッケージ名を php でインストールします。最新版一つ前の 5.3.27 が提供されています。ビルド日時は、2013/07/12 です。

$ sudo yum -y install php
(snip)

$ php -v
PHP 5.3.27 (cli) (built: Jul 12 2013 22:04:28)

PHP 5.4

パッケージ名を php54 でインストールします。最新版一つ前の 5.4.22 が提供されています。ビルド日時は、2013/12/09 です。

$ sudo yum -y install php54
(snip)

$ php -v
PHP 5.4.22 (cli) (built: Dec  9 2013 18:19:32)

PHP 5.5

パッケージ名を php55 でインストールします。最新版一つ前の 5.5.6 が提供されています。ビルド日時は、2013/12/09 です。

$ sudo yum -y install php55
(snip)

$ php -v
PHP 5.5.6 (cli) (built: Dec  9 2013 18:09:49)

さいごに

CentOS / Amazon Linux にて PHP を yum でインストールする方法を見てきました。現在は、PHP 5.3, 5.4, 5.5 どのバージョンにおいても yum でインストールすることが可能です。

検証は、CentOS 6 は Vagrant + VirtualBox + Docker 、CentOS 5 は Vagrant + VirtualBox で、Amazon Linux は AWS で行いました。こういった類の検証では、Docker コンテナの起動の速さは便利ですね。Vagrant ですら昨年の今頃はまだ触った程度だったのに、ここ一年の進化は早いものです。

参考

  • コメント (Close): 0
  • トラックバック (Close): 0

Travis CI を使って PHP コードを HHVM 環境でテストする

この記事の所要時間: 458

Shin x blog Advent Calendar 2013 の 14 日目です。

travis-ci-meets-hhvm

PHP の高速な実行環境として知られる HHVM の新しいバージョン 2.3.0 がリリースされました

今回のリリースでは、オープンソースプロジェクトの CI サービスとして人気の Travis CI へのサポートが発表されました。以前から Travis CI では、PHP 5.2 から PHP 5.5 の実行環境がサポートされていたのですが、ここに HHVM 環境が新たに加わることになります。

さっそく、Travis CI の HHVM 環境を試してみました。

Travis CI の設定

Travis CI 上で HHVM 環境でのテストを行う設定は簡単です。.travis.yml の php:hhvm を追加するだけです。

php:
  - hhvm

これで、次回のテストから hhvm 環境で実行されます。

Travis CI の HHVM 環境でテスト

簡単な PHP プロジェクトをテストしてみます。ソースコードは下記になります。

shin1x1/travis-ci-sample

ここでは足し算を行う TravisCISample\Calculator クラスを作り、そのテストを PHPUnit で書きました。ローカルで phpunit を実行するとテストが通ります。

$ ./vendor/bin/phpunit --colors test
PHPUnit 3.7.28 by Sebastian Bergmann.

.

Time: 23 ms, Memory: 2.25Mb

OK (1 test, 1 assertion)

Travis CI の設定を .travis.yml に書きました。PHP 5.3 から 5.5、そして HHVM を実行環境として設定しています。

language: php

php:
- 5.3
- 5.4
- 5.5
- hhvm

before_install:
- composer install

script:
- phpunit --colors --coverage-text test

このコードを GitHub に push します。あらかじめ Travis CI では、このプロジェクトを CI の対象として設定しているので、push するとテストが実行されます。

テスト結果が下記です。PHP のバージョンとして、HHVM 環境で実行されています。今回のテストに関しては、HHVM 上でも動作することが分かりました。

travis-ci-hhvm

https://travis-ci.org/shin1x1/travis-ci-sample/builds/15438927

つまづいた点

HHVM 環境を試してみて、つまづいた点を。

Composer インストール

.travis.yml の before_installcurl -sS https://getcomposer.org/installer | php を入れていたのですが、下記のエラーが出てビルドが停止しました。HHVM では、標準入力による PHP スクリプト実行はサポートされていないのかもしれません。

そもそも Travis CI の環境では、composer コマンドが用意されており composer.phar をインストールする必要が無かったので、この処理は省きました。

HipHop Notice: Nothing to do. Either pass a .php file to run, or use -m server

The command "php" failed and exited with 1 during before_install.

https://travis-ci.org/shin1x1/travis-ci-sample/jobs/15438538

php -q オプション

これは CakePHP のコードを HHVM で動かした時に発生したのですが、内部で php コマンドに -q オプションを付けて実行している箇所があり、このオプションを HHVM が対応していないためにエラーとなりました。

ためしに -q オプションを削除して実行してみると、その箇所は動作するようになりました。(また別のエラーが出ていますが。)

Error in command line: unknown option -q

https://travis-ci.org/shin1x1/cakephp/jobs/15436509

2.3 のリリースを見ると、HHVM 環境では HHVM_VERSION という定数が定義されるようなので、これ使えば、HHVM 固有の処理を記述ことができそうです。

if (defined('HHVM_VERSION')) {
    // HHVM 環境のみの処理
}

さいごに

Travis CI で簡単に HHVM 環境を使えることが分かりました。

本番環境として HHVM を使うようになるかどうかは分かりませんが、Travis CI なら自分で環境を作ること無く試すことができるのが良いです。

今回は簡単なスクリプトでしたが、PHP の実行速度を問われるようなコードであれば、HHVM の性能を測る手段としても使えそうですね。

HHVM 2.3.0 and Travis CI « HipHop Virtual Machine

  • コメント (Close): 0
  • トラックバック (Close): 0

とある CMS を使ったサイトに Varnish を導入した話

この記事の所要時間: 741

Shin x blog Advent Calendar 2013 の 6 日目です。

varnishcache-logo

とあるサイトに、Varnish をリバースプロキシとして導入して、半年が経過しました。

導入した経緯やその効果など書いてみたいと思います。

Varnish とは

Varnish は、HTTP アクセラレータです。Web サーバのリバースプロキシとして動作し、キャッシュを生かして高いパフォーマンスを発揮するのが特徴です。また、VCL という独自の設定言語を持ち、これにより状況に応じた設定を柔軟に行うことができます。

導入の経緯

このサイトでは LAMP 構成の CMS を利用しており、インフラには AWS を利用しています。基本、閲覧が中心なのですが、イベント時に多数のアクセスがあります。S3 や CloudFront も検討したのですが、コンテンツを数分おきに更新する必要があるので今回は採用しませんでした。

下記が構成のイメージです。なお図はかなり簡略化しており、実際の構成とは異なります。

before

こちらでパフォーマンスの問題が発生したので、CMS が生成したページ全体をキャッシュとして高速に返すよう Varnish Cache を導入しました。

after

当初、nginx の proxy_cache を試したのですが、同一 URL へ多数のリクエストが来ている状況でキャッシュのライフタイムが切れると、バックエンドへ同じ URL に対して複数のリクエストが飛んでしまい、PHP アプリケーション側に負荷がかかるという現象があったので、今回は取りやめました。

Varnish では、同一 URL に対して複数のリクエストがあっても、バックエンドへは 1 リクエストしか飛ばないようになっています。

導入

Varnish Cache は、m1.large インスタンスの Amazon Linux サーバに yum からインストールしました。

$ sudo rpm --nosignature -ivh http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch/varnish-release/varnish-release-3.0-1.el6.noarch.rpm
$ sudo yum -y install varnish

もし varnish のプロセスが落ちた場合に自動で再起動するように monit も入れています。varnish は、monit から起動しています。

$ sudo yum install monit
$ sudo chkconfig monit on

$ sudo vim /etc/monit.d/varnish
check process varnish with pidfile /var/run/varnishd.pid
start program = "/etc/init.d/varnish start"
stop program = "/etc/init.d/varnish stop"

$ sudo service monit start

監視

死活、性能監視として Zabbix を採用していたので、Varnish サーバも Zabbix で監視しています。

Zabbix のテンプレートは下記を利用しています。

rdvn / zabbix-templates

効果

Varnish 導入の効果はてきめんでした。

ELB 経由で来たリクエストは全て Varnish を経由しており、キャッシュが有効な期間(3分で設定しています)は、キャッシュを返すだけなので非常に高速です。

またキャッシュが切れた場合も、バックエンドへは 1 URL に対して 1 リクエストしか来ないため、バックエンドへの大きな負荷にはなりません。(ある特定の数ページのみが際立ってアクセスされるサイトなので)

導入前は、ピーク時にはバックエンドの Web サーバが応答を返せない場合があったのですが、それも一切無くなりました。

はっきりいって、下手に CMS を細々チューニングするよりも遥かに効果があります。導入後も安定して動いており、Varnish 起因の問題も発生していません。

参考の数値として、270,000 req/m のリクエストが来た時(Varnish 上位にある ELB の RequestCount)、Varnishサーバ(m1.large)の CPU 利用率は 56% 程度でした。その際の Client requests received(client_req)は 5,000 弱でした。外部からの閲覧に関して遅延など異常はありませんでした。

VCL

Varnish の特徴として挙げられるのが VCL = Varnish configuation Language による設定です。

VCL は小さな DSL となっており、プログラミングのように設定を書くことができます。イメージとしては nginx の設定をよりコードっぽくした感じですね。

例えば、下記は UserAgent を見て、iPhone が含まれていたら、http://sp.example.com/ へリダイレクトさせる VCL です。

if (req.url == "/") {
  if (req.http.user-agent ~ "(?i)iPhone") {
    error 750 "Moved Temporarily";
  }
}

sub vcl_error {
  if (obj.status == 750) {
    set obj.http.location = "https://sp.example.com/";
    set obj.status = 302;
    return (deliver);
  }
}

参考

構築にあたって参考にしたサイトです。柔軟に設定できるので、色々と調べながらの調整になりました。

さいごに

Varnish は、手軽に導入できるわりに簡単にパフォーマンスを向上させることができます。とくに CMS のような閲覧が中心となるアプリケーションには大きな効果を発揮します。

CMS 自体にもキャッシュ機構などは付いていますが、それよりの上位でキャッシュできるので、バックエンドが負荷に耐えられない構成でもうまく吸収することができます。

個人的には VCL がプログラムっぽく書けるのが設定しやすくて好きです。

アクセス過多でパフォーマンスに問題が出た際に使える切り札として覚えておくと、いつか役立つ日が来るやもしれません。

公式サイトのドキュメントが英語なので、日本語でのまとまった情報があればと思うのですが、詳しい方(チラチラッ、Kindle とかでどうでしょうか 😀

おまけ Vagrantfile

簡単に Varnish を試せるように Vagrantfile を作りました。

vagrant up して、http://192.168.33.50/sample.php にアクセスすると現在日時が表示されます。こちらがバックエンドアプリケーションの想定ですので、リロードする度に表示される日時は変わっていきます。

Varnish は 6081 port で待ち受けているので、http://192.168.33.50:6081/sample.php にアクセスするとその時点でのページがキャッシュされます。リロードするとキャッシュが返され、日時が変更されていないことが分かるでしょう。

shin1x1/vagrant-varnish

$ git clone https://github.com/shin1x1/vagrant-varnish
$ vagrant up
  • コメント (Close): 0
  • トラックバック (Close): 0

6分でわかる最近のPHP 2013年冬

この記事の所要時間: 659

Shin x blog Advent Calendar 2013 の4日目です。

php-logo

6分で分かるべく最近のPHP事情をざざざっとご紹介します。

過去のエントリはこちら。

6分でわかる最近のPHP ― 2012夏
5分でわかる最近のPHP – 2011夏

1. PHP 5.5 リリース

PHP5系の新しいバージョンとして、PHP 5.5 が 2013年6 月にリリースされました。

新しい機能としては、ジェネレータや finally 句の、パスワードハッシュ関数、OPCache などが追加されています。

2013/12/04 現在では、5.5.6 が最新版となっています。

PHP5.5 のコードキャッシュは APC から Zend OPcache へ
PHP: PHP 5.4.x から PHP 5.5.x への移行 – Manual
PHP 5.5の新機能:さっくり理解するPHP 5.5の言語仕様と「いい感じ」の使い方 (1/2) – @IT

PHP 5.5 を yum でインストールするなら、remi もしくは Webtatic リポジトリでインストールすることができます。

CentOSにPHP5.5をインストール – Qiita キータ
PHP 5.5 on CentOS/RHEL 6.4 and 5.9 via Yum | Webtatic.com

ちなみに次期バージョンの 5.6 の新機能については、こちらにまとめられています。

PHP 5.6の新機能 | yohgaki’s blog

2. PHP 5.3 EOL

PHP 5.5 リリースに合わせて、二つ前のマイナーバージョンである PHP 5.3 は EOL を迎えました。
5.3 は、今後セキュリティフィックスのみを行うメンテナンスフェーズに入っており、約 1 年経過した後はセキュリティフィックスも停止する予定です。

最終バージョンは 2013/7 にリリースされた 5.3.27 です。

5.3 は、名前空間やネイティブクロージャなど、現在の PHP へ続く機能が実装されたエポックメイキングなバージョンでした。EOL となったのは名残惜しいですが、いま 5.3 を使っている方は、5.4, 5.5 へのバージョンアップを行いましょう。
( なおパッケージベンダが 5.3 のパッチサポートを行う場合は無理に上げる必要はありません。)

PHP 5.3.27 Released – PHP 5.3 Reaching End of Life

3. php.net リニューアル

PHP 公式サイトである php.net がリニューアルしました。

いまどきのモダンなデザインに変わっています。個人的にはまだ違和感がありますが、慣れの問題ですかね。

久しぶりに開くとあれ?となるので、心の準備を。

PHP: Hypertext Preprocessor

php.net

4. Vagrant

PHP というわけではないのですが、PHP での開発環境構築ツールとして、Vagrant が注目を集めました。

Vagrant は、仮想サーバの構築、起動などコマンドで実行できるツールです。
利点としては「環境を仮想マシンに閉じ込める」「環境構築を自動化」「構築手順の共有」あたりですね。

受託開発などで複数の環境が必要な人や、チームで開発をしていて環境を統一したい場合などに特に有効です。

もう XAMPP / MAMP はいらない!
Vagrant で作る PHP 開発環境
Vagrantで作るPHP開発環境[実践編]をPHPカンファレンス2013で発表してきた
PHP開発環境のサンプルVagrantfile

こちらではPHP 開発環境構築に使える Vagrantfile がまとめられています。

PHPの開発に使えるVagrantfileのまとめ | Engine Yard Blog JP

5. Google App Engine の PHP サポート

Google の PaaS である Google App Engine で PHP がサポートされました。まだプレビュー版ではあるのですが、PHP で Google App Engine アプリケーションが書けるようになりました。

PHP 5.4 が動作するようで、公式サイトでは WordPress を動かすチュートリアルが掲載されています。

最近流行の Immutable Infrastructure の文脈でも PaaS が再評価されているので、Engine YardHeroku と共に、PHP アプリケーションを公開する環境として面白そうです。

Google App Engine — Google Developer

6. フレームワーク事情

みんな大好きフレームワーク事情など。

Symfony 2.3 の LTS リリース

Symfony 2.3 が LTS としてリリースされました。

LTS とは Long Term Support の略で、リリースから3年間はバグフィックスが、さらにもう1年間はセキュリティフィックスが行われます。ライフタイムが長いアプリケーションでは、こういった長期サポートが表明されていると安心して使えますね。

Symfony 2.3.0 – 最初のLTS(長期サポート) – がリリースされました | 日本Symfonyユーザー会

Laravel

今年、新たに注目を集めたフレームワークの一つで、Symfonyコンポーネントを利用したフルスタックフレームワークです。

PHP 5.45.3( tzt さん、ご指摘ありがとうございました! ) 以上が対象バージョンとなっており、ビルトインサーバによる開発や Composer 対応など最近の PHP らしいスタイルとなっています。

Symfony コンポーネントを利用していますが、その複雑さは上手くラッピングしているので、オブジェクト指向開発にあまり馴染みが無い人でも入りやすいのが特徴のようです。

Welcome! – Laravel PHP Framework
Laravel Advent Calendar 2013 – Qiita キータ

Phalcon

こちらも今年注目を集めたフレームワークです。

Phalcon は PHP 拡張として実装されており、フレームワークのソースコードも C で書かれています。つまり、実行速度の速さが大きな特徴です。

PHP 拡張なので、そもそも拡張がインストールできる環境で無いと使えなかったり、バージョンアップの際に Web サーバや php-fpm の再起動が必要、フレームワークのコードが読みにくいなどのデメリットは考えられますが、かなりキャラの立ったフレームワークですので、フレームワーク自体の実行速度がボトルネックになっている環境では大きな武器になるでしょう。

High performance PHP framework(Phalcon 公式)
PHP Phalcon 噂の爆速フレームワーク、はじめの一歩。
爆速フレームワーク!! Phalcon PHP Framework – Qiita キータ

書籍

今年もいくつかの PHP に関する書籍が登場したのですが、その中で2冊ほど。

PHPエンジニア養成読本

今どきのPHPに関する情報をぎゅっとまとめたムック本です。手前味噌ながら、こうしたPHP最新事情がまとまった書籍は少ないので、ざっくりと知るには良い本だと思います。

いまどきのPHPが分かる「PHPエンジニア養成読本」が出ます

PHP逆引きレシピ 第2版

PHP 逆引きレシピが、現在のPHP事情に合わせた内容となり、第2版として出版されました。

圧倒的なボリュームで、用途ごとに簡単な解説とコードの具体例が記載されており、実際に開発する際に手元に置いておくと参考になりそうです。

  • コメント (Close): 0
  • トラックバック (Close): 0

「Composer 再入門」を発表してきました( #KOF2013 )

この記事の所要時間: 312

2013/11/8, 9に大阪南港で開催されたKOF(関西オープンフォーラム)2013にて「関西PHP勉強会」のセッションを行いました。

Composer

今回は、いまやPHPerの必須ともいうべきComposerをテーマにしました。その中で「Composer 再入門」を発表してきました。

Composer再入門

Composer 再入門 from Masashi Shinbara

この発表では、Composer の基本的な使い方を紹介しています。自分でライブラリを公開する際の内容は @slywalker さんが発表されています

Composer を使うこと自体は簡単なので、基本的なところさえ知っておけば、特に問題は無いと思います。

ただ、今回の発表や先日行った Vagrant ハンズオンの際に感じたのですが、ターミナル操作の経験が無い人には、取っ付きづらいツールかもしれません。Composer を使わなくても、ZIP ファイルを直接ダウンロードすれば、フレームワークやライブラリを利用することができるのですが、そのフレームワークやライブラリも他のライブラリ利用に依存していたりするので、Composer で管理する方が楽です。

ターミナル操作に慣れる人が増えるか、はたまた Git のように GUI ツールが登場するか。PhpStorm のような IDE から Composer を使うのもアリですね。

Composer 小技

スライドでも紹介していますが、知っていれば便利な小技を少し。

Composer では composer.json に依存を書いていくわけですが、実は composer.json を書かなくても、依存コンポーネントをインストールできる方法があります。

composer.phar require

まずは composer.phar require です。

これは依存を追加するコマンドなのですが、composer.json が存在しない場合は自動で生成してくれます。さらに composer.phar install まで実行してくれるので、このコマンドだけで、composer.json 生成とインストールを実行してくれます。

例えば、下記コマンドを実行すると、composer.json の生成と twilio-php ライブラリをインストールが行われます。

$ ./composer.phar require twilio/sdk devmaster

なお、すでに composer.json が存在する場合は、composer.json に指定したコンポーネントを追加して、composer.phar install が実行されます。

composer.phar create-project

次に composer.phar create-project です。

このコマンドでは、既存のアプリケーションパッケージからチェックアウトして、新しいプロジェクトとして利用することができます。もちろん、そのアプリケーションが依存しているコンポーネントも自動でインストールされます。

下記は、Laravelの公式サイトに載っている例なのですが、このコマンドを実行するだけで、Laravel アプリケーションとフレームワークがチェックアウトされます。Symfony や CakePHP3 などでも同様の方法でプロジェクトを生成することができます。

$ ./composer.phar create-project laravel/laravel your-project-name --prefer-dist

  • コメント (Close): 0
  • トラックバック (Close): 0

Twilio をはじめるのに知っておくと良いこと6つ(Twilio API勉強会@大阪)

この記事の所要時間: 528

Twilio 盛り上がってきていますね。電話という身近でありながらシステムとして扱うには複雑な仕組みが必要なものを単純な API で操作できるというのは面白いサービスです。

先日大阪で行われたTwilio API勉強会@大阪にて、PHP から Twilio を触ってみるハンズオンセッションを行ないました。Twilio を使うと簡単な PHP コードで、自分の携帯を鳴らしたり、携帯から電話をかけてみたり、簡単に試すことができるので、これはハンズオンとしてもなかなか楽しかったです。

お声がけいただき、ありがとうございましたm(_ _)m

発表資料はこちら。

Twilio API を PHP で触ってみよう from Masashi Shinbara

ハンズオンの手順は、Gist に書いています。ここでは、Composer を使って、twilio-php(PHP版のTwilioライブラリ)をインストールしています。

https://gist.github.com/shin1x1/7006593

Twilio は使いやすいサービスなのですが、はじめる際に知っておくと良いポイントを挙げてみます。

1. まず Twilio をはじめるならこれ

Twilio 公式ドキュメントは内容が豊富で、リファレンスだけでなく実用例など役立つ内容なのですが、はじめて触る人は迷ってしまいまいがちです。

まず、Twilio とは何ぞや、ざっくりどう使えば良いかを掴むには、Twilio サイトにある「ゼロからはじめるぜ!Twilio」という連載がオススメです。

アカウント作成から、Twilio を使った電話のインバウンド、アウトバウンド、そしてPHPによるサンプルコードの実装など、まず第一歩を踏み出すには分かりやすい内容ですので、まずTwilioを触ってみようという人はこの連載を第一回から通して見てみるのが良いでしょう。

ゼロからはじめるぜ! Twilio – Twilio for KDDI Web Communications

2. 処理の流れをつかむ

Twilio と連携ライブラリには様々な機能があるので、はじめはどの局面でどれを使えば良いかが分からない場合があります。

まずは、Twilio と Web アプリケーションとでどういった連携を行うかを流れとして掴んでおくと良いでしょう。

Twilio とWebアプリケーション間ではHTTPリクエストで通信して連携を行ないます。これには、Twilio からアプリケーションWebアプリケーションへHTTPリクエストが送られるパターンと、反対にWebアプリケーションからTwilioへHTTPリクエストを送るパターンがあります。

まずは、Twilio から Web アプリケーションへ HTTP リクエストが送信するパターン。電話のインバウンドがこれにあたります。

この場合、Web アプリケーションでは、TwiML を生成して、返します。twilio-php を使う場合、Services_Twilio_Twimlクラスを利用します。

twilio-php-15-1

次に、Web アプリケーションから Twilio へ HTTP リクエストを送信するパターン。電話のアウトバウンドがこれにあたります。

この場合、Web アプリケーションでは、REST API を実行します。twilio-php を使う場合、Services_Twilioクラスを利用します。

twilio-php-41

つまり、用途に応じて、TwiML と返せば良いのか、REST API を実行すれば良いのかの見極めが重要となります。(とりあえず REST API を実行すれば良いのかと思い、REST API ばかり調べて「?」となりました:-p)

3. アプリケーションの検証は、まずはブラウザで

twilio-php で、Twilio 連携部分を実装した場合、いきなり電話をかけてテストするのではなく、まずはブラウザ等で TwiML が正常に生成されているかを確認しましょう。

ハンズオンでもあったのですが、そもそも PHP レベルでエラーとなっていると、電話をかけても正常に動作しません。電話ではエラーの原因もわからないので、まずはブラウザ等で動作確認してから、電話での確認を行うと良いです。(電話代もかかりますしね)

4. セキュリティ

  1. を見ると「おやっ?」と気づく人もいると思うのですが、Twilio からの Web アプリケーションへの通信は、単なる HTTP 通信なので、何も対応していないと Twilio を偽装したリクエストを Web アプリケーションへ送信することができてしまいます。

Web アプリケーション側では、送信されてきた HTTP リクエストが Twilio からのものかを検証する方法が用意されているので、本番環境ではこれらを対応しておくと良いでしょう。

  • HTTPS による通信
  • Basic認証 or Digest認証
  • Twilio からのリクエストをバリデーション

Twilio Docs – Security

5. SMS は、海外番号からしか送受信できない

Twilio でまず使いたくなるのが、SMS の送受信なのですが、現状(2013/10/30)、日本国内の番号からは利用することができません。

海外番号を入手するには、Twilio にクレジットカードを登録して、本アカウントに切り替える必要があります。

2要素認証など、SMS を活用したい場面があると思うので、お試しアカウントでも触れると便利なのですが。

6. そして Twilio 公式ドキュメント

こうして Twilio の概要をおさえた後は、Twilio 公式ドキュメントが大いに役立ちます。特にユースケース毎の実装例などは、仕組みを理解するにも良いですね。

Twilio ドキュメント
Twilio – ガイドとハウツー(実装例)

おまけ. SMS が、au より Softbank の方が安い

KDDI Web Communications のサービスなのですが、なぜか SMS 送信料が、au(9.6円)よりSoftbank(1.5円)の方が安くなっています。

不思議に思ったのですが、色々な事情があるようです。

  • コメント (Close): 0
  • トラックバック (Close): 0

イベント参加報告会という勉強会セッション(Fukuoka.php vol.10, 第10回関西PHP勉強会)

この記事の所要時間: 316

イベント参加報告会という勉強会セッションがあらためて面白かったという話。

Fukuoka.php PHPカンファレンス&WordCamp Tokyo参加報告会

Fukuoka.php vol.10 に参加してきました。もてなしていただき、ありがとうございましたm(_ _)m

今回は「PHPカンファレンス & WordCamp Tokyo」参加報告会ということで、イベントに参加した人がそれぞれの参加レポートを10分程度発表していくという形式でした。

参加レポートといっても、形式張ったものではなく、写真やスライドを交えて、実際に行った感想や、どのセッションを見た、こんな写真を撮った、宿はこうして確保など、友人に「こんなイベント行ってきたよ」と話すような気軽な内容です。

実際に参加してみて、これはとても良いアイデアだと思いました。

まずは、話す側から。

技術的なセッションとは違い、参加した自分自身の感想を話すセッションなので、その人が感じたことが正解であり、誰かに間違いを正されることはありません。詳しくないから話せいないということもなく、誰もが気軽に話せるセッションだと思います。話すきっかけを探している人にとっては良いチャンスです。

次に、聞く側から。

遠方のイベントに興味があるけれど、なかなか参加できないという人にとっては、参加した人の生の声を通してイベントを知ることができます。セッション内容やイベントとしての全体のレポートは Web 上でまとめられることが多いですが、身近な人から直接聞くことで、よりイベントを近くに感じることができます。

これを聞いた人が、次回以降にそのイベントへ参加するきっかけになると良いですね。

第10回関西PHP勉強会

後日開催した第10回関西PHP勉強会 では、このアイデアを拝借して、「PHPカンファレンス&WordCamp Tokyo&JAWS Festa Kansai参加報告会」を開催しました。( @akase244 さん、事後報告ですが、アイデア拝借させて頂きましたm(_ _)m )

私は、PHPカンファレンスとJAWS Festa Kansaiについての参加レポートを話してきました。参加レポートといってもメインは JAWS Festa Kansai で行われたアンカンファレンスについて話しました。

アンカンファレンスという名前から想像する印象とは異なっていたのですが、それぞれのテーマに基いてグループ(6–10人程度)が作られ、モデレータが中心となり、その話題について語り合うという内容です。Chef や AWS、カンファレンス運営や、baser CMSのチューニング方法など様々なテーマが用意されていました。

少人数で議論に参加するため、おそらく傍観者として、ただ見ているだけという人はいなかったように思います。テーマについての理解度は人それぞれですが、各々の立場での考えを述べて、それに対するリアクションと聞いてといった具合に全員が参加することができる良いセッションだと感じました。

いずれはこういったセッションもやってみたいですね。(もっと踏み込んで、グループで、何かの OSS についてパフォーマンスチューニングしたり、ハックするイベントをやるのも面白そう。)

参加レポートのために必要なこと

両イベントで色々な参加レポートを聞いたのですが、やはり写真は大事ですね。イベントの様子を話すには、写真があるとないとでは伝わることが大きく違います。blog 書く時も同様なので、写真は忘れずに撮っておきたいものです、はい。

そういえば、Fukuoka.php も関西PHP勉強会も今月 10 回目だったんですね!お互いに続けていければ良いですねー。

  • コメント (Close): 0
  • トラックバック (Close): 0

PHP開発環境のサンプルVagrantfile

この記事の所要時間: 510

PHPカンファレンス2013でPHP開発環境をVagrantで作る発表を行ったのですが、具体的なVagrantfileが欲しいという声を頂いたので、GitHubに公開しました。

vagrant

ご自身で構築するベースになれば良いと思うので、どう作れば良いの?と言う方は参考にしてみて下さい。

なお、このリポジトリの Vagrantfile は、開発PC内の VirtualBox 上で開発環境として動かすことを想定しています。セキュリティについては考慮されていないのでご注意下さい。

vagrant-lapp-sample

https://github.com/shin1x1/vagrant-lapp-sample

このリポジトリは、PHPアプリケーション(CakePHP)をイメージしています。構成は以下です。

  • CentOS 6.4
  • Apache 2.2
  • PHP 5.4
  • PostgreSQL 9.3
  • phpPgAdmin

ディレクトリ構成としては、app/ がアプリケーションのコードを置くディレクトリで、vagrant/ に Vagrant のファイルを置くイメージです。

app/ には、サンプルとして CakePHP アプリケーションを置いています。(cake bake project したもの)

使い方

git clone でプロジェクトのコードを取得して、あとは vagrant ディレクトリ で、vagrant up を実行するだけです。

$ git clone https://github.com/shin1x1/vagrant-lapp-sample
$ cd vagrant-lapp-sample/vagrant
$ vagrant up

アプリケーションへのアクセス

ブラウザから http://192.168.33.30/ にアクセスすると、PHPアプリケーションを実行することができます。

phpPgAdminへのアクセス

ブラウザから http://192.168.33.30/phpPgAdmin/ にアクセスすると、phpPgAdmin を利用できます。ユーザは vagrant、パスワードは pass です。(厳密にはパスワードは何でも ok です)

ポイント

synced_folder

このリポジトリのルートディレクトリ( app/ があるディレクトリ)を synced_folder に設定しており、仮想マシンからは /share でアクセスすることができます。

つまり、ホストPCで app/webroot/index.php というファイル編集すると、仮想マシンでは /share/app/webroot/index.php のファイルが自動で更新されます。

ドキュメントルート

Apache のドキュメントルートは、/share/app/webroot に設定しています。

これは vagrant/httpd.conf で設定しており、プロビジョニング実行時に /etc/httpd/conf/httpd.conf に上書きされます。変更が必要であれば、vagrant/httpd.conf を編集して、vagrant provision でプロビジョニングを再実行すると良いでしょう。

なお php.ini も同様に vagrant/php.ini を用意しています。

設定ファイルの準備

Apache や PHP などの設定ファイルを準備する際は、下記手順で行っています。

仮想マシン内での /vagrant ディレクトリが、ホストPCでは Vagrantfile があるディレクトリと synced_folder になっているのがポイントです。

  • まずが vagrant up で仮想マシンを起動
  • vagrant ssh でログインして、yum で対象パッケージをインストール
  • 設定ファイルを変更、動作確認
  • cp -a /etc/http/conf/http.conf /vagrant/
  • ホスト PC の variant/ に httpd.conf がコピーされる
  • プロビジョニングで、/vagrant/httpd.conf を /etc/httpd/conf/ にコピーするコードを書いておく

データベース

この Vagrantfile では、データベースの構築は行っていますが、アプリケーションで必要なテーブル定義などは行っていません。

このあたりはプロジェクトによって方法が異なると思いますが、フレームワークやライブラリ等でマイグレーション機能があればそちらを、無ければ dmp ファイルを適用するコマンドをプロビジョニングで記述することになります。
( PostgreSQL であれば、 psql -Uvagrant app < pgsql.dmp など。)

シェルプロビジョニング

プロビジョニングには、シェルを使っています。

普段、サーバにSSHログインして yum や apt-get などでインストールしているコマンドをそのまま Vagrantfile に記述していくだけなので、簡単に書けるのが利点です。

Chef や Puppet、Ansible などのプロビジョニングツールを利用しても良いのですが、以前にこういったツールを使ったことが無いのであれば、まずはシェルで構築してみて、次の段階として好みのプロビジョニングツールを試してみるがおすすめです。(もちろん、一気にプロビジョニングツールを使いたい方はその方法でも問題ありません。)

Composer

composer.json が存在すれば、composer.phar をダウンロードして、composer install を実行するようにしています。

このリポジトリでは、CakePHP と PHPUnit を Composer でインストールしています。

  • コメント (Close): 0
  • トラックバック (Close): 0

ホーム > PHP

検索
フィード
メタ情報

Return to page top