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