木匣子

Web/Game/Programming/Life etc.

MAMP 与 PhpStorm 远程调试

最近接手了一个用 PHP 作后端项目。本来团队里一直都是使用 Vagrant 来统一开发环境的,但是这个项目可能比较老,所以没有整合虚拟机。于是需要手动配置开发环境。配置中途遇到了一点问题,需要断点调试程序,方便追踪错误。本文相关运行环境:

Windows 10
MAMP for windows 3.3.1
Apache 2.2.31
PHP 5.3.23

MAMP for Windows

之前在 Mac 机上一直用 MAMP,相对于 WAMP 或者 XAMPP 比较熟悉前者。于是就在 Windows 上安装了 MAMP for windows,一样还是开箱即用的畅快。

Apache

Apache 的主配置文件位于 MAMP/conf/apache/httpd.conf,里面最重要的一行是端口配置:

Listen 80

这一行由 MAMP 主程序中的端口设置决定,随着用户选用的端口会变更。之所以这一行重要是因为,当你使用了 1024 以内的端口,需要系统管理员权限才能正常启动服务。在 Windows 上可以直接以管理员权限运行 MAMP 来解决。在 macOS 中,如果主端口在 1024 以内启动服务会自动请求管理员权限。

如果你将虚拟主机配置在其它文件,可以在主配置文件中用 Include 指令将其引入。但是要注意路径问题:1)如果用相对路径,则是以 apache 的主目录为起点,即 MAMP/bin/apache 而不是以上面提到主配置文件;2)可以用绝对路径;3)路径使用 forword slash / 而不是 backword slash \ 作为分隔,因为后者通常作为转义符使用:

Include conf/apache/extra/httpd-vhosts.conf
# or
Include G:/MAMP/bin/apache/conf/extra/httpd-vhosts.conf

如果遇到服务器无法启动,除了查看错误日志外,还可以用 httpd -t 检查一下配置文件是否有语法错误,并使用 -f 指定主配置文件:

G:\MAMP\bin\apache\bin>httpd -f ..\..\conf\apache\httpd.conf -t
Syntax OK

PHP

为了实现在 PhpStorm 中调试项目,需要在 MAMP 中启用 xdebug 扩展。首先要确定 MAMP 使用的 php.ini ,一般来说 MAMP 会使用 MAMP/conf/* 下面的配置,但是发现在不同的版本的操作系统上,会有变化。所以比较稳妥的方法是从 <?php phpinfo(); 指令运行的结果中查看当前使用的配置文件的路径。在 MAMP 自带的 phpinfo 页面可以找到一行信息:

Loaded Configuration File	G:\MAMP\conf\php5.3.23\php.ini

MAMP 带有多个版本的 PHP,但是免费版的主程序只会显示 MAMP/bin/php/* 下面版本号最大的两个。所以如果要用到比较老的版本,可以将高版本的文件夹重命名,在最前面加上 _ 例如 _php7.1.5 使其失效。

这些 PHP 一般都带有编译好的 xdebug 扩展程序,不需要自己另外编译。可以在扩展目录找到相应的动态库文件:MAMP\bin\php\php5.3.23\ext\php_xdebug.dll。另外可以在 php.ini 中可以看到这一行:

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

;extension=php_xdebug.dll

但是不要被它迷惑了。这里的 extension 是指 php extension,而我们需要让它以 zend_extension 方式启用。正确的方法是留着 ;extension=php_xdebug.dll 前面的分号,并在 php.ini 中添加下面内容:

;;;;;;;;;;;;;;;;;;;
; Module Settings ;
;;;;;;;;;;;;;;;;;;;

[Xdebug]
zend_extension="G:/MAMP/bin/php/php5.3.23/ext/php_xdebug.dll"
xdebug.remote_enable=1
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.idekey=PHPSTORM
;xdebug.remote_autostart=1
  • zend_extension 指明了扩展库的绝对地址
  • remote_enable 用来启动远程调试;
  • remote_host 设置调试器的主机地址;
  • remote_port 设置调试器的主机端口;
  • idekey 设置触发调试器的关键字,需要与所使用的 IDE 侦听的关键字一致;
  • remote_autostart 启用后会自动在 http response 加入 idekey 来激活调试器;

如果 remote_autostart 没有启用,需要手动在 http request 设置 idekey 来激活调试器。例如在 querystring 中添加 ?xdebug_session_start=phpstorm,或者在 cookie 中设置。Chrome 用户可以使用 xdebug-helper 这个扩展工具,省去手动操作。

配置好后启动 MAMP 服务器即可。

PhpStorm

开发环境这边需要在配置中启用 xdebug ,保证端口一致即可:

phpstorm-xdebug

在浏览器打开项目首页,并启用 xdebug-helper 的调试模式。可以看到 phpstorm 弹出以下对话框要求映射脚本文件:

phpstorm-xdebug-mapping

设置好正确的 index.php 路径即可。如果项目引用的框架比较散,可能需要进行多次映射。

如果在调试的过程中发现这个错误提示:

Cannot accept external Xdebug connection:Cannot evaluate expression 'isset($_SERVER['PHP_IDE_CONFIG'])

要检查一下 xdebug 扩展是否设置正确。注意要不将 xdebug 作为 php extesion 启用。而应该以 zend_extension 方式启用。并且不要同时以这两种方式都启用,否则会在 php-error.log 中发现如下错误:

[05-Oct-2017 07:01:26 UTC] PHP Warning:  Module 'xdebug' already loaded in Unknown on line 0

至此,可以愉快地 debug 了。

小节

最后经过一段时间调试,定位到了问题发生在一处 preg_replace_callback() 调用,由于正则处理深度太大,导致 PHP 进程崩溃,浏览器显示连接被重置。

原因是 PHP 的 windows 版本给 PCRE Library 的栈空间太小,而默认配置超过了该栈空间所至。详细的分析见此文。解决方法是在 php.ini 中设置 pcre.recursion_limit=524

参考资料

关于PhpStorm+MAMP+xdebug集成失败的处理办法