index.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. <?php
  2. /**
  3. * Фронтенд для отримання повідомлень про платежі від Приватбанку
  4. *
  5. * Можливе отримання запитів як у вигляді окремої змінної POST, так і у вигляді HTTP_RAW_POST_DATA
  6. */
  7. /**
  8. * Секція налаштувань
  9. */
  10. // Ім`я POST змінної в якій повинні надходити запити, або raw у разі отримання запитів в вигляді HTTP_RAW_POST_DATA.
  11. define('PBX_REQUEST_MODE', 'raw');
  12. // Режим відлагодження - змушує дані підвантажуватись з файлу debug.xml
  13. // (Так-так, кладете туди запит і дивитесь у браузері як на нього відповідає фронтенд)
  14. define('PBX_DEBUG_MODE', false);
  15. // Тексти сповіщень та виключень
  16. define('ISP_CODE', '1'); // Id в платіжній системі
  17. define('ISP_SERVICE_NAME', 'Інтернет'); // Найменування послуги
  18. define('ISP_SERVICE_CODE', '1'); // Код послуги
  19. define('USER_BALANCE_DECIMALS', -1); // Скільки знаків після коми повертати в балансі абонента 0 - повертати лише цілу частину
  20. define('FULL_DEBTINFO', false); // Чи повертати секцію з DebtInfo включаючи amountToPay та debt?
  21. // Виключення
  22. define('PBX_EX_NOT_FOUND', 'Абонента не знайдено');
  23. define('PBX_EX_DUPLICATE', 'Дублювання оплати');
  24. /**
  25. * Кінець секції налаштувань, далі нічого не чіпаємо.
  26. */
  27. error_reporting(E_ALL);
  28. // Підключаємо API OpenPayz
  29. include ("../../libs/api.openpayz.php");
  30. // Трішечки заголовків
  31. header('Last-Modified: ' . gmdate('r'));
  32. header('Content-Type: text/html; charset=utf-8');
  33. header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
  34. header("Pragma: no-cache");
  35. /**
  36. * Check for POST have needed variables
  37. *
  38. * @param $params array of POST variables to check
  39. * @return bool
  40. *
  41. */
  42. function pbx_CheckPost($params) {
  43. $result = true;
  44. if (!empty($params)) {
  45. foreach ($params as $eachparam) {
  46. if (isset($_POST[$eachparam])) {
  47. if (empty($_POST[$eachparam])) {
  48. $result = false;
  49. }
  50. } else {
  51. $result = false;
  52. }
  53. }
  54. }
  55. return ($result);
  56. }
  57. /**
  58. * Returns request data
  59. *
  60. * @return string
  61. */
  62. function pbx_RequestGet() {
  63. $result = '';
  64. if (PBX_REQUEST_MODE != 'raw') {
  65. if (pbx_CheckPost(array(PBX_REQUEST_MODE))) {
  66. $result = $_POST[PBX_REQUEST_MODE];
  67. }
  68. } else {
  69. //$result = $HTTP_RAW_POST_DATA;
  70. $result = file_get_contents('php://input');
  71. }
  72. return ($result);
  73. }
  74. /**
  75. * String entity search
  76. *
  77. * @param $string - string variable to compare
  78. * @param $search - searched substring
  79. * @return bool
  80. */
  81. function pbx_ispos($string, $search) {
  82. if (strpos($string, $search) === false) {
  83. return(false);
  84. } else {
  85. return(true);
  86. }
  87. }
  88. /**
  89. * Returns all user RealNames
  90. *
  91. * @return array
  92. */
  93. function pbx_UserGetAllRealnames() {
  94. $query = "SELECT * from `realname`";
  95. $all = simple_queryall($query);
  96. $result = array();
  97. if (!empty($all)) {
  98. foreach ($all as $io => $each) {
  99. $result[$each['login']] = $each['realname'];
  100. }
  101. }
  102. return($result);
  103. }
  104. /**
  105. * Returns user stargazer data by login
  106. *
  107. * @param string $login existing stargazer login
  108. *
  109. * @return array
  110. */
  111. function pbx_UserGetStargazerData($login) {
  112. $login = mysql_real_escape_string($login);
  113. $query = "SELECT * from `users` WHERE `login`='" . $login . "';";
  114. $result = simple_query($query);
  115. return ($result);
  116. }
  117. /**
  118. * Returns all user mobile phones
  119. *
  120. * @return array
  121. */
  122. function pbx_UserGetAllMobiles() {
  123. $query = "SELECT * from `phones`";
  124. $all = simple_queryall($query);
  125. $result = array();
  126. if (!empty($all)) {
  127. foreach ($all as $io => $each) {
  128. $result[$each['login']] = $each['mobile'];
  129. }
  130. }
  131. return($result);
  132. }
  133. /**
  134. * Returns all tariff prices array
  135. *
  136. * @return array
  137. */
  138. function pbx_TariffGetPricesAll() {
  139. $query = "SELECT `name`,`Fee` from `tariffs`";
  140. $allprices = simple_queryall($query);
  141. $result = array();
  142. if (!empty($allprices)) {
  143. foreach ($allprices as $io => $eachtariff) {
  144. $result[$eachtariff['name']] = $eachtariff['Fee'];
  145. }
  146. }
  147. return ($result);
  148. }
  149. /**
  150. * Returns random numeric string, which will be used as unique transaction hash
  151. *
  152. * @param int $size
  153. * @return int
  154. */
  155. function pbx_GenerateHash($size = 12) {
  156. $characters = '0123456789';
  157. $string = "";
  158. for ($p = 0; $p < $size; $p++) {
  159. $string .= $characters[mt_rand(0, (strlen($characters) - 1))];
  160. }
  161. return ($string);
  162. }
  163. /**
  164. * Returns array of availble user address as login=>address
  165. *
  166. * @return array
  167. */
  168. function pbx_AddressGetFulladdresslist() {
  169. $alterconf['ZERO_TOLERANCE'] = 0;
  170. $alterconf['CITY_DISPLAY'] = 0;
  171. $result = array();
  172. $query_full = "
  173. SELECT `address`.`login`,`city`.`cityname`,`street`.`streetname`,`build`.`buildnum`,`apt`.`apt` FROM `address`
  174. INNER JOIN `apt` ON `address`.`aptid`= `apt`.`id`
  175. INNER JOIN `build` ON `apt`.`buildid`=`build`.`id`
  176. INNER JOIN `street` ON `build`.`streetid`=`street`.`id`
  177. INNER JOIN `city` ON `street`.`cityid`=`city`.`id`";
  178. $full_adress = simple_queryall($query_full);
  179. if (!empty($full_adress)) {
  180. foreach ($full_adress as $ArrayData) {
  181. // zero apt handle
  182. if ($alterconf['ZERO_TOLERANCE']) {
  183. $apartment_filtered = ($ArrayData['apt'] == 0) ? '' : '/' . $ArrayData['apt'];
  184. } else {
  185. $apartment_filtered = '/' . $ArrayData['apt'];
  186. }
  187. if ($alterconf['CITY_DISPLAY']) {
  188. $result[$ArrayData['login']] = $ArrayData['cityname'] . ' ' . $ArrayData['streetname'] . ' ' . $ArrayData['buildnum'] . $apartment_filtered;
  189. } else {
  190. $result[$ArrayData['login']] = $ArrayData['streetname'] . ' ' . $ArrayData['buildnum'] . $apartment_filtered;
  191. }
  192. }
  193. }
  194. return($result);
  195. }
  196. /**
  197. * Returns presearch reply
  198. *
  199. * @return string
  200. */
  201. function pbx_ReplyPresearch($customerid) {
  202. $allcustomers = op_CustomersGetAll();
  203. if (isset($allcustomers[$customerid])) {
  204. $customerLogin = $allcustomers[$customerid];
  205. $allrealnames = pbx_UserGetAllRealnames();
  206. //normal search reply
  207. $templateOk = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  208. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Presearch">
  209. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="PayersTable">
  210. <Headers>
  211. <Header name="fio"/>
  212. <Header name="ls"/>
  213. </Headers>
  214. <Columns>
  215. <Column>
  216. <Element>' . @$allrealnames[$customerLogin] . '</Element>
  217. </Column>
  218. <Column>
  219. <Element>' . $customerid . '</Element>
  220. </Column>
  221. </Columns>
  222. </Data>
  223. </Transfer>';
  224. $result = $templateOk;
  225. } else {
  226. //search fail reply template
  227. $templateFail = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  228. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Presearch">
  229. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ErrorInfo" code="99">
  230. <Message>' . PBX_EX_NOT_FOUND . '</Message>
  231. </Data>
  232. </Transfer>';
  233. $result = $templateFail;
  234. }
  235. $result = trim($result);
  236. return ($result);
  237. }
  238. /**
  239. * Returns search reply
  240. *
  241. * @return string
  242. */
  243. function pbx_ReplySearch($customerid, $UsrBalanceDecimals = -1) {
  244. $allcustomers = op_CustomersGetAll();
  245. if (isset($allcustomers[$customerid])) {
  246. $customerLogin = $allcustomers[$customerid];
  247. $allrealnames = pbx_UserGetAllRealnames();
  248. $alladdress = pbx_AddressGetFulladdresslist();
  249. $allmobiles = pbx_UserGetAllMobiles();
  250. $userdata = pbx_UserGetStargazerData($customerLogin);
  251. $userBalance = ($UsrBalanceDecimals < 0) ? $userdata['Cash'] : (($UsrBalanceDecimals == 0) ? intval($userdata['Cash'], 10) : round($userdata['Cash'], $UsrBalanceDecimals, PHP_ROUND_HALF_EVEN));
  252. if (FULL_DEBTINFO) {
  253. $recommendedPay = '0.0';
  254. $debt = '0.0';
  255. if ($userdata['Cash'] < 0) {
  256. $recommendedPay = abs($userdata['Cash']);
  257. $debt = $userdata['Cash'];
  258. } else {
  259. $allTariffs = pbx_TariffGetPricesAll();
  260. $recommendedPay = $allTariffs[$userdata['Tariff']];
  261. $debt = '-' . $userdata['Cash'];
  262. }
  263. $debtInfoSection = '<DebtInfo amountToPay="' . $recommendedPay . '" debt="' . $debt . '">
  264. <Balance>' . $userBalance . '</Balance>
  265. </DebtInfo>';
  266. } else {
  267. $debtInfoSection = '<DebtInfo>
  268. <Balance>' . $userBalance . '</Balance>
  269. </DebtInfo>';
  270. }
  271. //normal reply
  272. $templateOk = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  273. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Search">
  274. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="DebtPack" billPeriod="' . date("Ym") . '">
  275. <PayerInfo billIdentifier="' . $customerid . '">
  276. <Fio>' . @$allrealnames[$customerLogin] . '</Fio>
  277. <Phone>' . @$allmobiles[$customerLogin] . '</Phone>
  278. <Address>' . @$alladdress[$customerLogin] . '</Address>
  279. </PayerInfo>
  280. <ServiceGroup>
  281. <DebtService serviceCode="' . ISP_SERVICE_CODE . '" >
  282. <CompanyInfo>
  283. <CompanyCode>' . ISP_CODE . '</CompanyCode>
  284. </CompanyInfo>
  285. ' . $debtInfoSection . '
  286. <ServiceName>' . ISP_SERVICE_NAME . '</ServiceName>
  287. <PayerInfo billIdentifier="' . $customerid . '" ls="' . $customerid . '">
  288. <Fio>' . @$allrealnames[$customerLogin] . '</Fio>
  289. <Phone>' . @$allmobiles[$customerLogin] . '</Phone>
  290. <Address>' . @$alladdress[$customerLogin] . '</Address>
  291. </PayerInfo>
  292. </DebtService>
  293. </ServiceGroup>
  294. </Data>
  295. </Transfer>
  296. ';
  297. $result = $templateOk;
  298. } else {
  299. //reply fail
  300. $templateFail = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  301. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Search">
  302. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ErrorInfo" code="2">
  303. <Message>' . PBX_EX_NOT_FOUND . '</Message>
  304. </Data>
  305. </Transfer>';
  306. $result = $templateFail;
  307. }
  308. $result = trim($result);
  309. return ($result);
  310. }
  311. /**
  312. * Function that gets last id from table
  313. *
  314. * @param string $tablename
  315. * @return int
  316. */
  317. function pbx_simple_get_lastid($tablename) {
  318. $tablename = mysql_real_escape_string($tablename);
  319. $query = "SELECT `id` from `" . $tablename . "` ORDER BY `id` DESC LIMIT 1";
  320. $result = simple_query($query);
  321. return ($result['id']);
  322. }
  323. /**
  324. * Returns payment possibility reply
  325. *
  326. * @return string
  327. */
  328. function pbx_ReplyCheck($customerid) {
  329. $allcustomers = op_CustomersGetAll();
  330. if (isset($allcustomers[$customerid])) {
  331. $customerLogin = $allcustomers[$customerid];
  332. $reference = pbx_GenerateHash();
  333. // following method may cause reference ID collisions
  334. // $reference = pbx_simple_get_lastid('op_transactions') + 1;
  335. $templateOk = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  336. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Check">
  337. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Gateway" reference="' . $reference . '" />
  338. </Transfer>
  339. ';
  340. $result = $templateOk;
  341. } else {
  342. $templateFail = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  343. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Check">
  344. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ErrorInfo" code="2">
  345. <Message>' . PBX_EX_NOT_FOUND . '</Message>
  346. </Data>
  347. </Transfer>
  348. ';
  349. $result = $templateFail;
  350. }
  351. $result = trim($result);
  352. return ($result);
  353. }
  354. /**
  355. * Checks is reference unique?
  356. *
  357. * @param int $rawhash reference number to check
  358. *
  359. * @return bool
  360. */
  361. function pbx_CheckHash($rawhash) {
  362. $rawhash = mysql_real_escape_string($rawhash);
  363. $hash = 'PBX_' . $rawhash;
  364. $query = "SELECT * from `op_transactions` WHERE `hash`='" . $hash . "';";
  365. $data = simple_query($query);
  366. if (empty($data)) {
  367. return (true);
  368. } else {
  369. return (false);
  370. }
  371. }
  372. /**
  373. * Returns payment processing reply
  374. *
  375. * @return string
  376. */
  377. function pbx_ReplyPayment($customerid, $summ, $rawhash) {
  378. $allcustomers = op_CustomersGetAll();
  379. if (isset($allcustomers[$customerid])) {
  380. if (pbx_CheckHash($rawhash)) {
  381. //do the payment
  382. $hash = 'PBX_' . $rawhash;
  383. $paysys = 'PBANKX';
  384. $note = 'inputreference: ' . $rawhash;
  385. op_TransactionAdd($hash, $summ, $customerid, $paysys, $note);
  386. op_ProcessHandlers();
  387. $templateOk = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  388. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Pay">
  389. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Gateway" reference="' . $rawhash . '">
  390. </Data>
  391. </Transfer>';
  392. $result = $templateOk;
  393. } else {
  394. $templateFail = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  395. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Pay">
  396. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ErrorInfo" code="7">
  397. <Message>' . PBX_EX_DUPLICATE . '</Message>
  398. </Data>
  399. </Transfer>';
  400. $result = $templateFail;
  401. }
  402. } else {
  403. $templateFail = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  404. <Transfer xmlns="http://debt.privatbank.ua/Transfer" interface="Debt" action="Pay">
  405. <Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ErrorInfo" code="2">
  406. <Message>' . PBX_EX_NOT_FOUND . '</Message>
  407. </Data>
  408. </Transfer>';
  409. $result = $templateFail;
  410. }
  411. $result = trim($result);
  412. return ($result);
  413. }
  414. /*
  415. * Controller part
  416. */
  417. if (!PBX_DEBUG_MODE) {
  418. $xmlRequest = pbx_RequestGet();
  419. } else {
  420. if (file_exists('debug.xml')) {
  421. $xmlRequest = file_get_contents('debug.xml');
  422. } else {
  423. die('PBX_DEBUG_MODE requires existing debug.xml file');
  424. }
  425. }
  426. //raw xml data received
  427. if (!empty($xmlRequest)) {
  428. $xmlParse = xml2array($xmlRequest);
  429. if (!empty($xmlParse)) {
  430. // Presearch action handling (deprecated?)
  431. if (isset($xmlParse['Transfer']['Data']['Unit_attr']['name'])) {
  432. if ($xmlParse['Transfer']['Data']['Unit_attr']['name'] == 'ls') {
  433. if (isset($xmlParse['Transfer']['Data']['Unit_attr']['value'])) {
  434. $customerid = vf($xmlParse['Transfer']['Data']['Unit_attr']['value'], 3);
  435. die(pbx_ReplyPresearch($customerid));
  436. }
  437. }
  438. }
  439. // Main search
  440. if (isset($xmlParse['Transfer']['Data']['Unit_attr']['name'])) {
  441. if ($xmlParse['Transfer']['Data']['Unit_attr']['name'] == 'bill_identifier') {
  442. if (isset($xmlParse['Transfer']['Data']['Unit_attr']['value'])) {
  443. if ($xmlParse['Transfer_attr']['action'] == 'Search') {
  444. $customerid = vf($xmlParse['Transfer']['Data']['Unit_attr']['value'], 3);
  445. die(pbx_ReplySearch($customerid, USER_BALANCE_DECIMALS));
  446. }
  447. }
  448. }
  449. }
  450. // Check payment possibility
  451. if (isset($xmlParse['Transfer_attr']['action'])) {
  452. if ($xmlParse['Transfer_attr']['action'] == 'Check') {
  453. if (isset($xmlParse['Transfer']['Data']['PayerInfo_attr']['billIdentifier'])) {
  454. $customerid = vf($xmlParse['Transfer']['Data']['PayerInfo_attr']['billIdentifier'], 3);
  455. die(pbx_ReplyCheck($customerid));
  456. }
  457. }
  458. }
  459. // Pay transaction handling
  460. if (isset($xmlParse['Transfer_attr']['action'])) {
  461. if ($xmlParse['Transfer_attr']['action'] == 'Pay') {
  462. if (isset($xmlParse['Transfer']['Data']['PayerInfo_attr']['billIdentifier'])) {
  463. $customerid = vf($xmlParse['Transfer']['Data']['PayerInfo_attr']['billIdentifier'], 3);
  464. $summ = $xmlParse['Transfer']['Data']['TotalSum'];
  465. $summ = str_replace(',', '.', $summ);
  466. $rawhash = $xmlParse['Transfer']['Data']['CompanyInfo']['CheckReference'];
  467. die(pbx_ReplyPayment($customerid, $summ, $rawhash));
  468. }
  469. }
  470. }
  471. } else {
  472. die('XML_PARSER_FAIL');
  473. }
  474. }
  475. //
  476. // _._._ _._._
  477. // _| |_ _| |_
  478. // | ... |_._._._._._._._._._._| ... |
  479. // | ||| | o ПРИВАТБАНК o | ||| |
  480. // | """ | """ """ """ | """ |
  481. // ()) |[-|-]| [-|-] [-|-] [-|-] |[-|-]| ())
  482. // (())) | |---------------------| | (()))
  483. // (())())| """ | """ """ """ | """ |(())())
  484. // (()))()|[-|-]| ::: .-"-. ::: |[-|-]|(()))()
  485. // ()))(()| | |~|~| |_|_| |~|~| | |()))(()
  486. // || |_____|_|_|_|__|_|_|__|_|_|_|_____| ||
  487. // ~ ~^^ @@@@@@@@@@@@@@/=======\@@@@@@@@@@@@@@ ^^~ ~
  488. // ^~^~ ~^~^