openSUSE15.3 apache无法解析php7的问题

开篇——这看起来是一个很简单的问题,但又绝不同于以往的任何一个类似的问题,即便搜遍全网,可能也找不到答案,但这篇会带领您一窥究竟
  • 先按国际惯例,安装好 apache2 和php7,以及 apache2-mod_php7
zypper install apache2
zypper install php7
//这时 apache2-mod_php7可能已经自动安装上了,如果没装,手动安装一下就好
zypper install apache2-mod_php7
  • 查看 apache 配置文件中 web 目录位置,然后新建 phpinfo.php
    openSUSE的 apache 的配置文件分得很散,一个配置文件可以搞定的事全部打散成各个小的配置文件位于 /etc/apache2 下,主配置文件是 /etc/apache2/httpd.conf,但是 web 目录位置配置又在 /etc/apache2/default-server.conf 里,这种体验很不友好,尤其是对新手
DocumentRoot "/srv/www/htdocs"

我们在 /srv/www/htdocs 下新建一个 phpinfo.php文件


  • 好玩的来了,当我打开浏览器访问 localhost/phpinfo.php 的时候,浏览器怎么也解析不了php文件,始终提示我下载文件
    按理说,如果是 CentOS,到这一步PHP环境基本就已经配置成功了
开始解决问题
  • 一开始我的直觉是没有加载mod_php7模块,后来证明也的确如此,于是乎我根据 http.conf 的配置顺藤摸瓜,发现 openSUSE 的 apache 把模块加载配置专门放到了一个 /etc/apache2/loadmodule.conf 文件里,我喜出望外,马上加上
LoadModule php7_module                    /usr/lib64/apache2/mod_php7.so

然后重启

service apache2 restart

呵呵,我还是太轻敌了,发现还是不行,但是诡异的是,明明执行 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,发现大有乾坤
[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 这个服务启动的配置和直接使用httpd命令执行apache使用的配置不一样,这就是为什么使用 httpd -M 可以看到加载了 mod_php7 模块,但使用 service 启动后浏览器却无法解析

那么我在 /etc/apache2/sysconfig.d//loadmodule.conf 里加上 mod_php7 的配置不就可以了吗,我再次喜出望外,当我加上之后,再次启动 apache ,发现这个 loadmodule.conf 居然又被重置了,也就是说,这个并不是一个真正的配置文件,而是通过其他的程序生成的一个缓存文件罢了

  • 再次顺藤摸瓜
    需要找到这个 loadmodule.conf 是怎么生成的,先找到 service 启动脚本所在 /usr/lib/systemd/system/apache2.service
//apache2.service的内容
[Unit]
Description=The Apache Webserver
After=network.target nss-lookup.target time-sync.target remote-fs.target
[email protected] 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行处可以看到调用了 get_module_list 这个函数,但是这个函数的实现却没有在这个脚本里,肯定在某个引用脚本里

#!/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 , 2001
#          Peter Poeml , 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
      ......

果不其然,这个函数的实现在这里,根据代码看得出是根据 $APACHE_MODULES 这个变量循环得出最后要加载那些模块,于是目光落在 $APACHE_MODULES 这个变量上,毫无疑问,这是个数组,而且也是通过某个配置文件读取加载的,看到 get_module_list 函数第一行就调用了 load_sysconfig,没错就是它了,它的函数实现在 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 函数里打印 $SYSCONFIG_FILE 的值,然后停掉 apache2服务,直接使用命令调用 apache2

service apache2 stop
/usr/sbin/start_apache2

最后输出

/etc/sysconfig/apache2

哈哈,最后抽丝剥茧,终于发现它了,打开这个文件

# 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 服务

service apache2 restart

终于看到了熟悉的 phpinfo 界面

  • openSUSE的开发环境体验还有待提升

你可能感兴趣的:(openSUSE15.3 apache无法解析php7的问题)