Php 用于登录的cURL。白页还是空白页

Php 用于登录的cURL。白页还是空白页,php,curl,login,Php,Curl,Login,这是我试图用来连接CFE网站的代码。有人能帮我吗。我找不到密码有什么问题 即使我更改了代码,我也会得到一个对象(移动到此处) 这就是我在遵循你的建议时得到的结果。至少我没有得到“物体移动到这里”。我可以获得登录页面,但仅此而已。它没有登录。尝试一下代码,至少你会看到它的作用。谢谢大家在这方面的帮助 <?php $ckfile = tempnam ("/tmp", "CURLCOOKIE"); $ch = curl_init(); curl_setopt($ch, CURLOPT

这是我试图用来连接CFE网站的代码。有人能帮我吗。我找不到密码有什么问题

即使我更改了代码,我也会得到一个对象(移动到此处)


这就是我在遵循你的建议时得到的结果。至少我没有得到“物体移动到这里”。我可以获得登录页面,但仅此而已。它没有登录。尝试一下代码,至少你会看到它的作用。谢谢大家在这方面的帮助

<?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;

?>

你做错了几件事。首先,您的$fields\u字符串编码不正确。在
application/x-www-urlencoded
中,当您尝试编码时,
$
必须编码为
%24
,但您只需直接发送$。但是如果你停下来想一想,很明显你的编码方法是错误的,因为,如果用户名或密码包含
&
,你认为会发生什么?如果用户名或密码中有
&
,则必须将其编码为
%26
,空格必须编码为
%20
,依此类推,使用urlencode()对其进行编码,更正编码循环,如下所示:

foreach($fields as $key=>$value) {
     $fields_string .= urlencode($key) . '=' . urlencode($value) . '&';
}
rtrim($fields_string, '&');
但幸运的是,php有一个专门的函数用于编码到
应用程序/x-www-urlencoded
,名为
http\u build\u query
,整个循环和修剪可以(并且应该)用这一行来代替:

$fields_string=http_build_query($fields);
第二,创建一个curl句柄,设置CURLOPT_COOKIEJAR,并获取登录页面,我猜您这样做是为了为您的登录请求获取一个cookie会话,您确实需要这样做,但是在创建一个全新的curl句柄来执行登录请求之前,您不需要关闭第一个curl句柄。CURLOPT_COOKIEJAR在curl句柄关闭时首先刷新,这意味着您的第一个curl句柄尚未保存cookies,因为您没有执行curl_close,因此您的第二个curl句柄无法加载第一个句柄的cookies,这意味着它尝试在没有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(…但最常见(且有缺陷)的方法是regexes…)

第五,这一行毫无意义,而且是错误的:
curl_setopt($ch,CURLOPT_POST,count($fields))
应该是bool-true,而不是post字段的数量(幸运的是,它无论如何都能工作,因为任何大于零的int都是
true-ish
,也称为足够接近,但它仍然很奇怪,表明作者不知道自己在做什么)

最后,protip,您可以根据需要多次重用同一个curl会话,没有理由在这段php代码中创建两个curl会话。此外,在调试curl代码时,启用CURLOPT_VERBOSE,它会打印许多有用的调试信息

下面是一个示例代码,用作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;
}

不是有效的用户名。

您有两个主要问题,
CURLOPT\u POST
是1或0,而不是
$fields
。你不需要将
$fields\u string
传递给
CURLOPT\u POSTFIELDS
,你只需要传递
$fields
,传递URL中的内容
Get
并传递
POST
,将CURLOPT\u POSTFIELDS更改为1并将CURLOPT\u POSTFIELDS更改为$fields并不明智,我仍然得到。$fields\u string现在得到两次生成,因为它应该是http\u build\u查询。你再也不需要用foreach了。在查看他们的表单后,您会丢失很多表单字段,如uuu VIEWSTATE和其他必需的内容。首先检索登录页面后,需要刮除字段。请求1:获取登录页面。刮表输入。请求2:发布到登录。请求3:确认登录。所有这些都来自一个curl_init的curl句柄,而不是多个。我有点听不懂你说的。我尝试了太多的东西,我很难接受。或者我进入登录页面,或者我得到一个500错误页面,或者我得到一个空白页面。谢谢你在这方面的帮助。唯一的问题是我得到了一个(HTTP错误500)页面更新:我设法在本地服务器上进行更新,然后得到了响应(HHB_VAR_DUMP_END login success!)。问题是它没有将我重定向到“”。我在你的代码中看到,你没有在登录后添加下面的链接。我可以把那个链接放在哪里?谢谢again@user3140580也许试着删除第5行,在第34行之后再写一行:
echo$hc->exec('https://app.cfe.gob.mx/Aplicaciones/CCFE/Recibos/Consulta/Default.aspx')->getStdOut()?您可以为html curl接收的浏览器提供服务,但是您不能将您的curl的登录会话/Cookie传输到浏览器(至少在没有目标网站对此类操作的支持的情况下),您可以做的最好的事情可能是让curl充当代理。(除非您从app.cfe.gob.mx网站devs获得支持),否则登录立即生效。我看到的最后一个问题是,它显示的是代码,而不是网站。有什么想法吗?
<?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."