$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://xxx.com/?id=23&type=1');//get参数直接带在url后面就行。 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //为啥要设置为1,呵呵,如果不设置为1,那么返回的数据不会投递到接收的变量里,而是直接输出到屏幕, //用命令式窗口执行交互脚本就会直接打印在命令窗口上了。 curl_setopt($ch, CURLOPT_HEADER, 0); //如果你要显示全部网页内容,包括hear头,就应该设置成1。 //如果你只想得到网页body部分的内容,那么就设置成0。 //很常用的地方就是用curl调用远程接口时,如果接口返回的是json数据, //就不能接收header信息,这会影响你解析json的(设置成1,你会发现用json_decode根本解析不出来返回的结果)。 $ret = curl_exec($ch); //如果返回的是json格式的数据,那么用json_decode($ret,true)解析成数组。 //这里顺便提一个小技巧,如果请求的地址返回的是jsonp形式的数据就无法用json_decode解析, //那么可以试着把url后面的callback参数去掉再去访问试试。 curl_close($ch);2、POST方式提交数据
$ch = curl_init(); $id = 28; $ip = '127.0.0.1'; $fields = "id=$id&ip=$ip"; //需要提交的post字段,要想想是否有必要对字段值进行urlencode编码。 //当然也可以用关联数组的方式,like this: $fields = array('id'=>$id,'ip'=>$ip); //注:传递一个数组到CURLOPT_POSTFIELDS时,cURL会把数据编码成 multipart/form-data, //而传递一个URL-encoded字符串时,数据会被编码成 application/x-www-form-urlencoded, //使用这两种方式的话,在接收端都可以通过POST方式得到请求字段。 curl_setopt($ch, CURLOPT_URL, 'http://xxx.com/api'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); $ret = curl_exec($ch); curl_close($ch); //注:曾经有网友利用curl可以GET到的某网页,但是换成POST之后却不行了。 //然后别人给了解决方案就是强制使用http1.0协议进行post:curl_setopt( $ch , CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_0 ); //为什么呢,据说http1.1的PUT,POST等资源操作方式都可以在服务端进行屏蔽, //例如apache:<limitexcept GET> deny from all </limitexcept> <limit POST> deny from all </limit>3、如果目标地址需要绑定IP才能访问怎么办?
$ch = curl_init(); $ip = '212.18.22.15'; $host = 'demo.hello.com'; $header = array("Host:".$host);//构造header curl_setopt($ch, CURLOPT_URL, 'http://'.$ip.'/api/info');//注意这里用的是ip curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch,CURLOPT_HTTPHEADER,$header );//把header传这里 $ret = curl_exec($ch); curl_close($ch);4、如果目标地址需要通过指定代理服务器访问怎么办?
$ch = curl_init(); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://www.xxx.cn'); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);//启用代理 curl_setopt($ch, CURLOPT_PROXY, 'proxy.lxvoip.com:1080');//代理服务器地址和端口 curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'user:password');//如果此代理服务器需要用户名和密码的话,在这里设置。 $data = curl_exec($ch); curl_close($ch);5、如果目标地址要带安全证书怎么办?
$ch = curl_init(); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://www.xxx.cn'); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSLCERT, ’c:/web/ssl/apiclient_cert.pem‘);//cert证书路径。 curl_setopt($ch, CURLOPT_SSLKEY, ’c:/web/ssl/apiclient_key.pem‘);//key证书路径。 $data = curl_exec($ch); curl_close($ch);6、如何使用curl上传文件?(PHP5.5及以后的版本,上传文件得借助CURLFile类)
$ch = curl_init(); $data = array('picno' => 'pic001', 'file1' => '@F:\website\images\pic.png'); //文件路径前面要加@符号,这样才会被认为是文件地址。 //而且文件路径必须是绝对地址,相对地址是行不通的。 curl_setopt($ch, CURLOPT_URL, 'http://demo.com/uploadPic.php'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data);//注意啦,要上传就得用数组形式的post数据。 //curl_setopt($ch, CURLOPT_UPLOAD, 1);//本以为这个参数是用来开启上传的,结果发现根本不能配置这个选项, //一配置它上传就不成功。 $out = curl_exec($ch); curl_close($ch);uploadPic.php代码:
$picno= $_POST['picno']; $picFile = date('YmdHis').$picno.'.jpg'; move_uploaded_file($_FILES['file1']['tmp_name'],$picFile); echo "success,".$picno;7、如何带cookie请求目标地址?
//POST数据,获取COOKIE $cookie_file = dirname(__FILE__) . '/cookie.txt'; $ch = curl_init($login_url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); curl_exec($ch); curl_close($ch); //带着上面得到的COOKIE获取需要登录后才能查看的页面内容 $ch = curl_init($get_url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); $contents = curl_exec($ch); curl_close($ch);8、FTP上传
//$remoteUrl = "ftp://xxx.xxx.xxx/log/test.png";//如果直接使用纯粹的地址话,要用CURLOPT_USERPWD选项设置用户名和密码 $remoteUrl = "ftp://motc_myname:".urlencode('mypass@2015')."@xxx.xxx.xxx/log/test.png"; //密码中含有@等特殊符号使用urlencode编码 $ch = curl_init(); $localFile = 'F:\website\tryit.com\arrow.png'; $fh = fopen($localFile, 'rb'); curl_setopt($ch, CURLOPT_URL, $remoteUrl); //curl_setopt($ch, CURLOPT_USERPWD, 'motc_myname:mypass@2015');//单独设置连接用的用户名和密码 curl_setopt($ch, CURLOPT_UPLOAD, 1);//准备FTP上传 curl_setopt($ch, CURLOPT_INFILE, $fh);//这个文件是你传送过来的输入文件。 curl_setopt($ch, CURLOPT_INFILESIZE, filesize($localFile)); $ret = curl_exec($ch); print "Error: " . curl_error($ch).'<br>'; curl_close($ch); var_dump($ret);9、FTP下载
$remoteUrl = "ftp://xxx.xxx.xxx/log/test.png"; $ch = curl_init(); $localFile = 'D:\test_arrow.png'; curl_setopt($ch, CURLOPT_URL, $remoteUrl); curl_setopt($ch, CURLOPT_USERPWD, 'motc_myname:mypass@2015'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $fh = fopen($localFile, 'wb'); curl_setopt($ch, CURLOPT_FILE, $fh);//这个文件将是你放置传送的输出文件,默认是STDOUT $ret = curl_exec($ch); fclose($fh); print "Error: " . curl_error($ch).'<br>'; curl_close($ch); var_dump($ret);10、另一些常用的配置参数:
CURLOPT_NOBODY: 为true时不要网页的body内容。
CURLOPT_PORT: 指定端口。
CURLOPT_TIMEOUT: 设置超时的秒数。
CURLOPT_TIMEOUT_MS:设置超时的毫秒数,在cURL 7.16.2中被加入。
CURLOPT_REFERER:设置referer。
CURLOPT_USERAGENT: 设置代理特征串!
忽略ssl证书:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 目标网址为自签名证书时往往需要跳过ssl检查。对应curl -k 参数
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // 请求头host的值与自签名证书的域名不匹配时,会触发错误,所以要关闭host检查。
11、利用curl_getinfo获取网页信息
在不知道这个函数之前,判断目标网址返回的http状态码时,我利用以下代码:
$ch = curl_init($url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); $ret = curl_exec($ch); curl_close($ch); $lines = explode("\n", $ret); $httpStatus = trim($lines[0]); if($httpStatus != 'HTTP/1.1 403 Forbidden'){ echo "403"; }else{ echo "other"; }其实用curl_getinfo()很容易得到状态码:
$res = curl_getinfo($ch);
$statusCode = $res['http_code'];//可以把$res打印出来,你会发现它包含了所有头信息。
或者更直接一点:
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);//第二个参数表明是要获取的目标字段名,更多参数请查阅文档
12、模拟浏览器发起请求的示例
$post_data = '{"openid":"xxxxxxxxxxx","company":"T","agntnum":"37052089"}'; $url = "http://mss.xxxxx.cn/vote/ifVote/"; $headers = array( "POST http://mss.xxxxx.cn/vote/ifVote/ HTTP/1.1", "Host: mss.xxxxxx.cn", "Connection: keep-alive", "Content-Length: ".strlen($post_data), //请求体的数据大小(字节,一个字节=一个英文字符) "Cache-Control: no-cache", "Pragma: no-cache", "Origin: http://mss.xxxxx.cn", "X-Requested-With: XMLHttpRequest", "Content-Type: application/json; charset=UTF-8",//这个东西很重要,可以研究一下 "Accept: */*", "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36", "Referer: http://mss.xxxxx.cn/vote/vote/", "Accept-Encoding: gzip,deflate,sdch", "Accept-Language: zh-CN,zh;q=0.8", "Cookie: JSESSIONID=1D2618AC52E4FE05FFC55AE79B57E6BB; BIGipServerwmss_web_pool=373720842.37407.0000", //"Content-type: text/xml;charset=\"utf-8\"", ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 60); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); //设置请求头 curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); $data = curl_exec($ch); if (curl_errno($ch)) { print "Error: " . curl_error($ch); } else { $json = json_decode($data); $echoMsg = '投票失败'; if($json->Data->code=='success') $echoMsg = '投票成功'; echo $echoMsg ; curl_close($ch); }通过这个示例,我们可以用php模拟浏览器提交,如果不知道如何写header的话,可以用fiddler工具抓个包,将里面的header复制出来处理一下就行了。刚才上面提到了header中的一个Content-Type字段,这个东东还是有点讲究的,在本例中,它的值是application/json; charset=UTF-8,所以在服务端应该不可以通过POST字段获取到请求的数据,如果是php的话,可能需要用到这个$GLOBALS["HTTP_RAW_POST_DATA"]来获取,但我没有尝试过。
其实,通过jquery的ajax方法,也是可以设置Content-Type的,可以在ajax参数中加入:contentType: "application/json; charset=utf-8",在chrome的开发者工具的network中可以看到,提交的headers中会出现Request Payload这个字段,这个字段的值就是你要提交给后台的post数据,但是它是一个json对象(前提是你的post数据是合法的json字符串格式,可以用JSON.stringify()进行格式化)。默认情况下,jq的ajax的contentType值是application/x-www-form-urlencoded,所以提交数据的时候,我们可以在看到chrome开发工具的network中看到Form Data字段,这个字段下面就是你要提交的每个post数据项。不同的contentType设置,意味着提交到后台的数据格式是不一样的,这一点要注意。
13、如何处理Location跳转。有些网站登录成功之后,会在header头中加入Location跳转链接去到需要登录态的页面。此时需要跟踪这个跳转。
$post_data = "csrfmiddlewaretoken=$token&username=$user&password=$password"; $post_url = "http://code.xxxx.org/login/"; $cookie_file = tempnam($_SERVER['SystemRoot'].'/temp','tmp');//保存cookie的文件路径 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$post_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 3*60); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//302-Location跳转 curl_setopt($ch, CURLOPT_MAXREDIRS, 1); //控制最大深度为1 curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);//保存登录cookie $html = curl_exec($ch); if (curl_errno($ch)) { $this->curlErro = curl_errno($ch).':'.curl_error($ch); curl_close($ch); exit; } curl_close($ch);14、当使用Http1.1协议进行POST提交,并且POST的数据大于1024字节时,curl并不会直接发起POST请求, 而是会分为俩步:
1)发送一个请求, Header包含一个Expect:100-continue, 询问目标Server是否愿意接受数据。
2)如果目标Server能够接受请求,则会返回一个100-continue应答,这时,CURL才开始真正地把数据POST到目标Server。
于是,这样就有了一个问题, 并不是所有的Server都会正确应答100-continue, 比如lighttpd1.4(1.5已经解决此问题), 就会返回417 “Expectation Failed”, 则会造成逻辑出错。那么如何解决这个问题呢?有两种方案:
a、将HTTP1.1协议降级到1.0, 此法过low,不推荐使用。
b、修改Header头,如下:
<?php
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
?>
15、Basic Authorization (认证请求)
$username = 'myusername';
$password = 'password123';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
//或者:curl_setopt($ch, CURLOPT_USERNAME, $username);curl_setopt($ch, CURLOPT_PASSWORD, $password);
$data = curl_exec($ch);
curl_close($ch);
服务端PHP验证:
$username = @$_SERVER['PHP_AUTH_USER'];
$password = @$_SERVER['PHP_AUTH_PW'];
if ($username != 'myusername' || $password != 'password123') {
header('WWW-Authenticate:Basic realm="Require username and password."');//realm是自定义提示消息
header('status: 401 Unauthorized');
exit;
}
echo 'Login successfully';
注意:在apache中以模块方式运行php的话方可得到环境变量PHP_AUTH_USER和PHP_AUTH_PW。服务端如果是以cgi方式运行php, 认证提交的用户名和密码字段将无法获取,此时需要修改apache配置,手动设置环境变量,如下:
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
总之,php的curl非常强大,特别是如果你很熟悉HTTP协议的话,对它的使用会更加有深刻的领会!