All pastes #1036502 Raw Edit

curl2 class

public text v1 · immutable
#1036502 ·published 2008-06-02 04:10 UTC
rendered paste body
<?php
/**************************
** COPYRIGHT 2006-2007 webuildspam.com
** This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Greece License
** http://creativecommons.org/licenses/by-nc-sa/3.0/gr/
**************************/

class CurlRequest {
	public $url; // URL to connect to
	public $options; // assoc array of curl options
	
	public $parseHeaders = true; // set to true to parse headers 
	public $parseCookies = true; // set to true to parse cookies, needs an assoc array in $headers
	public $cookies; // cookies assoc arrays
	public $headers; // headers assoc arrays	
	
	public $body; // body string
	public $head; // headers string
	
	public $status; // HTTP status code
	public $lastURL; // last effective url
	public $totalTime; // total time for last transfer
	
	public $error;	// curl error
	
	public $id; // index of the request in the curl object's $requests array
	public $curl; // reference to the curl object
	
	// set to true to keep curl handle alive
	public $keep = false;
	
	public function __construct($url, $opts=null) {
		$this->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);
    }
}

?>