· 7 years ago · Feb 08, 2018, 12:58 PM
1<?php
2namespace rsb;
3
4use Exception;
5
6define(__NAMESPACE__ . '\DS', DIRECTORY_SEPARATOR);
7define(__NAMESPACE__ . '\SAVE_LOG', false);
8
9
10abstract class CMainCurl
11{
12 /**
13 * @var array
14 */
15 private $headers = [];
16 /**
17 * @var array
18 */
19 private $options = [];
20 /**
21 * @var null|resource
22 */
23 private $ch = null;
24
25 /**
26 * @return CMainCurl
27 */
28 protected function clearHeaders()
29 {
30 $this->headers = [];
31 return $this;
32 }
33
34 /**
35 * @return CMainCurl
36 */
37 protected function clearOptions()
38 {
39 $this->options = [];
40 return $this;
41 }
42
43 /**
44 * @param string $key
45 * @param string $value
46 * @return CMainCurl
47 */
48 protected function addOption($key, $value)
49 {
50 $this->options[$key] = $value;
51 return $this;
52 }
53
54 /**
55 * @return bool
56 */
57 protected function setOptions()
58 {
59 return \curl_setopt_array($this->ch, $this->getOptions());
60 }
61
62 /**
63 * @return array
64 */
65 protected function getOptions()
66 {
67 return $this->options;
68 }
69
70 /**
71 * @param string $key
72 * @param string $value
73 * @return bool
74 */
75 protected function addHeader($key, $value)
76 {
77 if (isset($this->headers[$key]) === true) {
78 return false;
79 }
80 $this->headers[$key] = $value;
81 return true;
82 }
83
84 /**
85 * @return array|bool
86 */
87 protected function getHeaderArrayCurl()
88 {
89 if (empty($this->headers) === true)
90 return false;
91 $result = [];
92 foreach ($this->headers as $nameHeader => $value) {
93 $result[] = $nameHeader . ': ' . $value;
94 }
95
96 return $result;
97 }
98
99 /**
100 * @param string|null $url
101 * @return false|resource
102 */
103 protected function createConnection($url = null)
104 {
105 return ($this->ch = \curl_init($url));
106 }
107
108 /**
109 * @return string|false
110 */
111 protected function executeConnection()
112 {
113 $execute = \curl_exec($this->ch);
114
115 return $execute;
116 }
117
118 /**
119 * @param string $login
120 * @param string $password
121 * @return bool
122 */
123 protected function setBasicAuth($login, $password)
124 {
125 return \curl_setopt($this->ch, \CURLOPT_USERPWD, $login . ':' . $password);
126 }
127
128 /**
129 * @return string
130 */
131 protected function getError()
132 {
133 return \curl_error($this->ch);
134 }
135
136 /**
137 * @param int|null $opt
138 * @return mixed
139 */
140 protected function getInfo($opt = null)
141 {
142 return \curl_getinfo($this->ch, $opt);
143 }
144
145 /**
146 * close Curl connection
147 */
148 protected function closeConnection()
149 {
150 \curl_close($this->ch);
151 }
152}
153
154interface ErrorsCodeCurl
155{
156 const OMG32423 = [
157 'ERROR' => 1,
158 ];
159}
160
161interface ErrorsCodeOpenSSL
162{
163 const OMG = [
164 'ERROR' => 1,
165 ];
166}
167
168final class BankException extends \Exception implements ErrorsCodeCurl, ErrorsCodeOpenSSL
169{
170 public function __construct($message = '', $code = 0, Exception $previous = null)
171 {
172 parent::__construct($message, $code, $previous);
173 }
174}
175
176final class CRsbBank extends CMainCurl
177{
178 const HOST = '194.67.29.216:8443';
179 const URL = 'https://' . self::HOST . '/';
180
181 const PRIVATE_KEY_FILE_EXPANSION = '.key';
182 const OPENSSL_ALGO = \OPENSSL_ALGO_SHA1;
183 const RESPONSE_CHARSET = 'windows-1251';
184 const DEFAULT_CHARSET = 'utf-8';
185
186
187 private static $listUser = [
188 'LIZING' => [
189 'login' => 'LIZING',
190 'password' => 'LIZING',
191 'passwordPrivateKey' => 'LIZING',
192 ],
193 'STARLIZING' => [
194 'login' => 'STARLIZING',
195 'password' => 'STARLIZING',
196 'passwordPrivateKey' => 'STARLIZING',
197 ],
198 ];
199
200 public function __construct()
201 {
202// static::OMG['ERROR'];
203 }
204
205 public function generateRequest($params, $user)
206 {
207 @set_time_limit(0);
208// header('Content-type: application/xml; charset=windows-1251');
209 header('Content-type: text/html; charset=' . self::RESPONSE_CHARSET);
210 $dataXmlString = $this->generateRequestData($params);
211
212// echo $dataXmlString;
213// var_dump($dataXmlString);
214// die();
215 $signature = $this->generateSignature($dataXmlString, $user, true);
216
217 $fullXml = $this->generateXML([
218 'requestString' => $dataXmlString,
219 'signatureString' => $signature,
220 ], 'request_full');
221
222 echo $fullXml, "\n\n\n";
223 if (SAVE_LOG === true) {
224 \logger\CLogger::addLog('bank_rsb',
225 'Тіло запиту:', $dataXmlString,
226 'ПідпиÑ:', $signature,
227 'Повний xml:', $fullXml);
228 }
229 $result = $this->send($fullXml, $user);
230 echo $result;
231 //todo обробка відповіді
232 $parseResult = $this->parseResult($result);
233 }
234
235
236 private function generateRequestData($params)
237 {
238 //todo Ð²Ð°Ð»Ñ–Ð´Ð°Ñ†Ñ–Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ–Ð²
239 $xml = $this->generateXML($params, 'request_body');
240 return $xml;
241 }
242
243 private function basicAuth($user)
244 {
245 if (empty($user) === true || $this->checkUser($user) === false) {
246 throw new \Exception('Ðе переданий кориÑтувач/КориÑтувач не знайдений');
247 }
248
249 $userData = $this->getUser($user);
250 return parent::setBasicAuth($userData['login'], $userData['password']);
251 }
252
253 private function send($requestXml, $user)
254 {
255 if (empty($user) === true) {
256 throw new \Exception('Ðе переданий $user');
257 }
258
259 if ($this->createConnection(self::URL) === false) {
260 throw new \Exception('Ðе можу Ñтворити curl:' . self::URL);
261 }
262 $this->clearHeaders();
263 $this->addHeader('Content-Type', 'text/xml');
264 $this->addHeader('Accept', 'text/xml');
265 $this->addHeader('Accept-Encoding', '*');
266 $this->addHeader('Pragma', 'no-cache');
267 $this->addHeader('User-Agent', 'Mozilla/4.0');
268 $this->addHeader('Cache-Control', 'no-cache');
269 $this->addHeader('Host', self::HOST);
270
271 $contentLength = \mb_strlen($requestXml, '8bit');
272 $this->addHeader('Content-Length', $contentLength);
273
274 $this->addHeader('Expect', '100-continue');
275 $this->addHeader('Connection', 'Keep-Alive');
276
277 $this->clearOptions()
278 ->addOption(\CURLINFO_HEADER_OUT, true)
279 ->addOption(\CURLOPT_RETURNTRANSFER, true)
280 ->addOption(\CURLOPT_POST, true)
281 ->addOption(\CURLOPT_POSTFIELDS, $requestXml)
282 ->addOption(\CURLOPT_CONNECTTIMEOUT, 60)
283 ->addOption(\CURLOPT_TIMEOUT, 60)
284 ->addOption(\CURLOPT_VERBOSE, true)
285 ->addOption(\CURLOPT_SSL_VERIFYHOST, 2)
286 ->addOption(\CURLOPT_SSL_VERIFYPEER, false)
287 ->addOption(\CURLOPT_HTTPHEADER, $this->getHeaderArrayCurl())
288 ->setOptions();
289
290 $this->basicAuth($user);
291 if (($data = $this->executeConnection()) === false) {
292 if (SAVE_LOG === true) {
293 \logger\CLogger::addLog('bank_rsb', 'CUrl не получив відповіді:', $this->getError(), $this->getInfo());
294 }
295
296 $this->closeConnection();
297 throw new \Exception('CUrl не получив відповіді:', $this->getError(), $this->getInfo());
298 }
299 $this->closeConnection();
300
301 return $data;
302 }
303
304 private function parseResult($xml)
305 {
306 if (empty($xml) === true) {
307 throw new \Exception('Переданий пуÑьтив xml відповіді');
308 }
309 if (($xmlObjectResponse = \simplexml_load_string($xml, 'SimpleXMLElement')) === false) {
310 throw new \Exception('Ðе мову відкрити XML, Ñкий прийшов у відповідь');
311 }
312
313 return $xmlObjectResponse;
314 }
315
316 private function generateXML($params, $file)
317 {
318 if (empty($params) === true || \is_array($params) === false) {
319 throw new \Exception('$params error:' . \print_r($params, true));
320 }
321
322 if (empty($file) === true) {
323 throw new \Exception('FileName is empty:' . $file);
324 }
325
326 $filePath = __DIR__ . DS . 'xml' . DS . $file . '.php';
327 if (\file_exists($filePath) === false) {
328 throw new \Exception('Файл не найдет:' . $filePath);
329 }
330
331 \ob_start();
332 \extract($params);
333 require($filePath);
334 $xml = \ob_get_clean();
335
336 return $xml;
337 }
338
339
340 private function generateSignature($xml, $user, $binToHex = true)
341 {
342 if (empty($xml) === true) {
343 throw new \Exception('Переданий пуÑтий xml.');
344 }
345 if (empty($user) === true || $this->checkUser($user) === false) {
346 throw new \Exception('Ðе переданий кориÑтувач/КориÑтувач не знайдений');
347 }
348
349 $pathToKey = __DIR__ . DS . 'privateKey' . DS . \mb_strtolower($user) . self::PRIVATE_KEY_FILE_EXPANSION;
350
351 if (\file_exists($pathToKey) === false) {
352 throw new \Exception('Ðе знайдений файл із приватним ключем:' . $pathToKey);
353 }
354
355 if (($privateKey = \file_get_contents($pathToKey)) === false) {
356 throw new \Exception('Ðе можу прочитати файл:' . $pathToKey);
357 }
358
359
360 $userData = $this->getUser($user);
361 if (($secretKey = \openssl_pkey_get_private($privateKey, $userData['passwordPrivateKey'])) === false) {
362 throw new \Exception('Ðе можу получити приватний ключ(openssl_pkey_get_private).');
363 }
364
365 if ((\openssl_sign($xml, $signature, $secretKey, self::OPENSSL_ALGO)) === false) {
366 throw new \Exception('Ðе можу згеренувати підпиÑ(openssl_sign).');
367 }
368
369 if ($binToHex === true) {
370 return \bin2hex($signature);
371 }
372
373 return $signature;
374 }
375
376 /**
377 * @param string $user
378 * @return bool
379 */
380 private function checkUser($user)
381 {
382 //todo перевідка Ñ–ÑÐ½ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача
383 return (isset(self::$listUser[$user]) === true);
384 }
385
386 /**
387 * @param $user
388 * @return array|bool
389 */
390 private function getUser($user)
391 {
392 if ($this->checkUser($user) === true) {
393 return [
394 'login' => self::$listUser[$user]['login'],
395 'password' => self::$listUser[$user]['password'],
396 'passwordPrivateKey' => self::$listUser[$user]['passwordPrivateKey'],
397 ];
398 }
399 return false;
400 }
401
402 /**
403 * @param string $value
404 * @return string
405 */
406 public static function convertToBankCharset($value)
407 {
408 return \iconv(self::DEFAULT_CHARSET, self::RESPONSE_CHARSET, $value);
409 }
410
411 /**
412 * @param string $value
413 * @return string
414 */
415 public static function convertFromBankCharset($value)
416 {
417 return \iconv(self::RESPONSE_CHARSET, self::DEFAULT_CHARSET, $value);
418 }
419}
420
421
422-------------------------------------------------
423
424
425$class = new \rsb\CRsbBank();
426try {
427
428 $class->generateRequest([
429 //зарезервовано
430 'target' => 'client_system',
431 'operation' => 'AddRevPrePaid',
432
433 //ФІО
434 'clientsurname' => \rsb\CRsbBank::convertToBankCharset('Оверчук'),
435 'clientname' => \rsb\CRsbBank::convertToBankCharset('Михаил'),
436 'clientlastname' => \rsb\CRsbBank::convertToBankCharset('Олегович'),
437
438 'sex' => 1,
439 'birthday' => '08.06.1994',
440 'Born_country' => 1,
441 'bornplace' => \rsb\CRsbBank::convertToBankCharset('гор. Тамбов'),
442 'citizenship' => 1,
443 'changefio' => 0,
444 'idresident' => 1,
445 'isAnotherGrajd' => 0,
446 'AgreePersData' => 1,
447
448 /*
449 173: паÑпорт проÑрочен, не Ñовпадает ФИО , дата рождениÑ(еÑли в базе уже еÑть клиент Ñ Ñ‚Ð°ÐºÐ¸Ð¼Ð¸ же паÑпортными данными),недейÑтвительный паÑпорт по данным уфмÑ
450 * */
451 //паÑпорт
452 'docseries' => '7514', //Ð¡ÐµÑ€Ð¸Ñ Ð¿Ð°Ñпорта
453 'docnum' => '461997', //Ðомер паÑпорта
454 'docgive' => \rsb\CRsbBank::convertToBankCharset('отделением ÑƒÑ„Ð¼Ñ Ñ€Ð¾ÑÑии по ЧелÑбинÑкой облаÑти в ЧебаркульÑком районе'), //Кем выдан паÑпорт
455 'docgivedate' => '03.07.2014', //Дата выдачи паÑпорта в формате dd.mm.yyyy (не допуÑкать лишних пробелов)
456 'depcode' => '740-044',
457
458 'country_reg' => 1,
459 'postindex_reg' => 347640,
460 'region_reg' => \rsb\CRsbBank::convertToBankCharset('РоÑтовÑÐºÐ°Ñ Ð¾Ð±Ð»'),
461 'district_reg' => \rsb\CRsbBank::convertToBankCharset('СальÑкий Ñ€-н'),
462 'city_reg' => \rsb\CRsbBank::convertToBankCharset('СальÑк г'),
463 'settlement_reg' => '',
464 'street_reg' => \rsb\CRsbBank::convertToBankCharset('ÐйвазовÑкого'),
465 'street_reg_ext' => \rsb\CRsbBank::convertToBankCharset('ул'),
466 'housenumber_reg' => 8,
467 'housecase_reg' => '',
468 'appartment_reg' => '',
469 'idTimeReg' => 2,
470 'country_post' => 1,
471 'postindex_post' => 347640,
472 'region_post' => \rsb\CRsbBank::convertToBankCharset('РоÑтовÑÐºÐ°Ñ Ð¾Ð±Ð»'),
473 'district_post' => \rsb\CRsbBank::convertToBankCharset('СальÑкий Ñ€-н'),
474 'city_post' => \rsb\CRsbBank::convertToBankCharset('СальÑк г'),
475 'settlement_post' => 1,
476 'street_post' => \rsb\CRsbBank::convertToBankCharset('ÐйвазовÑкого'),
477 'street_post_ext' => \rsb\CRsbBank::convertToBankCharset('ул'),
478 'housenumber_post' => 8,
479 'housecase_post' => 8,
480
481
482 'appartment_post' => '9001260134',
483 'mobilphone' => '9001260134',
484 'POFDeclare' => 0,
485 'isPublicOfficer' => 1,
486 'codeword' => \rsb\CRsbBank::convertToBankCharset('codeword'),
487 'idcard' => '1000282867017',
488 //зарезервовано,завжди 3810
489 'currency' => 3810,
490
491 'amount' => 123.11,//12345.67
492 'transaction_id' => mt_rand(10000, 99999),
493 ], 'STARLIZING');
494} catch (\Exception $error) {
495 //todo має бути код помилки
496 echo 'Error:', $error->getMessage();
497}