8 require_once(
"ChPmtProvider.php");
10 define(
'BP_STATUS_NEW',
'new');
11 define(
'BP_STATUS_PAID',
'paid');
12 define(
'BP_STATUS_CONFIRMED',
'confirmed');
13 define(
'BP_STATUS_COMPLETE',
'complete');
14 define(
'BP_STATUS_EXPIRED',
'expired');
15 define(
'BP_STATUS_INVALID',
'invalid');
17 define(
'BP_SPEED_HIGH',
'high');
18 define(
'BP_SPEED_MEDIUM',
'medium');
19 define(
'BP_SPEED_LOW',
'low');
29 $this->_bRedirectOnResult =
false;
36 $this->aBpOptions[
'redirectURL'] .= $aCartInfo[
'vendor_id'];
38 $this->aBpOptions[
'notificationURL'] .= $aCartInfo[
'vendor_id'];
39 $this->aBpOptions[
'notificationURL'] =
ch_append_url_params($this->aBpOptions[
'notificationURL'], array(
'bxssl' => 1));
41 switch ($aCartInfo[
'vendor_currency_code']) {
51 $this->aBpOptions[
'currency'] = $aCartInfo[
'vendor_currency_code'];
55 'vnd' => (
string)$aCartInfo[
'vendor_id'],
56 'clt' => (
string)$aCartInfo[
'client_id'],
57 'pnd' => (
string)$iPendingId
60 'itemDesc' =>
'Payment to ' . $aCartInfo[
'vendor_profile_name']
62 $aResponse = $this->
createInvoice($iPendingId, (
float)$aCartInfo[
'items_price'], $aPosData, $aOptions);
63 if(!
empty($aResponse[
'error']))
64 return _t(is_array($aResponse[
'error']) ? $aResponse[
'error'][
'message'] : $aResponse[
'error']);
66 header(
'Location: ' . $aResponse[
'url']);
74 return array(
'code' => 2,
'message' =>
_t(
'_payment_bp_err_no_data_given'));
76 if(
empty($this->_aOptions) && isset($aData[
'posData'][
'd'][
'pnd'])) {
78 if(
empty($this->_aOptions))
79 return array(
'code' => 3,
'message' =>
_t(
'_payment_bp_err_no_vendor_given'));
85 if($aPosData ===
false)
86 return array(
'code' => 4,
'message' =>
_t(
'_payment_bp_err_incorrect_data'));
98 $iPendingId = (int)$aPosData[
'pnd'];
100 $this->_oDb->updatePending($iPendingId, array(
101 'order' => $sOrderId,
106 $aPending = $this->_oDb->getPending(array(
'type' =>
'id',
'id' => $iPendingId));
107 if((
int)$aPending[
'processed'] != 0)
108 return array(
'code' => 6,
'message' =>
_t(
'_payment_bp_err_already_processed'));
111 $sSpeed = $this->aBpOptions[
'transactionSpeed'];
113 return array(
'code' => 1,
'message' =>
'',
'pending_id' => $iPendingId);
115 return array(
'code' => 7,
'message' =>
_t(
'_payment_bp_err_no_confirmation_given'));
121 'message' =>
_t(
'_payment_bp_msg_checkout_finished')
134 public function createInvoice($orderId, $price, $posData, $options = array()) {
156 $options = array_merge($this->aBpOptions, $options);
157 $pos = array(
'd' => $posData);
159 if ($this->aBpOptions[
'verifyPos'])
160 $pos[
'h'] = $this->
_hash(serialize($posData), $options[
'apiKey']);
162 $options[
'posData'] = json_encode($pos);
163 if(strlen($options[
'posData']) > 100)
164 return array(
'error' =>
'_payment_bp_err_posdata_exceed_limit');
166 $options[
'orderID'] = $orderId;
167 $options[
'price'] = $price;
169 $postOptions = array(
'orderID',
'itemDesc',
'itemCode',
'notificationEmail',
'notificationURL',
'redirectURL',
170 'posData',
'price',
'currency',
'physical',
'fullNotifications',
'transactionSpeed',
'buyerName',
171 'buyerAddress1',
'buyerAddress2',
'buyerCity',
'buyerState',
'buyerZip',
'buyerEmail',
'buyerPhone');
173 foreach($postOptions
as $o) {
174 if (array_key_exists(
$o, $options))
175 $post[
$o] = $options[
$o];
177 $post = json_encode($post);
179 $response = $this->
_curl(
'https://bitpay.com/api/invoice/', $options[
'apiKey'], $post);
181 if($this->aBpOptions[
'useLogging']) {
182 $this->
_log(
'Create Invoice: ');
183 $this->
_log(
'-- Data: ' . $post);
184 $this->
_log(
'Response: ');
185 $this->
_log($response);
191 catch (Exception $e) {
192 if($this->aBpOptions[
'useLogging'])
193 $this->
_log(
'Error: ' . $e->getMessage());
195 return array(
'error' => $e->getMessage());
211 $apiKey = $this->aBpOptions[
'apiKey'];
213 $response = $this->
_curl(
'https://bitpay.com/api/invoice/'.$invoiceId, $apiKey);
215 if (is_string($response))
218 $response[
'posData'] = json_decode($response[
'posData'],
true);
219 $response[
'posData'] = $response[
'posData'][
'd'];
223 catch (Exception $e) {
224 if($this->aBpOptions[
'useLogging'])
225 $this->
_log(
'Error: ' . $e->getMessage());
227 return 'Error: ' . $e->getMessage();
242 $currencies = array();
243 $rate_url =
'https://bitpay.com/api/rates';
246 $clist = json_decode(file_get_contents($rate_url),
true);
248 foreach($clist
as $key => $value)
249 $currencies[$value[
'code']] = $value[
'name'];
253 catch (Exception $e) {
254 if($this->aBpOptions[
'useLogging'])
255 $this->
_log(
'Error: ' . $e->getMessage());
257 return 'Error: ' . $e->getMessage();
274 $rate_url =
'https://bitpay.com/api/rates';
277 $clist = json_decode(file_get_contents($rate_url),
true);
279 foreach($clist
as $key => $value) {
280 if($value[
'code'] == $code)
281 $rate = number_format($value[
'rate'], 2,
'.',
'');
286 catch (Exception $e) {
287 if($this->aBpOptions[
'useLogging'])
288 $this->
_log(
'Error: ' . $e->getMessage());
289 return 'Error: ' . $e->getMessage();
295 $this->aBpOptions[
'apiKey'] = $this->
getOption(
'api_key');
300 $this->aBpOptions[
'verifyPos'] =
true;
303 $this->aBpOptions[
'notificationEmail'] = $this->
getOption(
'notification_email');
307 $this->aBpOptions[
'notificationURL'] = $this->_oConfig->getDataReturnUrl(
true) . $this->_sName .
'/';
311 $this->aBpOptions[
'redirectURL'] = CH_WSB_URL_ROOT . $this->_oConfig->getBaseUri() .
'act_checkout_finished/' . $this->_sName .
'/';
315 $this->aBpOptions[
'currency'] =
'BTC';
319 $this->aBpOptions[
'physical'] =
false;
325 $this->aBpOptions[
'fullNotifications'] = $this->
getOption(
'full_notifications') ==
'on';
328 $this->aBpOptions[
'transactionSpeed'] = $this->
getOption(
'transaction_speed');
332 $this->aBpOptions[
'logFile'] =
$GLOBALS[
'dir'][
'tmp'] .
'ch_payment_bp.log';
336 $this->aBpOptions[
'useLogging'] =
true;
350 $this->
_log(
'Notification received: ' . date(
"m.d.y H:i:s"));
352 $post = file_get_contents(
"php://input");
354 $this->
_log(
'Error: No post data');
358 $json = json_decode($post,
true);
359 $this->
_log(
'-- Data: ' . $post);
365 if(!array_key_exists(
'posData', $json)) {
366 $this->
_log(
'Error: No posData');
370 $json[
'posData'] = json_decode($json[
'posData'],
true);
371 if(
empty($json[
'posData']) || !is_array($json[
'posData'])) {
372 $this->
_log(
'Error: Empty posData');
378 catch (Exception $e) {
379 if($this->aBpOptions[
'useLogging'])
380 $this->
_log(
'Error: ' . $e->getMessage());
395 if(!$this->aBpOptions[
'verifyPos']) {
396 if(
empty($aPosData[
'd']) || !is_array($aPosData[
'd'])) {
397 $this->
_log(
'Error: Payment data cannot be found.');
401 return $aPosData[
'd'];
404 if($this->
_hash(serialize($aPosData[
'd']), $this->aBpOptions[
'apiKey']) != $aPosData[
'h']) {
405 $this->
_log(
'Error: Authentication failed (bad posData hash).');
409 return $aPosData[
'd'];
413 $iPendingId = (int)$aPosData[
'pnd'];
415 $aPending = $this->_oDb->getPending(array(
'type' =>
'id',
'id' => $iPendingId));
416 if(
empty($aPending) || !is_array($aPending) || $fAmount != (float)$aPending[
'amount'])
434 if (
empty($response) || !(is_string($response)))
435 return array(
'error' =>
'ChPmtBitPay::_decodeResponse expects a string parameter.');
437 return json_decode($response,
true);
439 catch (Exception $e) {
440 if($this->aBpOptions[
'useLogging'])
441 $this->
_log(
'Error: ' . $e->getMessage());
443 return array(
'error' => $e->getMessage());
456 protected function _hash($data, $key) {
458 $hmac = base64_encode(hash_hmac(
'sha256', $data, $key,
TRUE));
459 return strtr($hmac, array(
'+' =>
'-',
'/' =>
'_',
'=' =>
''));
461 catch (Exception $e) {
462 if($this->aBpOptions[
'useLogging'])
463 $this->
_log(
'Error: ' . $e->getMessage());
465 return 'Error: ' . $e->getMessage();
478 protected function _curl(
$url, $apiKey, $post =
false) {
479 if(!isset(
$url) || trim(
$url) ==
'' || !isset($apiKey) || trim($apiKey) ==
'') {
481 if($this->aBpOptions[
'useLogging'])
482 $this->
_log(
'Error: You must supply non-empty url and apiKey parameters.');
484 return array(
'error' =>
'You must supply non-empty url and apiKey parameters.');
492 curl_setopt($curl, CURLOPT_POST, 1);
493 curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
494 $length = strlen($post);
497 $uname = base64_encode($apiKey);
501 'Content-Type: application/json',
502 'Content-Length: ' . $length,
503 'Authorization: Basic ' . $uname,
506 curl_setopt($curl, CURLOPT_URL,
$url);
507 curl_setopt($curl, CURLOPT_PORT, 443);
508 curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
509 curl_setopt($curl, CURLOPT_TIMEOUT, 10);
510 curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ;
511 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
512 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
513 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
514 curl_setopt($curl, CURLOPT_FORBID_REUSE, 1);
515 curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1);
517 $responseString = curl_exec($curl);
519 if($responseString ==
false) {
520 $response = array(
'error' => curl_error($curl));
521 if($this->aBpOptions[
'useLogging'])
522 $this->
_log(
'Error: ' . curl_error($curl));
525 $response = json_decode($responseString,
true);
527 $response = array(
'error' =>
'invalid json: '.$responseString);
528 if($this->aBpOptions[
'useLogging'])
529 $this->
_log(
'Error - Invalid JSON: ' . $responseString);
539 if($this->aBpOptions[
'useLogging'])
540 $this->
_log(
'Invalid data found in apiKey value passed to Bitpay::curl method. (Failed: base64_encode(apikey))');
542 return array(
'error' =>
'Invalid data found in apiKey value passed to Bitpay::curl method. (Failed: base64_encode(apikey))');
545 catch (Exception $e) {
547 if($this->aBpOptions[
'useLogging'])
548 $this->
_log(
'Error: ' . $e->getMessage());
549 return array(
'error' => $e->getMessage());
563 protected function _log($contents) {
565 if(isset($this->aBpOptions[
'logFile']) && $this->aBpOptions[
'logFile'] !=
'') {
566 $file = $this->aBpOptions[
'logFile'];
571 $file = dirname(__FILE__) .
'/bplog.txt';
574 file_put_contents($file, date(
'm-d H:i:s').
": ", FILE_APPEND);
576 if (is_array($contents))
577 $contents = var_export($contents,
true);
578 else if (is_object($contents))
579 $contents = json_encode($contents);
581 file_put_contents($file, $contents.
"\n", FILE_APPEND);
583 catch (Exception $e) {
584 echo
'Error: ' . $e->getMessage();