開篇——這看起來是一個很簡單的問題,但又絕不同于以往的任何一個類似的問題,即便搜遍全網(wǎng),可能也找不到答案,但這篇會帶領(lǐng)您一窺究竟
- 先按國際慣例,安裝好 apache2 和php7,以及 apache2-mod_php7
zypper install apache2
zypper install php7
//這時 apache2-mod_php7可能已經(jīng)自動安裝上了,如果沒裝,手動安裝一下就好
zypper install apache2-mod_php7
- 查看 apache 配置文件中 web 目錄位置,然后新建 phpinfo.php
openSUSE的 apache 的配置文件分得很散,一個配置文件可以搞定的事全部打散成各個小的配置文件位于 /etc/apache2 下,主配置文件是 /etc/apache2/httpd.conf,但是 web 目錄位置配置又在 /etc/apache2/default-server.conf 里,這種體驗(yàn)很不友好,尤其是對新手
DocumentRoot "/srv/www/htdocs"
我們在 /srv/www/htdocs 下新建一個 phpinfo.php文件
<?php
echo phpinfo();
?>
- 好玩的來了,當(dāng)我打開瀏覽器訪問 localhost/phpinfo.php 的時候,瀏覽器怎么也解析不了php文件,始終提示我下載文件
按理說,如果是 CentOS,到這一步PHP環(huán)境基本就已經(jīng)配置成功了
開始解決問題
- 一開始我的直覺是沒有加載mod_php7模塊,后來證明也的確如此,于是乎我根據(jù) http.conf 的配置順藤摸瓜,發(fā)現(xiàn) openSUSE 的 apache 把模塊加載配置專門放到了一個 /etc/apache2/loadmodule.conf 文件里,我喜出望外,馬上加上
LoadModule php7_module /usr/lib64/apache2/mod_php7.so
然后重啟
service apache2 restart
呵呵,我還是太輕敵了,發(fā)現(xiàn)還是不行,但是詭異的是,明明執(zhí)行 httpd -M 可以看到加載了 mod_php7
httpd -M
....
reqtimeout_module (shared)
authn_core_module (shared)
authz_core_module (shared)
php7_module (shared)
- 從錯誤日志入手
打開 /var/log/apache2/error_log,發(fā)現(xiàn)大有乾坤
[Sat Jun 26 04:02:53.190028 2021] [core:notice] [pid 9492] AH00094: Command line:
'/usr/sbin/httpd-prefork -D SYSCONFIG -C PidFile /var/run/httpd.pid -C
Include /etc/apache2/sysconfig.d//loadmodule.conf -C
Include /etc/apache2/sysconfig.d//global.conf -f /etc/apache2/httpd.conf -c
Include /etc/apache2/sysconfig.d//include.conf -D SYSTEMD -D FOREGROUND'
這是怎么回事,怎么是 /etc/apache2/sysconfig.d//loadmodule.conf 這個模塊加載配置文件,不是 /etc/apache2/loadmodule.conf 這個嗎?
原來 service apache2 restart 這個服務(wù)啟動的配置和直接使用httpd命令執(zhí)行apache使用的配置不一樣,這就是為什么使用 httpd -M 可以看到加載了 mod_php7 模塊,但使用 service 啟動后瀏覽器卻無法解析
那么我在 /etc/apache2/sysconfig.d//loadmodule.conf 里加上 mod_php7 的配置不就可以了嗎,我再次喜出望外,當(dāng)我加上之后,再次啟動 apache ,發(fā)現(xiàn)這個 loadmodule.conf 居然又被重置了,也就是說,這個并不是一個真正的配置文件,而是通過其他的程序生成的一個緩存文件罷了
- 再次順藤摸瓜
需要找到這個 loadmodule.conf 是怎么生成的,先找到 service 啟動腳本所在 /usr/lib/systemd/system/apache2.service
//apache2.service的內(nèi)容
[Unit]
Description=The Apache Webserver
After=network.target nss-lookup.target time-sync.target remote-fs.target
Before=getty@tty1.service plymouth-quit.service xdm.service
PartOf=apache2.target
[Service]
Type=notify
PrivateTmp=true
ExecStart=/usr/sbin/start_apache2 -DSYSTEMD -DFOREGROUND -k start
ExecReload=/usr/sbin/start_apache2 -DSYSTEMD -DFOREGROUND -k graceful
ExecStop=/usr/sbin/start_apache2 -DSYSTEMD -DFOREGROUND -k graceful-stop
KillMode=mixed
TasksMax=infinity
NotifyAccess=all
[Install]
WantedBy=multi-user.target
Alias=httpd.service apache.service
原來真正的啟動腳本是 /usr/sbin/start_apache2 ,再次打開這個文件,在143行處可以看到調(diào)用了 get_module_list 這個函數(shù),但是這個函數(shù)的實(shí)現(xiàn)卻沒有在這個腳本里,肯定在某個引用腳本里
#!/bin/sh
#
# Copyright (c) 1996, 1997, 1998 S.u.S.E. GmbH
# Copyright (c) 1998, 1999, 2000, 2001 SuSE GmbH
# Copyright (c) 2002, 2003, (2004?) SuSE Linux AG
# Copyright (c) 2004(?), 2005, 2006, 2007, 2008 SUSE Linux Products GmbH
#
# Authors: Rolf Haberrecker <apache@suse.de>, 2001
# Peter Poeml <apache@suse.de>, 2002, 2003, 2004, 2005, 2006, 2007,
# 2008, 2009, 2010
#
#
. /usr/share/apache2/script-helpers
看腳本開頭引入了 script-helpers 這么一個腳本,打開它
//大概64行處
function get_module_list
{
load_sysconfig
find_mpm
for module in $APACHE_MODULES; do
# special case
# remove or add 'd' on in cgi module name
case $module in mod_cgid|cgid)
case $HTTPD_MPM in prefork) module=${module%d};; esac;;
esac
case $module in mod_cgi|cgi)
case $HTTPD_MPM in event|worker) module=${module}d;; esac;;
esac
......
果不其然,這個函數(shù)的實(shí)現(xiàn)在這里,根據(jù)代碼看得出是根據(jù) $APACHE_MODULES 這個變量循環(huán)得出最后要加載那些模塊,于是目光落在 $APACHE_MODULES 這個變量上,毫無疑問,這是個數(shù)組,而且也是通過某個配置文件讀取加載的,看到 get_module_list 函數(shù)第一行就調(diào)用了 load_sysconfig,沒錯就是它了,它的函數(shù)實(shí)現(xiàn)在 script-helpers 的開頭
#!/bin/bash
HTTPD_SBIN_BASE="/usr/sbin/httpd"
#
# loads sysconfig variables into environment
#
# return value in: APACHE_*
#
function load_sysconfig
{
[ -n "$sysconfig_loaded" ] && return
[ ! -f "$SYSCONFIG_FILE" ] && return
. $SYSCONFIG_FILE
//在這里輸出 SYSCONFIG_FILE 的路徑
echo $SYSCONFIG_FILE
exit
export ${!APACHE_*} sysconfig_loaded=true
}
.....
在 load_sysconfig 函數(shù)里打印 $SYSCONFIG_FILE 的值,然后停掉 apache2服務(wù),直接使用命令調(diào)用 apache2
service apache2 stop
/usr/sbin/start_apache2
最后輸出
/etc/sysconfig/apache2
哈哈,最后抽絲剝繭,終于發(fā)現(xiàn)它了,打開這個文件
# fairly minimal
# APACHE_MODULES="authz_host alias auth dir log_config mime setenvif"
#
# apache's default installation
# APACHE_MODULES="authz_host actions alias asis auth autoindex cgi dir imap include log_config mime negotiation setenvif status userdir"
# your settings
APACHE_MODULES="actions alias auth_basic authn_core authn_file authz_host authz_groupfile authz_core authz_user autoindex cgi dir env expires include log_config mime negotiation setenvif ssl socache_shmcb userdir reqtimeout"
在80行,APACHE_MODULES變量就位于此處,將 php7 加上,修改后
APACHE_MODULES="actions alias auth_basic authn_core authn_file authz_host authz_groupfile authz_core authz_user autoindex cgi dir env expires include log_config mime negotiation setenvif ssl socache_shmcb userdir reqtimeout php7"
再次重啟 apache 服務(wù)
service apache2 restart
終于看到了熟悉的 phpinfo 界面
- openSUSE的開發(fā)環(huán)境體驗(yàn)還有待提升