api.pbfasturl.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. /**
  3. * Privat24 fast payments URL helper
  4. */
  5. class PBFastURL {
  6. /**
  7. * Contains ISP payment token
  8. *
  9. * @var string
  10. */
  11. protected $token = '';
  12. /**
  13. * Contains available prices listed in config option
  14. *
  15. * @var array
  16. */
  17. protected $pricesAvail = array();
  18. /**
  19. * Contains basic SMS text template placed before URL
  20. *
  21. * @var string
  22. */
  23. protected $template = '';
  24. /**
  25. * Full shortener service URL
  26. *
  27. * @var string
  28. */
  29. protected $shortener = '';
  30. /**
  31. * System message helper instance
  32. *
  33. * @var object
  34. */
  35. protected $messages = '';
  36. /**
  37. * Contains user currency
  38. *
  39. * @var string
  40. */
  41. protected $currency = '';
  42. /**
  43. * SendDog enabled/disabled flag
  44. *
  45. * @var int
  46. */
  47. protected $sendDogFlag = 0;
  48. /**
  49. * Is preview checkbox enabled?
  50. *
  51. * @var int
  52. */
  53. protected $previewFlag = 0;
  54. /**
  55. * Contains default mobile numbers prefix
  56. *
  57. * @var string
  58. */
  59. protected $mobilePrefix = '';
  60. //some predefined stuff here
  61. const BASE_URL = 'https://next.privat24.ua/payments/form/';
  62. const OPTION_TOKEN = 'PB_FASTURL_TOKEN';
  63. const OPTION_PRICES = 'PB_FASTURL_PRICES';
  64. const OPTION_TEMPLATE = 'PB_FASTURL_TEMPLATE';
  65. const OPTION_SHORTENER = 'PB_FASTURL_SHORTENER';
  66. const OPTION_CURRENCY = 'TEMPLATE_CURRENCY';
  67. const OPTION_SENDDOG = 'SENDDOG_ENABLED';
  68. const OPTION_PREVIEW = 'PB_FASTURL_PREVIEW';
  69. const OPTION_MOBILE_PREFIX = 'REMINDER_PREFIX';
  70. const AGENT_PREFIX = 'UbillingPBFastURL';
  71. const PROUTE_PAYID = 'pbfupaymentid';
  72. const PROUTE_AMOUNT = 'pbfuamount';
  73. const PROUTE_CUST_AMOUNT = 'pbfucustomamount';
  74. const PROUTE_PREVIEW = 'pbfonlypreview';
  75. const PROUTE_PHONE = 'pbfuphonenumber';
  76. const STYLE_PATH = 'skins/pbfu.css';
  77. //
  78. // _._._ _._._
  79. // _| |_ _| |_
  80. // | ... |_._._._._._._._._._._| ... |
  81. // | ||| | o ПРИВАТБАНК o | ||| |
  82. // | """ | """ """ """ | """ |
  83. // ()) |[-|-]| [-|-] [-|-] [-|-] |[-|-]| ())
  84. // (())) | |---------------------| | (()))
  85. // (())())| """ | """ """ """ | """ |(())())
  86. // (()))()|[-|-]| ::: .-"-. ::: |[-|-]|(()))()
  87. // ()))(()| | |~|~| |_|_| |~|~| | |()))(()
  88. // || |_____|_|_|_|__|_|_|__|_|_|_|_____| ||
  89. // ~ ~^^ @@@@@@@@@@@@@@/=======\@@@@@@@@@@@@@@ ^^~ ~
  90. // ^~^~ ~^~^
  91. public function __construct() {
  92. $this->initMessages();
  93. $this->setOptions();
  94. }
  95. /**
  96. * Sets the options for the current instance using global configuration parameters.
  97. *
  98. * This method retrieves various configuration parameters from the global
  99. * `$ubillingConfig` object and assigns them to the instance variables.
  100. *
  101. * @global object $ubillingConfig The global configuration object.
  102. *
  103. * @return void
  104. */
  105. protected function setOptions() {
  106. global $ubillingConfig;
  107. $this->token = $ubillingConfig->getAlterParam(self::OPTION_TOKEN);
  108. $pricesTmp = $ubillingConfig->getAlterParam(self::OPTION_PRICES);
  109. $this->pricesAvail = explode(',', $pricesTmp);
  110. $this->template = $ubillingConfig->getAlterParam(self::OPTION_TEMPLATE);
  111. $this->currency = $ubillingConfig->getAlterParam(self::OPTION_CURRENCY, 'грн');
  112. $this->shortener = $ubillingConfig->getAlterParam(self::OPTION_SHORTENER);
  113. $this->sendDogFlag = $ubillingConfig->getAlterParam(self::OPTION_SENDDOG);
  114. $this->previewFlag = $ubillingConfig->getAlterParam(self::OPTION_PREVIEW);
  115. $this->mobilePrefix = $ubillingConfig->getAlterParam(self::OPTION_MOBILE_PREFIX, '');
  116. if ($this->shortener) {
  117. //forcing trailing slash for shortener service URL
  118. if (substr($this->shortener, -1) != '/') {
  119. $this->shortener .= '/';
  120. }
  121. }
  122. }
  123. /**
  124. * Inits message helper for further usage
  125. *
  126. * @return void
  127. */
  128. protected function initMessages() {
  129. $this->messages = new UbillingMessageHelper();
  130. }
  131. /**
  132. * Generates a payment URL based on the provided payment ID and sum.
  133. *
  134. * @param string $paymentId The payment ID to include in the URL. Default is an empty string.
  135. * @param string $sum The sum to include in the URL. Default is an empty string.
  136. *
  137. * @return string
  138. */
  139. public function getUrl($paymentId = '', $sum = '') {
  140. $result = '';
  141. $fullUrl = self::BASE_URL;
  142. $urlData = array();
  143. if ($this->token) {
  144. $urlData['token'] = $this->token;
  145. if (!empty($paymentId)) {
  146. $urlData['personalAccount'] = $paymentId;
  147. }
  148. if (!empty($sum)) {
  149. $urlData['sum'] = $sum;
  150. }
  151. $encodedData = json_encode($urlData);
  152. $fullUrl .= $encodedData;
  153. if ($this->shortener) {
  154. $shortenerService = new OmaeUrl($this->shortener . '?shorten=' . $fullUrl);
  155. $ubVer = file_get_contents('RELEASE');
  156. $agent = self::AGENT_PREFIX . '/' . trim($ubVer);
  157. $shortenerService->setUserAgent($agent);
  158. $newShortenId = $shortenerService->response();
  159. if (!empty($newShortenId) and $shortenerService->httpCode() == 200) {
  160. $result .= $this->shortener . $newShortenId;
  161. }
  162. } else {
  163. $result .= $fullUrl;
  164. }
  165. }
  166. return ($result);
  167. }
  168. /**
  169. * Renders link preview
  170. *
  171. * @param string $data
  172. *
  173. * @return string|void
  174. */
  175. protected function renderLinkPreview($data) {
  176. $result = '';
  177. if (!empty($data)) {
  178. $result .= wf_tag('div', false, 'pbfu-container');
  179. $result .= wf_tag('span', false, 'pbfu-text', 'id="pbfu-text"');
  180. $result .= $data;
  181. $result .= wf_tag('span', true);
  182. $result .= wf_tag('button', false, 'pbfu-copy-btn', 'onclick="pbfuCopyToClipboard()"');
  183. $result .= wf_img('skins/clipcopy.png', __('Copy'));
  184. $result .= __('Copy');
  185. $result .= wf_tag('button', true);
  186. $result .= wf_tag('div', true);
  187. $result .= wf_tag('script');
  188. $result .= 'function pbfuCopyToClipboard() {
  189. const text = document.getElementById("pbfu-text").innerText;
  190. navigator.clipboard.writeText(text).then(() => {
  191. alert("' . __('Text copied to clipboard') . '");
  192. }).catch(err => {
  193. console.error("Failed to copy: ", err);
  194. });
  195. }';
  196. $result .= wf_tag('script', true);
  197. }
  198. return ($result);
  199. }
  200. /**
  201. * Catches SMS sending request and stores SMS into SendDog sending queue
  202. *
  203. * @return string|void
  204. */
  205. protected function catchSMSRequest() {
  206. $result = '';
  207. if ($this->sendDogFlag) {
  208. if (ubRouting::checkPost(array(self::PROUTE_PAYID, self::PROUTE_PHONE, self::PROUTE_AMOUNT))) {
  209. $paymentId = ubRouting::post(self::PROUTE_PAYID, 'mres');
  210. $mobileNumber = ubRouting::post(self::PROUTE_PHONE, 'mres');
  211. if ($this->mobilePrefix) {
  212. $mobileNumber = str_replace($this->mobilePrefix, '', $mobileNumber);
  213. $mobileNumber = $this->mobilePrefix . $mobileNumber;
  214. }
  215. $amount = ubRouting::post(self::PROUTE_AMOUNT, 'float');
  216. if (ubRouting::checkPost(self::PROUTE_CUST_AMOUNT)) {
  217. $amount = ubRouting::post(self::PROUTE_CUST_AMOUNT, 'float');
  218. }
  219. $paymentUrl = $this->getUrl($paymentId, $amount);
  220. if (!empty($paymentUrl)) {
  221. if (!empty($mobileNumber)) {
  222. $smsText = $this->template . ' ' . $paymentUrl;
  223. if (!ubRouting::checkPost(self::PROUTE_PREVIEW)) {
  224. //SMS sending
  225. $smsQueue = new UbillingSMS();
  226. $smsQueue->sendSMS($mobileNumber, $smsText, false, 'PBFASTURL');
  227. $result .= $this->messages->getStyledMessage($mobileNumber . ' ' . __('SMS') . ': ' . $smsText, 'success');
  228. } else {
  229. //rendering preview
  230. $result .= $this->renderLinkPreview($smsText);
  231. }
  232. } else {
  233. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Mobile') . ' ' . __('is empty'), 'error');
  234. }
  235. } else {
  236. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('URL') . ' ' . __('is empty'), 'error');
  237. }
  238. }
  239. }
  240. return ($result);
  241. }
  242. /**
  243. * Renders a form for processing a payment URL sending to user.
  244. *
  245. * @param string $paymentId The Payment ID of the user. Default is an empty string.
  246. * @param array $phones An array of phone numbers. Default is an empty array.
  247. * @param float $defaultAmount An default summ of payment placed on top of the list
  248. *
  249. * @return string The HTML string of the rendered form or an error message if inputs are invalid.
  250. */
  251. public function renderForm($paymentId = '', $phones = array(), $defaultAmount = 0) {
  252. $result = '';
  253. $result .= wf_tag('link', false, '', 'type="text/css" href="' . self::STYLE_PATH . '" rel="stylesheet"');
  254. $phonesParams = array();
  255. if ($this->sendDogFlag) {
  256. if (!empty($phones)) {
  257. foreach ($phones as $io => $each) {
  258. $phonesParams[$each] = $each;
  259. }
  260. if (!empty($paymentId)) {
  261. //may be some form already pushed?
  262. $sendingResult = $this->catchSMSRequest();
  263. if (!empty($sendingResult)) {
  264. $sendingResult = wf_tag('div', false, 'pbfu-result-container') . $sendingResult . wf_tag('div', true);
  265. $result .= wf_modalOpenedAuto(__('Result'), $sendingResult);
  266. }
  267. //form construct
  268. $inputs = wf_HiddenInput(self::PROUTE_PAYID, $paymentId);
  269. $inputs .= wf_Selector(self::PROUTE_PHONE, $phonesParams, __('Mobile'), '', true);
  270. $inputs .= wf_delimiter(0);
  271. $firstPrice = true;
  272. //default amount on top of the list
  273. if ($defaultAmount > 0) {
  274. $inputs .= wf_RadioInput(self::PROUTE_AMOUNT, $defaultAmount . ' ' . $this->currency, $defaultAmount, true, $firstPrice);
  275. $firstPrice = false;
  276. }
  277. //config-defined prices
  278. if (!empty($this->pricesAvail)) {
  279. foreach ($this->pricesAvail as $io => $each) {
  280. $eSum = trim($each);
  281. $inputs .= wf_RadioInput(self::PROUTE_AMOUNT, $eSum . ' ' . $this->currency, trim($eSum), true, $firstPrice);
  282. $firstPrice = false;
  283. }
  284. }
  285. $inputs .= wf_TextInput(self::PROUTE_CUST_AMOUNT, __('Other'), '', true, 4, 'finance');
  286. if ($this->previewFlag) {
  287. $inputs .= wf_CheckInput(self::PROUTE_PREVIEW, __('Just show me link'), true, false);
  288. }
  289. $inputs .= wf_delimiter(0);
  290. $inputs .= wf_Submit(__('Send SMS'));
  291. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  292. } else {
  293. $result .= $this->messages->getStyledMessage(__('Payment ID') . ': ' . __('is empty'), 'error');
  294. }
  295. } else {
  296. $result .= $this->messages->getStyledMessage(__('Phones') . ' ' . __('is empty'), 'error');
  297. }
  298. } else {
  299. $result .= $this->messages->getStyledMessage(__('SendDog') . ': ' . __('disabled'), 'error');
  300. }
  301. return ($result);
  302. }
  303. }