PHP调用Bash脚本清除Cloudflare单URL缓存失败求解决方案
问题:PHP调用Cloudflare缓存清除脚本无输出(手动运行正常)
我遇到了一个问题:我写了Bash脚本用来清除Cloudflare单个URL的缓存,手动通过SSH执行时完全正常,test.log里会显示SUCCESS;但通过PHP的exec()调用这个脚本时,test.log里没有任何输出,说明脚本执行失败了。
我的Bash脚本:
#!/bin/bash if [ -z "$1" ]; then echo "Usage: $0 http://your.domain.com/url" exit 0 fi #get this from Account section in Cloudflare TOKEN="SECRETTOKEN" EMAIL="EMAIL" DOMAIN="DOMAIN" curl -s https://www.cloudflare.com/api_json.html \ -d "a=zone_file_purge" \ -d "tkn=$TOKEN" \ -d "email=$EMAIL" \ -d "z=$DOMAIN" \ -d "url=$1" >> test.log #output to check if this script work
PHP脚本:
<?php $domain = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); $actual_link = $_SERVER[HTTP_REFERER]; exec("/bin/bash /path/to/bkl.sh $actual_link"); echo "Success"; header('Refresh: 5; URL=' . $_SERVER['HTTP_REFERER']); ?>
实现逻辑是:网站上有个按钮,用户点击后触发PHP脚本,调用Bash脚本清除对应文章URL的Cloudflare缓存,然后重定向回文章页。
排查与解决方案
我从几个常见的问题点入手,帮你逐步解决这个问题:
1. 权限问题(最常见)
PHP运行的用户(通常是www-data、apache或nginx)和你SSH登录的用户不是同一个,很可能没有执行脚本或写入日志的权限:
- 给Bash脚本添加执行权限:
chmod +x /path/to/bkl.sh - 确保
test.log所在目录对PHP运行用户有写入权限,比如:# 假设PHP用户是www-data chown www-data:www-data /path/to/test.log chown www-data:www-data /path/to/ # 如果日志在脚本目录,给目录加权限
2. 参数传递的特殊字符问题
$_SERVER['HTTP_REFERER']里可能包含&、空格或其他特殊字符,直接传递给Bash会被错误拆分,导致参数无效。解决方法是用escapeshellarg()转义参数:
修改PHP脚本:
<?php $domain = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); $actual_link = $_SERVER['HTTP_REFERER']; // 转义URL中的特殊字符 $escaped_link = escapeshellarg($actual_link); exec("/bin/bash /path/to/bkl.sh $escaped_link"); echo "Success"; header('Refresh: 5; URL=' . $_SERVER['HTTP_REFERER']); ?>
3. 路径问题(绝对路径才可靠)
PHP的exec()运行时的工作目录不一定是脚本所在目录,相对路径的test.log和curl可能找不到:
- 在Bash脚本里把
curl换成绝对路径(可以用which curl获取,比如/usr/bin/curl) - 把
test.log改成绝对路径,比如/var/log/cloudflare_purge.log,避免相对路径找不到:
修改Bash脚本的最后一行:
/usr/bin/curl -s https://www.cloudflare.com/api_json.html \ -d "a=zone_file_purge" \ -d "tkn=$TOKEN" \ -d "email=$EMAIL" \ -d "z=$DOMAIN" \ -d "url=$1" >> /var/log/cloudflare_purge.log 2>&1
这里的2>&1是把错误输出也写入日志,方便你查看执行失败的具体原因。
4. 捕获PHP执行的调试信息
修改PHP脚本,获取exec()的输出和返回状态,直接在页面上看到执行结果,方便调试:
<?php $domain = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); $actual_link = $_SERVER['HTTP_REFERER']; $escaped_link = escapeshellarg($actual_link); $output = []; $return_code = 0; exec("/bin/bash /path/to/bkl.sh $escaped_link", $output, $return_code); echo "执行返回码:$return_code<br>"; echo "脚本输出:<pre>" . print_r($output, true) . "</pre>"; header('Refresh: 10; URL=' . $_SERVER['HTTP_REFERER']); ?>
返回码为0表示成功,非0就是失败,输出里会有具体的错误提示。
5. 升级到Cloudflare API v4(推荐)
你现在用的是Cloudflare旧版API v1,官方已经推荐使用API v4,稳定性和安全性更好。可以把Bash脚本改成v4版本:
#!/bin/bash if [ -z "$1" ]; then echo "Usage: $0 http://your.domain.com/url" exit 0 fi # 从Cloudflare控制台获取API Token(注意是API Token,不是Global API Key) TOKEN="YOUR_API_TOKEN" # 从域名的Overview页面获取Zone ID ZONE_ID="YOUR_ZONE_ID" /usr/bin/curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"files": ["'"$1"'"]}' >> /var/log/cloudflare_purge.log 2>&1
这个版本不需要邮箱,用Bearer令牌验证,更安全。
内容的提问来源于stack exchange,提问作者DRMTV
相关产品推荐
相关产品推荐

