PHP fgetcsv读取大CSV遇SSL连接重置错误排查求助
问题描述
使用PHP的fgetcsv脚本加载包含115000行的CSV文件并更新数据库,但读取到约111000行时停止,报错:
Warning: fgetcsv(): SSL: Connection reset by peer in "script folder".
每次均在4.8632356325785秒后停止,已调整php.ini中的执行时长、内存限制等参数仍无法解决,错误指向代码行:
while (($data_string = fgetcsv($handle, ";")) !== FALSE) {
相关核心代码如下:
$row = 1; $url = $_POST['url_file']; $handle = fopen($url,"r"); $done = 0; while (($data_string = fgetcsv($handle, ";")) !== FALSE) { $num = count($data_string); $row++; $ean13 = ""; $price = ""; $quantity = ""; $data = explode(";",$data_string[0]); echo ob_get_clean();
问题原因及解决方案
核心原因
这个错误是远程服务器主动断开了SSL连接,和PHP的执行时间、内存限制无关——报错明确指向SSL层面的连接重置,且每次触发时间固定,说明是远程端设置了连接超时阈值(比如5秒内的连接时长或数据传输量限制),当脚本持续读取超过该阈值后,对方服务器强制断开连接。
同时你的代码存在两个加剧问题的细节:
fgetcsv参数使用错误:第二个参数应为每行最大字节数,你传入了分隔符";",导致fgetcsv无法正确解析行,反而把分隔符当成字节数限制,引发读取不完整,拖慢读取速度,更容易触发远程超时。- 循环内频繁调用
echo ob_get_clean():强制清空输出缓冲区并输出的操作会增加IO开销,拉长单循环耗时,更快达到远程服务器的超时限制。
解决步骤
修复
fgetcsv参数错误
正确用法是将分隔符放在第三个参数,第二个参数传0表示不限制行长度:while (($data_string = fgetcsv($handle, 0, ";")) !== FALSE) {修正后能让
fgetcsv正常解析行,提升读取效率。先下载CSV到本地再处理
直接读取远程URL易受网络波动、服务器限制影响,建议先将文件下载到本地:$url = $_POST['url_file']; $localPath = './temp_csv_file.csv'; // 用curl下载更稳定,支持超时设置 $ch = curl_init($url); $fp = fopen($localPath, 'w'); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_TIMEOUT, 300); // 设置下载超时为5分钟 curl_exec($ch); curl_close($ch); fclose($fp); // 读取本地文件 $handle = fopen($localPath, "r");本地读取完全规避远程连接超时问题,效率也更高。
优化循环内的IO与冗余操作
- 去掉循环内的
echo ob_get_clean(),如需输出进度,可每处理N行(如1000行)输出一次,减少IO次数; - 移除多余的
explode(";",$data_string[0])——fgetcsv已经按;将行拆分为数组,直接使用$data_string即可。
优化后的循环示例:
$row = 1; while (($data_string = fgetcsv($handle, 0, ";")) !== FALSE) { $row++; $ean13 = ""; $price = ""; $quantity = ""; $data = $data_string; // 直接使用fgetcsv解析后的数组 // 每1000行输出一次进度 if ($row % 1000 == 0) { echo "已处理{$row}行\n"; ob_flush(); flush(); } }- 去掉循环内的
若必须远程读取,优化连接稳定性
可通过添加HTTP头保持连接,或临时关闭SSL证书验证(仅在证书有问题时使用):$opts = [ 'http' => [ 'header' => "Connection: keep-alive\r\n" ], 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false ] ]; $context = stream_context_create($opts); $handle = fopen($url, "r", false, $context);
内容的提问来源于stack exchange,提问作者PicenoComputers
相关产品推荐
相关产品推荐

