curl_multi_add_handleは、PHPで複数の同時HTTP要求を処理する際のCURLマルチインターフェイスの重要な関数の1つです。これにより、単一のカールハンドルをマルチハンドルセッションに結合できるため、非ブロッキングの同時処理を可能にします。このメカニズムは、大きなファイルを処理する必要があるシナリオを充電およびダウンロードするために非常に役立ちます。
ブロックアップロードの基本的なアイデアは、大きなファイルをいくつかの小さな部分に分割し、これらの小さな部分を同時にアップロードすることです。 curl_multi_add_handleを使用すると、アップロード効率を大幅に改善できます。
大きなファイルを複数の小さなファイルチャンクに分割します( Fread()で手動でチャンキングすることができます)。
各ブロックの独立したカール要求を作成します(PutまたはPostメソッドを使用)。
これらのリクエストハンドルをCurl_multi_init()によって作成されたMulti Handle Managerに追加します。
curl_multi_exec()を使用して、すべてのアップロードリクエストを駆動して同時に実行します。
<span><span><span class="hljs-variable">$multiHandle</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_multi_init</span></span><span>();
</span><span><span class="hljs-variable">$chunkFiles</span></span><span> = [</span><span><span class="hljs-string">'chunk1.bin'</span></span><span>, </span><span><span class="hljs-string">'chunk2.bin'</span></span><span>, </span><span><span class="hljs-string">'chunk3.bin'</span></span><span>]; </span><span><span class="hljs-comment">// サンプルブロックファイル</span></span><span>
</span><span><span class="hljs-variable">$curlHandles</span></span><span> = [];
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$chunkFiles</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$index</span></span><span> => </span><span><span class="hljs-variable">$file</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-string">'https://example.com/upload_chunk'</span></span><span>);
</span><span><span class="hljs-variable">$fileData</span></span><span> = </span><span><span class="hljs-title function_ invoke__">file_get_contents</span></span><span>(</span><span><span class="hljs-variable">$file</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_setopt</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLOPT_POSTFIELDS, </span><span><span class="hljs-variable">$fileData</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_HTTPHEADER, [
</span><span><span class="hljs-string">'Content-Type: application/octet-stream'</span></span><span>,
</span><span><span class="hljs-string">'Content-Length: '</span></span><span> . </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$fileData</span></span><span>),
</span><span><span class="hljs-string">'X-Chunk-Index: '</span></span><span> . </span><span><span class="hljs-variable">$index</span></span><span>
]);
</span><span><span class="hljs-title function_ invoke__">curl_multi_add_handle</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-variable">$curlHandles</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-variable">$running</span></span><span> = </span><span><span class="hljs-literal">null</span></span><span>;
</span><span><span class="hljs-keyword">do</span></span><span> {
</span><span><span class="hljs-title function_ invoke__">curl_multi_exec</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$running</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_multi_select</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>);
} </span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-variable">$running</span></span><span> > </span><span><span class="hljs-number">0</span></span><span>);
</span><span><span class="hljs-comment">// リソースをクリーンアップします</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$curlHandles</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$ch</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">curl_multi_remove_handle</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</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__">curl_multi_close</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>);
</span></span>
ブロックダウンロードの場合、同じメカニズムが適用されます。範囲ヘッダーを設定することにより、ファイルの特定のバイト間隔を要求し、ファイル全体のさまざまな部分を同時にダウンロードしてから、これらの部分をマージすることができます。
ターゲットファイルの合計サイズを取得します。
たとえば、それを複数のセグメントに分けます。たとえば、それ自体セグメント1MB。
各セグメントのレンジヘッダーを使用してカール要求を作成します。
curl_multi_add_handleを使用して、同時ダウンロードのためにマルチハンドルセッションを追加します。
ダウンロード結果を順番にマージします。
<span><span><span class="hljs-variable">$url</span></span><span> = </span><span><span class="hljs-string">'https://example.com/largefile.zip'</span></span><span>;
</span><span><span class="hljs-variable">$fileSize</span></span><span> = </span><span><span class="hljs-number">10000000</span></span><span>; </span><span><span class="hljs-comment">// ファイルサイズがあると仮定します10MB</span></span><span>
</span><span><span class="hljs-variable">$chunkSize</span></span><span> = </span><span><span class="hljs-number">1000000</span></span><span>; </span><span><span class="hljs-comment">// 各ピース1MB</span></span><span>
</span><span><span class="hljs-variable">$multiHandle</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_multi_init</span></span><span>();
</span><span><span class="hljs-variable">$curlHandles</span></span><span> = [];
</span><span><span class="hljs-variable">$results</span></span><span> = [];
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$start</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$start</span></span><span> < </span><span><span class="hljs-variable">$fileSize</span></span><span>; </span><span><span class="hljs-variable">$start</span></span><span> += </span><span><span class="hljs-variable">$chunkSize</span></span><span>) {
</span><span><span class="hljs-variable">$end</span></span><span> = </span><span><span class="hljs-title function_ invoke__">min</span></span><span>(</span><span><span class="hljs-variable">$start</span></span><span> + </span><span><span class="hljs-variable">$chunkSize</span></span><span> - </span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-variable">$fileSize</span></span><span> - </span><span><span class="hljs-number">1</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_setopt</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, CURLOPT_RANGE, </span><span><span class="hljs-string">"<span class="hljs-subst">$start</span></span></span><span>-</span><span><span class="hljs-subst">$end</span></span><span>");
</span><span><span class="hljs-title function_ invoke__">curl_multi_add_handle</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-variable">$curlHandles</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-variable">$running</span></span><span> = </span><span><span class="hljs-literal">null</span></span><span>;
</span><span><span class="hljs-keyword">do</span></span><span> {
</span><span><span class="hljs-title function_ invoke__">curl_multi_exec</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$running</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_multi_select</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>);
} </span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-variable">$running</span></span><span> > </span><span><span class="hljs-number">0</span></span><span>);
</span><span><span class="hljs-comment">// 結果を収集してマージします</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$curlHandles</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$ch</span></span><span>) {
</span><span><span class="hljs-variable">$results</span></span><span>[] = </span><span><span class="hljs-title function_ invoke__">curl_multi_getcontent</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_multi_remove_handle</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</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__">curl_multi_close</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>);
</span><span><span class="hljs-comment">// 完全なファイルに書き込みます</span></span><span>
</span><span><span class="hljs-title function_ invoke__">file_put_contents</span></span><span>(</span><span><span class="hljs-string">'merged_file.zip'</span></span><span>, </span><span><span class="hljs-title function_ invoke__">implode</span></span><span>(</span><span><span class="hljs-string">''</span></span><span>, </span><span><span class="hljs-variable">$results</span></span><span>));
</span></span>
接続の制限:並行性が多すぎると、サーバーが接続を拒否する可能性があります。並行性の数(毎回5処理など)を制御することをお勧めします。
エラー処理: curl_error()およびcurl_multi_info_read()を使用して、各リクエストのステータスを確認します。
タイムアウト設定:個々のリクエストがプロセス全体に巻き込まれないように、 curlopt_timeoutを設定することをお勧めします。
curl_multi_add_handleは、同時のHTTP要求を構築するためのコアツールの1つです。チャンク戦略を組み合わせて、大きなファイルのタスクをアップロードしてダウンロードすることは効率的に処理できます。リクエストの合理的な組織、同時制御、およびエラー処理は、実際のアプリケーションで考慮する必要がある重要な要因です。 PHPネットワーク通信のパフォーマンスと信頼性を大幅に改善できます。