簡體   English   中英

登錄的cURL。 白頁或空白頁

[英]cURL for login . White page or blank page

這是我嘗試用於連接CFE網站的代碼。 有人可以幫我弄這個嗎。 我找不到代碼有什么問題。

即使我更改了代碼,也得到了(對象移至此處)

$ckfile = tempnam ("/tmp", "CURLCOOKIE");


$url = 


$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);

$fields = array(
'ctl00$PHContenidoPag$UCLogin2$LoginUsuario$UserName' => 'xxxxxxxxxxxx',
'ctl00$PHContenidoPag$UCLogin2$LoginUsuario$Password' => 'xxxxxxxxxxxx',
);

$fields_string = '';
foreach($fields as $key=>$value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');


$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 
$output = curl_exec($ch);

$url = 
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
echo $output;

你做錯了幾件事。 首先,您的$ fields_string編碼錯誤。 application/x-www-urlencoded ,當您嘗試編碼時, $必須被編碼為%24 ,但是您只需直接發送$即可。 但是如果您停止考慮的話,很明顯您的編碼方法是錯誤的,因為如果用戶名或密碼包含& ,您會怎么辦? 如果用戶名或密碼中有& ,則必須將其編碼為%26 ,空格必須編碼為%20 ,依此類推,使用urlencode()對其進行編碼,更正編碼循環,如下所示:

foreach($fields as $key=>$value) {
     $fields_string .= urlencode($key) . '=' . urlencode($value) . '&';
}
rtrim($fields_string, '&');

但幸運的是,php有一個專用於對application/x-www-urlencoded進行編碼的函數,稱為http_build_query ,整個循環和修整可以(並且應該)用以下這一行代替:

$fields_string=http_build_query($fields);

其次,您制作一個curl句柄,設置CURLOPT_COOKIEJAR,並獲取登錄頁面,我想您這樣做是為了獲得您的登錄請求的cookie會話,您確實需要這樣做,但是您沒有關閉第一個curl句柄在創建全新的curl句柄以執行登錄請求之前。 CURLOPT_COOKIEJAR在卷曲柄關閉時首先被刷新,這意味着您的第一個卷曲柄尚未保存cookie,因為您沒有做curl_close,因此第二個卷曲柄無法加載第一個柄的cookie,這意味着它將嘗試在沒有cookie會話的情況下登錄,需要在此處登錄。

第三,您的代碼完全忽略任何setopt錯誤。 如果設置您的選項時出現問題,curl_setopt返回bool(false),則不應忽略該問題。 為確保設置卷曲選項沒有問題,我建議您改用以下功能:

function ecurl_setopt ( /*resource*/$ch , int $option , /*mixed*/ $value ):bool{
    $ret=curl_setopt($ch,$option,$value);
    if($ret!==true){
        //option should be obvious by stack trace
        throw new RuntimeException ( 'curl_setopt() failed. curl_errno: ' .  curl_errno ($ch) .' curl_error: '.curl_error($ch) );
    }
    return true;
}

第四,此頁面似乎采用了類似CSRF令牌的方案__VIEWSTATE和__EVENTVALIDATION,這在登錄頁面加載的html中給出,這在登錄時是必需的,您的代碼將完全忽略它們,您必須將它們從html中解析出來並將它們添加到您的登錄請求中。 我強烈建議為此使用DOMDocument / DOMXPath(...但是最常見(也是有缺陷的)方法是正則表達式...)

第五,這行是荒謬的,並且會錯誤地起作用: curl_setopt($ch, CURLOPT_POST, count($fields)); 它應該是布爾值true,而不是發布字段的數量(幸運的是,它仍然有效,因為任何大於零的int都是true-ish ,也足夠接近,但是它仍然很奇怪,建議作者不知道自己在做什么)

最后,protip,您可以根據需要多次重復使用相同的curl會話,沒有理由在此php代碼中創建2個curl會話。 同樣,在調試curl代碼時,啟用CURLOPT_VERBOSE,它會打印許多有用的調試信息。

這是一個示例代碼,使用hhb_curl作為curl包裝器(負責錯誤檢測和報告,cookie處理等),不做任何錯誤,我認為可以在第3行和第4行使用正確的用戶名和密碼進行操作:

<?php
declare(strict_types = 1);
const USERNAME = '???';
const PASSWORD = '???';
header ( "content-type: text/plain;charset=utf8" );
require_once ('hhb_.inc.php');
$hc = new hhb_curl ( '', true );
$html = $hc->exec ( 'https://app.cfe.gob.mx/Aplicaciones/CCFE/Recibos/Consulta/login.aspx' )->getStdOut ();
$domd = @DOMDocument::loadHTML ( $html );
$inputsRaw = getDOMDocumentFormInputs ( $domd, true ) ['aspnetForm'];
$inputs = array ();
foreach ( $inputsRaw as $tmp ) {
    $inputs [$tmp->getAttribute ( "name" )] = $tmp->getAttribute ( "value" );
}
assert ( isset ( $inputs ['__VIEWSTATE'], $inputs ['__EVENTVALIDATION'] ) );
$inputs ['ctl00$PHContenidoPag$UCLogin2$LoginUsuario$UserName'] = USERNAME;
$inputs ['ctl00$PHContenidoPag$UCLogin2$LoginUsuario$Password'] = PASSWORD;
hhb_var_dump ( $inputs );
$html = $hc->setopt_array ( array (
        CURLOPT_URL => 'https://app.cfe.gob.mx/Aplicaciones/CCFE/Recibos/Consulta/login.aspx',
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query ( $inputs ) 
) )->exec ()->getStdOut ();
// hhb_var_dump($html) & die();
$domd = @DOMDocument::loadHTML ( $html );
$xp = new DOMXPath ( $domd );
$loginErrors = $xp->query ( '//*[(contains(@style,"color:Red") or contains(@color,"Red")) and not(contains(@style,"hidden"))]' );
foreach ( $loginErrors as $tmp ) {
    echo "login error!! ";
    var_dump ( $tmp->textContent );
}
if (0 === $loginErrors->length) {
    echo "login success!";
}

function getDOMDocumentFormInputs(\DOMDocument $domd, bool $getOnlyFirstMatches = false): array {
    // :DOMNodeList?
    $forms = $domd->getElementsByTagName ( 'form' );
    $parsedForms = array ();
    $isDescendantOf = function (\DOMNode $decendant, \DOMNode $ele): bool {
        $parent = $decendant;
        while ( NULL !== ($parent = $parent->parentNode) ) {
            if ($parent === $ele) {
                return true;
            }
        }
        return false;
    };
    // i can't use array_merge on DOMNodeLists :(
    $merged = function () use (&$domd): array {
        $ret = array ();
        foreach ( $domd->getElementsByTagName ( "input" ) as $input ) {
            $ret [] = $input;
        }
        foreach ( $domd->getElementsByTagName ( "textarea" ) as $textarea ) {
            $ret [] = $textarea;
        }
        foreach ( $domd->getElementsByTagName ( "button" ) as $button ) {
            $ret [] = $button;
        }
        return $ret;
    };
    $merged = $merged ();
    foreach ( $forms as $form ) {
        $inputs = function () use (&$domd, &$form, &$isDescendantOf, &$merged): array {
            $ret = array ();
            foreach ( $merged as $input ) {
                // hhb_var_dump ( $input->getAttribute ( "name" ), $input->getAttribute ( "id" ) );
                if ($input->hasAttribute ( "disabled" )) {
                    // ignore disabled elements?
                    continue;
                }
                $name = $input->getAttribute ( "name" );
                if ($name === '') {
                    // echo "inputs with no name are ignored when submitted by mainstream browsers (presumably because of specs)... follow suite?", PHP_EOL;
                    continue;
                }
                if (! $isDescendantOf ( $input, $form ) && $form->getAttribute ( "id" ) !== '' && $input->getAttribute ( "form" ) !== $form->getAttribute ( "id" )) {
                    // echo "this input does not belong to this form.", PHP_EOL;
                    continue;
                }
                if (! array_key_exists ( $name, $ret )) {
                    $ret [$name] = array (
                            $input 
                    );
                } else {
                    $ret [$name] [] = $input;
                }
            }
            return $ret;
        };
        $inputs = $inputs (); // sorry about that, Eclipse gets unstable on IIFE syntax.
        $hasName = true;
        $name = $form->getAttribute ( "id" );
        if ($name === '') {
            $name = $form->getAttribute ( "name" );
            if ($name === '') {
                $hasName = false;
            }
        }
        if (! $hasName) {
            $parsedForms [] = array (
                    $inputs 
            );
        } else {
            if (! array_key_exists ( $name, $parsedForms )) {
                $parsedForms [$name] = array (
                        $inputs 
                );
            } else {
                $parsedForms [$name] [] = $tmp;
            }
        }
    }
    unset ( $form, $tmp, $hasName, $name, $i, $input );
    if ($getOnlyFirstMatches) {
        foreach ( $parsedForms as $key => $val ) {
            $parsedForms [$key] = $val [0];
        }
        unset ( $key, $val );
        foreach ( $parsedForms as $key1 => $val1 ) {
            foreach ( $val1 as $key2 => $val2 ) {
                $parsedForms [$key1] [$key2] = $val2 [0];
            }
        }
    }
    return $parsedForms;
}

它當前輸出:

login error!! string(35) "Usuario No Existente en Aplicacion."

說那個??? 不是有效的用戶名。

這是我遵循您的建議時得到的。 至少我沒有把“對象移到這里”。 我可以獲取登錄頁面,僅此而已。 它沒有登錄。嘗試代碼,至少您會看到它的作用。 謝謝大家的幫助。

<?php


$ckfile = tempnam ("/tmp", "CURLCOOKIE");




$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$output = curl_exec($ch);

$fields = array(
'ctl00$PHContenidoPag$UCLogin2$LoginUsuario$UserName' => 'xxx',
'ctl00$PHContenidoPag$UCLogin2$LoginUsuario$Password' => 'xxx',
);

$fields_string = http_build_query($fields);
foreach($fields as $key=>$value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');


$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, count(1));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$output = curl_exec($ch);

$url = 
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$output = curl_exec($ch);
echo $output;

?>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM