在使用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環境,靈活管理傳輸狀態。掌握它,可以為你的網絡傳輸邏輯賦予前所未有的靈活性和控制力。