Autor Zpráva
Tomášeek
Profil
Ahoj,

mám u Wedosu nějaké předplacené služby, jejichž stav bych si rád pravidelně kontroloval, abych o nich měl větší přehled. Nedaří se mi ale se přihlásit skrze cURL (script se bude pouštět CRONem).

Vzhledem k tomu, že u login formulářů má wedos nějaké měnící se parametry v URL, nejprve si z kódu vytáhnu URL, kam se má form odesílat.

$page = file_get_contents('https://client.wedos.com/login/login.html');

$form = substr($page, strpos($page, '<h1>Přihlášení uživatele</h1>')); // toto možná pak budu zjišťovat jinak, pro pokus nyní dostačující
preg_match('~action="([^"]+)"~', $form, $matches);
$url = $matches[1];
echo $url; // tady vidím správnou URL, která je i ve zdrojáku

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1');
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); # nasel jsem jako reseni kvuli HTTPS, zkoušel jsem i bez tohoto
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); # nasel jsem jako reseni kvuli HTTPS, zkoušel jsem i bez tohoto
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array('login' => 'email@example.com', 'passwd' => 'example_pass'))); // login udaje jsou spravne, kontroloval jsem je
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$server_output = curl_exec ($ch);
echo $server_output;
curl_close ($ch);
Vždy ale dostanu odpověď 200 (jakože vše OK), ale neplatný login, přesměrování na stránku, kde mám heslo zadat znovu.

Poradíte mi, prosím, co dělám blbě? Proč se mi login nedaří? S cURLem jsem pracoval dosud jen jednou a navíc jinde, nevím, jestli tam bylo HTTPS (bohužel už ten kód nemám k dispozici) a nedaří se mi to opětovně rozchodit.

Děkuji za rady.
mckay
Profil
Tomášeek:
Proměnná $url není správně inicializovaná. Nemělo by Vám to takto vrátit nic.

V případě, že proměnnou naincializujete na hodnotu indexu 1 z $matches, bude v ní uložena adresa, na kterou chcete request posílat.

Pro zjištění, kde je problém se Vám bude do budoucna hodit vědět o funkcích int curl_errno($ch) a mixed array curl_getinfo($ch).


Kód jsem upravil a ozkoušel, a taktéž dostávám odpověď 200. Nikde ale nevyčtu nic o neplatném loginu? (Zadávám opravdové přihlašovací údaje k existujícímu účtu). Předpokládám, že docházíte k závěru, že navracená adresa pod "url" indexem odpovědi v curl_getinfo() je místo, kam Vás to přesměrovává. Řekl bych, že jde ve skutečnosti o adresu, která Vám "odpovídá" (tedy ta samá co requestujete). To co kód dle mého porozumění dělá je to, že odešle authentikační post požadavek na Wedos. A tím to končí a dělá to správně. Pravděpodobně budete chtít změnit pohled, kterým se na úkol díváte. Vy budete chtít žádat přímo stránku, která obsahuje informace o službě, kterou máte zaplacenou a společně s dotazem posílat autentikační data.
Tomášeek
Profil
mckay:
Proměnná URL existuje a vrací správnou hodnotu (mám ji tam echnutou a psal jsem i, že echuje správně. Musí tedy existovat a je zřejmé, že mám překlep). Tady jsem se v tom řádku uklepl, resp. mi tam vypadl mezitím řádek $url = $matches[1];. Doplnil jsem pro úplnost, byť to podstatu problému neřeší.

Jak jsem psal, vrací to stavový kód 200 a zobrazí login stránku wedosu. curl_error nevrací nic, tam chyba není, jinak by nebyl stavový kód 200.

Abych to shrnul, krásné povídání, děkuji za snahu, ale nijak jsi mi nepomohl (byť v dobré víře). I cesta, kterou se vydávám k cíli, je správná. Pokud u wedosu máš účet, a jsi přesvědčen o tom, že jsem natolik hloupý/blbý, že pracuji s neinicializovanou proměnnou url, zkus prosím se svými údaji se přihlásit řekněme na stránku s přehledem objednaných hostingů. Pak můžeme porovnat, kde jsem dělal chybu a nehledat ji v překlepu v definici proměnné.

Nějaké další nápady, někdo jiný? Děkuji za všechny rady (i mckayovi, byť to tak zatím nevypadá :-) ).
mckay
Profil
Tomášeek:
a jsi přesvědčen o tom, že jsem natolik hloupý/blbý, že pracuji s neinicializovanou proměnnou url,

Bohužel postujete z nového účtu bez předchozích příspěvků, takže po průzkumu Vašeho profilu jsem nemohl odhadnout úroveň Vašich dovedností a znalostí. Na diskusi se poměrně často děje, že člověku unikne hloupý řádek a má mírně nastavené chybové zprávy, takže příčinu nepozná.

zkus prosím se svými údaji se přihlásit řekněme na stránku s přehledem objednaných hostingů. Pak můžeme porovnat, kde jsem dělal chybu a nehledat ji v překlepu v definici proměnné.

Poslední dvě hodinky jsem se právě tímto zabýval. S cURL jsem se bohužel zatím v podstatě nesetkal, takže jsem problém nebyl schopný vyřešit, ale došel jsem k určitým závěrům.

Problém je v tom, jak se stavíme k procesu "přihlášení se" do Wedosové administrace. To, co řešíme výše uvedeným kódem je odeslání formuláře s přihlašovacími údaji na adresu, která provádí přihlášení. Po lehčím průzkumu jak se cURL používá už vím, že Váš kód je funkčí. Kód 200 je vrácen proto, protože samotná operace poslání přihlašovacích údajů na adresu, která je má zpracovat je úspěšné, ale samo o sobě je k ničemu.

V procesu přihlášení se dojde k nějakému ověření vůči databázi, vygenerování režijních dat a uložení těchto dat ke klientovi - například do cookies a následně dojde k přesměrování uživatele do administrace. Přirozeně nám to nefunguje, protože my pouze odesíláme data na tu adresu a o zbytek se nestaráme.

cURL ale umožňuje zachytit cookies, jejichž uložení náš požadavek vygeneruje, a to pomocí následujícího nastavení:
curl_setopt($ch2, CURLOPT_COOKIEJAR, $cookiePath); 

$cookiePath proměnná by měla být v závislosti na operačním systému absolutní nebo relativní cesta k souboru, do kterého chceme uložit cookie ze serveru. Windows tuším chce absolutní. Problém je zde s tím, že cookies jsou (nepřekvapivě) získány a uloženy až po provedení requestu (curl_exec()).

Pak je zde další nastavení, které umožňuje našemu požadavku využít soubor, ve kterém jsou cookies uloženy:
curl_setopt($ch2, CURLOPT_COOKIEFILE, $cookiePath);

Řešení, ke kterému jsem dospěl, ale neměl jsem čas ho dotáhnout do konce, by vypadalo nějak následovně:
1. Poslat Vámi již napsaný požadavek vůči přihlašovacímu skriptu, a pomocí nastavení CURLOPT_COOKIEJAR si uložit vygenerované cookies v odpovědi k sobě.
2. Poslat druhý požadavek, na konkrétní stránku na wedosu vyžadující autentikaci (testováno vůči client.wedos.com/domains) obohacený o cookies, které jsme si v kroku 1 uložili.

Nepodařilo se mi to rozchodit a bohužel se tím už ani dále zabývat nebudu. Zaujal mě Váš dotaz a tak jsem ho využil jako příležitost se trochu přivzdělat, ale nemohu tomu již bohužel více času věnovat, abych to dotáhl do konce.

Jako zdroje jsem použil následující, takřka identické dotazy k tomu vašemu na stacku: Login to remote site with php curl, Keeping session alive with php and curl, Why php does not save cookies in my local file, How can I send cookies using PHP curl in addition to CURLOPT_COOKIEFILE?, PHP post request with cURL and cookie.

Hodně štěstí.
Edit: A pokud se Vám to povede vyřešit, byl bych rád, kdybyste se podělil o řešení.
mckay
Profil
Edit 2: Zkusil jsem se se stejným přístupem lognout sem do diskuse, přes cURL a podařilo se. Strávil jsem nějaký další čas zkoumáním wedosového přihlašování a podařilo se mi to realizovat. Popíšu, jak.

Mám Google Chrome, pustím anonymní okno, F12 -> Developers tools, záložka network, pustím nahrávání. Vložím adresu client.wedos.com/home, přihlásím se pomocí svých přístupových údajů a vypnu nahrávání. Prohlédnu si prvotní request, který jsem zaslal (zejména se věnuji odpovědi na něj a položkám Set-Cookie). Potom se podívám na druhý request - ten přihlašovací, co prohlížeč poslal a věnuji pozornost hlavičce Cookie, která je odesílaná. Následně si všimnu, jaký je v tom vzor a vím, jakým způsobem musím napsat přihlášení do wedos administrace a zobrazení stránky s chráněným obsahem.
Tomášeek
Profil
mckay:
Zatím v tom stále tápu, nedaří se mi :-/

Jsem trochu povzbuzen tím tvým Edit 2, ale ještě asi někde dělám chybu, nebo mi něco chybí a nevím co. Dle tvého příspěvku výše mi chyběla COOKIEFILE, tu jsem doplnil, pak jsem si dále hrál s různými variantami, které se blížily příspěvku #5, ale zatím stále neúspěšně. Ani nevím, jaký kód bych sem šoupl, těch variací jsem zkoušel mnoho a nevím, která byla výsledku blíže či dále...

Pokud budeš chtít zveřejnit kód, kterým ses přihlásil, budu rád. Pokud ne, pochopím a budu bádat dál vím, že to jde.
nightfish
Profil
Tomášeek:
Třeba takto:
<?php

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://client.wedos.com/login/login.html');
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_COOKIEFILE, __DIR__.'/cookies.txt');
curl_setopt($curl, CURLOPT_COOKIEJAR, __DIR__.'/cookies.txt');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
$loginPage = curl_exec($curl);

if (preg_match('~action="(.*?)"~', $loginPage, $m)) {
    $newUrl = html_entity_decode($m[1]);
    curl_setopt($curl, CURLOPT_URL, $newUrl);
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(['login' => 'email@example.com', 'passwd' => 'example_pass']));
    $response = curl_exec($curl);
    curl_close($curl);
    if (preg_match('~Jste přihlášen jako <a.*?>(.*?)</a>~', $response, $m))
        echo "Přihlášený uživatel: ".$m[1];
    else {
        echo "Pravděpodobně nedošlo k přihlášení<br>";
        echo $response;
    }
}

1) Musíš si nastavit CURLOPT_COOKIEFILE a CURLOPT_COOKIEJAR, aby si cURL pamatovalo přihlášení i při dalších požadavcích.
2) Adresu pro přihlášení z atributu action <formu> musíš prohnat funkcí html_entities_decode, která převede &amp; na &
3) Není rozumné nastavovat CURL_SSL_VERIFYPEER na FALSE, lepší je nainstalovat si do cURL aktuální bundle root certifikátů (a pravidelně jej aktualizovat)
4) Detekce zda-li jsem přihlášen spoléhá na to, že skript je uložen v kódování UTF-8 a stejně tak odpověď ze serveru příjde v tomto kódování.
Tomášeek
Profil
nightfish:
Tenhle kód jsem zkoušel, možná i dříve (chybová hláška je mi známá), vyhazuje chybu/warning Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in ...

Mohu na sdíleném hostingu nějak přebít nastavení serveru? Našel jsem zatím jen možnosti, jak změnit toto nastavení v php.ini, kam nemám přístup. Dále jsem pak našel možnost přidat do .htaccess tento řádek php_admin_value open_basedir none, případně pouze php_value open_basedir none. První končí 500 internal error, druhý chybou nekončí, ale cURL hlásá totéž, k přepisu hodnoty tedy nedošlo.

Existuje nějaká možnost, jak tyto hodnoty na sdíleném serveru přepsat? Děkuji.


EDIT: teď koukám, že mi web běží na PHP 5.3 a nějaké drobné, od PHP 5.4 open_basedir už není. Nicméně nyní jsem na staré verzi PHP, je to řešitelné, abych nemusel měnit hosting? Děkuji.
Davex
Profil
Tomášeek:
Existuje nějaká možnost, jak tyto hodnoty na sdíleném serveru přepsat?
Ne.

Nicméně nyní jsem na staré verzi PHP, je to řešitelné, abych nemusel měnit hosting?
Můžeš si implementovat stejnou funkčnost jako dělá CURLOPT_FOLLOWLOCATION. Tedy přečíst z odpovědi HTTP hlavičku Location a následovat URL.
Tomášeek
Profil
Davex:
Můžeš si implementovat stejnou funkčnost jako dělá CURLOPT_FOLLOWLOCATION. Tedy přečíst z odpovědi HTTP hlavičku Location a následovat URL.
To zní dobře. Tím následováním myslíš redirect pomocí header? Samozřejmě zkusím, ptám se jen, pokud jsi stále online, jestli bys případně tu myšlenku nedokončil.

Díky za další posunutí, moc mi to pomůže (snad) :-)
Davex
Profil
Tomášeek:
Tím následováním myslíš redirect pomocí header?
Kdepak. Stránka z nové adresy se musí znova stáhnout (už přes GET) a případně projít další URL v hlavičce Location, dokud se nedostaneš k cílové stránce, kde už žádné přesměrování nebude.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: