PHP curl_pause函数

定义和用法

curl_pause() 函数用于暂停和恢复cURL连接。这个函数在需要临时停止数据传输(如流量控制、限速等场景)时非常有用。

注意:此函数在PHP 5.5.0及以上版本可用,并且需要cURL 7.18.0或更高版本支持。

语法

curl_pause ( CurlHandle $handle , int $flags ) : int

参数

参数 描述
handle curl_init() 返回的 cURL 句柄。
flags 控制暂停行为的标志位(参见下面的选项表)。

返回值

返回错误代码,成功时返回 CURLE_OK (0)。

可用选项

选项 描述
CURLPAUSE_RECV 1 暂停数据接收
CURLPAUSE_SEND 4 暂停数据发送
CURLPAUSE_ALL 5 暂停所有数据传输(接收和发送)
CURLPAUSE_CONT 0 恢复暂停的数据传输

示例

示例 1:基本用法 - 暂停和恢复数据传输

// 初始化cURL会话
$ch = curl_init();

// 设置cURL选项
curl_setopt_array($ch, [
    CURLOPT_URL => 'https://httpbin.org/drip?duration=5&numbytes=1000',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_WRITEFUNCTION => function($ch, $data) {
        static $total = 0;
        $total += strlen($data);
        echo "接收到 " . strlen($data) . " 字节数据,总计: {$total} 字节\n";

        // 当接收到500字节时暂停接收
        if ($total >= 500) {
            echo "已达到500字节,暂停接收...\n";
            curl_pause($ch, CURLPAUSE_RECV);

            // 3秒后恢复接收
            echo "等待3秒后恢复...\n";
            sleep(3);
            curl_pause($ch, CURLPAUSE_CONT);
            echo "恢复接收数据\n";
        }

        return strlen($data);
    }
]);

// 执行cURL请求
$result = curl_exec($ch);

if (curl_errno($ch)) {
    echo 'cURL错误: ' . curl_error($ch);
}

curl_close($ch);

示例 2:实现简单的流量控制

class RateLimitedDownload {
    private $ch;
    private $bytesPerSecond;
    private $lastTime;
    private $bytesTransferred;

    public function __construct($url, $bytesPerSecond = 1024) {
        $this->ch = curl_init();
        $this->bytesPerSecond = $bytesPerSecond;
        $this->lastTime = microtime(true);
        $this->bytesTransferred = 0;

        curl_setopt_array($this->ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_WRITEFUNCTION => [$this, 'writeCallback']
        ]);
    }

    public function writeCallback($ch, $data) {
        $dataLength = strlen($data);
        $this->bytesTransferred += $dataLength;

        // 计算应该传输的时间
        $expectedTime = $this->bytesTransferred / $this->bytesPerSecond;
        $actualTime = microtime(true) - $this->lastTime;

        // 如果传输太快,暂停一下
        if ($actualTime < $expectedTime) {
            $sleepTime = ($expectedTime - $actualTime) * 1000000; // 转换为微秒
            if ($sleepTime > 10000) { // 至少睡眠10毫秒
                curl_pause($this->ch, CURLPAUSE_RECV);
                usleep((int)$sleepTime);
                curl_pause($this->ch, CURLPAUSE_CONT);
            }
        }

        echo "已下载: {$this->bytesTransferred} 字节, 速率: " .
             round($this->bytesTransferred / max($actualTime, 0.001)) . " 字节/秒\n";

        return $dataLength;
    }

    public function download() {
        $this->lastTime = microtime(true);
        $result = curl_exec($this->ch);

        if (curl_errno($this->ch)) {
            throw new Exception('下载错误: ' . curl_error($this->ch));
        }

        return $result;
    }

    public function __destruct() {
        if ($this->ch) {
            curl_close($this->ch);
        }
    }
}

// 使用示例:限制下载速率为10KB/秒
try {
    $downloader = new RateLimitedDownload(
        'https://httpbin.org/stream-bytes/50000',
        10 * 1024 // 10KB/秒
    );
    $downloader->download();
} catch (Exception $e) {
    echo $e->getMessage() . "\n";
}

示例 3:在回调函数中动态控制数据传输

function controlledDownload($url, $controlCallback) {
    $ch = curl_init();

    $downloadInfo = [
        'total_size' => 0,
        'chunk_count' => 0,
        'start_time' => microtime(true)
    ];

    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => false,
        CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$downloadInfo, $controlCallback) {
            $chunkSize = strlen($data);
            $downloadInfo['total_size'] += $chunkSize;
            $downloadInfo['chunk_count']++;

            // 调用控制回调函数决定是否暂停
            $action = $controlCallback($downloadInfo, $chunkSize);

            if ($action === 'pause_recv') {
                curl_pause($ch, CURLPAUSE_RECV);
                // 模拟处理时间
                usleep(100000); // 100毫秒
                curl_pause($ch, CURLPAUSE_CONT);
            } elseif ($action === 'pause_all') {
                curl_pause($ch, CURLPAUSE_ALL);
                sleep(1); // 暂停1秒
                curl_pause($ch, CURLPAUSE_CONT);
            }

            echo "块 {$downloadInfo['chunk_count']}: {$chunkSize} 字节, " .
                 "总计: {$downloadInfo['total_size']} 字节\n";

            return $chunkSize;
        },
        CURLOPT_NOPROGRESS => false,
        CURLOPT_PROGRESSFUNCTION => function($ch, $dlTotal, $dlNow, $ulTotal, $ulNow) {
            if ($dlTotal > 0) {
                $percent = round(($dlNow / $dlTotal) * 100, 2);
                echo "进度: {$percent}% ({$dlNow}/{$dlTotal} 字节)\n";
            }
            return 0;
        }
    ]);

    $result = curl_exec($ch);

    if (curl_errno($ch)) {
        echo '错误: ' . curl_error($ch) . "\n";
    } else {
        $downloadTime = microtime(true) - $downloadInfo['start_time'];
        $speed = $downloadInfo['total_size'] / $downloadTime;
        echo "下载完成: {$downloadInfo['total_size']} 字节, " .
             "耗时: " . round($downloadTime, 2) . " 秒, " .
             "平均速度: " . round($speed, 2) . " 字节/秒\n";
    }

    curl_close($ch);
    return $result;
}

// 控制回调函数 - 每接收3个数据块暂停一次
$controlCallback = function($info, $chunkSize) {
    if ($info['chunk_count'] % 3 === 0) {
        return 'pause_recv';
    }
    return 'continue';
};

// 使用示例
controlledDownload('https://httpbin.org/bytes/50000', $controlCallback);

示例 4:上传数据时的暂停控制

function controlledUpload($url, $data, $chunkSize = 1024) {
    $ch = curl_init();

    // 准备上传数据
    $dataLength = strlen($data);
    $uploaded = 0;

    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_READFUNCTION => function($ch, $fd, $length) use ($data, &$uploaded, $dataLength, $chunkSize) {
            static $position = 0;

            if ($position >= $dataLength) {
                return ''; // 数据已发送完毕
            }

            // 读取指定大小的数据块
            $chunk = substr($data, $position, min($chunkSize, $dataLength - $position));
            $position += strlen($chunk);
            $uploaded += strlen($chunk);

            $percent = round(($position / $dataLength) * 100, 2);
            echo "上传进度: {$percent}% ({$position}/{$dataLength} 字节)\n";

            // 每上传1KB暂停100毫秒,模拟限速
            if ($uploaded >= 1024) {
                $uploaded = 0;
                curl_pause($ch, CURLPAUSE_SEND);
                usleep(100000); // 100毫秒
                curl_pause($ch, CURLPAUSE_CONT);
            }

            return $chunk;
        },
        CURLOPT_INFILESIZE => $dataLength
    ]);

    echo "开始上传 {$dataLength} 字节数据到 {$url}\n";
    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        echo '上传错误: ' . curl_error($ch) . "\n";
    } else {
        echo "上传完成,服务器响应: " . strlen($response) . " 字节\n";
    }

    curl_close($ch);
    return $response;
}

// 生成测试数据
$testData = str_repeat('0123456789', 1000); // 10KB数据

// 使用示例
controlledUpload(
    'https://httpbin.org/post',
    $testData,
    512 // 每次上传512字节
);

选项详解

CURLPAUSE_RECV

暂停数据接收。当设置此标志时,cURL将暂停从服务器接收数据,直到调用 CURLPAUSE_CONT

CURLPAUSE_SEND

暂停数据发送。当设置此标志时,cURL将暂停向服务器发送数据,直到调用 CURLPAUSE_CONT

CURLPAUSE_ALL

暂停所有数据传输(接收和发送)。这是 CURLPAUSE_RECV | CURLPAUSE_SEND 的组合。

CURLPAUSE_CONT

恢复暂停的数据传输。使用此标志可以恢复之前被暂停的接收或发送操作。

注意事项

版本要求:curl_pause() 函数需要PHP 5.5.0或更高版本,并且需要cURL 7.18.0或更高版本支持。
使用场景:这个函数在以下场景中特别有用:
  • 实现自定义的流量控制和限速
  • 在数据传输过程中插入处理逻辑
  • 模拟网络延迟或不稳定连接
  • 实现断点续传功能
注意事项:在回调函数(如 CURLOPT_WRITEFUNCTIONCURLOPT_READFUNCTION)中调用 curl_pause() 时,必须传递正确的cURL句柄参数。

常见问题

Q: curl_pause() 可以在任何地方调用吗?

A: curl_pause() 主要用于在cURL回调函数中调用,但也可以在传输过程中的其他地方调用。不过,在回调函数外部使用时需要谨慎,因为可能会影响正在进行的传输。

Q: 暂停操作会影响连接吗?

A: 暂停操作不会关闭连接,只是临时停止数据传输。连接保持打开状态,可以在恢复后继续传输数据。

相关函数