Изменить: почему минус один?
Я пытаюсь сделать следующее:
Поэтому мне нужно войти в систему, используя мой пропуск и номер, но для формы на школьном сайте также нужен скрытый «токен».
<form action="index.php" method="post"> <input type="hidden" name="token" value="becb14a25acf2a0e697b50eae3f0f205" /> <input type="text" name="user" /> <input type="password" name="password" /> <input type="submit" value="submit"> </form>
Я могу успешно извлечь токен. Затем я пытаюсь войти, но он терпит неудачу.
// Getting the whole website $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://www.school.com'); $data = curl_exec($ch); // Retrieving the token and putting it in a POST $regex = '/<regexThatWorks>/'; preg_match($regex,$data,$match); $postfields = "user=<number>&password=<secret>&token=$match[1]"; // Should I use a fresh cURL here? // Setting the POST options, etc. curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields); // I won't use CURLOPT_RETURNTRANSFER yet, first I want to see results. $data = curl_exec($ch); curl_close($ch);
Ну … Это не работает …
Извините за мой страшный английский, я голландский.
Какое сообщение об ошибке вы получаете? Независимо от этого; сайт вашей школы может проверить заголовок реферера и убедиться, что запрос идет (приложение, притворяющееся …) его страницей входа.
Вот как я это решил. Вероятно, проблема заключалась в том, что часть «не используется». Тем не менее это, вероятно, «уродливый» код, поэтому любые улучшения приветствуются!
// This part is for retrieving the token from the hidden field. // To be honest, I have no idea what the cookie lines actually do, but it works. $getToken= curl_init(); curl_setopt($getToken, CURLOPT_URL, '<schoolsite>'); // Set the link curl_setopt($getToken, CURLOPT_COOKIEJAR, 'cookies.txt'); // Magic curl_setopt($getToken, CURLOPT_COOKIEFILE, 'cookies.txt'); // Magic curl_setopt($getToken, CURLOPT_RETURNTRANSFER, 1); // Return only as a string $data = curl_exec($token); // Perform action // Close the connection if there are no errors if(curl_errno($token)){print curl_error($token);} else{curl_close($token);} // Use a regular expression to fetch the token $regex = '/name="token" value="(.*?)"/'; preg_match($regex,$data,$match); // Put the login info and the token in a post header string $postfield = "token=$match[1]&user=<number>&paswoord=<mine>"; echo($postfields); // This part is for logging in and getting the data. $site = curl_init(); curl_setopt($site, CURLOPT_URL, '<school site'); curl_setopt($site, CURLOPT_COOKIEJAR, 'cookies.txt'); // Magic curl_setopt($site, CURLOPT_COOKIEFILE, 'cookies.txt'); // Magic curl_setopt($site, CURLOPT_POST, 1); // Use POST (not GET) curl_setopt($site, CURLOPT_POSTFIELDS, $postfield); // Insert headers $forevil_uuh_no_GOOD_purposes = curl_exec($site); // Output the results // Close connection if no errors if(curl_errno($site)){print curl_error($site);} else{curl_close($site);}
Когда вы создаете скребок, вы можете создавать свои собственные классы для работы за то, что вам нужно делать в вашем домене. Вы можете начать с создания собственного набора классов запросов и ответов, которые касаются того, с чем вам нужно иметь дело.
Создание собственного класса запросов позволит вам реализовать запрос curl так, как вам нужно. Создавая свой собственный класс ответа, вы можете помочь вам получить доступ / обработать возвращенный HTML.
Это простой пример использования некоторых классов, которые я создал для демонстрации:
# simple get request $request = new MyRequest('http://hakre.wordpress.com/'); $response = new MyResponse($request); foreach($response->xpath('//div[@id="container"]//div[contains(normalize-space(@class), " post ")]') as $node) { if (!$node->h2->a) continue; echo $node->h2->a, "\n<", $node->h2->a['href'] ,">\n\n"; }
Он вернет мои сообщения в блогах:
Will Automattic join Dec 29 move away from GoDaddy day? <http://hakre.wordpress.com/2011/12/23/will-automattic-join-dec-29-move-away-from-godaddy-day/> PHP UTF-8 string Length <http://hakre.wordpress.com/2011/12/13/php-utf-8-string-length/> Title belongs into Head <http://hakre.wordpress.com/2011/11/02/title-belongs-into-head/> ...
Отправка запроса на получение запроса легко, как пирог, ответ можно легко получить с помощью выражения xpath (здесь SimpleXML ). XPath может быть полезен для выбора маркера из поля формы, поскольку он позволяет вам запрашивать данные документа более легко, чем с регулярным выражением.
Отправка запроса на отправку была следующей вещью для сборки, я попытался написать сценарий входа в свой блог, и оказалось, что он работает неплохо. Мне также нужно было разобрать заголовки ответов, поэтому я добавил несколько дополнительных процедур для моего класса запросов и ответов.
# simple post request $request = new MyRequest('https://example.wordpress.com/wp-login.php'); $postFields = array( 'log' => 'username', 'pwd' => 'password', ); $request->setPostFields($postFields); $response = new MyResponse($request->returnHeaders(1)->execute()); echo (string) $response; # output to view headers
Учитывая ваш сценарий, вы можете отредактировать свой собственный класс запросов, чтобы лучше справляться с тем, что вам нужно, и я уже использую файлы cookie, так как вы их используете. Поэтому некоторый код, основанный на этих классах для вашего сценария, может выглядеть так:
# input values $url = '<schoolsite>'; $user = '<number>'; $password = '<secret>'; # execute the first get request to obtain token $response = new MyResonse(new MyRequest($url)); $token = (string) $response->xpath('//input[@name="token"]/@value'); # execute the second login post request $request = new MyRequest($url); $postFields = array(; 'user' => $user, 'password' => $password, 'token' => $token ); $request->setPostFields($postFields)->execute();
Демо и код как сущность .
Если вы хотите еще больше улучшить это, следующим шагом будет то, что вы создаете себе класс для «школьного обслуживания», который вы используете для получения расписания:
class MySchoolService { private $url, $user, $pass; private $isLoggedIn; public function __construct($url, $user, $pass) { $this->url = $url; ... } public function getSchedule() { $this->ensureLogin(); # your code to obtain the schedule, eg in form of an array. $schedule = ... return $schedule; } private function ensureLogin($reuse = TRUE) { if ($reuse && $this->isLoggedIn) return; # execute the first get request to obtain token $response = new MyResonse(new MyRequest($this->url)); $token = (string) $response->xpath('//input[@name="token"]/@value'); # execute the second login post request $request = new MyRequest($this->url); $postFields = array(; 'user' => $this->user, 'password' => $this->password, 'token' => $token ); $request->setPostFields($postFields)->execute(); $this->isLoggedIn = TRUE; } }
После того, как вы хорошо завернули логику запроса / ответа в свой класс MySchoolService
вам нужно только создать его с правильной конфигурацией, и вы можете легко использовать его на своем веб-сайте:
$school = new MySchoolService('<schoolsite>', '<number>', '<secret>'); $schedule = $school->getSchedule();
В вашем основном скрипте используется только MySchoolService
.
MySchoolService
позаботится об использовании объектов MyRequest
и MyResponse
.
MyRequest
заботится о выполнении HTTP-запросов (здесь cUrl) с куки-файлами и т. Д.
MyResponse
помогает немного разобрать HTTP-ответы.
Сравните это со стандартным интернет-браузером:
Browser: Handles cookies and sessions, does HTTP requests and parses responses. MySchoolService: Handles cookies and sessions for your school, does HTTP requests and parses responses.
Итак, теперь у вас есть школьный браузер в вашем скрипте, который делает то, что вы хотите. Если вам нужно больше вариантов, вы можете легко расширить его.
Надеюсь, что это полезно, отправной точкой было предотвратить повторное использование одних и тех же строк кода cUrl, а также дать вам лучший интерфейс для анализа возвращаемых значений. MySchoolService
– это немного сахара на вершине, что упрощает работу с вашим собственным кодом веб-сайта / приложения.