1 <?php
2
3 namespace Alo;
4
5 use Alo\Exception\ExtensionException as EE;
6 use Log;
7
8 if (!defined('GEN_START')) {
9 http_response_code(404);
10 } else {
11
12 /**
13 * Object-oriented Curl wrapper
14 *
15 * @author Art <a.molcanovas@gmail.com>
16 */
17 class Curl {
18
19 /**
20 * Static reference to the last instance of the class
21 *
22 * @var Curl
23 */
24 static $this;
25
26 /**
27 * The Curl resource
28 *
29 * @var resource
30 */
31 protected $ch;
32
33 /**
34 * Result of exec()
35 *
36 * @var mixed
37 * @see self::exec()
38 */
39 protected $exec;
40
41 /**
42 * Error number of exec()
43 *
44 * @var int
45 * @see self::exec()
46 */
47 protected $errno;
48
49 /**
50 * Error message of exec()
51 *
52 * @var string
53 * @see self::exec()
54 */
55 protected $error;
56
57 /**
58 * Whether the connection is open
59 *
60 * @var boolean
61 */
62 protected $isOpen;
63
64 /**
65 * Instantiates the library
66 *
67 * @author Art <a.molcanovas@gmail.com>
68 *
69 * @param string $url Optionally, the URL for curl_init()
70 *
71 * @throws EE When the curl extention is not loaded
72 */
73 function __construct($url = null) {
74 if (!function_exists('curl_init')) {
75 throw new EE('Curl PHP extension not loaded', EE::E_EXT_NOT_LOADED);
76 } else {
77 $this->ch = curl_init();
78 $this->isOpen = true;
79 curl_setopt_array($this->ch, [CURLOPT_RETURNTRANSFER => true,
80 CURLOPT_SSLVERSION => 3,
81 CURLOPT_SSL_VERIFYPEER => true,
82 CURLOPT_FOLLOWLOCATION => true]);
83
84 Log::debug('Initialised Curl');
85
86 if ($url) {
87 $this->setURL($url);
88 }
89 }
90
91 self::$this = &$this;
92 }
93
94 /**
95 * Sets the connection URL
96 *
97 * @author Art <a.molcanovas@gmail.com>
98 *
99 * @param string $url The URL
100 *
101 * @return Curl
102 */
103 function setURL($url) {
104 Log::debug('Set Curl URL to ' . $url);
105 curl_setopt($this->ch, CURLOPT_URL, $url);
106
107 return $this;
108 }
109
110 /**
111 * Instantiates the library
112 *
113 * @author Art <a.molcanovas@gmail.com>
114 *
115 * @param string $url Optionally, the URL for curl_init()
116 *
117 * @throws EE When the curl extention is not loaded
118 *
119 * @return Curl
120 */
121 static function cURL($url = null) {
122 return new Curl($url);
123 }
124
125 /**
126 * A static wrapper function for __construct()
127 *
128 * @author Art <a.molcanovas@gmail.com>
129 *
130 * @param string $url Optionally, the URL for curl_init()
131 *
132 * @return Curl
133 */
134 static function init($url = null) {
135 return new Curl($url);
136 }
137
138 /**
139 * Sets CURLOPT_NOPROGRESS to FALSE and supplies the progress function
140 *
141 * @author Art <a.molcanovas@gmail.com>
142 *
143 * @param callable $callable The function
144 *
145 * @return bool
146 */
147 function setProgressFunction($callable) {
148 if (!is_callable($callable)) {
149 return false;
150 } else {
151 curl_setopt_array($this->ch, [CURLOPT_NOPROGRESS => false,
152 CURLOPT_PROGRESSFUNCTION => $callable]);
153
154 return true;
155 }
156 }
157
158 /**
159 * Set whether Curl should time out
160 *
161 * @author Art <a.molcanovas@gmail.com>
162 *
163 * @param boolean $enabled The switch
164 *
165 * @return Curl
166 */
167 function notimeout($enabled = true) {
168 $a = $enabled ? [CURLOPT_CONNECTTIMEOUT => 86400,
169 CURLOPT_TIMEOUT => 86400] : [CURLOPT_CONNECTTIMEOUT => 1,
170 CURLOPT_TIMEOUT => 1];
171
172 Log::debug('Curl timeout ' . ($enabled ? 'en' : 'dis') . 'abled');
173
174 return $this->setoptArray($a);
175 }
176
177 /**
178 * Sets an array of options
179 *
180 * @author Art <a.molcanovas@gmail.com>
181 *
182 * @param array $a An array specifying which options to set and their values. The keys should be valid
183 * curl_setopt() constants or their integer equivalents.
184 *
185 * @return Curl
186 * @link http://php.net/manual/en/function.curl-setopt-array.php
187 */
188 function setoptArray(array $a) {
189 curl_setopt_array($this->ch, $a);
190
191 return $this;
192 }
193
194 /**
195 * Toggles lax SSL verification mode which doesn't check certificates
196 *
197 * @author Art <a.molcanovas@gmail.com>
198 *
199 * @param boolean $enabled Whether the mode is enabled or disabled
200 *
201 * @return Curl
202 */
203 function laxSSLMode($enabled = true) {
204 Log::debug(($enabled ? 'Dis' : 'En') . 'abled CURLOPT_SSL_VERIFYPEER');
205 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, !$enabled);
206
207 return $this;
208 }
209
210 /**
211 * Returns a string representation of the object data
212 *
213 * @author Art <a.molcanovas@gmail.com>
214 * @return string
215 */
216 function __toString() {
217 return \debugLite($this);
218 }
219
220 /**
221 * URL encodes the given string
222 *
223 * @author Art <a.molcanovas@gmail.com>
224 *
225 * @param string $str The string
226 *
227 * @return string The escaped string
228 * @link http://php.net/manual/en/function.curl-escape.php
229 */
230 function escape($str) {
231 return curl_escape($this->ch, $str);
232 }
233
234 /**
235 * Pause and unpause a connection
236 *
237 * @author Art <a.molcanovas@gmail.com>
238 *
239 * @param int $bitmask One of CURLPAUSE_* constants.
240 *
241 * @return int An error code (CURLE_OK for no error).
242 * @link http://php.net/manual/en/function.curl-pause.php
243 */
244 function pause($bitmask) {
245 Log::debug('Changed the Curl pause state');
246
247 return curl_pause($this->ch, $bitmask);
248 }
249
250 /**
251 * Gets Curl version information
252 *
253 * @author Art <a.molcanovas@gmail.com>
254 *
255 * @param int $age
256 *
257 * @return array
258 * @link http://php.net/manual/en/function.curl-version.php
259 */
260 function version($age = CURLVERSION_NOW) {
261 return curl_version($age);
262 }
263
264 /**
265 * Checks whether the last transfer was successful
266 *
267 * @author Art <a.molcanovas@gmail.com>
268 * @return boolean|int If successful - true, if not & Curl error code exists
269 * - Curl error code, false otherwise
270 */
271 function wasSuccessful() {
272 if ($this->errno !== CURLE_OK) {
273 return 'Curl error #' . $this->errno;
274 } else {
275 $code = $this->getinfo(CURLINFO_HTTP_CODE);
276 if (!in_array(substr('' . $this->getinfo(CURLINFO_HTTP_CODE), 0, 1), [1, 2, 3])) {
277 return 'HTML response ' . $code;
278 } else {
279 return true;
280 }
281 }
282 }
283
284 /**
285 * Get information regarding a specific transfer
286 *
287 * @author Art <a.molcanovas@gmail.com>
288 *
289 * @param int $opt One of the Curl constants
290 *
291 * @return mixed
292 * @link http://php.net/manual/en/function.curl-getinfo.php
293 */
294 function getinfo($opt = 0) {
295 return curl_getinfo($this->ch, $opt);
296 }
297
298 /**
299 * Reset all options of a libcurl session handle
300 *
301 * @author Art <a.molcanovas@gmail.com>
302 * @return Curl
303 * @link http://php.net/manual/en/function.curl-reset.php
304 */
305 function reset() {
306 Log::debug('Reset Curl');
307 curl_reset($this->ch);
308 curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
309
310 return $this;
311 }
312
313 /**
314 * Decodes the given URL encoded string
315 *
316 * @author Art <a.molcanovas@gmail.com>
317 *
318 * @param string $str
319 *
320 * @return string The decoded string
321 * @link http://php.net/manual/en/function.curl-unescape.php
322 */
323 function unescape($str) {
324 return curl_unescape($this->ch, $str);
325 }
326
327 /**
328 * Auto-cleanup
329 *
330 * @author Art <a.molcanovas@gmail.com>
331 */
332 function __destruct() {
333 $this->close();
334 }
335
336 /**
337 * Closes a Curl connection
338 *
339 * @author Art <a.molcanovas@gmail.com>
340 * @return Curl
341 * @link http://php.net/manual/en/function.curl-close.php
342 */
343 function close() {
344 if ($this->isOpen) {
345 curl_close($this->ch);
346 $this->isOpen = false;
347 Log::debug('Closed Curl connection');
348 }
349
350 return $this;
351 }
352
353 /**
354 * Gets the results of a Curl exec. If $url is set, will exec on that URL
355 *
356 * @author Art <a.molcanovas@gmail.com>
357 *
358 * @param string $url Optional URL override
359 *
360 * @return mixed The results of exec()
361 */
362 function get($url = null) {
363 if ($url !== null) {
364 $this->setURL($url)->exec();
365 }
366
367 return $this->exec;
368 }
369
370 /**
371 * Executes the Curl connection parameters
372 *
373 * @author Art <a.molcanovas@gmail.com>
374 * @return Curl
375 * @link http://php.net/manual/en/function.curl-exec.php
376 */
377 function exec() {
378 Log::debug('Started Curl exec');
379 $this->exec = curl_exec($this->ch);
380 $this->errno = curl_errno($this->ch);
381 $this->error = curl_error($this->ch);
382 Log::debug('Finished curl exec');
383
384 return $this;
385 }
386
387 /**
388 * Returns the error message of the last exec()
389 *
390 * @author Art <a.molcanovas@gmail.com>
391 * @return string
392 * @see self::exec()
393 * @link http://php.net/manual/en/function.curl-error.php
394 */
395 function error() {
396 return $this->error;
397 }
398
399 /**
400 * Returns the error number of the last exec() or 0 if no error occurred
401 *
402 * @author Art <a.molcanovas@gmail.com>
403 * @return int
404 * @see self::exec()
405 * @link http://php.net/manual/en/function.curl-errno.php
406 */
407 function errno() {
408 return $this->errno;
409 }
410
411 /**
412 * Wrapper for setopt()
413 *
414 * @author Art <a.molcanovas@gmail.com>
415 *
416 * @param string $name Param name
417 * @param mixed $value Param value
418 */
419 function __set($name, $value) {
420 $this->setopt($name, $value);
421 }
422
423 /**
424 * Sets an option
425 *
426 * @author Art <a.molcanovas@gmail.com>
427 *
428 * @param int $name The option - see Curl constants
429 * @param mixed $value The option value
430 *
431 * @return Curl
432 * @link http://php.net/manual/en/function.curl-setopt.php
433 */
434 function setopt($name, $value) {
435 if ($name === CURLOPT_POSTFIELDS) {
436 curl_setopt($this->ch, CURLOPT_POST, true);
437 }
438
439 curl_setopt($this->ch, $name, $value);
440
441 return $this;
442 }
443
444 }
445 }
446