ares333/php-curl

最佳PHP cURL库。

v4.6.1 2018-12-13 03:47 UTC

README

关于

使用php-curl内部io事件实现,具有高性能、高通用性、高可扩展性,特别适用于大量任务和复杂逻辑案例。

需求

PHP: >=5.3

安装

composer require ares333/php-curl

特性

  1. 极低的CPU和内存消耗。
  2. 直接暴露所有curl选项,实现高通用性和高可扩展性。
  3. API非常简单。
  4. 支持中断进程并从上次运行状态恢复。
  5. 支持动态任务。
  6. 支持透明文件缓存。
  7. 支持自动重试失败的任务。
  8. 支持全局配置、任务配置、回调配置,格式相同,优先级从低到高。
  9. 所有配置都可以动态更改并立即生效。

工作流程

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。参数如下

  1. $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'] 重试的任务数。
  2. 当前的Curl实例。
  3. 是否是最后的调用。
public $onEvent = null

在IO事件上触发。回调参数是当前的Curl实例。

public $onFail = null

全局失败的回调,可以由任务的 'onTask' 覆盖。该回调接收两个参数。

  1. 包含以下键的数组:
  • errorCode CURLE_* 常量。
  • errorMsg 错误消息。
  • info 响应头。
  • 当前Curl实例。
  1. Curl::add()中返回的$item['args']值。
public function add(array $item, $onSuccess = null, $onFail = null, $ahead = null)

向池中添加一个任务。

  • $item
    1. $item['opt'] = array(),用于当前任务的CURLOPT_*。
    2. $item['args'],回调函数的参数。
    3. $item['cache'] = array(),当前任务的缓存配置。
  • $onSuccess,任务完成后触发。
    • 回调函数有两个参数:
      1. $result,数组,键如下所示
        • $result['info'],响应头。
        • $result['curl'],当前Curl实例。
        • $result['body'],响应体。在下载任务中不存在。
        • $result['header'],原始响应头。当CURLOPT_HEADER启用时存在。
        • $result['cacheFile'],当使用缓存时存在。
      2. 从$item['args']中获取值
    • 可以返回值。如果存在,必须为数组。数组键如下所示
      • 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实例。