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

PHP 2019-01-08

最近在为学校社团写一个模拟登录教务系统来进行成绩查询的功能,语言当然是使用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内容 

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

  1. 先聊一聊HTTP会话:会话是指一个用户与系统进行通讯的过程,比如从输入账户密码进入操作系统到退出操作系统就是一个会话过程。Session代表服务器与浏览器的一次会话过程,这个过程一般是连续的。在打开浏览器第一次请求网站的时候,服务器会自动为其创建一个session,并赋予其一个sessionID,发送给客户端的浏览器。以后客户端接着请求本应用中其他资源的时候,会自动在请求头上添加:(Cookie:SESSIONID=客户端第一次拿到的session ID)。这样,服务器端在接到请求时候,就会收到session ID,并根据ID在内存中找到之前创建的session对象,提供给请求使用。HTTP会话
  2. 第一步:抓包与分析

    工具可以使用谷歌浏览器的开发者工具(按下F12键调出,点击网络选项,查看访问的资源),对需要进行模拟登录的教务系统页面进行访问,获取相关信息。

  3. 第二步:获取想要的信息

    首先直接访问教务系统网址。我们能够很清楚的看到,验证码有着自己的地址,每一次我们刷新这个验证码URL地址的时候,这张小小的验证码都会实时的更新变化。那服务器怎么知道,在某一次提交中,是哪个人提交的表单数据,又怎么判断使用的是哪一张验证码呢!这就是一个问题了,所以HTTP会话的功能就体现出来了。当我们第一次访问网站,会和服务器建立起联系(进行了一次会话,在网页没有关闭前,这个会话一般会一直保持),会获得来一枚session,这枚session是唯一的,如果session改变,这就意味着这是一次新的会话,那么服务器收到的验证码也就无效,因为此次提交的数据,不是来自同一个会话中。这也是在验证码验证时的一个难点。所以保持会话,并提交数据就是我们需要重点处理的任务。

  4. 第三步:模拟登陆的思路

    我们访问教务系统页面,浏览器分别向教务系统主页面(202.206.xxx.xxx)和验证码页面(202.206.xxx.xxx/ValidateCodeAction.do)发送了请求,通过查看他们的头信息,可以发现他们的SESSION信息是一样的,这证明我上面所说的是真的。

    那我们想一想,我们要模拟登陆,就必须获取到验证码,当我们通过curl的到验证码后,会话就断开了,这个验证码就是一个废的验证码,当我们使用这个验证码提交登陆信息给教务系统,这次提交会生成一个新的会话,明显,这次模拟登陆会报错,理由是验证码不正确,此次会话产生的验证码与我们输入的验证码不匹配,因为一个验证码对应着一个唯一的会话。

    我们怎样让我们的会话保持下来呢?这里我提供一下我的思路:

    1. 获取验证码,并将验证码对应的 会话id(cookie) 保存
    2. 提交表单,使用获取验证码得到的 会话id(cookie) ,让会话保持
    3. 得到信息

    这里保存会话id用到的是我们的curl选项 CURLOPT_COOKIEJARCURLOPT_COOKIEFILE 。这些都讲的清楚了吧!开始写代码!

1. 获取验证码 保存会话cookie为文件

1. 全程开启session(为什么要开启,目的是为了防止访问人数过多,导致的cookie文件被重写)
2. 在当前目录下创建一个cookie文件夹用来存放会话生成的cookie文件
3. 在当前目录下创建一个images文件夹用来存放验证码文件
<?php 
    session_start();  //开启session,
    $id=session_id();    //获取当前session的id,这个id是存放在浏览器的本地cookie中的
    $_SESSION['id']=$id;  //因为这个id的唯一性,可以解决高访问量时登陆失败的问题
    $cookie = dirname(__FILE__) . '/cookie/'.$_SESSION['id'].'.txt'; //cookie文件保存的路径 当前路径下的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("./images/verifyCode.jpg","w");  //获取到的验证码文件名,为了防止多人同时访问导致的验证码覆盖问题,你可以使用session或生成随机名称来解决问题,这里写死为verifyCode.jpg文件名
    fwrite($fp,$img);  //写入文件 
    fclose($fp);
?>

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

登陆表单的设计

注意 : 这里需要先查看教务系统登录界面的源代码,获取表单的name值。有时某些字段被隐藏,你需要自己查看 Form Data 看提交的字段有哪些。

设计模拟登录的页面,将验证码的获取整合到了这里,我将代码贴出来如下(使用了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='http://www.pintuer.com/css/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='https://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");  //视学校而定
    //开始模拟登录
    $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); 

好了,教程写完了!谢谢支持! 有不懂的可以问我。QQ:1397190480

https://xblogs.cn


本文由 xuthus 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论