Расширенный PHP: настроить обратный вызов onBefore и / или onAfter для дескриптора cURL? - PullRequest
1 голос
/ 11 июня 2011

Я работаю с реализацией cURL в PHP и использую curl_multi_init () и curl_multi_exec () для параллельного выполнения пакетов запросов. Я делал это некоторое время, и понимаю этот кусок.

Однако, тела запроса содержат подпись , которая рассчитывается с отметкой времени. С момента создания этой подписи у меня есть ограниченное время, чтобы сделать запрос, прежде чем сервер отклонит запрос, как только он будет сделан. В большинстве случаев это нормально. Однако в некоторых случаях мне нужно выполнять большие загрузки (5+ ГБ).

Если я выполняю пакетные запросы в пул из 100, 200, 1000, 20000 или чего-либо промежуточного и загружаю большие объемы данных на сервер, начальные запросы, которые выполняются, будут успешно выполнены. Однако последующие запросы не начнутся, пока не истечет время, указанное в подписи, поэтому сервер отклоняет эти запросы из-под контроля.

Поток тока, который я использую, выглядит примерно так:

  1. Делать какие-либо обработки заранее.
  2. Добавить еще не выполненные маркеры cURL в пакет.
  3. Пусть cURL обрабатывает выполнение всех запросов.
  4. Посмотрите на данные, которые вернулись, и проанализируйте все это.

Мне интересно найти способ выполнить функцию обратного вызова, которая может генерировать подпись по требованию и обновлять тело запроса в тот момент, когда PHP / cURL отправляется для выполнения этого конкретного запроса. Я знаю, что вы можете связать функцию обратного вызова с дескриптором cURL, который будет выполняться неоднократно, пока выполняется запрос, и у вас есть доступ к дескриптору cURL на протяжении всего пути.

Так что мой вопрос таков: есть ли способ настроить обратный вызов onBefore и / или onAfter для дескриптора cURL? Что-то, что может быть выполнено непосредственно перед тем, как cURL выполнит запрос, а затем что-то, что может быть выполнено сразу после того, как ответ вернется, чтобы данные ответа могли быть проанализированы.

Я бы хотел сделать что-то более ориентированное на события, например:

  1. Добавить еще не выполненный дескриптор cURL в пакет, назначив функцию обратного вызова для выполнения, когда cURL (не я) выполняет запрос (как до, так и после).
  2. Возьмите результаты пакетного запроса и сделайте с данными все, что я хочу.

Ответы [ 3 ]

1 голос
/ 11 июня 2011

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

Например, смутно реализуя шаблон Observer:

<?php

class CurlWrapper {
    private $ch;
    private $listeners;

    public function __construct($url) {
        $this->ch = curl_init($url);
        $this->setopt(CURLOPT_RETURNTRANSFER, true);
    }

    public function setopt($opt, $value) {
        $this->notify('setopt', array('option' => $opt, 'value' => $value));
        curl_setopt($this->ch, $opt, $value);
    }

    public function setopt_array($opts) {
        $this->notify('setopt_array', array('options' => $opts));
        curl_setopt_array($this->ch, $opts);
    }

    public function exec() {
        $this->notify('beforeExec', array());
        $ret = curl_exec($this->ch);
        $this->notify('afterExec', array('result' => $ret));
        return $ret;
    }

    public function attachListener($event, $fn) {
        if (is_callable($fn)) {
            $this->listeners[$event][] = $fn;
        }
    }

    private function notify($event, $data) {
        if (isset($this->listeners[$event])) {
            foreach ($this->listeners[$event] as $listener) {
                $listener($this, $data);
            }
        }
    }
}

$c = new CurlWrapper('http://stackoverflow.com');
$c->setopt(CURLOPT_HTTPGET, true);
$c->attachListener('beforeExec', function($handle, $data) {
    echo "before exec\n";
});

$result = $c->exec();
echo strlen($result), "\n";

Вы можете добавить прослушиватели событий (которые должны вызываться) к объекту с помощью addListener, и они будут автоматически вызываться в соответствующий момент.

Очевидно, что вам нужно проделать дополнительную работу, чтобы она соответствовала вашим требованиям, но я думаю, это неплохое начало.

0 голосов
/ 11 июня 2011

Хорошо, вы говорите, что запросы распараллелены, я не совсем точно знаю, что это значит, но это не так уж важно.

В качестве пояснения я объясню, что я имею в виду под асинхронным. Если вы открываете необработанный сокет TCP, вы можете вызвать функцию socket_set_blocking для соединения, это означает, что операции чтения / записи не блокируются. Вы можете использовать несколько таких соединений и записать небольшое количество данных в каждое из них в цикле, таким образом вы отправляете свои запросы «сразу».

Причина, по которой я спросил, нужно ли ждать, пока все сообщение не будет использовано, прежде чем конечная точка проверяет подпись, заключается в том, что даже если Curl отправляет запросы «сразу», всегда есть вероятность, что время, необходимое для загрузки будет означать, что проверка не пройдена. Предположительно медленнее загружать 2000 запросов одновременно, чем загружать 5, так что вы ожидаете больше сбоев в первом случае? Точно так же, если ваши запросы обрабатываются синхронно (то есть по одному за раз), вы увидите ту же ошибку по той же причине, хотя в этом случае ожидаемые сбои ожидаются позднее. Возможно, вам нужно подумать о скорости загрузки данных, необходимой для загрузки сообщения определенного размера в течение определенного периода времени, а затем попытаться рассчитать оптимальный размер для нескольких полезных данных. Возможно, лучший подход самый простой: загружать по одному и вычислять подпись непосредственно перед каждой загрузкой?

Лучшим подходом было бы поместить подпись в заголовок сообщения, таким образом подпись может быть прочитана ранее в процессе загрузки.

0 голосов
/ 11 июня 2011

Все, что связано с cURL, не является продвинутым PHP. Это "продвинутая порка".

Если у вас есть эти огромные объемы данных, проходящие через cURL, я бы рекомендовал вообще не использовать cURL (на самом деле, я бы всегда рекомендовал не использовать cURL)

Я бы посмотрел на реализацию сокета. Хороших найти нелегко, но написать их не так сложно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...