cURL の書き込みコールバックは、ボディの先頭部分を上限付きで保持し、その上限に達した時点で転送を止められます。意図した停止か別の書き込み失敗かは、自前のフラグで区別します。

宛先 URL が設定済みの新しいハンドルの場合:

$limit = 32768;
$prefix = '';
$limitReached = false;

curl_setopt_array($ch, [
    CURLOPT_PROXY => 'socks5h://proxy.example.net:1080',
    CURLOPT_HEADER => false,
    CURLOPT_WRITEFUNCTION => function ($handle, $chunk)
        use (&$prefix, &$limitReached, $limit) {
        $remaining = $limit - strlen($prefix);
        $prefix .= substr($chunk, 0, $remaining);

        if (strlen($prefix) >= $limit) {
            $limitReached = true;
            return 0;
        }

        return strlen($chunk);
    },
]);

$result = curl_exec($ch);
$error = curl_errno($ch);

$expectedStop = $limitReached && $error === CURLE_WRITE_ERROR;
if ($result === false && !$expectedStop) {
    throw new RuntimeException(curl_error($ch), $error);
}

プロキシ URL の socks5h スキームは、宛先ホスト名の解決をプロキシ側に任せます。示した新しいハンドルで許可された公開宛先を試す場合、SOCKS5 プロキシ一覧のアカウント不要の項目がそのエンドポイントを提供できます。TLS 証明書の検証は通常の設定のままです。

空でないチャンクに対して 0 を返すと、libcurl にはコールバックが渡されたデータを受け取らなかったと伝わります。CURLE_WRITE_ERROR で中断します。ここで想定内とするのは、そのエラーとコールバックの limitReached フラグが揃った場合だけです。

上限より短い応答はそのまま正常に終わります。上限以上では、最後のコールバックがより大きいチャンクを受け取っても、prefix が保持するのは最大 32 KiB です。チャンクの大きさは変動し、要求したバッファサイズは固定長の呼び出しを約束するものではありません。

これが制限するのは保持するボディであり、接続上ですでにバッファされた、または転送されたすべてのバイトではありません。先頭部分はマルチバイト文字、JSON 値、HTML 要素の途中で終わりうるため、完全に解析できる文書だと決めつけないでください。

関連記事