<?php
/**
* FastCurlMulti (PHP object-oriented wrapper for {@link http://curl.haxx.se/ cURL})
*
* Copyright (c) 2010 Antonio López Vivar
*
* LICENSE:
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {@link http://www.gnu.org/licenses}.
*
*
* @category Library
* @package FastCurl
* @author Antonio López Vivar <tonikelope@gmail.com>
* @copyright 2010 Antonio López Vivar
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version 1.6
*/
/**
* @property mixed $_mh curl_multi handle.
* @property array $_ch FastCurl objects locked to this container.
* @property bool $_multiset If it's activated, you can set the same CURLOPT to all FastCurl objects making $fastmulti_handle->curlopt=value;
* @property bool $_implicit_refresh If it's activated when a FastCurl object (locked to this container) property is set, FastCurl object will be refresh.
*/
class FastCurlMulti
{
const VERSION='1.6';
private $_mh=NULL;
private $_ch=NULL;
private $_multiset=NULL;
private $_implicit_refresh=NULL;
/**
* @param FastCurl $chandle (It can be a single FastCurl object or an array of FastCurl objects)
* @param bool $multiset If it's activated, you can set the same CURLOPT to all FastCurl objects making $fastmulti_handle->curlopt=value;
* @param bool $_implicit_refresh If it's activated when a FastCurl object (locked to this container) property is set, FastCurl object will be refresh.
* @return FastCurlMulti $this
*/
public function __construct($chandle=NULL, $multiset=FALSE, $implicit_refresh=TRUE)
{
$this->_mh=curl_multi_init();
$this->_ch=array();
if($chandle)
{
if(is_array($chandle))
{
foreach($chandle as $ch)
$this->add($ch);
}
else
$this->add($chandle);
}
$this->_multiset=is_bool($multiset)?$multiset:FALSE;
$this->_implicit_refresh=is_bool($implicit_refresh)?$implicit_refresh:TRUE;
return $this;
}
/**
* @return bool Set ok
*/
public function set_multiset($value)
{
if(($ret=is_bool($value)))
$this->_multiset=$value;
return $ret;
}
/**
* @return bool Set ok
*/
public function set_implicit_refresh($value)
{
if(($ret=is_bool($value)))
$this->_implicit_refresh=$value;
return $ret;
}
/**
* @return bool
*/
public function is_multiset()
{
return $this->_multiset;
}
/**
* @return bool
*/
public function is_implicit_refresh()
{
return $this->_implicit_refresh;
}
/**
* Before closing curl_multi_handle, we remove any FastCurl locked object.
*/
public function __destruct()
{
foreach($this->_ch as $ch)
$this->remove($ch);
curl_multi_close($this->_mh);
}
/**
* @param FastCurl $ch
*/
public function add(FastCurl $ch)
{
$ch->lockMulti($this);
}
/**
* @param FastCurl $ch
*/
public function remove(FastCurl $ch)
{
$ch->unlockMulti($this);
}
/**
* @param FastCurl $ch
*/
public function refresh(FastCurl $ch)
{
if($ch->unlockMulti($this))
$ch->lockMulti($this);
}
/**
* Executes all curl handles parallelly (fastcookies support).
*
* @param bool $verbose Prints '+' while looping for all requests (useful to avoid browser's timeout (PHP output buffer must be off)).
*/
public function exec($verbose=FALSE)
{
$ir_orig=$this->is_implicit_refresh();
$this->set_implicit_refresh(FALSE);
$fc_redir=array();
foreach($this->_ch as $fc)
if($fc->followlocation && (is_array($fc->get_fc_cookies()) || $fc->is_fast_followlocation()))
{
$fc_redir[]=array($fc, $fc->url, $fc->referer);
$fc->followlocation=FALSE;
}
do
{
$active=NULL;
$mrc=FALSE;
$redir=FALSE;
foreach($fc_redir as $fc)
if(is_array($fc[0]->get_fc_cookies()))
$fc[0]->send_fc_cookies_from_multi($this);
do
{
if($mrc===FALSE || curl_multi_select($this->_mh)!=-1)
{
while(($mrc=curl_multi_exec($this->_mh, $active))==CURLM_CALL_MULTI_PERFORM);
if($verbose)
echo '+ ';
}
}while($active && $mrc==CURLM_OK);
foreach($fc_redir as $fc)
{
if(($res=curl_multi_getcontent($fc[0]->get_ch_from_multi($this))))
{
if(is_array($fc[0]->get_fc_cookies()))
$fc[0]->receive_fc_cookies_from_multi($this, $res);
if(strpos(trim($fc[0]->info('HTTP_CODE')), '3')===0)
{
if($verbose)
echo '> ';
if($fc[0]->post && $fc[0]->info('HTTP_CODE')!=307)
$fc[0]->enable_post(FALSE);
preg_match('/(?:(?:Location)|(Refresh))\: *?(?(1)\d+; *?url\=)(?P<redir>[^\r\n]+)/i', $res, $url);
if(preg_match('/^(?!.*?\:\/\/)/', ($url['redir']=trim($url['redir']))))
$url['redir']=preg_replace('/(?<!\:\/)\/[^\/]+$/','',$fc[0]->url).'/'.ltrim($url['redir'], '/');
if($fc[0]->autoreferer)
$fc[0]->referer=$fc[0]->url;
$fc[0]->url=$url['redir'];
$this->refresh($fc[0]);
$redir=TRUE;
}
}
}
}while($redir);
foreach($fc_redir as $fc)
{
$fc[0]->set_last_url_from_multi($this, $fc[0]->url);
$fc[0]->url=$fc[1];
$fc[0]->referer=$fc[2];
$fc[0]->followlocation=TRUE;
}
$this->set_implicit_refresh($ir_orig);
}
/**
* @param FastCurl $ch
*/
public function accept(FastCurl $ch)
{
$this->_ch[] = $ch;
curl_multi_add_handle($this->_mh, $ch->get_ch_from_multi($this));
}
/**
* @param FastCurl $ch
*/
public function release(FastCurl $ch)
{
if(($key=array_search($ch, $this->_ch, TRUE))!==FALSE)
{
curl_multi_remove_handle($this->_mh, $ch->get_ch_from_multi($this));
unset($this->_ch[$key]);
}
}
/**
* Sets a CURLOPT for every FastCurl object in the container (if _multiset is ON)
*
* @param string $opt
* @param mixed $value
* @return bool CURLOPT set ok
*/
public function __set($opt, $value)
{
if(($ret=($this->is_multiset() && defined('CURLOPT_'.strtoupper($opt)))))
{
foreach($this->_ch as $ch)
$ch->$opt=$value;
}
return $ret;
}
}
/* ?> */
|