记一次PHPStorm Xdebug Docker PHP 调试问题

记一次PHPStorm Xdebug Docker PHP 调试问题

背景

在这之前一直在用 Virtual Box 上的 Ubuntu v16.04.4 虚拟机在做测试环境,随着项目增加,12G硬盘大小的虚拟机会经常报磁盘已满,不断的删日志才能维持工作。于是我就想着再开一台虚拟机,硬盘设置个20G,(还是这么小气)。用的 ubuntu1 v16.04.10,(为啥不上ubuntu18,这个虚拟机软件太老装新系统,发现有性能问题,估计有指令不兼容问题)

我的是Mac环境,(之前也用过Windows)Virtual Box(后简称vbox),装好Ubuntu后,配置NAT网络,就开始装Docker软件,安装步骤是严格按照官网的步骤来的。
https://docs.docker.com/v17.09/engine/installation/linux/docker-ce/ubuntu/#install-using-the-repository

好吧,我承认我的环境有点非主流。这是有历史原因的。

开始造

安装好vbox、ocker,配置好Docker mirror,就开始用docker-compose 拉起测试环境。

Docker Remote API

开始在PHPStorm配置第二台Docker。这里遇到了很多次connection refused。我参考这为老哥的方法一,配置怎么都不生效。换第二个方案就好了。这是第一个坑。

将ubuntu那的 docker Daemon API 端口映射到Vbox nat网络上,我就不细讲了

得到Connection Successful的结果后。开始进行下一步。

PHPStorm php 运行环境

开始配置 PHP :: CLI Interpreter.

选择远程 Docker, Server 选择我们刚刚配置好的 server,在选择我们要调试的 php容器,(这个容器是在 php:7.1.21-cli-jessie 基础上构建的)。

然后就遇到这个问题:

 failed to parse validation script output

phpstorm_helper

当时出问题,没截图,这是网上找了个报错信息一样的图

通过搜索发现需要一个phpstorm_helper docker镜像。

于是在另外一台Ubuntu虚拟机上 docker save, 再到现在Ubuntu 上 docker import 搞定。

再点击刷新还是 failed to parse validation script output
然后,就又是在百度,谷歌,必应~~~
~~~

PHPStorm<->Docker 抓包

还是无果,去洗了下脸,想起网上有人用抓包定位这个问题。我这本地的PHPStorem和vbox里面的Docker Daemon通信就是用的tcp啊。

打开Wireshark,抓包。

通过抓包发现,PHPStorem 与 Docker 之间的请求就是:1.获取当前所有镜像,2.基于你选择的PHP镜像,来创建一个容器。3.运行容器,4.获取容器输出,5.删除容器。根据那一行红色的报错信息,我估计是在运行容器时,输出的内容不是phpstorm预期的,导致报错。由于最后一个操作是删除容器,我就不好调查这个创建的容器到底咋回事了。

于是就抓包,并模拟请求,在删除命令前止住。这样来调查这个创建的容器。

创建容器请求

转换为curl命令:

$ curl -X POST --header "Content-Type:application/json" http://127.0.0.1:52376/v1.24/containers/create -d '{"AttachStdin":true,"OpenStdin":true,"Env":["JETBRAINS_REMOTE_RUN=1"],"Cmd":["-dxdebug.remote_enable=0","/opt/.phpstorm_helpers/phpinfo.php"],"Entrypoint":["php"],"Image":"sha256:292111a5a867f13da8759d3388908b376cf455ecaece86785ea97e9b46f5255f","Volumes":{},"ExposedPorts":{},"HostConfig":{"Binds":["/Users/paulxu/Jumei/compose/portia/php/phpspider:/opt/project:rw"],"Links":[],"LogConfig":{"Type":null,"Config":null},"VolumesFrom":["abeb0f2ead37c672b838726ff9bef51bb1011235c8712dc687f7b7135610cbb2:rw"]}}'

这里的image的id是,作为PHP脚本运行的镜像的ID。

接触容器

对应curl命令:

$ curl -X POST --header "Content-Type:application/json" http://127.0.0.1:52376/v1.24/containers/f434099c2157c1a0cabea5131d9c2a5b8d809cc1e1289abcffb95eb7cf7fc4d0/attach?stdin=true&stdout=true&stderr=true&stream=true

这里的容器ID是上一个创建容器请求的返回值。

开始运行容器

curl 命令:

$ curl -X POST --header "Content-Type:application/json" http://127.0.0.1:52376/v1.24/containers/f434099c2157c1a0cabea5131d9c2a5b8d809cc1e1289abcffb95eb7cf7fc4d0/start

获取输出内容

转换为Curl命令:
curl -X POST –header “Content-Type:application/json” http://127.0.0.1:52376/v1.24/containers/f434099c2157c1a0cabea5131d9c2a5b8d809cc1e1289abcffb95eb7cf7fc4d0/wait

  • 我去看了下老环境的输出如下:

通过docker ps -a,找到通过api创建的容器

检查容器的日志

如下是新环境容器的报错信息:

Could not open input file: /opt/.phpstorm_helpers/phpinfo.php

我在打包的时候,记得是没有往镜像里打包这个文件的。通过查阅刚刚抓包的API参数,发现他有把一个容器作为磁盘挂载在这个新容器上。

来通过docker inspect [container ID] 检查两个容器有何不同。

如下是有问题的镜像

如下是正常的容器。

通过对比,我估计PHP容器所挂载的磁盘容器有问题。

检查容器磁盘

接下来我又细致检查了两个作为磁盘的容器。

如下是有问题的容器。

如下是正常的容器。

这两个作为磁盘的容器都是基于 phpstorm_helpers:PS-181.5281.35镜像构建的。都是基于同一个容器构建的会有什么问题呢?

接下来我检查了下 IMAGE ID,不一样。怎么会不一样呢。我查了下我的命令命令历史记录, docker savedocker import

结案

哦,这, saveloadexportimport。 我命令搞混了。在新环境删除了错误的镜像。重新让PHPStorm检查下就好了。

附上成功图:

PHPStorm Xdebug 断点调试 Docker 环境下 PHP教程

最详细的保姆级别的Dcoker环境想配置PHPStorm Xdebug 断点调试教程,图文并茂

为什么

PHP程序报错,肉眼review了多少遍都觉得自己的写得没问题;有个switch代码分支判断,为什么进不了我想要的case; 调试PHP代码还在用 var_dump($re); die();。试试Xdebug断点调试吧。

他能做什么

开启Debug监听,一步步顺着代码走进程序的最深处。你会了解到真实的代码运行步骤,以及调用关系。你还能知道每个变量在程序运行时,值的多少,以及变化。同时避免了 var_dump 代码植入,(如果忘了删除,提交到线上,那这个耻辱柱会狠狠地钉在你身上)

好的来介绍下我们的这期主角 Xdebug

Xdebug 是

Xdebug是一个PHP扩展,提供了调试和性能分析功能。[1]它使用DBGp调试协议。

Xdebug可以提供的调试信息包括以下内容:

  • 错误消息[2]中的堆栈和函数跟踪具有:

  • 用户定义功能的全参数显示

  • 函数名称,文件名和行指示
  • 支持成员功能

  • 内存分配

  • 保护无限递归

Xdebug还提供:

  • PHP脚本的概要分析信息[3]
  • 代码覆盖率分析
  • 调试器前端交互地调试脚本的功能。[4]

以上摘自wiki

开始动手

环境介绍

这篇文章主要围绕Docker环境下PHP的Xdebug调试展开。

先说下笔者演示环境:Mac环境,安装Virtual Box,跑了一个Ubuntu虚拟机,再装了Docker ce软件。看到这,大伙儿先别急着关网页啊,我的环境估计有些奇葩,但大致流程是差不多的。

这套PHP Docker环境这篇文章有详细介绍: [Docker快速搭建一套PHP、Nginx、MySQL、Redis、Xdebug、Memcached 开发环境

安装软件

为 PHP 安装 Xdebug

Xdebug 官方文档已介绍。

  • Linux 或 Mac 环境通过命令行:
$ pecl install xdebug
  • Windows 用户通过 Xdebug Download 页面,根据自己的PHP版本可直接下载 *.dll 放入到拓展目录即可。
$ php -v    // 查看 PHP 版本
  • 手动编译安装

对于网络不那么畅通,pecl不能用时。

## 获取源码
$ git clone https://github.com/xdebug/xdebug.git
## 进入目录
$ cd xdebug
## php检查
$ phpize
## 编译前配置,一般来说 phpize 已经准备好了大部分工作,以及配置
$ ./configure
## 编译
$ make
## 测试并安装
$ make test && make install
  • Docker 环境为PHP安装PHP拓展

Docker 环境下提供了两种方式,第一种是通过pecl在线下载安装,受限于网络状况,大概了下会失败。

那么可以尝试通过其他途径下载好pecl-Xdebug的压缩包,Add到docker容器中安装。

FROM php:7.3-fpm-buster

...

# 方法1 pecl 安装
RUN yes | pecl install xdebug \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_autostart=off" >> /usr/local/etc/php/conf.d/xdebug.ini

## ------------------------------------------------
# 方法2 下载安装 xdebug
ADD ./xdebug-2.6.1.tgz /tmp/php7-xdebug
RUN cd /tmp/php7-xdebug/xdebug-2.6.1/ && phpize && ./configure && \
    make && make install

配置 xdebug

找到我们的配置文件.

## 文件: /etc/php/conf.d/xdebug.ini

zend_extension=xdebug.so            // 启用xdebug拓展!

xdebug.remote_connect_back=1
xdebug.remote_enable = 1            // 启用远程调试
xdebug.remote_mode = "req"
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "10.0.2.2"     // 这是你PHPStorm运行环境的IP地址
xdebug.remote_port = 9000           // 默认9000,最好别动
xdebug.idekey="PHPSTORM"            // PHPStormIDE用的默认值
xdebug.remote_autostart = 1

关于这个 xdebug.remote_host 这个ip,不是想当然就填个 127.0.0.1, 你要看看你PHPStorm所运行的环境,和PHP运行环境是否在一个环境,如果是,你填 127.0.0.1 是没问题。是Docker那么就肯定不在一个环境了,怎么看我们IDE所处环境的IP呢,先编辑下入口文件 index.php, 获取SERVER变量的 REMOTE_ADDR 属性。

## 文件: ~/public/index.php
<?php
print_r($_SERVER['REMOTE_ADDR']);die();

打开浏览器访问下php-fpm服务。这里是多少,xdebug.remote_host 就填多少。

配置 Docker

Docker环境下,要用IDE去debug代码,IDE还需要和Docker打交道。就是在PHPStorm配置好Dcoker的API入口。

这个大家可以参考这片文章 Docker开启Remote API 访问 2375端口 来配置下Docker环境。

转载注明出处

配置 phpstorm

以上准备好了后,就开始我们的重头戏,配置PHPStorm.

1.将Docker Remote API配置在PHPStorm上.

由于我的环境装了Vbox,用了NAT,所以端口是42376,你要自己的环境配置为准。

下面的 Connection Successful 就表示配置成功了。这里的 Name: 名字要记下来,后面要用。

2.新增PHP Cli Interpreter.

搜索: php language,点击最右侧 ··· 按钮

选择 From Dcoker...

这里的 Server: 名字选择 第 1 步 的 Dcoker Server 的名字。 Image name: 选择你的php容器。

点击确认后,PHPStorm会检查 PHP容器的版本,Xdebug拓展是否启用。有如下提示,没有报错,则表示环境无误,可进行下一步。

留意下红框里面的 PHP version:

这里就是配置好之后的展示效果,PHP language level: 最好和 PHP 容器内一致.

3.配置 Deployment

这个配置是用来让IDE知道PHP代码运行环境,以及本地PHP代码之间的目录映射关系。

这里选择 Local or mounted flolder,首先会让你输入 New server name:

我输入的是 bs。你也可以输入别的,但都要记录下来,后面会用到这个名字。

这里Folder:配置PHPStorm运行环境的文件路径。(也就是Mac下文件路径。)

这里我们查看下 PHP 容器内代码路径.

切到 Deployemnt 配置的 Mapping Tab,在 Deploment path: 填上容器内代码路径, Local path: 选择本地环境代码路径。

4.配置PHP > Server, 这里点击圆圈内的 导入 按钮。在弹框中选择刚刚新增的 Deployment 配置。(就是刚刚输入的 New server name

File/Direcotry 你检查下,一般都没问题。Absolute path on the server 是你代码运行的Docker容器内的根目录。调整好之后,点击 OK.

先别急,关闭弹框后,再确认下 Absolute path on the server

这里估计是 PHPStorm 的一个Bug 还是产品的需求,弹框里外都要配置一次才好。

好PHPStorm的配置就完成了。

Docker runtime 配置

别急

Docker 运行时容器内,还需配置两个环境变量 PHP_IDE_CONFIG, XDEBUG_CONFIG.

  1. serverNameDeployment 配置的名字。

  2. remote_host 填PHPStorm环境的IP,也就是PHP中 $_SERVER['REMOTE_ADDR'] 的值。

  3. remote_port 默认 900.

  • 需要对 docker-compose.yaml 配置文件中的 php 容器新增环境变量:
## 文件: ~/docker-compose.yaml

version: "2"
services:
    php:
        image: paulxu/php:5.6-fpm-jessis-pdo-xdebug-mysqli-gd-mb-zip-2
        volumes:
            ...
        ports:
            ...
        environment: 
            PHP_IDE_CONFIG: "serverName=bs"
            XDEBUG_CONFIG: "remote_host=10.0.2.2 remote_port=9000"
  • 如果你用的 docker run 拉起的容器,加上如下参数
$ docker run ... --env PHP_IDE_CONFIG="serverName=dealman" --env PHP_IDE_CONFIG="serverName=bs" ... php /bin/bash

开始Debug

1.启用Xdebug listening,点击以下红色电话。

现在就是开始侦听状态。

2.找到入口文件 ~/index.php,选择第一行代码,打一个断点,(不知道点哪,按Commond+F8)

3.开始访问Web站点。

这里第一个断点是红色箭头处,通过点击绿色按钮 Step over,代码一步步执行到了蓝色箭头处,这行代码也被IDE蓝色高亮标底,此时还能从 Variables 看到 已定义变量 $conf 的值。

结语

以前的大佬还在炫耀用notepad手撕代码,一遍过。在越来越快的开发节奏中,使用高级的工具,以及详尽的仪表盘来开发调试代码。希望大家看了,都能配置成功。

有问题欢迎提问。

参考

vscode用xdebug调试php多进程程序
Mac下基于Docker在PhpStorm中配置Xdebug
使用 Xdebug 在 PHPStorm 中调试 PHP 程序(框架/原生均适用)