Dockerで古いPHP(5.x)のXdebugを組み込んだデバッグ環境を構築する

# はじめに
新しい技術が好きな技術者といえども、古いシステムの改修や保守のために既にサポートが切れてしまっているようなバージョンのソフトウェアを触ることになる、という経験は誰しも訪れる。

そんなとき、古い開発環境をわざわざインストールしたくない。

ならば仮想化技術の出番でしょう。

# 追記 1
mac OSでうまく動かなかったので対処しました。
mac OSの場合は最終的にlocalhostにDockerコンテナ内のportがマッピングされるので、`http://localhost/`でアクセスできるようになります。
詳しくは[Docker公式 Networking features in Docker for Mac の項を参照](https://docs.docker.com/docker-for-mac/networking/)

作成したコードは[こちらのgithubリポジトリ](https://github.com/gcoka/php5-debug)にあります。

# 追記 2
mac OSではXdebugでのブレークポイントが確認できていません。
[こちらのGist](https://gist.github.com/ralphschindler/535dc5916ccbd06f53c1b0ee5a868c93)を元に、コンテナ内からhostのmac OSに接続できるように設定してあげれば良いはずなのですが・・・

# やること
- Dockerを使って、ローカル環境を汚さずにPHP5.3を実行できるhttpdサーバーを立てる開発環境を構築する
- VSCodeからPHPにデバッグをかけ、ブレークポイントを張る

# 最終形のファイル構成
このような形で進めていきます。

`public`の中には、webコンテンツが、`logs`の中にはapacheのログファイルが入ります。

```
.
├── docker-compose.yml
├── Dockerfile
├── logs
│   ├── access_log
│   ├── error_log
│   └── .gitkeep
├── public
│   ├── index.php
│   └── phpinfo.php
├── README.md
└── .vscode
    └── launch.json
```

# Dockerのバージョン確認
Dockerのバージョンを念の為に確認します。

```bash
$ docker -v
Docker version 17.09.0-ce, build afdb6d4

$ docker-compose -v
docker-compose version 1.15.0, build e12f3b9
```

# Dockerを使って、ローカル環境を汚さずにPHP5.3を実行できるhttpdサーバーを立てる開発環境を構築する
ここはもう、えいやと、Dockerfileとdocker-compose.ymlを作成します。

[こちら](https://github.com/nickistre/docker-lamp/tree/centos-6.6)のDockerfileを大いに参考にしました。

```Dockerfile:Dockerfile
FROM centos:6.6

# set repository
RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm

# install httpd
RUN yum -y install httpd vim-enhanced bash-completion unzip

# install php
RUN rpm --rebuilddb; yum install -y php php-mysql php-devel php-gd php-pecl-memcache php-pspell php-snmp php-xmlrpc php-xml

# Install xdebug for php debugging
RUN yum install -y php-pecl-xdebug
RUN echo "xdebug.default_enable = 1" > /etc/php.d/xdebug_settings.ini \
    && echo "xdebug.remote_enable=on" >> /etc/php.d/xdebug_settings.ini \
    && echo "xdebug.remote_autostart=on" >> /etc/php.d/xdebug_settings.ini \
    && echo "xdebug.remote_connect_back = on" >> /etc/php.d/xdebug_settings.ini \
    && echo "xdebug.remote_port = 9000" >> /etc/php.d/xdebug_settings.ini

EXPOSE 80

# Start web server
CMD ["httpd", "-D", "FOREGROUND"]
```

```docker-compose.yml
php-debug:
  build: .
  environment:
    # replace with your local IP
    XDEBUG_CONFIG: remote_host={{192.168.179.3}} 
  volumes:
    # ローカルのWebコンテンツをマウント
    - ./public:/var/www/html
    # Apacheのlogファイルをローカルに書き出してもらうために、logsをマウント
    - ./logs:/var/log/httpd
```

docker-compose.ymlファイルを作成するのは、２つ理由があります。
- MySQLなどのDBコンテナを簡単に連携させるため(この記事内でDB接続はしません)
- この開発環境を利用する開発者各自のローカル環境に依存する設定をコンテナ定義の外側に出すため

Dockerのビルドの前に、開発端末のlocal IPを調べて、docker-compose.ymlを書き換える必要があります。

```bash
ip a // linux, macOS
ipconfig // windows
```


次のコマンドを実行して、Dockerのビルドと実行をします。
最初はイメージやライブラリのダウンロードとインストールがあるので、それなりに時間がかかります。

```bash
docker-compose build
docker-compose up
```
ここまで実行すると、次のようなメッセージがコンソールに表示され、httpdサービスがコンテナ内で動作している状態になります。

```
Recreating phpdebug_php-debug_1 ... 
Recreating phpdebug_php-debug_1 ... done
Attaching to phpdebug_php-debug_1
php-debug_1  | httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3 for ServerNam
```
表示されているIPアドレスをブラウザに打ち込んでみましょう。

**Apache 2 Test Page
powered by CentOS**

と表示されていれば成功です。

あとは、コンテナ内の`/var/www/html`にマウントしているディレクトリの中にphpinfo.phpを作成して、ちゃんとマウントされているかも確認しておきましょう。

```php:phpinfo.php
<?
    phpinfo();
?>
```
ブラウザに `172.17.0.3/phpinfo.php` と入力してphpinfo()の内容が見れるか確認しましょう。

# VisualStudioCodeからPHPにデバッグをかけ、ブレークポイントを張る

Xdebugの機能でPHPのデバッグを行うのは、VisualStudioCode限定ではないのですが、有料のPhpStormを除けば、一番手軽だと思うので、VisualStudioCodeでデバッグをしてみます。

手順はとても簡単です。

- VisualStudioCodeにphp-debugの拡張をインストール
- デバッグでXdebug向け構成を作成
- デバッガ起動
- 動作を確認したいphpコードにブレークポイントを張る
- phpファイルにブラウザからアクセス

## VisualStudioCodeにphp-debugの拡張をインストール
拡張の検索で、 `php-debug` と入力してさくっとインストールしてください。

ブレークポイントを張るという目的ならば必要ありませんが、がっつり開発したいなら、好みで、`php-intellisense`を入れましょう。
機能を最大限使うためには、ローカル環境にphp 7コマンドをインストールしてあげる必要があります。

## デバッグでXdebug向け構成を作成
デバッグ構成の追加でlaunch.jsonファイルを生成して、内容は以下のようにします。

```json:.vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [

    {
      "name": "Listen for XDebug",
      "type": "php",
      "request": "launch",
      "port": 9000,
      "pathMappings": {
        "/var/www/html": "${workspaceRoot}/public"
      }
    }
  ]
}
```
デフォルト生成状態では追加されない項目が以下の２つですが、ブレークポイントを張るためには重要なので、設定を追加してください。
`localSourceRoot`は、ローカル環境に置いてある、デバッグ対象のWebコンテンツルートを指定します。この記事の例では、同じプロジェクトディレクトリにあるので、${workspaceRoot}を使っていますが、そうでない場合は、絶対パスでgitリポジトリを指定するなどしましょう。
`serverSourceRoot`はコンテナ内のWebコンテンツルートを指定します。


## デバッガ起動
VisualStudioCodeのデバッグ構成から`Listen for XDebug`を選択して、デバッグ開始します。

## 動作を確認したいphpコードにブレークポイントを張る
試しにということで、次のようなファイルを作成してみます。

```php:index.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div style="background-color:lightgray;">
    <?php
    $a = "world";
    echo "hello " . $a . " <br/>";
    echo "from xdebug!";
?>
    </div>

</body>
</html>
```

phpコード内の任意の行にブレークポイントを張りました。
![Screenshot from 2017-10-06 01-28-30.png](https://qiita-image-store.s3.amazonaws.com/0/193814/a617fa55-fb57-9372-5e82-2b23d6cffe38.png)

## phpファイルにブラウザからアクセス

ブレークポイントを張った状態でブラウザから対象のphpファイルにアクセスすると、ブラウザが応答待ちになり、VisualStudioCode側はブレークポイントで待機状態となります。

ちゃんと、変数の内容も表示されていますね。
![Screenshot from 2017-10-06 01-33-56.png](https://qiita-image-store.s3.amazonaws.com/0/193814/557178a1-5e41-bff2-5b11-ead1e304ed5c.png)

# 補足
xdebugの設定で、remoteポートを9000を設定したのに、DockerfileでEXPOSEしなかったことに疑問を持った方がいるかもしれません。
これは、VisualStudioCodeが9000でListenして、そこにコンテナ内のxdebugがアクセスするという仕組みになっているため、コンテナ内→外の通信なのでポート開放する必要がないというわけです。

よーくVisualStudioCodeのデバッグ設定を見てみると、「Listen for XDebug」 となっていて、9000番ポートの通信を待っているのはVisualStudioCodeの方ということになります。
このあたりは、Debugger for Chromeと通信方向が逆なので勘違いしやすいかもしれません。
(Chromeデバッグモードは、9222ポートで通信を待っているので、エディタ側が接続しに行く)