3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
13 * This class handles HTTP downloads
15 * FIXME: fetch() and get() report errors differently -- e.g.
16 * fetch() returns fatal and get() returns an error code. Should
17 * refactor both (or get a third-party HTTP library) but don't
18 * want to deal with that so late in the 4.3 dev cycle.
21 * @copyright CiviCRM LLC https://civicrm.org/licensing
23 class CRM_Utils_HttpClient
{
25 const STATUS_OK
= 'ok';
26 const STATUS_WRITE_ERROR
= 'write-error';
27 const STATUS_DL_ERROR
= 'dl-error';
30 * @var CRM_Utils_HttpClient
32 protected static $singleton;
36 * seconds; or NULL to use system default
38 protected $connectionTimeout;
41 * @return CRM_Utils_HttpClient
43 public static function singleton() {
44 if (!self
::$singleton) {
45 self
::$singleton = new CRM_Utils_HttpClient();
47 return self
::$singleton;
51 * @param null $connectionTimeout
53 public function __construct($connectionTimeout = NULL) {
54 $this->connectionTimeout
= $connectionTimeout;
58 * Download the remote zipfile.
60 * @param string $remoteFile
62 * @param string $localFile
63 * Path at which to store the .zip file.
64 * @return STATUS_OK|STATUS_WRITE_ERROR|STATUS_DL_ERROR
66 * @throws CRM_Core_Exception
68 public function fetch($remoteFile, $localFile) {
69 // Download extension zip file ...
70 if (!function_exists('curl_init')) {
71 throw new CRM_Core_Exception('Cannot install this extension - curl is not installed!');
74 list($ch, $caConfig) = $this->createCurl($remoteFile);
75 if (preg_match('/^https:/', $remoteFile) && !$caConfig->isEnableSSL()) {
76 throw new CRM_Core_Exception('Cannot install this extension - does not support SSL');
79 $fp = @fopen
($localFile, "w");
81 return self
::STATUS_WRITE_ERROR
;
83 curl_setopt($ch, CURLOPT_FILE
, $fp);
86 if (curl_errno($ch)) {
87 return self
::STATUS_DL_ERROR
;
95 return self
::STATUS_OK
;
99 * Send an HTTP GET for a remote resource.
101 * @param string $remoteFile
102 * URL of remote file.
104 * array(0 => STATUS_OK|STATUS_DL_ERROR, 1 => string)
106 public function get($remoteFile) {
107 // Download extension zip file ...
108 if (!function_exists('curl_init')) {
110 CRM_Core_Session
::setStatus(
111 ts('As a result, actions like retrieving the CiviCRM news feed will fail. Talk to your server administrator or hosting company to rectify this.'),
112 ts('Curl is not installed')
114 return [self
::STATUS_DL_ERROR
, NULL];
117 list($ch, $caConfig) = $this->createCurl($remoteFile);
119 if (preg_match('/^https:/', $remoteFile) && !$caConfig->isEnableSSL()) {
120 return [self
::STATUS_DL_ERROR
, NULL];
123 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, 1);
124 $data = curl_exec($ch);
125 if (curl_errno($ch)) {
126 return [self
::STATUS_DL_ERROR
, $data];
132 return [self
::STATUS_OK
, $data];
136 * Send an HTTP POST for a remote resource.
138 * @param string $remoteFile
139 * URL of a .zip file.
140 * @param array $params
143 * array(0 => STATUS_OK|STATUS_DL_ERROR, 1 => string)
145 public function post($remoteFile, $params) {
146 // Download extension zip file ...
147 if (!function_exists('curl_init')) {
148 return [self
::STATUS_DL_ERROR
, NULL];
151 list($ch, $caConfig) = $this->createCurl($remoteFile);
153 if (preg_match('/^https:/', $remoteFile) && !$caConfig->isEnableSSL()) {
154 return [self
::STATUS_DL_ERROR
, NULL];
157 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, 1);
158 curl_setopt($ch, CURLOPT_POST
, TRUE);
159 curl_setopt($ch, CURLOPT_POST
, count($params));
160 curl_setopt($ch, CURLOPT_POSTFIELDS
, $params);
161 $data = curl_exec($ch);
162 if (curl_errno($ch)) {
163 return [self
::STATUS_DL_ERROR
, $data];
169 return [self
::STATUS_OK
, $data];
173 * @param string $remoteFile
175 * (0 => resource, 1 => CA_Config_Curl)
177 protected function createCurl($remoteFile) {
178 $caConfig = CA_Config_Curl
::probe([
179 'verify_peer' => (bool) Civi
::settings()->get('verifySSL'),
183 curl_setopt($ch, CURLOPT_URL
, $remoteFile);
184 curl_setopt($ch, CURLOPT_HEADER
, FALSE);
185 curl_setopt($ch, CURLOPT_ENCODING
, 'gzip');
186 curl_setopt($ch, CURLOPT_VERBOSE
, 0);
187 if ($this->isRedirectSupported()) {
188 curl_setopt($ch, CURLOPT_FOLLOWLOCATION
, TRUE);
190 if ($this->connectionTimeout
!== NULL) {
191 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT
, $this->connectionTimeout
);
193 if (preg_match('/^https:/', $remoteFile) && $caConfig->isEnableSSL()) {
194 curl_setopt_array($ch, $caConfig->toCurlOptions());
197 return [$ch, $caConfig];
203 public function isRedirectSupported() {
204 return (ini_get('open_basedir') == '') && (ini_get('safe_mode') == 'Off' ||
ini_get('safe_mode') == '' ||
ini_get('safe_mode') === FALSE);