156 lines
5.6 KiB
PHP
156 lines
5.6 KiB
PHP
<?php
|
||
/**
|
||
* MSIN API ChronoTrack — client HTTP bas niveau (cURL).
|
||
*/
|
||
|
||
function fxChronotrackApiHttpRequest($strMethod, $strUrl, $arrOptions = array()) {
|
||
$intMaxAttempts = max(1, intval($arrOptions['retries'] ?? 1));
|
||
// MSIN-4574 — 502/503/429 = surcharge CT ou proxy : backoff, pas abandon immédiat
|
||
$tabRetryCodes = array(429, 502, 503, 504);
|
||
$arrLast = null;
|
||
|
||
for ($intAttempt = 1; $intAttempt <= $intMaxAttempts; $intAttempt++) {
|
||
$arrLast = fxChronotrackApiHttpRequestOnce($strMethod, $strUrl, $arrOptions);
|
||
if (($arrLast['state'] ?? '') === 'ok') {
|
||
$arrLast['attempts'] = $intAttempt;
|
||
return $arrLast;
|
||
}
|
||
$intCode = intval($arrLast['http_code'] ?? 0);
|
||
$blnRetry = ($intAttempt < $intMaxAttempts) && (
|
||
in_array($intCode, $tabRetryCodes, true)
|
||
|| (!empty($arrLast['curl_error']) && (
|
||
stripos((string)$arrLast['curl_error'], 'timed out') !== false
|
||
|| stripos((string)$arrLast['curl_error'], 'reset') !== false
|
||
))
|
||
);
|
||
if (!$blnRetry) {
|
||
$arrLast['attempts'] = $intAttempt;
|
||
return $arrLast;
|
||
}
|
||
// Backoff : 1s, 2s, 4s…
|
||
usleep((int)(1000000 * pow(2, $intAttempt - 1)));
|
||
}
|
||
|
||
if (is_array($arrLast)) {
|
||
$arrLast['attempts'] = $intMaxAttempts;
|
||
}
|
||
return $arrLast;
|
||
}
|
||
|
||
/**
|
||
* Une seule tentative cURL (sans retry).
|
||
*/
|
||
function fxChronotrackApiHttpRequestOnce($strMethod, $strUrl, $arrOptions = array()) {
|
||
$arrResult = array(
|
||
'state' => 'error',
|
||
'http_code' => 0,
|
||
'body' => '',
|
||
'json' => null,
|
||
'curl_error' => '',
|
||
);
|
||
|
||
if (!function_exists('curl_init')) {
|
||
$arrResult['curl_error'] = 'cURL indisponible';
|
||
return $arrResult;
|
||
}
|
||
|
||
$ch = curl_init();
|
||
$arrHeaders = isset($arrOptions['headers']) && is_array($arrOptions['headers']) ? $arrOptions['headers'] : array();
|
||
$intTimeout = max(30, intval($arrOptions['timeout'] ?? 90));
|
||
|
||
curl_setopt($ch, CURLOPT_URL, $strUrl);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, $intTimeout);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||
curl_setopt($ch, CURLOPT_HTTPHEADER, $arrHeaders);
|
||
|
||
$strMethod = strtoupper(trim($strMethod));
|
||
if ($strMethod === 'GET') {
|
||
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
||
} else {
|
||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $strMethod);
|
||
if (isset($arrOptions['body'])) {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, $arrOptions['body']);
|
||
} elseif ($strMethod === 'POST') {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
|
||
}
|
||
}
|
||
|
||
if (!empty($arrOptions['basic_user']) || !empty($arrOptions['basic_pass'])) {
|
||
curl_setopt($ch, CURLOPT_USERPWD, $arrOptions['basic_user'] . ':' . $arrOptions['basic_pass']);
|
||
}
|
||
|
||
$strBody = curl_exec($ch);
|
||
$arrResult['http_code'] = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
if ($strBody === false) {
|
||
$arrResult['curl_error'] = curl_error($ch);
|
||
} else {
|
||
$arrResult['body'] = $strBody;
|
||
$tabJson = json_decode($strBody, true);
|
||
if (is_array($tabJson)) {
|
||
$arrResult['json'] = $tabJson;
|
||
}
|
||
}
|
||
curl_close($ch);
|
||
|
||
if ($arrResult['curl_error'] !== '') {
|
||
return $arrResult;
|
||
}
|
||
|
||
if ($arrResult['http_code'] >= 200 && $arrResult['http_code'] < 300) {
|
||
$arrResult['state'] = 'ok';
|
||
}
|
||
|
||
return $arrResult;
|
||
}
|
||
|
||
function fxChronotrackApiHttpGetJsonErrorMessage($arrHttp) {
|
||
if (!empty($arrHttp['curl_error'])) {
|
||
return $arrHttp['curl_error'];
|
||
}
|
||
|
||
$arrParts = array();
|
||
if (is_array($arrHttp['json'])) {
|
||
foreach (array('errorMessage', 'message', 'error_description', 'errorCode', 'error') as $strKey) {
|
||
if (empty($arrHttp['json'][$strKey])) {
|
||
continue;
|
||
}
|
||
// MSIN-4574 — restauré : CT renvoie souvent error = string OU liste d’objets
|
||
if ($strKey === 'error' && is_array($arrHttp['json']['error'])) {
|
||
foreach ($arrHttp['json']['error'] as $mixErr) {
|
||
if (is_string($mixErr) && trim($mixErr) !== '') {
|
||
$arrParts[] = $mixErr;
|
||
} elseif (is_array($mixErr)) {
|
||
if (!empty($mixErr['errorMessage'])) {
|
||
$arrParts[] = (string)$mixErr['errorMessage'];
|
||
} elseif (!empty($mixErr['message'])) {
|
||
$arrParts[] = (string)$mixErr['message'];
|
||
}
|
||
}
|
||
}
|
||
continue;
|
||
}
|
||
if (is_string($arrHttp['json'][$strKey]) || is_numeric($arrHttp['json'][$strKey])) {
|
||
$arrParts[] = (string)$arrHttp['json'][$strKey];
|
||
}
|
||
}
|
||
}
|
||
|
||
$strBody = trim((string)($arrHttp['body'] ?? ''));
|
||
if (count($arrParts) > 0) {
|
||
return 'HTTP ' . intval($arrHttp['http_code']) . ' — ' . implode(' | ', array_unique($arrParts));
|
||
}
|
||
|
||
if ($strBody !== '') {
|
||
// Page HTML 503 CT / proxy
|
||
if (stripos($strBody, '503') !== false || stripos($strBody, 'Service Unavailable') !== false) {
|
||
return 'HTTP ' . intval($arrHttp['http_code'])
|
||
. ' — Service Unavailable (surcharge CT/proxy — lot trop gros ou trop rapide)';
|
||
}
|
||
return 'HTTP ' . intval($arrHttp['http_code']) . ' — ' . substr($strBody, 0, 400);
|
||
}
|
||
|
||
return 'HTTP ' . intval($arrHttp['http_code']);
|
||
}
|