public function scrape($announce = null, $hash_info = null, $timeout = self::timeout)
{
$packed_hash = urlencode(pack('H*', $hash_info ? $hash_info : $this->hash_info()));
$handles = $scrape = array();
if (!function_exists('curl_multi_init')) {
return self::set_error(new Exception('Install CURL with "curl_multi_init" enabled'));
}
$curl = curl_multi_init();
foreach ((array) ($announce ? $announce : $this->announce()) as $tier) {
foreach ((array) $tier as $tracker) {
$tracker = str_ireplace(array('udp://', '/announce', ':80/'), array('http://', '/scrape', '/'), $tracker);
if (isset($handles[$tracker])) {
continue;
}
$handles[$tracker] = curl_init($tracker . '?info_hash=' . $packed_hash);
curl_setopt($handles[$tracker], CURLOPT_RETURNTRANSFER, true);
curl_setopt($handles[$tracker], CURLOPT_TIMEOUT, $timeout);
curl_multi_add_handle($curl, $handles[$tracker]);
}
}
do {
while (($state = curl_multi_exec($curl, $running)) == CURLM_CALL_MULTI_PERFORM) {
}
if ($state != CURLM_OK) {
continue;
}
while ($done = curl_multi_info_read($curl)) {
$info = curl_getinfo($done['handle']);
$tracker = explode('?', $info['url'], 2);
$tracker = array_shift($tracker);
if (empty($info['http_code'])) {
$scrape[$tracker] = self::set_error(new Exception('Tracker request timeout (' . $timeout . 's)'), true);
continue;
} elseif ($info['http_code'] != 200) {
$scrape[$tracker] = self::set_error(new Exception('Tracker request failed (' . $info['http_code'] . ' code)'), true);
continue;
}
$data = curl_multi_getcontent($done['handle']);
$stats = self::decode_data($data);
curl_multi_remove_handle($curl, $done['handle']);
$scrape[$tracker] = empty($stats['files']) ? self::set_error(new Exception('Empty scrape data'), true) : array_shift($stats['files']) + (empty($stats['flags']) ? array() : $stats['flags']);
}
} while ($running);
curl_multi_close($curl);
return $scrape;
}