上回文章中我们已经学习了 CURL 的基本操作,对于一个能够发送 GET 和 POST 数据的远程请求扩展来说,经常也会使用 CURL 来进行爬虫或是自动操作的一些项目的开发,在这其中,还有许多功能也是我们经常会使用到的,比如文件上传以及多个请求同时发送。这个在笔者的实际工作开发中也都是做过的东西,相对来说,CURL 的这些功能肯定不如直接的 POST 请求之类的功能常用,但它们的出镜率也着实不低。
文件上传
首先就是文件上传功能,PHP5.5 之前和之后的语法是不一样的,这里我们当然是以最新的方式来演示文件上传功能的实现。
$file = "./1.学习一个PHP中用于检测危险函数的扩展Taint.php";
$ch = curl_init("http://localhost:9001");
$cfile = new CURLFile($file, 'text/plain', 'phpfile.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POST => 1,
// CURLOPT_POSTFIELDS => ['a' =>' post测试', 'files' => curl_file_create($file, 'text/plain', 'phpfile.php')],
CURLOPT_POSTFIELDS => ['a' => 'post测试', 'files' => $cfile],
]);
$res = curl_exec($ch);
curl_close($ch);
var_dump($res);
// string(244) "测试数据
// post测试
// Array
// (
// [files] => Array
// (
// [name] => phpfile.php
// [type] => text/plain
// [tmp_name] => /private/tmp/phpvKyesy
// [error] => 0
// [size] => 1785
// )
// )
// "
例子非常简单,也是文件上传最基本的实现。我们需要的就只是在 POST 字段中添加一个 CURLFile 对象就可以实现文件的上传功能。它在实例化的时候需要三个参数,分别是要上传的文件路径、mime类型以及上传时显示的文件名。关于这个上传时的文件名,我们可以看到在服务端打印 $_FIELS 时,就会显示在 name 字段中。对于最常用的图片文件来说,mime类型就是常用的 image/jpeg 之类的,而对于文本文件,直接使用 text/plain 就可以了,就像我们在这个测试代码中直接上传的 php 文件一样。
除了使用 CURLFile 对象进行实例化以外,我们还可以直接使用一个 curl_file_create() 函数,它的作用也是返回一个 CURLFile 对象,其实就是 CURLFile 对象实例化的面向过程写法而已,作用和参数都是一样的。
批量 CURL 请求
这个功能是我之前在做广告系统时使用过的,对于发出去的广告文章,百度是否收录了,就会使用这种批量的请求来查看多个链接中是否包含我们的广告数据。当然,它并不是并发执行的,而是按顺序请求的。
$ch1 = curl_init();
$ch2 = curl_init();
curl_setopt($ch1, CURLOPT_URL, "https://www.baidu.com/");
curl_setopt($ch2, CURLOPT_URL, "http://localhost:9001");
curl_setopt($ch2, CURLOPT_POST, 1);
curl_setopt($ch2, CURLOPT_POSTFIELDS, ['a' => 'post测试']);
$mh = curl_multi_init();
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
$running=null;
do {
sleep(2);
curl_multi_exec($mh,$running);
echo "============= ", $running, " =============", PHP_EOL;
} while ($running > 0);
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
// ============= 2 =============
// ============= 2 =============
// ============= 2 =============
// 测试数据
// post测试
// ============= 2 =============
// ============= 1 =============
// <!DOCTYPE html><!--STATUS OK-->
// <html>
// <head>
// <meta http-equiv="content-type" content="text/html;charset=utf-8">
// <meta http-equiv="X-UA-Compatible" content="IE=Edge">
// <link rel="dns-prefetch" href="//s1.bdstatic.com"/>
// <link rel="dns-prefetch" href="//t1.baidu.com"/>
// <link rel="dns-prefetch" href="//t2.baidu.com"/>
// <link rel="dns-prefetch" href="//t3.baidu.com"/>
// <link rel="dns-prefetch" href="//t10.baidu.com"/>
// <link rel="dns-prefetch" href="//t11.baidu.com"/>
// <link rel="dns-prefetch" href="//t12.baidu.com"/>
// <link rel="dns-prefetch" href="//b1.bdstatic.com"/>
// <title>百度一下,你就知道</title>
// ………………………………
// ………………………………
// ………………………………
// </body></html>
// ============= 0 =============
通过 curl_multi_init() 获得一个批量执行的 CURL 句柄,然后 curl_multi_add_handle() 添加普通的 CURL 句柄。在执行的时候就会按照添加的顺序依次执行请求。每个请求都可以单独设置自己的各种选项参数,比如我们这里就是分别使用 GET 和 POST 进行不同的请求。
在执行的过程中,可以看出,后添加的请求会先执行。curl_multi_exec() 中的第二个参数是一个引用参数,会不断地返回当前执行的任务,从第 2 个任务开始递减,直到没有任务,也就是我们判断的 running > 0 这个条件。
总结
CURL 中其实还有其它的一些功能,比如 curl_share_init() 这种共享句柄,不过使用的频率不高,但它是可以在不同的请求句柄之间共享一些数据的,比如说 cookie 数据。有需要的同学可以自己查阅相关的文档。对于 CURL 的功能就简单的介绍到这里,因为它的使用还是比较频繁的,而且更多的是在于各种 opt 常量的设置,这块除了常用的那些之外,更多的情况还是去文档中查找自己需要的内容,毕竟记忆的成本太大了。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/02/source/5.学习CURL扩展功能的使用(二).php
参考文档:
https://www.php.net/manual/zh/ref.curl.php