linux环境下curl上传文件设置postfiled导致php-fpm子进程崩溃
1. 问题描述
1). 出现问题过程
1.我在使用curl请求接口时,突然出现了请求某几个接口时发起请求的一端报502的情况,但是502出现以后再次进入其它页面也是很正常的,在查看nginx日志以后显示:
2024/10/21 09:36:00 [error] 21876#21876: *3150 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: , server: localhost, request: "GET /index.php/Admin/index/index/clientid/58174.html HTTP/1.1", upstream: "fastcgi://unix:/home/im_user/im_server/im_webserver/php/var/php.sock:", host: "ip:8000", referrer: "http://ip:8000/index.php/Home/login/index/clientid/58174.html"
2.接着我去查询了php-fpm的错误日志,内容是php-fpm的子进程退出了,又重新启动了,导致在报502以后其它页面还是正常的:
[21-Oct-2024 09:36:56] WARNING: [pool www] child 25252 exited with code 127 after 228293.010424 seconds from start
[21-Oct-2024 09:36:56] NOTICE: [pool www] child 30319 started
日志中可以看进程退出又重启的过程。
2). 代码排查定位
1.在看日志不确定以后我去查看了curl的相关代码
function test($url,$post_data = array(), $timeout = 5, $method = CURL_POST,$header=[])
{
$methos_m = ['GET', 'POST', 'PUT', 'DELETE'];
$method=$methos_m[$method];
$method = strtoupper($method);
if (!in_array($method, $methos_m)) {
return false;
}
switch ($method) {
case "PUT":
$header[] = "X-HTTP-Method-Override: PUT";
break;
case "DELETE":
$header[] = "X-HTTP-Method-Override: DELETE";
break;
default:
}
$data = $post_data ;
$ch = curl_init();
// https请求 不验证证书和hosts
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt ($ch, CURLOPT_URL, $url);
if ($header){
curl_setopt ($ch, CURLOPT_HTTPHEADER, $header);
}
if ($method=='POST'){
curl_setopt ($ch, CURLOPT_POST, 1);
}
if($data){
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_HEADER, false);
$file_contents = curl_exec($ch);
$res = curl_error($ch);
$code = curl_errno($ch);
curl_close($ch);
return $file_contents;
}
2.在日志加断点以后发现问题出现于
if($data){
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
在$data为数组传值时设置CURLOPT_POSTFIELDS会导致php-fpm子进程崩溃,这个我并不能理解其中的原理
3). 尝试修改出现的后续问题
1.http_build_query处理
在确定参数问题以后我通过http_build_query进行参数的处理
if (is_array($data))
{
$data=http_build_query($data);
}
这样处理了以后常规参数不再报导致php-fpm退出
2.处理以后文件传输问题
因为需求上有一些服务器之间的文件传输通过curl进行,类似于
$a['file']=new \CURLFile(__DIR__.'/test.php');
$res =test("http://127.0.0.1:8000/test.php",$a);
这样的传输方式通过http_build_query会导致最终只能传输文件路径,
但是不通过http_build_query会导致php-fpm子进程崩溃
<2024-10-21 10:38>补充:在尝试php版本替换为php7.4以后不会出现传入数组导致子进程崩溃的问题
4). 当前系统
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
5). php版本
php版本:8.3.9
2. 当前疑惑
是否有能处理curl_setopt($ch, CURLOPT_POSTFIELDS, $data);传入数组时导致php-fpm子进程退出,
或者兼容处理curl传输文件处理的方式
经过反复调试,在寻找了一台干净的centos机器上对php8.3.9使用了同样的参数进行重新编译,过程中缺少的依赖直接使用yum进行升级,再次调试的时候这个问题没有再出现,应该是运维在编译时的环境影响了curl的功能