在使用 PHP 进行文件下载或抓取网络资源时,cURL 是最常用的工具之一。一般来说,我们使用 curl_exec() 来执行请求,并同步地等待请求完成。但在某些高级场景中,例如需要等,就必须用到 curl_pause() 这个函数。
本文将深入介绍 curl_pause() 的作用、使用场景,以及如何结合其他 cURL 函数实现更复杂的下载控制。
curl_pause() 是 libcurl 提供的函数,用于控制正在进行中的传输操作,可以对接收(读取)或发送(写入)进行暂停或恢复。
在 PHP 中,这个函数的原型如下:
<span><span><span class="hljs-title function_ invoke__">curl_pause</span></span><span>(CurlHandle </span><span><span class="hljs-variable">$handle</span></span><span>, </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$bitmask</span></span><span>): </span><span><span class="hljs-keyword">int</span></span><span>
</span></span>
其中 $bitmask 参数可以是以下常量的组合:
CURLPAUSE_RECV:暂停接收数据
CURLPAUSE_SEND:暂停发送数据
CURLPAUSE_ALL:暂停发送和接收
CURLPAUSE_CONT:继续传输(解除暂停)
返回值是 CURLcode 类型的状态码,通常为 0 表示成功。
你可能需要根据带宽、用户操作或服务端响应来动态暂停下载。例如,当带宽紧张时,可以暂停某个下载任务,稍后再恢复。
<span><span><span class="hljs-variable">$ch</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_init</span></span><span>(</span><span><span class="hljs-string">"https://example.com/largefile.zip"</span></span><span>);
</span><span><span class="hljs-variable">$fp</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fopen</span></span><span>(</span><span><span class="hljs-string">"largefile.zip"</span></span><span>, </span><span><span class="hljs-string">"w"</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_setopt</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLOPT_FILE, </span><span><span class="hljs-variable">$fp</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_setopt</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLOPT_WRITEFUNCTION, function(</span><span><span class="hljs-variable">$ch</span></span><span>, </span><span><span class="hljs-variable">$data</span></span><span>) </span><span><span class="hljs-keyword">use</span></span><span> (&$</span><span><span class="hljs-title">paused</span></span><span>) {
</span><span><span class="hljs-title">static</span></span><span> $</span><span><span class="hljs-title">total</span></span><span> = 0;
</span><span><span class="hljs-variable">$len</span></span><span> = </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$data</span></span><span>);
</span><span><span class="hljs-variable">$total</span></span><span> += </span><span><span class="hljs-variable">$len</span></span><span>;
</span><span><span class="hljs-comment">// 模拟:下载到1MB就暂停</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$total</span></span><span> >= </span><span><span class="hljs-number">1024</span></span><span> * </span><span><span class="hljs-number">1024</span></span><span> && !</span><span><span class="hljs-variable">$paused</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">curl_pause</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLPAUSE_RECV);
</span><span><span class="hljs-variable">$paused</span></span><span> = </span><span><span class="hljs-literal">true</span></span><span>;
}
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$len</span></span><span>;
});
</span><span><span class="hljs-title function_ invoke__">curl_exec</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-comment">// 稍后恢复</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$paused</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">sleep</span></span><span>(</span><span><span class="hljs-number">5</span></span><span>); </span><span><span class="hljs-comment">// 假设我们等待5秒</span></span><span>
</span><span><span class="hljs-title function_ invoke__">curl_pause</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLPAUSE_CONT);
</span><span><span class="hljs-title function_ invoke__">curl_exec</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
}
</span><span><span class="hljs-title function_ invoke__">curl_close</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$fp</span></span><span>);
</span></span>
在使用 curl_multi_exec() 处理多个并发请求时,curl_pause() 更加重要。你可以精确地暂停某个 handle,而不会影响其他请求。
<span><span><span class="hljs-variable">$mh</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_multi_init</span></span><span>();
</span><span><span class="hljs-variable">$chs</span></span><span> = [];
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$urls</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$url</span></span><span>) {
</span><span><span class="hljs-variable">$ch</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_init</span></span><span>(</span><span><span class="hljs-variable">$url</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_setopt</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLOPT_RETURNTRANSFER, </span><span><span class="hljs-literal">true</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_multi_add_handle</span></span><span>(</span><span><span class="hljs-variable">$mh</span></span><span>, </span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-variable">$chs</span></span><span>[] = </span><span><span class="hljs-variable">$ch</span></span><span>;
}
</span><span><span class="hljs-comment">// 在某些条件下暂停某个请求</span></span><span>
</span><span><span class="hljs-title function_ invoke__">curl_pause</span></span><span>(</span><span><span class="hljs-variable">$chs</span></span><span>[</span><span><span class="hljs-number">0</span></span><span>], CURLPAUSE_RECV);
</span><span><span class="hljs-comment">// 恢复时:</span></span><span>
</span><span><span class="hljs-title function_ invoke__">curl_pause</span></span><span>(</span><span><span class="hljs-variable">$chs</span></span><span>[</span><span><span class="hljs-number">0</span></span><span>], CURLPAUSE_CONT);
</span></span>
并非所有服务器或传输都支持暂停恢复,尤其是在没有 Range 支持的服务器上,暂停可能等同于中断。
如果使用 CURLOPT_RETURNTRANSFER,暂停后无法再使用 curl_exec() 获取剩余数据,需使用 curl_multi 或流式处理。
暂停后数据仍可能在缓冲区中,因此你仍可能看到 WRITEFUNCTION 回调被调用一次。
curl_pause() 为 PHP 提供了对 HTTP 传输行为的更细粒度控制,适用于需要动态控制数据流的高级场景,尤其在文件下载、流媒体处理、多线程任务控制等方面表现出巨大价值。
在使用时应结合 WRITEFUNCTION 回调与 curl_multi 环境,灵活管理传输状态。掌握它,可以为你的网络传输逻辑赋予前所未有的灵活性和控制力。