模擬登錄神器之PHP基於cURL實現自動模擬登錄類


一、構思

  • 從Firefox瀏覽器拷貝cURL命令(初始頁、提交、提交后)
  • 自動分析curl形成模擬登錄代碼
  • 默認參數:ssl/302/gzip

二、實現

接口

(一)根據curl信息執行並解析結果 public function execCurl($curlContent, $callbackBefore = false, $callbackAfter = false)
(二)解析curl信息 protected function _parseCurl($curlContent)
(三)執行curl請求 protected function _execCurl
(四)獲取上一次存儲cookie的文件 public function getLastCookieFile()
(五)設置上一次存儲cookie的文件 protected function setLastCookieFile($cookieFile)
(六)登錄成功后,鎖定上一次存儲cookie的文件,避免覆蓋 public function lockLastCookieFile()
(七)解鎖上一次存儲cookie的文件 public function unlockLastCookieFile()
(八)登錄成功, get 方式獲取url信息 public function getUrl($url, $header = false)
(九)登錄成功, post 方式獲取url信息 public function postUrl($url, $postData = false, $header = false)
(十)記錄日志 protected function _log($msg)

<?php

namespace PhpUtility;

/**
 * class CurlAutoLogin
 * @author Zjmainstay
 * @website http://www.zjmainstay.cn
 *
 * 利用curl信息自動解析實現模擬登錄
 */
class CurlAutoLogin {
    //最后一次cookie存儲文件
    protected $lastCookieFile = '';
    //登錄成功后,鎖定cookie的更新
    protected $lockedLastCookieFile = false;

    /**
     * 根據curl信息執行並解析結果
     * @param  string  $curlContent    利用Firefox瀏覽器復制cURL命令
     * @param  boolean $callbackBefore 對curl結果前置處理,如更換用戶名、密碼等
     * @param  boolean $callbackAfter  對采集結果后置處理,如解析結果的csrf token等
     * @return mixed
     */
    public function execCurl($curlContent, $callbackBefore = false, $callbackAfter = false) {
        $parseCurlResult = $this->_parseCurl($curlContent);
        if(!empty($callbackBefore)) {
            $parseCurlResult = $callbackBefore($parseCurlResult);
        }
        $execCurlResult  = $this->_execCurl($parseCurlResult);

        if(!empty($callbackAfter)) {
            $execCurlResult = $callbackAfter($parseCurlResult, $execCurlResult);
        }

        return $execCurlResult;
    }

    /**
     * 解析curl信息
     * @param  string $curlContent 利用Firefox瀏覽器復制cURL命令
     * @return bool|array
     */
    protected function _parseCurl($curlContent) {
        if(!preg_match("#curl '([^']*?)'#is", $curlContent, $matchUrl)) {
            return false;
        }

        //remove cookie data in header
        $curlContent = preg_replace("#-H 'Cookie:[^']*'#is", '', $curlContent);

        if(!preg_match_all("#-H '([^']*?)'#is", $curlContent, $headerMatches)) {
            $httpHeader = [];
        } else {
            $httpHeader = $headerMatches[1];
        }

        if(!preg_match("#--data '([^']*?)'#is", $curlContent, $postDataMatch)) {
            $postData = '';
        } else {
            $postData = $postDataMatch[1];
        }

        return [
            'url'       => $matchUrl[1],
            'header'    => $httpHeader,
            'post'      => $postData,
        ];
    }

    /**
     * 執行curl請求
     * @param  array $parseCurlResult curl信息的解析結果,包含 url/header/post 三個鍵值參數
     * @return string
     */
    protected function _execCurl($parseCurlResult) {
        if(empty($parseCurlResult['url'])) {
            return '';
        }

        $ch = curl_init($parseCurlResult['url']);
        curl_setopt($ch,CURLOPT_HEADER,0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //返回數據不直接輸出
        curl_setopt($ch, CURLOPT_ENCODING, "gzip"); //指定gzip壓縮

        //add header
        if(!empty($parseCurlResult['header'])) {
            $this->curl->opt[CURLOPT_HTTPHEADER] = $parseCurlResult['header'];
        }

        //add ssl support
        if(substr($parseCurlResult['url'], 0, 5) == 'https') {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);    //SSL 報錯時使用
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);    //SSL 報錯時使用
        }

        //add 302 support
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        //add cookie support
        //設置一個不存在的目錄以在系統臨時目錄隨機生成一個緩存文件,避免多進程cookie覆蓋
        $cookieFile = tempnam('/not_exist_dir/', 'autologin');
        curl_setopt($ch,CURLOPT_COOKIEJAR,$cookieFile); //存儲提交后得到的cookie數據

        //add previous curl cookie
        if(!empty($this->lastCookieFile)) {
            curl_setopt($ch,CURLOPT_COOKIEFILE, $this->lastCookieFile); //使用提交后得到的cookie數據
        }

        //add post data support
        if(!empty($parseCurlResult['post'])) {
            curl_setopt($ch,CURLOPT_POST, 1);
            curl_setopt($ch,CURLOPT_POSTFIELDS, $parseCurlResult['post']);
        }

        try {
            $content = curl_exec($ch); //執行並存儲結果
        } catch (\Exception $e) {
            $this->_log($e->getMessage());
        }

        $curlError = curl_error($ch);
        if(!empty($curlError)) {
            $this->_log($curlError);
        }

        curl_close($ch);

        //update last cookie file
        $this->setLastCookieFile($cookieFile);

        return $content;
    }

    /**
     * 記錄日志
     * @param  [type] $msg [description]
     * @return [type]      [description]
     */
    protected function _log($msg) {
        file_put_contents(__DIR__ . '/run.log', $msg . "\n", 8);
    }

    /**
     * 獲取上一次存儲cookie的文件
     * @return [type] [description]
     */
    public function getLastCookieFile() {
        return $this->lastCookieFile;
    }

    /**
     * 設置上一次存儲cookie的文件
     * @param [type] $cookieFile [description]
     */
    protected function setLastCookieFile($cookieFile) {
        if(!$this->lockedLastCookieFile) {
            $this->lastCookieFile = $cookieFile;
        }
    }

    /**
     * 登錄成功后,鎖定上一次存儲cookie的文件,避免覆蓋
     * @return [type] [description]
     */
    public function lockLastCookieFile() {
        $this->lockedLastCookieFile = true;
    }

    /**
     * 解鎖上一次存儲cookie的文件
     * @return [type] [description]
     */
    public function unlockLastCookieFile() {
        $this->lockedLastCookieFile = false;
    }

    /**
     * 登錄成功, get 方式獲取url信息
     * @param  [type]  $url    [description]
     * @param  boolean $header [description]
     * @return [type]          [description]
     */
    public function getUrl($url, $header = false) {
        $ch = curl_init($url);
        curl_setopt($ch,CURLOPT_HEADER,0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //返回數據不直接輸出
        curl_setopt($ch, CURLOPT_ENCODING, "gzip"); //指定gzip壓縮

        //add header
        if(!empty($header)) {
            $this->curl->opt[CURLOPT_HTTPHEADER] = $header;
        }

        //add ssl support
        if(substr($url, 0, 5) == 'https') {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);    //SSL 報錯時使用
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);    //SSL 報錯時使用
        }

        //add 302 support
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        curl_setopt($ch,CURLOPT_COOKIEFILE, $this->lastCookieFile); //使用提交后得到的cookie數據

        try {
            $content = curl_exec($ch); //執行並存儲結果
        } catch (\Exception $e) {
            $this->_log($e->getMessage());
        }

        $curlError = curl_error($ch);
        if(!empty($curlError)) {
            $this->_log($curlError);
        }

        curl_close($ch);

        return $content;
    }

    /**
     * 登錄成功, post 方式獲取url信息
     * @param  [type]  $url      [description]
     * @param  boolean $postData [description]
     * @param  boolean $header   [description]
     * @return [type]            [description]
     */
    public function postUrl($url, $postData = false, $header = false) {
        $ch = curl_init($url);
        curl_setopt($ch,CURLOPT_HEADER,0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //返回數據不直接輸出
        curl_setopt($ch, CURLOPT_ENCODING, "gzip"); //指定gzip壓縮

        //add header
        if(!empty($header)) {
            $this->curl->opt[CURLOPT_HTTPHEADER] = $header;
        }

        //add ssl support
        if(substr($url, 0, 5) == 'https') {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);    //SSL 報錯時使用
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);    //SSL 報錯時使用
        }

        //add 302 support
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        curl_setopt($ch,CURLOPT_COOKIEFILE, $this->lastCookieFile); //使用提交后得到的cookie數據

        //add post data support
        if(!empty($postData)) {
            curl_setopt($ch,CURLOPT_POST, 1);
            curl_setopt($ch,CURLOPT_POSTFIELDS, $postData);
        }

        try {
            $content = curl_exec($ch); //執行並存儲結果
        } catch (\Exception $e) {
            $this->_log($e->getMessage());
        }

        $curlError = curl_error($ch);
        if(!empty($curlError)) {
            $this->_log($curlError);
        }

        curl_close($ch);

        return $content;
    }
}

三、演示

運行:PHP cURL自動模擬登錄演示

<?php

require_once __DIR__.'/../vendor/autoload.php';

$autologin = new PhpUtility\CurlAutoLogin();

//0. 未登錄
$getDataUrl = 'http://demo.zjmainstay.cn/js/simpleAjax/loginResult.php';
echo 'Before Login: ' . $autologin->getUrl($getDataUrl) . "\n";

//1. 初始化登錄頁
$firstCurl = "curl 'http://demo.zjmainstay.cn/js/simpleAjax/' -H 'Host: demo.zjmainstay.cn' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:47.0) Gecko/20100101 Firefox/47.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3' -H 'Accept-Encoding: gzip, deflate' -H 'Cookie: Hm_lvt_1526d5aecf5561ef9401f7c7b7842a97=1468327822,1468327904,1468341636,1468411918; Hm_lpvt_1526d5aecf5561ef9401f7c7b7842a97=1468421526' -H 'Connection: keep-alive' -H 'If-Modified-Since: Mon, 27 Oct 2014 08:31:18 GMT' -H 'If-None-Match: \"32e-453-506635ac5e180\"' -H 'Cache-Control: max-age=0'";
$autologin->execCurl($firstCurl);

//2. 提交登錄表單
$secondCurl = "curl 'http://demo.zjmainstay.cn/js/simpleAjax/doPost.php' -H 'Host: demo.zjmainstay.cn' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:47.0) Gecko/20100101 Firefox/47.0' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3' -H 'Accept-Encoding: gzip, deflate' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Referer: http://demo.zjmainstay.cn/js/simpleAjax/' -H 'Cookie: Hm_lvt_1526d5aecf5561ef9401f7c7b7842a97=1468327822,1468327904,1468341636,1468411918; Hm_lpvt_1526d5aecf5561ef9401f7c7b7842a97=1468421526' -H 'Connection: keep-alive' --data 'username=demousername'";
$realUsername = 'Zjmainstay';
//前置處理,替換錯誤的用戶名
$autologin->execCurl($secondCurl, function($parseCurlResult) use ($realUsername) {
        $parseCurlResult['post'] = str_replace('=demousername', "={$realUsername}", $parseCurlResult['post']);
        return $parseCurlResult;
    });

//3. 登錄成功,鎖定cookie的更新,直接訪問已登錄頁面內容
$autologin->lockLastCookieFile();
echo 'After Login: ' . $autologin->getUrl($getDataUrl) . "\n";

四、更多

請關注github項目 php-utility-class 上面的更新。

文章首發自Zjmainstay學習筆記《PHP基於cURL實現自動模擬登錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM