#php #curl #remote-server
#php #curl #удаленный сервер
Вопрос:
У меня есть пользовательская функция cURL, которая должна загружать огромное количество изображений с удаленного сервера. Меня забанили пару раз раньше, когда я использовал file_get_contents() . Я обнаружил, что curl_multi_init() — лучший вариант, так как при 1 подключении он может загружать, например, 20 изображений одновременно. Я создал пользовательские функции, которые используют curl_init(), и я пытаюсь выяснить, как я могу реализовать curl_multi_init(), поэтому в моем ЦИКЛЕ, где я беру список из 20 URL-адресов из базы данных, я могу вызвать свою пользовательскую функцию и в последнем цикле использовать curl_close() . В текущей ситуации моя функция генерирует соединение для каждого URL-адреса в ЦИКЛЕ. Вот функция:
function downloadUrlToFile($remoteurl,$newfileName){
$errors = 0;
$options = array(
CURLOPT_FILE => fopen('../images/products/'.$newfileName, 'w'),
CURLOPT_TIMEOUT => 28800,
CURLOPT_URL => $remoteurl,
CURLOPT_RETURNTRANSFER => 1
);
$ch = curl_init();
curl_setopt_array($ch, $options);
$imageString =curl_exec($ch);
$image = imagecreatefromstring($imageString);
if($imageString !== false AND !empty($imageString)){
if ($image !== false){
$width_orig = imagesx($image);
if($width_orig > 1000){
$saveimage = copy_and_resize_remote_image_product($image,$newfileName);
}else $saveimage = file_put_contents('../images/products/'.$newfileName,$imageString);
}else $errors ;
}else $errors ;
curl_close($ch);
return $errors;
}
Должен быть способ использовать curl_multi_init() и мою функцию downloadUrlToFile, потому что:
- Мне нужно изменить имя файла на лету
- В моей функции я также проверяю несколько вещей для удаленного изображения.. В примере функции я проверяю только размер и изменяю его размер, если это необходимо, но эта функция выполняет гораздо больше задач (я сократил эту часть для сокращения, но я также использую функцию для передачи большего количества переменных ..)
Как следует изменить код, чтобы во время цикла подключаться к удаленному серверу только один раз?
Заранее спасибо
Ответ №1:
Попробуйте этот шаблон для Multi CURL
$urls = array($url_1, $url_2, $url_3);
$content = array();
$ch = array();
$mh = curl_multi_init();
foreach( $urls as $index => $url ) {
$ch[$index] = curl_init();
curl_setopt($ch[$index], CURLOPT_URL, $url);
curl_setopt($ch[$index], CURLOPT_HEADER, 0);
curl_setopt($ch[$index], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch[$index]);
}
$active = null;
for(;;) {
curl_multi_exec($mh, $active);
if($active < 1){
// all downloads completed
break;
}else{
// sleep-wait for more data to arrive on socket.
// (without this, we would be wasting 100% cpu of 1 core while downloading,
// with this, we'll be using like 1-2% cpu of 1 core instead.)
curl_multi_select($mh, 1);
}
}
foreach ( $ch AS $index => $c ) {
$content[$index] = curl_multi_getcontent($c);
curl_multi_remove_handle($mh, $c);
//You can add some functions here and use $content[$index]
}
curl_multi_close($mh);
Комментарии:
1. #Александр, спасибо за ваше время. Это был мой первый подход, когда я обнаружил, что с подобным кодом я не могу передать несколько переменных, которые мне нужны. Если бы я мог, этот код мог бы работать для меня, но.. Например, мне нужно передать: product_id, product_name, product_code.. В моем примере функции я показываю только название продукта, но я объяснил, что на самом деле я отправил больше переменных
2. не используйте busyloop; это приведет к потере 100% процессора (из 1 ядра процессора) без уважительной причины. вместо этого попробуйте:
for(;;){curl_multi_exec($mh,$active);if($active<1){/*all downloads completed*/break;}curl_multi_select($mh,1);}
— он будет использовать намного меньше процессора и не будет медленнее. (серьезно, если у вас одноядерный экземпляр AWS, ваш код будет использовать 100% cpu, пока все не будет загружено. добавьте туда select(), и он будет использовать примерно 1-2% процессора, пока все не будет загружено.)3. #ханшенрик что такое busyloop? Был ли этот комментарий для ответа Александра?
4. @Europeuser вы можете прочитать об этом здесь , была проблема с исходным кодом Александра, где он использовал бы что-то вроде 98% больше процессора, чем на самом деле необходимо. но не обращайте внимания на это, код обновляется, эта проблема исправлена 🙂