ares333 / php-curl
最佳PHP cURL库。
Requires
- php: >=5.3.0
- ext-curl: *
README
关于
使用php-curl内部io事件实现,具有高性能、高通用性、高可扩展性,特别适用于大量任务和复杂逻辑案例。
需求
PHP: >=5.3
安装
composer require ares333/php-curl
特性
- 极低的CPU和内存消耗。
- 直接暴露所有curl选项,实现高通用性和高可扩展性。
- API非常简单。
- 支持中断进程并从上次运行状态恢复。
- 支持动态任务。
- 支持透明文件缓存。
- 支持自动重试失败的任务。
- 支持全局配置、任务配置、回调配置,格式相同,优先级从低到高。
- 所有配置都可以动态更改并立即生效。
工作流程
Curl::add() 将任务添加到任务池。Curl::start() 开始事件循环并阻塞。当所有任务完成后,将触发事件(onSuccess,onFail,onInfo,onTask...)并动态调用回调。循环结束。
教程
基础
use Ares333\Curl\Curl; $curl = new Curl(); $curl->add( array( 'opt' => array( CURLOPT_URL => 'http://baidu.com', CURLOPT_RETURNTRANSFER => true ), 'args' => 'This is user argument' ), function ($r, $args) { echo "Request success for " . $r['info']['url'] . "\n"; echo "\nHeader info:\n"; print_r($r['info']); echo "\nRaw header:\n"; print_r($r['header']); echo "\nArgs:\n"; print_r($args); echo "\n\nBody size:\n"; echo strlen($r['body']) . ' bytes'; echo "\n"; }); $curl->start();
文件下载
use Ares333\Curl\Curl; $curl = new Curl(); $url = 'https://www.baidu.com/img/bd_logo1.png'; $file = __DIR__ . '/download.png'; // $fp is closed automatically on download finished. $fp = fopen($file, 'w'); $curl->add( array( 'opt' => array( CURLOPT_URL => $url, CURLOPT_FILE => $fp, CURLOPT_HEADER => false ), 'args' => array( 'file' => $file ) ), function ($r, $args) { if($r['info']['http_code']==200) { echo "download finished successfully, file=$args[file]\n"; }else{ echo "download failed\n"; } })->start();
任务回调
任务可以在任务回调中添加。有关更多信息,请参阅Curl::$onTask。
use Ares333\Curl\Toolkit; use Ares333\Curl\Curl; $toolkit = new Toolkit(); $toolkit->setCurl(); $curl = $toolkit->getCurl(); $curl->maxThread = 1; $curl->onTask = function ($curl) { static $i = 0; if ($i >= 50) { return; } $url = 'http://www.baidu.com'; /** @var Curl $curl */ $curl->add( array( 'opt' => array( CURLOPT_URL => $url . '?wd=' . $i ++ ) )); }; $curl->start();
运行信息
use Ares333\Curl\Toolkit; use Ares333\Curl\Curl; $curl = new Curl(); $toolkit = new Toolkit(); $curl->onInfo = array( $toolkit, 'onInfo' ); $curl->maxThread = 2; $url = 'http://www.baidu.com'; for ($i = 0; $i < 100; $i ++) { $curl->add( array( 'opt' => array( CURLOPT_URL => $url . '?wd=' . $i ) )); } $curl->start();
在命令行中运行并将以下格式的输出
SPD DWN FNH CACHE RUN ACTIVE POOL QUEUE TASK FAIL
457KB 3MB 24 0 3 3 73 0 100 0
'onInfo' 回调将接收所有信息。默认回调只显示部分信息。
SPD:Download speed
DWN:Bytes downloaded
FNH:Task count which has finished
CACHE:Cache count which were used
RUN:Task running count
ACTIVE:Task count which has IO activities
POOL:Task count in task pool
QUEUE:Task count which has finished and waiting for onSuccess callback to process
TASK:Task count has been added to the task pool
FAIL:Task count which has failed after retry.
透明缓存
use Ares333\Curl\Toolkit; use Ares333\Curl\Curl; $curl = new Curl(); $toolkit = new Toolkit(); $curl->onInfo = array( $toolkit, 'onInfo' ); $curl->maxThread = 2; $curl->cache['enable'] = true; $curl->cache['dir'] = __DIR__ . '/output/cache'; if (! is_dir($curl->cache['dir'])) { mkdir($curl->cache['dir'], 0755, true); } $url = 'http://www.baidu.com'; for ($i = 0; $i < 20; $i ++) { $curl->add( array( 'opt' => array( CURLOPT_URL => $url . '?wd=' . $i ) )); } $curl->start();
运行脚本第二次将输出:
SPD DWN FNH CACHE RUN ACTIVE POOL QUEUE TASK FAIL
0KB 0MB 20 20 0 0 0 0 20 0
结果表明所有任务都在使用缓存,没有网络活动。
动态任务
use Ares333\Curl\Curl; $curl = new Curl(); $url = 'http://baidu.com'; $curl->add(array( 'opt' => array( CURLOPT_URL => $url ) ), 'cb1'); echo "add $url\n"; $curl->start(); function cb1($r) { echo "finish " . $r['info']['url'] . "\n"; $url = 'http://bing.com'; $r['curl']->add( array( 'opt' => array( CURLOPT_URL => $url ) ), 'cb2'); echo "add $url\n"; } function cb2($r) { echo "finish " . $r['info']['url'] . "\n"; }
输出如下
add http://baidu.com
finish https://www.baidu.com/
add http://bing.com
finish http://cn.bing.com/
完成的URL有'/'后缀,因为cURL已自动处理了3xx重定向(Curl::$opt[CURLOPT_FOLLOWLOCATION]=true)。应使用Curl::onTask来处理大量任务。
Curl (src/Curl.php 核心功能)
public $maxThread = 10
最大工作并行数,可以动态更改。
public $maxTry = 3
在触发onFail事件之前最大重试次数。
public $opt = array ()
全局CURLOPT_*,可以由任务配置覆盖。
public $cache = array( 'enable' => false, 'compress' => 0, //0-9,6 is a good choice if you want use compress. 'dir' => null, //Cache dir which must exists. 'expire' => 86400, 'verifyPost' => false //If http post will be part of cache id. );
全局缓存配置。缓存ID从URL映射。配置可以由任务配置和onSuccess回调返回值覆盖。
public $taskPoolType = 'queue'
堆栈或队列。
public $onTask = null
当工作并行数小于Curl::$maxThread且任务池为空时触发。回调参数是当前的Curl实例。
public $onInfo = null
运行状态回调在IO事件上触发,最大频率为1/s。参数如下
- $info 数组包含两个键 'all' 和 'running'。键 'running' 包含每个正在运行的任务的响应头(curl_getinfo())。键 'all' 包含全局信息,键如下
- $info['all']['downloadSpeed'] 下载速度。
- $info['all']['bodySize'] 下载的正文大小。
- $info['all']['headerSize'] 下载的头部大小。
- $info['all']['activeNum'] 有IO活动的任务数。
- $info['all']['queueNum'] 等待onSuccess的任务数。
- $info['all']['finishNum'] 已完成的任务数。
- $info['all']['cacheNum'] 缓存命中数。
- $info['all']['failNum'] 重试后失败的任务数。
- $info['all']['taskNum'] 任务池中的任务数。
- $info['all']['taskRunningNum'] 运行中的任务数。
- $info['all']['taskPoolNum'] 任务池数。
- $info['all']['taskFailNum'] 重试的任务数。
- 当前的Curl实例。
- 是否是最后的调用。
public $onEvent = null
在IO事件上触发。回调参数是当前的Curl实例。
public $onFail = null
全局失败的回调,可以由任务的 'onTask' 覆盖。该回调接收两个参数。
- 包含以下键的数组:
- errorCode CURLE_* 常量。
- errorMsg 错误消息。
- info 响应头。
- 当前Curl实例。
- Curl::add()中返回的$item['args']值。
public function add(array $item, $onSuccess = null, $onFail = null, $ahead = null)
向池中添加一个任务。
- $item
- $item['opt'] = array(),用于当前任务的CURLOPT_*。
- $item['args'],回调函数的参数。
- $item['cache'] = array(),当前任务的缓存配置。
- $onSuccess,任务完成后触发。
- 回调函数有两个参数:
- $result,数组,键如下所示
- $result['info'],响应头。
- $result['curl'],当前Curl实例。
- $result['body'],响应体。在下载任务中不存在。
- $result['header'],原始响应头。当CURLOPT_HEADER启用时存在。
- $result['cacheFile'],当使用缓存时存在。
- 从$item['args']中获取值
- $result,数组,键如下所示
- 可以返回值。如果存在,必须为数组。数组键如下所示
- cache,与Curl::$cache相同格式。这是最后一次控制缓存的机会。
- 回调函数有两个参数:
- $onFail,覆盖Curl::$onFail。
- $ahead,是否添加到高优先级队列。
返回:当前Curl实例。
public function start()
启动事件循环并阻塞。
public function stop()
停止事件循环并返回未处理的任务。
public function parseResponse($response)
从响应中解析http头和体。
public function getCacheFile($url, $post = null)
生成相对缓存路径。
工具包(src/Toolkit.php必要的工具)
function setCurl($curl = null)
如果$curl为null,则使用默认Curl实例。
默认实例将初始化Curl::$opt、Curl::onInfo、Curl::onFail。Curl::$opt的初始值如下
array( CURLINFO_HEADER_OUT => true, CURLOPT_HEADER => true, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, CURLOPT_AUTOREFERER => true, CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36', CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_MAXREDIRS => 5 )
function onFail($error, $args)
默认失败回调。有关详细信息,请参阅Curl::$onFail。
function onInfo($info)
默认信息回调。有关详细信息,请参阅Curl::onInfo。
可以通过字符串参数手动触发此方法,该参数将被添加到输出缓冲区。目的是避免shell控制字符的干扰。
function htmlEncode($html, $in = null, $out = 'UTF-8', $mode = 'auto')
强大的HTML编码转换器,可以自动获取当前编码并在
中替换HTML编码值。参数:- $html,HTML字符串。
- $in,当前编码。最好指定一个。
- $out,目标编码。
- $mode,auto|iconv|mb_convert_encoding。
返回:新的编码HTML。
function isUrl($url)
是否为完整URL。返回bool。
function formatUrl($url)
替换空格,处理方案和主机,并删除锚点等。
function buildUrl(array $parse)
parse_url()的逆函数。
function uri2url($uri, $urlCurrent)
将uri转换为currentPage的完整URL。$urlCurrent在3xx后应该被重定向。
function url2uri($url, $urlCurrent)
将完整URL转换为currentPage的uri。$urlCurrent在3xx后应该被重定向。
function url2dir($url)
将完整URL转换为dir。$urlCurrent在3xx后应该被重定向。
function url2absolute($url, $urlCurrent)
将基本URL和相对URL组合以生成新的绝对URL。
function urlRemoveDotSegments($path)
从URL的路径中过滤出"."和".."段,并返回结果。
function getCurl()
返回当前Curl实例。