4 * An Object Oriented interface to PHP's cURL extension
8 * Copyright (c) 2007, The PEAR Group
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
15 * - Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * - Neither the name of the The PEAR Group nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
38 * @author David Costa <gurugeek@php.net>
39 * @author Sterling Hughes <sterling@php.net>
40 * @author Joe Stump <joe@joestump.net>
41 * @author Philippe Jausions <jausions@php.net>
42 * @copyright 1997-2008 The PHP Group
43 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
44 * @version CVS: $Revision: 1.15 $
45 * @link http://pear.php.net/package/Net_Curl
49 * Include PEAR package for error handling
51 require_once 'PEAR.php';
54 * Object-oriented implementation of the Curl extension
58 * @author David Costa <gurugeek@php.net>
59 * @author Sterling Hughes <sterling@php.net>
60 * @author Joe Stump <joe@joestump.net>
61 * @author Philippe Jausions <jausions@php.net>
62 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
63 * @link http://pear.php.net/package/Net_Curl
67 // {{{ Public Properties
69 * The URL for cURL to work with
77 * The Username for standard HTTP Authentication
79 * @var string $username
85 * The Password for standard HTTP Authentication
87 * @var string $password
93 * The SSL version for the transfer
95 * @var integer $sslVersion
101 * The filename of the SSL certificate
103 * @var string $sslCert
109 * The password corresponding to the certificate
110 * in the $sslCert property
112 * @var string $sslCertPasswd
118 * User Agent string when making an HTTP request
120 * @var string $userAgent
126 * Whether or not to include the header in the results
127 * of the CURL transfer
129 * @var boolean $header
134 * Whether or not to output debug information while executing a
137 * @var boolean $verbose
140 var $verbose = false;
143 * Whether or not to display a progress meter for the current transfer
145 * @var boolean $progress
148 var $progress = false;
151 * Whether or not to suppress error messages
159 * Whether or not to follow HTTP Location headers.
161 * @var boolean $followLocation
164 var $followLocation = true;
167 * Whether or not to follow HTTP Location headers.
169 * @var boolean $follow_location
173 var $follow_location = false;
176 * Time allowed for current transfer, in seconds. 0 means no limit
184 * Whether or not to return the results of the
187 * @var boolean $returnTransfer
190 var $returnTransfer = true;
193 * Whether or not to return the results of the
196 * @var boolean $return_transfer
200 var $return_transfer = false;
203 * The type of transfer to perform (ie. 'POST', 'GET', 'PUT', etc)
211 * The file to upload (PUT, or FTP methods)
219 * The file size of the file pointed to by the $file
222 * @var integer $fileSize
228 * The file size of the file pointed to by the $file
231 * @var integer $file_size
235 var $file_size = false;
239 * The cookies to send to the remote site
241 * @var array $cookies
244 var $cookies = array();
247 * Additional HTTP headers to send to the remote site
249 * @var array $httpHeaders
252 var $httpHeaders = null;
255 * Additional HTTP headers to send to the remote site
257 * @var array $http_headers
261 var $http_headers = false;
264 * The fields to send in a 'POST' request
272 * The proxy server to go through
280 * The username for the Proxy server
282 * @var string $proxyUser
288 * The password for the Proxy server
290 * @var string $proxyPassword
298 * FALSE to stop CURL from verifying the peer's certificate.
299 * Alternate certificates to verify against can be specified
300 * with the CURLOPT_CAINFO option or a certificate directory
301 * can be specified with the CURLOPT_CAPATH option.
302 * CURLOPT_SSL_VERIFYHOST may also need to be TRUE or FALSE
303 * if CURLOPT_SSL_VERIFYPEER is disabled (it defaults to 2).
305 * @var boolean $verifyPeer
308 var $verifyPeer = true;
313 * 0 : to stop CURL from verifying the host's certificate.
314 * 1 : to check the existence of a common name in the SSL peer certificate.
315 * 2 : to check the existence of a common name and also verify that it
316 * matches the hostname provided.
318 * @var bool $verifyHost
326 * Set value for CURLOPT_CAINFO. The name of a file holding one or more
327 * certificates to verify the peer with. This only makes sense when used
328 * in combination with CURLOPT_SSL_VERIFYPEER. curl-ca-bundle.crt is
329 * avaible on the Curl website http://curl.haxx.se/ for download inside
332 * @var string $caInfo
340 * Set value for CURLOPT_CAPATH. A directory that holds multiple CA
341 * certificates. Use this option alongside CURLOPT_SSL_VERIFYPEER.
343 * @var string $caPath
348 // {{{ Private Properties
350 * The current curl handle
354 * @see Net_Curl::create()
359 * The file upload resource
361 * The CURLOPT_INFILE requires a file resource and not just a file name.
362 * This is used by execute to open the file.
366 * @see Net_Curl::execute()
371 // {{{ __construct($url = '', $userAgent = '')
373 * The Net_Curl PHP 5.x constructor, called when a new Net_Curl object
374 * is initialized (also called via 4.x constructor)
376 * @param string $url The URL to fetch (can be set using the $url
378 * @param string $userAgent The userAgent string (can be set using the
379 * $userAgent property as well)
382 * @author Joe Stump <joe@joestump.net>
385 function __construct($url = '', $userAgent = '')
387 if (is_string($url) && strlen($url)) {
391 if (is_string($userAgent) && strlen($userAgent)) {
392 $this->userAgent
= $userAgent;
397 // {{{ Net_Curl($url = '', $userAgent = '')
401 * PHP 4.x constructor.
403 * @param string $url The URL to fetch (can be set using the $url
405 * @param string $userAgent The userAgent string (can be set using the
406 * $userAgent property as well)
411 function Net_Curl($url = '', $userAgent = '')
413 $this->__construct($url, $userAgent);
419 * Executes a prepared CURL transfer
421 * Run this function to execute your cURL request. If all goes well you
422 * should get a string (the output from the remote host regarding your
423 * request) or true (if you choose to output directly to the browser). If
424 * something fails then PEAR_Error is returned.
428 * require_once 'Net/Curl.php';
430 * $curl = new Net_Curl('http://www.example.com');
431 * $curl->fields = array('foo' => '1', 'bar' => 'apple');
432 * $result = $curl->execute();
433 * if (!PEAR::isError($result)) {
440 * @author Sterling Hughes <sterling@php.net>
441 * @author Joe Stump <joe@joestump.net>
442 * @return PEAR_Error on failure, true/result on success
447 // Create cURL handle if it hasn't already been created
448 if (!is_resource($this->_ch
)) {
449 $result = $this->create();
450 if (PEAR
::isError($result)) {
455 // Map the deprecated variables and throw a bunch of errors
456 $this->_mapDeprecatedVariables();
458 // Default return value is true.
462 $ret = curl_setopt($this->_ch
, CURLOPT_URL
, $this->url
);
463 $ret = curl_setopt($this->_ch
, CURLOPT_HEADER
, $this->header
);
465 // Whether or not to return the transfer contents
466 if ($this->returnTransfer
=== true ||
$this->mute
=== true) {
467 $ret = curl_setopt($this->_ch
, CURLOPT_RETURNTRANSFER
, true);
470 // HTTP Authentication
471 if ($this->username
!= '') {
472 $ret = curl_setopt($this->_ch
,
474 $this->username
. ':' . $this->password
);
478 if (isset($this->sslVersion
)) {
479 $ret = curl_setopt($this->_ch
,
484 if (isset($this->sslCert
)) {
485 $ret = curl_setopt($this->_ch
, CURLOPT_SSLCERT
, $this->sslCert
);
488 if (isset($this->sslCertPasswd
)) {
489 $ret = curl_setopt($this->_ch
,
490 CURLOPT_SSLCERTPASSWD
,
491 $this->sslCertPasswd
);
494 // Proxy Related checks
495 if (isset($this->proxy
)) {
496 $ret = curl_setopt($this->_ch
, CURLOPT_PROXY
, $this->proxy
);
499 if (isset($this->proxyUser
) ||
isset($this->proxyPassword
)) {
500 $ret = curl_setopt($this->_ch
,
501 CURLOPT_PROXYUSERPWD
,
502 $this->proxyUser
. ':' . $this->proxyPassword
);
505 if (is_bool($this->verifyPeer
)) {
506 if (!$this->setOption(CURLOPT_SSL_VERIFYPEER
, $this->verifyPeer
)) {
507 return PEAR
::raiseError('Error setting CURLOPT_SSL_VERIFYPEER');
511 if (is_numeric($this->verifyHost
) && $this->verifyHost
>= 0 &&
512 $this->verifyHost
<= 2) {
513 if (!$this->setOption(CURLOPT_SSL_VERIFYHOST
, $this->verifyHost
)) {
514 return PEAR
::raiseError('Error setting CURLOPT_SSL_VERIFYPEER');
518 if (is_bool($this->verifyPeer
) && $this->verifyPeer
== true) {
519 if (isset($this->caInfo
) && strlen($this->caInfo
)) {
520 if (file_exists($this->caInfo
)) {
521 if (!$this->setOption(CURLOPT_CAINFO
, $this->caInfo
)) {
522 return PEAR
::raiseError('Error setting CURLOPT_CAINFO');
525 return PEAR
::raiseError('Could not find CA info: '.
530 if (isset($this->caPath
) && is_string($this->caPath
)) {
531 if (!$this->setOption(CURLOPT_CAPATH
, $this->caPath
)) {
532 return PEAR
::raiseError('Error setting CURLOPT_CAPATH');
538 if (isset($this->type
)) {
539 switch (strtolower($this->type
)) {
541 $ret = curl_setopt($this->_ch
, CURLOPT_POST
, true);
544 $ret = curl_setopt($this->_ch
, CURLOPT_PUT
, true);
549 // Transfer upload, etc. related
550 if (isset($this->file
)) {
551 if (!file_exists($this->file
)) {
552 return PEAR
::raiseError('File does not exist: '.$this->file
);
555 $this->_fp
= fopen($this->file
, 'r');
556 if (!is_resource($this->_fp
)) {
557 return PEAR
::raiseError('Could not open file: '.$this->file
);
560 if (!isset($this->fileSize
)) {
561 $this->fileSize
= filesize($this->file
);
564 $ret = curl_setopt($this->_ch
, CURLOPT_INFILE
, $this->_fp
);
565 $ret = curl_setopt($this->_ch
, CURLOPT_INFILESIZE
, $this->fileSize
);
566 $ret = curl_setopt($this->_ch
, CURLOPT_UPLOAD
, true);
569 if (isset($this->fields
)) {
571 if (!isset($this->type
)) {
572 $this->type
= 'post';
573 $ret = curl_setopt($this->_ch
, CURLOPT_POST
, true);
576 // If fields is an array then turn it into a string. Sometimes
577 // cURL doesn't like fields as an array.
578 // Exception: if a value is prefixed with "@" and the rest of the
579 // value resolves to an existing file, then pass
580 // the values as the original array.
581 if (is_array($this->fields
)) {
583 foreach ($this->fields
as $key => $val) {
584 if (strlen($val) > 1 && $val{0} == '@') {
585 $file = substr($val, 1);
586 if (is_file($file) && is_readable($file)) {
591 $sets[] = urlencode($key) . '=' . urlencode($val);
595 if (!is_null($sets)) {
596 $fields = implode('&', $sets);
598 $fields = $this->fields
;
600 $ret = curl_setopt($this->_ch
, CURLOPT_POSTFIELDS
, $fields);
604 if ($this->progress
=== true) {
605 $ret = curl_setopt($this->_ch
, CURLOPT_PROGRESS
, true);
608 if ($this->verbose
=== true) {
609 $ret = curl_setopt($this->_ch
, CURLOPT_VERBOSE
, true);
612 // If a Location: header is passed then follow it
613 $ret = curl_setopt($this->_ch
,
614 CURLOPT_FOLLOWLOCATION
,
615 $this->followLocation
);
617 // If a timeout is set and is greater then zero then set it
618 if (is_numeric($this->timeout
) && $this->timeout
> 0) {
619 $ret = curl_setopt($this->_ch
, CURLOPT_TIMEOUT
, $this->timeout
);
622 if (isset($this->userAgent
)) {
623 $ret = curl_setopt($this->_ch
, CURLOPT_USERAGENT
, $this->userAgent
);
627 if (is_array($this->cookies
) && count($this->cookies
)) {
629 foreach ($this->cookies
as $name => $value) {
630 $cookieData .= $name . '=' . $value . ';';
633 $ret = curl_setopt($this->_ch
, CURLOPT_COOKIE
, $cookieData);
636 // Other HTTP headers
637 if ($this->httpHeaders
!== null) {
638 if (is_array($this->httpHeaders
)) {
639 $ret = curl_setopt($this->_ch
,
643 return PEAR
::raiseError('Net_Curl::$httpHeaders must be an array');
647 $ret = curl_exec($this->_ch
);
649 // Close the file before we return anything
650 if (is_resource($this->_fp
)) {
654 if (curl_errno($this->_ch
)) {
655 return PEAR
::raiseError(curl_error($this->_ch
), curl_errno($this->_ch
));
658 // Check to make sure we get a 2XX/3XX code and not a 404 or something.
659 $info = $this->getInfo();
660 if (!isset($info['http_code'])) {
661 return PEAR
::raiseError('Unknown or invalid HTTP response');
663 $type = substr($info['http_code'], 0, 1);
664 if ($type != 2 && $type != 3) {
665 return PEAR
::raiseError('Unexpected HTTP code: ' .
674 // {{{ setOption($option, $value)
676 * Sets an option for your cURL session. Please note that the cURL handler
677 * is NOT created before execute(). This is for error checking purposes.
678 * You should use setOption() in the following manner:
683 * require_once 'Net/Curl.php';
684 * $curl = new Net_Curl('http://www.example.com');
685 * $check = $curl->create();
686 * if (!PEAR::isError($check)) {
687 * $curl->setOption(CURLOPT_FOO, 'bar');
688 * $result = $curl->execute();
689 * if (!PEAR::isError($result)) {
697 * @param int $option cURL constant (ie. CURLOPT_URL)
698 * @param mixed $value The option's value
700 * @author Joe Stump <joe@joestump.net>
704 function setOption($option, $value)
706 if (is_resource($this->_ch
)) {
707 return curl_setopt($this->_ch
, $option, $value);
716 * Returns the info from the cURL session. PEAR_Error if you try and run
717 * this before you execute the session.
719 * @author Joe Stump <joe@joestump.net>
721 * @return mixed PEAR_Error if there is no resource, info on success
725 if (is_resource($this->_ch
)) {
726 return curl_getinfo($this->_ch
);
729 return PEAR
::isError('cURL handler does not exist!');
735 * Creates a cURL resource. If curl_init() doesn't exist or we could not
736 * create a resource it will error out.
738 * @author Joe Stump <joe@joestump.net>
739 * @return boolean TRUE on success, PEAR_Error on failure
743 if (!PEAR
::loadExtension('curl')) {
744 return PEAR
::raiseError('CURL extension is not available');
746 if (!function_exists('curl_init')) {
747 return PEAR
::raiseError('Function curl_init() not found');
750 $this->_ch
= curl_init();
751 if (!is_resource($this->_ch
)) {
752 return PEAR
::raiseError('Could not initialize cURL handler');
761 * Sets verbose output
763 * Turns on super debugging mode by not suppressing errors, turning on
764 * verbose mode, showing headers and displaying progress.
767 * @author David Costa <gurugeek@php.net>
770 function verboseAll()
772 $this->verbose
= true;
774 $this->header
= true;
775 $this->progress
= true;
781 * Sets verbose output
784 * @author David Costa <gurugeek@php.net>
788 function verbose_all()
791 PEAR
::raiseError('Net_Curl::verbose_all() is deprecated! Please use Net_Curl::verboseAll()'." <br />\n", null, PEAR_ERROR_PRINT
);
797 * Closes the curl transfer and finishes the object (kinda ;)
800 * @author Sterling Hughes <sterling@php.net>
806 if (is_resource($this->_ch
)) {
807 curl_close($this->_ch
);
812 // {{{ _mapDeprecatedVariables()
814 * Maps deprecated variables into the appropriate places. It also throws
815 * the necessary notices.
817 * @author Joe Stump <joe@joestump.net>
821 function _mapDeprecatedVariables()
824 if ($this->follow_location
!== false) {
825 if ($this->follow_location
> 0) {
826 $this->followLocation
= true;
828 $this->followLocation
= false;
831 $bad[] = array('follow_location', 'followLocation');
834 if ($this->return_transfer
!== false) {
835 if ($this->return_transfer
> 0) {
836 $this->returnTransfer
= true;
838 $this->returnTransfer
= false;
841 $bad[] = array('return_transfer', 'returnTransfer');
844 if ($this->file_size
!== false) {
845 $this->fileSize
= $this->file_size
;
846 $bad[] = array('file_size', 'fileSize');
849 if ($this->http_headers
!== false) {
850 $this->httpHeaders
= $this->http_headers
;
851 $bad[] = array('http_headers', 'httpHeaders');
854 foreach ($bad as $map) {
855 PEAR
::raiseError('Net_Curl::$'. $map[0]. ' is deprecated! Please use Net_Curl::$'.$map[1]." instead! <br />\n", null, PEAR_ERROR_PRINT
);
862 * PHP 5.x destructor.
864 * Runs Net_Curl::close() to make sure we close our cURL connection.
866 * @author Joe Stump <joe@joestump.net>
867 * @see Net_Curl::close()
869 function __destruct()