兼容 PHP 8.5:消除全部弃用调用
PHP 8.5 把 curl_close()/finfo_close() 这类"空操作函数"标为弃用, 并把预定义局部变量 http_response_header 标为弃用(编译期判定,@ 与三元短路都压不住)。 - 句柄关闭收进 fb_curl_close()/fb_finfo_close():仅 PHP < 8.0 真正调用, 新版本直接跳过(8.0 起句柄随引用计数释放),保留 7.4 兼容 - 响应头读取改用 http_get_last_response_headers()(8.4+); 老版本经 get_defined_vars() 从作用域变量表取,源码不再出现已弃用标识符 - 新 API 是全局状态,用「请求前基线」比对,避免把上一次的残留头当成本次结果 - 安装体检与 README 的推荐版本区间更新为 8.1~8.5 验证:PHP 8.5.12 下五套测试全绿(25/25、22/22、60/60、7/7、反向 4 组全被抓住), error_log 零条弃用记录;PHP 8.4.25 同样全绿。
This commit is contained in:
+1
-1
@@ -362,7 +362,7 @@ function fb_attach_verify(array $list) {
|
||||
$ct = '';
|
||||
if (function_exists('finfo_open')) {
|
||||
$f = @finfo_open(FILEINFO_MIME_TYPE);
|
||||
if ($f) { $ct = strtolower(trim((string)@finfo_file($f, $p))); @finfo_close($f); }
|
||||
if ($f) { $ct = strtolower(trim((string)@finfo_file($f, $p))); fb_finfo_close($f); }
|
||||
} elseif (function_exists('mime_content_type')) {
|
||||
$ct = strtolower(trim((string)@mime_content_type($p)));
|
||||
}
|
||||
|
||||
+17
-7
@@ -490,7 +490,7 @@ function fb_oss_put_file($key, $path, $mime = 'application/octet-stream') {
|
||||
$errno = curl_errno($ch);
|
||||
$errtxt = curl_error($ch);
|
||||
$status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
fb_curl_close($ch);
|
||||
if ($errno) { @fclose($fp); return [false, '上传请求失败:' . $errtxt, $status]; }
|
||||
$errBody = (string)$body;
|
||||
} else {
|
||||
@@ -502,9 +502,15 @@ function fb_oss_put_file($key, $path, $mime = 'application/octet-stream') {
|
||||
'timeout' => $timeout,
|
||||
'ignore_errors' => true,
|
||||
]]);
|
||||
$hdrBefore = FB_HAS_HTTP_LAST_HDRS ? http_get_last_response_headers() : null;
|
||||
$body = @file_get_contents($url, false, $ctx);
|
||||
if (isset($http_response_header) && is_array($http_response_header)
|
||||
&& preg_match('#^HTTP/\S+\s+(\d{3})#', $http_response_header[0], $m)) {
|
||||
// PHP 8.5 起预定义局部变量 http_response_header 已弃用(连 @ 都压不住),
|
||||
// 8.4 起改用 http_get_last_response_headers();老版本仍读局部变量。
|
||||
// 三元短路:新版本不执行第二支,老版本也不碰第一支。
|
||||
$hdrRaw = FB_HAS_HTTP_LAST_HDRS
|
||||
? fb_last_http_headers($hdrBefore)
|
||||
: fb_local_http_headers(get_defined_vars());
|
||||
if ($hdrRaw && preg_match('#^HTTP/\S+\s+(\d{3})#', $hdrRaw[0], $m)) {
|
||||
$status = (int)$m[1];
|
||||
}
|
||||
$errBody = ($body === false ? '' : (string)$body);
|
||||
@@ -588,7 +594,7 @@ function fb_oss_stream_get($key, $rangeHeader = '', array $subResource = [], $on
|
||||
$errno = curl_errno($ch);
|
||||
$errtxt = curl_error($ch);
|
||||
$st2 = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
fb_curl_close($ch);
|
||||
if ($st2 > 0) { $status = $st2; }
|
||||
if (!$statusFired && is_callable($onStatus)) { $onStatus($status); }
|
||||
|
||||
@@ -685,7 +691,7 @@ function fb_http($method, $url, array $opt = []) {
|
||||
$bad = ($raw === false) || curl_errno($ch);
|
||||
$hsz = (int)curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$st = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
fb_curl_close($ch);
|
||||
if ($bad) { return [0, [], '']; }
|
||||
return [$st, fb_parse_headers(substr((string)$raw, 0, $hsz)), (string)substr((string)$raw, $hsz)];
|
||||
}
|
||||
@@ -698,12 +704,16 @@ function fb_http($method, $url, array $opt = []) {
|
||||
];
|
||||
if ($noproxy) { $streamOpt['proxy'] = ''; $streamOpt['request_fulluri'] = false; }
|
||||
$ctx = stream_context_create(['http' => $streamOpt]);
|
||||
$hdrBefore = FB_HAS_HTTP_LAST_HDRS ? http_get_last_response_headers() : null;
|
||||
$body = @file_get_contents($url, false, $ctx);
|
||||
|
||||
$status = 0; $rawHead = '';
|
||||
if (isset($http_response_header) && is_array($http_response_header)) {
|
||||
$hdrRaw = FB_HAS_HTTP_LAST_HDRS
|
||||
? fb_last_http_headers($hdrBefore)
|
||||
: fb_local_http_headers(get_defined_vars());
|
||||
if ($hdrRaw) {
|
||||
$lines = [];
|
||||
foreach ($http_response_header as $line) {
|
||||
foreach ($hdrRaw as $line) {
|
||||
if (preg_match('#^HTTP/\S+\s+(\d{3})#i', $line, $m)) { $status = (int)$m[1]; $lines = []; }
|
||||
else { $lines[] = $line; }
|
||||
}
|
||||
|
||||
@@ -347,6 +347,65 @@ function fb_admin_set_password($pw) {
|
||||
return fb_set_setting('admin.password_hash', password_hash((string)$pw, PASSWORD_DEFAULT));
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭一个 curl 句柄(跨版本安全)。
|
||||
* --------------------------------------------------------------
|
||||
* PHP 8.0 起 CurlHandle 是对象,句柄随引用计数自动释放,curl_close() 变成空操作;
|
||||
* PHP 8.5 起官方把这类"空操作函数"标为弃用,调用会写 E_DEPRECATED 日志。
|
||||
* 但 PHP 7.4 上它仍是真的释放动作(项目最低支持 7.4),所以只在新版本上跳过。
|
||||
*/
|
||||
function fb_curl_close($ch) {
|
||||
if (PHP_VERSION_ID < 80000 && $ch !== null) { @curl_close($ch); }
|
||||
}
|
||||
|
||||
/** 关闭一个 finfo 句柄(跨版本安全;理由同 fb_curl_close) */
|
||||
function fb_finfo_close($f) {
|
||||
if (PHP_VERSION_ID < 80000 && $f !== null) { @finfo_close($f); }
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 8.4+ 提供 http_get_last_response_headers();PHP 8.5 起,旧的预定义局部变量
|
||||
* http_response_header 已弃用(实测连 @ 抑制符都压不住,会照写 E_DEPRECATED)。
|
||||
* 这里探测一次存成常量,供各调用点做三元短路 —— 关键点:未取中的分支不会求值,
|
||||
* 所以新版本上根本不会去读那个已被弃用的变量。
|
||||
*/
|
||||
if (!defined('FB_HAS_HTTP_LAST_HDRS')) {
|
||||
define('FB_HAS_HTTP_LAST_HDRS', function_exists('http_get_last_response_headers'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取「上一次 http(s) 流请求」的响应头(仅 PHP 8.4+ 可调用本函数)。
|
||||
* ★ 新 API 是全局状态:若本次请求压根没发出去,它会返回 *上一次* 的残留头,
|
||||
* 把旧状态当成新结果。所以要求传入请求前的基线 $before,未变化即视为「本次没有头」。
|
||||
* @param array|null $before 请求前 http_get_last_response_headers() 的快照
|
||||
* @return array
|
||||
*/
|
||||
function fb_last_http_headers($before = null) {
|
||||
if (!function_exists('http_get_last_response_headers')) { return []; }
|
||||
$h = http_get_last_response_headers();
|
||||
$h = is_array($h) ? $h : [];
|
||||
if ($before !== null && $h === (array)$before) { return []; }
|
||||
return $h;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从「当前作用域变量表」里取预定义变量 http_response_header(仅 PHP < 8.4 需要)。
|
||||
* --------------------------------------------------------------
|
||||
* 为什么不用直接读变量:PHP 8.5 对该变量的弃用是【编译期】判定的 —— 实测把它写在
|
||||
* 三元运算的「不该执行」那一支里照样报警,`@` 也压不住。也就是说,只要源码里出现
|
||||
* 这个标识符就会被记日志。唯一干净的做法是根本不去引用它,改用 get_defined_vars()
|
||||
* 拿作用域变量表,再按键名取值。
|
||||
* ⚠️ 必须在发起请求的【同一作用域】调用($vars 由调用方传 get_defined_vars())。
|
||||
* @param array $vars get_defined_vars() 的结果
|
||||
* @return array
|
||||
*/
|
||||
function fb_local_http_headers($vars) {
|
||||
if (!is_array($vars)) { return []; }
|
||||
$k = 'http_response_header';
|
||||
if (!isset($vars[$k]) || !is_array($vars[$k])) { return []; }
|
||||
return $vars[$k];
|
||||
}
|
||||
|
||||
/** 写一条操作日志 */
|
||||
function fb_mod_log($action, $threadId = null, $detail = '') {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user