乐趣区

Xdebug-远程调试你会用吗

前言

在开发过程中,我们最少不了的就是调试,因为 php 不能像 Java 和 C# 那样与生俱来的优势,拥有开箱即用的断点调试,很多时候我们的开发者都是使用的 var_dump 方法来对结果进行输出,而有的时候需要查看调用栈时,有的开发者甚至都不知道如和下手。(可以 throw 异常 或者 使用 debug_print_backtracedebug_backtrace 来打印调用栈),虽然很多开发者知道xdebug 但是也会因为其繁琐的安装望而却步,又或许你在本地高高兴兴搭建好了,有时候要调试一下外网的,比如测试服务器,你会发现这是个坑,很多文章都没有正确的引导你去如何的安装它。

服务器如何安装 Xdebug

环境准备

  • ubuntu 16.04
  • php 7+
  • XShell

首先打开 Xdebug 官网。

是不是看到硕大的 Download 链接吸引到了你,如果你知道你的 php 是什么版本 你可以在这里愉快的下载,然后并安装。

偶,我凑,怎么全是 Windows 的,Linux 的呢?Linux 当然是要从源码构建啦。

我凑,不会?没关系咱们一起来学一学,首先新建一个 php 文件,如果你是用包管理器安装的那么请直接跳转到包管理器

// info.php
<?php
phpinfo();

然后放到你的 web 目录,看清楚,一定是 web 目录。不要觉得你耍小聪明,使用 php -S 来启动一个临时的 web 服务器,不允许,因为你这样用到的 php.inicli 的,而不是 fpm 的,当 phpinfo 信息显示出来。

然后我们回到官网,点击下载页面的 custom installation instructions.

来到这个页面后看到一个输入框,但是什么意思呢?

duang,翻译一下。

这一下明白了吧,就是把 phpinfo 的完整输出 复制到这个框框里面,然后提交,这下我们回到 phpinfo 页面,Ctrl + A , Ctrl + C,一气呵成,过来粘贴提交。

是的,没错,每一步该干什么它全都告诉你了,你只需要根据上面提供的 Ctrl+Insert(复制),Shift + Insert (粘贴),执行就完事儿。

第 9 步 直接用 vim 打开 php.ini 在最后加入那一行即可。

现在,在命令行执行

php -m

看到最后面有 XDebug,别着急,这才成功了一半。
当然,到这里我还要告诉你一个不好的消息,哈哈。
如果你的 php 不是 手动编译 的,而是通过 包管理器 (apt),因为 ubuntu 16.04 默认的安装源 安装的是 7.0,没有更高级的版本,你需要用 PPA 源来下载最新的 php。当然,这里我们就不在讨论了。

包管理器

如果你是使用的 apt 或者 apt-get 安装的,那么你可以通过 apt search xdebug 命令来查找 apt 中有关 xdebug 的包。

你可能会看到这个东西,没错,直接复制名字执行。

apt install php-xdebug

然后这时候,你去执行 php -m 就会发现 Xdebug 已经安装好了。

宝塔面板

如果你是宝塔面板的用户,你可以在面板的软件管理,对你需要操作的 php 版本中可以找到有直接安装 xdebug 扩展的位置。

接下来

不管你是 包管理器 还是 手动编译 安装的,这里的内容都需要看了。

打开 fpm 的 php.ini ,如果你是 宝塔面板 用户,你可以在宝塔的在线编辑,也可以根据 phpinfo 中的 路径直接编辑,在 php.ini 最后面加入。

; 这个是节点名字 无所谓大小写
[XDebug]
; 允许远程 可以为 On 或者 1 都表示启用,Off 和 0 表示关闭关闭
xdebug.remote_enable = 1
; 远程主机的 IP 这里我们填写,固定的 127.0.0.1 
xdebug.remote_host = 127.0.0.1
; 调试连接端口 请记住这个端口,后续会用到。此配置项默认值为 9000,但是通常 9000 端口被 fpm 占据,故更换端口。; 另外,请在你服务器的控制面板和服务器防火墙中开放这个端口的进出站。; 如果你是宝塔面板用户 请放行此端口。xdebug.remote_port = 19000
; 接下来的值都是可选的,但是我推荐你使用
; 连接 IDE 的 Key,请记住他,可以自己自定义,主要用来过滤请求。xdebug.idekey=PHPSTORM
; 这个表示扩展的位置,如果你是编译安装的,那么这个值你应该在第九步已经设置好了,如果你是 使用 包管理器安装的,那么这个值应该是自动设置的,而且你不会在这个 php.ini 中找到他,但是此时你已经不用设置它了。; 如果你是宝塔的用户,你会发现在你编辑这个文件之前,宝塔已经帮你设置好了
; 另外,通常我建议你将路径使用引号包裹起来,因为当路径中有特殊字符或者空格时会出现问题

; zend_extension=php_xdebug.dll

好了,保存完成后,我们需要重启 fpm

service php7.0-fpm restart

因为我的 php 版本是 7.0 所以上面的命令是这样,如果你的不是,请根据实际情况来定。
如果你是宝塔面板的用户,请直接在面板操作。
如果你是自己编译的改了服务名字,不记得了,请执行

service --status-all

这将会打印出所有的服务(有可能会很慢),你可以在其中慢慢找。

当你准备好了之后,我们回到我们的开发端,打开 PHP Storm

客户端

使用 PHP Storm 打开你的项目。

看到右上角的调试面板,然后选择这个按钮,然后进去添加。

请根据图片提示

emm,过滤请求那个框一时找不到,就描述一下吧,当我们有开启多个 PHP Storm 窗口时,如果有一个以上的 窗口都启用的 Xdebug,那么,IDE 此时将会不知道该调用哪一个而发生矛盾,你可以在弹出的窗口中选择使用哪一个项目。

还有,当你通过 APP 请求时,你可能也不需要去过滤,故也不需要去勾选它,使用更加宽松的调试。

刚刚图上既然说到的了 mappings,但是我一般都不会去启用它,希望你也用不到。

不知道呢是否还记得,刚刚在修改 php.ini 时,我让你记住的那个 IDE Key,现在你可以用到它了。

接下来,我们还要去修改另外一个 配置,本地的调试端口。

按下 Ctrl+Alt+S 打开设置界面,或者在 左上角 File > Settings 并且定位到

Languages & Frameworks > PHP > Debug

当你设置好这个端口后,请记住它,接下来就会用到。

偶,好像最后一个标注错误,最后一个是,当在项目外时,在第一行断点。

这个才是在首行进行断点。

设置到这里,你是不是觉得应该 OK 了?当然,不是,是否记得刚刚在 准备工具 中提到的 Xshell 和 在 php.ini 中设置的 端口没有使用。

Xshell 设置

请确保在你的 Xshell 左侧的 会话管理器 中已经添加了你的服务器连接。

图片中虽然已经对大部分内容进行了模糊处理,毕竟是外网服务器,如有遗漏之处,也请不要对其进行恶意请求,谢谢。

点开属性,依次选择 连接 >SSH> 隧道 > 添加

请参考图片进行操作

如果隧道转发没有成功该怎么办?

  • 查看本地端口的使用是否正确。

打开命令行,执行如下命令,其中 9001 是在 PHP Storm 中设置的端口。

# 找到 PID
netstat -aon | findstr 9001
# 通过 PID 找到 是谁在使用。tasklist | findstr {PID}
# 结束进程 如果这端口被占用 可以使用如下命令结束,当然,我更加推荐你换个端口。taskkill /PID {PID}

如果本地正常,那么问题就应该在服务器。

在服务端执行如下命令,19000 为 服务器设置的端口。

lsof -i:19000

此时,如果隧道未连接,那么这个端口是不应该被占用的,反之则显示为一个 SSHD,如果不为空,那么就是端口被其他程序占用了,我建议你换个端口。

最后一线

当以上步骤都完成后,我们就可以来进行测试了吗?不是的,还有一步,代码同步,这是非常重要的一步。

代码同步

顾名思义,代码同步,需要你本地的代码和线上的代码一致。为了在调试时追踪跳转文件,避免因文件无法映射而导致无法同步。

一般情况下,我们都是使用 git 来进行代码托管,直接从 git 上拉取代码即可,这样就能确保我们的代码是同步的,现在我们就可以 happy 的进行调试代码了,但是当你直接访问你却发现,IDE 并没有拦截你的请求,是不是很尴尬。

启用调试

如图上所说,其实这种情况下我们也可以正常进行调试。

当我们直接访问,却发现 PHP Storm 并没有捕获到我们的请求这是为什么?

原因很简单,我们没有告诉 Xdebug 我们要关心这个请求,否则试想一下,有几个人同时请求你的网页,全部被 IDE 接收了,是不是疯了?

这时候,我们只需要在 URL 后面加上 XDEBUG_SESSION_START=233 首先,这个 XDEBUG_SESSION_START 是必须的,但是他的值是可以随便填写的。
此时 URL 变成了,参考文档

https://xxx.com?XDEBUG_SESSION_START=233

就可以正常捕获了。

如果你觉得手动添加,很麻烦,那你还可以安装一个 Chrome 插件。

Xdebug helper – Chrome 网上应用店

这个工具会自动帮你设置,只不过他是在 cookie 里面设置,依赖 cookie。

安装完成后,需要先配置,右键扩展栏的虫子图标,选择选项。

选择 PHP Storm,当然,别忘了旁边的 Save

常见问题

无法断点

  • 确认服务器端口在隧道连通后,是 SSHD 在使用那一个端口。
  • 确认服务器端口在防火墙以及服务器面板放行了端口。
  • 确认本地端口是被 phpstorm 所使用的。
  • 确认 XShell 隧道连接是成功状态。
  • 确认 PHP Storm 中的 电话 图标是绿色,并且正确配置了调试服务器。

本地无法跳转

这个主要是表现在 使用追踪时,突然就跳出了循环,明明下面还有断点,这是因为一些项目中使用了 自定义一些复杂的表达式来引入文件,导致没法映射导致,比如 微擎。这时候就需要单步骤调试,到出错的位置,Xdebug 的 Debugger 窗格会为我们提示。

手动添加映射

也可以直接在上级目录,为整个目录添加映射。

映射添加完成后,就可以以继续调试了

但是要注意路径对应否则会影响调试。

调试自动断开 nginx 返回 504

这是应为,你没有调整 PHP 和 FPM 以及 Nginx 的最大执行时间,修改到一个较大的值即可。

宝塔面板问题

宝塔面板的用户你会发现你网页端使用的 php 版本和 cli 的版本不一致,可以打开

网站 > PHP 命令行版本(就在添加网站那一排的最后一个按钮)

然后再进入

软件商店 > 对应的 php 版本 > 设置 > 安装扩展 > 选择 Xdebug

顺便还可以把超时这些也在这里修改了 解决上面的 504 问题。

当安装完 Xdebug 后,切换到 服务 然后选择「 重启 」一定是 重启 而不是 重载配置

然后点击下面的 > phpinfo > 查看 phpinfo。这时候你就能看到了,然后可以搜索 xdebug 验证是否安装成功。

接着 去修改 php.ini,配置我们方才 提到的

注意

  • 不能用于 Swoole
  • 不能用于 Workerman
  • 理论上类似框架都不能,不过实践出真理
  • 理论上只能同时一台物理机对应一台服务器进行调试,因为 xshell 隧道占用。当然 你可以多启动 fpm 使用不同的 php.ini 文件(理论可行)。

使用 Xdebug

图例:

  • 1、Debug 窗口 在启动 debug 时 该窗口会自动打开
  • 2、跳转到下一个断点
  • 3、暂停执行
  • 4、结束脚本执行
  • 5、查看所有断点
  • 6、屏蔽所有断点
  • 7、逐行执行代码
  • 8、进入方法或文件
  • 9、强制进入方法或文件
  • 10、跳出方法或文件
  • 10 和 11 中间,运行到光标所在行,如果期间有断点会优先执行断点
  • 11、执行表达式
  • 12、Debugger 窗体,可以查看执行的调用栈,查看 / 修改运行时环境,变量。
  • 13、Console 窗体,可以执行命令
  • 14、脚本结果窗体

这些都是有快捷键的,可以把鼠标放上去看,可以参考官方手册。

结束

曾经因为在远程调试走了很多弯路,至此就专门去研究这个,经过多次的实践和应用,稳定了次方案进行安装,故发出来,也希望对你有所帮助。

当你习惯了使用 Xdebug 调试,或许你以后都不再想用 var_dump 了。

参考资料

  • Xdebug: Documentation
  • PhpStorm_ReferenceCard.pdf
退出移动版