前些天差不多把 Ubuntu 美化完了,基本上达到作为工作环境的基础条件。这几天集中精力鼓捣 PHP 的研发环境。要说 PHP 研发环境搭建绝对是最恶心的一个过程,没有之一,为此 Apache 还纠结了几个伙伴,成立了 Apache Friends,搞了个 XAMPP,来尽可能简化开发环境的搭建。不过自己动手的感觉是很棒的,虽然以后我应该不会再全程手工搭建犯这个贱了。
记录一下这个“恶心”的过程,留个念想。
这篇日志主要记录在 Ubuntu 18.04 LTS 版本上通过源码方式安装 PHP 研发环境的方法。
1. ANSI-C 编译和构建系统
无论是 Apache 还是 PHP,通过源码方式安装,首先必须具备的是一套编译和构建环境,以 GCC 安装为例:
sudo apt-get install build-essential
安装结束后,可以执行如下命令进行确认:
gcc --version
gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2. 编译/安装/运行 Apache HTTP Server
PHP 大多数情况下都是配合 HTTP Server 使用,以 Apache HTTP Server 安装为例:
Apache HTTP Server 官网已经给出清晰的指导(http://httpd.apache.org/docs/2.4/install.html)
- Download : Download the latest release from http://httpd.apache.org/download.cgi
- Extract : gzip -d httpd-NN.tar.gz -> tar xvf httpd-NN.tar -> cd httpd-NN
- Configure : ./configure --prefix=PREFIX
- Compile : make
- Install : make install
- Customize : vi PREFIX/conf/httpd.conf
- Test : PREFIX/bin/apachectl -k start
但在上面第三步时,先不要着急执行 “configure”,Apache HTTP Server 的安装还有一些依赖,这些在官网上也有清晰的说明,主要是这两点:
- APR 和 APR-Util
Download the latest versions of both APR and APR-Util from Apache APR, unpack them into /httpd_source_tree_root/srclib/apr and /httpd_source_tree_root/srclib/apr-util (be sure the directory names do not have version numbers; for example, the APR distribution must be under /httpd_source_tree_root/srclib/apr/) and use ./configure's --with-included-apr option
下载地址:http://apr.apache.org/download.cgi
安装方法:
- APR:./configure --prefix=/usr/local/apr; make ; make install(这里注意用 sudo)
- APR-Util:./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr; make; make install(这里注意用 sudo)
在我的系统上,编译 APR-Util的时候上报缺少expat的开发库:xml/apr_xml.c:35:19: error: expat.h: No such file or directory,这样解决:sudo apt-get install libexpat1-dev
- PCRE
Download the source code from http://www.pcre.org. If your build system can't find the pcre-config script installed by the PCRE build, point to it using the --with-pcre parameter.
这里注意下载 PCRE1,不要使用 PCRE2,否则后面编译 Apache HTTP Server 会出错
安装方法:./configure --prefix=/usr/local/pcre; make; make install(这里注意用 sudo)
在我的系统上,就是因为开始编译使用的是 PCRE2,所以报了这个错误:util_pcre.c:58:10: fatal error: pcre.h: No such file or directory
编译 PCRE 的时候,还可能遇到另外一个编译问题:You need a C++ compiler for C++ support.
这是因为 PCRE 的编译需要 C++ 的环境,但我们往往认为安装了 gcc 就万事大吉,其实还需要安装 g++
通过这个命令来查看是否安装了 g++:g++ -vsudo apt-get install g++
把 APR/APR-Util/PCRE 编译及安装好后,就可以开始配置 Apache HTTP Server 的编译选项以及最终的编译安装了。
Apache 的编译选项有很多,但最基本的如下所示:
./configure --prefix=/usr/local/apache2 --with-apr=/usr/local/apr/bin/apr-1-config --with-apr-util=/usr/local/apr-util/bin/apu-1-config --with-pcre=/usr/local/pcre/bin/pcre-config
* --prefix==XXXX:这个代表将 Apache HTTP Server 安装到哪里
* --with-apr=XXXX:这个要设置为前面编译安装 APR 的目录中的 apr-config 文件
* --with-apr-util=XXXX:这个要设置为前面编译安装 APR-Util 的目录中的 apr-config 文件
* --with-pcre=XXXX:这个要设置为前面编译安装 PCRE 的目录中的 pcre-config 文件
完成编译和安装后,在运行前设置一下 Apache HTTP Server 的配置文件 httpd.conf,增加 “ServerName 127.0.0.1:80” 的配置
#Listen 12.34.56.78:80
Listen 80
#这里是新增的配置
ServerName 127.0.0.1:80
然后可以执行如下的命令(后台执行)开启和关闭 Apache HTTP Server。
sudo ./apachectl -k start
sudo ./apachectl -k stop
至此,基于源码安装 Apache HTTP Server 的过程暂时告一段落。
3. 安装 MariaDB
MySQL 被 Oracle 收购后,社区便单独拉出了 MariaDB 分支,继续开源,它们在本质上是相同的。
在 Ubuntu 上安装 MariaDB ,MariaDB 官方推荐使用 apt 等软件包管理工具,官方也给出了详细的安装指导,参见(https://downloads.mariadb.org/mariadb/repositories/#mirror=tuna&distro=Ubuntu&distro_release=bionic--ubuntu_bionic&version=10.3)。
简单整理一下步骤:
sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64] http://mirrors.neusoft.edu.cn/mariadb/repo/10.3/ubuntu bionic main'
sudo apt update
sudo apt install mariadb-server
安装过程结束后,检查是否能够连接成功
andy@andy-ubuntu:/usr/local$ sudo mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 47
Server version: 10.3.7-MariaDB-1:10.3.7+maria~bionic mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> exit
Bye
启动/关闭 MariaDB 服务的方法
sudo service mysql start // 开启 MariaDB 服务
sudo service mysql stop // 关闭 MariaDB 服务
3. 编译/安装/运行 PHP
编译安装 PHP 的过程,可以参考 PHP 官网手册( http://php.net/manual/zh/install.unix.apache2.php )。
1) 编译 PHP
PHP 的编译选项也比较多,主要是打开各种功能,我的编译选项比较简单:
./configure --prefix=/usr/local/PHP \
--with-config-file-path=/usr/local/PHP/lib \
--with-apxs2=/usr/local/apache2/bin/apxs \
--with-mysqli \
--enable-mbstring
--with-apxs2:让 Apache HTTP Server 支持 PHP,体现在 httpd.conf 中增加了一条配置(LoadModule php7_module modules/libphp7.so)
--with-mysqli:mysqli 扩展技术不仅可以调用 MySQL 的存储过程、处理 MySQL 事务,而且还可以使访问数据库工作变得更加稳定
--enable-mbstring:使能 mbstring 扩展插件,我的项目调用了一点相关接口
编译检查时,报了一个错:
configure: error: libxml2 not found. Please check your libxml2 installation.
// 执行如下命令解决
sudo apt-get install libxml2-dev
2) 设置 php.ini
将源码目录中的 php.ini-development 拷贝到 /usr/local/PHP/lib 目录中。
cp php.ini-development /usr/local/PHP/lib/php.ini
3) 检查 Apache HTTP Server 配置文件中是否开启了对 PHP 的支持
- 打开 httpd.conf 文件,如果找到
“LoadModule php7_module modules/libphp7.so”
,说明 Apache HTTP Server 已经开启对 PHP 的支持。 - 设置 Apache 将特定的扩展名解析成 PHP,例如,让 Apache 将扩展名 .php 解析成 PHP。为了避免潜在的危险,例如上传或者创建类似 exploit.php.jpg 的文件并被当做 PHP 执行,PHP已经不再使用 Apache 的 AddType 指令来设置。可以参考官网给出的说明
SetHandler application/x-httpd-php
修改后重启 Apache HTTP Server。
4) 检查 PHP 和 Apache HTTP Server 的配合
写一个简单的测试文件 phpinfo.php 放到 Apache HTTP Server 的 htdoc 目录中
在浏览器中输入 http://127.0.0.1/phpinfo,如果能够成功显示 PHP 的配置信息,说明 PHP 和 Apache 的关联已经成功,Apache HTTP Server 已经能够成功解析 PHP。
**5) 检查 PHP 和 MariaDB(MySQL)的配合
首先,我在 MariabDB上创建了用户、数据库和数据表。通过 source
命令导入如下脚本:
CREATE USER andy IDENTIFIED BY '123456';
CREATE DATABASE IF NOT EXISTS phpstudy;
USE phpstudy;
CREATE TABLE IF NOT EXISTS admin (
username VARCHAR(32) NOT NULL,
password VARCHAR(32) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO admin VALUES ('admin', '12345678');
CREATE TABLE IF NOT EXISTS article (
id INT(11) NOT NULL AUTO_INCREMENT,
class VARCHAR(32) NOT NULL,
title VARCHAR(256) NOT NULL,
modifydate DATE NOT NULL,
author VARCHAR(32) NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
GRANT ALL PRIVILEGES ON phpstudy.* TO andy;
然后,写一个简单的数据库连接和访问的代码,db_func.php 中封装了数据库的连接函数, db_test.php 中则访问了一张数据表:
/* db_func.php */
connect_errno) {
echo "Fatal Error : connect MySQL failed : " . $mysqli->connect_errno . "
";
$mysqli = null;
}
return $mysqli;
}
?>
/* db_test.php */
query($query);
if ($db_conn->errno) {
echo "Fatal Error : " . $mysqli->errno . "
";
exit;
}
else {
$record = $result->fetch_assoc();
$username = $record['username'];
$password = $record['password'];
echo 'username = ' . $username . '
';
echo 'password = ' . $password . '
';
}
?>
随后在 Apache HTTP Server 中创建了一个虚拟目录,用于以后的代码调试:
# 设置虚拟目录
Alias /phpstudy "/home/andy/Research/PHP/src"
AllowOverride None
Options None
Require all granted
# 设置打开虚拟目录后可以自动识别index.php
DirectoryIndex index.html index.php
访问 “http://127.0.0.1/phpstudy/db/db_test.php” 成功显示如下结果:
username = admin
password = 12345678
这里遇到一个数据库连接的问题,即代码中通过 “127.0.0.1” 能够连接 MariaDB,但通过 “localhost” 就提示连接失败。
Unix 系统下连接 MariaDB 的方式有两种,一种是 TCP,一种是 Socket。TCP 是所有系统都支持的,通过 TCP/IP 协议可以访问本地和远程 Server;而 Socket 只有 Unix 系统支持,通过 Unix Socket File 只能访问本地server。
通过 --host 参数可以指定主机,默认情况下输入 IP 地址即通过 TCP 方式连接,输入 localhost 或者不指定默认即通过 Socket 方式连接。
1. mysql --host=127.0.0.1 -u root -p # 通过 TCP 连接
2. mysql --host=localhost -u root -p # 通过 Socket 连接
3. mysql -u root -p # 通过 Socket 连接
而我在 Terminal 中通过 mysql -u rott -p
也就是 Socket 方式,是能够正常连接的:
andy@andy-ubuntu:/home$ mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 50
Server version: 10.3.7-MariaDB-1:10.3.7+maria~bionic mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
然而,在 PHP 脚本中却无法连接 localhost:
// 告警,连接失败
Warning: mysqli::mysqli(): (HY000/2002): No such file or directory
显然不是 MariaDB 而是 PHP 引擎出现了问题。
我引用这个页面的解答(https://segmentfault.com/q/1010000000328531)
PHP报的错误是No such file or directory,也就是说PHP找不到这个socket文件,那么PHP去哪找了?看手册:
mysqli::__construct ([ string username = ini_get("mysqli.default_user") [, string dbname = "" [, int socket = ini_get("mysqli.default_socket") ]]]]]]
所有参数都是可选参数,如果不指定,默认会从ini配置文件去读。那这个默认值是什么呢? 在php.ini里找到mysqli.default_socket这一行,我的这里是空值。
解决方案有两个:
一个是调用的时候,参数全部指定,如:
$db = new mysqli('localhost','uname','passwd','dbname','3306','/var/run/mysqld/mysqld.sock');
另一个是修改php.ini文件,找到mysqli.default_socket= ,修改为
mysqli.default_socket=/var/run/mysqld/mysqld.sock
我直接修改了 php.ini 文件。有一个小问题,就是 php.ini 文件在哪里。因为有的环境可能采用源码编译 PHP,有的可能是直接下载二进制包,因此大家的 php.ini 存放位置都可能不同,最靠谱的方式是通过 phpinfo() 系统函数来查询,如下是我的系统查询结果:
Item | Value |
---|---|
Configure Command | './configure' '--prefix=/usr/local/PHP' '--with-apxs2=/usr/local/apache2/bin/apxs' '--with-mysqli' |
Configuration File (php.ini) Path | /usr/local/PHP/lib |
Loaded Configuration File | /usr/local/PHP/lib/php.ini |
修改 php.ini 后重启 Apache HTTP Server,重新访问,通过 localhost 成功连接 MariaDB。