Meet Phalcon! - Phalcon PHPフレームワークを Nginx on Amazon EC2 にインストール！

あけましておめでとうございます！ [cloudpack][] の @dz_ こと[大平かづみ][]です。
今年の初投稿です、今年度もどうぞよろしくお願いいたします！

Prologue - はじめに
=================================================

お気に入りのPHPフレームワーク [Phalcon Framework][phalcon] を、[Nginx][] で動かしてみます！

[phalcon]:http://phalconphp.com/ "High performance PHP framework"

最初に Phalcon を触った時は、インフラ担当さんに作ってもtらった IIS + Phalcon で動かしていました。
コードは書きますが、環境構築は手順に従うことが多かったのです。

そんな私ですが、自力で試行錯誤して作りました！

Nginx は初めて触ったので至らぬ点もあるかも知れません。
改善・改良点あれば、すぐに反映させていただきます。ご了承くださいますよう、よろしくお願いいたします。

やること
==================================================

1. Nginx で PHP が動く環境を作る
2. Phalcon を動かす環境を作る
3. Phalcon のプロジェクトを動かす環境を作る
4. 環境の自動起動を設定しておく

----

1. Nginx で PHP が動く環境を作る
=================================================

それではまず、Amazon Linux (t2.micro) に Nginx +　PHP(php-fpm) の環境をつくって行きます！

WEBサーバーの動作環境を作る
----------------------------------------------------
### Nginx をインストール
手始めに [Nginx][] を yum でちょちょいとインストールします。
[Nginx]:http://nginx.org/ "Nginx Official Site"

```bash
# nginx のインストール、および起動確認
$ sudo yum install nginx
$ sudo service nginx start
Starting nginx:                                            [  OK  ]
```

この状態で、 `http://そのインスタンスのURL(or IPアドレス)/` にアクセスすると、Nginx のテスト画面が表示されているはずです。 

PHP の動作環境を作る
----------------------------------------------------
### php-fpm をインストール
続いて、[php-fpm][] のインストールです。
[php-fpm][] は、PHPのFastCGIの実装のひとつで、 Nginx + php-fpm の組み合わせはよく使われているようです。

[php-fpm]:http://php.net/manual/ja/install.fpm.php "PHP: FastCGI Process Manager (FPM) - Manual"

```bash
# php-fpm のインストール、起動
$ sudo yum install php-fpm
$ sudo service php-fpm start
Starting php-fpm:                                          [  OK  ]
```

Nginx + PHP(php-fpm) が動くように設定する
------------------------------------------------

PHP が動くように設定します。

まずは動作確認を兼ねて、手っ取り早く、ドキュメントルート (`/usr/share/nginx/html`) の配下に .php ファイルを置く想定で、設定します。
(virtual host で動かしたりはまたあとで…！)

### nginx.confを設定する

`/etc/nginx/nginx.conf` を以下のように変更しましょう。

- 下記がコメントアウトされているので、有効にしてください。
- `root` はコメントのままでも動きました。
- `fastcgi_param  SCRIPT_FILENAME` の値を   `$document_root$fastcgi_script_name;` に変更してください。

```bash:/etc/nginx/nginx.conf

...

server {

...

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
        #    root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
        #   fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

...
```

### 落とし穴

うまくいかないときは、ログを見てみましょう。

```bash
# nginx のエラーログを見てみる
$ sudo tail /var/log/nginx/error.log
...
2015/01/01 05:23:35 [error] 2418#0: *2 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: yy.yy.yy.yy, server: localhost, request: "GET /info.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "xx.xx.xx.xx"
```

例えば、以下のようなエラーが…

- `FastCGI sent in stderr: "Primary script unknown"` というエラーが出ている場合は、 `fastcgi_param  SCRIPT_FILENAME` の設定が正しくありません。 `/scripts` ではなく、適切なパス(今回は、`$document_root`)を設定してください。

Nginx + PHP(php-fpm) の動作確認をする
---------------------------------------------------

ここまでくると、純粋な Nginx + PHP(php-fpm) の環境ができているはずです。 PHP が正しく動作するか確認してみましょう。

今回のドキュメントルートは `/usr/share/nginx/html` です。
ここに以下の `info.php` (任意)を作って、`phpinfo()` で PHP の状況を表示させます。

```php:/usr/share/nginx/html/info.php
<?php
phpinfo();
```

そして、ブラウザで `http://*そのインスタンスのIPアドレス*/info.php` にアクセスすると、
見慣れた薄紫色の画面が見えましたね？
![20150101_phpinfo_000.png](https://qiita-image-store.s3.amazonaws.com/0/3812/6f99ecb0-bbd9-378d-345f-6d2494571400.png)


さぁ、やっと土台ができました。続いて、Phalcon の準備を進めましょう。

----

2. Phalcon を動かす環境を作る
===================================================

Phalcon が依存するモジュールのインストール
--------------------------------------------------

Phalcon [ダウンロードページ][phalcon-download]の下部に、依存するモジュールが記載されています。この中で最低限必要なモジュールをインストールします。

[phalcon-download]:http://phalconphp.com/ja/download "Download Phalcon for Linux&#x2F;Unix&#x2F;Mac"

### MySQLサーバーをインストール
```bash
# MySQLサーバーをインストール
$ sudo yum install mysql-server

# MySQLサーバーを起動
$ sudo service mysqld start

# MySQLのセキュアなインストールを実施し、記載に従って初期設定を行う
$ sudo /usr/bin/mysql_secure_installation
```

MySQLサーバーのインストールについては資料が多く出ているので、不明点はそちらをご参照いただければ幸いですm(_ _)m

### PDO, php-mysqlnd をインストール

[PDO][pdo-introduction] とは、PHP Data Objects 拡張モジュールのことです。様々なデータベースが PDO に対応しており、これを利用することで、PHP からデータベースを扱う部分を共通化できます。
また、[php-mysqlnd][] は、MySQL Native Driver のことで、PHP 5.3 以降で PDO MySQL を利用する際に併せて利用するモジュールです。

[pdo-introduction]:http://php.net/manual/ja/intro.pdo.php "PHP: PDO: 導入 - Manual"
[php-mysqlnd]:http://php.net/manual/ja/intro.mysqlnd.php "PHP: Mysqlnd: 導入 - Manual"

```bash
# PDOを と php-mysqlnd をインストール
$ sudo yum install php-pdo php-mysqlnd
```


Phalconモジュールを組み込む
---------------------------------------------------

### Phalconモジュールを作る (コンパイル)

```bash
# phalcon のコンパイルに必要なものをインストール
$ sudo yum install php-devel pcre-devel gcc make

# phalcon のソースを取得、コンパイル
$ git clone --depth=1 git://github.com/phalcon/cphalcon.git
$ cd cphalcon/build
$ sudo ./install
```

Phalconのモジュール `phalcon.so` はここに出力されます。(64bitの場合)

`./cphalcon/build/64bits/modules/phalcon.so`

### phalcon.so を設置
phpのモジュールを置くディレクトリに `phalcon.so` を置き、phpにそれをロードするよう設定ファイルを追加します。

```bash
# モジュールを配置
$ sudo cp ./cphalcon/build/64bits/modules/phalcon.so /usr/lib64/php/modules/

# phalcon.ini を新規作成 (※内容は後述)
$ sudo vi /etc/php.d/phalcon.ini

# php-fpm を再起動
$ sudo service php-fpm restart
Stopping php-fpm:                                          [  OK  ]
Starting php-fpm:                                          [  OK  ]
```

`phalcon.ini` には以下のように記述します。

```:/etc/php.d/phalcon.ini
extension=phalcon.so
```

### Phalconモジュールが正しくロードされたか確認

再度 `phpinfo()` を表示させ、`phalcon` があることを確認します。

![20150103_phpinfo-include-phalcon_002.png](https://qiita-image-store.s3.amazonaws.com/0/3812/17013747-45e3-14d5-498b-61b172e0c5d3.png)


さらに、エクステンションにモジュールが正しくロードされてるか確認してみましょう。
 list_extensions.php (任意) を作成して、Phalconドキュメントの「[インストールの確認][check-installing-phalcon]」で紹介されている `get_loaded_extensions()` を用いて確認しました。

[check-installing-phalcon]:http://docs.phalconphp.com/ja/latest/reference/tutorial.html#id2 
```bash
# list_extensions.php を作って、ロードされているエクステンションを確認
$ sudo vi /usr/share/nginx/html/list_extensions.php
```

```php:/usr/share/nginx/html/list_extensions.php
<?php
print_r(get_loaded_extensions());
```

![20150103_php-extensions_002.png](https://qiita-image-store.s3.amazonaws.com/0/3812/6de894b3-a8ad-9bc6-4fb0-cb37743f7f08.png)


3. Phalcon のプロジェクトを動かす環境を作る
=====================================================

それでは、次は Phalcon のプロジェクトを用意して、動作させるところまで作りましょう！あともう少しです！

Phalcon DevTools をインストール
----------------------------------------------------

Phalconドキュメントの「[デベロッパーツールのダウンロード][phalcon-tools]」に従って、 DevTools をインストールします。

[phalcon-tools]:http://phalconphp.com/ja/download/tools "Download Phalcon Developer Tools"

### Composer をインストール
[Composer][] は、PHP のライブラリ管理ツールです。json で必要なライブラリのリストを記述することで、依存関係のライブラリも含めて管理してくれます。

[Composer]:https://getcomposer.org/ "Composer - Dependency Manager for PHP"

```bash
# Composer のインストール
$ curl -s http://getcomposer.org/installer | php
#!/usr/bin/env php
All settings correct for using Composer
Downloading...

Composer successfully installed to: /home/ec2-user/dev/composer.phar
Use it: php composer.phar
```

### phalcon/devtools をインストール

Composer をインストールできたら、管理ファイル `composer.json` に必要なライブラリ `phalcon/devtools` を書きます。
この `composer.json` は、私はユーザーディレクトリ配下に置きましたが、Phalcon のプロジェクトディレクトリの近くに置くのがいいかも知れません。

```json:composer.json
{
    "require": {
        "phalcon/devtools": "dev-master"
    }
}
```

```bash
# phalcon/devtools をインストール (composer.json があるディレクトリで実行)
$ php composer.phar install

# 実行できるようにリンク、権限の調整
$ sudo ln -s ~/vendor/phalcon/devtools/phalcon.php /usr/bin/phalcon
$ sudo chmod ugo+x /usr/bin/phalcon
```

Phalcon DevTools を使ってみる
-------------------------------------------------------------

さて、ここまで来ると、 `phalcon` コマンドが使えるようになっています。

以下で少し試してみますが、詳しくは、Phalconドキュメントの「[Phalcon 開発者ツール][Phalcon DevTools]」ページをご参照ください。
[Phalcon DevTools]:http://docs.phalconphp.com/ja/latest/reference/tools.html "Phalcon 開発者ツール — Phalcon 1.3.1 ドキュメント"

### Phalcon DevTools のコマンドを確認してみる

Phalcon DevTools は、以下のことができます。

- プロジェクトの作成
- scaffoldの生成
- コントローラ/モデルの作成
- webインタフェースによるプロジェクト管理の有効化
- などなど…

```bash
$ phalcon commands

Phalcon DevTools (1.3.4)

Available commands:
  commands (alias of: list, enumerate)
  controller (alias of: create-controller)
  model (alias of: create-model)
  all-models (alias of: create-all-models)
  project (alias of: create-project)
  scaffold
  migration
  webtools
```

Phalcon のプロジェクトを作ってみる
-------------------------------------------------------------

### sample プロジェクトを作る

実際に、プロジェクトのサンプルを作ってみます。
今度はドキュメントルートを `/var/www/phalcon` にして、進めます。

```bash
# ドキュメントルートにする /var/www/phalcon ディレクトリを作成
$ sudo mkdir /var/www/phalcon
$ cd /var/www/phalcon

# sample プロジェクトを作成
$ phalcon create-project sample
$ cd ./sample
```

`sudo yum install tree` で `tree`コマンドをインストールして、プロジェクトのディレクトリの階層構造を表示してみました。

```bash
$ tree .
.
├── app
│   ├── cache
│   │   ├── _var_www_phalcon_sample_app_views_index_index.volt.php
│   │   └── _var_www_phalcon_sample_app_views_index.volt.php
│   ├── config
│   │   ├── config.php
│   │   ├── loader.php
│   │   └── services.php
│   ├── controllers
│   │   ├── ControllerBase.php
│   │   └── IndexController.php
│   ├── models
│   └── views
│       ├── index
│       │   └── index.volt
│       ├── index.volt
│       └── layouts
├── index.html
└── public
    ├── css
    ├── files
    ├── img
    ├── index.php
    ├── info.php
    ├── js
    ├── list_extensions.php
    └── temp

14 directories, 13 files
```

### cacheディレクトリに書き込み権限を与える

Phalcon は、テンプレートエンジン (Volt) を使ってビューを生成します。
このとき、生成したビューは、以下のように `*.volt.php` として `app/cache` 配下に出力されます。
そのため、 `app/cache` に書き込み権限を与える必要があります。

```bash
.
├── app
│   ├── cache
│   │   ├── _var_www_phalcon_sample_app_views_index_index.volt.php
│   │   └── _var_www_phalcon_sample_app_views_index.volt.php

...

```

```bash
# app/cacheディレクトリに書き込み権限を与える
$ sudo chmod o+w ./app/cache
```

###  Phalcon プロジェクトに合わせて nginx.conf を調整する

Phalcon は、仕組み上、 httpリクエストを rewrite して /public/index.php に集約して、ルーティングを行います。
デフォルトでは、`.htaccess` を利用するのですが、Nginx では、confファイルで設定します。

[Nginx インストール ノート][phalcon-nginx-installation-note]を参考に、以下のように設定しました。
[phalcon-nginx-installation-note]:http://docs.phalconphp.com/ja/latest/reference/nginx.html "Nginx インストール ノート — Phalcon 1.3.1 ドキュメント"

- `http` の `index` の先頭に、`index.php` を追加
- `root` を `$root_path` を利用して `/var/www/phalcon/sample/public` に変更 (プロジェクトディレクトリの `public`ディレクトリへ)
- `try_files ... ` から下数行を以下のように追記
-  `location ~ \.php$ { ... }` を以下のように追記
-   `location ~ /\.ht { deny  all; }` のコメントアウトを外す

```:/etc/nginx/nginx.conf
http {

...

#    index   index.html index.htm;
    index index.php index.html index.htm;

    server {
        listen       80;
        server_name  localhost;

#        root         /usr/share/nginx/html;
        set $root_path '/var/www/phalcon/sample/public';
        root $root_path;

        try_files $uri $uri/ @rewrite;

        location @rewrite {
                rewrite ^/(.*)$ /index.php?_url=/$1;
        }

        location ~* ^/(css|img|js|flv|swf|download)/(.+)$ {
                root $root_path;
        }

...

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
        #    root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;

            fastcgi_split_path_info             ^(._+\.php)(/.+)$;
            fastcgi_param  PATH_INFO            $fastcgi_path_info;
            fastcgi_param  PATH_TRANSLATED      $document_root$fastcgi_path_info;
            fastcgi_param  SCRIPT_FILENAME      $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        location ~ /\.ht {
            deny  all;
        }
    }
```

### Phalcon の sample プロジェクトを動作確認する

さぁ、これで初めての Phalcon アプリケーションが動くはずです！

`http://サイトのURL/` にアクセス！！

![20150101_Phalcon-PHP-Framework_congrat.png](https://qiita-image-store.s3.amazonaws.com/0/3812/69ef082a-e523-8027-fdb7-43ed17d3c1a7.png)

__Congratulations!!__

やったーーー！

----

Epilogue - おわりに
==================================================

念願の Phalcon の環境構築ができました…！(嬉し泣き)
慣れたフレームワークの PHP の動作環境ができたので、これをベースにさらにいろいろ修行していきます！


### 最後に…、環境の自動起動を設定しておく

最後に、こうしておくことで、リブートしても自動で起動してくれます。

```bash
# リブート時に自動で起動するように設定
$ sudo chkconfig mysqld on
$ sudo chkconfig php-fpm on
$ sudo chkconfig nginx on
```



----

近況
---------

[cloudpack技術ブログ][cloudpack-blog]でも、AWS Lambda や 運用ツールに関して記事を書いています。ご興味あれば読んでいただけると嬉しいです！

- <a href="http://blog.cloudpack.jp/author/oohira/" title="大平 かづみ の記事一覧 | cloudpack技術情報サイト"　target="_blank">大平 かづみ の記事一覧</a>


[cloudpack]:https://cloudpack.jp/ "cloudpack（クラウドパック） 400社を超える導入実績! EC2などAWSクラウドの導入設計、構築、運用保守サービス"
[cloudpack-blog]:http://blog.cloudpack.jp/ "cloudpack技術情報サイト"
[大平かづみ]:http://blog.cloudpack.jp/author/oohira/ "大平かづみの記事一覧"