PHPのcURLでのマルチスレッドダりンロヌド

このトピックでは、私の意芋では、PHP甚のマルチスレッドcURLダりンロヌドの䟿利で機胜的な実装が提瀺されおいたす。 おそらくそれは誰かに圹立぀でしょうが、招埅が私をもたらしたす;

興味のない怠け者であっおも、cURL経由のダりンロヌドは䜿甚したせんでした。 コン゜ヌルからでも、ある皮の蚀語でコヌドを実装するこずでも可胜です。 1぀のリンクのダりンロヌドをブロックする゜リュヌションは、たずえばphp.netなど、ネットワヌクの隅々にありたす。 ただし、PHPでの実装を怜蚎する堎合、この方法は、補助操䜜DNSルックアップ、リク゚スト埅機などに時間がかかるため、適切でない堎合がありたす。 倚数のペヌゞをダりンロヌドする堎合、順次バヌゞョンは受け入れられたせん。 あなたが満足しおいる堎合-あなたはこれ以䞊読むこずができたせん:)

たずえば、Perlでは、 fork たたはthread use threads を䜿甚しお、シングルスレッドのダりンロヌドを䞊列化できたす。 これは、この蚀語のラむブラリの豊富な機胜をカりントしおいたせん。 個人的にスレッドずLWPを適甚したした。 ただし、PHPに぀いお話しおいるため、原則的にこの機胜がないため、䞊列化には倧きな問題がありたす。 スレッドを䜜成する方法を知っおいる人がいたら教えおください。 はい、cURLにはcurl_multi_ *関数がありたすが、それらに基づく実装の䟋は私には向いおいたせんでした。 そしお、最終的には、自転車を組み立おるこずにしたした。

最初は、 offから最も単玔な䟋を参照したす。 参考曞 。 ここに持っおきおください:)
<php
//䞡方のcURLリ゜ヌスを䜜成したす
$ ch1 = curl_init ;
$ ch2 = curl_init ;

// URLおよびその他の適切なオプションを蚭定したす

curl_setopt  $ ch1 、 CURLOPT_URL 、 " www.example.com " ;
curl_setopt  $ ch1 、 CURLOPT_HEADER 、 0 ;
curl_setopt  $ ch2 、 CURLOPT_URL 、 " www.php.net " ;

curl_setopt  $ ch2 、 CURLOPT_HEADER 、 0 ;

//耇数のcURLハンドルを䜜成したす
$ mh = curl_multi_init ;


// 2぀のハンドルを远加したす
curl_multi_add_handle  $ mh 、 $ ch1 ;
curl_multi_add_handle  $ mh 、 $ ch2 ;


$ running = null ;
//ハンドルを実行したす
{
curl_multi_exec  $ mh 、 $ running ;
} while $ running > 0 ;


//ハンドルを閉じたす
curl_multi_remove_handle  $ mh 、 $ ch1 ;
curl_multi_remove_handle  $ mh 、 $ ch2 ;
curl_multi_close  $ mh ;

>

このコヌドは、アプリケヌションコヌドずラむブラリの盞互䜜甚のより耇雑な構成により、シングルスレッドアプロヌチずは異なりたす。
1各接続には独自のcurl_init があり、パラメヌタヌはcurl_setopt で蚭定されたす。 ここではすべおが暙準です。説明なしに匕甚したす。
2 curl_multi_init 呌び出しのダりンロヌドの䞀般的な制埡のために、個別の蚘述子が䜜成され、それを介しおすべおのさらなる䜜業が実行されたす。
3指定された蚘述子ぞのcurl_multi_add_handle 呌び出しは、最初に別の接続を䜜成したす 。
準備段階が完了し、今すぐ盎接ダりンロヌドしたす
4ラむブラリは自動的にダりンロヌドされたす; curl_exec のように明瀺的な呌び出しはもうありたせん。 curl_multi_exec を繰り返し呌び出すこずで眮き換えられたす。 名前は䌌おいたすが、この関数はわずかに異なる圹割を果たしたす-アクティブなスレッドの数の倉化をブロックしお通知したす発生した゚ラヌ。 2番目のパラメヌタヌは、呌び出されるず、珟圚アクティブな接続の数を栌玍する数倀倉数ぞの参照です。 数量が倉曎されたした-これは、䞀郚のスレッドが䜜業を完了したこずを意味したす。 このため、ダりンロヌドサむクルは
{
curl_multi_exec  $ mh 、 $ running ;
} while $ running > 0 ;

5最埌に、ダりンロヌド埌、リ゜ヌスが解攟されたす。 重芁 curl_init によっお䜜成された接続はメむン蚘述子に「固執」したすが、自動的には閉じたせん。curl_close に加えおcurl_multi_remove_handle を呌び出しお手動で閉じる必芁がありたす。

誰かがそのような実装を十分に持っおいるかもしれず、圌らはそれ以䞊読むこずができないかもしれたせん。 さらに進んでいきたす。
この実装の䜕が悪いのですか 最も明癜なポむントのいく぀か
  1. コヌドで盎接指定された2぀のリンクのダりンロヌドに関する厳しい制限
  2. 結果のペヌゞはSTDOUTに盎接衚瀺されたす

これはほんの䞀郚であり、残りは以䞋で説明したす。

私はこれらの欠点を修正し、たずえば次のようになりたす
<php
$ urls = array " www.example.com " 、 " www.php.net " ;

$ mh = curl_multi_init ;

$ chs = array;

foreach $ urls as $ url {
$ chs [] = $ ch = curl_init ;
curl_setopt  $ ch 、 CURLOPT_URL 、 $ url ;

curl_setopt  $ ch 、 CURLOPT_HEADER 、 0 ;
// CURLOPT_RETURNTRANSFER-関数の結果ずしお倀を返し、stdoutには出力したせん

curl_setopt  $ ch 、 CURLOPT_RETURNTRANSFER 、 1 ;
curl_multi_add_handle  $ mh 、 $ ch ;
}

$ prev_running = $ running = null ;

{
curl_multi_exec  $ mh 、 $ running ;

if $ running = $ prev_running {
//珟圚の接続に関する情報を取埗したす

$ info = curl_multi_info_read  $ mh ;

if is_array  $ info && $ ch = $ info [ 'handle' ]{

//ロヌドされたペヌゞのコンテンツを取埗したす
$ content = curl_multi_getcontent  $ ch ;

//ここにある皮のペヌゞテキスト凊理

//珟時点では元のように-STDOUTぞの出力
゚コヌ $コンテンツ ;
}


//珟圚アクティブな接続のキャッシュ数を曎新したす
$ prev_running = $ running ;
}

} while $ running > 0 ;


foreach $ chs as $ ch {
curl_multi_remove_handle  $ mh 、 $ ch ;
curl_close  $ ch ;

}
curl_multi_close  $ mh ;
>


さらに、ほずんどの堎合、STDOUTでペヌゞを衚瀺するのは非垞に簡単です。 さらに、これは実際のダりンロヌドの順序に応じおランダムな順序で発生したすゞョブはcurl_multi_add_handle を呌び出したせん。 たた、倧量のボリュヌムがダりンロヌドされる堎合、すべおのペヌゞが受信されるのを埅぀こずは意味がありたせん。受信したペヌゞの凊理を開始できたす。 しかし、すべおを䞀括で取埗するオプションも、離陞する䟡倀はありたせん。
これを行うには、1関数の圢匏ですべおを実装したす。2受信した各ファむルに察しお呌び出されるコヌルバック関数を指定するパラメヌタヌを導入したす。 コヌルバックが蚭定されおいない堎合、すべおのペヌゞを䞀床に取埗するオプションが適甚されたす。 以䞋に䟋を瀺したす。
<php
//単玔なコヌルバックの䟋。 実質的にダミヌ機胜。
function my_callback  $ url 、 $ content 、 $ curl_status 、 $ ch {

echo "ペヌゞのダりンロヌド[$ url]" ;
if $ curl_status {
゚コヌは 「成功したした。 ペヌゞテキスト\ n $ content \ n " ;

}
その他{
echo "゚ラヌで倱敗したした$ curl_status" 。 curl_error  $ ch 。 "\ n" ;
}

}

function http_load  $ urls 、 $ callback = false {
$ mh = curl_multi_init ;


$ chs = array;
foreach $ urls as $ url {
$ chs [] = $ ch = curl_init ;

curl_setopt  $ ch 、 CURLOPT_URL 、 $ url ;
curl_setopt  $ ch 、 CURLOPT_HEADER 、 0 ;
// CURLOPT_RETURNTRANSFER-関数の結果ずしお倀を返し、stdoutには出力したせん

curl_setopt  $ ch 、 CURLOPT_RETURNTRANSFER 、 1 ;
curl_multi_add_handle  $ mh 、 $ ch ;
}

// $コヌルバックがfalseに蚭定されおいる堎合、関数は$コヌルバックを呌び出すべきではありたせんが、䜜業の結果ずしおペヌゞを返したす

if $ callback === false {
$ results = array;
}

$ prev_running = $ running = null ;

{
curl_multi_exec  $ mh 、 $ running ;

if $ running = $ prev_running {
//珟圚の接続に関する情報を取埗したす

$ info = curl_multi_info_read  $ ghandler ;

if is_array  $ info && $ ch = $ info [ 'handle' ]{

//ロヌドされたペヌゞのコンテンツを取埗したす
$ content = curl_multi_getcontent  $ ch ;

//ダりンロヌドしたリンク
$ url = curl_getinfo  $ ch 、 CURLINFO_EFFECTIVE_URL ;


if $ callback == false {
//コヌルバックハンドラヌを呌び出したす
$コヌルバック  $ url 、 $ content 、 $ info [ 'result' ]、 $ ch ;

}
その他{
//結果のハッシュに远加したす
$ results [ $ url ] = array 'content' => $ content 、 'status' => $ info [ 'result' ]、 'status_text' => curl_error  $ ch ;

}

}

//珟圚アクティブな接続のキャッシュ数を曎新したす
$ prev_running = $ running ;
}


} while $ running > 0 ;

foreach $ chs as $ ch {
curl_multi_remove_handle  $ mh 、 $ ch ;

curl_close  $ ch ;
}
curl_multi_close  $ mh ;

//結果
return $ callback == false  true  $ results ;

}

$ urls = array " www.example.com " 、 " www.php.net " ;

//簡単な発行のオプション
print_r  http_load  $ urls ;


//コヌルバック付きオプション
var_export  http_load  $ urls 、 my_callback ;

>

すでにはるかに興味深い。 重芁な点コヌルバックの堎合、4番目のパラメヌタヌは$ ch接続蚘述子であり、ハッシュを出力する堎合、゚ラヌの単なる文字列の説明ですすべおが問題なければ、空の文字列です。 なんで curl_errorは蚘述子を枡す必芁があり、関数の最埌で終了したす。 そのため、コヌルバックではただ存圚し、䜿甚できたすが、ハッシュでは䜕の䟡倀も䞎えられたせん。 たたは、゚ラヌコヌドの文字列の説明はこちらにありたす 。

それでは、先に進みたしょう。 リンクの配列に察しおだけでなく、単䞀のペヌゞをダりンロヌドできるように関数を呌び出したいです。 これを行うには、1行だけ远加したす。
<php function http_load  $ urls 、 $ callback = false {
...
//唯䞀のパラメヌタが枡されおも、配列芁玠ずみなしたす

//これはアナログです$ urls = is_array$ urls $ urls配列$ urls;
$ urls =配列 $ urls ;

.... >

これで、リンクを䞀床に1぀ず぀ダりンロヌドできたすhttp_load 'google.com'。 ある皮の基本ぞの回垰。

次に、接続甚にさらに倚くの送信ヘッダヌを蚭定する必芁がありたした。 curl_setoptで䞀床に1぀ず぀指定するのは実甚的ではありたせん。 curl_setopt_array関数を䜿甚するこずをお勧めしたす。 やり盎しお取埗コヌドの䞀郚
<php
{ //すべおの接続に共通のヘッダヌ
$ ext_headers = array
「期埅」 、
'Accepttext / html、application / xhtml + xml、application / xml; q = 0.9' 、

'Accept-Languageru、en-us; q = 0.7、en; q = 0.7' 、
// 'Accept-Encodinggzip、deflate'、//埌で解凍する必芁がありたす。 さお、今のずころ...
'文字セットを受け入れるutf-8、windows-1251; q = 0.7、*; q = 0.5' 、
;
$ curl_options = array

CURLOPT_PORT => 80 、
CURLOPT_RETURNTRANSFER => 1 、 //関数の結果ずしお倀を返し、stdoutには出力したせん

CURLOPT_BINARYTRANSFER => 1 、 //バむナリセヌフに枡したす
CURLOPT_CONNECTTIMEOUT => 10 、 //接続タむムアりトルックアップ+接続

CURLOPT_TIMEOUT => 30 、 //デヌタ受信のタむムアりト
CURLOPT_USERAGENT => 'Mozilla / 5.0X11; U; Linux x86_64; en-US; rv1.9.1.1Gecko / 20090716 Ubuntu / 9.04jauntyShiretoko / 3.5.1' 、

CURLOPT_VERBOSE => 2 、 //情報レベル
CURLOPT_HEADER => 0 、 //ヘッダヌは機胜したせん
CURLOPT_FOLLOWLOCATION => 1 、 //リダむレクトに埓う

CURLOPT_MAXREDIRS => 7 、 //リダむレクトの最倧数
CURLOPT_AUTOREFERER => 1 、 //リダむレクトする堎合、「Referer」を「Location」の倀に眮き換えたす

// CURLOPT_FRESH_CONNECT => 0、//毎回新しい接続を䜿甚
CURLOPT_HTTPHEADER => $ ext_headers 、
;
}


function http_load  $ urls 、 $ callback = false {
グロヌバル $ curl_options ;

$ mh = curl_multi_init ;

if $ mh === false  falseを返す ;

$ urls =配列 $ urls ;

$ chs = array;

foreach $ urls as $ url {
$ chs [] = $ ch = curl_init ;


curl_setopt_array  $ ch 、 $ curl_options ; //ヘッダヌを䞀括で蚭定したす
curl_setopt  $ ch 、 CURLOPT_URL 、 $ url ;


curl_multi_add_handle  $ mh 、 $ ch ;
}
...
>


Firefoxのふりをしたす。 芋出しに぀いおコメントしたした。 詳现な説明に぀いおは、 こちらに送信しおください 。
そしお、これらのヘッダヌを远跡するために、関数に3番目のパラメヌタヌが远加されたす。
<?php function http_load( $urls, $callback = false, $urls_params = array() ) {} ?>
ヘッダヌを指定できたす。ヘッダヌは、初期化時に接続に远加されたす。 したがっお、パラメヌタヌを䜿甚しおPOSTリク゚ストを正垞に送信したり、玹介や送信デヌタの圢匏を指定したりできたすたずえば、圧瞮䞭。
<php
...
foreach $ urls as $ ind => $ url {
$ chs [] = $ ch = curl_init ;


curl_setopt_array  $ ch 、 $ curl_options ; //ヘッダヌを䞀括で蚭定したす
curl_setopt  $ ch 、 CURLOPT_URL 、 $ url ;


//この接続を初期化する远加のパラメヌタヌはありたすか
ifisset $ urls_params [ $ ind ]&& is_array  $ urls_params [ $ ind ]{

curl_setopt_array  $ ch 、 $ urls_params [ $ ind ];
}

curl_multi_add_handle  $ mh 、 $ ch ;

}
...
>


これがそのような関数です。 たた、CookieずPOSTリク゚ストの操䜜に぀いお曞くこずもできたすが、これは招埅を受けた堎合です。 そしお、圌はたくさん曞いた、䜕人がマスタヌしたか ;

Source: https://habr.com/ru/post/J68175/


All Articles