搭建本地WordPress开发调试环境

WordPress的运行环境是很传统的Apache + MySQL + PHP,其中PHP用的是PHP5,因此部署过程中应该不会有很难解决的问题,只不过步骤可能会比较繁琐。除此以外就是调试的配置需要摸索一阵子。

一开始我曾想过花钱买MAMP PRO来搭建WordPress的本地开发环境(MAMP免费版本只支持PHP7),图省事。但后来还是决定自己折腾,省下这笔钱。于是花了那么几天自己搭建了一套本地WordPress编码、运行和调试环境。除了Apache + MySQL + PHP之外,为了能在编辑器中单步调试,我还给PHP加装了Xdebug扩展,并给Vim编辑器加装了Vdebug插件。最终我将自己的WordPress站点从云主机拷贝到了本地,并在Vim中愉快地编写和调试里面的PHP代码:




让我哭笑不得的是,在我把环境搭建好一个月后写这篇文章的过程中,才发现其实Mac本身已经自带了Apache和PHP,并不用我自己去下载源代码再安装。



1 MySQL


可能是因为涉及到授权的问题,Mac并没有自带MySQL,所以还是要自己装。不过这几个软件当中MySQL的安装算是很容易的,从官方网站下载安装包解压安装,再配置一下环境变量即可。可参考这篇文章:《mac安装mysql的两种方法(含配置)》。



2 Apache


2.1 通过源代码安装Apache服务器


如果想使用Mac自带的Apache,可以跳过这一小节。

如果是要自己下载Apache源代码来安装的话,PHP的安装文档,即PHP源代码包中的INSTALL文件包含了Apache HTTP服务器的安装说明。我参考的是Apache 2.x on Unix systems这节。文档给出的Apache配置命令是:

./configure --enable-so

设置了 --enable-so 才能在不重编译apache的情况下通过配置文件添加PHP和URL重写等模块。

然而对我来说仅仅 --enable-so是不够的。Apache 2.4在Unix系统上的多处理模块(Multi-Processing Module,简称MPM)默认是event模式,即多线程,默认开启了线程安全。但线程安全模式是无法加载Xdebug的。因此我需要将MPM设为传统的prefork模式:


./configure --enable-so --with-mpm=prefork

接着 make; sudo make install 即可。configure和make的过程可能会遇到缺少别的库而导致失败。到网上搜索下载相应的库然后 ./configure; make; sudo make install 三部曲编译安装即可。大多是Apache软件基金会的库,如apr和apr-util。


2.2 启动并配置Apache服务器


安装好后,启动apache。从源代码安装的apache目录是在/usr/local/apache2/,因此启动命令为

sudo /usr/local/apache2/bin/apachectl start

Mac自带的apachectl位于/usr/sbin/目录,已经在PATH环境变量中,所以如果想启动Mac自带的apache,则可以省去命令中的路径:

sudo apachectl start

两者的版本可以通过 -v 选项区分:

$ /usr/local/apache2/bin/apachectl -v
Server version: Apache/2.4.25 (Unix)
Server built:   May  3 2017 23:44:06
$ apachectl -v
Server version: Apache/2.4.23 (Unix)
Server built:   Aug  8 2016 18:10:45

Apache服务器启动后,打开浏览器,在地址栏中输入localhost并回车,看到下面“It works!”的页面,就证明apache已经成功安装并正常运行了:



Mac自带的Apache的默认站点根目录是/Library/WebServer/Documents/,自己安装的Apache的默认站点根目录则是/usr/local/apache2/htdocs/。这两个目录都不在用户主目录中,往里面放文件总是会涉及权限的问题,既不够方便也有点危险。我在自己的用户主目录下新建了一个Sites文件夹,希望将它设为站点根目录。

编辑apache的配置文件httpd.conf。Mac自带apache的该文件的路径是/etc/apache2/httpd.conf,通过源代码安装的这个文件则是/usr/local/apache2/conf/httpd.conf。在httpd.conf中找到下面的配置:

DocumentRoot "/Library/WebServer/Documents"

...



DocumentRoot "/usr/local/apache2/htdocs"

...

将它替换为

DocumentRoot "/Users/zhixiangzhu/Sites"

    Options Indexes ExecCGI FollowSymLinks Multiviews
    MultiviewsMatch Any 
    AllowOverride All
    Require all granted
    Order allow,deny
    Allow from all

其中/Users/zhixiangzhu/是我的用户主目录。保存文件后重启Apache服务器:

sudo apachectl restart



sudo /usr/local/apache2/bin/apachectl restart

然后在~/Sites/目录中创建一个index.html,内容随意。比如我的文件内容如下;


  
    
    子子翔的站点
  
  
    

站点主页


现在在浏览器中刷新localhost,应该能看见~/Sites/index.html的内容:



这说明站点根目录已经被设为~/Sites/。


3 PHP


3.1 通过源代码安装PHP


如果想使用Mac自带的PHP,可以跳过这一小节。

PHP的安装依然是 ./configure; make; sudo make install 三部曲。安装文档给出的最基本的configure命令是:

./configure --with-apxs2=/usr/local/apache2/bin/apxs --with-mysql

注意这里要使用自己通过源码安装而非Mac自带的Apache目录下的命令行工具apxs。我试过用 --with-apx2=/usr/sbin/apxs 指向Mac自带的apxs,结果configure会出错。

另外我还要多加一些configure选项。

为了能在PHP中使用cURL,需要加上 --with-curl 。Mac自带了curl,因此不用指定curl的路径。

我的开发中用到了 imagecreatefromstring 函数,因此还需要添加GD扩展。Mac并未自带GD库,因此要先通过Homebrew安装libgd:

brew install libgd

这会将GD库安装在/user/local/目录下。因此GD的选项为 --with-gd=/usr/local 。

但是GD库还要依赖XPM的库,这是X11的东西。我之前已经将X11安装在了/opt/X11/目录:

$ ls /opt/X11/
bin	etc	include	lib	share	var
$ ls /opt/X11/lib/libXpm.*
/opt/X11/lib/libXpm.4.dylib	/opt/X11/lib/libXpm.dylib

因此PHP的configure选项中还要加上 --with-xpm-dir=/opt/X11 。

不过在make的时候,configure为xpm默认加上的-I选项只会到/opt/X11/这一层而不会到/opt/X11/include/,因此还要加上 -I/opt/X11/include/ 。

如果要在本地使用WordPress的更新功能,还要加上zlib扩展。使用PHP源码包自带的zlib即可,只需在configure选项加上 --with-zlib 。

于是完整的configure命令如下:

./configure --with-apxs2=/usr/local/apache2/bin/apxs --with-mysql --with-curl --with-gd=/usr/local --with-xpm-dir=/opt/X11/ --with-zlib CPPFLAGS=-I/opt/X11/include/

3.2 配置Apache服务器以启用PHP


在Sites目录放入一个phpinfo.php文件,内容只有一行:


这个文件是用来验证PHP是否已成功启用。

接下来,如果想启用Mac自带的Apache和PHP,只需编辑/etc/apache2/httpd.conf,找到下面这行配置:

#LoadModule php5_module libexec/apache2/libphp5.so

把前面的#号注释删掉,保存文件,重启Apache。在浏览器中查看localhost/phpinfo.php,看到如下页面,就说明PHP已经启用。



当然,也可以让Mac自带的Apache启用我自己通过源代码安装的PHP。只需将LoadModule的配置改为:

LoadModule php5_module /usr/local/apache2/modules/libphp5.so

如果想采用自己安装的Apache,就要在apache的配置文件httpd.conf中加入如下配置:

LoadModule php5_module        modules/libphp5.so
 

    SetHandler application/x-httpd-php

注意必须要加上 FilesMatch 这一段,这样Apache才能将php为扩展名的文件视为真正的php文件。之所以不用在Mac自带的Apache配置中添加这一段,是因为/etc/apache2/other/php5.conf中已经有这样的配置,而/etc/apache2/httpd.conf包含了这个php5.conf:

Include /private/etc/apache2/other/*.conf

现在重启Apache服务器并在浏览器中查看localhost/phpinfo.php,应该同样能看到如下图的页面:



在这个页面中应该能看到我需要的各个PHP扩展,包括curl:



gd:



和zlib:





4 WordPress


WordPress的官方文档有一份安装说明,其中包含了“著名的5分钟安装”。不过我的情况并不是从零开始安装WordPress,而是要将我在云主机上的站点迁移到我本地。因此我要做的是将云主机站点的整个目录下载到我的Sites文件夹,并且将云主机的数据库dump出来,导入到我本地的MySQL中。

不管怎样,都要按照wp-config.php里的数据库配置创建好MySQL中的用户名、密码和数据库,并给用户赋予最大权限。

准备好WordPress站点文件和数据库后,删掉之前创建的~/Sites/index.html,让WordPress的index.php作为站点主页。如果是用自己安装的apache,还要编将httpd.conf中的下面配置


    DirectoryIndex index.html

改为


    DirectoryIndex index.html index.php

现在启动apache并在浏览器查看localhost(可能需要清空浏览器缓存),页面就会变成WordPress站点的首页。

不过要注意的是,WordPress在很多地方记录的是绝对路径的URL;而且将云主机上的既有站点拷贝到本地的情况下,访问localhost/index.php的时候,WordPress会重定向到云主机上的站点域名。因此为了访问本地WordPress站点的内容,还需要在/etc/hosts里加上一行,将云主机站点的域名指向本地:

127.0.0.1       zxtechart.com

如果在浏览器中访问WordPress站点页面时出现数据库连接错误,可以用下面的PHP代码揪出具体原因:


比如我遇到的数据库连接错误是因为这个原因:mysql_connect(): No such file or directory。这是因为mysql.sock在我系统上的路径是/tmp/mysql.sock,但 mysql_connect 实际执行的时候需要的却是/var/mysql/mysql.sock。解决办法倒也简单,只要建一个符号链接就行:

cd /var 
sudo mkdir mysql
sudo chmod 755 mysql
cd mysql
sudo ln -s /tmp/mysql.sock mysql.sock

参见StackOverflow上的这个回答。

数据库的问题解决之后,可能还会遇到访问首页成功,但访问具体文章均出现404错误的问题。这可能是因为Apache服务器没有开启URL重写功能,或者站点目录中缺少了.htaccess文件。首先要编辑httpd.conf,给Mac自带Apache加入下面这行配置:

LoadModule rewrite_module libexec/apache2/mod_rewrite.so

或者是给通过源码安装的Apache加入:

LoadModule rewrite_module modules/mod_rewrite.so

重启Apache。接着登入WordPress站点的管理后台http://localhost/wp-admin,进入“设置”->“固定链接”页面,点击“保存更改”,一般就能修复该问题:


但有时候可能会遇到上图“保存更改”按钮下方的提示,即.htaccess不可写。这时就要自己在站点根目录中创建一个.htaccess文件,然后按提示所说的,复制文本框里的所有内容,粘贴到.htaccess中。这样就能访问到具体的文章页面了。.htaccess的内容如下:


RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

可参见《How to Fix WordPress Posts Returning 404 Error》这篇文章。

这里我想多解释几句。在WordPress站点中,URL为http://zxtechart.com/2017/04/30/sketch-2017-04-23/的文章并不是真的存放在站点的2017/04/30/目录中,实际上没这个目录。文章都存储在数据库里。WordPress之所以能通过URL查询到数据库里的文章,是借助了URL重写的特性,将URL中的2017/04/30/sketch-2017-04-23转换成数据库查询用的参数。

到这里WordPress在本地的运行环境就部署好了。接下来还要搭建开发调试用的环境。


5 Xdebug


要调试PHP就要安装Xdebug。这是一个PHP扩展。Xdebug的官方安装文档表示在Mac上可以通过Homebrew安装Xdebug。文档中给出的安装命令是:

brew install -xdebug

对我的PHP5.6环境来说即是:

brew install php56-xdebug

然而我实际运行这个命令时却安装失败,Homebrew提示找不到安装包。于是我搜了一下xdebug安装包的具体名字:

$ brew search xdebug
homebrew/php/php53-xdebug     homebrew/php/php54-xdebug     homebrew/php/xdebug-osx
homebrew/php/php55-xdebug     homebrew/php/php56-xdebug     homebrew/php/php70-xdebug
homebrew/php/php71-xdebug

所以安装命令应该改为:

brew install homebrew/php/php56-xdebug

安装成功后,Homebrew提示说创建了一份/usr/local/etc/php/5.6/conf.d/ext-xdebug.ini文件,说如果卸载Xdebug时记得移除它。这份文件的内容只有两行:

[xdebug]
zend_extension="/usr/local/opt/php56-xdebug/xdebug.so"

将这个内容拷贝到php.ini中。如果是想用Mac自带的PHP,php.ini的默认路径是/etc/php.ini。这份文件可能不存在,但会存在一份/etc/php.ini.default模板,将它拷贝一份作为php.ini就行:

sudo cp /etc/php.ini.default /etc/php.ini

如果是用通过源码安装的PHP,php.ini的路径是/usr/local/lib/php.ini。重启Apache,应该能在phpinfo的输出中看见xdebug模块:



这里再次提醒,前文Apache的编译安装一节已经提过,Apache的MPM必须为prefork模式才能正常加载Xdeubg,否则phpinfo中是看不见xdebug模块的,而且Apache启动过程中加载Xdebug的时候,error_log也会打印出“xdebug.so cannot be loaded because Symbol not found…“这样的错误。error_log的路径可以在httpd.conf中查看。Mac自带Apache的error_log默认是/var/log/apache2/error_log,通过源码安装的Apache的error_log则默认是/usr/local/apache2/logs/error_log。

确认Apache的MPM是否为prefork模式的方法是用 http -l 或 http -V 命令。如果命令输出带有prefork则是正确的。见这篇StackOverflow帖子:How to find what MPM model Apache is using in Linux (worker, prefork or event)

$ httpd -l # Mac自带Apache
Compiled in modules:
  core.c
  mod_so.c
  http_core.c
  prefork.c
$ httpd -V # Mac自带Apache
Server version: Apache/2.4.23 (Unix)
Server built:   Aug  8 2016 18:10:45
Server's Module Magic Number: 20120211:61
Server loaded:  APR 1.5.2, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture:   64-bit
Server MPM:     prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_FLOCK_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/usr"
 -D SUEXEC_BIN="/usr/bin/suexec"
 -D DEFAULT_PIDLOG="/private/var/run/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="/private/etc/apache2/mime.types"
 -D SERVER_CONFIG_FILE="/private/etc/apache2/httpd.conf"
$ /usr/local/apache2/bin/httpd -l  # 通过源码安装的Apache
Compiled in modules:
  core.c
  mod_so.c
  http_core.c
  prefork.c
$ /usr/local/apache2/bin/httpd -V  # 通过源码安装的Apache
Server version: Apache/2.4.25 (Unix)
Server built:   May  3 2017 23:44:06
Server's Module Magic Number: 20120211:67
Server loaded:  APR 1.5.2, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture:   64-bit
Server MPM:     prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/usr/local/apache2"
 -D SUEXEC_BIN="/usr/local/apache2/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

光是让Xdeubg成功加载还不够。为了能在IDE和编辑器中能够单步调试,还要在php.ini的xdebug一节中加入下面几行:

xdebug.remote_enable=true
xdebug.remote_autostart=true
xdebug.remote_host=localhost
xdebug.remote_port=10000
xdebug.remote_handler=dbgp
xdebug.idekey=netbeans-xdebug

其中xdebug.remote_port是调试器用的端口,这个可以自己随意更改。改好php.ini后记得重启Apache。

除了通过Homebrew安装Xdebug,也可以自己从Xdebug官网下载源代码安装。按照官网或源码包里的README.rst中的说明安装即可。不过这种情况下默认的xdebug.so安装路径是在/usr/lib/php/extensions/的子目录中,比如我的安装路径是/usr/lib/php/extensions/no-debug-non-zts-20131226/xdebug.so。因此php.ini中的xdebug配置就要改为:

[xdebug]
zend_extension="/usr/lib/php/extensions/no-debug-non-zts-20131226/xdebug.so"


6 Vdebug


Xdebug只是基于DBGp协议为调试器提供了一套接口,算是调试器的后端。要在IDE或编辑器中利用Xdebug方便地单步调试,还要加装一个支持DBGp协议的调试器前端。作为Vim粉我自然希望能在Vim中单步调试。幸运的是有Vdebug这个插件。我是通过Pathogen安装Vdebug的。这样就只需要将Vdebug的整个目录拷贝到 ~/.vim/bundle中。然后在~/.vimrc中加入下面几行代码:

let g:vdebug_options = {'ide_key': 'netbeans-xdebug'}
let g:vdebug_options = {'break_on_open': 0}
let g:vdebug_options = {'server': '127.0.0.1'}
let g:vdebug_options = {'port': '10000'}

其中server和port要和之前在php.ini中配置的Xdebug地址和端口一致。

调试方法是在Vim中按F5,Vim就会进入等待连接的状态。你要在20秒内在浏览器中刷新站点页面,否则Vdebug就会停止等待:



页面刷新时,Vdebug就会暂停在Apache执行的第一条PHP代码上:



此时你可以打开想下断点的源代码,按F10下断点。当然也可以在按F5让Vim等待连接之前就下好断点。下好断点后再按F5,程序就会继续执行,在断点处暂停——当然,前提是程序确实会执行到你下断点的地方。

可用Vim命令 :help Vdebug 查看Vdebug的使用方法。不过在此之前要先给Vdebug的文档建好tag:

:helptags ~/.vim/bundle/vdebug/doc


7 Vim


现在WordPress的运行和调试环境都搭建好了。但我还要对Vim的配置做些调整,因为WordPress的编码规范和我个人的编码风格不太一样。比如WordPress的编码规范是用制表符缩进,并且php、html、js和css文件都是缩进一个制表符;而我个人习惯用空格缩进,并且php文件缩进四个空格,html、js和css文件缩进两个空格。为了在编写WordPress代码时采用WordPress编码规范,我在.vimrc中加入了如下代码:

if exists('WordPress')
        autocmd FileType php,css,javascript,html set shiftwidth=4 | set tabstop=4 | set noexpandtab
endif

然后在~/.bash_profile中定义了一个命令别名:

alias wpvim="vim --cmd \"let WordPress=1\" \"+set textwidth=0\""

在编写WordPress程序时,我用 wpvim 命令打开源代码文件,这样Vim就会采用WordPress的编码规范。

这里稍微解释一下我对 textwidth 的处理。其实我还没找到一个解决方案。平常在用Vim写tex之类的文本文件时,我习惯设置 textwidth 以便让Vim自动换行避免一行文本过长。但是WordPress插件的readme.txt和github的README.md都是一段文字就是一行文本。因此在编写README的时候我需要将 textwidth 设0。但不知为何,仅仅在.vimrc中设置有时并无效果,似乎会被不知何处的设置覆盖,所以我只好将设置 textwidth 的命令搬到vim的启动参数中。但有时发现这只对vim打开的第一个文件有效,当在vim中用 :e 或者在MiniBufExplorer切换到另一个文件时, textwidth 又变成非0了,这时只好再设置一次。不过这只是个小瑕疵。

最后,我还给Vim安装了Tagbar插件,使用phpctags和tagbar-phpctags生成tags,在Vim中用命令 :TagbarOpen 就能在侧边栏浏览当前PHP源文件的函数列表。



现在终于可以开始愉快地编写和调试WordPress代码了。作为一个从2003年发展至今的历史悠久且生命力旺盛的优秀项目,WordPress的内部代码还是很值得探究学习的。

本文在我的独立博客上的地址:http://zxtechart.com/2017/06/22/setup-wordpress-environment/

你可能感兴趣的:(Web)