51function getURLContent($url, $postorget =
'GET', $param =
'', $followlocation = 1, $addheaders = array(), $allowedschemes = array(
'http',
'https'), $localurl = 0, $ssl_verifypeer = -1, $timeoutconnect = 0, $timeoutresponse = 0, $otherCurlOptions = array(), $morelogsuffix =
'')
60 dol_syslog(
"getURLContent postorget=".$postorget.
" URL=".$url);
62 dol_syslog(
"getURLContent postorget=".$postorget.
" URL=".$url.
" json_encode(param)=".json_encode($param), LOG_DEBUG, 0,
'_curl');
65 dol_syslog(
"getURLContent postorget=".$postorget.
" URL=".$url.
" json_encode(param)=".json_encode($param), LOG_DEBUG, 0, $morelogsuffix);
68 if (!function_exists(
'curl_init')) {
70 dol_syslog(
"getURLContent PHP curl library must be installed", LOG_DEBUG, 0,
'_curl');
73 dol_syslog(
"getURLContent PHP curl library must be installed", LOG_DEBUG, 0, $morelogsuffix);
76 return array(
'http_code' => 500,
'content' =>
'',
'curl_error_no' => 1,
'curl_error_msg' =>
'PHP curl library must be installed');
88 curl_setopt($ch, CURLOPT_VERBOSE,
getDolGlobalInt(
'MAIN_CURL_DEBUG') ?
true :
false);
89 curl_setopt($ch, CURLOPT_USERAGENT,
'Dolibarr geturl function');
93 @curl_setopt($ch, CURLOPT_FOLLOWLOCATION,
false);
95 if (is_array($addheaders) && count($addheaders)) {
96 curl_setopt($ch, CURLOPT_HTTPHEADER, $addheaders);
98 curl_setopt($ch, CURLINFO_HEADER_OUT,
true);
101 curl_setopt($ch, CURLOPT_HEADER,
true);
108 curl_setopt($ch, CURLOPT_SSLVERSION, (
int) $sslversion);
113 if ($ssl_verifypeer < 0) {
114 global $dolibarr_main_prod;
115 $ssl_verifypeer = ($dolibarr_main_prod ? true :
false);
122 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, ($ssl_verifypeer ?
true :
false));
128 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, ($ssl_verifypeer ? 2 : 0));
132 $redir_list = array();
133 if (is_array($allowedschemes)) {
134 foreach ($allowedschemes as $allowedscheme) {
135 if ($allowedscheme ==
'http') {
136 $protocols |= CURLPROTO_HTTP;
137 $redir_list[
"HTTP"] = 1;
138 } elseif ($allowedscheme ==
'https') {
139 $protocols |= CURLPROTO_HTTPS;
140 $redir_list[
"HTTPS"] = 1;
141 } elseif ($allowedscheme ==
'ftp') {
142 $protocols |= CURLPROTO_FTP;
143 $redir_list[
"FTP"] = 1;
144 } elseif ($allowedscheme ==
'ftps') {
145 $protocols |= CURLPROTO_FTPS;
146 $redir_list[
"FTPS"] = 1;
150 return array(
'http_code' => 500,
'content' =>
'',
'curl_error_no' => 1,
'curl_error_msg' =>
'Parameter allowedschemes of getURLContent must be an array of protocol schemes');
153 $newtimeoutconnect = ($timeoutconnect ? $timeoutconnect :
getDolGlobalInt(
'MAIN_USE_CONNECT_TIMEOUT', 5));
154 $newtimeoutresponse = ($timeoutresponse ? $timeoutresponse :
getDolGlobalInt(
'MAIN_USE_RESPONSE_TIMEOUT', 30));
157 dol_syslog(
"getURLContent newtimeoutconnect=".$newtimeoutconnect.
" newtimeoutresponse=".$newtimeoutresponse, LOG_DEBUG, 0,
'_curl');
159 if ($morelogsuffix) {
160 dol_syslog(
"getURLContent newtimeoutconnect=".$newtimeoutconnect.
" newtimeoutresponse=".$newtimeoutresponse, LOG_DEBUG, 0, $morelogsuffix);
163 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $newtimeoutconnect);
164 curl_setopt($ch, CURLOPT_TIMEOUT, $newtimeoutresponse);
168 if ($maxsize && defined(
'CURLOPT_MAXFILESIZE_LARGE')) {
169 curl_setopt($ch, CURLOPT_MAXFILESIZE_LARGE, $maxsize * 1024);
171 if ($maxsize && defined(
'CURLOPT_MAXFILESIZE')) {
172 curl_setopt($ch, CURLOPT_MAXFILESIZE, $maxsize * 1024);
176 curl_setopt($ch, CURLOPT_RETURNTRANSFER,
true);
180 curl_setopt($ch, CURLOPT_ENCODING,
'');
182 $responsebuffer =
'';
183 $responsetoolarge =
false;
192 $writefunction =
function ($curl, $data) use (&$responsebuffer, &$responsetoolarge, $maxsize) {
193 if (strlen($responsebuffer) + strlen($data) > $maxsize * 1024) {
194 $responsetoolarge =
true;
197 $responsebuffer .= $data;
198 return strlen($data);
200 curl_setopt($ch, CURLOPT_WRITEFUNCTION, $writefunction);
202 if ($postorget ==
'POST') {
203 curl_setopt($ch, CURLOPT_POST,
true);
204 curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
205 } elseif ($postorget ==
'POSTALREADYFORMATED') {
206 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'POST');
207 curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
208 } elseif ($postorget ==
'PUT') {
209 $array_param = array();
210 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'PUT');
211 if (!is_array($param)) {
212 parse_str($param, $array_param);
214 dol_syslog(
"parameter param must be a string", LOG_WARNING);
215 $array_param = $param;
217 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($array_param));
218 } elseif ($postorget ==
'PUTALREADYFORMATED') {
219 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'PUT');
220 curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
221 } elseif ($postorget ==
'PATCH') {
222 $array_param = array();
223 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'PATCH');
224 if (!is_array($param)) {
225 parse_str($param, $array_param);
227 dol_syslog(
"parameter param must be a string", LOG_WARNING);
228 $array_param = $param;
230 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($array_param));
231 } elseif ($postorget ==
'PATCHALREADYFORMATED') {
232 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'PATCH');
233 curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
234 } elseif ($postorget ==
'HEAD') {
235 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'HEAD');
236 curl_setopt($ch, CURLOPT_NOBODY,
true);
237 curl_setopt($ch, CURLOPT_HEADER,
true);
238 } elseif ($postorget ==
'DELETE') {
239 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
'DELETE');
241 curl_setopt($ch, CURLOPT_POST,
false);
246 dol_syslog(
"getURLContent set proxy to ".$PROXY_HOST.
":".$PROXY_PORT.
" - ".$PROXY_USER.
":".$PROXY_PASS);
248 curl_setopt($ch, CURLOPT_PROXY, $PROXY_HOST.
":".$PROXY_PORT);
250 curl_setopt($ch, CURLOPT_PROXYUSERPWD, $PROXY_USER.
":".$PROXY_PASS);
254 if (is_array($otherCurlOptions)) {
257 $forbiddencurloptions = [CURLOPT_FOLLOWLOCATION, CURLOPT_URL, CURLOPT_RESOLVE, CURLOPT_PROXY, CURLOPT_PROTOCOLS, CURLOPT_REDIR_PROTOCOLS];
258 foreach ([
'CURLOPT_CONNECT_TO',
'CURLOPT_UNIX_SOCKET_PATH',
'CURLOPT_ABSTRACT_UNIX_SOCKET',
'CURLOPT_PRE_PROXY'] as $constname) {
259 if (defined($constname)) {
260 $forbiddencurloptions[] = constant($constname);
263 foreach ($otherCurlOptions as $option => $value) {
264 if (in_array($option, $forbiddencurloptions,
true)) {
265 dol_syslog(
"getURLContent curl option ".$option.
" can not be set with otherCurlOptions, ignored", LOG_WARNING);
268 curl_setopt($ch, $option, $value);
278 if ($maxRedirection < 1) {
280 dol_syslog(
"getURLContent http_code=400 Maximum number of redirections reached", LOG_DEBUG, 0,
'_curl');
282 return array(
'http_code' => 400,
'content' =>
'Maximum number of redirections reached',
'curl_error_no' => 1,
'curl_error_msg' =>
'Maximum number of redirections reached');
285 curl_setopt($ch, CURLOPT_URL, $newUrl);
288 $newUrlArray = parse_url($newUrl);
289 if (!is_array($newUrlArray) || (empty($newUrlArray[
'host']) && empty($newUrlArray[
'path']))) {
291 return array(
'http_code' => 400,
'content' =>
'',
'curl_error_no' => 1,
'curl_error_msg' =>
'Bad URL '.$newUrl);
293 $hosttocheck = !empty($newUrlArray[
'host']) ? $newUrlArray[
'host'] : $newUrlArray[
'path'];
294 $hosttocheck = str_replace(array(
'[',
']'),
'', $hosttocheck);
297 if (in_array(strtolower($hosttocheck), array(
'metadata.google.internal'))) {
298 $info[
'http_code'] = 400;
299 $info[
'content'] =
'Error bad hostname '.$hosttocheck.
' (Used by Google metadata). This value for hostname is not allowed.';
301 dol_syslog(
"getURLContent http_code=400 ".$info[
'content'], LOG_DEBUG, 0,
'_curl');
303 return array(
'http_code' => 400,
'content' => $info[
'content'],
'curl_error_no' => 1,
'curl_error_msg' => $info[
'content']);
309 if (preg_match(
'/^(0x[0-9a-f]+|[0-9]+)$/i', $hosttocheck)) {
310 return array(
'http_code' => 400,
'content' =>
'',
'curl_error_no' => 1,
'curl_error_msg' =>
'Host is a numeric address that is not allowed');
314 if (filter_var($hosttocheck, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
315 $iptocheck = $hosttocheck;
316 } elseif (in_array($hosttocheck, array(
'localhost',
'localhost.domain'))) {
317 $iptocheck =
'127.0.0.1';
318 } elseif (in_array($hosttocheck, array(
'ip6-localhost',
'ip6-loopback'))) {
326 if (!filter_var($iptocheck, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
327 return array(
'http_code' => 400,
'content' =>
'',
'curl_error_no' => 1,
'curl_error_msg' =>
'Host '.$hosttocheck.
' can not be resolved into an IP');
333 $info[
'http_code'] = 400;
334 $info[
'content'] = $tmpresult;
336 dol_syslog(
"getURLContent http_code=400 ".$info[
'content'], LOG_DEBUG, 0,
'_curl');
338 return array(
'http_code' => 400,
'content' => $tmpresult,
'curl_error_no' => 1,
'curl_error_msg' => $tmpresult);
345 if (defined(
'CURLOPT_CONNECT_TO')) {
347 $ipforconnect = (strpos($iptocheck,
':') !==
false) ?
'['.$iptocheck.
']' : $iptocheck;
348 $connect_to = array(sprintf(
"%s:%s:%s:%s", $newUrlArray[
'host'], empty($newUrlArray[
'port']) ?
'' : $newUrlArray[
'port'], $ipforconnect, empty($newUrlArray[
'port']) ?
'' : $newUrlArray[
'port']));
351 curl_setopt($ch, CURLOPT_CONNECT_TO, $connect_to);
357 curl_setopt($ch, CURLOPT_PROTOCOLS, $protocols);
358 curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, $protocols);
366 $responsebuffer =
'';
367 $responsetoolarge =
false;
368 $response = curl_exec($ch);
371 $response = ($response ===
false || $responsetoolarge) ?
false : $responsebuffer;
374 $info = curl_getinfo($ch);
375 $http_code = $info[
'http_code'];
377 if ($followlocation && in_array($http_code, [301, 302, 303, 307, 308]) && !empty($info[
'redirect_url'])) {
378 $newUrl = $info[
'redirect_url'];
384 $currenthost = (is_array($newUrlArray) && !empty($newUrlArray[
'host'])) ? $newUrlArray[
'host'] :
'';
385 $nexthost = (string) parse_url($newUrl, PHP_URL_HOST);
386 if (strtolower($nexthost) != strtolower($currenthost)) {
389 curl_setopt($ch, CURLOPT_HTTPHEADER, $addheaders);
391 if (in_array($http_code, [301, 302, 303]) && !in_array($postorget, [
'GET',
'HEAD'])) {
394 curl_setopt($ch, CURLOPT_CUSTOMREQUEST,
null);
395 curl_setopt($ch, CURLOPT_HTTPGET,
true);
401 }
while ($http_code);
403 $request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
405 dol_syslog(
"getURLContent request without content body=".$request);
408 dol_syslog(
"getURLContent request without body=".$request, LOG_DEBUG, 0,
'_curl');
409 dol_syslog(
"getURLContent response=".$response, LOG_DEBUG, 0,
'_curl');
411 if ($morelogsuffix) {
413 dol_syslog(
"getURLContent request without body=".$request, LOG_DEBUG, 0, $morelogsuffix);
414 dol_syslog(
"getURLContent response=".$response, LOG_DEBUG, 0, $morelogsuffix);
417 dol_syslog(
"getURLContent response size=".strlen($response));
420 if (curl_errno($ch)) {
423 $rep[
'content'] = (string) $response;
425 $rep[
'content'] =
'';
428 $rep[
'http_code'] = 0;
429 $rep[
'curl_error_no'] = curl_errno($ch);
430 $rep[
'curl_error_msg'] = curl_error($ch);
431 if ($responsetoolarge) {
433 $rep[
'curl_error_no'] = 63;
434 $rep[
'curl_error_msg'] =
'Maximum file size exceeded';
437 dol_syslog(
"getURLContent response array is ".implode(
',', $rep));
440 dol_syslog(
"getURLContent curl_error_no=".$rep[
'curl_error_no'].
" curl_error_msg=".$rep[
'curl_error_msg'], LOG_DEBUG, 0,
'_curl');
442 if ($morelogsuffix) {
443 dol_syslog(
"getURLContent curl_error_no=".$rep[
'curl_error_no'].
" curl_error_msg=".$rep[
'curl_error_msg'], LOG_DEBUG, 0, $morelogsuffix);
454 dol_syslog(
"getURLContent http_code=".$rep[
'http_code']);
458 $rep[
'content'] = (string) $response;
459 if ($postorget ==
'HEAD' ||
getDolGlobalInt(
'MAIN_CURL_GET_RESPONSE_HEADER')) {
460 $rep[
'header'] = substr($rep[
'content'], 0, intval($rep[
'header_size']));
461 $rep[
'content'] = substr($rep[
'content'], intval($rep[
'header_size']));
464 $rep[
'content'] =
'';
467 $rep[
'curl_error_no'] = 0;
468 $rep[
'curl_error_msg'] =
'';