Visual Studio CodeでPHPをリモートデバッグ

PHPのデバッグはNetBeansを使っていたが、時代遅れになってきたのでVisual Studio Code(VSCode)でリモートデバッグ環境を構築した。


しかし、検索内容の通りにやってもうまくいかず、悪戦苦闘したので、なんとかリモートデバッグできるようになった方法を説明する。

このページでやりたいこと

PHPのデバッグといっても、大きく分けて2つのデバッグ方法がある。

ローカルデバッグ

リモートデバッグ

  1. ローカルデバッグ
    (WEBサーバ・PHPがインストールされたPCでPHPプログラムの実行デバッグを行う)
  2. リモートデバッグ
    (WEBサーバ・PHPがインストールされたPCとは違う、ネットワークで接続された他のPCからPHPプログラムの実行デバッグを行う)

今回は2.の方法の解説を行う。1.の方法は他の技術系サイトでやり方がごまんと紹介されているので、そちらを参照いただきたい。

リモートデバッグの準備手順

サーバ構成

サーバの構成は以下を前提にしている。

OSUbuntu 20.04.1
WebサーバApache 2.4.41
PHPPHP Version 7.4.3
Zend XdebugVersion 2.9.2

php.ini

Xdebugの設定は以下の通り

zend_extension=xdebug.so

xdebug.remote_enable = On
xdebug.remote_autostart = On
xdebug.remote_port = 9000
xdebug.remote_host = localhost
xdebug.remote_log = /var/log/xdebug.log
xdebug.remote_log_level = 5

ログ出力先やログレベルは適宜設定する。特にログレベルに7以上を設定すると膨大なログの記録が行われる。デバッガ不具合の原因調査以外では7以上は推奨しない。

ログレベルは以下表の通り

LevelNameExample
1ErrorsConnection errors
3WarningsConnection warnings
5CommunicationProtocol messages
7Information Information while connecting
10DebugBreakpoint resolving information

上記表は以下より引用

https://2.xdebug.org/docs/all_settings

Ubuntu20.04では、設定ファイルは

/etc/php/7.4/apache2/conf.d/20-xdebug.ini

に格納されている。

ユーザPC構成

ユーザPCの構成は以下を前提にしている。

OSWindows10
Visual Studio Code1.63.2
PuTTY (PuTTY-ranvis)0.76-ranvis2

Visual Studio Codeの設定

VSCodeの拡張機能は以下を入れている
(特に関係すると思われるものだけ)

PHP Debugv1.22.0
Japanese Language Pack for Visual Studio Codev1.63.3

VSCodeはとても多機能で拡張可能なため、おそらくPuTTYを使わなくてもTCPトンネリングできると思うが・・・その方法が判明したらこの記事はUpdateしよう。

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "pathMappings": {
                "/var/www/htdocs/phptest": "${workspaceRoot}"
            }
        }
    ]
}

launch.jsonはこの設定にしている。設定のポイントはpathMappingsの項目で、デフォルトのlaunch.jsonではそもそもパラメータが存在していないので追加する。
ここは、
”サーバ側のデバッグ対象フォルダ”:”VSCodeで開いているフォルダ”
の関係性にする必要がある。
あとは、Xdebugの通信ポートを合わせて保存する。

このとき、ユーザPCとサーバのPHPの内容が同じでないとデバッグはできないため、バックグラウンドでSFTPなどでファイルを同期化しておく。今回はサーバのSambaでWeb公開フォルダを共有フォルダにし、それをユーザPCからVSCodeで開いてデバッグを行った。

PuTTYでTCPトンネリング

このままでは、サーバで接続待受しているXdebugのデバッガへ接続できないため、サーバとユーザPCのデータを橋渡しするためTCPトンネリングを行う。これはSSHに備わるトンネリング機能を使って実現する。

サーバはXdebugがポート9000で接続待受しているため、ユーザPCのポート9000をTCPトンネリングで転送する。その為、PuTTYは以下の設定にする。

これによりPuTTYを接続開始するとポート9000のデバッグ通信がサーバに伝達され、PHPのデバッグが可能になる。

「開く」をクリックしするとサーバへログインするので、ユーザ名、パスワードを入力する。

リモートデバッグの実施

デバッグの対象

今回のデバッグサンプルはPHPを使用した簡易アクセスカウンタとする。ページ読み込みの度に、前回カウント数+1を求めWebページに描画する。

HTMLはindex.phpに、アクセスカウント機能はcounter.phpに記述している。

<!DOCTYPE html>
<html lang="ja">

<head>
    <title>php test page</title>
</head>

<body>
    access counter=<?php include('counter.php'); ?>
</body>

</html>
<?php
$counter_file = 'counter.txt';

$fp = fopen($counter_file, 'c+');

if ($fp) {
    if (flock($fp, LOCK_EX)) {

        $counter = intval(fgets($fp));//前回カウント値を取得
        $counter++;
        $counter = intval($counter);//桁あふれ対応
        if ($counter < 0) {//インクリメントして負数になってたら桁あふれ
            $counter = 0;//ゼロクリアする
        }

        ftruncate($fp, 0);//一旦ファイル内容クリア
        rewind($fp);//ファイルポインタを先頭に移動

        if (fwrite($fp,  $counter) === FALSE) {//カウント値を保存
            print('カウントUpdate失敗');
        }
        flock($fp, LOCK_UN);
    }
}
fclose($fp);
print($counter);//カウント値を返す

デバッグ対象のファイル・フォルダ構成

/var/www/htdocs/phptest がデバッグ対象となっている。
VSCodeでもphptestフォルダを指定し開いておく。

counter.txtはアクセス数を保存している。数値が書かれたテキストファイルである。初めはなくても自動生成する。

デバッグの開始

VSCdode左にあるバーのボタン「実行とデバッグ」をクリックする。
launch.jsonに設定した実行環境名が表示されているので、その左の緑三角ボタンをクリックする。

ブレークポイントの設定

counter.phpの9行目にブレークポイントを設定し、ファイルから読み込んだ数値を確認してみようと思う。
9行目の行番号の左をクリックすると赤丸がつく。

実行指示

VSCodeの中央上部に以下のようなツールバーが出現している。簡単に使い方を説明すると、

  1. (ブレークポイントに来た時)次のブレークポイントまでプログラム実行
    (ブレークポイントに来ていないとき)プログラム実行の一時停止
  2. 関数やメソッドを実行して一時停止 ステップオーバー
  3. 1行プログラムを実行して一時停止 ステップイン
  4. (関数やメソッドの内部を実行しているとき)関数やメソッドをすべて実行してから一時停止 ステップアウト
  5. デバッガの再起動
  6. デバッガの停止

Webブラウザで閲覧

ここまでの状態で、index.phpをWebブラウザを通して閲覧すると、9行目のブレークポイントでプログラム実行が一時停止するはず。

このとき、ブラウザはデータ読み込み中になって表示はされない。これはプログラムデバッグ中でブラウザの応答が待たされているためである。

この時、$counterにマウスカーソルを合わせて2秒ほど待つと、この変数の中身が表示される。
この時は$counterには値が読み込まれる前なのでnuinitializedとなる。ここでステップオーバーを押すと10行目でブレークする。再度$counterにマウスカーソルを合わせ待つと、counter.txtから読みだした数値がこの変数に格納されているはずである。

ステップインやステップオーバーを駆使して動作を確認すると、思いもよらない記述ミスや動作不具合も発見できるはず。
echoやprintでブラウザに変数を書き出しては確認、などといった非効率的なデバッグ作業から解放される。

デバッグ時の注意

デバッグ終了時、VSCodeのデバッガ停止ボタンを押してサーバのデバッガと接続を切断するが、そのままにしておくとWebページのレスポンスが非常に悪くなる。これはデバッグポート9000にデバッグ指示が来ないか、Xdebugが待機してしまうため。
これを防止するためには、デバッグ終了時にPuTTYも切断してしまう。こうすることで Webページのレスポンス は通常通りとなる。


コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください