xdebug3相对于2,配置方式修改了很多,在配置的时候会给出相应提示。本文使用较大篇幅分析xdebug的调试原理,以及简单的调试。针对结合PHPSTROM进行php调试也有简单涉及。
xdebug3常用配置迁移
开启方式,不再是0,1的简单设置,而是使用mode来指定xdebug处于什么模式。方便于xdebug只是加载实际需要的特性。
xdebug.mode=debug # 开启Step Debugging # 其他值off 关闭,develop 开启开发辅助,coverage 开启代码覆盖率分析,gcstats 开启垃圾收集状态统计, profile 开启分析,trace 开启函数追踪特性。 # 可以使用 xdebug_info() 查看配置
激活命令行调试
export XDEBUG_CONFIG=idekey=yourname
替换为export XDEBUG_SESSION=xdebug_is_great
自动开启调试
xdebug.remote_autostart
替换为xdebug.start_with_request
调试端口默认不再是9000,而是9003(更合理,9000往往会和fpm冲突)
调试原理
- IDE集成遵循BGDP的xdebug插件,监听9000端口,监听服务端发过来的debug信息
- 浏览器发送带了XDEBUG_SESSION_START参数
- 后端php收到该请求(开启xdebug),xdebug向来源客户端9000端口发送debug请求
- 客户端相应这个请求,debug就建立了
- 后端php已经准备好后,一行行执行代码,每执行一行,就交给xdebug处理一下
- xdebug处理过程,会暂停代码执行,向客户端发送代码的执行情况,等待客户端的操作
上文提到的客户端、IDE,这些指代监听9000端口这一方。而后端、服务端是指php,真正执行代码一方。 现实场景有可能是:客户端(浏览器)发起http请求,nginx接受http请求,转发给fpm(服务端),执行PHP代码。
代码分析
演示代码
<?php
echo 'Hello world'; // 1
$a = 20; // 2
$b = 40; // 3
$c = $a + $b; // 4
echo $c.''; // 5
echo 'Hello world'; // 6
方便后面分析,后面注释代表行号。
简单检测
按照调试原理,可以看出,当开启了
xdebug.mode=debug
xdebug.start_with_request
执行php代码php index.php
, 执行方即php
, 会发送9003的请求给客户端。客户端如果依赖于ide(如phpstorm),开启右上角监听按钮即可。为了分析具体情况,可以用nc
模拟监听9003端口
nc -lv 127.0.0.1 9003
# 可以参考引用中的链接,了解nc命令
这个时候在nc命令行界面便可以看到打印的init信息
<?xml version="1.0" encoding="iso-8859-1"?>\n<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///Users/jerry/Desktop/work/phptest/index.php" language="PHP" xdebug:language_version="7.4.16" protocol_version="1.0" appid="29040"><engine version="3.0.3"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2021 by Derick Rethans]]></copyright></init>
如果想检测具体的网络协议:
tcpdump -i eth1 -nn -A port 9003
或者wireshark
tcp.port==9003 && tcp.flags.push == 1
交互测试
import base64
import binascii
import re
import socket
ip_port = ('0.0.0.0', 9003)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(10)
conn, addr = sk.accept()
while True:
client_data = b''
data_len = 0
data = b''
while True:
client_data = conn.recv(1024)
if not client_data:
break
client_data_arr = client_data.split(b'\x00')
# 开始处为内容的长度
if not data_len:
data_len = client_data_arr[0]
data += client_data_arr[1]
else:
data += client_data_arr[0]
# 最后面是以\x00结尾
if client_data_arr[len(client_data_arr) - 1] == b'':
break
print("[+] Raw Result: %s" % data)
g = re.search(rb'<\!\[CDATA\[([a-z0-9=\./\+]+)\]\]>', data, re.I)
if g:
data = g.group(1)
try:
print('[+] Result: %s' % base64.b64decode(data).decode())
except binascii.Error:
print('[-] May be not string result...')
else:
print('[-] No result...')
data = input('>> ')
# conn.sendall('eval -i 1 -- %s\x00' % data.encode('base64'))
conn.sendall(data.encode('utf-8') + b'\x00')
程序简单解释:
- 监听9003端口(如果其他配置的是其他端口,自行修改程序)
'\x00'
协议以该字节结尾,循环判断内容是否读取完毕- 正则提取xml里的data数据
- 使用base64解码内容
- 等待用户输入
- 发送给服务端命令
- 循环以上过程
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///Users/jerry/Desktop/work/phptest/index.php" language="PHP" xdebug:language_version="7.4.16" protocol_version="1.0" appid="27099"><engine version="3.0.3"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2021 by Derick Rethans]]></copyright></init>'
[-] May be not string result...
>> breakpoint_set -i 1 -t line -f index.php -n 3
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="1" id="270990001"></response>'
[-] No result...
>> breakpoint_get -i 1 -d 270990001
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_get" transaction_id="1"><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3" state="enabled" hit_count="0" hit_value="0" id="270990001"></breakpoint></response>'
[-] No result...
>> breakpoint_list -i 1
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="1"><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3" state="enabled" hit_count="0" hit_value="0" id="270990001"></breakpoint></response>'
[-] No result...
>> breakpoint_set -i 1 -t line -f index.php -n 11
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="1" id="270990002"></response>'
[-] No result...
>> breakpoint_list -i 1
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="1"><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3" state="enabled" hit_count="0" hit_value="0" id="270990001"></breakpoint><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="11" state="enabled" hit_count="0" hit_value="0" id="270990002"></breakpoint></response>'
[-] No result...
>> run -i 1
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="run" transaction_id="1" status="break" reason="ok"><xdebug:message filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3"></xdebug:message></response>'
以上内容为简单演示了程序,分别测试了:设置断点、获取某个断点、列出所有断点、运行。其他演示操作可以参考引用中的文档。
总结
通过程序模拟了dbgp的过程,如果感兴趣还可以通过程序发送system('ls')
的命令,感受dbgp协议的流程。关于IDE的配置,主要是在配置里找到xdebug调试端口,在这里对应php配置中的xdebug.client_port。如果修改了,重启一下ide即可。根据是否开启自动调试配置,进行不同方式的触发即可。
更详细的配置,网络上很多,本文主要在于原理分析。
引用
https://xdebug.org/docs/upgrade_guide
https://www.secpulse.com/archives/115172.html
https://wsgzao.github.io/post/nc/ nc命令
https://xdebug.org/docs/dbgp dbgp协议