[addon curl-wrapper] cURL wrapper
- Honza Kuchař
- Člen | 1662
Vidím v todo parser HTML. Mohu vřele doporučit tento: http://simplehtmldom.sourceforge.net/
- sairon
- Člen | 32
Perfektní věc, jen bych měl dvě výtky ohledně přesměrovávání:
- bylo by vhodné ošetřit případné zacyklení při přesměrování v případě, že se nepoužívá výchozí přesměrování přes CURLOPT_FOLLOWLOCATION
- CURLOPT_FOLLOWLOCATION není zakázané pouze v safe_mode, ale i při nastaveném open_basedir, což, jak koukám do zdrojáku, skript v potaz nebere
Doplnění 4.5.:
Ještě jsem si všimnul, že má přesměrování ve skriptu problém
v případech, kdy není Location zadána absolutně – sice to není košer,
ale setkávám se s tím často. To by také nebylo od věci vyřešit, ať je
ta náhrada FOLLOWLOCATION plnohodnotná.
Editoval sairon (4. 5. 2010 22:26)
- sairon
- Člen | 32
Možná by to šlo vyřešit nějak elegantněji, já to zatím vyřešil po vzoru curl_redir_exec z komentářů na php.net.
V Curl->set_request_options:
<?php
if( $this->getFollowRedirects() AND strtolower(ini_get('safe_mode')) !== 'on' AND ini_get('open_basedir') == ""){
curl_setopt($this->request, CURLOPT_FOLLOWLOCATION, true);
}
?>
Upravený Curl->request():
<?php
public function request($method, $url, $vars = array(), $cyc = 0)
{
if($cyc > 15)
throw new CurlException("Redirect loop");
$this->error = Null;
$used_proxies = 0;
if( is_array($vars) ){
$this->vars = http_build_query($vars, '', '&');
}
if( !is_string($url) AND $url !== '' ){
throw new CurlException("Invalid URL: " . $url);
}
do{
$this->closeRequest();
$this->request = curl_init();
if( count($this->proxies) > $used_proxies ){
//$this->setOption['HTTPPROXYTUNNEL'] = True;
$this->setOption('PROXY', $this->proxies[$used_proxies]['ip'] . ':' . $this->proxies[$used_proxies]['port']);
$this->setOption('PROXYPORT', $this->proxies[$used_proxies]['port']);
//$this->setOption('PROXYTYPE', CURLPROXY_HTTP);
$this->setOption('TIMEOUT', $this->proxies[$used_proxies]['timeout']);
if( $this->proxies[$used_proxies]['user'] !== NUll AND $this->proxies[$used_proxies]['pass'] !== Null ){
$this->setOption('PROXYUSERPWD', $this->proxies[$used_proxies]['user'] . ':' . $this->proxies[$used_proxies]['pass']);
}
$used_proxies++;
} else {
unset($this->option['PROXY'], $this->option['PROXYPORT'], $this->option['PROXYTYPE'], $this->option['PROXYUSERPWD']);
} //debug::dump($this->options);
$this->set_request_method($method);
$this->set_request_options($url);
$this->set_request_headers();
$response = curl_exec($this->request);
$this->error = curl_errno($this->request).' - '.curl_error($this->request);
$this->info = curl_getinfo($this->request);
} while( curl_errno($this->request) == 6 AND count($this->proxies) < $used_proxies );
$this->closeRequest();
if( $response ){
$response = new CurlResponse($response, $this);
$response_headers = $response->getHeaders();
if( isset($response_headers['Location']) AND $this->getFollowRedirects() ) {
$url = @parse_url($response_headers['Location']);
if(!$url) {
throw new CurlException("Can't parse location header: " . $response_headers['Location']);
}
$lastUrl = parse_url($this->info['url']);
if(!isset($url['scheme']))
$url['scheme'] = $lastUrl['scheme'];
if(!isset($url['host']))
$url['host'] = $lastUrl['host'];
if(!isset($url['path']))
$url['path'] = $lastUrl['path'];
$location = $url['scheme'] . "://" . $url['host'] . $url['path'] . (isset($url['query'])?"?".$url['query']:"");
$response = $this->request($this->getMethod(), $location, array(), ++$cyc);
}
} else {
if ($this->info['http_code'] == 400) {
throw new CurlException('Bad request - ' . $response);
} elseif ($this->info['http_code'] == 401) {
throw new CurlException('Permission Denied - ' . $response);
} else {
throw new CurlException($this->error);
}
}
return $response;
}
?>
- Filip Procházka
- Moderator | 4668
rozběhl jsem github https://github.com/…cURL-wrapper
přidal namespaces
přilepil saironovu opravu
a ještě pár menších oprav :)
- Honza Kuchař
- Člen | 1662
Taková poznámka, když budete potřebovat číst nějaké gigantické
soubory (>2GB, >4GB), použijte cUrl, nemá s tím žádné problémy na
rozdíl od nativních fcí PHPka. (nefunguje třeba fseek) Stačí použít
protokol file://
- kravčo
- Člen | 721
Na linuxe mi funguje fseek+fgetc bez problémov… Je potrebné sa uistiť, že nie sme na WIN, máme dostatočnú presnosť a implementáciu doublu podľa IEEE (presné po ~4EB). Samozrejme problémy môžu byť pri rôznych distribúciách a verziách, no na zisťovanie toho čas nemám…
Ale má to zmysel len ak je výrazne rýchlejší ako cURL (čo asi bude…).
!!! toto je len nástrel, program nemusí fungovať na inom ako mojom počítači…
if (ini_get('precision') >= 14 // check php's precision
&& strncasecmp(php_uname('s'), 'WIN', 3) // no Win platform please...
&& strncasecmp(PHP_OS, 'WIN', 3) // really, no Win platform...
&& in_array(pack('d', -4294967295.0), array( // is double stored as
"\x00\x00\xE0\xFF\xFF\xFF\xEF\xC1", // 64bit IEEE floating-point?
"\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", // (we generously support LE/BE)
))) :
// TODO: should test some floating-point operation too (FADD)
function safe_filesize($filename)
{
$fp = fopen($filename, 'rb');
if (!$fp) return FALSE;
flock($fp, LOCK_SH);
if (fseek($fp, 0x7fffffff, SEEK_SET)) {
throw new Exception("File '$filename' does not support seeking at all.");
}
$size = filesize($filename); // realsize % 4Gi signed
if ($size < 0) $size += 0x80000000; // realsize % 2Gi unsigned
while(fgetc($fp) !== FALSE) {
$size += 0x80000000;
if (fseek($fp, 0x7fffffff, SEEK_CUR)) {
throw new Exception("Your OS does not support seeking beyond 2GB boundary and/or end of file.");
}
}
flock($fp, LOCK_UN);
fclose($fp);
return $size;
}
else :
function safe_filesize($filename)
{
throw new Exception("Function safe_filesize() may malfunction when
a) PHP precision is set below 14 digits (your setting: " . ini_get('precision') . ")
b) you run it on Windows (your environment: ". php_uname('s') . ")
c) your floating-point implementation is not IEEE conformant.
One or more of these conditions were satisfied for you.");
}
endif;
- Honza Kuchař
- Člen | 1662
Vypadá to fajn, já se chtěl vyhnout něčemu co funguje jen na Linuxu, protože ho nikde nemám, neumím nastavit a tudíž ani kde otestovat.
Nicméně u zjistění souboru bych to přidal, protože tam jde o rychlost a může to být voláno hodněkrát. (prosím tedy o otestování, přidám to do distribuce BigFileTools)
A v implementaci File Downloaderu (ke čtení souborů), se curl použije jen pokud je při segmentovém stahování startovací pozice větší než PHP_INI_MAX. Tedy opravdu výjimečné situace… (a na 64bitových distribucích, to snad ani nemůže nastat)
PS: Šlo by to předělat, tak aby to nepoužívalo float. ;) (což File Downloader asi čeká také nebo myslíš, že je to zbytečné?)
- kravčo
- Člen | 721
Bez floatu to asi nepôjde, pretože čísla väčšie ako 4Gi 32bitové
phpko proste nezvládne. Riešenie, kde by sme rozdelili veľkosť na dolných
31 bitov ($lsize = filesize($filename)
) a horných 31 bitov
($hsize++
) mi príde len posúvanie problému inam – ale
rozšírenie bude nezávislé od floating point implementácie
(return array($lsize, $hsize)
). Skúsim napísať malý skriptík
na otestovanie.
Alebo myslíš použitie rozšírení ako BCMath/GMP?
- Honza Kuchař
- Člen | 1662
No asi takhle, libi se mi vice GMP, ale bcmath je součástí distribuce. (nemusí se načítat)
- Elijen
- Člen | 171
Neřešil jste náhodou někdo přepsání tohoto (výborného) doplňku do Nette2? Problém jsem měl v metodě fixUrl, která se volá v případě přesměrování a používá třídu Nette\Web\Uri. Myslel jsem, že by to mělo vyřešit pouhé nahrazení za Nette\Http\Url, ale buď třída nění zpětně kompatibilní nebo je problém ještě někde jinde. Po nahrazení to hází tuto chybu (vypadá to, že pouze při přesměrování):
exception 'Nette\FatalErrorException' with message 'curl_setopt(): 223 is not a valid File-Handle resource' in /var/www/dealbon.cz/libs/Curl/Request.php:1308
- Filip Procházka
- Moderator | 4668
Mohl bych alespoň opravit kompatibilitu, pravda.
Celou knihovnu jsem ale kompletně přepsal a hodně vylepšil a opravil i pár chyb. Aktuálně k vidění v Kdyby. Obsahuje sice víc tříd, ale kódu moc nepřibylo, spíše jsem rozděloval původní God-objekty.
- Elijen
- Člen | 171
HosipLan napsal(a):
Mohl bych alespoň opravit kompatibilitu, pravda.
Celou knihovnu jsem ale kompletně přepsal a hodně vylepšil a opravil i pár chyb. Aktuálně k vidění v Kdyby. Obsahuje sice víc tříd, ale kódu moc nepřibylo, spíše jsem rozděloval původní God-objekty.
Koukám, že většinou public metody třídy Request zůstaly, takže by teoreticky nahrazení stávajícího doplňku za novou verzi nemusel být problém. Nebo mě čeká nějaké překvapení? :)
Edit: Tak Request ted chce URL primo v constructoru, coz me stve :(
Editoval Elijen (27. 2. 2012 15:04)
- Filip Procházka
- Moderator | 4668
Co takto?
services:
curlSender:
class: Kdyby\Curl\CurlSender
setup:
- setDownloadDir("%tempDir%/download")
$request = new Kdyby\Curl\Request($url);
$request->method = Kdyby\Curl\Request::DOWNLOAD;
$response = $this->context->curlSender->send($request);
Já bych k tomu měl spíš sepsat nějakou docku … https://github.com/…amework/wiki
Editoval HosipLan (27. 2. 2012 16:15)
- Elijen
- Člen | 171
Tak nějak jsem to udělal, díky :-) .. Ještě koukám, že se nedá
nastavit jméno souboru, kam se má stažený soubor uložit, což dříve šlo.
Nyní se pro vygenerování jména používá
Nette\Utils\Strings::random()
… já používal:
do {
$fileName = uniqid() . ".tmp";
} while (is_file($this->downloadFolder . "/" . $fileName));
Ale to už mě zas tolik netrápí. Dík za pomoc.
Editoval Elijen (27. 2. 2012 18:17)
- RDPanek
- Člen | 189
Ahoj, chci pouzit toto rozsireni, ale pravdepodobne spatne nakladam se session: http://pastebin.com/ERa3FNuh
Aplikacka pro svuj beh se potrebuje autentizovat na Facebooku. kdyz cilovou adresu spustim v prohlizeci – aplikacka pokracuje v tom co ma, ale jak mile jdu pres curl, tak se chce vzdy autorizovat.
Viz. pastebin – co delam spatne? Díky
- Filip Procházka
- Moderator | 4668
Doporučil bych ti raději použít aktualizovaný wrapper a k tomu hračičku na
„simulování uživatele“ (tak jako to dělá selenium). Závislosti jsou
definované v composer.json
.
$browser = new Kdyby\Extension\Browser\WebBrowser;
$session = $browser->createSession();
$page1 = $session->open('http://applikacka/');
$page2 = $session->open('/'); // pamatuje si domenu
Mělo by to být docela odladěné, ale dělal jsem pořádek a ještě jsem to pořádně neotestoval po přesunutí do samostatého balíčku, takže možná to bude chtít trpělivost :)
Editoval HosipLan (11. 4. 2012 13:10)
- Tracy
- Člen | 8
Ja bych to tak rad pouzival ale porad me to posila nekam :)
Mohl by mi nekdo jen poupravit body co potrebuju k alespon zakladnimu zprovozneni?
S nejnovejsim nette, mam pouzivat tu starsi verzi nebo tu novou uvnitr
kdyby?
Potrebuji pridavat nastaveni do config.neon nebo to v zakladu musi bezet
i bez toho?
Dekuju moc
- jspetrak
- Člen | 15
Řeším OAuth implementaci pro získání přístupu na Instragram účet. V třetím kroku se vyžaduje odeslání HTTP POST a v odpovědi má přijít JSON s tokenem + údaji o Instaúčtu.
Zkouším už nějakou chvíli třetí krok řešit použitím Kdyby/Curl z akce presenteru, nicméně neustále dostávám $response:
{"code": 400, "error_type": "OAuthException", "error_message": "You must provide a client_id"}
Všechny parametry ale do POSTu předávám.
$curl = new \Kdyby\Curl\CurlWrapper();
$curl->setUrl('https://api.instagram.com/oauth/access_token');
$curl->setMethod(\Kdyby\Curl\Request::POST);
$curl->setPost($post = array(
'cliend_id' => 'spravne ID',
'client_secret' => 'spravny secret',
'grant_type' => 'authorization_code',
'redirect_uri' => $this->getHttpRequest()->getUrl(),
'code' => $params['code']
));
$curl->execute();
$response = $curl->response;
Stejné výsledky dává
$request = new \Kdyby\Curl\Request('https://api.instagram.com/oauth/access_token');
$response = $request->post(array(
'cliend_id' => 'spravne ID',
'client_secret' => 'spravny secret',
'grant_type' => 'authorization_code',
'redirect_uri' => $this->getHttpRequest()->getUrl(),
'code' => $params['code']
));
Nápady, proč se ty parametry neodešlou?
Editoval jspetrak (30. 4. 2013 12:20)
- Honza Kuchař
- Člen | 1662
Ahojte! Objevil jsem memoryleak, máte nějaké nápady jak to fixnout? Když pouštím request jednou za 3 sekundy, za den mám 60 mb obsazeno, potom samozřejmě skončí skript chybout. issue je tu. Díky moc za rady!