作者:廖新喜

原文地址:PhpStorm Xdebug远程调试环境搭建原理分析及问题排查

网上关于 phpstorm 调试的文章很多,真实实践过的不多,都是几篇文章转来转去,没有原理分析,甚至有些文章的配置文件都是错的,我就是按照一篇错误的配置一路走过来的,不过好歹把这些坑都给埋了,这篇文章不仅仅有操作,还有原理分析,更有问题排查思路。

对于简单的工程,直接print_r();exit()已经足够,但是对于大型项目有时就有点力不从心,如果直接将 apache 部署在本地,phpstorm 调试本地代码这种方式也可以,我以前就是这么干的,这篇文章主要介绍远程调试系问题排除。

一. 环境介绍

本地:windows7(192.168..)+ phpstorm8

远程:Ubuntu14.04(192.168.3.206)+ apache2 + php5

二. 远程环境配置

2.2 Xdebug安装

Ubuntu下直接apt-get安装,安装命令如下:apt-get install php5-xdebug

2.3 配置

首先通过locate定位到 xdebug.ini,这个位置一定得对,在 Ubuntu 上位于/etc/php5/apache2/conf.d/20-xdebug.ini

zend_extension=xdebug.so  
xdebug.idekey=PHPSTORM  
xdebug.remote_connect_back = 1  
;//如果开启此,将忽略下面的 xdebug.remote_host 的参数

;xdebug.remote_host=192.168.x.x
; //注意这里是,客户端的ip<即IDE的机器的ip,不是你的web server>

xdebug.remote_enable=on  
xdebug.remote_port = 9001  
;//注意这里是,客户端的端口<即IDE的机器的ip,不是你的web server>

xdebug.remote_handler = dbgp  
xdebug.auto_trace = 1  
xdebug.remote_log = /tmp/xdebug.log  

三. 本地phpstorm配置

下面的配置有执行顺序要求,请一步一步来。

3.1 下载远程代码

phpstorm在新建项目的时候提供了选项,可以通过ftp/sftp远程下载代码,直接按照提示下一步下一步就可以。

3.2 添加php解释器

通过file->settings->Languages & Frameworks找到php栏。

3.3 配置Debug

路径还是在file->settings->Languages & Frameworks->PHP,选择Debug,选择要监听的端口,这里设置为9001,如图所示:

设置完端口还需要设置DBGp Proxy,配置如下:

在设置完Debug页面后,在DBGp Proxy页面的端口已经确定,添加上IDE key为刚才Xdebug配置文件设置的key:PHPSTORM,Host则为要调试的远程主机。

3.4 配置Server

通过file->settings->Languages Frameworks->PHP找到Servers,Host对应远程主机IP, Debugger 选用 Xdebug ,如果是远程调试,一定得开启路径映射功能,否则无法调试,本地的路径不用选,在新建远程项目的时候就已经确定,Absolute path on the server 则是远程主机的 Web 路径。在途中红框上方有一个 Validate remote environment 可以用来验证远程的 Xdebug 配置,如果配置明显不对的话,会有提示信息,可按照提示信息修改远程服务器的 Xdebug 配置。

3.5 配置调试选项

由于调试的目标是一个项目,所以这里需要设置PHP Web Application,配置中Server:远程目标主机,Start URL设为/,设置完之后会在左侧新建一个PHP Web Application

到目前为止,该配置的都已经配置完成,这里面配置的选项比较多,一步一步配置,有顺序要求。配置完之后就是调试。点击下图右边红框中的小按钮,打开 Xdebug 监听,再选择我们要调试的目标,这里是server,最后点击那个调试按钮,就能开启调试之旅。

打开 Xdebug 监听的时候,可以看到IDE已经在本地建立监听服务,具体如下:

可以看到调试页面。如下所示

3.6 浏览器添加书签或者Xdebug Helper

前面描述的是通过PHPStorm的 debug 按钮,发送类似?XDEBUG_SESSION_START=17212这种请求调起浏览器来达到调试的目的,但是这种方式只能调起首页,存在缺陷。下面介绍另外一种启动调试的方式,就是通过浏览器中带XDEBUG_SESSION 的cookie直接发起,可以安装Chrome插件Xdebug Helper或者添加浏览器的调试插件、或书签来达到目的。新建书签的url:https://www.jetbrains.com/phpstorm/marklets/ , 这里就不再做示例,插件和书签的原理都是一样的,都是在cookie中添加XDEBUG_SESSION=PHPSTORM。

四. 数据流程

前面的配置完全是一个操作指南,如果仅仅是为了配置,上面的内容已经足够,但是如果配置中遇到什么问题,就需要接下来的原理分析。古人说的好,我们得知其然还得知其所以然。

4.1 Xdebug工作原理
  1. IDE(如PhpStorm)已经集成了一个遵循BGDP的Xdebug插件,当开启它的时候, 会在本地开一个Xdebug调试服务,监听在调试器中所设置的端口上,默认是9000,这个服务就会监听所有到9000端口的链接。在PhpStorm中,位于:工具栏 > Run > Start / Stop Listening for PHP Xdebug Connetions。

  2. 当浏览器发送一个带 XDEBUG_SESSION_START 的参数的请求到服务器时,服务器接受后将其转到后端的php处理,如果php开启了xdebug模块,则会将debug信息转发到客户端IP的IDE的调试端口上。当参数或者cookie信息中不带 XDEBUG_SESSION_START ,则不会启动调试。这就为后续在浏览器中添加开关提供了可能。Xdebug的官方给出了一个示例图:很好的展示了相互调用关系。
    这个示例图是绑定了ip,即使用了固定ip地址,xdebug.remote_connect_back = 0 ,也是 Xdebug 的默认方式,这种情况下,Xdebug 在收到调试通知时会读取配置 xdebug.remotehost 和 xdebug.remote_port ,默认是 localhost:9000,然后向这个端口发送通知,这种方式只适合单一客户端开发调试。 另外一种方式则是不绑定IP,Xdebug根据请求来源(REMOTEHOST)来发起调试。示例图如下:

那从用户发起请求到,到IDE的整个流程图如下:

当用户的请求参数或者cookie中不带调试信息,数据流就是浏览器到Apache(或其他web容器)到PHP,如果加上了调试参数,则请求还会由PHP转给Xdebug处理,Xdebug再把信息转发给IDE,完成调试功能。

五. 问题分析

由于拷贝了错误的Xdebug参数,导致走了不少弯路,如果仅仅是为了配置PhpStorm及Xdebug原理,关注前面部分即可。下面主要分析排除过程。

错误的配置如下:

zend_extension=xdebug.so  
xdebug.idekey=PHPSTORM

#xdebug.remote_connect_back = 1 //如果开启此,将忽略下面的 xdebug.remote_host 的参数

xdebug.remote_host=192.168.x.x //注意这里是,客户端的ip<即IDE的机器的ip,不是你的web server>

xdebug.remote_enable=on  
xdebug.remote_port = 9001 //注意这里是,客户端的端口<即IDE的机器的ip,不是你的web server>

xdebug.remote_handler = dbgp  
xdebug.auto_trace = 1  
xdebug.collect_includes = 1  
xdebug.collect_params = 1  
;xdebug.collect_return = 1

xdebug.remote_autostart = 1

xdebug.remote_log = /tmp/xdebug.log  

问题现象: Apache反应奇慢无比,一个普通请求能耗时10分钟,但是最终会有效应。

排查过程:

5.1 问题背景

本地环境:Windows7,远程服务器:Ubuntu14.04,这个远程服务器是本地环境下VMWare WorkStation下的一台虚拟机,网络连接方式是桥接。在调试远程项目时,作者使用的sftp来管理服务器的资源,这里面就会涉及到权限的问题。远程服务器只开了一个普通账户liaoxinxi,而/var/www 目录以前是root权限的,由于PhpStorm调试时会在远程服务器web目录下创建一个文件,这必然会导致权限问题,为了解决这个问题,执行chmod liaoxinxi:liaoxinxi /var/www -R将web目录修改为liaoxinxi用户所有。当然为了远程调试,我配置了xdebug.ini,这个配置参数当时也不是太清楚具体含义,比较着急,就从某篇号称亲手测试过可用的Xdebug环境拷贝而来。下午比较混沌,当时做过的操作还挺多,Xdebug这个配置我居然忘记我配过了,只记得修改了权限相关内容。重启Apache之后,web请求响应奇慢无比。

5.2 疑问点

5.2.1 权限

当时一股脑的认为是权限的问题,就又把web目录权限全改为777,还是奇慢无比,查看apache日志也没有半点异常。

5.2.2 网络

无意之中发现在远程服务器上直接访问,很快就能得到响应。这个远程服务器是我VMware下的虚拟机,通过桥接模式与宿主机通信。中午与其他同事讨论这个问题的时候将问题排查点转移到网络环境。怀疑是网络的问题,将桥接模式改成NAT,又是重启虚拟机,重启宿主机,都不起作用。

5.2.3 Apache配置

于是又将矛盾转移到Apache的配置上,Apache的配置文件被我改动了很多回,当时觉得很简单所以没设置备份点,一个好的备份是多么重要。只能重装,这个在Ubuntu下还是很简单的,一条命令搞定apt-get auto-remove --purge apache2,并且删除了原有的配置文件。再通过apt-get重新安装,apt-get install apache2,重启apache后发现在本地访问,很快得到响应,不过响应的都是原始的php文件,再安装一下libapache2php模块,安装完之后,响应还是一样的奇慢无比。难道跟这个模块有关系,但是找不到相关资料。再翻看安装apache2的输出信息时发现其重启了Xdebug模块,回想一下,是不是这些模块导致的问题呢?再仔细想想,那天下午好像还改了Xdebug的配置,可能有问题。

5.2.4 Xdebug配置

回到Xdebug的配置文件,其中一个配置xdebug.remote_host=192.168.*.* //这个配置是用来,感觉峰回路转了,因为只有这个ip访问就会奇慢无比,于是注释掉,再重启apache访问,果然奇慢无比的问题解决了。

但是这又带来一个新的问题,这个ip是我的本地环境,如果不配置的话怎么调试呢?于是将//后边的内容用;注释起来,前期一直以为//也是个注释。//这种注释方式在Xdebug中不识别,所以根本不会向IDE所在机器发送调试包,会一直等到超时,所以就会特别慢。 再去调试,在index.php下断点,终于断下来了。调试的过程中发现,开启或者未开启调试参数都会直接进入调试模式,见了鬼了,回想起调试流程图,肯定出问题的地方在Xdebug的配置,打开配置文件,果然发现一个相关参数xdebug.remote_autostart = 1,这个参数的意思就是自动打开远程调试,注释掉就能接收不使用Xdebug调试的参数。

说到最后不得不佩服这位兄弟,挖了两个大大的坑(坑的位置),好歹我全埋了,提醒大家尽量找官方文档,如果官方文档写的不详细的,还是多见识见识几份文档。

综合来看,信息大爆炸的年代,干扰信息太多,各位见仁见智。


欢迎扫描以下二维码赞赏作者(微信)