2014-11-23 2 views
12

Я столкнулся с довольно странной проблемой.cURL работает от терминала, но не от PHP

Я пытаюсь войти в удаленную настройку moodle, используя curl из PHP.

У меня есть команда curl, которая отлично работает в Терминале.

Когда я переводил то же самое в PHP, он работает, но он просто не входит в систему. Точно такое же значение, которое успешно входит в систему через терминал, каким-то образом вытаскивает систему входа через PHP и не входит в систему. Вместо этого он снова возвращает страницу входа в систему.

Моя Curl команда (раздел данные пропущены как это имеет свое имя пользователя и пароль):

curl 'http://moodle.tsrs.org/login/index.php' 
-H 'Pragma: no-cache' 
-H 'Origin: http://moodle.tsrs.org' 
-H 'Accept-Encoding: gzip, deflate' 
-H 'Accept-Language: en-US,en;q=0.8' 
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36' 
-H 'Content-Type: application/x-www-form-urlencoded' 
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' 
-H 'Cache-Control: no-cache' 
-H 'Referer: http://moodle.tsrs.org/login/index.php' 
-H 'Cookie: MoodleSession=ngcidh028m37gm8gbdfe07mvs7; MOODLEID_=%25F1%25CD%2519D%25B2k%25FE%251D%25EFH%25E5t%25B1%2503%258E; MoodleSessionTest=NhzaTNij6j; _ga=GA1.2.925953522.1416155774; _gat=1; __utmt=1; __utma=147409963.925953522.1416155774.1416642544.1416692798.3; __utmb=147409963.1.10.1416692798; __utmc=147409963; __utmz=147409963.1416155774.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)' 
-H 'Connection: keep-alive' 

Соответствующий PHP код:

function login() { 
    $username = $_POST['username']; 
    $password = $_POST['password']; 

    if(!isset($_POST['username']) || !isset($_POST['password'])) { 
     echo "No login data received"; 
     return; 
    } 

    $creq = curl_init(); 

    $data = array('username' => $username, 'password' => $password, 'testcookies'=> '1'); 

    $headers = array('Pragma: no-cache', 'Origin: http://moodle.tsrs.org', 'Accept-Encoding: ', 'Accept-Language: en-US,en;q=0.8', 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36', 'Content-Type: application/x-www-form-urlencoded', 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Cache-Control: no-cache', 'Cookie: MoodleSession=ngcidh028m37gm8gbdfe07mvs7; MOODLEID_=%25F1%25CD%2519D%25B2k%25FE%251D%25EFH%25E5t%25B1%2503%258E; MoodleSessionTest=NhzaTNij6j; _ga=GA1.2.925953522.1416155774; _gat=1; __utmt=1; __utma=147409963.925953522.1416155774.1416642544.1416692798.3; __utmb=147409963.1.10.1416692798; __utmc=147409963; __utmz=147409963.1416155774.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)', 'Connection: keep-alive'); 
     curl_setopt_array($creq, array(
     CURLOPT_URL => 'http://moodle.tsrs.org/login/index.php', 
     CURLOPT_RETURNTRANSFER => true, 
     CURLOPT_POST => true, 
     CURLOPT_ENCODING => '', 
     CURLINFO_HEADER_OUT => true, 
     CURLOPT_POSTFIELDS => $data, 
     CURLOPT_HTTPHEADER => $headers, 
     CURLOPT_FOLLOWLOCATION => false 
    )); 

    $output = curl_exec($creq); 

    echo print_r(curl_getinfo($creq)); 

    echo "\n" . $output . "\n"; 
} 

И выход curlinfo:

Array 
(
    [url] => http://moodle.tsrs.org/login/index.php 
    [content_type] => text/html; charset=utf-8 
    [http_code] => 200 
    [header_size] => 541 
    [request_size] => 945 
    [filetime] => -1 
    [ssl_verify_result] => 0 
    [redirect_count] => 0 
    [total_time] => 1.462409 
    [namelookup_time] => 0.002776 
    [connect_time] => 0.330766 
    [pretransfer_time] => 0.330779 
    [size_upload] => 365 
    [size_download] => 8758 
    [speed_download] => 5988 
    [speed_upload] => 249 
    [download_content_length] => -1 
    [upload_content_length] => 365 
    [starttransfer_time] => 0.694866 
    [redirect_time] => 0 
    [certinfo] => Array 
     (
     ) 

    [primary_ip] => 125.22.33.149 
    [redirect_url] => 
    [request_header] => POST /login/index.php HTTP/1.1 
Host: moodle.tsrs.org 
Pragma: no-cache 
Origin: http://moodle.tsrs.org 
Accept-Language: en-US,en;q=0.8 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 
Cache-Control: no-cache 
Cookie: MoodleSession=ngcidh028m37gm8gbdfe07mvs7; MOODLEID_=%25F1%25CD%2519D%25B2k%25FE%251D%25EFH%25E5t%25B1%2503%258E; MoodleSessionTest=NhzaTNij6j; _ga=GA1.2.925953522.1416155774; _gat=1; __utmt=1; __utma=147409963.925953522.1416155774.1416642544.1416692798.3; __utmb=147409963.1.10.1416692798; __utmc=147409963; __utmz=147409963.1416155774.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) 
Connection: keep-alive 
Content-Length: 365 
Expect: 100-continue 
Content-Type: application/x-www-form-urlencoded; boundary=----------------------------83564ee60d56 


) 

Кто-нибудь знает любую возможную причину этого? Я попытался заменить жесткий файл с COOKIEFILE и COOKIEJAR, но ничего не изменил.

+0

я сделал то же самое раньше, но не может найти code- я думаю, что его, потому что он перенаправляет после входа в систему , поэтому вам нужно разрешить перенаправление - используйте что-то вроде curl_setopt ($ curl, CURLOPT_MAXREDIRS, 10); –

+0

Заголовки ** НЕ ** то же самое в вопросе. Командная строка cURL включает в себя заголовок «Referer» и значение «Accept-Encoding». PHP cURL вообще не включает Referer и пустое пространство для Accept-Encoding. @RichardTheKiwi, просто для того, чтобы уточнить, ваша проблема также зависит от конкретной модели? – HPierce

+0

после перезагрузки, вы нашли какой-нибудь файл cookie в своем браузере? –

ответ

0

Я подозреваю, что ваша первая попытка с использованием команды curl - использовать метод GET в файле index.php. Я предлагаю вам включить --trace-ascii в свой первый запрос на завивки в командной строке и посмотреть, будет ли на сервере задан запрос GET. Если да, вы должны изменить свой PHP-скрипт, который использует метод POST. Если вы измените значение CURLOPT_POST на false, скрипт PHP должен работать.

+0

Я вполне уверен, что это запрос POST, так как я снял его с инструментов Chrome Dev, а документация Moodle строго говорит, что логин только через POST. Кроме того, страница, к которой я клонирую, как представляется, получает мои данные POST, так как страница входа в нее, возвращаемая в PHP, имеет мое имя пользователя, предварительно заполненное, которое было отправлено как переменная POST. –

1

Скорее всего, ваша проблема связана с HTTP-заголовком Expect: 100-continue, который cURL отправляет по умолчанию для каждого запроса POST.

Заголовок Expect: 100-continue используется в запросах POST, содержащих большие данные, когда клиент не уверен, что сервер примет такой запрос. В этом случае клиент сначала отправляет запрос только с заголовками, включая Expect: 100-continue, и, если ответ сервера будет успешным, отправьте тот же запрос с телом (данные POST).

Проблема в том, что не все веб-серверы правильно обрабатывают этот заголовок. В таких случаях отправка этого заголовка нежелательна.

Решение вручную удаляет Expect заголовок от отправки заголовков, обходя array('Expect:') до CURLOPT_HTTPHEADER. В вашем случае вы можете просто добавить «Ожидать:» строку $headers массива:

$headers[] = 'Expect:'; 
+0

Пробовал это сейчас. Без изменений –

+0

@Raghav Sood Вы должны показать заголовки ответов. Это может помочь найти источник проблемы.Добавьте 'CURLOPT_HEADER' в массив опций и заголовков выходных ответов. Также вы должны предоставить заголовки ответов для запроса CLI cURL – hindmost

4

Использование http_build_query на $data массива перед переходом к скручиванию, чтобы избежать Content-Type: application/x-www-form-urlencoded; boundary=---. Это также гарантирует кодирование любых специальных символов из пароля.

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); 

Переформуйте ваши запросы свертыванию следующим образом:

Сделать запрос GET на страницу входа в систему с указанием файла куки в $cookies = '/tmp/some/dir/xyz.cookie.txt'. Убедитесь, что вы используете полный путь для имени файла cookie. А затем закройте ручку завитка. Это сохранит файл cookie в файле cookie.

$creq = curl_init(); 
curl_setopt_array($creq, array(
    CURLOPT_URL => 'http://moodle.tsrs.org/login/index.php', 
    CURLOPT_RETURNTRANSFER => true, 
    CURLOPT_ENCODING => '', 
    CURLINFO_HEADER_OUT => true, 
    CURLOPT_HTTPHEADER => $headers, 
    CURLOPT_FOLLOWLOCATION => false, 
    CURLOPT_COOKIEJAR => $cookies // save cookie 
)); 
$output = curl_exec($creq); 
curl_close($creq); 

Теперь сделайте запрос POST со вторым запросом на завивание. На этот раз укажите тот же файл cookie с параметром COOKIEFILE.

$creq = curl_init(); 
curl_setopt_array($creq, array(
    CURLOPT_URL => 'http://moodle.tsrs.org/login/index.php', 
    CURLOPT_RETURNTRANSFER => true, 
    CURLOPT_POST => true, 
    CURLOPT_ENCODING => '', 
    CURLINFO_HEADER_OUT => true, 
    CURLOPT_POSTFIELDS => http_build_query ($data), 
    CURLOPT_HTTPHEADER => $headers, 
    CURLOPT_FOLLOWLOCATION => false, 
    CURLOPT_COOKIEJAR => $cookies, // save cookie 
    CURLOPT_COOKIEFILE => $cookies // load cookie 
); 
$output = curl_exec($creq); 
curl_close($creq); 

Это может произойти, иногда внешний вид сервера для печенья, когда запрос Войти сделал (чтобы убедиться, что запрос пришел после посещения страницы входа).

+0

Это правильный ответ. – drew010

+0

'Это также гарантирует кодирование любых специальных символов из пароля, который вводит в заблуждение,' multipart/form-data' закодированные данные бинарно безопасны, при передаче массива curl будет автоматически кодировать его. кроме того, при передаче больших данных, не относящихся к ascii, он использует значительно меньшую пропускную способность, чем «application/x-www-form-urlencoded», данные формы имеют большие накладные расходы заголовка (поэтому, почему он не использует меньше bw для небольших данных) , но он вообще не кодирует данные. с urlencoded, (почти) каждый байт без ascii закодирован в 3 байта. в формах данных все байты (включая байты без ascii) составляют ровно 1 байт. – hanshenrik

+0

, но да, возможно, поэтому он не работает. в командной строке curl используется кодировка 'application/x-www-form-urlencoded', в то время как php curl (используя его код) использует кодировку' multipart/form-data', которая, вероятно, отклоняется. использование http_build_query сделает код php curl также использовать 'application/x-www-form-urlencoded' – hanshenrik

7

Это могло бы быть отлажено лучше, видя все, что было сделано cURL. Это делается добавлением флагового знака в команду: -v.

$ curl localhost/login [...] -v 

Мы можем получить же выход из завитка PHP, добавив опцию CURLOPT_VERBOSE. Обратите внимание, что добавив эту строку, вы даете указание cURL выводить ту же информацию в STDOUT - она ​​не будет возвращена и контент не будет отправлен в браузер, поэтому это необходимо отладить в терминале.

curl_setopt($curl, CURLOPT_VERBOSE, 1); 

Делая это таким образом, вы можете получить последовательный и сопоставимый вывод обоих HTTP-запросы, он должен выглядеть sommthing так:

POST/HTTP/1.1 
Host: localhost:3000 
Pragma: no-cache 
Origin: http://moodle.tsrs.org 
Accept-Language: en-US,en;q=0.8 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 
Cache-Control: no-cache 
Cookie: MoodleSession=ngcidh028m37gm8gbdfe07mvs7; MOODLEID_=%25F1%25CD%2519D%25B2k%25FE%251D%25EFH%25E5t%25B1%2503%258E; MoodleSessionTest=NhzaTNij6j; _ga=GA1.2.925953522.1416155774; _gat=1; __utmt=1; __utma=147409963.925953522.1416155774.1416642544.1416692798.3; __utmb=147409963.1.10.1416692798; __utmc=147409963; __utmz=147409963.1416155774.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) 
Connection: keep-alive 
Content-Length: 250 
Expect: 100-continue 
Content-Type: application/x-www-form-urlencoded; boundary=------------------------b4d79f17a3887f2d 

< HTTP/1.1 100 Continue 
< HTTP/1.1 200 OK 
< X-Powered-By: Express 
< Content-Type: application/json; charset=utf-8 
< Content-Length: 2 
< ETag: W/"2-mZFLkyvTelC5g8XnyQrpOw" 
< Date: Thu, 22 Dec 2016 19:13:40 GMT 
< Connection: keep-alive 

Слева: Командная строка Керл, как это предусмотрено в вопросе (с дополнительным -v флагом)

справа: PHP Curl, как писал в вопросе (с CURLOUT_VERBOSE включен)

Как вы можете видеть, заголовки не являются тем же, и это делает это ясным. В вызове PHP отсутствует Accept-Encoding и Referer заголовки.

side by side comparison of curl on the command line vs php curl outputs


Если не оказаться ничего, давайте попробуем изменить некоторые более Curl настройки PHP обратно в исходные Curl по умолчанию.

Internally, PHP opts to override some defaults in cURL не сообщая вам. Хотя эти параметры должны быть хорошо, давайте изменим их обратно явно переустановку их обратно к скручиванию по умолчанию:

curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 60); 
curl_setopt($curl, CURLOPT_DNS_USE_GLOBAL_CACHE, 0); 
curl_setopt($curl, CURLOPT_MAXREDIRS, -1); 
curl_setopt($curl, CURLOPT_NOSIGNAL, 0); 
+0

Moodle имеет возможность проверить HTTP_REFERER. Я собирался опубликовать тот же ответ, прежде чем увижу твое. Заголовок Referer ** определенно ** что-то проверить, даже если могут возникнуть дополнительные проблемы. – LSerni

+0

Отлично. Я считаю себя обученным. большое спасибо – RichardTheKiwi

Смежные вопросы