【PHP】リモートマシンのデバッグを、「複数人で」やる【Xdebug×DBGpProxy】


[参考](http://matthardy.net/blog/configuring-phpstorm-xdebug-dbgp-proxy-settings-remote-debugging-multiple-users/)

やむにやまれない理由で、ローカル環境またはローカルの仮想マシン内に自分だけの開発環境を構築できない場合があります。

でもリモートデバッグはやりたい...ヨダレが出るほどに...var_dumpとか書きたくないし！


#想定環境

今回の想定は、↓の図のような感じで開発してるものとします。

![legacy-dev-env.png](https://qiita-image-store.s3.amazonaws.com/0/34165/97939a33-9fce-2013-856f-7bb6dd2bb144.png "legacy-dev-env.png")

ポイントは、

* 開発者のローカル端末でソースコード編集が行われず、開発サーバ内のソースコードをみんなで編集している
* 開発サーバが、開発者ローカル端末と __同サブネットに存在しない__。

##開発サーバが同サブネットに存在する場合は...

同サブネットに存在する場合は、そもそもxdebugの設定で解決する（はず）と思います。

[xdebug.remote_connect_back](http://xdebug.org/docs/all_settings#remote_connect_back)の設定がそれです。
remote_connect_backは、\$\_SERVER['REMOTE_ADDR']によってデバッグ待機中のマシンを確認します。
同サブネット内の場合はこれでOKなのですが、ルータを挟んだりすると\$\_SERVER['REMOTE_ADDR']はルータのIPアドレスになってしまうので、開発者端末のIPアドレスがわからず、開発サーバから開発者端末への接続ができないのです。

#実験環境

AWS上のPHPサーバを、自宅からインターネット越しにデバッグします。

![ex-env.png](https://qiita-image-store.s3.amazonaws.com/0/34165/f4a6576d-d0fb-c1ad-f362-ed0248e1f9da.png "ex-env.png")

##概要

xdebugが有効になっている場合、PHPの実行時には、xdebug.remote_hostで設定したIPのポート9000（デフォルト。xdebug.remote_portの設定を変更することで変更可能）へ接続してきます。

ですので、開発サーバが自身のローカルマシンである場合はxdebug.remote_hostにlocalhostを設定し、開発サーバとローカルマシンが１：１の関係である場合は、xdebug.remote_hostにローカルマシンのIPアドレスを指定します。

__しかし開発サーバに対し複数マシンがあり、かつ開発サーバとの間にルータなどを介す場合、開発サーバが接続しに行くremote_hostが見つからないという事態になります。このような場合の解決策です。__

まず、xdebug.remote_hostの設定はlocalhost、xdebug.remote_portの設定は9000にしておきます。
DBGpProxyは外部からの接続をポート9001ポートで待ち構えておき、ローカルホストのポート9000への接続をプロキシします。

端末Aでは、「cookieのXDEBUG_SESSIONがAcomputerだったら、自身への接続のポートは9002でお願いします」というふうにDBGpProxyへ登録し、さらにルータ側ではDBGpProxyから来たポート9002への接続を、端末Aのポート9002へフォワーディングすることで、道通する、という流れです。

端末Bの場合は、XDEBUG_SESSIONが端末B特有のものであることと、利用ポートが9003であることだけで、考え方は端末Aと同じです。


##開発サーバのセッティング

開発サーバ上でプロキシサーバを動かします。

AWS上の開発サーバにはGIPを付与し、自宅のGIPからのInBoundのTCP 9001番ポート（プロキシがListenするポート）を開けます。

### PHPなど

以下、導入します。

```shell
$ sudo yum update #最初のyum update
$ sudo yum install php httpd php-pecl-xdebug git

```


xdebugの設定をいじります。

```/etc/php.d/xdebug.ini

;下記記述を足します。
xdebug.remote_enable=1
xdebug.remote_autostart=1

```

リモートデバッグ対象のPHPのサンプルプロジェクトをgit cloneしてきます。

```shell
$ chmod 755 /home/ec2-user #きっと実行権限がないと思うので。
$ cd ~
$ git clone https://takudo@bitbucket.org/takudo/php-remote-dbg-test.git #ただのPHPスクリプト
```

中身はこんなのです。

```php:index.php

<?php

echo 'step1';

$array = array(
    1,
    2,
    3,
    4,
    5
);


foreach($array as $partial) {
    echo $partial;
}

echo 'step2';

echo 'step3';

```

apacheのドキュメントルート変更しておきます。

```/etc/httpd/conf/httpd.conf
DocumentRoot "/home/ec2-user/php-remote-dbg-test/" #変更
```

apacheを起動して、ブラウザで画面が表示されるか確認しましょう。

![php-remote-dbg-test.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/82dab183-95a6-a374-bec3-c8941755b3a5.jpeg "php-remote-dbg-test.jpg")


### プロキシサーバ

PHPサーバに、プロキシサーバを導入します。

pythonのdbgpモジュールが必要なので、いろいろ入れます。
[このへん](https://pypi.python.org/pypi/setuptools#unix-wget)を参考にしつつ、まずはsetuptoolsを

```
$ mkdir ~/src
$ cd ~/src
$ wget https://bootstrap.pypa.io/ez_setup.py
$ sudo python ez_setup.py
$ sudo easy_install pip
$ sudo pip install dbgp

```

プロキシサーバの最新のパッケージは↓を参考にしてください。
http://code.activestate.com/komodo/remotedebugging/


```shell

$ cd ~/src
$ wget http://downloads.activestate.com/Komodo/releases/8.5.3/remotedebugging/Komodo-PythonRemoteDebugging-8.5.3-83298-linux-x86_64.tar.gz
$ tar -xvzf Komodo-PythonRemoteDebugging-8.5.3-83298-linux-x86_64.tar.gz
$ cd Komodo-PythonRemoteDebugging-8.5.3-83298-linux-x86_64
$ 

```

プロキシサーバを起動します。

```shell 
$ ./pydbgpproxy -i 0.0.0.0:9001 -d 127.0.0.1:9000
INFO: dbgp.proxy: starting proxy listeners.  appid: 1632
INFO: dbgp.proxy:     dbgp listener on 127.0.0.1:9000
INFO: dbgp.proxy:     IDE listener on  0.0.0.0:9001
```


##ローカル環境・端末セッティング

### ローカルルータ

AWSの開発サーバ（プロキシサーバ）から、ローカル（自宅）環境への接続が行われるので、アクセス制限を解除しないといけません。
また、ローカルのルータにポートフォワーディングを設定することで、プロキシサーバからの接続を、ローカル端末A・端末Bに振り分けます。

ルータを何使っているかで設定の詳細はいろいろだと思うのですが、
設定しなければならないのは、下記です。

* 開発サーバのGIP（インターネット）からのローカルルータへの接続を許可する
* ローカルルータへの外部からの接続をポートフォワーディングする。
	* 例：
		* ローカルルータGIP:9002への接続を、端末AのローカルIP:9002へ転送
		* ローカルルータGIP:9003への接続を、端末BのローカルIP:9003へ転送

### IDE(IntelliJの場合)

※ローカル環境でも、開発サーバと共通のソースコードをgit cloneしておき、IntelliJでプロジェクトとして開いておいて下さい。

まずは端末Aを設定します（Bでも同様の手順で設定して下さい）

Tools > DBGp Proxy > Configuration を開いて、下記のように入力します。

![DBGp_Proxy.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/3d9ea96e-3cc6-1eff-ef56-1443a67230db.jpeg "DBGp_Proxy.jpg")

つぎに、端末Aで待ち受けるポートの設定です。
Preference > PHP > Debug で、下記のように入力して保存します。

![Preferences.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/6efcb7e9-2930-3141-1736-cc43f8f545ad.jpeg "Preferences.jpg")


DBGpProxyに、待ち受けるポートとIDE Keyの登録を行います。
Tools > DBGp Proxy > Register IDE で、↓のように表示されればOKです。

![index_php_-__php-remote-dbg-test__-_php-remote-dbg-test_-____Development_PHP_php-remote-dbg-test__-_IntelliJ_IDEA__Cardea__IU-135_1019.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/7d9cc7a9-0e6a-7135-5b9f-daf8053435a5.jpeg "index_php_-__php-remote-dbg-test__-_php-remote-dbg-test_-____Development_PHP_php-remote-dbg-test__-_IntelliJ_IDEA__Cardea__IU-135_1019.jpg")

DBGpProxyが開発サーバで立ち上がっていなかったり、端末Aから開発サーバ:9001への接続が許可されていなければ、接続失敗します。

また、DBGpProxyのコンソールでは、下記のように表示されるはずです。

```shell
INFO: dbgp.proxy: Server:onConnect ('ローカルルータのGIP', ***) [proxyinit -p 9002 -k Acomputer -m 1]
```

端末Bでも同様の手順で環境設定をして下さい。

（すみません、EclipseとかNetbeansとかでは試してないのですが、Eclipseなら[ここ](http://onlineconsultant.jp/pukiwiki/?Xdebug%E3%82%92%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B)、Netbeansなら[ここ](http://www.kuroienogu.net/archive/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AExdebug%E3%82%92%E9%96%8B%E7%99%BA%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%AEnetbeans%E3%81%A7%E3%81%84%E3%81%9F%E3%81%A0%E3%81%8F.html)とかを参考にするといいかもしれません。が、実際検証はしてないので、なんとも言えません）

__これで準備完了！__


#デバッグしてみる

##ブレークポイント

ブレークポイントを設定してみてください。

![index_php.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/821bd7d2-3f10-b6b1-1000-1da2b886d2fa.jpeg "index_php.jpg")

##デバッガ

次に、デバッガ起動します。

![index_php.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/af15277d-078e-e00b-4d3c-5a1bfcc487d8.jpeg "index_php.jpg")

↓のように緑になります。

![index_php.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/748e9423-69a1-5042-5b68-56ea7f915869.jpeg "index_php.jpg")

## cookie(XDEBUG_SESSION)の設定

Preference > PHP > Debug の bookmarkletsなんちゃらというリンクをクリックします

![Preferences.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/54f4d770-73bc-f7fc-f4a6-cdd2b5a21d47.jpeg "Preferences.jpg")

クリックすると、デフォルトブラウザでページが開くので、ブックマークレット登録を行います。

![Xdebug___Zend_Debugger_bookmarklets_generator_for_PhpStorm.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/841b40df-13dd-4f31-3120-d19aba20cab0.jpeg "Xdebug___Zend_Debugger_bookmarklets_generator_for_PhpStorm.jpg")

このブックマークレットは単に、「現在開いているドメインのトップパスに、XDEBUG_SESSIONのクッキーを登録するJavaScript」というだけです。

ブックマークレットを作成したら、端末Aのブラウザで、開発サーバに一度アクセスしてみます。
アクセスしたらブックマークレットをクリックして、cookie登録をします。
こんな感じでcookie登録されてればOKです。

![chrome_devtool.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/4bdacb18-8276-fced-d4d1-c5ead6947416.jpeg "chrome_devtool.jpg")


##ブレークポイントで止めてみる

では、もう一度端末Aで画面をリロードしてみましょう。
__出来ましたか？__

![index_php.jpg](https://qiita-image-store.s3.amazonaws.com/0/34165/7c242bfd-d023-6030-de28-22ac47c273bc.jpeg "index_php.jpg")

## 端末Aと端末Bが混同されてないか確認

端末Bでも同様にセットアップしておき、端末Bでも動作確認ができたら、
端末Aでのアクセスによって、端末Bで設定しているブレークポイントで止まったりしないことを確認しましょう。
またその逆も確認しましょう。

#所感

やりたい場面はそこそことあるのかなと思うのに、設定の大変さときたら。
やはり皆さんローカルマシン内で開発していることが多いでしょうから、あまり複数人デバッグの情報、それもDBGpProxyを利用した場合の情報がなかなか出てこず苦労しました。

今回の実験はインターネット越しに行いましたが、LAN内でルータを介す場合の場合でも応用がきくと思います。

ただ、社内の環境が開発サーバまでにルータを介すような場合って、そのルータのフォワーディング設定をしてもらえるかどうか、それが一番難易度が高いところかなと思いました。

以上。