LAMP开发环境搭建日志

前些天差不多把 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

  1. Download : Download the latest release from http://httpd.apache.org/download.cgi
  2. Extract : gzip -d httpd-NN.tar.gz -> tar xvf httpd-NN.tar -> cd httpd-NN
  3. Configure : ./configure --prefix=PREFIX
  4. Compile : make
  5. Install : make install
  6. Customize : vi PREFIX/conf/httpd.conf
  7. 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++ -v

sudo 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 指令来设置。可以参考官网给出的说明
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

修改后重启 Apache HTTP Server。

4) 检查 PHP 和 Apache HTTP Server 的配合

写一个简单的测试文件 phpinfo.php 放到 Apache HTTP Server 的 htdoc 目录中

<?php
    phpinfo();
?>

在浏览器中输入 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 */
<?php
    /*
     * Connect to database
     * Return a connection object(mysqli)
     */
    function db_conn() {
        $mysqli = new mysqli("127.0.0.1", "andy", "123456", "phpstudy", 3306);
        if ($mysqli->connect_errno) {
            echo "Fatal Error : connect MySQL failed : " . $mysqli->connect_errno . "<br />";
            $mysqli = null;
        }

        return $mysqli;
    }
?>

/* db_test.php */
<?php
    require 'db_func.php';

    $db_conn = db_conn();
    if (!$db_conn) {
        exit;
    }

    $query = "select * from admin";
    $result = $db_conn->query($query);
    if ($db_conn->errno) {
        echo "Fatal Error : " . $mysqli->errno . "<br />";
        exit;
    }
    else {
        $record = $result->fetch_assoc();
        $username = $record['username'];
        $password = $record['password'];

        echo 'username = ' . $username . '<br>';
        echo 'password = ' . $password . '<br>';
    }
?>

随后在 Apache HTTP Server 中创建了一个虚拟目录,用于以后的代码调试:

# 设置虚拟目录
Alias /phpstudy  "/home/andy/Research/PHP/src"

<Directory "/home/andy/Research/PHP/src">
    AllowOverride None
    Options None
    Require all granted
</Directory>

# 设置打开虚拟目录后可以自动识别index.php
<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

访问 “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:

<?php
    /*
     * Connect to database
     * Return a connection object(mysqli)
     */
    function db_conn() {
        ...
        ...
        $mysqli = new mysqli("localhost", "andy", "123456", "phpstudy", 3306);
        ...
        ...
    }
?>

// 告警,连接失败
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 host = ini_get("mysqli.default_host") [, stringusername = ini_get("mysqli.default_user") [, string passwd = ini_get("mysqli.default_pw") [, stringdbname = "" [, int port = ini_get("mysqli.default_port") [, stringsocket = 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。

至此,在 Ubuntu 上搭建 PHP 运行环境的工作已经完成。后面也尝试用一用 XMAPP 或 XMNP 这种自动化套件。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容