curl_multi_* 함수를 이용.
curl 버전 7.20.0 이전과 이후의 curl_multi_exec() 반환값 핸들링이 다르므로 그 차이만 주의하면 됨.
여러 url을 순차적으로 호출하는 것보다 확실히 빠름.
함수와 사용 예제.
<?PHP
/*
URL 배열을 받아 비동기 방식으로 호출하고 그 결과값을 반환
[INPUT]
array(
'URL1', 'URL2', 'URL3', ...
)
[RETURN]
array(
'URL1' => array(
'err' => '', // 에러 메시지. 없으면 빈 문자열
'content' => '', // 호출 결과 문자열
't' => 0 // 호출 소요시간
),
'URL2' => array(
'err' => '',
'content' => '',
't' => 0
),
'URL3' => array(
'err' => '',
'content' => '',
't' => 0
),
...
)
*/
function curl_multi($urlList)
{
$chList = array();
$resultList = array();
$handleUrlMap = array();
foreach ($urlList as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$chList[$url] = $ch;
$handleUrlMap[$ch] = $url;
$resultList[$url] = array(
'err' => '',
'content' => '',
't' => 0
);
}
$cmh = curl_multi_init();
foreach ($chList as $ch) {
curl_multi_add_handle($cmh, $ch);
}
$t = microtime(true);
$curlVersion = curl_version();
// 7.20.0 이후(>=) 버전
if (version_compare($curlVersion['version'], '7.20.0', '>=') === true) {
do {
$status = curl_multi_exec($cmh, $active);
while (false !== ($info = curl_multi_info_read($cmh))) {
$url = $handleUrlMap[$info['handle']];
$resultList[$url]['t'] = microtime(true)-$t;
// error
if ($info['result'] != CURLE_OK) {
$resultList[$url]['err'] = curl_error($info['handle']);
}
}
if ($active) {
curl_multi_select($cmh);
}
} while ($active && $status == CURLM_OK);
}
// 7.20.0 이전 옛날 버전
else {
do {
$status = curl_multi_exec($cmh, $active);
if ($status === CURLM_CALL_MULTI_PERFORM) continue;
curl_multi_select($cmh);
while (false !== ($info = curl_multi_info_read($cmh))) {
$url = $handleUrlMap[$info['handle']];
$resultList[$url]['t'] = microtime(true)-$t;
// error
if ($info['result'] != CURLE_OK) {
$resultList[$url]['err'] = curl_error($info['handle']);
}
}
} while ($active);
}
foreach ($chList as $url=>$ch) {
if (strlen($resultList[$url]['err']) > 0) continue;
$resultList[$url]['content'] = curl_multi_getcontent($ch);
curl_multi_remove_handle($cmh, $ch);
curl_close($ch);
}
curl_multi_close($cmh);
return $resultList;
}
$urlList = array();
// 1페이지부터 10페이지까지 비동기로 한 번에 가져온다고 가정
for ($i=1; $i<=10; $i++) {
$urlList[] = 'https://mydomain.com/list.php?page='.$i;
}
$resultList = curl_multi($urlList);
curl 버전에 따른 차이점에 대해 자세히 설명하자면,
7.20.0 이전 버전의 curl_multi_exec() (libcurl의 curl_multi_perform()에 해당) 함수는 CURLM_CALL_MULTI_PERFORM (-1) 을 반환하기도 하는데,
이건 실제로는 에러가 아니라 select()를 호출하지 말고 curl_multi_exec()를 재호출 하라는 뜻이다.
이로 인해 7.20.0 이전/이후의 로직이 미묘하게 달라지게 된다.
참고: https://curl.haxx.se/libcurl/c/libcurl-errors.html#CURLMCALLMULTIPERFORM
'PHP' 카테고리의 다른 글
[PHP] pecl install 실행시 popen() disabled 관련 warning과 함께 ERROR: failed to run `phpize' 에러 발생 (0) | 2021.02.10 |
---|---|
[PHP] 문자열 조합해서 상수 읽어오기 (use string concatenation to read constant) (0) | 2021.01.27 |
[PHP] curl 사용시 SSL connect error (35) (0) | 2020.08.12 |
[PHP] curl -v(verbose) 옵션 세팅 및 결과 확인하기 (0) | 2020.08.11 |
[PHP] heredoc 내부에서 함수 호출하기 (calling function inside heredoc) (0) | 2020.07.14 |