url = $url; if($opts) $this->options = $opts; } /* // If no curl error happens with the handle. If softfail is set and status>=400, success is not executed. public function success() { } // If a curl error happens with the handle public function failure() { } // If status>=400 public function softfail() { } // Before handle is initialised and options set public function before() { } // After success/softfail/failure are executed public function after() { } */ public function cookie($str) { $this->options[CURLOPT_COOKIE] = $str; } public function proxy($ip, $port, $user=null, $pwd=null) { $this->options[CURLOPT_PROXYPORT] = $port; $this->options[CURLOPT_PROXY] = $ip; if($user) $this->options[CURLOPT_PROXYUSERPWD] = $user.':'.$pwd; } public function ua($str) { $this->options[CURLOPT_USERAGENT] = $str; } public function ip($str) { $this->options[CURLOPT_INTERFACE] = $str; } } class Curl { /* VERY IMPORTANT ** MULTI MODE: true,false ** If you are having problems with curl_multi or you just don't need concurrent requests, change to false and it will work with ** non-multi curl. You will still be able to use perform() to execute multiple requests (however they won't be executed concurrently). ** ** Curl still blocks in the following operations even if multi is used: ** - Name resolves on non-windows unless c-ares is used ** - GnuTLS SSL connections ** - Active FTP connections ** - HTTP proxy CONNECT operations ** - TFTP transfers ** - file:// transfers */ public $multi = true; // Max simultaneous requests, if there are more in the request pool it runs chunk() public $maxParallelRequests = 50; // Delay between requests in seconds, only works with $multi set to false. public $delayBetweenSingle = 0; // Delay between chunks in seconds, only works with $multi set to true. public $delayBetweenChunks = 0; // Request pool public $requests = array(); // DEFAULT CURL OPTIONS // Will override $curlOptions in make() // DO NOT CHANGE 'CURLOPT_RETURNTRANSFER' and 'CURLOPT_HEADER' UNLESS YOU KNOW WHAT YOU ARE DOING public $defaultOptions = array( CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_AUTOREFERER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_COOKIEJAR => 'cookies.txt', CURLOPT_COOKIEFILE => 'cookies.txt', CURLOPT_HTTPHEADER => array("Expect:"), CURLOPT_MAXREDIRS => 20); // Curl Multi errors public $multiErrors = array(); /* ** Internal variables */ // Pool of handles for the multihandle protected $chPool; // Multi curl handle protected $mh; protected $activeConnection =null; protected $mrc; // Request chunks protected $chunks = false; // Request count protected $rCount = 0; // Active requests protected $active = array(); /* ** Constructor */ public function __construct() { set_time_limit(0); } /* ** Single HTTP methods */ public function get($url, $curlOpts='') { $r = new CurlRequest($url, $curlOpts); $r->options[CURLOPT_HTTPGET] = true; $id = $this->add($r); $this->perform(); return $this->requests[$id]; } public function post($url, $vars, $curlOpts='') { $r = new CurlRequest($url, $curlOpts); $r->options[CURLOPT_POST] = true; $r->options[CURLOPT_POSTFIELDS] = $vars; $id = $this->add($r); $this->perform(); return $this->requests[$id]; } /* ** Multiple HTTP methods */ public function add(&$request, $id=null) { if(!isset($id)) { $id = $this->rCount; } $this->active[$id] = ''; $this->requests[$id] = $request; $this->requests[$id]->id = $id; $this->requests[$id]->curl = &$this; $this->rCount++; return $id; } public function perform() { if(($k = count($this->active)) > 0 ) { //If there's only one request drop down to single mode if($k == 1) $this->multi = false; // Initialise the multi-handle if($this->multi) { if(!($this->mh = curl_multi_init())) { $this->multiErrors[] = "Failed to initialize multi handle"; return; } } // Chunk and perform() once for each chunk if($this->multi && $this->maxParallelRequests < $k) { $this->chunk(); foreach($this->chunks as $chunk) { $this->active = $chunk; // delay if needed if($this->delayBetweenChunks > 0) sleep($this->delayBetweenChunks); while(count($this->active)>0) { // initialise the single handles, stored in $this->chPool $this->makeHandles(); // perform requests in the pool $this->performMulti(); } } } // Only one chunk else { while(count($this->active)>0) { $this->makeHandles(); $this->performMulti(); } } // Close the multi handle if($this->multi) curl_multi_close($this->mh); } } /* ** Static methods */ public static function vars($vars) { $str = ''; foreach( $vars as $k => $v) $str .= urlencode($k).'='.urlencode($v).'&'; return substr($str, 0, -1); } public static function parseHeaders($str) { //$str = str_replace("\r\n","\n",$str); $h = array_filter(explode("\r\n",$str)); $a = array(); $c = -1; foreach($h as $i) { if(($p = strpos($i, ': ')) !== false) { $type = trim(strtolower(substr($i,0,$p))); $a[$c][$type] = trim(substr($i,$p+1)); } else { $c++; $parts = explode(' ', $i,3); $a[$c]['http'] = array( 'version' => $parts[0], 'status' => $parts[1], 'string' => $parts[2] ); } } return $a; } public static function parseCookies($arr,$other=false) { $cookies = array(); foreach($arr as $i => $headers) { if(!($str = $headers['set-cookie'])) continue; if( strpos($str,';') === false) { $c = explode('=',$str,2); $c[0] = trim($c[0]); $c[1] = trim($c[1]); $cookies[$i][$c[0]] = $c[1]; } else { $cookieparts = explode( ';', $str ); foreach($cookieparts as $data ) { $c = explode( '=', $data, 2); $c[0] = trim($c[0]); $c[1] = trim($c[1]); if(in_array( $c[0], array('domain', 'expires', 'path', 'secure', 'comment'))) { if($other) { switch($c[0]) { case 'expires': $c[1] = strtotime($c[1]); break; case 'secure': $c[1] = true; break; } $cookies[$i][$c[0]] = $c[1]; } } else { $cookies[$i][$c[0]] = $c[1]; } } } } return $cookies; } public static function discoverInterfaces() { $a = shell_exec( 'ifconfig -a' ); //$a .= 'lala addr:127.123.123.123 addr:122.234.354.34 lala addr:10.10.10.10 addr:100.12.12.12 '; preg_match_all( '@addr:(?=([0-9.]+))(?!(?:10\.|127\.|172\.[1-3][6-9_0]\.|192\.|169\.254\.[0-9.]+))@', $a, $m); return $m[1]; } /****** ** Internal methods ******/ protected function chunk() { $this->chunks = array_chunk($this->active, $this->maxParallelRequests, true); } protected function setOptions(&$ch, $curlOptions) { if(!empty($curlOptions) && is_array($curlOptions)) curl_setopt_array($ch, $curlOptions); } protected function initHandle($k) { if( ($this->chPool[$k] = curl_init()) !== false) { $this->requests[$k]->options[CURLOPT_URL] = $this->requests[$k]->url; $this->requests[$k]->options = $this->requests[$k]->options + $this->defaultOptions; $this->setOptions($this->chPool[$k], $this->requests[$k]->options); if($this->multi) $this->addHandle($k); } else { unset($this->chPool[$k]); unset($this->active[$k]); $this->requests[$k]->error = array( 'n' => 99, 'msg' => 'Failed to initialize handle' ); } } protected function addHandle($k) { if(($n = curl_multi_add_handle($this->mh,$this->chPool[$k])) !== 0) { $this->multiErrors[] = 'Failed to add id:'.$k.' to multihandle. Err n:'.$n; unset($this->chPool[$k]); unset($this->active[$k]); $this->requests[$k]->error = array( 'n' => 99, 'msg' => 'Failed to add to multihandle' ); } } protected function removeHandle($k) { if(($n = curl_multi_add_handle($this->mh,$this->chPool[$k])) === false) { $this->multiErrors[] = 'Failed to remove id:'.$k.' from multihandle'; } } protected function makeHandles() { foreach($this->active as $k => $kk) { if(method_exists($this->requests[$k],'before')) $this->requests[$k]->before(); if(!$this->requests[$k]->keep) { $this->initHandle($k); } else { $this->requests[$k]->options[CURLOPT_URL] = $this->requests[$k]->url; $this->setOptions($this->chPool[$k], $this->requests[$k]->options); if($this->multi) $this->addHandle($k); } } } protected function performMulti() { if($this->multi) { // Start performing the requests do { $this->mrc = curl_multi_exec($this->mh, $this->activeConnection); } while($this->mrc == CURLM_CALL_MULTI_PERFORM); while ($this->activeConnection && $this->mrc === CURLM_OK) { // Wait for network if (curl_multi_select($this->mh) != CURLM_CALL_MULTI_PERFORM) { // pull in any new data, or at least handle timeouts do { $this->mrc = curl_multi_exec($this->mh, $this->activeConnection); } while( $this->mrc == CURLM_CALL_MULTI_PERFORM); } } if ($this->mrc !== CURLM_OK) { $this->multiErrors[] = "Curl multi read error: $this->mrc\n"; //return; } } foreach($this->active as $i => $ii) { $this->execute($i); } } protected function execute($i) { if(!$this->multi) { if($this->delayBetweenSingle > 0) sleep($this->delayBetweenSingle); $response = curl_exec($this->chPool[$i]); } // No curl error if ( ($ern = curl_errno($this->chPool[$i])) === 0 ) { if($this->multi) $response = curl_multi_getcontent($this->chPool[$i]); $inf = curl_getinfo($this->chPool[$i]); if($this->requests[$i]->options[CURLOPT_HEADER] && $this->requests[$i]->options[CURLOPT_RETURNTRANSFER]) { $this->requests[$i]->head = substr($response,0,$inf['header_size']); $this->requests[$i]->body = substr($response,$inf['header_size']); } elseif($this->requests[$i]->options[CURLOPT_RETURNTRANSFER]) { $this->requests[$i]->body = $response; } $this->requests[$i]->status = $inf['http_code']; $this->requests[$i]->lastURL = $inf['url']; $this->requests[$i]->totalTime = $inf['total_time']; if($this->requests[$i]->head && $this->requests[$i]->parseHeaders) $this->requests[$i]->headers = self::parseHeaders($this->requests[$i]->head); if($this->requests[$i]->headers && $this->requests[$i]->parseCookies) $this->requests[$i]->cookies = self::parseCookies($this->requests[$i]->headers); if($this->requests[$i]->status >= 400 && method_exists($this->requests[$i],'softfail')) { $this->requests[$i]->softfail(); } elseif(method_exists($this->requests[$i],'success')) { $this->requests[$i]->success(); } // Some curl error } else { $this->requests[$i]->error = array( 'n' => $ern, 'msg' => curl_error($this->chPool[$i]) ); if(method_exists($this->requests[$i],'failure')) $this->requests[$i]->failure(); } if(method_exists($this->requests[$i],'after')) $this->requests[$i]->after(); if($this->multi) curl_multi_remove_handle($this->mh, $this->chPool[$i]); if(!$this->requests[$i]->keep) { curl_close($this->chPool[$i]); unset($this->active[$i]); unset($this->chPool[$i]); } } } class CurlSingle { function setup() { $cookieJar = 'cookies.txt'; curl_setopt($this->curl,CURLOPT_COOKIEJAR, $cookieJar); curl_setopt($this->curl,CURLOPT_COOKIEFILE, $cookieJar); curl_setopt($this->curl,CURLOPT_AUTOREFERER, true); curl_setopt($this->curl,CURLOPT_FOLLOWLOCATION, true); curl_setopt($this->curl,CURLOPT_RETURNTRANSFER, true); curl_setopt($this->curl,CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11'); } function get($url) { $this->curl = curl_init($url); $this->setup(); return $this->request(); } function getAll($reg,$str) { preg_match_all($reg,$str,$matches); return $matches[1]; } function post($url, $fields, $referer='') { $timeout = 0; $this->curl = curl_init($url); $this->setup(); curl_setopt($this->curl, CURLOPT_URL, $url); curl_setopt($this->curl, CURLOPT_POST, 1); curl_setopt($this->curl, CURLOPT_REFERER, $referer); curl_setopt($this->curl, CURLOPT_POSTFIELDS, $fields); curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Expect:')); return $this->request(); } function getInfo($info) { $info = ($info == 'lasturl') ? curl_getinfo($this->curl, CURLINFO_EFFECTIVE_URL) : curl_getinfo($this->curl, $info); $info = ($info == 'http_code') ? curl_getinfo($this->curl, CURLINFO_HTTP_CODE) : curl_getinfo($this->curl, $info); return $info; } function request() { return curl_exec($this->curl); } } ?>