1. 程式人生 > >PHP之CURL實現含有驗證碼的模擬登入

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