首页 PHP 正文
780

PHP之CURL的常用示例

1、GET方式请求网页数据
$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协议的话,对它的使用会更加有深刻的领会!

正在加载评论...