以前讲过很多关于curl模拟登陆用户的一些例子了,今天我来介绍一个登录百度产品的一个php程序代码,希望文章给你带来帮助,此文章只供学习使用。
最近弄了一个工具,希望能获取自己百度网盘里面的数据但又不想公开数据,于是想到了模拟登陆百度,用常规的模拟登陆测试了下发现不行,抓取登陆时的数据才发现,其实百度登陆过程中跳转了几次页面,如果仅仅对http://passport.baidu.com/v2/api/?login一个页面获取cookie是不完整的那样就只有BAIDUID的值,而仅仅这个cookie值是没有多少作用的。
通过对抓包数据的分析,实际登陆过程中是先请求了一次http://passport.baidu.com/v2/api/?getapi&class=login&tpl=mn&tangram=true这个页面,服务器同时给浏览器设置两个cookie,一个BAIDUID的cookie值,这个应该是与seesion id相关的;另一个是
Set-Cookie:
HOSUPPORT=1; expires=Thu, 19-Aug-2021 15:41:37 GMT; path=/; domain=passport.baidu.com; httponly
推测这个应该是百度检测浏览器是否支持cookie;
再次请求该页面,获取网页数据会得到一个token值用于登陆;
然后登陆成功会得到BDUSS等相关的cookie值,以上才是登陆成功,记录下上面的cookie即可!
下面是简单的请求及登陆函数集合,作为基础类吧,可能简单了点,以后再完善吧!
代码如下 |
复制代码 |
<?php
/**
* 百度基础类
* @author qaulau@hotmail.com
* @file baidu.php
* @date 2013-6-2 www.111cn.net
*/
class baidu{
private $cookie = '';
private $username = '';
private $password = '';
const COOKIE_DIR = 'temp'; //cookie存放目录
const COOKIE_VALIDATE = 604800; //cookie有效期,默认为7天
const SECRET_KEY = 'hAFS6as8askNBVSuiealkkw'; //密钥用于加密cookie文件名,防止保存的cookie路径被猜测
private function http_request($url, $post_data, $referef,$header = true){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if ($post_data != ""){
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
if ($referef != ""){
curl_setopt($ch, CURLOPT_REFERER, $referef);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, $header);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31");
if ($this->cookie != ""){
curl_setopt($ch, CURLOPT_COOKIE, $this->cookie);
}
$data = curl_exec($ch);
curl_close($ch);
if ($header){
preg_match_all('/Set-Cookie:((.+)=(.+))$/m ', $data, $cookies);
if(is_array($cookies) && count($cookies) > 1 && count($cookies[1]) > 0){
foreach($cookies[1] as $i => $k){
$cookieinfos = explode(";", $k);
if(is_array($cookieinfos) && count($cookieinfos) > 1){
$this->cookie .= $cookieinfos[0];
$this->cookie .= "; ";
}
}
}
}
return $data;
}
private function login(){
//生成一个cookie
$ret = $this->http_request("https://passport.baidu.com/v2/api/?getapi&class=login&tpl=mn&tangram=true", "", "");
//获取token并保存cookie
$ret = $this->http_request("https://passport.baidu.com/v2/api/?getapi&class=login&tpl=mn&tangram=true", "", "");
preg_match_all('/login_token='(.+)'/', $ret, $tokens);
$login_token = $tokens[1][0];
//登陆并保存cookie
$post_data = array();
$post_data['username'] = $this->username;
$post_data['password'] = $this->password;
$post_data['token'] = $login_token;
$post_data['charset'] = "UTF-8";
$post_data['callback'] = "parent.bd12Pass.api.login._postCallback";
$post_data['index'] = "0";
$post_data['isPhone'] = "false";
$post_data['mem_pass'] = "on";
$post_data['loginType'] = "1";
$post_data['safeflg'] = "0";
$post_data['staticpage'] = "https://passport.baidu.com/v2Jump.html";
$post_data['tpl'] = "mn";
$post_data['u'] = "http://www.baidu.com/";
$post_data['verifycode'] = "";
$ret = $this->http_request("http://passport.baidu.com/v2/api/?login", $post_data, "https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F");
//记录下所有cookie
$this->writeCookie();
}
private function writeCookie(){
if(!file_exists(self::COOKIE_DIR)){
@mkdir(self::COOKIE_DIR) && touch(self::COOKIE_DIR.'/index.html');
}
$filename = self::COOKIE_DIR.'/'.md5($this->username.self::SECRET_KEY);
file_put_contents($filename, $this->cookie);
}
public function baidu($username,$password){
$this->username = $username;
$this->password = $password;
$filename = self::COOKIE_DIR.'/'.md5($this->username.self::SECRET_KEY);
if ((@filemtime($filename)+ self::COOKIE_VALIDATE > time()) && ($cookie = file_get_contents($filename))!= ''){
//如果cookie在有效期内且不为空
$this->cookie = $cookie;
}else {
$this->login();
}
}
/** www.111Cn.net
* 请求页面
* @param string $url :页面地址
* @param string $referef :引用页面
* @param string $post_data :post数据,如果填写则为post方式否则为get方式
* 返回页面数据
*/
public function request($url,$referef = '',$post_data = ''){
return $this->http_request($url,$referef,$post_data,false);
}
}
|
这个只是基本的类,只涉及登陆及请求与提交数据,可在此基础上使用,例如请求百度云网盘:
代码如下 |
复制代码 |
$baidu = new baidu('用户名','密码');
$data = $baidu->request('http://pan.baidu.com/api/list?channel=chunlei&clienttype=0&web=1&num=100&page=1&dir=%2F','http://pan.baidu.com');
echo $data;
|
还可以用来作为贴吧的发帖或百度空间更新工具.
实现的原理比较简单只要获取用户IP然后再在我们黑名单库中验证一下当前IP是不是存在即可进行过滤操作了,具体例子如下。
段代码是我在网上搜相关解决方法时搜到的,这个类的makePregIP函数逻辑有点问题,我修改了下可以使用了。这个类得功能是允许白名单中的IP地址访问,如果要实现限制黑名单中的IP地址访问,简单修改下checkIP函数中的代码逻辑就可以了。
使用方法
代码如下 |
复制代码 |
$allow_ip = array("192.168.1.1","210.10.2.1-20","222.34.4.*","127.0.0.1");
$oBlock_ip = new allowIp($allow_ip);
if( !$oBlock_ip->checkIP() ){
echo '您的IP为:';
echo $oBlock_ip->ip;
exit('禁止访问');
}
|
allowIP类文件
代码如下 |
复制代码 |
class allowIp {
function __construct($allow_ip){
if (empty($allow_ip)) {
return false;
}
$this->allow_ip = $allow_ip;
$this->ip = '';
}
private function makePregIP($str)
{
if (strstr($str,"-")) {
$aIP = explode(".",$str);
foreach ($aIP as $k=>$v) {
if (!strstr($v,"-")) {
$preg_limit .= $this->makePregIP($v);
$preg_limit .= ".";
} else{
$aipNum = explode("-",$v);
for($i=$aipNum[0];$i<=$aipNum[1];$i++){
$preg .=$preg?"|".$i:"[".$i;
}
$preg_limit .=strrpos($preg_limit,".",1)==(strlen($preg_limit)-1)?$preg."]":".".$preg."]";
}
}
}
else {
$preg_limit = $str;
}
return $preg_limit;
}
private function getAllBlockIP(){
if ($this->allow_ip) {
$i = 1;
foreach ($this->allow_ip as $k=>$v) {
$ipaddres = $this->makePregIP($v);
$ip = str_ireplace(".",".",$ipaddres);
$ip = str_replace("*","[0-9]{1,3}",$ip);
$ipaddres = "/".$ip."/";
$ip_list[] = $ipaddres;
$i++;
}
}
return $ip_list;
}
public function checkIP() {
$iptable = $this->getAllBlockIP();
$IsJoined = false;
//取得用户ip
$Ip = $this->get_client_ip();
$Ip = trim($Ip);
//在白名单中
if ($iptable) {
foreach($iptable as $value) {
if (preg_match("{$value}",$Ip)) {
$IsJoined = true;
break;
}
}
}
//不在白名单中
if( !$IsJoined ){
return false;
}
return true;
}
private function get_client_ip(){
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
$ip = getenv("HTTP_CLIENT_IP");
else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
$ip = getenv("HTTP_X_FORWARDED_FOR");
else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
$ip = getenv("REMOTE_ADDR");
else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
$ip = $_SERVER['REMOTE_ADDR'];
else
$ip = "unknown";
$this->ip = $ip;
return($ip);
}
}
|
PHP5.2.0及以上版本具有json_decode函数,该函数是用来解析JSON格式的数据,可以返回array(数组)或object(对象)两种结果,下面将分两种情况具体介绍json_decode的用法以及如何取得我们想要的值。
1.json_decode()
json_decode
(PHP 5 >= 5.2.0, PECL json >= 1.2.0)
json_decode — 对 JSON 格式的字符串进行编码
说明
mixed json_decode ( string $json [, bool $assoc ] )
接受一个 JSON 格式的字符串并且把它转换为 PHP 变量
参数
json
待解码的 json string 格式的字符串。
assoc
当该参数为 TRUE 时,将返回 array 而非 object 。
返回值
Returns an object or if the optional assoc parameter is TRUE, an associative array is instead returned.
范例
Example #1 json_decode() 的例子
代码如下 |
复制代码 |
<?php
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
var_dump(json_decode($json));
var_dump(json_decode($json, true));
?>
上例将输出:
object(stdClass)#1 (5) {
["a"] => int(1)
["b"] => int(2)
["c"] => int(3)
["d"] => int(4)
["e"] => int(5)
}
array(5) {
["a"] => int(1)
["b"] => int(2)
["c"] => int(3)
["d"] => int(4)
["e"] => int(5)
}
$data='[{"Name":"a1","Number":"123","Contno":"000","QQNo":""},{"Name":"a1","Number":"123","Contno":"000","QQNo":""},{"Name":"a1","Number":"123","Contno":"000","QQNo":""}]';
echo json_decode($data);
结果为:
Array ( [0] => stdClass Object ( [Name] => a1 [Number] => 123 [Contno] => 000 [QQNo] => ) [1] => stdClass Object ( [Name] => a1 [Number] => 123 [Contno] => 000 [QQNo] => ) [2] => stdClass Object ( [Name] => a1 [Number] => 123 [Contno] => 000 [QQNo] => ) )
|
可以看出经过json_decode()编译出来的是对象,现在输出json_decode($data,true)试下
代码如下 |
复制代码 |
echo json_decode($data,true);
结果:
Array ( [0] => Array ( [Name] => a1 [Number] => 123 [Contno] => 000 [QQNo] => ) [1] => Array ( [Name] => a1 [Number] => 123 [Contno] => 000 [QQNo] => ) [2] => Array ( [Name] => a1 [Number] => 123 [Contno] => 000 [QQNo] => ) )
|
可以看出 json_decode($data,true)输出的一个关联数组,由此可知json_decode($data)输出的是对象,而json_decode("$arr",true)是把它强制生成PHP关联数组.
假如我们获取的JSON数据如下:(可以使用curl、fsockopen等方式获取)
代码如下 |
复制代码 |
{
"from":"zh",
"to":"en",
"trans_result":[
{
"src":"u4f60u597d",
"dst":"Hello"
}
]
}
|
一、json_decode返回array的方式:
json_decode($data,true);用json_decode函数返回array的方式得到:
代码如下 |
复制代码 |
Array
(
[from] => zh
[to] => en
[trans_result] => Array
(
[0] => Array
(
[src] => 你好
[dst] => Hello
)
)
)
|
我们在PHP语言中可以用以下方法取得我们想要的值:
代码如下 |
复制代码 |
<?php
$data = <<<STR
{
"from":"zh",
"to":"en",
"trans_result":[
{
"src":"u4f60u597d",
"dst":"Hello"
}
]
}
STR;
$jsondata=json_decode($data,true);
header("Content-Type: text/html; charset=UTF-8");
print_r($jsondata);www.111cn.net
echo "<br />".$jsondata['to']; //en
echo "<br />".$jsondata['trans_result'][0]['dst']; //Hello
?>
|
二、json_decode返回object的方式:
json_decode($data);
用json_decode函数返回object的方式得到:
代码如下 |
复制代码 |
stdClass Object
(
[from] => zh
[to] => en
[trans_result] => Array
(
[0] => stdClass Object
(
[src] => 你好
[dst] => Hello
)
)
)
|
我们在PHP语言中可以用以下方法取得我们想要的值:
代码如下 |
复制代码 |
<?php
$data = <<<STR
{
"from":"zh",
"to":"en",
"trans_result":[
{
"src":"u4f60u597d",
"dst":"Hello"
}
]
}
STR;
$jsondata=json_decode($data);
header("Content-Type: text/html; charset=UTF-8");
print_r($jsondata);
echo "<br />".$jsondata->from; //zh
echo "<br />".$jsondata->trans_result[0]->src; //你好
?>
|
PHP程序员滴我们,在习惯习性使用OOP滴时代,更多滴时候考虑程序模块化,功能愈简单愈好,全部封装供程序调用!想法是好滴,但未必都可取。。。
PHP草根滴我们,一直以为数据库是万能,为了实现功能却很少去考虑效率与数据库瓶颈问题。比如在一个循环中查询数据库,一个迭代方法中查询数据库都是非常不可取滴,尤其是前端程序!在访问量不大,并发少时看不出任何问题!一旦访问量突增,并发访问量多时往往就成数据库服务器负荷过重,严重情况会宕机,后果真不堪设想,而且在这种情况下PHP程序员往往很难查具体原因。
先看一个迭代案例代码,当分类达到1000个以上滴时候,调用一次就要查询超1000次以上滴数据库查询,这样滴代码是何其恐怖,不用再细说了吧!
代码如下 |
复制代码 |
/**
* 递归获取分类
* @author:xxx
* @param $tree_id
*/
function get_child_tree($tree_id = 0)
{
$three_arr = array();
$sql = “SELECT count(*) FROM TABLE WHERE parent_id = “$tree_id” AND is_show = 1 ";
if ($GLOBALS[db]->getOne($sql) || $tree_id == 0)
{
$child_sql = "SELECT ……";
$res = $GLOBALS[db]->getAll($child_sql);
foreach ($res AS $row)
{
if ($row[is_show])
{
$arr[id] = $row[cat_id];
……
}
if ( intval($row[cat_id]) != 0) {
$three_arr[$row[cat_id]][cat_id] = get_child_tree($row[cat_id]);
……
}
}
}
return $three_arr;
}
|
再有一些例子,有些同学喜欢用while,for等循环中作数据库查询操作,同样是不可取滴,还是那句话,当数据库并发更新不大,或者访问量不大滴情况下,数据库服务器负荷也是很重滴,操作时须谨慎。特别是在作为封装滴函数内部,因为往后滴程序你会不小心滴多调用几次这个函数,那造成服务器滴开销是无法估量滴。
根据IP地址查找我们的IP地址所在地,这个最简单办法就是直接把ip在百度搜索就可以知道你的IP地址所在地了,但对于一些网站我们不能使用此方法,但可以通过api来实现
例子,利用第三方接口实例
代码如下 |
复制代码 |
<form action=www.111cn.net method="post">
<p>请输入ip地址:<input type="text" name="ip" /></p>
<p><input type="submit" value="查询" /></p>
</form>
<?php
//获取ip地址
//$ip = $_SERVER['REMOTE_ADDR']; //自动获取客户端的IP
//ip对应的地区
if(!empty($_POST['ip'])){
$ip = $_POST['ip'];
//接口地址,这样返回的是一个xml结果集,
$str = file_get_contents("http://www.yodao.com/smartresult-xml/search.s?type=ip&q=".$ip);
//这里要得到里面的地址信息,提取xml方法有很多,我用的是正则。
preg_match_all( "/<location>(.*?)</location>/",$str,$addr1);
//最终结果,如图2;
$addr = $ip."=>".$addr1[1][0];
echo $addr;
}
?>
|
例子,利用QQWry
目前只支持PHP5版本。
安装
1.sudo pecl install qqwry-beta或者直接下载编译,phpize && ./configure && make && sudo make install
2.编辑php.ini,加入extension=qqwry.so
3.重启http server
使用很简单,首先就是实例化,传入纯真数据库的文件路径,然後调用q方法。该方法返回一个数组,第一个值为地址1,例如南宁市,第二个值为地址2,例如邕 宁区电信ADSL。看例子吧,一目了然。下面的iconv是把数据从GB2312转到UTF-8,如果你的站点是用GB2312,那么这一步是不需要的。
代码如下 |
复制代码 |
$qqwry=new qqwry('QQWry.Dat');
list($addr1,$addr2)=$qqwry->q('127.0.0.1');
$addr1=iconv('GB2312','UTF-8',$addr1);
$addr2=iconv('GB2312','UTF-8',$addr2);
echo $addr1,'|',$addr2," ";
$arr=$qqwry->q('222.216.47.4');
$arr[0]=iconv('GB2312','UTF-8',$arr[0]);
$arr[1]=iconv('GB2312','UTF-8',$arr[1]);
echo $arr[0],'|',$arr[1]," ";
$arr=$qqwry->q('64.233.187.99');
$arr[0]=iconv('GB2312','UTF-8',$arr[0]);
$arr[1]=iconv('GB2312','UTF-8',$arr[1]);
echo $arr[0],'|',$arr[1]," ";
|
输出:
本机地址|
广西南宁市|(青秀区)电信ADSL
美国|加利福尼亚州Google公司
例子,如果你只要查查IP地址就不需相面那么复杂了,如我在百度输入 110.110.110.110
显示地址为
IP地址: 110.110.110.110黑龙江省哈尔滨市 铁通
如下图所示
标签:[!--infotagslink--]