copayco.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. <?php
  2. /**
  3. * CoPayCo API (CoPayCo Application Programming Interface)
  4. *
  5. * This file is part of CoPayCo system
  6. * Copyright (C) 2010 CoPayCo, http://www.copayco.com/
  7. *
  8. * @author: Alexandr Nosov (alex@copayco.com)
  9. * @version: 2.1.5
  10. */
  11. class copayco_api
  12. {
  13. /**
  14. * CoPayCo submit URL
  15. */
  16. const SUBMIT_URL = 'https://www.copayco.com/pay.php';
  17. /**
  18. * CoPayCo submit test URL
  19. */
  20. const SUBMIT_URL_TEST = 'https://www.test.copayco.com/pay.php';
  21. /**
  22. * CoPayCo notification URL
  23. */
  24. const NOTIFICATION_URL = 'https://www.copayco.com/notify_delivering.php';
  25. /**
  26. * CoPayCo notification test URL
  27. */
  28. const NOTIFICATION_URL_TEST = 'https://www.test.copayco.com/notify_delivering.php';
  29. /**
  30. * Key of transaction id
  31. */
  32. const TA_ID_KEY = 'ta_id';
  33. /**
  34. * Key of request type
  35. */
  36. const REQUEST_TYPE_KEY = 'request_type';
  37. /**
  38. * Key of signature
  39. */
  40. const SIGNATURE_KEY = 'signature';
  41. /**
  42. * Key of signature
  43. */
  44. const PAYMENT_MODE_KEY = 'payment_mode';
  45. /**
  46. * Key of status
  47. */
  48. const STATUS_KEY = 'status';
  49. /**
  50. * @var array Allowed request fields (From Merchant to CoPAYCo)
  51. */
  52. private static $aReqFields = array(
  53. 'shop_id' => TRUE,
  54. 'ta_id' => TRUE,
  55. 'amount' => TRUE,
  56. 'currency' => TRUE,
  57. 'description' => FALSE,
  58. 'custom' => FALSE,
  59. 'payment_mode' => FALSE,
  60. 'charset' => FALSE,
  61. 'lang' => FALSE,
  62. 'order_no' => FALSE,
  63. 'purpose' => FALSE,
  64. 'date_time' => FALSE,
  65. 'random' => FALSE,
  66. 'signature' => FALSE,
  67. );
  68. /**
  69. * @var array Allowed check fields (From CoPAYCo to Merchant)
  70. */
  71. private static $aCheckFields = array(
  72. 'request_type' => TRUE,
  73. 'ta_id' => TRUE,
  74. 'amount' => TRUE,
  75. 'currency' => TRUE,
  76. 'custom' => FALSE,
  77. 'payment_mode' => FALSE,
  78. 'client_ip' => TRUE,
  79. 'date_time' => FALSE,
  80. 'random' => FALSE,
  81. 'signature' => TRUE,
  82. );
  83. /**
  84. * @var array Allowed perform fields (From CoPAYCo to Merchant)
  85. */
  86. private static $aPerformFields = array(
  87. 'request_type' => TRUE,
  88. 'status' => TRUE,
  89. 'ta_id' => TRUE,
  90. 'cpc_ta_id' => TRUE,
  91. 'amount' => TRUE,
  92. 'currency' => TRUE,
  93. 'custom' => FALSE,
  94. 'payment_mode' => FALSE,
  95. 'date_time' => FALSE,
  96. 'random' => FALSE,
  97. 'signature' => TRUE,
  98. );
  99. /**
  100. * @var array Allowed notification fields (From Merchant to CoPAYCo)
  101. */
  102. private static $aNotificationFields = array(
  103. 'shop_id' => TRUE,
  104. 'ta_id' => TRUE,
  105. 'amount' => TRUE,
  106. 'currency' => FALSE,
  107. 'state' => TRUE,
  108. 'date_time' => TRUE,
  109. 'random' => FALSE,
  110. 'signature' => TRUE,
  111. 'return_url' => FALSE,
  112. );
  113. /**
  114. * @var array Correspondence field-data to current property
  115. */
  116. private static $aCorrespondence = array(
  117. 'shop_id' => 'iShopId',
  118. 'ta_id' => 'sTaId',
  119. 'amount' => 'nAmount',
  120. 'currency' => 'sCurrency',
  121. // 'status' => '',
  122. 'description' => 'sDescription',
  123. 'custom' => 'mCustom',
  124. 'payment_mode' => 'aPaymentMode',
  125. 'cpc_ta_id' => 'iCPCTaId',
  126. 'charset' => 'sCharset',
  127. 'lang' => 'sLanguage',
  128. 'order_no' => 'sOrderNo',
  129. 'purpose' => 'sPurpose',
  130. 'date_time' => 'sDateTime',
  131. 'random' => 'iRand',
  132. 'state' => 'sState',
  133. 'return_url' => 'sReturnUrl',
  134. );
  135. /**
  136. * @var array Fill property automatically by HTTP-vars
  137. */
  138. private static $aAutoFill = array(
  139. //'aPaymentMode',
  140. 'iCPCTaId',
  141. 'sDateTime',
  142. 'iRand',
  143. );
  144. /**
  145. * @var array Field number (for error code)
  146. */
  147. private static $aFieldNumber = array(
  148. 'shop_id' => 1,
  149. 'ta_id' => 2,
  150. 'amount' => 3,
  151. 'currency' => 4,
  152. 'description' => 5,
  153. 'custom' => 6,
  154. 'payment_mode' => 7,
  155. 'request_type' => 9,
  156. 'status' => 10,
  157. 'state' => 11,
  158. 'return_url' => 12,
  159. 'client_ip' => 20,
  160. 'cpc_ta_id' => 30,
  161. 'order_no' => 60,
  162. 'purpose' => 61,
  163. 'charset' => 70,
  164. 'lang' => 71,
  165. 'date_time' => 80,
  166. 'random' => 81,
  167. 'signature' => 99,
  168. );
  169. /**
  170. * @var array Allowed currencies
  171. */
  172. private static $aLegalCurrencies = array(
  173. 'UAH',
  174. 'RUB',
  175. 'USD',
  176. 'EUR',
  177. );
  178. /**
  179. * @var array Allowed payment modes
  180. */
  181. private static $aLegalPaymentMode = array(
  182. 'paycard',
  183. 'account',
  184. 'ecurrency',
  185. 'copayco',
  186. 'terminal',
  187. 'sms',
  188. );
  189. /**
  190. * @var array Allowed languages
  191. */
  192. private static $aLegalLanguages = array(
  193. 'ru',
  194. 'en',
  195. 'ua',
  196. );
  197. /**
  198. * @var array Allowed Charsets
  199. */
  200. private static $aLegalCharsets = array(
  201. 'utf-8',
  202. 'windows-1251',
  203. 'koi8-r',
  204. 'koi8-u',
  205. );
  206. /**
  207. * @var boolean Test mode
  208. */
  209. private $bTestMode = FALSE;
  210. /**
  211. * @var boolean Test mode
  212. */
  213. private $sNotifyMode = 'curl';
  214. /**
  215. * @var string Error Message
  216. */
  217. private $sErrMsg = NULL;
  218. /**
  219. * @var string Signature Key
  220. */
  221. private $sSignKey = NULL;
  222. /**
  223. * @var integer Use Random number in The request
  224. */
  225. private $iUseRand = 2;
  226. /**
  227. * @var integer Shop ID
  228. */
  229. protected $iShopId = NULL;
  230. /**
  231. * @var string Merchant's Transaction ID
  232. */
  233. protected $sTaId = NULL;
  234. /**
  235. * @var string CoPAYCo's Transaction ID
  236. */
  237. protected $iCPCTaId = NULL;
  238. /**
  239. * @var numeric Amount of payment
  240. */
  241. protected $nAmount = NULL;
  242. /**
  243. * @var string Currency of payment
  244. */
  245. protected $sCurrency = NULL;
  246. /**
  247. * @var string Description of payment
  248. */
  249. protected $sDescription = NULL;
  250. /**
  251. * @var mixed Custom field
  252. */
  253. protected $mCustom = NULL;
  254. /**
  255. * @var array Payment Mode (paycard, account, copayco)
  256. */
  257. protected $aPaymentMode = array();
  258. /**
  259. * @var string
  260. */
  261. protected $sCharset = NULL;
  262. /**
  263. * @var string
  264. */
  265. protected $sLanguage = NULL;
  266. /**
  267. * @var string
  268. */
  269. protected $sOrderNo = NULL;
  270. /**
  271. * @var string
  272. */
  273. protected $sPurpose = NULL;
  274. /**
  275. * @var string Date/time from server which makes request
  276. */
  277. protected $sDateTime = NULL;
  278. /**
  279. * @var string Rantom number (0-1024)
  280. */
  281. protected $iRand = NULL;
  282. /**
  283. * @var string Transaction State
  284. */
  285. protected $sState = NULL;
  286. /**
  287. * @var string Return Url (for HTML-form)
  288. */
  289. protected $sReturnUrl = NULL;
  290. /**
  291. * Constructor of copayco
  292. * @param string $sSignKey
  293. */
  294. protected function __construct($sSignKey)
  295. {
  296. $aConf = $this->get_config($sSignKey);
  297. // Set Signature Key
  298. if (!empty($aConf['sign_key'])) {
  299. $this->sSignKey = $aConf['sign_key'];
  300. }
  301. // Set Shop ID
  302. if (!empty($aConf['shop_id'])) {
  303. $this->iShopId = $aConf['shop_id'];
  304. }
  305. // Set Notify mode
  306. if (!empty($aConf['notify_mode'])) {
  307. if (!in_array($aConf['notify_mode'], array('curl'))) {
  308. throw new copayco_exception('Incorrect notify mode: "' . $aConf['notify_mode'] . '".', 10001);
  309. }
  310. $this->sNotifyMode = $aConf['notify_mode'];
  311. }
  312. // Set Charset
  313. if (isset($aConf['charset'])) {
  314. $this->set_charset($aConf['charset']);
  315. }
  316. // Set Random value
  317. if (isset($aConf['use_rand'])) {
  318. $this->iUseRand = $aConf['use_rand'];
  319. }
  320. // Set Test mode
  321. if (isset($aConf['test_mode'])) {
  322. $this->bTestMode = !empty($aConf['test_mode']);
  323. }
  324. } // function __construct
  325. /**
  326. * Get instance of copayco API
  327. * @param string $sSignKey
  328. * @return copayco
  329. */
  330. public static function instance($sSignKey = NULL)
  331. {
  332. return new copayco_api($sSignKey);
  333. } // function instance
  334. // -------------- Preparing data -------------- \\
  335. /**
  336. * Set main data of copayco payment
  337. * @param string $sTaId
  338. * @param numeric $nAmount
  339. * @param integer $iShopId
  340. * @param string $sCurrency
  341. */
  342. public function set_main_data($sTaId, $nAmount, $sCurrency = 'UAH', $iShopId = NULL)
  343. {
  344. // Check ID of TA
  345. if (empty($sTaId)) {
  346. throw new copayco_exception('Transaction ID can\'t be empty.', 10020);
  347. }
  348. // Check Amount
  349. if (empty($nAmount)) {
  350. throw new copayco_exception('Amount of payment can\'t be equal to 0.', 10030);
  351. }
  352. if (!is_numeric($nAmount)) {
  353. throw new copayco_exception('Amount must be numeric value.', 10031);
  354. }
  355. if ($nAmount < 0) {
  356. throw new copayco_exception('Amount must be greater than 0.', 10032);
  357. }
  358. // Check shop ID
  359. if (!empty($iShopId)) {
  360. $this->iShopId = $iShopId;
  361. } elseif (empty($this->iShopId)) {
  362. throw new copayco_exception('Shop ID isn\'t set.', 10010);
  363. }
  364. // Check Currency
  365. if (empty($sCurrency) || !in_array($sCurrency, self::$aLegalCurrencies)) {
  366. throw new copayco_exception('Currency must be equal to "' . implode('", "', self::$aLegalCurrencies) . '".', 10040);
  367. }
  368. $this->sTaId = $sTaId;
  369. $this->nAmount = round($nAmount * 100);
  370. $this->sCurrency = $sCurrency;
  371. } // function set_main_data
  372. /**
  373. * Set description of copayco payment
  374. * @param string $sDescription
  375. */
  376. public function set_description($sDescription)
  377. {
  378. if (!is_scalar($sDescription)) {
  379. throw new copayco_exception('Description must have a scalar value.', 10050);
  380. }
  381. $sDescription = (string)$sDescription;
  382. if (strlen($sDescription) > 255) {
  383. throw new copayco_exception('Description can\'t be more than 255 symbols.', 10051);
  384. }
  385. $this->sDescription = $sDescription;
  386. } // function set_description
  387. /**
  388. * Set custom field of copayco payment
  389. * @param mixed $mCustom
  390. */
  391. public function set_custom_field($mCustom)
  392. {
  393. if (!is_scalar($mCustom)) {
  394. throw new copayco_exception('Custom field must have a scalar value.', 10060);
  395. }
  396. $mCustom = (string)$mCustom;
  397. if (strlen($mCustom) > 255) {
  398. throw new copayco_exception('Custom field can\'t be more than 255 symbols.', 10061);
  399. }
  400. $this->mCustom = $mCustom;
  401. } // function set_custom_field
  402. /**
  403. * Set payment mode of copayco payment
  404. * @param mixed $mPaymentMode
  405. */
  406. public function set_payment_mode($mPaymentMode)
  407. {
  408. if (empty($mPaymentMode)) {
  409. throw new copayco_exception('Payment Mode can\'t be empty.', 20070);
  410. }
  411. if (is_array($mPaymentMode)) {
  412. foreach ($mPaymentMode as $v) {
  413. $this->set_payment_mode($v);
  414. }
  415. } else {
  416. if (!is_scalar($mPaymentMode) || !in_array($mPaymentMode, self::$aLegalPaymentMode)) {
  417. throw new copayco_exception('Payment Mode must be equal to "' . implode('", "', self::$aLegalPaymentMode) . '".', 20071);
  418. }
  419. if (!in_array($mPaymentMode, $this->aPaymentMode)) {
  420. $this->aPaymentMode[] = $mPaymentMode;
  421. }
  422. }
  423. } // function set_payment_mode
  424. /**
  425. * Clear payment mode of copayco payment
  426. */
  427. public function clear_payment_mode()
  428. {
  429. $this->aPaymentMode = array();
  430. } // function clear_payment_mode
  431. /**
  432. * Set charset
  433. * @param string $sCharset
  434. */
  435. public function set_charset($sCharset)
  436. {
  437. $sCharset = strtolower($sCharset);
  438. if (!in_array($sCharset, self::$aLegalCharsets)) {
  439. throw new copayco_exception('Incorrect Charset: "' . $sCharset . '".', 20700);
  440. }
  441. $this->sCharset = $sCharset;
  442. } // function set_charset
  443. /**
  444. * Set language
  445. * @param string $sLanguage
  446. */
  447. public function set_language($sLanguage)
  448. {
  449. $sLanguage = strtolower($sLanguage);
  450. if (!in_array($sLanguage, self::$aLegalLanguages)) {
  451. throw new copayco_exception('Incorrect Language: "' . $sLanguage . '".', 20710);
  452. }
  453. $this->sLanguage = $sLanguage;
  454. } // function set_language
  455. /**
  456. * Set order_no
  457. * @param string $sOrderNo
  458. */
  459. public function set_order_no($sOrderNo)
  460. {
  461. $this->sOrderNo = $sOrderNo;
  462. } // function set_order_no
  463. /**
  464. * Set purpose
  465. * @param string $sPurpose
  466. */
  467. public function set_purpose($sPurpose)
  468. {
  469. $this->sPurpose = $sPurpose;
  470. } // function set_purpose
  471. /**
  472. * Get form fields
  473. * @param array $aAttr 2-x array (first key - field name; second key - attribute name; value - attribute value)
  474. * @param string $sSeparator field separator (for example: "\t", "\n", etc). If $sSeparator is null, method return array of tags, but isn't string
  475. * @return mixed string OR array
  476. */
  477. public function get_form_fields($aAttr = array(), $sSeparator = '')
  478. {
  479. $mRet = is_null($sSeparator) ? array() : '';
  480. $this->set_date_and_rand();
  481. foreach ($this->prepare_send_data() as $k => $v) {
  482. $sTag = '<input type="' . (isset($aAttr[$k]['type']) ? $aAttr[$k]['type'] : 'hidden') . '" name="' . $k . '" value="' . htmlspecialchars($v) . '"';
  483. $sTag .= (isset($aAttr[$k]) ? $this->get_additional_attr($aAttr[$k]) : '') . ' />';
  484. if (is_null($sSeparator)) {
  485. $mRet[] = $sTag;
  486. } else {
  487. $mRet .= $sTag . $sSeparator;
  488. }
  489. }
  490. return $mRet;
  491. } // function get_form_fields
  492. /**
  493. * Get request URI
  494. * @param string $sSeparator -- GET-separator ('&' OR '&amp;')
  495. * @return string
  496. */
  497. public function get_request_uri($sSeparator = '&amp;')
  498. {
  499. $sRet = '';
  500. $this->set_date_and_rand();
  501. foreach ($this->prepare_send_data() as $k => $v) {
  502. $sRet .= ($sRet ? $sSeparator : '') . $k . '=' . urlencode($v);
  503. }
  504. return $this->get_submit_url() . '?' . $sRet;
  505. } // function get_request_uri
  506. /**
  507. * Get submit url, taking into account the test mode
  508. * @return string
  509. */
  510. public function get_submit_url()
  511. {
  512. return $this->bTestMode ? self::SUBMIT_URL_TEST : self::SUBMIT_URL;
  513. } // function get_submit_url
  514. /**
  515. * Get notification url, taking into account the test mode
  516. * @return string
  517. */
  518. public function get_notification_url()
  519. {
  520. return $this->bTestMode ? self::NOTIFICATION_URL_TEST : self::NOTIFICATION_URL;
  521. } // function get_submit_url
  522. // -------------- Check data (1-st answer) -------------- \\
  523. /**
  524. * Check full data of copayco payment
  525. * @return boolean
  526. */
  527. public function check_data()
  528. {
  529. if ($this->get_request_type() != 'check') {
  530. throw new copayco_exception('It isn\'t check request.', 30091);
  531. }
  532. $this->define_http_val();
  533. return $this->check_http_fields(self::$aCheckFields, TRUE);
  534. } // function check_data
  535. /**
  536. * Set error message
  537. * @param string $sMsg
  538. */
  539. public function set_error_message($sErrMsg)
  540. {
  541. if ($sErrMsg) {
  542. $this->sErrMsg = $sErrMsg;
  543. }
  544. } // function set_error_message
  545. /**
  546. * Output first answer for copayco server
  547. * @param string $sCharset
  548. */
  549. public function output_check_answer($sCharset = NULL)
  550. {
  551. $sMsg = $this->get_request_type() == 'check' ? ($this->sErrMsg ? $this->sErrMsg : 'ok') : 'It isn\'t check request.';
  552. $this->output_header($sMsg, $sCharset);
  553. echo $sMsg;
  554. } // function output_first_answer
  555. // -------------- Perform data (2-nd answer) -------------- \\
  556. /**
  557. * Get transaction status
  558. * @return string
  559. */
  560. public function get_perform_status()
  561. {
  562. if ($this->get_request_type() != 'perform') {
  563. throw new copayco_exception('It isn\'t perform request.', 30092);
  564. }
  565. $this->define_http_val();
  566. if ($this->check_http_fields(self::$aPerformFields)) {
  567. return $this->get_http_val(self::STATUS_KEY);
  568. }
  569. throw new copayco_exception('Perform status isn\'t set.', 30093);
  570. } // function get_perform_status
  571. /**
  572. * Get CoPAYCo's transaction id
  573. * @return string
  574. */
  575. public function get_copayco_ta_id()
  576. {
  577. return $this->iCPCTaId;
  578. } // function get_copayco_ta_id
  579. /**
  580. * Check is transaction status reserved?
  581. * @return boolean
  582. */
  583. public function is_reserved()
  584. {
  585. return $this->get_perform_status() == 'reserved';
  586. } // function is_reserved
  587. /**
  588. * Check is transaction status finished?
  589. * @return boolean
  590. */
  591. public function is_finished()
  592. {
  593. return $this->get_perform_status() == 'finished';
  594. } // function is_finished
  595. /**
  596. * Check is transaction status canceled?
  597. * @return boolean
  598. */
  599. public function is_canceled()
  600. {
  601. return $this->get_perform_status() == 'canceled';
  602. } // function is_canceled
  603. /**
  604. * Output first answer for copayco server
  605. * @param string $sCharset
  606. */
  607. public function output_perform_answer($sCharset = NULL)
  608. {
  609. $sMsg = $this->get_request_type() == 'perform' ? ($this->sErrMsg ? $this->sErrMsg : 'ok') : 'It isn\'t perform request.';
  610. $this->output_header($sMsg, $sCharset);
  611. echo $sMsg;
  612. } // function output_perform_answer
  613. // -------------- Send delivering state: delivered OR canceled -------------- \\
  614. /**
  615. * Send "delivered" state about delivering of goods/service
  616. */
  617. public function send_delivered_state()
  618. {
  619. $this->send_notification('delivered');
  620. } // function send_delivered_state
  621. /**
  622. * Send "canceled" state about delivering of goods/service
  623. */
  624. public function send_canceled_state()
  625. {
  626. $this->send_notification('canceled');
  627. } // function send_canceled_state
  628. // -------------- Auxiliary methods -------------- \\
  629. /**
  630. * Get request type
  631. * @return string
  632. */
  633. final public function get_request_type()
  634. {
  635. $sKey = self::REQUEST_TYPE_KEY;
  636. $sType = $this->get_http_val($sKey);
  637. if (!in_array($sType, array('check', 'perform'))) {
  638. throw new copayco_exception('Field "' . $sKey . '" contain incorrect data.', 30002 + self::$aFieldNumber[$sKey] * 10);
  639. }
  640. return $sType;
  641. } // function get_request_type
  642. /**
  643. * Get transaction ID from HTTP-request (for check/perform)
  644. * @return mixed
  645. */
  646. public function get_ta_id()
  647. {
  648. return $this->get_http_val(self::TA_ID_KEY);
  649. } // function get_ta_id
  650. /**
  651. * Get full request data for "check" and "perform" operation
  652. * @return mixed
  653. */
  654. public function get_request_data()
  655. {
  656. $aFields = $this->get_request_type() == 'check' ? self::$aCheckFields : self::$aPerformFields;
  657. $aRet = array();
  658. foreach ($aFields as $k => $v) {
  659. $mVal = $this->get_http_val($k);
  660. if (!is_null($mVal)) {
  661. $aRet[$k] = $mVal;
  662. }
  663. }
  664. return $aRet;
  665. } // function get_request_data
  666. /**
  667. * Check signature
  668. * @return boolean
  669. */
  670. public function check_signature($sSignature)
  671. {
  672. return $this->sSignKey ? $this->get_signature() == $sSignature : TRUE;
  673. } // function check_signature
  674. /**
  675. * Get signature
  676. * @return string
  677. */
  678. final public function get_signature()
  679. {
  680. if ($this->sSignKey) {
  681. $sStr = $this->sTaId . $this->nAmount . $this->sCurrency;
  682. $sStr .= empty($this->mCustom) || !empty($this->sState) ? '' : $this->mCustom;
  683. $sStr .= empty($this->sState) ? '' : $this->sState;
  684. $sStr .= empty($this->sDateTime) ? '' : $this->sDateTime;
  685. $sStr .= empty($this->iRand) ? '' : $this->iRand;
  686. $sStr .= $this->sSignKey;
  687. return md5($sStr);
  688. } else {
  689. return NULL;
  690. }
  691. } // function get_signature
  692. /**
  693. * Get signature key
  694. * @return string
  695. */
  696. final public function get_sign_key()
  697. {
  698. return $this->sSignKey;
  699. } // function get_sign_key
  700. /**
  701. * Get field numbers
  702. * @return array
  703. */
  704. public static function get_field_number($sKey = NULL)
  705. {
  706. return empty($sKey) ? self::$aFieldNumber : (isset(self::$aFieldNumber[$sKey]) ? self::$aFieldNumber[$sKey] : NULL);
  707. } // function get_field_number
  708. // -------------- Private/Protected methods -------------- \\
  709. /**
  710. * Get config
  711. * @param string $sSignKey
  712. * @return string
  713. */
  714. protected function get_config($sSignKey)
  715. {
  716. $sConfPath = $this->get_config_path();
  717. $aRet = $sConfPath && file_exists($sConfPath) ? include($sConfPath) : array();
  718. if (!empty($sSignKey)) {
  719. $aRet['sign_key'] = $sSignKey;
  720. }
  721. return $aRet;
  722. } // function get_config
  723. /**
  724. * Get path to config-file
  725. * @return string
  726. */
  727. protected function get_config_path()
  728. {
  729. return dirname(__FILE__) . '/config.php';
  730. } // function get_config_path
  731. /**
  732. * Get additional attributes
  733. * @return string
  734. */
  735. protected function set_date_and_rand()
  736. {
  737. $this->sDateTime = date('Y-m-d H:i:s');
  738. if (!empty($this->iUseRand) && (empty($this->iRand) || $this->iUseRand > 1)) {
  739. $this->iRand = rand(1, 1024);
  740. }
  741. } // function set_date_and_rand
  742. /**
  743. * Get additional attributes
  744. * @param array $aAttr
  745. * @return string
  746. */
  747. protected function get_additional_attr($aAttr)
  748. {
  749. $sRet = '';
  750. if ($aAttr) {
  751. foreach ($aAttr as $k => $v) {
  752. if (!in_array($k, array('type', 'name', 'value'))) {
  753. $sRet .= ' ' . $k . '="' . $v . '"';
  754. }
  755. }
  756. }
  757. return $sRet;
  758. } // function get_additional_attr
  759. /**
  760. * Prepare data for send (For "form" or "link"
  761. * @return array
  762. */
  763. protected function prepare_send_data()
  764. {
  765. $aRet = array();
  766. foreach (self::$aReqFields as $k => $v) {
  767. $mVal = $this->get_property_val($k, $v);
  768. if ($mVal) {
  769. if ($k == self::PAYMENT_MODE_KEY) {
  770. if (count($mVal) > 1) {
  771. $i = 0;
  772. foreach ($mVal as $v1) {
  773. $aRet[$k . '[' . $i++ . ']'] = $v1;
  774. }
  775. } else {
  776. $aRet[$k] = $mVal[0];
  777. }
  778. } else {
  779. $aRet[$k] = $mVal;
  780. }
  781. }
  782. }
  783. return $aRet;
  784. } // function prepare_send_data
  785. /**
  786. * Get value of property
  787. * @param string $sField
  788. * @param boolean $bRequired
  789. * @return mixed
  790. */
  791. protected function get_property_val($sField, $bRequired)
  792. {
  793. $nNum = self::$aFieldNumber[$sField] * 10;
  794. if ($sField == self::SIGNATURE_KEY) {
  795. $mPropVal = $this->get_signature();
  796. } else {
  797. $sProp = self::$aCorrespondence[$sField];
  798. $mPropVal = $this->$sProp;
  799. }
  800. if ($bRequired && !$mPropVal) {
  801. throw new copayco_exception('Required field "' . $sField . '" isn\'t set.', 20001 + $nNum);
  802. }
  803. return $mPropVal;
  804. } // function get_property_val
  805. /**
  806. * Check POST/GET fields of HTTP-request
  807. * @param array $aCheckFields
  808. * @return boolean
  809. */
  810. protected function check_http_fields($aCheckFields, $bSetErrMsg = FALSE)
  811. {
  812. foreach ($aCheckFields as $k => $v) {
  813. $nNum = self::$aFieldNumber[$k] * 10;
  814. $mVal = $this->get_http_val($k);
  815. if ($v && is_null($mVal)) {
  816. $this->fix_error_message('Undefined required field "' . $k . '".', 30001 + $nNum, $bSetErrMsg);
  817. }
  818. $sProp = isset(self::$aCorrespondence[$k]) ? self::$aCorrespondence[$k] : NULL;
  819. if ($v && $sProp && $mVal != $this->$sProp) {
  820. $this->fix_error_message('Field "' . $k . '" contain incorrect data.', 30002 + $nNum, $bSetErrMsg);
  821. }
  822. }
  823. if (!$this->check_signature($this->get_http_val(self::SIGNATURE_KEY))) {
  824. $this->fix_error_message('Request contain incorrect signature.', 30992, $bSetErrMsg);
  825. }
  826. return TRUE;
  827. } // function check_http_fields
  828. /**
  829. * Fix error message for method "check_http_fields"
  830. * @param string $sErrMsg
  831. * @param integer $nCode
  832. * @param boolean $bSetErrMsg
  833. */
  834. protected function fix_error_message($sErrMsg, $nCode, $bSetErrMsg)
  835. {
  836. if ($bSetErrMsg) {
  837. $this->set_error_message($sErrMsg);
  838. }
  839. throw new copayco_exception($sErrMsg, $nCode);
  840. } // function fix_error_message
  841. /**
  842. * Define extendet POST/GET value of HTTP-request
  843. */
  844. protected function define_http_val()
  845. {
  846. $aCor = array_flip(self::$aCorrespondence);
  847. foreach (self::$aAutoFill as $v) {
  848. if (empty($this->$v)) {
  849. $this->$v = $this->get_http_val($aCor[$v]);
  850. }
  851. }
  852. } // function define_http_val
  853. /**
  854. * Get POST/GET value of HTTP-request
  855. * @param string $sKey
  856. * @return mixed
  857. */
  858. protected function get_http_val($sKey)
  859. {
  860. return isset($_POST[$sKey]) ? $_POST[$sKey] : (isset($_GET[$sKey]) ? $_GET[$sKey] : NULL);
  861. } // function get_http_val
  862. /**
  863. * Send notification about delivering
  864. * @param string $sState - TA state
  865. */
  866. protected function send_notification($sState)
  867. {
  868. $this->sState = $sState;
  869. $oCurl = curl_init($this->get_notification_url());
  870. curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
  871. if ($this->bTestMode) {
  872. curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, 0);
  873. curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, 0);
  874. }
  875. $this->set_date_and_rand();
  876. $aData = array();
  877. foreach (self::$aNotificationFields as $k => $v) {
  878. $aData[$k] = $this->get_property_val($k, $v);
  879. }
  880. curl_setopt($oCurl, CURLOPT_POSTFIELDS, $aData);
  881. curl_exec($oCurl);
  882. $sErr = curl_error($oCurl);
  883. curl_close($oCurl);
  884. if ($sErr) {
  885. throw new copayco_exception('There is CURL error ocured:' . $sErr, 50001);
  886. }
  887. } // function send_notification
  888. /**
  889. * Output HTTP-header
  890. * @param string $sMsg
  891. * @param string $sCharset
  892. */
  893. protected function output_header($sMsg, $sCharset = NULL)
  894. {
  895. if (empty($sCharset)) {
  896. $sCharset = empty($this->sCharset) ? 'utf-8' : $this->sCharset;
  897. }
  898. header('Content-Type: text/plain; charset=' . $sCharset);
  899. header('Accept-Ranges: bytes');
  900. header('Content-Length: ' . strlen($sMsg));
  901. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  902. header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
  903. header(
  904. $_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.0' ?
  905. 'Pragma: no-cache' :
  906. 'Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0'
  907. ); // max-age=0
  908. } // function output_header
  909. } // class copayco_api
  910. /**
  911. * Copayco exception class
  912. * Structure of error code
  913. * |XX|XX|X|
  914. * | | |_ serial number
  915. * | |____ field number (See copayco_api::$aFieldNumber)
  916. * |_______ error type (10 - source data, 20 - make request, 30 - check data, 40 - perform data, 50 - notify delivering)
  917. *
  918. */
  919. class copayco_exception extends Exception
  920. {
  921. /**
  922. * Get error type code
  923. * @return boolean
  924. */
  925. public function get_error_type_code()
  926. {
  927. return substr($this->getCode(), 0, 2);
  928. } // function get_error_type_code
  929. /**
  930. * Get field code
  931. * @return boolean
  932. */
  933. public function get_field_code()
  934. {
  935. return substr($this->getCode(), 2, 2);
  936. } // function get_field_code
  937. /**
  938. * Get error serial number
  939. * @return boolean
  940. */
  941. public function get_error_serial_number()
  942. {
  943. return substr($this->getCode(), -1);
  944. } // function get_error_serial_number
  945. /**
  946. * Get field name
  947. * @return string
  948. */
  949. public function get_field_name()
  950. {
  951. $aFields = array_flip(copayco_api::get_field_number());
  952. $nCode = (int)$this->get_field_code();
  953. return $nCode && isset($aFields[$nCode]) ? $aFields[$nCode] : NULL;
  954. } // function get_field_name
  955. } // class copayco_exception
  956. ?>