%PDF- %PDF-
Direktori : /home/bitrix/www/bitrix/modules/sale/lib/services/base/ |
Current File : //home/bitrix/www/bitrix/modules/sale/lib/services/base/restclient.php |
<?php namespace Bitrix\Sale\Services\Base; use Bitrix\Main\Error; use Bitrix\Main\Loader; use Bitrix\Main\ModuleManager; use Bitrix\Sale\Result; use Bitrix\Main\Context; use Bitrix\Main\Web\Json; use Bitrix\Main\Config\Option; use Bitrix\Main\Text\Encoding; use Bitrix\Main\Web\HttpClient; use Bitrix\Main\Localization\Loc; use Bitrix\Sale\Location\Exception; use Bitrix\Sale\ResultSerializable; Loc::loadMessages(__FILE__); class RestClient { const REST_URI = '/rest/'; const REGISTER_URI = '/oauth/register/'; const SCOPE = 'sale'; const SERVICE_ACCESS_OPTION = 'saleservices_access'; const ERROR_WRONG_INPUT = 1; const ERROR_WRONG_LICENSE = 2; const ERROR_SERVICE_UNAVAILABLE = 3; const ERROR_NOTHING_FOUND = 4; const UNSUCCESSFUL_CALL_OPTION = 'sale_hda_last_unsuccessful_call'; const UNSUCCESSFUL_CALL_TRYINGS = 3; //times const UNSUCCESSFUL_CALL_WAIT_INTERVAL = 300; //sec protected $httpTimeout = 10; protected $accessSettings = null; protected $serviceHost = 'https://saleservices.bitrix.info'; protected $version = 4; /** * Performs call to the REST method and returns decoded results of the call. * define SALE_SRVS_RESTCLIENT_DISABLE_SRV_ALIVE_CHECK to disable server alive checking. * @param string $methodName Name of the REST method. * @param array $additionalParams Parameters, that should be passed to the method. * @param bool $licenseCheck Should client send license key as a parameter of the http request. * @param bool $clearAccessSettings Should client clear authorization before performing http request. * @return Result $result */ protected function call($methodName, $additionalParams = null, $licenseCheck = false, $clearAccessSettings = false) { $result = new ResultSerializable(); if(!self::isServerAlive() && !defined('SALE_SRVS_RESTCLIENT_DISABLE_SRV_ALIVE_CHECK')) { $result->addError( new Error( Loc::getMessage('SALE_SRV_BASE_REST_CONNECT_ERROR').' '.$this->getServiceHost(), self::ERROR_SERVICE_UNAVAILABLE ) ); return $result; } if ($clearAccessSettings) { $this->clearAccessSettings(); $this->accessSettings = null; } if (is_null($this->accessSettings)) { $this->accessSettings = $this->getAccessSettings(); } if (!$this->accessSettings) { $result->addError(new Error(Loc::getMessage('SALE_SRV_BASE_REST_ACCESS_SETTINGS_ERROR'))); return $result; } if (!is_array($additionalParams)) $additionalParams = array(); else $additionalParams = Encoding::convertEncodingArray($additionalParams, LANG_CHARSET, "utf-8"); $additionalParams['version'] = $this->version; $additionalParams['client_id'] = $this->accessSettings['client_id']; $additionalParams['client_secret'] = $this->accessSettings['client_secret']; $additionalParams['lang'] = LANGUAGE_ID; if ($licenseCheck) { $additionalParams = static::signLicenseRequest($additionalParams, static::getLicense()); } $host = $this->getServiceHost(); $http = new HttpClient(array('socketTimeout' => $this->httpTimeout)); $postResult = @$http->post( $host.static::REST_URI.$methodName, $additionalParams ); try { $answer = $this->prepareAnswer($postResult); } catch(\Exception $e) { $answer = false; } if (!is_array($answer)) { $result->addError(new Error(Loc::getMessage('SALE_SRV_BASE_REST_ANSWER_ERROR').' '.$this->getServiceHost().'. (Status: "'.$http->getStatus().'", Result: "'.$postResult.'")', static::ERROR_SERVICE_UNAVAILABLE)); $this->setLastUnSuccessCallInfo(); return $result; } if(self::getLastUnSuccessCount() > 0) $this->setLastUnSuccessCallInfo(true); if (array_key_exists('error', $answer)) { if ($answer['error'] === 'verification_needed') { if($licenseCheck) { $result->addError(new Error($answer['error'].". ".$answer['error_description'], self::ERROR_WRONG_LICENSE)); return $result; } else { return $this->call($methodName, $additionalParams, true); } } else if (($answer['error'] === 'ACCESS_DENIED' || $answer['error'] === 'Invalid client' || $answer['error'] === 'NO_AUTH_FOUND') && !$clearAccessSettings) { return $this->call($methodName, $additionalParams, true, true); } $result->addError(new Error($answer['error'].". ".$answer['error_description'])); return $result; } if ($answer['result'] == false) $result->addError(new Error('Nothing found', static::ERROR_NOTHING_FOUND)); if (is_array($answer['result'])) $result->addData($answer['result']); return $result; } /** * @return string Host. * Define const SALE_SRVS_RESTCLIENT_SRV_HOST to change server host. */ public function getServiceHost() { if(!defined('SALE_SRVS_RESTCLIENT_SRV_HOST')) $result = $this->serviceHost; else $result = SALE_SRVS_RESTCLIENT_SRV_HOST; return $result; } /** * Decodes answer of the method. * @param string $result Json-encoded answer. * @return array|bool|mixed|string Decoded answer. */ protected function prepareAnswer($result) { return Json::decode($result); } /** * Registers client on the properties service. * @return Result */ protected function register() { $result = new Result(); $httpClient = new HttpClient(); $queryParams = array( "scope" => static::SCOPE, "redirect_uri" => static::getRedirectUri(), ); $queryParams = static::signLicenseRequest($queryParams, static::getLicense()); $host = $this->getServiceHost(); $postResult = $httpClient->post($host.static::REGISTER_URI, $queryParams); if ($postResult === false) { $result->addError(new Error(implode("\n", $httpClient->getError()), static::ERROR_SERVICE_UNAVAILABLE)); return $result; } try { $jsonResult = Json::decode($postResult); } catch(Exception $e) { $result->addError(new Error($e->getMessage())); return $result; } if($jsonResult["error"]) $result->addError(new Error($jsonResult["error"], static::ERROR_WRONG_LICENSE)); else $result->addData($jsonResult); return $result; } public static function signLicenseRequest(array $request, $licenseKey) { if(Loader::includeModule('bitrix24')) { $request['BX_TYPE'] = 'B24'; $request['BX_LICENCE'] = BX24_HOST_NAME; $request['BX_HASH'] = \CBitrix24::RequestSign(md5(implode("|", $request))); } else { $request['BX_TYPE'] = ModuleManager::isModuleInstalled('intranet') ? 'CP' : 'BSM'; $request['BX_LICENCE'] = md5("BITRIX".$licenseKey."LICENCE"); $request['BX_HASH'] = md5(md5(implode("|", $request)).md5($licenseKey)); } return $request; } /** * Stores access credentials. * @param array $params Access credentials. * @return void */ protected static function setAccessSettings(array $params) { Option::set('sale', static::SERVICE_ACCESS_OPTION, serialize($params)); } /** * Reads and returns access credentials. * @return array|false Access credentials or false in case of errors. */ protected function getAccessSettings() { $accessSettings = Option::get('sale', static::SERVICE_ACCESS_OPTION); if($accessSettings != '') { $accessSettings = unserialize($accessSettings); if($accessSettings) return $accessSettings; else $this->clearAccessSettings(); } /** @var Result $result */ $result = $this->register(); if($result->isSuccess()) { $accessSettings = $result->getData(); $this->setAccessSettings($accessSettings); return $accessSettings; } else { return array(); } } /** * Drops current stored access credentials. * @return void */ public function clearAccessSettings() { Option::set('sale', static::SERVICE_ACCESS_OPTION, null); } /** * Internal method for usage in registration process. * @return string URL of the host. */ protected static function getRedirectUri() { $request = Context::getCurrent()->getRequest(); $host = $request->getHttpHost(); $isHttps = $request->isHttps(); return ($isHttps ? 'https' : 'http').'://'.$host."/"; } /** * Returns md5 hash of the license key. * @return string md5 hash of the license key. */ protected static function getLicenseHash() { return md5(static::getLicense()); } protected static function getLicense() { return LICENSE_KEY; } protected static function getLastUnSuccessCallInfo() { $result = Option::get('sale', static::UNSUCCESSFUL_CALL_OPTION, ""); if(strlen($result) > 0) $result = unserialize($result); return is_array($result) ? $result : array(); } /** * @param bool|false $reset */ protected static function setLastUnSuccessCallInfo($reset = false) { static $alreadySetted = false; if($alreadySetted && !$reset) return; $data = ""; if(!$reset) { $alreadySetted = true; $last = static::getLastUnSuccessCallInfo(); $data = serialize(array( 'COUNT' => intval($last['COUNT']) > 0 ? intval($last['COUNT'])+1 : 1, 'TIMESTAMP' => time() )); } Option::set('sale', static::UNSUCCESSFUL_CALL_OPTION, $data); } /** * Check if server is alive. * @return bool */ public static function isServerAlive() { $last = static::getLastUnSuccessCallInfo(); if(empty($last)) return true; if(time() - intval($last['TIMESTAMP']) >= self::UNSUCCESSFUL_CALL_WAIT_INTERVAL) return true; if(intval($last['COUNT']) <= self::UNSUCCESSFUL_CALL_TRYINGS) return true; return false; } /** * @return int Counts */ protected function getLastUnSuccessCount() { $last = static::getLastUnSuccessCallInfo(); return intval($last['COUNT']) > 0 ? intval($last['COUNT']) : 0; } }