chuyskywalker/rolling-curl
Composer 安装命令:
composer require chuyskywalker/rolling-curl
包简介
Rolling-Curl: A non-blocking, non-dos multi-curl library for PHP
README 文档
README
A cURL library to fetch a large number of resources while maintaining a consistent number of simultaneous connections
Authors:
- Jeff Minard (jrm.cc)
- Josh Fraser (joshfraser.com)
- Alexander Makarov (rmcreative.ru)
Overview
RollingCurl is a more efficient implementation of curl_multi().
curl_multi is a great way to process multiple HTTP requests in parallel in PHP but suffers from a few faults:
- The documentation for curl_multi is very obtuse and, as such, is easy to incorrectly or poorly implement
- Most curl_multi examples queue up all requests and execute them all at once
The second point is the most important one for two reasons:
- If you have to wait on every single request to complete, your program is "blocked" by the longest running request.
- More importantly, when you run a large number of cURL requests simultaneously you are, essentially, running a DOS attack. If you have to fetch hundreds or even thousands of URLs you're very likely to be blocked by automatic DOS systems. At best, you're not being a very respectful citizen of the internet.
RollingCurl deals with both issues by maintaining a maximum number of simultaneous requests and "rolling" new requests into the queue as existing requests complete. When requests complete, and while other requests are still running, RollingCurl can run an anonymous function to process the fetched result. (You have the option to skip the function and instead process all requests once they are done, should you prefer.)
Installation (via composer)
Get composer and add this in your requires section of the composer.json:
{
"require": {
"chuyskywalker/rolling-curl": "*"
}
}
and then
composer install
Usage
Basic Example
$rollingCurl = new \RollingCurl\RollingCurl(); $rollingCurl ->get('http://yahoo.com') ->get('http://google.com') ->get('http://hotmail.com') ->get('http://msn.com') ->get('http://reddit.com') ->setCallback(function(\RollingCurl\Request $request, \RollingCurl\RollingCurl $rollingCurl) { // parsing html with regex is evil (http://bit.ly/3x9sQX), but this is just a demo if (preg_match("#<title>(.*)</title>#i", $request->getResponseText(), $out)) { $title = $out[1]; } else { $title = '[No Title Tag Found]'; } echo "Fetch complete for (" . $request->getUrl() . ") $title " . PHP_EOL; }) ->setSimultaneousLimit(3) ->execute();
Fetch A Very Large Number Of Pages
Let's scrape google for the first 500 links & titles for "curl"
$rollingCurl = new \RollingCurl\RollingCurl(); for ($i = 0; $i <= 500; $i+=10) { // https://www.google.com/search?q=curl&start=10 $rollingCurl->get('https://www.google.com/search?q=curl&start=' . $i); } $results = array(); $start = microtime(true); echo "Fetching..." . PHP_EOL; $rollingCurl ->setCallback(function(\RollingCurl\Request $request, \RollingCurl\RollingCurl $rollingCurl) use (&$results) { if (preg_match_all('#<h3 class="r"><a href="([^"]+)">(.*)</a></h3>#iU', $request->getResponseText(), $out)) { foreach ($out[1] as $idx => $url) { parse_str(parse_url($url, PHP_URL_QUERY), $params); $results[$params['q']] = strip_tags($out[2][$idx]); } } // Clear list of completed requests and prune pending request queue to avoid memory growth $rollingCurl->clearCompleted(); $rollingCurl->prunePendingRequestQueue(); echo "Fetch complete for (" . $request->getUrl() . ")" . PHP_EOL; }) ->setSimultaneousLimit(10) ->execute(); ; echo "...done in " . (microtime(true) - $start) . PHP_EOL; echo "All results: " . PHP_EOL; print_r($results);
Setting custom curl options
For every request
$rollingCurl = new \RollingCurl\RollingCurl(); $rollingCurl // setOptions will overwrite all the default options. // addOptions is probably a better choice ->setOptions(array( CURLOPT_HEADER => true, CURLOPT_NOBODY => true )) ->get('http://yahoo.com') ->get('http://google.com') ->get('http://hotmail.com') ->get('http://msn.com') ->get('http://reddit.com') ->setCallback(function(\RollingCurl\Request $request, \RollingCurl\RollingCurl $rollingCurl) { echo "Fetch complete for (" . $request->getUrl() . ")" . PHP_EOL; }) ->setSimultaneousLimit(3) ->execute();
For a single request:
$rollingCurl = new \RollingCurl\RollingCurl(); $sites = array( 'http://yahoo.com' => array( CURLOPT_TIMEOUT => 15 ), 'http://google.com' => array( CURLOPT_TIMEOUT => 5 ), 'http://hotmail.com' => array( CURLOPT_TIMEOUT => 10 ), 'http://msn.com' => array( CURLOPT_TIMEOUT => 10 ), 'http://reddit.com' => array( CURLOPT_TIMEOUT => 25 ), ); foreach ($sites as $url => $options) { $request = new \RollingCurl\Request($url); $rollingCurl->add( $request->addOptions($options) ); } $rollingCurl->execute();
More examples can be found in the examples/ directory.
TODO:
- PHPUnit test
- Ensure PSR spec compatibility
- Fix TODOs
- Better validation on setters
Feel free to fork and pull request to help out with the above. :D
Similar Projects
chuyskywalker/rolling-curl 适用场景与选型建议
chuyskywalker/rolling-curl 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 459.24k 次下载、GitHub Stars 达 207, 最近一次更新时间为 2013 年 05 月 30 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「curl」 「http」 「requests」 「parallel」 「multi」 「asynchronous」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 chuyskywalker/rolling-curl 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 chuyskywalker/rolling-curl 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 chuyskywalker/rolling-curl 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
cURL and cURL based Soap-Client for PHP
repository php library
Rest client to make GET, POST, PUT, DELETE, PATCH, etc calls.
Simple cURL wrapper
This package is free and can be used for API Brazil website functions
A simple package to better handle application requests.
统计信息
- 总下载量: 459.24k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 213
- 点击次数: 26
- 依赖项目数: 8
- 推荐数: 0
其他信息
- 授权协议: Apache-2.0
- 更新时间: 2013-05-30