Heroku での PHP アプリとビルドパックの連携方法

Heroku が PHP を公式サポートしてくれたので、この記事は役目を終えたと思います。この記事をストック、見てくれたありがとうございました。
https://blog.heroku.com/archives/2014/4/29/introducing_the_new_php_on_heroku
https://devcenter.heroku.com/articles/php-support

~~Heroku では PHP を公式でサポートしていません~~が、Heroku 上で PHP を動かすという話はよく聞きますよね。
Heroku は、``git push`` した際にデプロイの処理が走るという特徴があり、ビルドパックという仕組みが支えています。

公式サポートはしていないものの、Heroku は PHP のビルドパックを公開していて、fork することでカスタムビルドパックを作ることができます。
https://github.com/heroku/heroku-buildpack-php

「Heroku buildpack php」 や、「Heroku php mbstring」などとビルドパックの作り方を調べると、github で公開されてるビルドパックを使う手順になっているか、mbstring などを読み込ませて phpinfo に表示させるという手順止まりなことが多いです。

PHP アプリを動かすために、環境面は極力ビルドパックに寄せる方針で環境を作った中で見えてきたことをまとめます。


## PHP の module をビルドする
Heroku では、``heroku run bash`` で dyno の中でターミナル操作ができます。
この dyno の中では、/tmp にだけ書き込み権限があるようなので、/tmp にPHPのソースコードを clone し、module のビルドをします。PHP のソースコードを一度でも git push しておかないと、phpize コマンドが使えないので注意しましょう。


1.``heroku create``
2.``git push origin master`` => 適当なPHP コードを push しておく
3.``heroku run bash``
4.``mkdir tmp && cd tmp``
5.``git clone https://github.com/php/php-src.git``
6.``cd php-src``
7.``git checkout php-5.3.10``
8.``cd ext/mbstring && /app/php/bin/phpize && ./configure --with-php-config=/app/php/bin/php-config && make``


## ビルドした module をアプリに含める


実際に動かしたいアプリのリポジトリにコンパイル済みの module を含めてしまいます。
その事前準備として、Heroku の dyno 中にリポジトリを clone します。
Private リポジトリなら、https://password@github.com/hare/hore.git のように書く必要があります。

9.``git clone https://github.com/hare/hore.git``
10.``cd hore``

Heroku の dyno から github に push するので、git の username と email address を設定します。

11.``git config --global user.name "hokkai7go"``
12.``git config --global user.email hokkai7go@gmail.com``
13.``mkdir libs``
14.``cp /app/tmp/php-src/ext/mbstring/modules/mbstring.so .``
15.``git add mbstring.so``
16.``git commit -m "Add mbstring module to repository"``

ここでは仮に origin(GitHub)の heroku ブランチに push します。

17.``git push origin heroku``

push が終わったら、``exit`` コマンドで heroku の dyno から出ても構いません。
これで、アプリケーションのリポジトリに mbstring.so が含まれました。

## ビルドパックの調整

しかし、これでは mbstring は有効になりません。なぜでしょうか。読み込む設定が書かれていないからです。
ここでカスタムビルドパックの登場です。
Heroku では、PHPを公式サポートしていませんが、GitHub でビルドパックを公開しています。
https://github.com/heroku/heroku-buildpack-php
PHPアプリが push されるとデフォルトで、このビルドパックが使われます。
それでは、このビルドパックを fork して mbstring が読まれるようにしてみましょう。

ここでは、自分が fork したものを例に解説します。
18.``git clone git@github.com:hokkai7go/heroku-buildpack-php.git``
19.``vi conf/php.ini``

``extension=/app/www/libs/mbstring.so
``
``*.so`` で検索すると、extension のパスを設定しているところがあるので、上に書いた一行を追加します。

20.``git add conf/php.ini``
21.``git commit -m "Add path to mbstring.so"``
22.``git push origin master``

Heroku では、アプリケーションのリポジトリは、/app/www に展開されるので、そこに libs フォルダを作成し、mbstring.so を入れました。php.ini にパスを書いてあげてビルドパック側の調整は終わりです。

それでは、アプリケーションで使うビルドパックを変更しましょう。``heroku create`` したディレクトリに移動して以下のコマンドを実行して下さい。

23.``heroku config:set BUILDPACK_URL=https://github.com/hokkai7go/heroku-buildpack-php``

ここに二つ、ハマリポイントがあります。

* ハマリポイント1

heroku の config vars にはいろんな値をセットできるのですが、自分は最初 ``BUILD_PACK_URL`` としてセットしていました。正しくは BUILDPACK_URL ですね。
間違っていても特に何か起こるわけではないので、間違いに気が付きにくかったです。

* ハマリポイント2

23.のコマンドで、ビルドパックを変更しても ``git push`` しないとカスタムビルドパックを使ってくれません。
``git push`` 以外に、方法が無さそうです。
設定変更をして、再度デプロイするというユースケース結構あると思うんだけどなぁ。
この対処については、23. を見て下さい。

24.``git commit --allow-empty -m "Apply buildpack setting" && git push heroku master``

空コミットして、``git push`` することで対処しました。
これでアプリ側に問題がなければ、mbstring が有効になっていると思います。
phpinfo を push してみてみるといいですね。


上記の例では、PHP 5.3.10 用に module をビルドしていますが、PHP 5.3 は End of Life を迎えたはずなので PHP5.4 用のブランチを checkout してビルドするのがよさそうです。

8. のディレクトリ移動先を変えることで、mbstring 以外のモジュールも同様にビルドされます。

## 注意点
注意すべきなのは
/tmp/php-src/ext/mbstring 以下に mbstring.so が作られている点と
この dyno を再起動すると、/tmp 自体が消えてしまうので、ビルドしたモジュールはおろか、clone してきた php-src すら消えてしまう点です。

# 参考情報
https://devcenter.heroku.com/articles/buildpacks
http://blog.candycane.jp/archives/1375