首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何使用php curl远程登录gmail帐号?

如何使用php curl远程登录gmail帐号?
EN

Stack Overflow用户
提问于 2018-02-15 18:51:29
回答 2查看 1.4K关注 0票数 0

我想要远程登录gmail帐户。我正在尝试下面的代码,但代码不工作,代码也没有显示我的错误。当我在我的服务器上浏览它时,它显示了“登录失败”的消息,而且这条消息已经设置在字符串上。请检查下面的代码,问题出在哪里。

<?php

$USERNAME = 'your_gmail_id_name@gmail.com';
$PASSWORD = 'your_gmail_password';
$COOKIEFILE = 'cookies.txt';

// initialize curl handle used for all requests
$ch = curl_init();

// set some options on the handle
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, $COOKIEFILE);
curl_setopt($ch, CURLOPT_COOKIEFILE, $COOKIEFILE);
curl_setopt($ch, CURLOPT_HEADER, 0);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);

// url of our first request fetches the account login page
curl_setopt($ch, CURLOPT_URL, 
  'https://accounts.google.com/ServiceLogin?hl=en&service=alerts&continue=http://www.google.com/alerts/manage');
$data = curl_exec($ch);

// extract form fields from account login page
$formFields = getFormFields($data);

// inject email and password into form
$formFields['Email']  = $USERNAME;
$formFields['Passwd'] = $PASSWORD;
unset($formFields['PersistentCookie']);

$post_string = http_build_query($formFields); // build urlencoded POST string for login

// set url to login page as a POST request
curl_setopt($ch, CURLOPT_URL, 'https://accounts.google.com/ServiceLoginAuth');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);

// execute login request
$result = curl_exec($ch);

// check for "Redirecting" message in title to indicate success
// based on your language - you may need to change this to match some other string
if (strpos($result, '<title>Redirecting') === false) {
    die("Login failed");
    var_dump($result);
}

// login likely succeeded - request account page; unset POST so we do a regular GET
curl_setopt($ch, CURLOPT_URL, 'https://mail.google.com/mail/h/jeu23doknfnj/?zy=e&f=1');
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, null);

// execute request for login page using our cookies
$result = curl_exec($ch);

echo $result;


// helpef functions below

// find google "#gaia_loginform" for logging in
function getFormFields($data)
{
    if (preg_match('/(<form.*?class=.?RFjuSb.*?<\/form>)/is', $data, $matches)) {
        $inputs = getInputs($matches[1]);

        return $inputs;
    } else {
        die('didn\'t find login form');
    }
}

// extract all <input fields from a form
function getInputs($form)
{
    $inputs = array();

    $elements = preg_match_all('/(<input[^>]+>)/is', $form, $matches);

    if ($elements > 0) {
        for($i = 0; $i < $elements; $i++) {
            $el = preg_replace('/\s{2,}/', ' ', $matches[1][$i]);

            if (preg_match('/name=(?:["\'])?([^"\'\s]*)/i', $el, $name)) {
                $name  = $name[1];
                $value = '';

                if (preg_match('/value=(?:["\'])?([^"\'\s]*)/i', $el, $value)) {
                    $value = $value[1];
                }

                $inputs[$name] = $value;
            }
        }
    }

    return $inputs;
}
?>

我已经在谷歌和stackoverflow上搜索解决方案,但我没有得到解决方案,我没有得到替代登录码或答案。

我想是的,填写表单并提交登录按钮的问题。我不确定问题到底出在哪里。stackoverflow有许多天才的编码器,所以我相信,我会从这里得到解决方案。

这是登录表单字段:

$formFields['Email']  = $USERNAME;
$formFields['Passwd'] = $PASSWORD;
unset($formFields['PersistentCookie']);

谢谢

EN

回答 2

Stack Overflow用户

发布于 2018-02-15 18:56:25

几年前我曾尝试过使用curl,但不起作用,试试Gmail API Gmail API

票数 0
EN

Stack Overflow用户

发布于 2018-02-20 02:42:08

你做错了几件事,例如,你试图用正则表达式解析HTML,这肯定会失败。此外,您的regex- html -parser不支持html编码,因此如果输入数据中有任何编码字符,您的代码将发送错误的数据。(例如,如果1如果csrf标记包含&,则它将被编码为&amp;,然后必须将其解码回&,但getInputs()函数不会尝试检测/解码html编码的字符)

再往下一点,你试图同时发送用户名和密码给https://accounts.google.com/ServiceLoginAuth -这不是它的工作方式,你必须分两批发送它们,首先是用户名,然后是不同的请求,密码,而且url是动态的,对于每个cookie会话它是不同的,但是在你的代码中,你已经硬编码了url,停止这样做,而不是向https://gmail.com/发出请求,它将几次http-location-重定向到一个动态的<form>,url的gaia_loginform将包含一个id为url的url,表单的“<input>”属性将指示您将用户名发送到何处,它还具有一组隐藏的action字段,您需要解析这些字段并将其添加到请求中。如果这个请求成功了,它会把你的http-location-redirect再重定向几次,转到另一个动态的url,它规定了你应该把密码和更多隐藏的<input>字段发送到哪里。

如果请求成功,则表示您已登录。但要使用适当的DOM解析器,如DOMDocument、don't use regex for parsing HTML.

对你来说幸运的是,我也需要一段时间以编程方式登录gmail,下面是我是如何做到的,使用hhb_curl -

编辑:警告,当gmail检测到你的登录“奇怪”时,它有时会问你,显然是完全随机的,要求你验证这是否真的是账户所有者登录的。验证您的方法之一是提供您的恢复电子邮件(因为只有帐户所有者才应该有该信息,对吧?),而我在这里发布的原始代码在被要求验证身份时会崩溃。下面是一个更新的代码,它接受第三个参数,即恢复电子邮件,并在被要求时自动验证身份:https://gist.github.com/divinity76/544d7cadd3e88e057ea3504cb8b3bf7e

尽管如此,由于历史原因,也因为我懒得更新SO答案代码,下面是我在这里发布的原始代码:

<?php
declare(strict_types = 1);
// header ( "content-type: text/plain;charset=utf8" );
require_once ('hhb_.inc.php');
function loginGmail(string $username, string $password): \hhb_curl {
    $hc = new hhb_curl ( '', true );
    $hc->setopt_array ( array (
            CURLOPT_TIMEOUT => 20, // i just have a shitty connection :(
            CURLOPT_CONNECTTIMEOUT => 10 
    ) );
    if (0) {
        $hc->setopt_array ( array (
                CURLOPT_USERAGENT => 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1' 
        ) );
    }
    $html = $hc->exec ( 'https://gmail.com' )->getStdOut ();
    $domd = @DOMDocument::loadHTML ( $html );
    $inputs = getDOMDocumentFormInputs ( $domd, true, false ) ['gaia_loginform'];
    // hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ) & die();
    $loginUrl = $domd->getElementById ( "gaia_loginform" )->getAttribute ( "action" );
    $inputs ['Email'] = $username;
    $html = $hc->setopt_array ( array (
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
            CURLOPT_URL => $loginUrl 
    ) )->exec ()->getStdOut ();
    $domd = @DOMDocument::loadHTML ( $html );
    $inputs = getDOMDocumentFormInputs ( $domd, true, false ) ['gaia_loginform'];
    // hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs );
    $loginUrl = $domd->getElementById ( "gaia_loginform" )->getAttribute ( "action" );
    $inputs ['Passwd'] = $password;
    try {
        $starttime = microtime ( true );
        $html = $hc->setopt_array ( array (
                CURLOPT_POST => 1,
                CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
                CURLOPT_URL => $loginUrl 
        ) )->exec ()->getStdOut ();
    } finally{
        // hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs, (microtime ( true ) - $starttime) ) & die ();
    }
    $domd = @DOMDocument::loadHTML ( $html );
    $xp = new DOMXPath ( $domd );
    $loginErrors = $xp->query ( '//span[contains(@class,"error-msg")]' );
    $loginErrorText = '';
    foreach ( $loginErrors as $tmp ) {
        $tmp = trim ( $tmp->textContent );
        if (strlen ( $tmp )) {
            $loginErrorText .= ' - ' . $tmp;
        }
    }
    if (! empty ( $loginErrorText )) {
        throw new \RuntimeException ( 'errors loggin in: ' . $loginErrorText );
    } else {
        // logged in! :D
    }
    // now we need to enable HTML view, it's a <form> POST request, but we can't use getDOMDocumentFormInputs (bug?)
    $found = false;
    foreach ( $domd->getElementsByTagName ( "form" ) as $form ) {
        if (false === stripos ( $form->textContent, "Gmail's basic HTML view, which doesn't require JavaScript" )) {
            continue;
        }
        $found = true;
        $url = $form->getAttribute ( "action" );
        if (! parse_url ( $url, PHP_URL_HOST )) {
            $url = $hc->getinfo ( CURLINFO_EFFECTIVE_URL ) . $url;
        }
        // hhb_var_dump ( $url ) & die ();
        $inputs = [ ];
        foreach ( $form->getElementsByTagName ( "input" ) as $input ) {
            $name = $input->getAttribute ( "name" );
            if (empty ( $name )) {
                continue;
            }
            $inputs [$name] = $input->getAttribute ( "value" );
        }
        // hhb_var_dump ( $inputs ) & die ();
        break;
    }
    if (! $found) {
        throw new \RuntimeException ( 'failed to find HTML version request form!' );
    }
    $html = $hc->setopt_array ( array (
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
            CURLOPT_URL => $url 
    ) )->exec ()->getStdOut ();
    hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ); // & die ();
    return $hc;
}
function rightTrim($str, $needle, $caseSensitive = true) {
    $strPosFunction = $caseSensitive ? "strpos" : "stripos";
    if ($strPosFunction ( $str, $needle, strlen ( $str ) - strlen ( $needle ) ) !== false) {
        $str = substr ( $str, 0, - strlen ( $needle ) );
    }
    return $str;
}
function getDOMDocumentFormInputs(\DOMDocument $domd, bool $getOnlyFirstMatches = false, bool $getElements = true): array {
    // :DOMNodeList?
    if (! $getOnlyFirstMatches && ! $getElements) {
        throw new \InvalidArgumentException ( '!$getElements is currently only implemented for $getOnlyFirstMatches (cus im lazy and nobody has written the code yet)' );
    }
    $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];
            }
        }
    }
    if ($getElements) {
        return $parsedForms;
    }
    $ret = array ();
    foreach ( $parsedForms as $formName => $arr ) {
        $ret [$formName] = array ();
        foreach ( $arr as $ele ) {
            $ret [$formName] [$ele->getAttribute ( "name" )] = $ele->getAttribute ( "value" );
        }
    }
    return $ret;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48805440

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档