403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sberbank.ecom2/lib/rbs/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sberbank.ecom2/lib/rbs/Gateway.php
<?php

namespace Sberbank\Payments;

// version: 1.0.13
// date: 2025-03-14

use Bitrix\Main\Web;
use DateTime;

define('LOG_FILE', realpath(dirname(dirname(dirname(__FILE__)))) . "/logs/sberbank.log");
define('SBERBANK_CACERT_FILE', realpath(dirname(dirname(dirname(__FILE__)))) . "/cacert.cer");

// 0 - заказ зарегистрирован, но не оплачен;
// 1 - предавторизованная сумма удержана (для двухстадийных платежей);
// 2 - проведена полная авторизация суммы заказа;
// 3 - авторизация отменена;
// 4 - по транзакции была проведена операция возврата;
// 5 - инициирована авторизация через сервер контроля доступа банка-эмитента;
// 6 - авторизация отклонена.

// 1 = approved - операция удержания (холдирования) суммы;
// 6 = declinedByTimeout - операция отклонения заказа по истечении его времени жизни;
// 2 = deposited - операция завершения;
// 3 = reversed - операция отмены;
// 4 = refunded - операция возврата.

class Gateway
{

	const log_file = LOG_FILE;

	const cacert_file = SBERBANK_CACERT_FILE;
	const PHONE_VALIDATION_PATTERN = '/^\+?[0-9]{0,15}$/';
	
	/**
	 * Массив с НДС
	 *
	 * @var integer
	 * 0 = Без НДС
	 * 1 = НДС по ставке 0%
	 * 2 = НДС чека по ставке 10%
	 * 3 = НДС чека по ставке 18%
	 * 4 = НДС чека по ставке 10/110
	 * 6 = НДС чека по ставке 20%
	 * 7 = НДС чека по ставке 20/120
	 * 10 = НДС по ставке 5%
	 * 11 = НДС по расчетной ставке 5/105
	 * 12 = НДС по ставке 7%
	 * 13 = НДС по расчетной ставке 7/107
	 */

    private static $arr_tax = array(
		1 => 0,
		2 => 10,
		3 => 18,
		6 => 20,
		10 => 5,
		12 => 7, 
    );

	private $gate_url;

	private $basket = array();

	private $data = array();

	private $options = array(
		'gate_url_prod' => '',
		'gate_url_test' => '',
		'payment_link' => '',
		'ofd_enabled' => false,
		'module_version' => 'def',
		'language' => 'ru',
		'ofd_tax' => 0,
		'handler_two_stage' => 0,
		'default_cartItem_tax' => 6,
		'delivery' => false,
		'handler_logging' => true,
		'customer_phone' => '',
		'customer_email' => '',
		'customer_name' => '',
		'callback_redirect' => 0,
		'domain_found' => false,
		'callback_url' => '',
		'additionalOfdParams' => array(),
		'ffd_version' => '1.05',
		'measurement_code' => 0,
		'ignore_product_tax' => false,
		'callback_mode' => true,

		'enable_cacert' => false,
		'request_method' => 'curl', // curl || httpClient
		'callback_actions' => [],
		'callback_action_order_status' => [],
		'callback_operation' => false,
		'callback_operations' => ['deposited', 'approved', 'reversed', 'refunded', 'declinedByTimeout'],
		'fes_cashboxId' => '',
		'gate_url_alternative_prod' => '',
		'gate_url_alternative_test' => '',
		'callback_type' => 'DYNAMIC', // DYNAMIC | STATIC
		// 'enable_phone_validation' => false,
		'enable_order_payer_data' => true,

	);

	// FFD 1.2
	static $measureList = array(
		0 => 'шт',
		1 => 'ед', // alternate 0 value
		10 => 'г',
		11 => 'кг',
		12 => 'т',
		20 => 'см',
		21 => 'дм',
		22 => 'м',
		30 => 'кв.см',
		31 => 'кв.дм',
		32 => 'кв.м',
		40 => 'мл',
		41 => 'л',
		255 => '-',
	);


	public function buildData($data)
	{
		foreach ($data as $key => $value) {
			$this->data[$key] = $value;
		}
	}


	public function setOptions($data)
	{
		foreach ($data as $key => $value) {
			$this->options[$key] = $value;
		}
	}


	public function registerOrder()
	{
		$this->transformPrices();
		$orderPayerData = array();
		$json_params = array(
			'CMS' => $this->options['cms_version'],
			'Module-Version' => $this->options['module_version'],
			'USER_FIO' => $this->options['customer_name'],
		);

		if (strlen($this->options['customer_email']) > 3) {
			$json_params['email'] = $this->options['customer_email'];
		}
		if ($this->isIssetPhone($this->options['customer_phone'])) {
			$json_params['phone'] = $this->formatPhone($this->options['customer_phone']);
		   	$orderPayerData['mobilePhone'] = $this->formatPhone($this->options['customer_phone']);
		}
		if($this->options['fes_cashboxId'] && strlen($this->options['fes_cashboxId']) > 3) {
			$json_params['fes_cashboxId'] = $this->options['fes_cashboxId'];
		}
		$this->buildData(array(
			'CMS' => $this->options['cms_version'],
			'language' => $this->options['language'],
			'jsonParams' => Web\Json::encode($json_params),
		));
		
		if($this->options['enable_order_payer_data'] && count($orderPayerData)) {
			$this->buildData(array(
				'orderPayerData' => Web\Json::encode($orderPayerData),
			));
		}

		$gateData = $this->data;
		$orderId = $this->data['orderNumber'];
		$callback_actions = implode(",", array_keys($this->options['callback_actions']));

		for ($i = 0; $i < 30; $i++) {

			$gateData['orderNumber'] = $orderId . "_" . $i;
			$method = 'getOrderStatusExtended.do';
			$gateResponse = $this->setRequest($method, array(
				'userName' => $gateData['userName'],
				'password' => $gateData['password'],
				'orderNumber' => $gateData['orderNumber']
			));

			if ($gateResponse['amount'] != $gateData['amount'] && $gateResponse['errorCode'] != 6 && $gateResponse['errorCode'] == 0) {
				continue;
			}
			if ($gateResponse['errorCode'] == 6) {

				// register order from gate
				if ($this->ofdEnable()) {
					$this->addFFDParams();
					$gateData = $this->addOrderBundle($gateData);
					if (isset($this->options['additionalOfdParams']) && count($this->options['additionalOfdParams']) > 0) {
						$gateData['additionalOfdParams'] = json_encode($this->options['additionalOfdParams']);
					}
				}
				$method = $this->options['handler_two_stage'] ? 'registerPreAuth.do' : 'register.do';
				$gateResponse = $this->setRequest($method, $gateData);

				if ($this->options['domain_found'] && $this->options['callback_mode']) {
					$this->updateCallback([
						'login' => $this->data['userName'],
						'password' => $this->data['password'],
						'test_mode' => $this->options['test_mode'],
						'callback_type' => $this->options['callback_type'],
						'callback_http_method' => 'GET',
						'callbacks_enabled' => true,
						'callback_addresses' => $this->options['callback_url'],
						'callback_operations' => $callback_actions
					]);
				}
				if ($gateResponse['errorCode'] == 0) {
					$this->setRequest('addParams.do', array(
						'userName' => $this->data['userName'],
						'password' => $this->data['password'],
						'orderId' => $gateResponse['orderId'],
						'language' => $this->options['language'],
						'params' => Web\Json::encode(array('formUrl' => $gateResponse['formUrl'])),
					));

					$this->createPaymentLink($gateResponse['formUrl'], 'register.do');
				}
				break;
			} else if ($gateResponse['errorCode'] == 0 && $gateResponse['orderStatus'] == 0) {
				// return and build payment link already registered order from gate
				foreach ($gateResponse['merchantOrderParams'] as $key => $item) {
					if ($item['name'] == 'formUrl') {
						$this->createPaymentLink($item['value'], 'getOrderStatusExtended.do');
						break;
					}
				}

				break;
			} else if ($gateResponse['errorCode'] == 0 && $gateResponse['orderStatus'] == 2 && $gateResponse['amount'] == $gateData['amount']) {
				// order allready payed
				$gateResponse = array('payment' => 1);
				break;
			} else if ($gateResponse['errorCode'] != 0) {
				break;
			}
		}

		if ($gateResponse['errorCode'] != 0) {
			$this->baseLogger($this->gate_url, $method, $gateData, $gateResponse, 'REGISTER_ERROR');
		} else if (($method == 'registerPreAuth.do' || $method == 'register.do') && $this->options['handler_logging']) {
			$this->baseLogger($this->gate_url, $method, $gateData, $gateResponse, 'REGISTER_NEW_ORDER');
		}

		return $gateResponse;
	}


	public function checkOrder()
	{
		$gateData = $this->data;
		$gateResponse = $this->setRequest('getOrderStatusExtended.do', $gateData);

		if ($this->options['handler_logging']) {
			$title = $this->options['callback_redirect'] ? 'CALLBACK_RETURN' : 'USER_RETURN';
			$this->baseLogger($this->gate_url, 'getOrderStatusExtended.do', $gateData, Web\Json::encode($title == 'USER_RETURN' ? array('orderNumber' => $gateResponse['orderNumber']) : $gateResponse, JSON_UNESCAPED_UNICODE), $title);
		}
		return $gateResponse;
	}


	public function refund()
	{
		$gateData = $this->data;

		$gateResponse = $this->setRequest('refund.do', $gateData);

		if ($this->options['handler_logging']) {
			$this->baseLogger($this->gate_url, 'refund.do', $gateData, Web\Json::encode($gateResponse), 'REFUND');
		}
		return $gateResponse;
	}


	public function deposit()
	{
		$gateData = $this->data;
		$gateResponse = $this->setRequest('deposit.do', $gateData);

		if ($this->options['handler_logging']) {
			$this->baseLogger($this->gate_url, 'deposit.do', $gateData, Web\Json::encode($gateResponse), 'DEPOSIT');
		}
		return $gateResponse;
	}


	public function ofdEnable()
	{
		if ($this->options['ofd_enabled'] == true) {
			return true;
		}
		return false;
	}


	public function setPosition($position)
	{
		array_push($this->basket, $position);
	}


	public function getBasket()
	{
		return $this->basket;
	}


	public function getTaxCode($tax_rate) {
		$result = $this->options['default_cartItem_tax'];

		if(!$this->options['ignore_product_tax']) {
			if($tax_rate === null) {
				return 0;
			}
			$tax_rate = $tax_rate * 100;
			foreach (self::$arr_tax as $key => $value) {
				if($value == $tax_rate) {
					$result = $key;
				}
			}
		}
		           
		return $result;
	}


	public function getTaxCodeDelivery($tax_rate)
	{
		$result = 0;
		if($tax_rate === null) {
			return 0;
		}
		$tax_rate = $tax_rate;
		foreach (self::$arr_tax as $key => $value) {
			if ($value == $tax_rate) {
				$result = $key;
			}
		}

		return $result;
	}


	public function getCurrencyCode($currency)
	{
		$result = 0;
		foreach ($this->options['iso'] as $key => $value) {

			if ($key == $currency) {
				$result = $value;
			}
		}
		return $result;
	}


	private function addFFDParams() 
	{

		foreach ($this->basket as $key => $item) {

			if($this->options['delivery'] && count($this->basket) == $key+1) {
				$paymentMethod = $this->options['ffd_payment_method_delivery'] ? $this->options['ffd_payment_method_delivery'] : 1;
				$paymentObject = $this->options['ffd_payment_object_delivery'] ? $this->options['ffd_payment_object_delivery'] : 4;
			} else {
				$paymentMethod = $this->options['ffd_payment_method'];
				$paymentObject = $this->options['ffd_payment_object'];
			}
			
			$this->basket[$key]['itemAttributes'] = array(
                'attributes' => array(
                    array(
                        'name' => 'paymentMethod',
                        'value' => $paymentMethod,
                    ),
                    array(
                        'name' => 'paymentObject',
                        'value' => $paymentObject,
                    ),
                )
            );

			if(isset($this->basket[$key]['supplier_info'])) {
				 $this->basket[$key]['itemAttributes']['attributes'][] = array(
				 	'name' => 'supplier_info.name',
                    'value' => $this->basket[$key]['supplier_info']['name'],
				 );
				 $this->basket[$key]['itemAttributes']['attributes'][] = array(
				 	'name' => 'supplier_info.inn',
					'value' => $this->basket[$key]['supplier_info']['inn'],
				 );
			}
			unset($this->basket[$key]['supplier_info']);

			if(isset($this->basket[$key]['nomenclature'])) {
				if($this->basket[$key]['nomenclature']) {
					$this->basket[$key]['itemAttributes']['attributes'][] = array(
						'name' => 'nomenclature',
						'value' => $this->basket[$key]['nomenclature'],
					);
				}
			}
			unset($this->basket[$key]['nomenclature']);

			if($this->options['ffd_version'] == '1.2') {
				$this->basket[$key]['quantity']['measure'] = strval($this->options['measurement_code']);
			}

			if($item['fes_truCode']) {
				$this->basket[$key]['itemDetails']['itemDetailsParams'][] = array(
					'name' => 'fes_truCode',
                    'value' => $item['fes_truCode'],
				);
			}
			unset($this->basket[$key]['fes_truCode']);

		}
	}


	private function transformMeasure($value)
	{
		$result = array_search($value, $this->measureList);
		if ($result == 1) {
			return '0';
		}
		return $result ? strval($result) : strval($this->options['measurement_code']);
	}



	private function setRequest($method, $data)
	{

		global $APPLICATION;

		$this->gate_url = $this->options['test_mode'] ?  $this->options['gate_url_test'] : $this->options['gate_url_prod'];
		$request_url = $this->gate_url . $method;

		if (mb_strtoupper(SITE_CHARSET) != 'UTF-8') {
			$data = $APPLICATION->ConvertCharsetArray($data, 'windows-1251', 'UTF-8');
		}


		if ($this->options['request_method'] === 'curl' && function_exists('curl_init')) {
			$headers = array(
				'CMS: ' . $this->options['cms_version'],
				'Module-Version: ' . $this->options['module_version'],
			);
			$response = $this->requestByCurl($request_url, $data, $headers);
		} else {
			$response = $this->requestByHttpClient($request_url, $data);
		}


		return $response;
	}

	private function requestByHttpClient($url, $data)
	{
		$http = new Web\HttpClient();
		$http->setCharset("utf-8");
		// $http->setHeader('CMS: ', $this->options['cms_version']);
		// $http->setHeader('Module-Version: ', $this->options['module_version']);
		$http->disableSslVerification();
		$http->post($url, $data);

		$response =  $http->getResult();

		if ($this->is_json($response)) {
			$response =  Web\Json::decode($response);
		} else {
			$response = array(
				'errorCode' => 999,
				'errorMessage' => 'Server not available',
			);
			//var_dump( $http->getError() );
			//var_dump( $http->getStatus() );
			//var_dump( $http->getHeaders() );
		}

		if (mb_strtoupper(SITE_CHARSET) != 'UTF-8') {
			$APPLICATION->ConvertCharsetArray($response, 'UTF-8', 'windows-1251');
		}

		return $response;
	}

	private function requestByCurl($url, $data, $headers = array(), $ca_info = null)
	{

		$ca_info = self::cacert_file;

		$curl_opt = array(
			CURLOPT_HTTPHEADER => $headers,
			CURLOPT_VERBOSE => true,
			CURLOPT_SSL_VERIFYHOST => false,
			CURLOPT_URL => $url,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_POST => true,
			CURLOPT_POSTFIELDS => $data,
			CURLOPT_HEADER => false,
		);

		$ssl_verify_peer = false;
		if ($this->options['enable_cacert'] === true && file_exists($ca_info)) {
			$ssl_verify_peer = true;
			$curl_opt[CURLOPT_CAINFO] = $ca_info;
		}

		$curl_opt[CURLOPT_SSL_VERIFYPEER] = $ssl_verify_peer;
		$ch = curl_init();
		curl_setopt_array($ch, $curl_opt);
		$response = curl_exec($ch);


		if ($this->is_json($response)) {
			$response = json_decode($response, true);
		} else {
			$response = array(
				'errorCode' => 999,
				'errorMessage' => curl_error($ch),
			);
		}

		// echo htmlentities(substr($response, 0, $header_size)) . "<br/>";
		// echo htmlentities(substr($response, $header_size)) . "<hr/>";
		curl_close($ch);
		// return substr($response, $header_size);
		return $response;
	}



	private function is_json($string, $return_data = false)
	{
		$data = json_decode($string);
		return (json_last_error() == JSON_ERROR_NONE) ? ($return_data ? $data : TRUE) : FALSE;
	}


	private function addOrderBundle($data)
	{
		$data['orderBundle']['customerDetails'] = array(
			'email' => $this->options['customer_email'],
		);
		if ($this->isIssetPhone($this->options['customer_phone'])) {
			$data['orderBundle']['customerDetails']['phone'] = $this->formatPhone($this->options['customer_phone']);
		}
		$data['orderBundle']['cartItems']['items'] = $this->basket;
		$data['taxSystem'] = $this->options['ofd_tax'];

		$data['orderBundle'] = Web\Json::encode($data['orderBundle']);
		return $data;
	}


	private function transformPrices()
	{
		$this->data['amount'] = $this->data['amount'] * 100;
		if (is_float($this->data['amount'])) {
			$this->data['amount'] = round($this->data['amount']);
		}
		if ($this->ofdEnable()) {
			foreach ($this->basket as $key => $item) {
				$this->basket[$key]['itemPrice'] = round($item['itemPrice'] * 100);
				$this->basket[$key]['itemAmount'] = round($item['itemAmount'] * 100);
			}
		}
	}


	private function createPaymentLink($linkPart, $method)
	{

		if ($method == 'register.do' || $method == 'registerPreAuth.do') {
			$this->options['payment_link'] = $linkPart;
		} else if ($method == 'getOrderStatusExtended.do') {
			$this->options['payment_link'] = $linkPart;
		}
	}


	public function getPaymentLink()
	{
		return $this->options['payment_link'];
	}


	public function debug($data)
	{
		echo "<pre>";
		print_r($data);
		echo "</pre>";
	}


	public function baseLogger($url, $method, $data, $response, $title)
	{
		$objDateTime = new DateTime();
		$file = self::log_file;
		$logContent = '';

		if (file_exists($file)) {
			$logSize = filesize($file) / 1000;
			if ($logSize < 10000) {
				$logContent = file_get_contents($file);
			}
		}
		$operation = $this->options['callback_operation'];
		if ($operation) {
			$operation_value = in_array($operation, $this->options['callback_operations']) ? $operation : '';
		}
		$logContent .= $title . "\n";
		$logContent .= '----------------------------' . "\n";
		$logContent .= "DATE: " . $objDateTime->format("Y-m-d H:i:s") . "\n";
		$logContent .= 'REQUEST_METHOD: ' . $this->options['request_method'] . "\n";
		$logContent .= 'URL ' . $url . "\n";
		$logContent .= 'METHOD ' . $method . "\n";
		$logContent .= $operation_value ? 'CALBACK_OPERATION ' . $operation_value . "\n" : '';



		if ($title != 'USER_RETURN') {
			$logContent .= "DATA: \n" . print_r($data, true) . "\n";
		}
		$logContent .= "RESPONSE: \n" . print_r($response, true) . "\n";

		$logContent .= "\n\n";
		file_put_contents($file, $logContent);
	}

	public function updateCallback($data)
	{
		if (!isset($data['login']) && !isset($data['password'])) {
			return false;
		}

		$data['name'] = str_replace('-api', "", $data['login']);

		if ($data['test_mode'] == 1) {
			$gate_url = $this->options['gate_url_alternative_test'] . "mportal-uat/mvc/public/merchant/";
		} else {
			$gate_url = $this->options['gate_url_alternative_prod'] . "mportal/mvc/public/merchant/";
		}
		$gate_url = $gate_url . 'update/' . $data['name'];


		$http = new Web\HttpClient();
		$http->setHeader('Content-Type', 'application/json');
		$http->setAuthorization($data['login'], $data['password']);
		$http->disableSslVerification();
		$http->post($gate_url, json_encode($data));
		$response =  $http->getResult();


		$this->baseLogger($gate_url, 'update', $data, $response, 'CALLBACK_UPDATE');
		$response = json_decode($response, true);
		if ($response['status'] == 'SUCCESS') {
			return 1;
		} else {
			return 0;
		}
	}


	public function getCallback($data)
	{
		if (!isset($data['login']) && !isset($data['password'])) {
			return false;
		}

		$data['name'] = str_replace('-api', "", $data['login']);

		if ($data['test_mode'] == 1) {
			$gate_url = $this->options['gate_url_alternative_test'] . "mportal-uat/mvc/public/merchant/";
		} else {
			$gate_url = $this->options['gate_url_alternative_prod'] . "mportal/mvc/public/merchant/";
		}
		$gate_url = $gate_url . 'get/' . $data['name'];


		$http = new Web\HttpClient();
		$http->setHeader('Content-Type', 'application/json');
		$http->setAuthorization($data['login'], $data['password']);
		$http->disableSslVerification();
		$http->post($gate_url, json_encode($data));
		$response =  $http->getResult();


		// $this->baseLogger($gate_url, 'get', $data, $response,'CALLBACK_GET');
		$response = json_decode($response, true);
		if ($response && $response['status'] == 'SUCCESS') {
			return $response['callback_addresses'];
		}
		return false;
	}


	public function broadcast_callback($url, $params)
	{
		$data = http_build_query($params);
		$result_url = strpos($url, '?') ? $url . '&' . $data : $url . '?' . $data;
		$http = new Web\HttpClient();
		$http->get($result_url);
		$response =  $http->getResult();
		$this->baseLogger($result_url, '', '', '', 'CALLBACK_BROADCAST');
	}

	public function closeOfdReceipt($data) {
		$this->buildData(array(
			'mdOrder' => $data['mdOrder'],
			'amount' => $data['amount'],
			'userName' => $data['userName'],
			'password' => $data['password'],
		));

		$this->transformPrices();
		$gateData = $this->data;

		if($this->ofdEnable()) {
			$this->addFFDParams();
			$gateData = $this->addOrderBundle($this->data);
		}

		if($gateData) {
			$gateResponse = $this->setRequest('closeOfdReceipt.do', $gateData);
		} else if($this->options['handler_logging']) {
			$this->baseLogger($this->gate_url, 'closeOfdReceipt.do', json_encode($gateData), '', 'CLOSE_OFD_ERROR');
		}

		if($this->options['handler_logging']) {
			$log_method_name = $this->ofdEnable() ? 'CLOSE_OFD_RECEIPT+ORDER_BUNDLE' : 'CLOSE_OFD_RECEIPT';
			$this->baseLogger($this->gate_url, 'closeOfdReceipt.do', $gateData, Web\Json::encode($gateResponse), $log_method_name);
		}
		return $gateResponse;
	}

	/**
	 * Форматирование номера телефона
	 * 
	 * @param string $phone Номер телефона
	 * @return string Отформатированный номер телефона
	 */
	private function formatPhone($phone)
	{
	    if (empty($phone)) {
	        return '';
	    }

	    $phone = preg_replace('/[^0-9+]/', '', $phone);
	    $phone = preg_replace('/^\+7/', '', $phone);
	    
	    return $phone;
	}
	private function isIssetPhone($phone)
	{
		return strlen($this->options['customer_phone']) > 1;
	}

}

Youez - 2016 - github.com/yon3zu
LinuXploit