PHP curl_init()、curl_exec() 在命令行下可以工作,但在通过 Web 服务器浏览/访问时会失败

PHP curl_init()、curl_exec() 在命令行下可以工作,但在通过 Web 服务器浏览/访问时会失败

以下 PHP 脚本(未匿名)在命令行上成功运行。它使用 curl_init() 和 curl_exec() 检索 JSON 格式的数据,将结果转换为关联数组,并显示特定的数组值。

#!/usr/bin/php
<?php
$url = "https://host.ext";
$user = "<user>";
$pass = "<pw>";

$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $user.":".$pass);
curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
//curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json'));

$result = curl_exec($curl);
$resultlen = strlen($result);

curl_close($curl);

$r_ary = array();
$r_ary = json_decode( $result , true , 512 , JSON_OBJECT_AS_ARRAY );
$st = 'status';
$status = $r_ary[$st];

echo "<!doctype html>";
echo "<html>";
echo "<body>";
   echo "Length: $resultlen";
   echo "Status: $status";
echo "</body>";
echo "</html>";
?>

它检索 913 个字符的数据并生成输出:

[root@box local]# ./test.php 
<!doctype html><html><body>Length: 913Status: active</body></html>
[root@box local]# 

但是,如果我删除初始的“#!...”行,将结果放在我的 Web 服务器的文档根目录中,然后浏览文件,我将检索到零字节: 零长度

通过本地 LAN 其他地方的调用脚本访问 test.php 得到了相同的结果:

[root@box2 work23]$ 
[root@box2 work23]$ cat call.php
#!/usr/bin/php
<?php
$webPage = "http://box/test.php";
date_default_timezone_set("America/New_York");
$fd = fopen($webPage, "r");
$r = file_get_contents( $webPage );
print "Retrieved: $r \n";
fclose($fd);
?>

[root@box2 work23]$ ./call.php 
Retrieved: <!doctype html><html><body>Length: 0Status: </body></html>
 

[root@box2 work23]$ 

对 RETURNTRANSFER 和 HTTPHEADER 选项的不同组合进行注释/取消注释对 Web 服务器版本没有影响,但命令行版本需要 RETURNTRANSFER 选项才能工作。系统是 Centos Stream 9,运行 apache 2.4.57 和 php-fpm 而不是 mod_php。PHP 解释器是版本 8.0.30。我在类似年份的 AlmaLinux 系统上遇到了同样的问题。

[root@box local]# apachectl -v
Server version: Apache/2.4.57 (CentOS Stream)
Server built:   Jul 20 2023 00:00:00
[root@box local]# uname -a
Linux box 5.14.0-402.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 21 19:46:35 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
[root@box local]# cat /etc/redhat-release 
CentOS Stream release 9
[root@box local]#

/var/log/php-fpm 中的日志并不是特别具有启发性,但是它们确实表明所有 curl_xxx() 函数都不会产生错误,只是 curl_exec() 似乎没有返回任何数据:

[root@box php-fpm]# pwd
/var/log/php-fpm
[root@box php-fpm]# ls -l
total 8
-rw-------. 1 root   root   2160 Jan  5 15:48 error.log
-rw-r--r--. 1 apache apache 4003 Jan  5 17:08 www-error.log
[root@box php-fpm]# tail -3 www-error.log 
[05-Jan-2024 22:05:12 UTC] PHP Warning:  Trying to access array offset on value of type null in /var/www/html/test.php on line 25
[05-Jan-2024 22:08:57 UTC] PHP Warning:  Trying to access array offset on value of type null in /var/www/html/test.php on line 25
[05-Jan-2024 22:08:57 UTC] PHP Warning:  Trying to access array offset on value of type null in /var/www/html/test.php on line 25
[root@box php-fpm]# tail error.log 
[04-Jan-2024 00:18:23] NOTICE: Terminating ...
[04-Jan-2024 00:18:23] NOTICE: exiting, bye-bye!
[04-Jan-2024 13:21:25] NOTICE: fpm is running, pid 1056
[04-Jan-2024 13:21:25] NOTICE: ready to handle connections
[04-Jan-2024 13:21:25] NOTICE: systemd monitor interval set to 10000ms
[05-Jan-2024 01:08:01] NOTICE: Terminating ...
[05-Jan-2024 01:08:01] NOTICE: exiting, bye-bye!
[05-Jan-2024 15:48:49] NOTICE: fpm is running, pid 1055
[05-Jan-2024 15:48:49] NOTICE: ready to handle connections
[05-Jan-2024 15:48:49] NOTICE: systemd monitor interval set to 10000ms
[root@box php-fpm]# 

我通过 dnf 安装了 httpd、php、php-fpm 及其先决条件。我找不到大量有关 php-fpm 及其配置方法的信息。我找到了文件 /etc/php-fpm.conf 和 /etc/php-fpm.d/www.conf,但它们没有对 curl 的引用。/etc 中只有一个 php.ini 文件。

如果有人遇到并解决了这个问题,我将不胜感激。httpd 配置文件表明可以从 php-fpm 切换到 mod_php。如果 mod_php 仍然可用,我可能会尝试一下。

答案1

事实证明,我本应该更早考虑这个问题:selinux。每当没有充分理由导致某件东西无法工作,但它仍然无法工作时,selinux 和/或firewalld 很可能是问题的一部分。

httpd 的默认 selinux 策略不允许 Web 文档打开任何类型的新文件/流,包括与其他网站的连接。要使 PHP 脚本在启用 selinux 的情况下工作,我必须切换两个 selinux 布尔值:

[root@arch php-fpm]# setsebool -P httpd_can_network_connect 1
[root@arch php-fpm]# setsebool -P httpd_unified 1

然后重新启动httpd。

之后,我的 PHP 脚本的 curl_exec() 调用的 Web 版本能够检索与我从命令行运行脚本时相同的数据。

相关内容