CRM/Utils add comments
[civicrm-core.git] / CRM / Utils / HttpClient.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06b69b18 4 | CiviCRM version 4.5 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
e647e388
TO
29 * This class handles HTTP downloads
30 *
31 * FIXME: fetch() and get() report errors differently -- e.g.
32 * fetch() returns fatal and get() returns an error code. Should
33 * refactor both (or get a third-party HTTP library) but don't
34 * want to deal with that so late in the 4.3 dev cycle.
6a488035
TO
35 *
36 * @package CRM
06b69b18 37 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
38 * $Id$
39 *
40 */
41class CRM_Utils_HttpClient {
42
43 const STATUS_OK = 'ok';
44 const STATUS_WRITE_ERROR = 'write-error';
45 const STATUS_DL_ERROR = 'dl-error';
46
3b6f287b
TO
47 /**
48 * @var CRM_Utils_HttpClient
49 */
50 protected static $singleton;
51
afcc9be0 52 /**
021cfda1 53 * @var int|NULL seconds; or NULL to use system default
afcc9be0 54 */
021cfda1 55 protected $connectionTimeout;
afcc9be0 56
5bc392e6
EM
57 /**
58 * @return CRM_Utils_HttpClient
59 */
3b6f287b
TO
60 public static function singleton() {
61 if (!self::$singleton) {
62 self::$singleton = new CRM_Utils_HttpClient();
63 }
64 return self::$singleton;
65 }
66
5bc392e6
EM
67 /**
68 * @param null $connectionTimeout
69 */
021cfda1
TO
70 public function __construct($connectionTimeout = NULL) {
71 $this->connectionTimeout = $connectionTimeout;
afcc9be0
TO
72 }
73
6a488035
TO
74 /**
75 * Download the remote zipfile.
76 *
77 * @param string $remoteFile URL of a .zip file
78 * @param string $localFile path at which to store the .zip file
79 * @return STATUS_OK|STATUS_WRITE_ERROR|STATUS_DL_ERROR
80 */
3b6f287b 81 public function fetch($remoteFile, $localFile) {
6a488035
TO
82 // Download extension zip file ...
83 if (!function_exists('curl_init')) {
84 CRM_Core_Error::fatal('Cannot install this extension - curl is not installed!');
85 }
e647e388
TO
86
87 list($ch, $caConfig) = $this->createCurl($remoteFile);
6a488035
TO
88 if (preg_match('/^https:/', $remoteFile) && !$caConfig->isEnableSSL()) {
89 CRM_Core_Error::fatal('Cannot install this extension - does not support SSL');
90 }
91
6a488035
TO
92 $fp = @fopen($localFile, "w");
93 if (!$fp) {
94 CRM_Core_Session::setStatus(ts('Unable to write to %1.<br />Is the location writable?', array(1 => $localFile)), ts('Write Error'), 'error');
95 return self::STATUS_WRITE_ERROR;
96 }
97 curl_setopt($ch, CURLOPT_FILE, $fp);
98
99 curl_exec($ch);
100 if (curl_errno($ch)) {
101 CRM_Core_Session::setStatus(ts('Unable to download extension from %1. Error Message: %2',
102 array(1 => $remoteFile, 2 => curl_error($ch))), ts('Download Error'), 'error');
103 return self::STATUS_DL_ERROR;
104 }
105 else {
106 curl_close($ch);
107 }
108
109 fclose($fp);
110
111 return self::STATUS_OK;
112 }
afcc9be0
TO
113
114 /**
115 * Send an HTTP GET for a remote resource
116 *
dadcd1ac 117 * @param string $remoteFile URL of remote file
afcc9be0
TO
118 * @return array array(0 => STATUS_OK|STATUS_DL_ERROR, 1 => string)
119 */
120 public function get($remoteFile) {
afcc9be0
TO
121 // Download extension zip file ...
122 if (!function_exists('curl_init')) {
dadcd1ac
FG
123 // CRM-13805
124 CRM_Core_Session::setStatus(
125 ts('As a result, actions like retrieving the CiviCRM news feed will fail. Talk to your server administrator or hosting company to rectify this.'),
126 ts('Curl is not installed')
127 );
afcc9be0
TO
128 return array(self::STATUS_DL_ERROR, NULL);
129 }
e647e388
TO
130
131 list($ch, $caConfig) = $this->createCurl($remoteFile);
132
afcc9be0
TO
133 if (preg_match('/^https:/', $remoteFile) && !$caConfig->isEnableSSL()) {
134 //CRM_Core_Error::fatal('Cannot install this extension - does not support SSL');
135 return array(self::STATUS_DL_ERROR, NULL);
136 }
137
afcc9be0 138 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
afcc9be0
TO
139 $data = curl_exec($ch);
140 if (curl_errno($ch)) {
2b5a6dbf 141 return array(self::STATUS_DL_ERROR, $data);
afcc9be0
TO
142 }
143 else {
144 curl_close($ch);
145 }
146
147 return array(self::STATUS_OK, $data);
e647e388
TO
148 }
149
49626e3d
CW
150 /**
151 * Send an HTTP POST for a remote resource
152 *
153 * @param string $remoteFile URL of a .zip file
f4aaa82a
EM
154 * @param $params
155 *
156 * @internal param string $localFile path at which to store the .zip file
49626e3d
CW
157 * @return array array(0 => STATUS_OK|STATUS_DL_ERROR, 1 => string)
158 */
159 public function post($remoteFile, $params) {
160 // Download extension zip file ...
161 if (!function_exists('curl_init')) {
162 //CRM_Core_Error::fatal('Cannot install this extension - curl is not installed!');
163 return array(self::STATUS_DL_ERROR, NULL);
164 }
165
166 list($ch, $caConfig) = $this->createCurl($remoteFile);
167
168 if (preg_match('/^https:/', $remoteFile) && !$caConfig->isEnableSSL()) {
169 //CRM_Core_Error::fatal('Cannot install this extension - does not support SSL');
170 return array(self::STATUS_DL_ERROR, NULL);
171 }
172
173 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
174 curl_setopt($ch, CURLOPT_POST, true);
175 curl_setopt($ch, CURLOPT_POST,count($params));
176 curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
177 $data = curl_exec($ch);
178 if (curl_errno($ch)) {
2b5a6dbf 179 return array(self::STATUS_DL_ERROR, $data);
49626e3d
CW
180 }
181 else {
182 curl_close($ch);
183 }
184
185 return array(self::STATUS_OK, $data);
186 }
187
e647e388
TO
188 /**
189 * @param string $remoteFile
190 * @return array (0 => resource, 1 => CA_Config_Curl)
191 */
192 protected function createCurl($remoteFile) {
193 require_once 'CA/Config/Curl.php';
194 $caConfig = CA_Config_Curl::probe(array(
195 'verify_peer' => (bool) CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL', NULL, TRUE)
196 ));
197
198 $ch = curl_init();
199 curl_setopt($ch, CURLOPT_URL, $remoteFile);
200 curl_setopt($ch, CURLOPT_HEADER, FALSE);
201 curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
202 curl_setopt($ch, CURLOPT_VERBOSE, 0);
eb066397 203 if ($this->isRedirectSupported()) {
439b9688
LS
204 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
205 }
021cfda1
TO
206 if ($this->connectionTimeout !== NULL) {
207 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectionTimeout);
208 }
e647e388
TO
209 if (preg_match('/^https:/', $remoteFile) && $caConfig->isEnableSSL()) {
210 curl_setopt_array($ch, $caConfig->toCurlOptions());
211 }
afcc9be0 212
e647e388 213 return array($ch, $caConfig);
afcc9be0
TO
214 }
215
5bc392e6
EM
216 /**
217 * @return bool
218 */
eb066397 219 public function isRedirectSupported() {
535819a0 220 return (ini_get('open_basedir') == '') && (ini_get('safe_mode') == 'Off' || ini_get('safe_mode') === FALSE);
eb066397
TO
221 }
222
6a488035 223}