诡异的 Mac + PHP + Nginx 问题

前两天又遇到一个诡异的问题,以上是解决手段。

问题描述

这次是微信公众号开发,本身就有很多问题,也严重加剧了我调试的难度。正在做一个 WordPress 插件,功能是将公众号文章和 WordPress 互相同步。之前一切正常,突然有用户反馈抓不到公众号上的文章了。

顺便说下,插件地址:https://github.com/meathill/wp-plugin-weixin 目前支支持手动部署,完成二维码之后开始做发布版。

于是恢复本地环境开始调试。先修了几个不起眼的 Bug,一切正常,然后就开始出问题,表现为服务器没有返回任何数据。该有的 Header 都有,比如 Content-type: application/json,状态也是 200,但是没有任何 body 数据。

打断点调试一切正常,直到最后一步。于是以为是 wp_die() 的问题,反复尝试 wp_die()exit()die() 无果。

接着查日志,打开 /usr/local/var/log/nginx/error.log,没有 PHP Fatal error,甚至连 Warning 都没有,只有一个不熟悉的

2017/12/14 00:42:32 [crit] 33897#0: *444 open() "/usr/local/var/run/nginx/fastcgi_temp/6/02/0000000026" failed (13: Permission denied) while reading upstream, client: 127.0.0.1, server: dev.weclimbing.com, request: "GET /wp-admin/admin-ajax.php?action=mm_weixin_fetch_news_list&page=1 HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "dev.weclimbing.com:8080", referrer: "http://localhost:8080/wp-admin/options-general.php?page=master_meat_weixin"

看起来有些可疑,不过似乎和 PHP 关系不大,以前从来没见过。短暂思考了一下决定先放一放,试试别的方案。没想到离真相越来越远……

接下来开始鬼打墙。首先我发现 Bug 重现并不稳定,我要呈现文章列表,原本数据量比较大,而且包含富文本,于是我想会不会是 json_encode 的问题?于是我替换成简单的数据 ['test' => true],果然 Bug 消失了。于是我开始缩小数据量,逐步放大;甚至最后放大到全量,也可以正常输出。于是我起来上了趟厕所,问题就又出现了……

然后开始翻 WordPress 文档,把 die()exit()wp_die() 仔细看了一遍,又以它们为关键词搜了半天,无果;把 json_encode 换成 wp_send_json,好了一下下;再加上 @ 忽略错误,又好了一下下……

就这么撞来撞去,转了一两个小时毫无进展,只好再翻错误日志,发现上面这条错误出现的时间和 Bug 重现的时间高度吻合,应该就是它的问题。于是赶紧 Google 之,错误本身不复杂,因为生成的 ‘/usr/local/var/run/nginx/fastcgi_temp’ 权限不对,所以写不进去,才产生错误。

sudo chown meathill:staff /usr/local/var/run/nginx/fastcgi_temp

复盘

Mac 下的 Nginx 和 php-fpm 之间通过端口交互,跟 Ubuntu 不一样。

比较大块的内容,nginx 会把它写到一个临时文件里,位置就是 ‘/run/nginx/fastcgi_temp’,目的是节省内存。

不知道为什么,可能和 brew 有关,默认临时目录的权限是 root,但是运行用户是 meathill 也就是当前用户,所以这个就写不进去。

然后就报错,但是不是 PHP 的错,是 Nginx 的错,所以也就没有任何之前熟悉的错误信息,前端看到的也是有 http header,没 http body。

当我把内容减少,就不需要写临时文件,所以不报错。

Mac 下通过 homebrew 配置 PHP + Nginx + MySQL 开发环境

最后简单说一下在 Mac 上用 Homebrew 部署开发环境的方法。

  1. 安装 Homebrew
  2. brew install nginx
  3. brew install php71
  4. brew install php71-xdebug

一通咔咔咔之后,应该安装好了。因为 Mac 系统内嵌 Apache2,我们最好把它关掉:

sudo apachectl stop

brew 会把软件安装在 ‘/usr/local/etc/’ 目录下,所以我们可以编辑 ‘/usr/local/etc/nginx/nginx.conf’ 来配置 ngxin,编辑 ‘/usr/local/etc/php71/php.ini’ 配置 PHP-fpm。需要注意的是,Mac 下使用端口,也就是 fastcgi_pass 和 php-fpm 通信,和 Ubuntu 下不同。

接下来启动服务。这里需要注意,brew 和 ubuntu 不同,参数顺序刚好相反,同时,是复数的 services,而不是 service

brew services start php71
brew services start nginx 

基本上就这样。如果使用 Xdebug 的话,默认端口和 php-fpm 冲突,需要改掉其中一个。我选择把 Xdebug 放到 9001。


参考阅读:

作者: meathill

爱编程,爱旅游,爱吐槽。 今年的目标是完成并运营至少一个 Side Project。 《Electron + Vue 实战开发》龟速创作中……

欢迎吐槽,请勿装死