fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "' LIMIT 1"; return $objDatabase->fxGetRow($sql); } function fxChronotrackApiOAuthSaveToken($strAccessToken, $strRefreshToken, $intExpiresEpoch) { global $objDatabase; $strExpires = ''; if ($intExpiresEpoch > 0) { $strExpires = date('Y-m-d H:i:s', $intExpiresEpoch); } $sqlExists = "SELECT token_key FROM api_chronotrack_token WHERE token_key = '" . $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "' LIMIT 1"; if ($objDatabase->fxGetRow($sqlExists) !== null) { $sql = "UPDATE api_chronotrack_token SET access_token = '" . $objDatabase->fxEscape($strAccessToken) . "', refresh_token = '" . $objDatabase->fxEscape($strRefreshToken) . "', expires_at = " . ($strExpires !== '' ? "'" . $objDatabase->fxEscape($strExpires) . "'" : 'NULL') . ", updated_at = '" . fxGetDateTime() . "' WHERE token_key = '" . $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "'"; } else { $sql = "INSERT INTO api_chronotrack_token SET token_key = '" . $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "', access_token = '" . $objDatabase->fxEscape($strAccessToken) . "', refresh_token = '" . $objDatabase->fxEscape($strRefreshToken) . "', expires_at = " . ($strExpires !== '' ? "'" . $objDatabase->fxEscape($strExpires) . "'" : 'NULL') . ", updated_at = '" . fxGetDateTime() . "'"; } $objDatabase->fxQuery($sql); } function fxChronotrackApiOAuthTokenValid($arrRow) { if ($arrRow === null || trim((string)($arrRow['access_token'] ?? '')) === '') { return false; } if (empty($arrRow['expires_at'])) { return true; } $intExpires = strtotime($arrRow['expires_at']); if ($intExpires === false) { return true; } return ($intExpires > (time() + 120)); } function fxChronotrackApiOAuthFetchToken($blnForceRefresh = false) { if (!fxChronotrackApiSettingsConfigured()) { return array('state' => 'error', 'message' => fxChronotrackApiSettingsErrorMessage()); } if (!$blnForceRefresh) { $arrCached = fxChronotrackApiOAuthGetTokenRow(); if (fxChronotrackApiOAuthTokenValid($arrCached)) { return array( 'state' => 'ok', 'access_token' => $arrCached['access_token'], 'from_cache' => true, ); } } $strBase = fxChronotrackApiGetBaseUrl(); $strQuery = http_build_query(array( 'grant_type' => 'password', 'username' => fxChronotrackApiGetServiceUser(), 'password' => fxChronotrackApiGetServicePass(), )); $strUrl = $strBase . '/oauth2/token?' . $strQuery; $arrHttp = fxChronotrackApiHttpRequest('GET', $strUrl, array( 'basic_user' => fxChronotrackApiGetClientId(), 'basic_pass' => fxChronotrackApiGetClientSecret(), )); if ($arrHttp['state'] !== 'ok' || !is_array($arrHttp['json'])) { return array( 'state' => 'error', 'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp), ); } $arrJson = $arrHttp['json']; if (!empty($arrJson['errorCode']) || !empty($arrJson['error'])) { return array( 'state' => 'error', 'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp), ); } $strToken = trim((string)($arrJson['access_token'] ?? '')); if ($strToken === '') { return array( 'state' => 'error', 'message' => 'access_token absent — ' . fxChronotrackApiHttpGetJsonErrorMessage($arrHttp), ); } $strRefresh = trim((string)($arrJson['refresh_token'] ?? '')); $intExpires = intval($arrJson['expires'] ?? 0); if ($intExpires <= 0 && !empty($arrJson['expires_in'])) { $intExpires = time() + intval($arrJson['expires_in']); } fxChronotrackApiOAuthSaveToken($strToken, $strRefresh, $intExpires); return array( 'state' => 'ok', 'access_token' => $strToken, 'from_cache' => false, ); } function fxChronotrackApiOAuthApiGet($strPath, $arrQuery = array()) { $arrToken = fxChronotrackApiOAuthFetchToken(false); if ($arrToken['state'] !== 'ok') { return $arrToken; } $arrQuery['client_id'] = fxChronotrackApiGetClientId(); $strUrl = fxChronotrackApiGetApiBaseUrl() . '/' . ltrim($strPath, '/'); if (!empty($arrQuery)) { $strUrl .= '?' . http_build_query($arrQuery); } $arrHttp = fxChronotrackApiHttpRequest('GET', $strUrl, array( 'headers' => array('Authorization: Bearer ' . $arrToken['access_token']), )); if ($arrHttp['state'] === 'ok') { return array('state' => 'ok', 'json' => $arrHttp['json'], 'http' => $arrHttp); } return array( 'state' => 'error', 'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp), 'http' => $arrHttp, ); } function fxChronotrackApiOAuthApiPost($strPath, $mixBody, $arrQuery = array()) { $arrToken = fxChronotrackApiOAuthFetchToken(false); if ($arrToken['state'] !== 'ok') { return $arrToken; } $arrQuery['client_id'] = fxChronotrackApiGetClientId(); $strUrl = fxChronotrackApiGetApiBaseUrl() . '/' . ltrim($strPath, '/'); if (!empty($arrQuery)) { $strUrl .= '?' . http_build_query($arrQuery); } $strBody = json_encode($mixBody, JSON_UNESCAPED_UNICODE); if (!is_string($strBody)) { return array('state' => 'error', 'message' => 'json_encode a échoué'); } $arrHttp = fxChronotrackApiHttpRequest('POST', $strUrl, array( 'headers' => array( 'Authorization: Bearer ' . $arrToken['access_token'], 'Content-Type: application/json', 'Accept: application/json', ), 'body' => $strBody, )); if ($arrHttp['state'] === 'ok') { return array('state' => 'ok', 'json' => $arrHttp['json'], 'http' => $arrHttp); } return array( 'state' => 'error', 'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp), 'http' => $arrHttp, ); } function fxChronotrackApiOAuthApiPut($strPath, $mixBody, $arrQuery = array()) { $arrToken = fxChronotrackApiOAuthFetchToken(false); if ($arrToken['state'] !== 'ok') { return $arrToken; } $arrQuery['client_id'] = fxChronotrackApiGetClientId(); $strUrl = fxChronotrackApiGetApiBaseUrl() . '/' . ltrim($strPath, '/'); if (!empty($arrQuery)) { $strUrl .= '?' . http_build_query($arrQuery); } $strBody = json_encode($mixBody, JSON_UNESCAPED_UNICODE); if (!is_string($strBody)) { return array('state' => 'error', 'message' => 'json_encode a échoué'); } $arrHttp = fxChronotrackApiHttpRequest('PUT', $strUrl, array( 'headers' => array( 'Authorization: Bearer ' . $arrToken['access_token'], 'Content-Type: application/json', 'Accept: application/json', ), 'body' => $strBody, )); if ($arrHttp['state'] === 'ok') { return array('state' => 'ok', 'json' => $arrHttp['json'], 'http' => $arrHttp); } return array( 'state' => 'error', 'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp), 'http' => $arrHttp, ); }