SiteVisorСайтвизор
cURL
PHP разработка

Асинхронное скачивание файлов на Битрикс с помощью CURL

Как ускорить загрузку файлов в Битрикс с помощью cURL Multi: асинхронная параллельная загрузка вместо последовательной, с примером кода.

Киселев Александр
Киселев Александр
Разработчик SiteVisor.Cloud15 авг 2024· 9 мин
Читать автора

В современном веб-разработке, эффективная загрузка файлов является важным аспектом для поддержки стабильной и быстрой работы приложений. Особенно это актуально для проектов, которые работают с большим количеством медиафайлов, например, изображений или документов. В этой статье мы рассмотрим, как с помощью асинхронного скачивания файлов на платформе Битрикс можно значительно улучшить производительность вашего приложения, а также разберем тонкости использования cURL Multi для параллельной загрузки.

Зачем нужна асинхронная загрузка?

Загрузка файлов в синхронном режиме предполагает, что каждый файл загружается последовательно, что может существенно увеличивать время выполнения скрипта, особенно если объем загружаемых данных велик. Асинхронная загрузка позволяет запустить несколько запросов параллельно, что значительно ускоряет процесс.На платформе Битрикс асинхронное скачивание файлов с использованием cURL Multi позволяет:

  • Обрабатывать запросы параллельно.

  • Экономить время на загрузке больших объемов данных.

  • Оптимизировать выполнение запросов в сценариях с массовым скачиванием изображений или других файлов.

Принцип работы асинхронного скачивания с cURL Multi

cURL — это библиотека для передачи данных с использованием различных протоколов, таких как HTTP, FTP, SMTP и других. В данном случае нас интересует работа с cURL Multi, который позволяет управлять сразу несколькими запросами одновременно.

Особенности cURL Multi:

  1. Асинхронность — запросы выполняются параллельно, и вам не нужно дожидаться завершения одного запроса для начала следующего.

  2. Эффективное управление ресурсами — использование мультиплексирования запросов снижает задержки и позволяет более эффективно использовать системные ресурсы.

  3. Управление дескрипторами — cURL Multi работает с несколькими дескрипторами запросов одновременно и поддерживает контроль за их выполнением.

Пример кода

Давайте рассмотрим конкретную реализацию на примере кода:

protected function saveFiles(array $urls): array
    {
        // Массив для хранения дескрипторов cURL
        $multiCurl = [];
        $mh = curl_multi_init();

        // Инициализируем cURL запросы
        foreach ($urls as $i => $url) {
            $multiCurl[$i] = curl_init();
            curl_setopt($multiCurl[$i], CURLOPT_URL, $url);
            curl_setopt($multiCurl[$i], CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($multiCurl[$i], CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($multiCurl[$i], CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($multiCurl[$i], CURLOPT_SSL_VERIFYHOST, false);
            curl_multi_add_handle($mh, $multiCurl[$i]);
        }

        // Выполняем все запросы
        $running = null;
        do {
            curl_multi_exec($mh, $running);
            curl_multi_select($mh);
        } while ($running > 0);

        $files = [];

        // Обрабатываем результаты
        foreach ($multiCurl as $i => $ch) {
            $response = curl_multi_getcontent($ch);

            if(!$response){
                continue;
            }

            $url = $urls[$i];
            $pathInfo = pathinfo(parse_url($url, PHP_URL_PATH));
            $extension = $pathInfo['extension'] ?? null;

            if(is_null($extension)){
                continue;
            }

            $tmpDirectory = \CTempFile::GetDirectoryName();
            $tmpName =  $tmpDirectory.$pathInfo['basename'];

            \Bitrix\Main\IO\Directory::createDirectory($tmpDirectory);

            $res = file_put_contents($tmpName, $response);

            if(!$res){
                continue;
            }

            $fileSize = filesize($tmpName);
            $fileType = mime_content_type($tmpName);

            $files[] = [
                'name' => $pathInfo['basename'],
                'size' => $fileSize,
                'tmp_name' => $tmpName,
                'type' => $fileType
            ];

            // Удаляем дескриптор cURL
            curl_multi_remove_handle($mh, $ch);
            curl_close($ch);
        }

        // Закрываем дескриптор cURL
        curl_multi_close($mh);

        return $files;
    }

Детали работы данного метода

1. Инициализация cURL дескрипторов

Для каждого URL, который мы передаем в метод, создается cURL-дескриптор, который управляет запросом к серверу. Параметры, передаваемые через curl_setopt, позволяют задать такие настройки, как:

  • CURLOPT_RETURNTRANSFER — возвращать результат в виде строки.

  • CURLOPT_FOLLOWLOCATION — следовать за редиректами.

  • CURLOPT_SSL_VERIFYPEER и CURLOPT_SSL_VERIFYHOST — отключение валидации SSL, что ускоряет процесс, но используется только в безопасных окружениях.

2. Запуск параллельного выполнения запросов

Мы используем curl_multi_exec для запуска всех запросов одновременно. Этот цикл работает до тех пор, пока все запросы не будут завершены. Такой подход позволяет значительно ускорить процесс загрузки по сравнению с последовательными запросами.

3. Получение ответа и сохранение файлов

После завершения каждого запроса мы получаем контент с помощью curl_multi_getcontent. Если ответ получен корректно, он сохраняется в файловую систему на временное хранилище с помощью file_put_contents.

4. Работа с временными файлами

Файлы сохраняются во временные директории, создаваемые через \CTempFile::GetDirectoryName(). Эта функция предоставляет временную директорию для файлов, которую можно легко очистить после завершения работы.

Тонкости и особенности использования cURL Multi на Битрикс

1. Ограничение на количество одновременных потоков

Стоит отметить, что серверные ресурсы могут ограничивать количество одновременных соединений. Если у вас много URL для загрузки, стоит ограничить число потоков (дескрипторов cURL), чтобы избежать перегрузки сервера и ошибок выполнения. Можно использовать технику "батчей" — запускать загрузку файлами группами, например, по 10-20 файлов за раз.

2. Работа с типами файлов

Так как расширение файла не всегда указывается в URL, необходимо корректно извлекать информацию о формате файла. В коде используется pathinfo для получения расширения файла. Однако важно учитывать, что расширение может быть неверно указано в URL, и лучше использовать mime_content_type для определения реального типа файла.

3. Безопасность

При работе с файлами через интернет стоит учитывать безопасность. Отключение проверки SSL, как показано в примере, возможно только в контролируемых средах, например, при локальной разработке или на внутренних серверах. На боевых серверах лучше оставить включенной валидацию SSL для предотвращения потенциальных атак.

4. Очистка ресурсов

Важно не забывать освобождать дескрипторы cURL после их использования с помощью curl_multi_remove_handle и закрывать их через curl_close. Это необходимо для предотвращения утечек памяти и стабильной работы приложения.

Тестирование и сравнение скорости

В процессе тестирования мы сравнили стандартный метод синхронного скачивания файлов через CFile::MakeFileArray с нашим асинхронным подходом на базе cURL.Для теста использовались 17 изображений. Ниже представлены результаты времени выполнения для обоих подходов:

  • Синхронный метод через CFile::MakeFileArray: Среднее время скачивания всех 17 изображений составило 3.5-4 секунды.

  • Асинхронное скачивание через cURL (multi-cURL): Время выполнения не превышало 0.5 секунд для тех же 17 изображений.

Прирост производительности:

Чтобы оценить прирост производительности, мы можем рассчитать ускорение:

  1. Синхронный подход: 3.5-4 секунд.

  2. Асинхронный подход: 0.5 секунд.

Среднее время синхронного подхода составляет 3.75 секунд. Для асинхронного подхода это 0.5 секунд.Теперь посчитаем прирост:

Таким образом, асинхронное скачивание ускоряет процесс в 7.5 раз по сравнению со стандартным синхронным подходом.

Пример:

Допустим, у вас есть страница с каталогом товаров, на которой требуется загрузить 50 изображений для рендеринга. Используя стандартный подход, загрузка займет около 11-12 секунд, что негативно скажется на пользовательском опыте. Однако с применением асинхронного скачивания это время сократится до 1.5-2 секунд, что делает загрузку значительно быстрее и улучшает производительность системы.

Заключение

Асинхронное скачивание файлов с использованием cURL Multi — это мощный инструмент для повышения производительности на веб-платформе Битрикс. Правильная настройка и использование этого механизма позволяет значительно ускорить процесс загрузки файлов, особенно при работе с большим количеством медиафайлов. Важно помнить о тонкостях управления ресурсами, безопасностью, а также корректной обработке различных типов данных.

Просмотров: 772

Комментарии (5)

Р
Руслан19 июл 2026

Спасибо за curl_multi_exec с CURLM_CALL_MULTI_PERFORM - я всегда забываю про этот нюанс и потом удивляюсь почему часть запросов зависает. У меня в итоге получилось только через связку curl_multi_select + таймаут выхода, без этого просто цикл в 100% cpu уходил.

Е
Егор8 июл 2026

Делал похожее для парсинга картинок из фида поставщика — при curl_multi обязательно ставьте CURLOPT_TIMEOUT и CURLOPT_CONNECTTIMEOUT на каждый handle отдельно, иначе один зависший хост держит весь пул и параллелизм превращается в фикцию.

y
ya_marketolog25 мая 2026

а зачем тут вообще curl multi, если можно тупо через symfony http-client или guzzle с пулом промисов сделать то же самое, только с нормальным ретраем из коробки? для битрикса это тоже подключается без проблем

k
kot_seo16 янв 2026

а как вы ограничиваете количество одновременных соединений? если файлов, скажем, 500 штук, все сразу в multi запихивать же не вариант - хостинг попросту прибьёт процесс по памяти. Делаю пачками по 10-15 через while(count(active)) с добавлением новых по мере завершения, но не уверена что это оптимально для d7 агентов

m
mixail_k6 июн 2025

попробовал по инструкции на битрикс 22.х, скрипт из агента (init.php cron) падал по memory_limit при скачивании ~200 файлов. Оказалось дело не в curl вообще, а в том что каждый файл целиком грузился в память через curl_multi_getcontent вместо CURLOPT_FILE с прямой записью на диск. Как только переключил на запись в поток - память перестала расти

Похожие материалы

Проверьте это на своём сайте

Бесплатные инструменты SiteVisor разбирают индексацию, robots.txt, редиректы и микроразметку — без регистрации и настройки.