Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [klasa]Curl - bardziej przyjaźnie ?
Forum PHP.pl > Inne > Oceny
Fifi209
Często zdarza mi się korzystać z Curl'a, jak wiadomo jest to średnio przyjemne dlatego postanowiłem na szybko opakować go na swój sposób, moim zdaniem pracuje się całkiem przyjemnie jednak pytanie czy takie podejście dobre?

Zamysł był taki, aby było prościej i szybciej, czy się udało?
[PHP] curl.php - pobierz, plaintext
  1. class curl_exception extends Exception {}
  2.  
  3. class curl {
  4.  
  5. private $handle;
  6. private $url='';
  7. private $path=''; // cookie path
  8. private $userAgent='';
  9.  
  10. public function __construct($url='') {
  11. if (!function_exists('curl_init')) {
  12. throw new curl_exception('Curl jest wyłączony');
  13. }
  14.  
  15. $this->handle = curl_init();
  16.  
  17. if (!empty($url)) {
  18. $this->setUrl($url);
  19. }
  20. }
  21.  
  22. public function setUrl($url) {
  23. $this->url = $url;
  24. $this->setOpt(CURLOPT_URL, $url);
  25. return $this;
  26. }
  27.  
  28. public function getUrl() {
  29. return $this->url;
  30. }
  31.  
  32. public function setCookiePath($path) {
  33. if (!opendir($path)) {
  34. throw new curl_exception('Brak dostępu do ścieżki');
  35. }
  36. $this->path = $path;
  37.  
  38. $this->setOpt(CURLOPT_COOKIEJAR, $path.'/cookie.txt')->setOpt(CURLOPT_COOKIEFILE, $path.'/cookie.txt');
  39.  
  40. return $this;
  41. }
  42.  
  43. public function getCookiePath() {
  44. return $this->path;
  45. }
  46.  
  47. public function setOpt($option, $value) {
  48. curl_setopt($this->handle, $option, $value);
  49. return $this;
  50. }
  51.  
  52. public function setPost($string) {
  53. $this->setOpt(CURLOPT_POST, true)->setOpt(CURLOPT_POSTFIELDS, $string);
  54. return $this;
  55. }
  56.  
  57. public function setUserAgent($agent) {
  58. $this->userAgent = $agent;
  59. $this->setOpt(CURLOPT_USERAGENT, $agent);
  60. return $this;
  61. }
  62.  
  63. public function getUserAgent() {
  64. return $this->userAgent;
  65. }
  66.  
  67. public function exec() {
  68. if (!empty($this->url)) {
  69. $exec = curl_exec($this->handle);
  70. if ($this->getErrno()) {
  71. throw new curl_exception($this->getError());
  72. }else{
  73. return $exec;
  74. }
  75. }else{
  76. throw new curl_exception('Url jest wymagany!');
  77. }
  78. }
  79.  
  80. private function getError() {
  81. return curl_error($this->handle);
  82. }
  83.  
  84. private function getErrno() {
  85. return curl_errno($this->handle);
  86. }
  87.  
  88. public function getHandle() {
  89. return $this->handle;
  90. }
  91.  
  92. }
  93.  
  94. class curl_multi {
  95.  
  96. private $handle;
  97. private $handles = array();
  98.  
  99. public function __construct() {
  100. if (!function_exists('curl_multi_init')) {
  101. throw new curl_exception('Curl jest wyłączony');
  102. }
  103. $this->handle = curl_multi_init();
  104. }
  105.  
  106. public function addHandle(curl $obj) {
  107. curl_multi_add_handle($this->handle, $obj->getHandle());
  108. $this->handles[] = $obj;
  109. return $this;
  110. }
  111.  
  112. public function clean() {
  113. foreach($this->handles as $obj) {
  114. curl_multi_remove_handle($this->handle, $obj->getHandle());
  115. }
  116. return $this;
  117. }
  118.  
  119. public function exec() {
  120. do {
  121. $status = curl_multi_exec($this->handle, $running);
  122. }while($running > 0);
  123.  
  124. return $this;
  125. }
  126.  
  127. public function getContent() {
  128. $content = array();
  129.  
  130. foreach ($this->handles as $obj) {
  131. $content[$obj->getUrl()] = curl_multi_getcontent($obj->getHandle());
  132. }
  133.  
  134. return $content;
  135. }
  136.  
  137.  
  138. }
[PHP] curl.php - pobierz, plaintext
Crozin
curl_post -> tablica + http_build_query
curl i curl_multi to na dobrą sprawę nakładka 1:1 na funkcję curl_*() nie ułatwiająca niczego, a jedynie ograniczająca.

Do tego "pierdoły" typu niepoprawne nazewnictwo czy złe użycie wyjątków.
Fifi209
Cytat(Crozin @ 24.08.2011, 00:51:50 ) *
curl_post -> tablica + http_build_query

A o tym nie wiedziałem tak szczerze.
Cytat(Crozin @ 24.08.2011, 00:51:50 ) *
curl i curl_multi to na dobrą sprawę nakładka 1:1 na funkcję curl_*() nie ułatwiająca niczego, a jedynie ograniczająca.

Gdzie ogranicza? smile.gif jest set uniwersalny i set'y do najczęściej używanych (przeze mnie) url, cookie, post
Cytat(Crozin @ 24.08.2011, 00:51:50 ) *
złe użycie wyjątków.

Hmm, jeżeli klasa nie może pracować z powodu braku uprawnień czy wyłączonego curl'a to uznałem że powinna wyrzucać wyjątek.
Crozin
Cytat
Gdzie ogranicza? jest set uniwersalny [...]
A racja, nie zauważyłem.
Cytat
Cytat
złe użycie wyjątków.
Hmm, jeżeli klasa nie może pracować z powodu braku uprawnień czy wyłączonego curl'a to uznałem że powinna wyrzucać wyjątek.
To może bardziej rozwinę:
- Zła klasa curl_exception. Zła bo klasa wyjątku ma symbolizować przyczynę jego wystąpienia nie miejsce jego wyrzucenia. W dodatku dziedziczysz po złej klasie (Exception). Powinieneś skorzystać z wyjątków z SPL-a. Nie ma ich zbyt wielu i nie pokrywają one wszystkich zastosowań, niemniej jednak zawsze powinieneś dziedziczyć po jak najbardziej wyspecjalizowanej klasie, czyli co najwyżej po LogicExcepton lub RuntimeException.
- Metody typu curl::exec() powinny same sprawdzić czy są odpowiednio skonfigurowane oraz czy nie wystąpił błąd po ich odpaleniu i w razie potrzeby wywalić wyjątek. Wyjątki mają być automatycznie wyrzucane, a metod typu getError() nie powinno nawet być.
Fifi209
Cytat(Crozin @ 24.08.2011, 01:14:13 ) *
To może bardziej rozwinę:
- Zła klasa curl_exception. Zła bo klasa wyjątku ma symbolizować przyczynę jego wystąpienia nie miejsce jego wyrzucenia. W dodatku dziedziczysz po złej klasie (Exception). Powinieneś skorzystać z wyjątków z SPL-a. Nie ma ich zbyt wielu i nie pokrywają one wszystkich zastosowań, niemniej jednak zawsze powinieneś dziedziczyć po jak najbardziej wyspecjalizowanej klasie, czyli co najwyżej po LogicExcepton lub RuntimeException.

Szczerze mówiąc nic to nie zmieni, prócz tego, że będę po czymś innym dziedziczył - chyba, że czegoś nie doczytałem.
Cytat(Crozin @ 24.08.2011, 01:14:13 ) *
- Metody typu curl::exec() powinny same sprawdzić czy są odpowiednio skonfigurowane

Fakt, można tutaj dodać sprawdzanie czy url został wprowadzony bo to jedyny wymóg.
Cytat(Crozin @ 24.08.2011, 01:14:13 ) *
oraz czy nie wystąpił błąd po ich odpaleniu i w razie potrzeby wywalić wyjątek. Wyjątki mają być automatycznie wyrzucane, a metod typu getError() nie powinno nawet być.

getError, getErrno mogę zmienić na prywatne, po odpaleniu exec odpalać je i sprawdzać ew. błędy i wyrzucić wyjątek - czy taki pomysł jest do zaakceptowania?

[offtopic]
Liczyłem właśnie na Twoją krytykę smile.gif
[/offtopic]

@edit
Wywaliłem curl_post, usunąłem private $post,
Metody: getErrno(), getError() zostały zmienione na prywatne
W setPost drobna zmiana kosmetyczna
Exec według Twoich uwag.

(edytuję pierwszego posta z kodem)



@edit2

Dodane metody:
getCookiePath()
setUserAgent()
getUserAgent()

Edytowane:
setCookiePath() - nie zmieniał ścieżki, teraz to robi.
l0ud
Popraw metodę exec w curl_multi - aktualna zajeżdża procesor.

Dołóż w środku curl_multi_select albo zrób dokładnie tak jak w manualu do curl_multi_exec
Fifi209
Masz na myśli ten skrawek kodu:
  1. while ($active && $mrc == CURLM_OK) {
  2. if (curl_multi_select($mh) != -1) {
  3. do {
  4. $mrc = curl_multi_exec($mh, $active);
  5. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  6. }
  7. }


?
l0ud
Chociażby. Chodzi o to, żeby wywoływać to curl_multi_select(), bo bez tego ta pętla będzie się wykonywać non-stop zajeżdżając procesor serwera.
melkorm
Cytat
Szczerze mówiąc nic to nie zmieni, prócz tego, że będę po czymś innym dziedziczył - chyba, że czegoś nie doczytałem.


Chodzi o poprawne informowanie użytkownika klasy co poszło nie tak, czy zawiódł kod / programista / serwer itp Bardzo łądnie opisane ma to na swoim blogu Zyx.
Rzucając curl_exception - wiem tyle co nic, ot klasa zawiodła, ale czemu? Ok - wiadomość ale to też mi nie daje możliwości zareagowania na odpowiednie błędy, załóżmy sytuację że dostaję curl_exception z Twojej klasy
aby zareagować na odpowiednie błędy muszę sprawdzać wartość message - a tak by wyglądał ocoś w stylu:
  1. try
  2. {
  3. //operacje curl
  4. }
  5. catch( Exception_Curl_Missing $e)
  6. {
  7. // ok nie ma curl próbujemy z fsockopen
  8. }
  9. catch( Exception_Curl_UrlInvalid $e) //dziedziczy po UnexpectedValueException
  10. {
  11. // ok nie porpaweny url tutaj w zależności czy wymuszamy walidację na osobie obsługującą klasę czy na samą klasę zmieniamy typ wyjątku po którym dziedziczymy
  12. // z UnexpectedValue_Exception na InvalidArgumentException
  13. }


Bo na razie bardziej te wyjątki służą Tobie jako walidator i provider dla komunikatów błędów niż po coś innego.

Ogólnie bardziej tą klasę widziałbym jako adapter, dla bardziej ogólnej klasy wtedy byś mógł z łatwością wymieniać interejfsy gdy np. nie ma curl używasz fsockopen itp.
Do tego ogólny interfejs by w ogóle użyteczność tej klasy miała jakikolwiek sens, bo na razie jest przydatna Tobie i tylko w momencie używania CURL'a, w momencie wystapienia wyjątku braku curl'a nie mam możliwość podmiany adapter'a i próby ponownego wywołania tylko tworzenie od nowa kolejnej klasy lub kompletne zignorowanie wyjątku co jest ogólnie pomyłką.

Ogólnie z chęcią zobaczę co inni powiedzą na temat mojego myślenia, ponieważ zazwyczaj hamuję się z wypowiadaniem na takie tematy ponieważ mam wrażenie że wciąż w tych klockach jestem za `cienki`, ale jak lepiej się uczyć niż na swoich błędach - chociaż brzmi to nawet logicznie :]
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.