JFIFxxC      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbrload()->getConfig(); $this->setConfig($config); $apiClient->setConfig($config); $this->attempts = self::DEFAULT_ATTEMPTS_COUNT; $this->apiClient = $apiClient; } /** * Устанавливает авторизацию по логин/паролю. * * @example 01-client.php 7 1 Пример авторизации * * @param string|int $login * @param string $password * * @return $this */ public function setAuth(mixed $login, string $password): self { $this->login = $login; $this->password = $password; $this->apiClient ->setBearerToken(null) ->setShopId($this->login) ->setShopPassword($this->password) ; return $this; } /** * Устанавливает авторизацию по Oauth-токену. * * @example 01-client.php 9 1 Пример авторизации * * @return $this */ public function setAuthToken(string $token): self { $this->apiClient ->setShopId(null) ->setShopPassword(null) ->setBearerToken($token) ; return $this; } /** * Возвращает CURL клиента для работы с API. */ public function getApiClient(): ApiClientInterface { return $this->apiClient; } /** * Устанавливает CURL клиента для работы с API. * * @return $this */ public function setApiClient(ApiClientInterface $apiClient): self { $this->apiClient = $apiClient; $this->apiClient->setConfig($this->config); $this->apiClient->setLogger($this->logger); return $this; } /** * Устанавливает логгер приложения. * * @param null|callable|LoggerInterface|object $value Инстанс логгера */ public function setLogger(mixed $value): self { if (null === $value || $value instanceof LoggerInterface) { $this->logger = $value; } else { $this->logger = new LoggerWrapper($value); } $this->apiClient?->setLogger($this->logger); return $this; } /** * Возвращает настройки клиента. */ public function getConfig(): array { return $this->config; } /** * Устанавливает настройки клиента. */ public function setConfig(array $config): void { $this->config = $config; } /** * Установка значения задержки между повторными запросами. * * @return $this */ public function setRetryTimeout(int $timeout = self::DEFAULT_DELAY): self { $this->timeout = $timeout; return $this; } /** * Установка значения количества попыток повторных запросов при статусе 202. * * @return $this */ public function setMaxRequestAttempts(int $attempts = self::DEFAULT_ATTEMPTS_COUNT): self { $this->attempts = $attempts; return $this; } /** * Метод проверяет, находится ли IP адрес среди IP адресов Юkassa, с которых отправляются уведомления. * * @param string $ip IPv4 или IPv6 адрес webhook уведомления * * @throws Exception Выбрасывается, если будет передан IP адрес неверного формата */ public function isNotificationIPTrusted(string $ip): bool { return (new SecurityHelper())->isIPTrusted($ip); } /** * Кодирует массив данных в JSON строку. * * @param array $serializedData Массив данных для кодировки * * @return string Строка JSON * * @throws JsonException Выбрасывается, если не удалось конвертировать данные в строку JSON */ protected function encodeData(array $serializedData): string { if ([] === $serializedData) { return '{}'; } return json_encode($serializedData, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } /** * Декодирует JSON строку в массив данных. * * @param ResponseObject $response Объект ответа на запрос к API * * @return array Массив данных * @throws JsonException */ protected function decodeData(ResponseObject $response): array { return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR); } /** * Выбрасывает исключение по коду ошибки. * * @throws ApiException неожиданный код ошибки * @throws BadApiRequestException Неправильный запрос. Чаще всего этот статус выдается из-за нарушения правил взаимодействия с API. * @throws ForbiddenException секретный ключ или OAuth-токен верный, но не хватает прав для совершения операции * @throws InternalServerError Технические неполадки на стороне ЮKassa. Результат обработки запроса неизвестен. Повторите запрос позднее с тем же ключом идемпотентности. * @throws NotFoundException ресурс не найден * @throws ResponseProcessingException запрос был принят на обработку, но она не завершена * @throws TooManyRequestsException Превышен лимит запросов в единицу времени. Попробуйте снизить интенсивность запросов. * @throws UnauthorizedException неверное имя пользователя или пароль или невалидный OAuth-токен при аутентификации * @throws AuthorizeException Ошибка авторизации. Не установлен заголовок. */ protected function handleError(ResponseObject $response): void { switch ($response->getCode()) { case BadApiRequestException::HTTP_CODE: throw new BadApiRequestException($response->getHeaders(), $response->getBody()); break; case ForbiddenException::HTTP_CODE: throw new ForbiddenException($response->getHeaders(), $response->getBody()); break; case UnauthorizedException::HTTP_CODE: throw new UnauthorizedException($response->getHeaders(), $response->getBody()); break; case InternalServerError::HTTP_CODE: throw new InternalServerError($response->getHeaders(), $response->getBody()); break; case NotFoundException::HTTP_CODE: throw new NotFoundException($response->getHeaders(), $response->getBody()); break; case TooManyRequestsException::HTTP_CODE: throw new TooManyRequestsException($response->getHeaders(), $response->getBody()); break; case ResponseProcessingException::HTTP_CODE: throw new ResponseProcessingException($response->getHeaders(), $response->getBody()); break; default: if ($response->getCode() > 399) { throw new ApiException( 'Unexpected response error code', $response->getCode(), $response->getHeaders(), $response->getBody() ); } } } /** * Задержка между повторными запросами. * * @param ResponseObject $response Объект ответа на запрос к API * @throws JsonException */ protected function delay(ResponseObject $response): void { $timeout = $this->timeout; $responseData = $this->decodeData($response); if ($timeout) { $delay = $timeout; } else { if (isset($responseData['retry_after'])) { $delay = $responseData['retry_after']; } else { $delay = self::DEFAULT_DELAY; } } usleep($delay * 1000); } /** * Выполнение запроса и обработка 202 статуса. * * @param string $path URL запроса * @param string $method HTTP метод * @param array $queryParams Массив GET параметров запроса * @param null|string $httpBody Тело запроса * @param array $headers Массив заголовков запроса * * @return mixed|ResponseObject * * @throws ApiException * @throws AuthorizeException * @throws ApiConnectionException * @throws ExtensionNotFoundException */ protected function execute(string $path, string $method, array $queryParams, ?string $httpBody = null, array $headers = []): mixed { $attempts = $this->attempts; $response = $this->apiClient->call($path, $method, $queryParams, $httpBody, $headers); while (in_array($response->getCode(), [202, 500], true) && $attempts > 0) { $this->delay($response); --$attempts; $response = $this->apiClient->call($path, $method, $queryParams, $httpBody, $headers); } return $response; } }