Featured image of post PHP解决curl响应过大时爆内存的问题

PHP解决curl响应过大时爆内存的问题

PHP 调用 http 服务此前一直都是封装的 curl,这事儿我也干过不少次了,不过今天碰到了一个新问题。

接口是 clickhouse 服务,查询的响应体比较大,放在内存里要超过 1 G,再继续修改 max_memory_limit 意义不大,所以就希望把结果直接放入文件,然后逐行读取处理,以减少整个过程的内存消耗,那么怎么把结果写入文件呢?

相关的选项是这个

1
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

这个选项设置为 1/true 时,就会把结果放在 $response = curl_exec($ch) 里的这个 $response 里,这也是现在这个问题的来源,$response 太大了。但如果把它设置为 0/false,它会写到标准输出,又没办法用代码处理。

参考了这个问题,给出了两个思路。

Bilibili 视频av号或BV号错误!请检查视频av号或BV号是否正确

当前视频av或BV号://player.bilibili.com/player.html?aid=1302993488&bvid=BV1DM4m1Q71a&cid=1499653065&p=1,视频分P:1

直接写入文件

1
2
3
$fh = fopen($file, 'w');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_FILE, $fh);

一定要注意的是,如果 $file 对应的目录不存在,则无法自动创建目录,整个过程会失败。

写回调方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# setup a global file pointer
$GlobalFileHandle = null;

function saveRemoteFile($url, $filename) {
  global $GlobalFileHandle;

  set_time_limit(0);

  # Open the file for writing...
  $GlobalFileHandle = fopen($filename, 'w+');

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_FILE, $GlobalFileHandle);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);

  # Assign a callback function to the CURL Write-Function
  curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curlWriteFile');

  # Exceute the download - note we DO NOT put the result into a variable!
  curl_exec($ch);

  # Close CURL
  curl_close($ch);

  # Close the file pointer
  fclose($GlobalFileHandle);
}

function curlWriteFile($cp, $data) {
  global $GlobalFileHandle;
  $len = fwrite($GlobalFileHandle, $data);
  return $len;
}

这个看起来有点多此一举了,因为不指定这个回调函数也会写入这个方法,只是无法对写入的方式做一些精细控制,这个回调函数多数时候是不需要的,因为我更倾向于先整体写入文件,上层的方法再根据业务需求去处理,而不是在这里决定。

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy