2012-05-19 5 views
0

Я пытаюсь создать скрипт, который отправляет информацию в RoyalMail tracking system и извлекает результат.Faking Post Request с PHP Curl - Rejection

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

Вещи, которые я думаю, что я принял во внимание:

  • Используя точную копию их формы, анализируя его заранее (почтовые параметры)
  • Сохранение куки между запросами
  • Прием перенаправлять заголовки
  • обеспечивая см заголовок, который на самом деле действительный (ранее посещенных страниц)

Кто-нибудь знает что-нибудь еще, что мне нужно, чтобы проверить или выяснить, что я делаю неправильно?

Полная копия источника в EDIT: смотрите мой ответ ниже

+0

_I я получаю сообщение об ошибке от их server_ - какая ошибка вы получаете? Изменить: ага, это в вашей второй ссылке. – halfer

+0

Я получал ошибку, но мне нужно было следить за их переадресацией! –

+0

@pez - Так вам удалось это решить? – Lix

ответ

1

Я исправил это, проблема была связана с PHP-завиванием и последующими переадресациями, кажется, что он не всегда публикует данные запроса и отправляет запрос GET при выполнении.

Чтобы справиться с этим, я отключил завиток, следуя местоположению с curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);, а затем сам построил систему следования, которая работает рекурсивно. По сути, он извлекает заголовок местоположения из ответа, проверяет наличие 301 или 302 и затем снова запускает метод по мере необходимости.

Это означает, что информация, безусловно, будет отправлена ​​повторно.

Я также улучшил строку пользовательского агента, просто скопировав свой текущий на основе, он не будет заблокирован в течение длительного времени, так как в 2012 году он активно используется!

Вот окончательный вариант локонов класса (в случае, если связь умирает - был вниз проголосовали за то, в прошлом), которая работает:

/** 
* Make a curl request respecting redirects 
* Also supports posts 
*/ 
class pegCurlRequest { 
    private $url, $postFields = array(), $referer = NULL, $timeout = 3; 
    private $debug = false, $postString = ""; 
    private $curlInfo = array(); 
    private $content = ""; 
    private $response_meta_info = array(); 

    static $cookie; 

    function __construct($url, $postFields = array(), $referer = NULL, $timeout = 3) { 
    $this->setUrl($url); 
    $this->setPost($postFields); 
    $this->setReferer($referer); 
    $this->setTimeout($timeout); 
    if(empty(self::$cookie)) self::$cookie = tempnam("/tmp", "pegCurlRequest"); //one time cookie 
    } 

    function setUrl($url) { 
    $this->url = $url; 
    } 

    function setTimeout($timeout) { 
    $this->timeout = $timeout; 
    } 

    function setPost($postFields) { 
    if(is_array($postFields)) { 
     $this->postFields = $postFields; 
    } 
    $this->updatePostString(); 
    } 

    function updatePostString() { 
    //Cope with posting 
    $this->postString = ""; 
    if(!empty($this->postFields)) { 
     foreach($this->postFields as $key=>$value) { $this->postString .= $key.'='.$value.'&'; } 
     $this->postString= rtrim($this->postString,'&'); //Trim off the waste 
    } 
    } 

    function setReferer($referer) { 
    //Set a referee either specified or based on the url 
    $this->referer = $referer; 
    } 

    function debugInfo() { 
    //Debug 
    if($this->debug) { 
     echo "<table><tr><td colspan='2'><b><u>Pre Curl Request</b><u></td></tr>"; 
     echo "<tr><td><b>URL: </b></td><td>{$this->url}</td></tr>"; 
     if(!empty(self::$cookie)) echo "<tr><td><b>Cookie String: </b></td><td>".self::$cookie."</td></tr>"; 
     if(!empty($this->referer)) echo "<tr><td><b>Referer: </b></td><td>".$this->referer."</td></tr>"; 
     if(!empty($this->postString)) echo "<tr><td><b>Post String: </b></td><td>".$this->postString."</td></tr>"; 

     if(!empty($this->postFields)) { 
     echo "<tr><td><b>Post Values:</b></td><td><table>"; 
     foreach($this->postFields as $key=>$value) 
      echo "<tr><td>$key</td><td>$value</td></tr>"; 
     echo "</table>"; 
     } 
     echo "</td></tr></table><br />\n"; 
    } 
    } 

    function debugFurtherInfo() { 
    //Debug 
    if($this->debug) { 
     echo "<table><tr><td colspan='2'><b><u>Post Curl Request</b><u></td></tr>"; 
     echo "<tr><td><b>URL: </b></td><td>{$this->url}</td></tr>"; 
     if(!empty($this->referer)) echo "<tr><td><b>Referer: </b></td><td>".$this->referer."</td></tr>"; 
     if(!empty($this->curlInfo)) { 
     echo "<tr><td><b>Curl Info:</b></td><td><table>"; 
     foreach($this->curlInfo as $key=>$value) 
      echo "<tr><td>$key</td><td>$value</td></tr>"; 
     echo "</table>"; 
     } 
     echo "</td></tr></table><br />\n"; 
    } 
    } 

    /** 
    * Make the actual request 
    */ 
    function makeRequest($url=NULL) { 
    //Shorthand request 
    if(!is_null($url)) 
     $this->setUrl($url); 

    //Output debug info 
    $this->debugInfo(); 

    //Using a shared cookie 
    $cookie = self::$cookie; 

    //Setting up the starting information 
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 Safari/536.11"); 
    curl_setopt($ch, CURLOPT_URL, $this->url); 
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie); 
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); 
    curl_setopt($ch, CURLOPT_ENCODING, "gzip"); 

    //register a callback function which will process the headers 
    //this assumes your code is into a class method, and uses $this->readHeader as the callback //function 
    curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this,'readHeader')); 

    //Some servers (like Lighttpd) will not process the curl request without this header and will return error code 417 instead. 
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:")); 

    //Referer 
    if(empty($this->referer)) { 
     curl_setopt($ch, CURLOPT_REFERER, dirname($this->url)); 
    } else { 
     curl_setopt($ch, CURLOPT_REFERER, $this->referer); 
    } 

    //Posts 
    if(!empty($this->postFields)) { 
     curl_setopt($ch, CURLOPT_POST, true); 
     curl_setopt($ch, CURLOPT_POSTFIELDS, $this->postString); 
    } 

    //Redirects, transfers and timeouts 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_AUTOREFERER, false); 
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout); 
    curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); 
    curl_setopt($ch, CURLOPT_MAXREDIRS, 10); 

    //Debug 
    if($this->debug) { 
     curl_setopt($ch, CURLOPT_VERBOSE, true); // logging stuffs 
     curl_setopt($ch, CURLINFO_HEADER_OUT, true); // enable tracking 
    } 

    //Get the content and the header info 
    $content = curl_exec($ch); 
    $response = curl_getinfo($ch); 

    //get the default response headers 
    $headers = curl_getinfo($ch); 

    //add the headers from the custom headers callback function 
    $this->response_meta_info = array_merge($headers, $this->response_meta_info); 

    curl_close($ch); //be nice 

    //Curl info 
    $this->curlInfo = $response; 

    //Output debug info 
    $this->debugFurtherInfo(); 

    //Are we being redirected? 
    if ($response['http_code'] == 301 || $response['http_code'] == 302) { 
     $location = $this->getHeaderLocation(); 
     if(!empty($location)) { //the location exists 
     $this->setReferer($this->getTrueUrl()); //update referer 
     return $this->makeRequest($location); //recurse to location 
     } 
    } 
    //Is there a javascript redirect on the page? 
    elseif (preg_match("/window\.location\.replace\('(.*)'\)/i", $content, $value) || 
     preg_match("/window\.location\=\"(.*)\"/i", $content, $value)) { 
     $this->setReferer($this->getTrueUrl()); //update referer 
     return $this->makeRequest($value[1]); //recursion 
    } else { 
     $this->content = $content; //set the content - final page 
    } 
    } 

    /** 
    * Get the url after any redirection 
    */ 
    function getTrueUrl() { 
    return $this->curlInfo['url']; 
    } 

    function __toString() { 
    return $this->content; 
    } 

    /** 
    * CURL callback function for reading and processing headers 
    * Override this for your needs 
    * 
    * @param object $ch 
    * @param string $header 
    * @return integer 
    */ 
    private function readHeader($ch, $header) { 
     //This is run for every header, use ifs to grab and add 
     $location = $this->extractCustomHeader('Location: ', '\n', $header); 
     if ($location) { 
      $this->response_meta_info['location'] = trim($location); 
     } 
     return strlen($header); 
    } 

    private function extractCustomHeader($start,$end,$header) { 
     $pattern = '/'. $start .'(.*?)'. $end .'/'; 
     if (preg_match($pattern, $header, $result)) { 
      return $result[1]; 
     } else { 
      return false; 
     } 
    } 

    function getHeaders() { 
     return $this->response_meta_info; 
    } 

    function getHeaderLocation() { 
     return $this->response_meta_info['location']; 
    } 
} 
+0

Код менее интересен, чем фактическое решение. не могли бы вы объяснить свое решение более подробно, а не просто сбросить весь скрипт здесь? – Lix

+1

Добавлено выше с подробными сведениями для вас –

1

Ну, прежде всего, вы являются говорить о Royal Mail. Так что я не уверен, если это просто маленький трюк будет срабатывать их ...

Но что вы мог попробовать это подмена вашего агента пользователя с быстрым ini_set() -

ini_set('user_agent', 'Mozilla/5.0 (X11; CrOS i686 1660.57.0) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.46 Safari/535.19' 

Это хром Ubuntu строка пользовательского агента.

Строка пользовательского агента cRUL будет выглядеть совсем по-другому. Например

curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 

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

+0

Если вы проверите код, который вы увидите, я использую: curl_setopt ($ ch, CURLOPT_USERAGENT, «Mozilla/5.0 (Windows; U; Windows NT 5.1; rv: 1.7.3) Gecko/20041001 Firefox/0.10.1 "); –

+1

@PezCuckow, если вы хотите, чтобы люди просматривали код, вы должны вставить его в свой вопрос. –

+0

Я отметил вас так же правильно, как вы указали мне в правильном направлении на раннем этапе, подумал, что это не то, что на самом деле зафиксировано! Я дал ответ с полной копией решения. –

1

Веб-сайты обычно используют 2 способа определить, являетесь ли вы человеком или ботом: HTTP REFERER и USER AGENT. Я предлагаю вам использовать Curl прописанным агент пользователя и реферер (замените «HTTP: // что-то /» с реальной URL страницы вы обычно посетить Прежде чем перейти к URL вы хотите скачать с PHP):

<?php 

$url = 'http://track2.royalmail.com/portal/rm/track'; 
$html = file_get_contents2($url, ''); 


$post['_dyncharset'] = 'ISO-8859-1'; 

$post['trackConsigniaPage'] = 'track'; 

$post['/rmg/track/RMTrackFormHandler.value.searchCompleteUrl'] = '/portal/rm/trackresults?catId=22700601&pageId=trt_rmresultspage'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.searchCompleteUrl'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.invalidInputUrl'] = '/portal/rm/trackresults?catId=22700601&pageId=trt_rmresultspage&keyname=track_blank'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.invalidInputUrl'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.searchBusyUrl'] = '/portal/rm/trackresults?catId=22700601&pageId=trt_busypage&keyname=3E_track'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.searchBusyUrl'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.searchWaitUrl'] = '/portal/rm/trackresults?catId=22700601&timeout=true&pageId=trt_timeoutpage&keyname=3E_track'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.searchWaitUrl'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.keyname'] = '3E_track'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.keyname'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.previousTrackingNumber'] = ''; 
$post['_D:/rmg/track/RMTrackFormHandler.value.previousTrackingNumber'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.trackingNumber'] = 'ZW791944749GB'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.trackingNumber'] = ''; 
$post['/rmg/track/RMTrackFormHandler.track.x'] = '50'; 
$post['/rmg/track/RMTrackFormHandler.track.y'] = '14'; 
$post['_D:/rmg/track/RMTrackFormHandler.track'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.day'] = '19'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.day'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.month'] = '5'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.month'] = ''; 
$post['/rmg/track/RMTrackFormHandler.value.year'] = '2012'; 
$post['_D:/rmg/track/RMTrackFormHandler.value.year'] = ''; 
$post['_DARGS'] = '/portal/rmgroup/apps/templates/html/rm/rmTrackResultPage.jsp'; 

$url2 = 'http://track2.royalmail.com/portal/rm?_DARGS=/portal/rmgroup/apps/templates/html/rm/rmTrackAndTraceForm.jsp'; 
$html2 = file_get_contents2($url2, $url, $post); 

echo $html2; 

function file_get_contents2($address, $referer, $post = false) 
{ 
    $useragent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"; 

    $c = curl_init(); 
    curl_setopt($c, CURLOPT_URL, $address); 
    curl_setopt($c, CURLOPT_USERAGENT, $useragent);  
    curl_setopt($c, CURLOPT_HEADER, 0); 
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); 

    if ($post) 
    { 
     $postF = http_build_query($post); 
     curl_setopt($c, CURLOPT_POST, true); 
     curl_setopt($c, CURLOPT_POSTFIELDS, $postF);  
    } 

    curl_setopt($c, CURLOPT_COOKIEJAR, 'cookie.txt'); 
    //curl_setopt($c, CURLOPT_FRESH_CONNECT, 1); 
    curl_setopt($c, CURLOPT_REFERER, $referer); 
    curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1); 
    if (!$data = curl_exec($c)) 
    { 
     return false; 
    } 

    return $data; 
} 

выше обновленный код вернул меня:

Item ZW791944749GB was posted at 1 High Street RG17 9TJ on 19/05/12 and is being progressed through our network for delivery. 

Так что кажется, что это работает.

+1

Если вы проверите мой код, вы увидите, что я уже делаю это, возможно, я должен был сделать это яснее! –

+1

Хорошо, но вы используете «Firefox/0.10.1» в качестве пользовательского агента. Они могут проверять номер версии и запрещать слишком старые браузеры. Попробуйте увеличить число. Заголовок 301 Http предназначен для перенаправления - куда он перенаправляет вас? Также, пожалуйста, сохраните в файл, что именно вы получаете от них, и разместите файл где-нибудь. – Tom