161 lines
5.6 KiB
PHP
161 lines
5.6 KiB
PHP
<?php
|
|
/**
|
|
* Fociz Pure PHP HTTP Client Helper
|
|
* Ondersteunt cURL met automatische fallback naar stream wrappers (file_get_contents).
|
|
*/
|
|
|
|
if (!function_exists('fociz_http_request')) {
|
|
/**
|
|
* Voert een HTTP request uit en retourneert de statuscode, body en geparsede JSON.
|
|
*
|
|
* @param string $url
|
|
* @param array $options [
|
|
* 'method' => 'GET'|'POST'|'PUT'|'DELETE',
|
|
* 'headers' => ['Header-Name: Value'] of ['Header-Name' => 'Value'],
|
|
* 'body' => string|array,
|
|
* 'timeout' => int (seconden, default 12),
|
|
* 'verify_ssl' => bool (default true)
|
|
* ]
|
|
* @return array ['status' => int, 'body' => string, 'json' => ?array, 'error' => ?string]
|
|
*/
|
|
function fociz_http_request(string $url, array $options = []): array {
|
|
$method = strtoupper($options['method'] ?? 'GET');
|
|
$timeout = (int)($options['timeout'] ?? 12);
|
|
$verifySsl = $options['verify_ssl'] ?? true;
|
|
|
|
// Normaliseer headers naar 'Name: Value' regels
|
|
$rawHeaders = $options['headers'] ?? [];
|
|
$headerLines = [];
|
|
foreach ($rawHeaders as $k => $v) {
|
|
if (is_numeric($k)) {
|
|
$headerLines[] = $v;
|
|
} else {
|
|
$headerLines[] = "{$k}: {$v}";
|
|
}
|
|
}
|
|
|
|
// Bereid payload voor
|
|
$body = $options['body'] ?? null;
|
|
if (is_array($body)) {
|
|
$hasJsonHeader = false;
|
|
foreach ($headerLines as $h) {
|
|
if (stripos($h, 'application/json') !== false) {
|
|
$hasJsonHeader = true;
|
|
break;
|
|
}
|
|
}
|
|
if ($hasJsonHeader) {
|
|
$body = json_encode($body);
|
|
} else {
|
|
$body = http_build_query($body);
|
|
$headerLines[] = 'Content-Type: application/x-www-form-urlencoded';
|
|
}
|
|
}
|
|
|
|
// Voeg standaard User-Agent toe als die er niet is
|
|
$hasUserAgent = false;
|
|
foreach ($headerLines as $h) {
|
|
if (stripos($h, 'User-Agent:') !== false) {
|
|
$hasUserAgent = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$hasUserAgent) {
|
|
$headerLines[] = 'User-Agent: Fociz-Integrations/1.0';
|
|
}
|
|
|
|
// 1. Probeer cURL indien beschikbaar
|
|
if (extension_loaded('curl')) {
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, min(4, max(1, $timeout - 1)));
|
|
curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 600);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerLines);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifySsl);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verifySsl ? 2 : 0);
|
|
|
|
if ($body !== null && in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
|
}
|
|
|
|
$responseBody = curl_exec($ch);
|
|
$curlError = curl_error($ch);
|
|
$statusCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($responseBody === false && !empty($curlError)) {
|
|
return [
|
|
'status' => $statusCode ?: 0,
|
|
'body' => '',
|
|
'json' => null,
|
|
'error' => "cURL fout: {$curlError}"
|
|
];
|
|
}
|
|
|
|
$parsedJson = json_decode((string)$responseBody, true);
|
|
|
|
return [
|
|
'status' => $statusCode,
|
|
'body' => (string)$responseBody,
|
|
'json' => is_array($parsedJson) ? $parsedJson : null,
|
|
'error' => null
|
|
];
|
|
}
|
|
|
|
// 2. Fallback: PHP Streams (file_get_contents)
|
|
$contextOptions = [
|
|
'http' => [
|
|
'method' => $method,
|
|
'header' => implode("\r\n", $headerLines),
|
|
'timeout' => $timeout,
|
|
'ignore_errors' => true // Zorgt dat we ook bij 4xx / 5xx responses de body en statuscode kunnen lezen
|
|
],
|
|
'ssl' => [
|
|
'verify_peer' => $verifySsl,
|
|
'verify_peer_name' => $verifySsl
|
|
]
|
|
];
|
|
|
|
if ($body !== null && in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
|
$contextOptions['http']['content'] = $body;
|
|
}
|
|
|
|
$context = stream_context_create($contextOptions);
|
|
$responseBody = @file_get_contents($url, false, $context);
|
|
|
|
$statusCode = 0;
|
|
if (!empty($http_response_header)) {
|
|
// Zoek de laatste HTTP status regel (bij eventuele redirects)
|
|
foreach (array_reverse($http_response_header) as $hdr) {
|
|
if (preg_match('#HTTP/\d\.\d\s+(\d{3})#i', $hdr, $matches)) {
|
|
$statusCode = (int)$matches[1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($responseBody === false) {
|
|
$lastErr = error_get_last();
|
|
return [
|
|
'status' => $statusCode ?: 0,
|
|
'body' => '',
|
|
'json' => null,
|
|
'error' => 'Stream fout: ' . ($lastErr['message'] ?? 'Kan verbinding niet voltooien')
|
|
];
|
|
}
|
|
|
|
$parsedJson = json_decode((string)$responseBody, true);
|
|
|
|
return [
|
|
'status' => $statusCode,
|
|
'body' => (string)$responseBody,
|
|
'json' => is_array($parsedJson) ? $parsedJson : null,
|
|
'error' => null
|
|
];
|
|
}
|
|
}
|
|
|