Cheetah
ChPmtPayPal.php
Go to the documentation of this file.
1 <?php
2 
8 require_once("ChPmtProvider.php");
9 
10 define('PP_MODE_LIVE', 1);
11 define('PP_MODE_TEST', 2);
12 
13 define('PP_PRC_TYPE_DIRECT', 1);
14 define('PP_PRC_TYPE_PDT', 2);
15 define('PP_PRC_TYPE_IPN', 3);
16 
18 {
20 
24  public function __construct($oDb, $oConfig, $aConfig)
25  {
26  parent::__construct($oDb, $oConfig, $aConfig);
27  $this->_bRedirectOnResult = false;
28 
29  $this->_sDataReturnUrl = $this->_oConfig->getDataReturnUrl() . $this->_sName . '/';
30  }
31  public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
32  {
33  $iMode = (int)$this->getOption('mode');
34  $sActionURL = $iMode == PP_MODE_LIVE ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
35 
36  if ($bRecurring) {
37  $aFormData = array(
38  'cmd' => '_xclick-subscriptions',
39  'a3' => sprintf("%.2f", (float)$aCartInfo['items_price']),
40  'p3' => $iRecurringDays,
41  't3' => 'D',
42  'src' => '1', // repeat billings unless member cancels subscription
43  'sra' => '1' // reattempt on failure
44  );
45  } else {
46  $aFormData = array(
47  'cmd' => '_xclick',
48  'amount' => sprintf("%.2f", (float)$aCartInfo['items_price'])
49  );
50  }
51 
52  $aFormData = array_merge($aFormData, array(
53  'business' => $iMode == PP_MODE_LIVE ? $this->getOption('business') : $this->getOption('sandbox'),
54  'bn' => 'Cheetah_SP',
55  'item_name' => _t('_payment_txt_payment_to', $aCartInfo['vendor_username']),
56  'item_number' => $iPendingId,
57  'currency_code' => $aCartInfo['vendor_currency_code'],
58  'no_note' => '1',
59  'no_shipping' => '1',
60  'custom' => md5($aCartInfo['vendor_id'] . $iPendingId)
61  ));
62 
63  $iIndex = 1;
64  foreach ($aCartInfo['items'] as $aItem) {
65  $aFormData['item_name'] .= ' ' . ($iIndex++) . '. ' . $aItem['title'];
66  }
67 
68  switch ($this->getOption('prc_type')) {
69  case PP_PRC_TYPE_PDT:
70  case PP_PRC_TYPE_DIRECT:
71  $aFormData = array_merge($aFormData, array(
72  'return' => $this->_sDataReturnUrl . $aCartInfo['vendor_id'],
73  'rm' => '2'
74  ));
75  break;
76  case PP_PRC_TYPE_IPN:
77  $aFormData = array_merge($aFormData, array(
78  'return' => $this->_oConfig->getReturnUrl(),
79  'notify_url' => $this->_sDataReturnUrl . $aCartInfo['vendor_id'],
80  'rm' => '1'
81  ));
82  break;
83  }
84 
85  Redirect($sActionURL, $aFormData, 'post', $this->_sCaption);
86  exit();
87  }
88 
89  // Deano mod. Remove the & reference from $aData
90  public function finalizeCheckout($aData)
91  {
92  // Deano mod. Changed from original.
93  // if ($aData['txn_type'] == 'web_accept' || isset($aData['tx'])) {
94  if ($aData['txn_type'] == 'web_accept' || $aData['txn_type'] == 'cart' || $aData['tx'] != '') {
95  return $this->_registerCheckout($aData);
96  }
97 
98  return array('code' => 2, 'message' => _t('_payment_pp_err_no_data_given'));
99  }
100 
109  // Deano mod. Remove the & reference from $aData
110  public function _registerCheckout($aData, $bSubscription = false, $iPendingId = 0)
111  {
112  if (empty($this->_aOptions) && isset($aData['item_number'])) {
113  $this->_aOptions = $this->getOptionsByPending($aData['item_number']);
114  }
115 
116  if (empty($this->_aOptions)) {
117  return array('code' => -1, 'message' => _t('_payment_pp_err_no_vendor_given'));
118  }
119 
120  $iPrcType = (int)$this->getOption('prc_type');
121 
122  // Deano mod. Changed this block of code from original.
123  if (($iPrcType == PP_PRC_TYPE_IPN || $iPrcType == PP_PRC_TYPE_DIRECT) && ($aData['item_number1'] == '' && $aData['txn_id'] == '')) {
124  return array('code' => 2, 'message' => _t('_payment_pp_err_no_data_given'));
125  } elseif ($iPrcType == PP_PRC_TYPE_PDT && $aData['tx'] == '') {
126  return array('code' => 2, 'message' => _t('_payment_pp_err_no_data_given'));
127  }
128 
129  // Not going to validate.
130  //$aResult = $this->_validateCheckout($aData);
131  // Set as if it passed validation.
132  $aResult = array('code' => 1, 'message' => _t('_payment_pp_msg_verified'));
133 
134  if (!$bSubscription || empty($iPendingId)) {
135  $iPendingId = (int)$aData['item_number1'];
136  }
137 
138  $aPending = $this->_oDb->getPending(array('type' => 'id', 'id' => $iPendingId));
139  if (!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0) {
140  return array('code' => -1, 'message' => _t('_payment_pp_err_already_processed'));
141  }
142 
143  //--- Update pending transaction ---//
144  $this->_oDb->updatePending($iPendingId, array(
145  'order' => $aData['txn_id'],
146  'error_code' => $aResult['code'],
147  'error_msg' => $aResult['message']
148  ));
149 
150  $sBuyerFirstName = process_db_input($aData['first_name'], CH_TAGS_STRIP);
151  $sBuyerLastName = process_db_input($aData['last_name'], CH_TAGS_STRIP);
152  $sBuyerEmail = process_db_input($aData['payer_email'], CH_TAGS_STRIP);
153 
154  $aResult['pending_id'] = $iPendingId;
155  $aResult['payer_name'] = _t('_payment_txt_buyer_name_mask', $sBuyerFirstName, $sBuyerLastName);
156  $aResult['payer_email'] = $sBuyerEmail;
157 
158  return $aResult;
159  }
160 
161  // Deano mod. Remove the & reference from $aData
162  public function _validateCheckout($aData)
163  {
164  $iMode = (int)$this->getOption('mode');
165  if ($iMode == PP_MODE_LIVE) {
166  $sBusiness = $this->getOption('business');
167  $sConnectionUrl = 'www.paypal.com';
168  } else {
169  $sBusiness = $this->getOption('sandbox');
170  $sConnectionUrl = 'www.sandbox.paypal.com';
171  }
172 
173  $iPrcType = $this->getOption('prc_type');
174  if ($iPrcType == PP_PRC_TYPE_DIRECT || $iPrcType == PP_PRC_TYPE_IPN) {
175  if ($aData['payment_status'] != 'Completed') {
176  return array('code' => 0, 'message' => _t('_payment_pp_err_not_completed'));
177  }
178 
179  if ($aData['business'] != $sBusiness) {
180  return array('code' => -1, 'message' => _t('_payment_pp_err_wrong_business'));
181  }
182 
183  $sRequest = 'cmd=_notify-validate';
184  foreach ($aData as $sKey => $sValue) {
185  if (in_array($sKey, array('cmd'))) {
186  continue;
187  }
188 
189  $sRequest .= '&' . urlencode($sKey) . '=' . urlencode(process_pass_data($sValue));
190  }
191 
192  $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
193  if ((int)$aResponse['code'] !== 0) {
194  return $aResponse;
195  }
196 
197  array_walk($aResponse['content'], function (&$arg) {
198  $arg = trim($arg);
199  });
200  if (strcmp($aResponse['content'][0], "INVALID") === 0) {
201  return array('code' => -1, 'message' => _t('_payment_pp_err_wrong_transaction'));
202  } elseif (strcmp($aResponse['content'][0], "VERIFIED") !== 0) {
203  return array('code' => 2, 'message' => _t('_payment_pp_err_wrong_verification_status'));
204  }
205  } elseif ($iPrcType == PP_PRC_TYPE_PDT) {
206  $sRequest = "cmd=_notify-synch&tx=" . $aData['tx'] . "&at=" . $this->getOption('token');
207  $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
208 
209  if ((int)$aResponse['code'] !== 0) {
210  return $aResponse;
211  }
212 
213  if (strcmp($aResponse['content'][0], "FAIL") === 0) {
214  return array('code' => -1, 'message' => _t('_payment_pp_err_wrong_transaction'));
215  } elseif (strcmp($aResponse['content'][0], "SUCCESS") !== 0) {
216  return array('code' => 2, 'message' => _t('_payment_pp_err_wrong_verification_status'));
217  }
218 
219  $aKeys = array();
220  foreach ($aResponse['content'] as $sLine) {
221  list($sKey, $sValue) = explode("=", $sLine);
222  $aKeys[urldecode($sKey)] = urldecode($sValue);
223  }
224 
225  $aData = array_merge($aData, $aKeys);
226 
227  if ($aData['payment_status'] != 'Completed') {
228  return array('code' => 0, 'message' => _t('_payment_pp_err_not_completed'));
229  }
230 
231  if ($aData['business'] != $sBusiness) {
232  return array('code' => -1, 'message' => _t('_payment_pp_err_wrong_business'));
233  }
234  }
235 
236  $aPending = $this->_oDb->getPending(array('type' => 'id', 'id' => $aData['item_number']));
237  $aVendor = $this->_oDb->getVendorInfoProfile($aPending['seller_id']);
238  $fAmount = (float)$this->_getReceivedAmount($aVendor['currency_code'], $aData);
239  if ($fAmount != (float)$aPending['amount']) {
240  return array('code' => -1, 'message' => _t('_payment_pp_err_wrong_amount'));
241  }
242 
243  if ($aData['custom'] != md5($aPending['seller_id'] . $aPending['id'])) {
244  return array('code' => -1, 'message' => _t('_payment_pp_err_wrong_custom_data'));
245  }
246 
247  return array('code' => 1, 'message' => _t('_payment_pp_msg_verified'));
248  }
249 
250  public function _readValidationData($sConnectionUrl, $sRequest)
251  {
252  $rConnect = curl_init('https://' . $sConnectionUrl . '/cgi-bin/webscr');
253  curl_setopt($rConnect, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
254  curl_setopt($rConnect, CURLOPT_POST, 1);
255  curl_setopt($rConnect, CURLOPT_RETURNTRANSFER, 1);
256  curl_setopt($rConnect, CURLOPT_POSTFIELDS, $sRequest);
257  curl_setopt($rConnect, CURLOPT_SSL_VERIFYPEER, 1);
258  curl_setopt($rConnect, CURLOPT_SSL_VERIFYHOST, 2);
259  curl_setopt($rConnect, CURLOPT_FORBID_REUSE, 1);
260  curl_setopt($rConnect, CURLOPT_HTTPHEADER, array('Connection: Close'));
261 
262  $sResponse = curl_exec($rConnect);
263  if (curl_errno($rConnect) == 60) { // CURL_SSL_CACERT
264  curl_setopt($rConnect, CURLOPT_CAINFO, CH_DIRECTORY_PATH_PLUGINS . 'curl/cacert.pem');
265  $sResponse = curl_exec($rConnect);
266  }
267 
268  curl_close($rConnect);
269  if (!$sResponse) {
270  return array('code' => 6, 'message' => $this->_sLangsPrefix . 'err_cannot_validate');
271  }
272 
273  return array('code' => 0, 'content' => explode("\n", $sResponse));
274  }
275 
276  public function _getReceivedAmount($sCurrencyCode, &$aResultData)
277  {
278  $fAmount = 0.00;
279  $fTax = isset($aResultData['tax']) ? (float)$aResultData['tax'] : 0.00;
280 
281  if ($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['payment_gross']) && !empty($aResultData['payment_gross'])) {
282  $fAmount = (float)$aResultData['payment_gross'] - $fTax;
283  } elseif ($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['mc_gross']) && !empty($aResultData['mc_gross'])) {
284  $fAmount = (float)$aResultData['mc_gross'] - $fTax;
285  } elseif ($aResultData['settle_currency'] == $sCurrencyCode && isset($aResultData['settle_amount']) && !empty($aResultData['settle_amount'])) {
286  $fAmount = (float)$aResultData['settle_amount'] - $fTax;
287  }
288 
289  return $fAmount;
290  }
291 }
ChPmtPayPal\finalizeCheckout
finalizeCheckout($aData)
Definition: ChPmtPayPal.php:90
process_db_input
process_db_input($sText, $iStripTags=0)
Definition: utils.inc.php:256
ChPmtProvider
Definition: ChPmtProvider.php:9
ChPmtPayPal\_getReceivedAmount
_getReceivedAmount($sCurrencyCode, &$aResultData)
Definition: ChPmtPayPal.php:276
ChPmtPayPal\initializeCheckout
initializeCheckout($iPendingId, $aCartInfo, $bRecurring=false, $iRecurringDays=0)
Definition: ChPmtPayPal.php:31
PP_MODE_LIVE
const PP_MODE_LIVE
Definition: ChPmtPayPal.php:10
$aResult
$aResult
Definition: index.php:19
php
ChPmtPayPal\_validateCheckout
_validateCheckout($aData)
Definition: ChPmtPayPal.php:162
Redirect
Redirect($ActionURL, $Params=null, $Method="get", $Title='Redirect')
Definition: utils.inc.php:432
exit
exit
Definition: cart.php:21
$iIndex
$iIndex
Definition: bottom_menu_compose.php:142
ChPmtProvider\getOptionsByPending
getOptionsByPending($iPendingId)
Definition: ChPmtProvider.php:47
$oDb
global $oDb
Definition: db.inc.php:39
ChPmtPayPal\$_sDataReturnUrl
$_sDataReturnUrl
Definition: ChPmtPayPal.php:19
_t
_t($key, $arg0="", $arg1="", $arg2="")
Definition: languages.inc.php:509
PP_PRC_TYPE_IPN
const PP_PRC_TYPE_IPN
Definition: ChPmtPayPal.php:15
$aConfig
$aConfig
Definition: config.php:8
CH_TAGS_STRIP
const CH_TAGS_STRIP
Definition: utils.inc.php:22
process_pass_data
process_pass_data($text, $strip_tags=0)
Definition: utils.inc.php:290
PP_PRC_TYPE_DIRECT
const PP_PRC_TYPE_DIRECT
Definition: ChPmtPayPal.php:13
ChPmtPayPal\_registerCheckout
_registerCheckout($aData, $bSubscription=false, $iPendingId=0)
Definition: ChPmtPayPal.php:110
ChPmtPayPal\__construct
__construct($oDb, $oConfig, $aConfig)
Definition: ChPmtPayPal.php:24
PP_PRC_TYPE_PDT
const PP_PRC_TYPE_PDT
Definition: ChPmtPayPal.php:14
empty
Attr AllowedRel this is empty
Definition: Attr.AllowedRel.txt:7
as
as
Definition: Filter.ExtractStyleBlocks.Escaping.txt:10
ChPmtPayPal
Definition: ChPmtPayPal.php:18
ChPmtPayPal\_readValidationData
_readValidationData($sConnectionUrl, $sRequest)
Definition: ChPmtPayPal.php:250
ChPmtProvider\getOption
getOption($sName)
Definition: ChPmtProvider.php:55