2009-09-07 6 views
2

J'ai un problème avec curl_multi_*, je veux créer une classe/fonction qui reçoit, disons 1000 URLs, et traite toutes ces URL 5 à la fois, donc quand une URL a fini de télécharger il attribuera l'emplacement disponible à une nouvelle URL qui n'a pas encore été traitée.Problème avec CURL (Multi)

Je l'ai vu someimplementations de curl_multi, mais aucun d'eux ne me permet de faire ce que je veux, je crois que la solution se trouve quelque part dans l'utilisation de curl_multi_select mais la documentation est pas très claire et l'utilisateur note n » t aider beaucoup.

Quelqu'un peut-il s'il vous plaît me fournir quelques exemples de comment je peux mettre en œuvre une telle fonctionnalité?

Répondre

6

Voici une façon de le faire. Ce script récupère un nombre illimité d'URL à la fois, et en ajoute une nouvelle à la fin de chaque opération (donc il récupère toujours $ maxConcurrent pages).

$sites = array('http://example.com', 'http://google.com', 'http://stackoverflow.com'); 
$concurrent = 2; // Any number. 

$mc = new MultiCurl($sites, $concurrent); 
$mc->process(); 

echo '</pre>'; 

class MultiCurl 
{ 
    private $allToDo; 
    private $multiHandle; 
    private $maxConcurrent = 2; 
    private $currentIndex = 0; 
    private $info   = array(); 
    private $options  = array(CURLOPT_RETURNTRANSFER => true, 
            CURLOPT_FOLLOWLOCATION => true, 
            CURLOPT_MAXREDIRS  => 3, 
            CURLOPT_TIMEOUT  => 3); 

    public function __construct($todo, $concurrent) 
    { 
     $this->allToDo = $todo; 
     $this->maxConcurrent = $concurrent; 
     $this->multiHandle = curl_multi_init(); 
    } 

    public function process() 
    { 
     $running = 0; 
     do { 
      $this->_addHandles(min(array($this->maxConcurrent - $running, $this->_moreToDo()))); 
      while ($exec = curl_multi_exec($this->multiHandle, $running) === -1) { 
      } 
      curl_multi_select($this->multiHandle); 
      while ($multiInfo = curl_multi_info_read($this->multiHandle, $msgs)) { 
       $this->_showData($multiInfo); 
       curl_multi_remove_handle($this->multiHandle, $multiInfo['handle']); 
       curl_close($multiInfo['handle']); 
      } 
     } while ($running || $this->_moreTodo()); 
     return $this; 
    }  

    private function _addHandles($num) 
    { 
     while ($num-- > 0) { 
      $handle = curl_init($this->allToDo[$this->currentIndex]); 
      curl_setopt_array($handle, $this->options); 
      curl_multi_add_handle($this->multiHandle, $handle); 
      $this->info[$handle]['url'] = $this->allToDo[$this->currentIndex]; 
      $this->currentIndex++; 
     } 
    }   

    private function _moreToDo() 
    { 
     return count($this->allToDo) - $this->currentIndex; 
    } 

    private function _showData($multiInfo) 
    { 
     $this->info[$multiInfo['handle']]['multi'] = $multiInfo; 
     $this->info[$multiInfo['handle']]['curl'] = curl_getinfo($multiInfo['handle']); 
     //print_r($this->info[$multiInfo['handle']]); 
     $content = curl_multi_getcontent($multiInfo['handle']); 
     echo $this->info[$multiInfo['handle']]['url'] . ' - ' . strlen($content) . ' bytes<br />'; 
     //echo htmlspecialchars($content); 
    } 
} 
+1

depuis cet exemple n'utilise pas curl_multi_select(), il boucle occupé comme un fou et donc prendre 100% du CPU jusqu'à ce que tous les transferts sont effectués ... –

+1

Stenberg @ Daniel - Merci; tu as raison. J'ai remplacé ce code par une classe (réduite) qui est plus rapide et utilise beaucoup moins de temps CPU. – GZipp