php login curl code работает не так, как ожидалось

Я пытаюсь использовать функцию curl в php для входа на определенную страницу. Пожалуйста, ознакомьтесь с приведенным ниже кодом. Я связываюсь с моей электронной почтой и паролем на banggood.com, а затем я хотел бы перенаправить на другую личную страницу, но она не работает должным образом. У меня нет ошибок. Вместо этого я перенаправляюсь на эту страницу (https://www.banggood.com/index.php?com=account), используя приведенный ниже код. После входа в систему я хочу получить доступ к личной странице, где мои заказы существуют. Любая помощь оценивается.

//The username or email address of the account.
define('EMAIL', '[email protected]');

//The password of the account.
define('PASSWORD', 'mypassword');

//Set a user agent. This basically tells the server that we are using Chrome ;)
define('USER_AGENT', 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36');

//Where our cookie information will be stored (needed for authentication).
define('COOKIE_FILE', 'cookie.txt');

//URL of the login form.
define('LOGIN_FORM_URL', 'https://www.banggood.com/login.html');

//Login action URL. Sometimes, this is the same URL as the login form.
define('LOGIN_ACTION_URL', 'https://www.banggood.com/login.html');


//An associative array that represents the required form fields.
//You will need to change the keys / index names to match the name of the form
//fields.
$postValues = array(
    'email' => EMAIL,
    'password' => PASSWORD
);

//Initiate cURL.
$curl = curl_init();

//Set the URL that we want to send our POST request to. In this
//case, it the action URL of the login form.
curl_setopt($curl, CURLOPT_URL, LOGIN_ACTION_URL);

//Tell cURL that we want to carry out a POST request.
curl_setopt($curl, CURLOPT_POST, true);

//Set our post fields / date (from the array above).
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postValues));

//We don't want any HTTPS errors.
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

//Where our cookie details are saved. This is typically required
//for authentication, as the session ID is usually saved in the cookie file.
curl_setopt($curl, CURLOPT_COOKIEJAR, COOKIE_FILE);

//Sets the user agent. Some websites will attempt to block bot user agents.
//Hence the reason I gave it a Chrome user agent.
curl_setopt($curl, CURLOPT_USERAGENT, USER_AGENT);

//Tells cURL to return the output once the request has been executed.
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

//Allows us to set the referer header. In this particular case, we are
//fooling the server into thinking that we were referred by the login form.
curl_setopt($curl, CURLOPT_REFERER, LOGIN_FORM_URL);

//Do we want to follow any redirects?
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);

//Execute the login request.
curl_exec($curl);

//Check for errors!
if(curl_errno($curl)){
    throw new Exception(curl_error($curl));
}

//We should be logged in by now. Let attempt to access a password protected page
curl_setopt($curl, CURLOPT_URL, 'https://www.banggood.com/index.php?com=account&t=ordersList');

//Use the same cookie file.
curl_setopt($curl, CURLOPT_COOKIEJAR, COOKIE_FILE);

//Use the same user agent, just in case it is used by the server for session validation.
curl_setopt($curl, CURLOPT_USERAGENT, USER_AGENT);

//We don't want any HTTPS / SSL errors.
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

//Execute the GET request and print out the result.
curl_exec($curl);

Ответ 1

Вы делаете несколько ошибок:

  1. Вы пытаетесь войти в систему до того, как у вас будет сеанс cookie, но на сайте требуется, чтобы у вас был сеанс cookie перед отправкой запроса на вход.

  2. Там CSRF лексема привязанным к куки сессии, здесь называется at, что вам нужно разобрать из Войти страницы HTML и обеспечить ваш запрос авторизации, который ваш код не выборки.

  3. Самое главное, что изображение captcha привязано к вашему сеансу cookie, которое нужно извлечь и решить, и какой текст вам нужно добавить в свой запрос на вход, который ваш код полностью игнорирует.

  4. Ваш запрос на вход требует заголовка x-requested-with: XMLHttpRequest request x-requested-with: XMLHttpRequest но ваш код не добавляет этот заголовок.

  5. В вашем запросе на вход требуются поля com=account и t=submitLogin в данных POST, но ваш код не добавляет ни один из них (вы пытаетесь добавить их в свой URL-адрес, но они не должны быть в URL-адресе, они должны быть в данных POST, иначе это ваш массив $ postValues, а не URL-адрес)

Вот что вам нужно сделать:

  • Сначала выполните обычный запрос GET на страницу входа. Это даст вам идентификатор cookie сеанса, токен CSRF и URL-адрес вашего изображения captcha.
  • Сохраните идентификатор файла cookie и обязательно предоставите ему все дальнейшие запросы, затем проанализируйте токен csrf (он в html выглядит как <input type="hidden" name="at" value="5aabxxx5dcac0"/>) и url для изображения captcha (его разные для каждого сеанса cookie, поэтому не жуйте его).
  • Затем принести проверочное изображение, решить, и добавьте их в данные вашей POST запроса Войти, вместе с именем пользователя, пароль, искаженным ответ, com и t, и добавить заголовок HTTP x-requested-with: XMLHttpRequest для запроса авторизации также отправьте его на https://www.banggood.com/login.html, затем вы должны войти в систему!

Вот пример реализации, использующий hhb_curl для веб-запросов (это завитка, зависящая от куки файлов, превращение молчащих curl_-ошибок в RuntimeExceptions и т.д.), DOMDocument для разбора маркера CSRF и deathbycaptcha.com api для взлома captcha.

Ps: код примера не будет работать до тех пор, пока вы не предоставите реальное зачисленное имя пользователя/пароль deathbycaptcha.com api в строке 6 и 7, также как и в том, что captcha выглядит так просто, что я думаю, что его нарушение может быть автоматизировано, если вы достаточно мотивированы, я Нет. - edit, кажется, они улучшили свой captcha, так как я написал это, теперь это выглядит очень сложно. Кроме того, учетная запись banggood - это только временная тестовая учетная запись, и вред от нее не скомпрометирован, что, очевидно, происходит, когда я публикую здесь имя пользователя/пароль)

<?php

declare(strict_types = 1);
require_once ('hhb_.inc.php');
$banggood_username = '[email protected]';
$banggood_password = '[email protected]';
$deathbycaptcha_username = '?';
$deathbycaptcha_password = '?';

$hc = new hhb_curl ( '', true );
$html = $hc->exec ( 'https://www.banggood.com/login.html' )->getStdOut ();
$domd = @DOMDocument::loadHTML ( $html );
$xp = new DOMXPath ( $domd );
$csrf_token = $xp->query ( '//input[@name="at"]' )->item ( 0 )->getAttribute ( "value" );
$captcha_image_url = 'https://www.banggood.com/' . $domd->getElementById ( "get_login_image" )->getAttribute ( "src" );
$captcha_image = $hc->exec ( $captcha_image_url )->getStdOut ();

$captcha_answer = deathbycaptcha ( $captcha_image, $deathbycaptcha_username, $deathbycaptcha_password );

$html = $hc->setopt_array ( array (
        CURLOPT_POST => 1,
        CURLOPT_POSTFIELDS => http_build_query ( array (
                'com' => 'account',
                't' => 'submitlogin',
                'email' => $banggood_username,
                'pwd' => $banggood_password,
                'at' => $csrf_token,
                'login_image_code' => $captcha_answer 
        ) ),
        CURLOPT_HTTPHEADER => array (
                'x-requested-with: XMLHttpRequest' 
        ) 
) )->exec ()->getStdOut ();
var_dump ( // $hc->getStdErr (),
$html );

function deathbycaptcha(string $imageBinary, string $apiUsername, string $apiPassword): string {
    $hc = new hhb_curl ( '', true );
    $response = $hc->setopt_array ( array (
            CURLOPT_URL => 'http://api.dbcapi.me/api/captcha',
            CURLOPT_POST => 1,
            CURLOPT_HTTPHEADER => array (
                    'Accept: application/json' 
            ),
            CURLOPT_POSTFIELDS => array (
                    'username' => $apiUsername,
                    'password' => $apiPassword,
                    'captchafile' => 'base64:' . base64_encode ( $imageBinary )  // use base64 because CURLFile requires a file, and i cba with tmpfile() .. but it would save bandwidth.
            ),
            CURLOPT_FOLLOWLOCATION => 0 
    ) )->exec ()->getStdOut ();
    $response_code = $hc->getinfo ( CURLINFO_HTTP_CODE );
    if ($response_code !== 303) {
        // some error
        $err = "DeathByCaptcha api retuned \"$response_code\", expected 303, ";
        switch ($response_code) {
            case 403 :
                $err .= " the api username/password was rejected";
                break;
            case 400 :
                $err .= " we sent an invalid request to the api (maybe the API specs has been updated?)";
                break;
            case 500 :
                $err .= " the api had an internal server error";
                break;
            case 503 :
                $err .= " api is temorarily unreachable, try again later";
                break;
            default :
                {
                    $err .= " unknown error";
                    break;
                }
        }
        $err .= ' - ' . $response;
        throw new \RuntimeException ( $err );
    }
    $response = json_decode ( $response, true );
    if (! empty ( $response ['text'] ) && $response ['text'] !== '?') {
        return $response ['text']; // sometimes the answer might be available right away.
    }
    $id = $response ['captcha'];
    $url = 'http://api.dbcapi.me/api/captcha/' . urlencode ( $id );
    while ( true ) {
        sleep ( 10 ); // check every 10 seconds
        $response = $hc->setopt ( CURLOPT_HTTPHEADER, array (
                'Accept: application/json' 
        ) )->exec ( $url )->getStdOut ();
        $response = json_decode ( $response, true );
        if (! empty ( $response ['text'] ) && $response ['text'] !== '?') {
            return $response ['text'];
        }
    }
}

Ответ 2

Установите CURLOPT_FOLLOWLOCATION в 1 или true, вам может понадобиться CURLOPT_AUTOREFERER вместо статического REFERER.

COOKIEJAR ли вы куки в свой COOKIEJAR (файл cookie.txt)? Помните, что файл уже должен существовать, и PHP нуждается в разрешениях на запись.

Если у вас есть PHP, выполняющийся на локальном хосте, инструмент Network sniffer может помочь отладить проблему, попробуйте с Wireshark или некоторым эквивалентным программным обеспечением. Потому что, возможно, запрос по-прежнему пропускает некоторые важные заголовки HTTP, такие как Host