我刚刚在工作中遇到了一个有趣的情况,这让我对 apache2 如何执行 php 文件的理解彻底改变了。
我的印象是 apache2 会确定正确的文件类型并通过正确的文件解析器运行它。这将允许解析器进行实际执行,因此我的理解是 apache 执行的 php 文件只需要读取权限。
例子:
以一个拥有 744 个权限的简单 php 文件为例
#!/usr/bin/php
<?php
echo "test";
?>
使用 ./test.php 执行会导致权限被拒绝。
但使用 /usr/bin/php test.php 执行它可以正常工作。
将权限更改为 755 并且它可以通过 ./test.php 正确执行
这似乎与 apache 执行文件时发生的事情相同。它返回了禁止错误。
所以最后...问题来了。
Apache 实际上如何处理和传递文件请求?
它如何将文件交给正确的解析器?
为什么需要执行权限?显然解析器并不是像我最初预期的那样只读取文件。
请温柔一点...我以为我知道这些东西。
答案1
- 文件的执行权限对 apache 来说毫无意义。这只是为了让内核知道在您尝试执行文件时如何执行该文件(例如,通过 shell)。只要您有 apache 可以读取的读取权限,就没问题。
编辑读取权限是最重要的 - apache 需要对目录直至根目录具有执行权限。对于目录,执行意味着可搜索,而 apache 需要对目录具有搜索权限才能查找文件。
- Apache 不会“传递”这些文件。它不会执行它们。Apache 中有一个嵌入式解释器,可以处理 PHP 文件。这发生在 Apache 进程中。它的配置方式如下:
您添加模块:
LoadModule php5_module libexec/libphp5.so
模块被编译/创建以了解如何解析 php。它与 php 解释器链接,基本上由 PHP 与 apache 通信的粘合代码组成,以 apache 期望的方式。PHP 模块具体知道如何处理两种 MIME 类型application/x-httpd-php
和application/x-httpd-php-source
。因此,现在您必须告诉 apache 如何将 php 文件连接到模块。这通常通过以下方式完成:
<IfModule mod_php5.c>
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
</IfModule>
因此,现在我们告诉 apache 将 .php 文件传递给 PHP 处理器。使用后缀是唯一的方法吗?不,您可以配置任何目录以包含所有 PHP 文件或整个服务器。但这是最有意义的。另外,请注意,我们不关心 shebang 行 (#!/usr/bin/php)。我们仅针对文件扩展名进行配置。
- 好的,那么为什么会出现禁止错误?我不知道。出现这种情况的原因有很多。你检查过错误日志吗?文件系统目录上的权限是否正确,apache 进程是否可以读取目录直至根目录?配置文件中的权限是否正确?我会检查错误日志。
第二次编辑
我想我了解你的困惑......
通过 apache 生成动态内容有两种方式。一种是通过嵌入式解释器,如 PHP。Perl 和 python 也是常见的嵌入式解释器。Web 服务器使用 glue 模块(mod_php、mod_perl 等)将解释器加载到 httpd 进程中。代码不是“执行”的,而是在 httpd 进程中加载、解析和解释的。
第二种方法是通过 CGI 脚本。在本例中,Apache做执行文件。在这种情况下,粘合剂是环境变量(apache 设置了一些标志)以及脚本的标准输入。要发送回 apache,您需要在标准输出上发送内容,apache 会添加一些修饰并发送给客户端,然后您可以在 stderr 上发送错误,apache 会将其附加到其 error_log 中。CGI 规范规定了此“胶水”的工作规则。在本例中,您正在执行一个文件,因此该文件的执行权限对 Apache 来说很重要。
CGI 已经不像以前那么常见了。CGI 的优点是它是一个与 Web 服务器隔离的进程。它不会对 Web 服务器造成任何损害(当然,只要安全地解析输出)。缺点是隔离。每次运行时我都需要 fork/exec(尽管有一些称为 fastCGI 的方案可以帮助实现这一点)。PHP(以及其他一些语言)也有一个不同的编码模型,您可以在其中向 HTML 添加一些代码,而不是编写一个大脚本并从那里推出 HTML。这让大多数人更容易编写,这也是 PHP 在 Web 上如此受欢迎的一个重要原因。