0

Strava.cz 用のサードパーティのランチ注文システムを作ろうとしています。私はそれを行うべきライブラリを作りました。strava_czChoose 関数以外はすべて機能します。エラーはスローされませんが、何もしません。彼らのサーバーは Windows ASPX に基づいているため、送信されたすべてのデータを理解するのは困難です。コード全体は次のとおりです。

<?php
/**
 * Additional function for DOMDocument
 * * * * *
 * @param DOMDocument $DOMDocument Document where you want to search
 * @patam string $className Name of the class you are searching of
 * * * * *
 */
function getElementsByClassName(\DOMDocument $DOMDocument, $className) {
 $Elements = $DOMDocument->getElementsByTagName("*");
 $Matched = array();

 for($i=0;$i<$Elements->length;$i++) {
  if(in_array($ClassName, explode(' ', $Elements->item($i)->attributes->getNamedItem('class')->nodeValue))) {
   $Matched[]=$Elements->item($i);
  }
 }

 return $Matched;
}

$strava_czHeader="User-Agent:(none; StravaCekujNET; Linux x86_64; rv:1.0)\r\nAccept:(text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8)\r\nAccept-Language:(cs,sk;q=0.8,en;q=0.6,en-gb;q=0.4,en-us;q=0.2)\r\nAccept-Encoding:(gzip, deflate)\r\nDNT:(1)\r\nConnection:(keep-alive)\r\n";
$strava_czHandle="n/a";

/**
 * * * * * * * * * * * * * * * *
 * Přihlášení (strava_czLogin) *
 * * * * * * * * * * * * * * * *
 * @param int|string $machine Zařízení (4 číslice, string v případě, že začíná nulou)
 * @param int|string $user Uživatel (10 číslic, string v případě, že začíná nulou)
 * @param string $pass Heslo pro přihlášení
 * * * * *
 */
function strava_czLogin($machine,$user,$pass){
 global $strava_czHeader;
 global $strava_czHandle;

 //Zašle první požadavek > $dom
 $src = file_get_contents('http://m.strava.cz/Stravnik/formprihlaseni.aspx',false,stream_context_create(array('http'=>array('header' => $strava_czHeader))));
 $dom = new domDocument;        //Vytvoří DOM
 $doc->strictErrorChecking = false;
  $src = mb_convert_encoding($src, 'HTML-ENTITIES', "UTF-8");
 $dom->loadHTML($src);         //Načte HTML
 unset($http_response_header, $src); //Uvolní paměť

 //Zpracuje přijatá data a zjistí klíč > $key
 $query['viewstate'] = $dom->getElementById('__VIEWSTATE')->getAttribute('value');
 $query['eventvalidation'] = $dom->getElementById('__EVENTVALIDATION')->getAttribute('value');
 $key = '?__EVENTTARGET'.
     '&__EVENTARGUMENT'.
     '&__VIEWSTATE='.urlencode($query['viewstate']).
     '&__EVENTVALIDATION='.urlencode($query['eventvalidation']).
     '&ctl00%24ContentPlaceHolder1%24txtZarizeni='.urlencode($machine).
     '&ctl00%24ContentPlaceHolder1%24txtUzivatel='.urlencode($user).
     '&ctl00%24ContentPlaceHolder1%24txtHeslo='.urlencode($pass).
     '&ctl00%24ContentPlaceHolder1%24butOdeslat=Odeslat';
 unset($dom, $query);  //Uvolní paměť

 //Zašle požadavek > $src, $http_response_header
 $src = file_get_contents('http://m.strava.cz/Stravnik/formprihlaseni.aspx'.$key,false,stream_context_create(array('http'=>array('header' => $strava_czHeader))));
 unset($key, $src); //Uvolní paměť


 //Zpracuje přijaté sušenky (mňam!)
 $i = 1;
 $strava_czHandle = array();
 $strava_czHandle['cookies'] = "";
 foreach ($http_response_header as $value) {
  $preg = preg_match('/^Set-Cookie:\s*.[^=]*=.[^;]*/m', $value, $matches);
  if ($preg) {
   foreach ($matches as $match) {
    $strava_czHandle['cookies'] .= substr($match, 12); //Zápis do handleru
    //Substring proto, aby se do handleru nezapisovalo i "SetCookie: "
   }
  }
 }
 unset($i, $http_response_header, $matches, $match, $value); //Uvolní paměť

 //Případně vyhodí chybu
 if ($strava_czHandle['cookies']==""){throw new Exception("noResult");}
}


/**
 * * * * * * * * * * * * * * * *
 * Odhlášení (strava_czLogout) *
 * * * * * * * * * * * * * * * *
 */
function strava_czLogout(){
 global $strava_czHandle;

 if ($strava_czHandle=="n/a") {throw new Exception("notLogged");}

 //Zašle požadavek
 $src = file_get_contents('http://m.strava.cz/Stravnik/odhlaseni.aspx',false,stream_context_create(array('http'=>array('header' => $strava_czHeader."Cookie: ".$strava_czHandle['cookies']."\r\n"))));

 //Zkontroluje správnost přijatých dat
 if (preg_match('/<form.*[^>]action="Default.aspx".*[^>]>/m',$src)){
  $strava_czHandle="n/a";
 } else {
  throw new Exception("unknownError");
 }
}


/**
 * * * * * * * * * * * * * * * * * * * * *
 * Získání jídelníčku (strava_czGetList) *
 * * * * * * * * * * * * * * * * * * * * *
 */
function strava_czGetList(){
 global $strava_czHeader;
 global $strava_czHandle;

 if (!$strava_czHandle||$strava_czHandle=="n/a") {throw new Exception("notLogged");}

 //Zašle požadavek > $dom
 $src = file_get_contents('http://m.strava.cz/Stravnik/objednavky.aspx',false,stream_context_create(array('http'=>array('header' => $strava_czMozHeader."Cookie:".$strava_czHandle['cookies']."\r\n"))));
 $dom = new domDocument;              //Vytvoří DOM
 $doc -> strictErrorChecking = FALSE;
  $src = mb_convert_encoding($src, 'HTML-ENTITIES', "UTF-8");
 $dom -> loadHTML($src);              //Načte HTML
 unset($http_response_header, $src); //Uvolní paměť

 //Zpracuje přijatá data > $nodeArray, $xpath
 $tbl = $dom -> getElementById('tblObjednavky') -> childNodes;
 $nodeArray=array(); $j=-1; $class = null;
 foreach ($tbl as $item) {
  if (($item -> getAttribute('class')) === 'tblObjednavkyDatum') {$j++;}
  $nodeArray[$j][] = $item;
 }
 $xpath = new DOMXPath($dom);
 unset($dom, $tbl, $j, $class, $item);

 /*
  Vytvořeno dvourozměrné pole. První rozměr určuje den a druhý konkrétní node
  (0 pro řádek s datem, vyšší číslo pro řádek s jídlem).
 */

 //Roztřídí přijatá data > $result
 $result = array();
 $i = 0;
 foreach ($nodeArray as $item) {
  $result[$i]['chosen'] = null;
  $result[$i]['choosable'] = false;
  $result[$i]['day'] = null;
  $j = -1;
  foreach ($item as $subitem) {
   if ($j > -1) {
    //Nastaví hodnoty, které jsou pro každou volbu individuální
    $result[$i]['name'][$j] = substr($xpath -> evaluate('./td[4]', $subitem) -> item(0) -> textContent, 4);

    /*
       Lowercase
       Všechny bílé znaky převést na mezeru a zakázat více mezer za sebou (chování jako HTML bez white-space:pre)
       Za každou tečku a čárku, za kterou není mezera, přidat mezeru.
    */
    $result[$i]['name'][$j] = preg_replace('([\.,])', '$0 ', $result[$i]['name'][$j]);
    $result[$i]['name'][$j] = preg_replace('/\s+/m',' ', mb_strtolower($result[$i]['name'][$j], 'utf-8'));

    if ($xpath -> evaluate('./td[2]/img', $subitem) -> length) {$result[$i]['chosen'] = $j;}
    $x = $xpath -> evaluate('./td[3]/span/input', $subitem);
    if ($x -> length) {
     $result[$i]['choosable'] = true;
     $result[$i]['day'] = $x -> item(0) -> getAttribute('name');
     $result[$i]['lunch'][$j] = $x -> item(0) -> getAttribute('value');
    }
   }
   $j++;
  }
  //Nastaví hodnoty, které platí pro celý den
  $result[$i]['date'] = $item[0] -> textContent;
  /* TODO Převést datum na DD/MM/YYYY */
  $i++;
 }

 //Vrátí výsledné hodnoty
 if ($result == array()) {throw new Exception("noResult");} else {return $result;}
}

/**
 * * * * * * * * * * * * * * * * * * * *
 * Objednávání jídel (strava_czChoose) *
 * * * * * * * * * * * * * * * * * * * *
*/
function strava_czChoose($list) {
 global $strava_czHeader;
 global $strava_czHandle;

 if (!$strava_czHandle||$strava_czHandle=="n/a") {throw new Exception("notLogged");}

 //Pošle první požadavek (získá ty mrkvosofťácký "chujoviny", jak by řekl Keby) > $dom, $list
 $src = file_get_contents('http://m.strava.cz/Stravnik/objednavky.aspx',false,stream_context_create(array('http'=>array('header' => $strava_czMozHeader."Cookie:".$strava_czHandle['cookies']."\r\n"))));
 $dom = new domDocument; //Vytvoří DOM
 $doc->strictErrorChecking = false;
  $src = mb_convert_encoding($src, 'HTML-ENTITIES', "UTF-8");
 $dom->loadHTML($src);   //Načte HTML
 unset($http_response_header,$src);

 //Zpracuje data a zjistí klíč > $key, $list
 $query['viewstate'] = $dom->getElementById('__VIEWSTATE')->getAttribute('value');
 $query['eventvalidation'] = $dom->getElementById('__EVENTVALIDATION')->getAttribute('value');
 $key = '?_EVENTTARGET=butOdeslat'.
        '&_EVENTARGUMENT'.
        '&_VIEWSTATE='.urlencode($query['viewstate']).
        '&_EVENTVALIDATION='.urlencode($query['eventvalidation']);
 unset($dom,$query);

 //Ze zadání vytvoří string dotazu > $data, $key
 $data = '';
 foreach ($list as $day => $lunch) {
  $data .= '&'.urlencode($day).'=radObjednavka'.urlencode($lunch);
 }
 var_dump('http://m.strava.cz/Stravnik/objednavky.aspx'.$key.$data);

 //Pošle druhý požadavek (odešle objednávku), případně vyhodí error
 file_get_contents('http://m.strava.cz/Stravnik/objednavky.aspx'.$key.$data,false,stream_context_create(array('http'=>array('header' => $strava_czMozHeader."Cookie:".$strava_czHandle['cookies']."\r\n"))));
 if (preg_match('/500/',$http_response_header)) {throw new Exception("unknownError");}
}

try {strava_czLogin(/*secret*/);}
 catch (Exception $e) {exit("</div><div>Přihlášení se nezdařilo, chyba: ".($e -> getMessage()));}
try {$r=strava_czGetList();}
 catch (Exception $e) {exit("</div><div>Zjištení jídel se nezdařilo, chyba: ".($e -> getMessage()));}
try {strava_czChoose(array('2013-03-121' => 'P754'));}
 catch (Exception $e) {exit("</div><div>Chyba při odesílání objednávek: ".($e -> getMessage()));}
try {strava_czLogout();}
 catch (Exception $e) {exit("</div><div>Odhlaseni se nezdařilo, chyba: ".($e -> getMessage()));}
var_dump($r);
?>

何が悪いのかわからない。コメントは申し訳ありませんが、チェコ語です。Google 翻訳を使用できますが、翻訳はdoubleplusgoodではありません。助けてくれてありがとう、m93a

編集:サーバーが HTTP 302 を返す場合、それは受け入れられる選択であることがわかりました。HTTP 200 を取得します。GET の代わりに POST を使用してみましたが、それでも 200 になります。

4

1 に答える 1

0

最後に、私はその理由を見つけました。ブラウザの HTTP リクエストとアプリのリクエストを徹底的に比較したところ、__EVENTTARGET「butOdeslat2」に設定する必要があることがわかりました。小さな間違いもありましたが、すぐに見つけて修正しました。

すべてが完璧に機能するようになりました。

于 2013-03-09T22:14:36.693 に答える