PHP之CURL实现含有验证码的模拟登录

博主最近在为学校社团写一个模拟登录教务系统来进行成绩查询的功能,语言当然是使用PHP啦,原理是通过php数据传输神器---curl扩展,向学校教务系统发送请求,通过模拟登录,获取指定url下的内容。


在开始实验之前有必要对curl扩展进行一下认识

使用CURL的PHP扩展完成一个HTTP请求的发送一般有以下几个步骤:
    1. 初始化连接句柄;  #  curl_init()
    2. 设置CURL选项(关键);    # curl_setopt()
    3. 执行并获取结果;         #curl_exec()
    4. 释放VURL连接句柄。      #curl_close()

下面看一个简单的实例

 $ch = curl_init();     // 1.  初始化
 curl_setopt($ch,CURLOPT_URL,$url);     // 2. 设置选项,包括URL
 curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);     //设置选项 , 返回url获取的内容
 curl_setopt($ch,CURLOPT_HEADER,0);    //设置选项 , 不返回HTTP头部信息
 $output = curl_exec($ch);     // 3. 执行并获取HTML文档内容
 //对获取到的内容进行操作
 if($output === FALSE ){
 echo "CURL Error:".curl_error($ch);
 }
 curl_close($ch);    // 4. 释放curl句柄
 
 下面是curl_setopt选项的常用选项,在下面的实验中将会用到
 CURLOPT_URL                    需要获取的URL地址,也可以在 curl_init()函数中设置
 CURLOPT_HEADER            	    不返回HTTP头部信息
 CURLOPT_COOKIEJAR      	    连接结束后保存cookie信息的文件。 
 CURLOPT_COOKIEFILE      	    包含cookie数据的文件名
 CURLOPT_REFERER                伪造来源
 CURLOPT_RETURNTRANSFER         将 curl_exec()获取的信息以文件流的形式返回,而不是直接输出
 CURLOPT_POST                   设置post提交方式
 CURLOPT_POSTFIELDS       	    传递post内容 

现在来开始我们的模拟登录实验吧!

第一步:抓包与分析

工具这里使用到的是谷歌浏览器到的开发者工具,对需要进行模拟登录的教务系统页面进行访问,获取相关信息。

我们分析一下抓取到的请求数据:首先直接访问教务系统网址,则在请求头中则会设置cookie。

通过chrome的开发者工具分析网页的请求信息:

由上面可以看到,当我们第一次访问,和服务器建立起联系时,会获得来一枚session,这枚session是唯一的,如果改变,将会导致此次会话断开,重新开始新的会话,这也是在验证码验证时的一个难点。由JSESSIONID名称的特性,我们知道了教务系统是由JAVA编写的,不管使用什么语言编写,数据交互的本质都没有改变。我们照样将实验进行到底。我们再来看看验证码的请求信息:

由上图可以看到,浏览器分别向教务系统主页面(202.206.xxx.xxx)和验证码页面(ValidateCodeAction.do)发送了请求,得到的SESSION是一样的,这也是会话连通的特点。

由上面的特点知道:想要登录成功,必须先获取登录页面的COOKIES,然后拿着COOKIES找服务器对应的验证码。最后提供服务器需要的全部信息。,这里说明一下,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)也就是为什么我将session看作cookie的原因。希望理解,你们自己看成session也无所谓,个人有个人的不同理解罢了!

好了,现在科普玩了,就开始我们的实验吧!!!

我们先来开始获取验证码页面的cookie操作,然后将获取到的验证码写入文件
<?php 
	//第一步,配置保存的cookie文件的目录,下面使用的session的获取和验证码页面的cookie没有半毛钱关系,纯属是为了解决高并发问题,防止因为多人访问时,因为cookie文件被重写,导致的登录失败
	session_start();  //开启session,
    $id=session_id();	//获取当前session的id,这个id是存放在浏览器的本地cookie中的
    $_SESSION['id']=$id;  //因为这个id的唯一性,可以解决高并发访问时登陆失败的问题
    $cookie = dirname(__FILE__) . '/cookie/'.$_SESSION['id'].'.txt'; //cookie文件保存的路径
    
    //开始模拟访问验证码页面,获取其cookie
    $verify_code_url = "http://xxx.xxx.xxx.xxx/ValidateCodeAction.do"; //这里是验证码地址
    $curl = curl_init();	//初始化句柄
    curl_setopt($curl, CURLOPT_URL, $verify_code_url);	//设置模拟访问的URL
    curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie);  //保存模拟访问时得到的cookie(关键)
    curl_setopt($curl, CURLOPT_HEADER, 0);	//不输出头信息
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);	//返回文件流
    $img = curl_exec($curl);  //执行curl
    curl_close($curl);	//释放资源句柄
    $fp = fopen("verifyCode.jpg","w");  //获取到的验证码文件名
    fwrite($fp,$img);  //写入文件 
    fclose($fp);
?>

获取到的验证码当然是要放到模拟登录的提交表单中咯。假设数据提交页面是login.php,那么,请将上面的代码放到login.php里面,在标签的src属性中写入verifyCode.jpg的路径。然后将代码提交到deal.php---模拟登录处理页面中。
先查看教务系统登录界面的源代码,获取表单的name。

然后就是设计模拟登录的页面,我将代码贴出来如下(使用了pintuer的前端框架,需要可以自行下载):

<!DOCTYPE html> 
<html lang='zh-cn'>
 <head> 
 <title>登录</title> 
 <meta charset='utf-8' /> 
 <meta name='viewport' content='width=device-width, initial-scale=1.0'> 
 <link rel='stylesheet' href='pintuer.css'> 
 </head> 
 <body> 
 <h1></h1>
 <div class="container-layout"> 
 <div class="line"> 
 <div class="xs12 xm12 xb12">
 <div class="panel border-main"> 
 <div class="panel-head border-sub bg-main text-center">登录</div> 
 <div class="panel-body"> <style type="text/css"> 
  .passcode { position: absolute; right: 0; top: 0; height: 32px; margin: 1px; border-left: solid 1px #ddd; text-align: center; line-height: 32px; border-radius: 0 4px 4px 0; } 
  </style> 
  <div align="center"> 
  <form action="deal.php" method="post"> 
  <div class="panel padding" style="text-align: left;"> 
  <div class="text-center"> 
  <br> 
  <h2><strong>欢迎使用&nbsp;服务</strong></h2>
  </div> 
  <div class="" style="padding:30px;"> 
  <div class="form-group"> 
  <div class="field field-icon-right">
  <input type="text" class="input" name="zjh" placeholder="登录账号" data-validate="required:请填写账号,length#>=5:账号长度不符合要求" /> 
  <span class="icon icon-user"></span> 
  </div> 
  </div> 
  <div class="form-group"> 
  <div class="field field-icon-right"> 
  <input type="password" class="input" name="mm" placeholder="登录密码" data-validate="required:请填写密码,length#>=8:密码长度不符合要求" /> 
  <span class="icon icon-key"></span> 
  </div> 
  </div> 

  <?php 
      //保存session会话
      session_start();
      $id = session_id();
      $_SESSION['id'] = $id;

      // 验证码保存
      $cookie_jar = dirname(__FILE__) . '/cookie/'.$_SESSION['id'].'.txt';
      $url_img='http://202.206.1.176/validateCodeAction.do?random=0.09896789042747245';
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url_img);
      curl_setopt($ch,CURLOPT_HEADER,0);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1) ; 
      curl_setopt($ch, CURLOPT_REFERER, 'http://202.206.1.176/');
      curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
      $img = curl_exec($ch);
      curl_close($ch);
      $img_code = rand(0,500);
      $img_name = 'vcode'.$img_code.'.jpg';
      $op_file = fopen('./images/'.$img_name, 'w');
      fwrite($op_file,$img);
      fclose($op_file);
   ?>

  <div class="form-group"> 
  <div class="field"> 
  <input type="text" class="input" name="v_yzm" placeholder="输入验证码" data-validate="required:请填写右侧的验证码" /> 
  <img src="./images/<?php echo $img_name;?>" width="80" height="32" class="passcode" /> 
  </div> 
  </div> 
  <div class="form-group"> 
  <div class="field"> 
  <input class="button button-block bg-main text-big" type='submit' value='立即登录'>
  </div> 
  </div> 
   </div> 
   </form> 
   </div>
   </div> 
 <div class='panel-foot border-sub bg-main text-center'><a class='text-red' target='_blank' href='http://xblogs.cn'>xuthus  </a> 版权所有</div> 
 </div>
 </div> 
 </div>
 </div> 
 </body> 
 </html>
在模拟登录处理页面deal.php中
重点就是使用上面的验证码页面获取得到的cookie文件,让访问在同一个会话中,否则这样验证码虽然是出来,但这个验证码不属于你,所以在你远程登录时候,验证码永远是错误的,永远登录失败。怎么操作呢?看下面代码:
<?php 
    session_start();//重点,这个必须要开启,否则验证码cookie文件会出错,在其他页面使用curl来进行同一个会话时,这个也要开起
    header("Content-type: text/html; charset=gb2312");  //视学校而定,博主学校是gb2312编码,php也采用的gb2312编码方式
    	//开始模拟登录
    	$url = "http://202.206.xxx.xxx";
    	$cookie = dirname(__FILE__) . '/cookie/'.$_SESSION['id'].'.txt';
    	$post = "name=xx&pwd=xx&yzm=xx";//具体的表单字段(name,pwd,yzm)需要自己查看网页源代码进行获取,后面的值(xx)自己通过$_POST['']来获取,简化的操作可以通过http_build_query($_POST)来实现
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);  //不自动输出头信息
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);  //不自动输出数据
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);  //抓取跳转后数据
        curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); //这里就是使用验证码cookie文件的地方
        curl_setopt($ch, CURLOPT_REFERER, $url);  //302跳转需要referer,也可以用来伪装来源
        curl_setopt($ch, CURLOPT_POSTFIELDS,$post);  //post提交数据
        $result=curl_exec($ch);
        curl_close($ch);
    	echo $result; //输出内容,如果返回登录成功的界面,那么恭喜你,操作成功啦!!!没操作成功,那么请看看自己哪里出了错,也可以联系博主,我们共同解决。

登录成功后,就可以进行各项查询操作,你可以新建一个专门的chaxun.php页面,先通过chrome的开发者工具,获取到成绩页面的地址,然后再次使用curl进行获取,比如:
  	<?php
  		 session_start();//这一步不要忘记了哦
  		 $url = 'http://202.206.xxx.xxx/bxqcjcxAction.do';//本学期成绩
 		 $cookie_jar = dirname(__FILE__) . '/cookie/'.$_SESSION['id'].'.txt';
		 $ch = curl_init() ;
		 curl_setopt($ch, CURLOPT_URL,$url) ; 
          curl_setopt($ch, CURLOPT_HEADER, 0);
          curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
          curl_setopt($ch, CURLOPT_REFERER, 'http://202.206.1.176/');
          curl_setopt($ch,CURLOPT_COOKIEFILE,$cookie_jar);
          $data=curl_exec($ch);
          echo $data;//返回查询结果
          curl_close($ch); 
好了,教程写完了!本人博客http://xblogs.cn
posted @ 2017-03-19 10:45  xuthus5  阅读(1168)  评论(0编辑  收藏  举报