protected function onPaymentNotification() { if (!$this->canRun()) { return; } ob_end_clean(); $name = $this->getTranslation($this->params->get('payment_name', 'PayPal')); require_once JPATH_ADMINISTRATOR . '/components/com_rsmembership/helpers/adapters/input.php'; $db = JFactory::getDBO(); $query = $db->getQuery(true); $jinput = RSInput::create(); $log = array(); $req = $this->_buildPostData(); $this->addLog("IPN received: {$req}"); // post back to PayPal system to validate $url = $this->params->get('mode') ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr'; $only_completed = (int) $this->params->get('only_completed', 0); if (!extension_loaded('curl') || !function_exists('curl_exec') || !is_callable('curl_exec')) { $this->addLog('[err] cURL is not installed or executable, cannot connect back to PayPal for validation!'); $this->finish(); } $this->addLog("Connecting to {$url} to verify if PayPal response is valid."); require_once JPATH_ADMINISTRATOR . '/components/com_rsmembership/helpers/version.php'; $version = (string) new RSMembershipVersion(); $website = JUri::root(); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com')); curl_setopt($ch, CURLOPT_USERAGENT, "RSMembership!/{$version} ({$website})"); $res = curl_exec($ch); $errstr = curl_error($ch); curl_close($ch); if ($errstr) { $this->addLog('[err] cURL reported error: ' . $errstr); $this->finish(); } // assign posted variables to local variables $item_name = $jinput->get('item_name', '', 'none'); $item_number = $jinput->get('item_number', '', 'none'); $payment_status = $jinput->get('payment_status', '', 'none'); $payment_amount = $jinput->get('mc_gross', '', 'none'); $payment_currency = $jinput->get('mc_currency', '', 'none'); $txn_id = $jinput->get('txn_id', '', 'none'); $txn_type = $jinput->get('txn_type', '', 'none'); $receiver_email = $jinput->get('receiver_email', '', 'none'); $payer_email = $jinput->get('payer_email', '', 'none'); $custom = $jinput->get('custom', 0, 'none'); // try to get the transaction id based on the custom hash $transaction_id = $this->getTransactionId($custom); // Do not deny the transaction for now. $deny = false; $this->addLog("Transaction ID is '{$transaction_id}', based on '{$custom}'."); if ($res) { $this->addLog("Successfully connected to {$url}. Response is {$res}"); if (strcmp($res, "VERIFIED") == 0) { $this->addLog("Response is VERIFIED."); $log[] = "PayPal reported a valid transaction."; $log[] = "Payment status is " . (!empty($payment_status) ? $payment_status : 'empty') . "."; // check the payment_status is Completed if (!$only_completed || $only_completed && $payment_status == 'Completed') { // sign up - do nothing, we use our "custom" parameter to identify the transaction if ($txn_type == 'subscr_signup') { $log[] = "Subscription signup has been received."; // If this is a free trial, we'll need to make sure that the transaction is accepted since "subscr_payment" will be received after the trial ends $mc_amount1 = $jinput->get('mc_amount1', '', 'none'); $subscr_id = $jinput->get('subscr_id', '', 'none'); if ((double) $mc_amount1 == (double) $transaction->price && $mc_amount1 == '0.00') { // Emulate the variables needed below to approve the transaction // No txn_id here, let's just use subscr_id so we can use something for PayPal identification. $txn_id = 'Subscription ID: ' . $subscr_id; $payment_amount = $mc_amount1; // Load the transaction so that it can be processed below $transaction = $this->getTransaction($transaction_id, 'id'); } } elseif ($txn_type == 'subscr_payment' || $txn_type == 'recurring_payment') { $log[] = "Adding new payment..."; // check that txn_id has not been previously processed // check custom_hash from db -> if custom_hash == txn_id $query->clear(); $query->select($db->qn('id'))->from($db->qn('#__rsmembership_transactions'))->where($db->qn('hash') . ' = ' . $db->q($txn_id))->where($db->qn('gateway') . ' = ' . $db->q($name)); $db->setQuery($query); if (!$db->loadResult()) { $transaction = $this->getTransaction($custom); // check if transaction exists if (!empty($transaction)) { // this transaction has already been processed // we need to create a new "renewal" transaction if ($transaction->status == 'completed') { $log[] = "Identified this payment as recurring."; $query->clear(); $query->select($db->qn('id'))->select($db->qn('user_id'))->select($db->qn('membership_id'))->from($db->qn('#__rsmembership_membership_subscribers'))->where($db->qn('from_transaction_id') . ' = ' . $db->q($transaction->id)); $db->setQuery($query); $membership = $db->loadObject(); if (!empty($membership)) { $user = JFactory::getUser($membership->user_id); JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_rsmembership/tables'); $transaction = JTable::getInstance('Transaction', 'RSMembershipTable'); $transaction->user_id = $user->get('id'); $transaction->user_email = $user->get('email'); $transaction->type = 'renew'; $params = array(); $params[] = 'id=' . $membership->id; $params[] = 'membership_id=' . $membership->membership_id; $transaction->params = implode(';', $params); // params, membership, extras etc $date = JFactory::getDate(); $transaction->date = $date->toSql(); $transaction->ip = $_SERVER['REMOTE_ADDR']; $transaction->price = $payment_amount; $transaction->currency = RSMembershipHelper::getConfig('currency'); $transaction->hash = ''; $transaction->gateway = $name; $transaction->status = 'pending'; // store the transaction $transaction->store(); RSMembership::finalize($transaction->id); $log[] = "Successfully added the recurring transaction to the database."; } else { $log[] = "Could not identify the original transaction for this recurring payment."; } } } else { $log[] = "Could not identify transaction with custom hash {$custom}. Stopping."; } } else { $log[] = "The transaction {$txn_id} has already been processed. Stopping."; } } else { // check that txn_id has not been previously processed // check custom_hash from db -> if custom_hash == txn_id $query->clear(); $query->select($db->qn('id'))->from($db->qn('#__rsmembership_transactions'))->where($db->qn('hash') . ' = ' . $db->q($txn_id))->where($db->qn('gateway') . ' = ' . $db->q($name)); $db->setQuery($query); if (!$db->loadResult()) { $query->clear(); $query->select('*')->from($db->qn('#__rsmembership_transactions'))->where($db->qn('custom') . ' = ' . $db->q($custom))->where($db->qn('status') . ' != ' . $db->q('completed')); $db->setQuery($query); $transaction = $db->loadObject(); // check if transaction exists if (empty($transaction)) { $log[] = "Could not identify transaction with custom hash {$custom}. Stopping."; } } else { $log[] = "The transaction {$txn_id} has already been processed. Stopping."; } } if (!empty($transaction)) { $plugin_email = $this->normalize($this->params->get('email')); $primary_email = $this->normalize($this->params->get('primary_email')); $receiver_email = $this->normalize($receiver_email); if (!$primary_email) { $primary_email = $plugin_email; } // check that receiver_email is your Primary PayPal email if ($receiver_email == $plugin_email || $receiver_email == $primary_email) { // check that payment_amount/payment_currency are correct // check $payment_amount == $price from $subscription_id && $payment_currency == $price from $subscription_id $price = $this->_convertNumber($transaction->price); $currency = $this->normalize(RSMembershipHelper::getConfig('currency')); $payment_currency = $this->normalize($payment_currency); if ((double) $payment_amount >= (double) $price) { if ($currency == $payment_currency) { // set the hash $this->setTransactionHash($transaction->id, $txn_id); // process payment unless manual activation selected $membership_id = $this->getMembershipId($transaction->params, $transaction->type); if ($membership_id) { $query->clear()->select('activation')->from($db->qn('#__rsmembership_memberships'))->where($db->qn('id') . ' = ' . $db->q((int) $membership_id)); $db->setQuery($query); $activation = $db->loadResult(); if ($activation != MEMBERSHIP_ACTIVATION_MANUAL) { RSMembership::approve($transaction->id); } $activationText = 'missing'; if ($activation == MEMBERSHIP_ACTIVATION_MANUAL) { $activationText = 'manual'; } elseif ($activation == MEMBERSHIP_ACTIVATION_AUTO) { $activationText = 'auto'; } elseif ($activation == MEMBERSHIP_ACTIVATION_INSTANT) { $activationText = 'instant'; } $log[] = "Activation is {$activationText}."; $log[] = "Successfully added the payment to the database."; } else { $log[] = "The membership could not be found in the database."; } } else { $log[] = "Expected a currency of {$currency}. PayPal reports this payment is made in {$payment_currency}. Stopping."; $deny = true; } } else { $log[] = "Expected an amount of {$price} {$currency}. PayPal reports this payment is {$payment_amount} {$payment_currency}. Stopping."; $deny = true; } } else { $log[] = "Expected payment to be made to {$plugin_email}" . ($primary_email ? " or {$primary_email}" : "") . ". PayPal reports this payment is made for {$receiver_email}. Stopping."; $deny = true; } } } else { $log[] = "Payment status is {$payment_status}. Stopping."; } } elseif (strcmp($res, "INVALID") == 0) { $this->addLog("[err] Response is INVALID."); $log[] = "Could not verify transaction authencity. PayPal said it's invalid."; $log[] = "String sent to PayPal is {$req}"; $deny = true; // log for manual investigation } else { $this->addLog("[err] PayPal response returned invalid data. Data is presented below:"); $this->addLog($res); $this->addLog("End of data."); $log[] = 'PayPal response is not valid! Should be either VERIFIED or INVALID, received "' . strip_tags($res) . '"'; } } else { $log[] = "Could not open {$url} in order to verify this transaction. Error reported is: {$errstr}"; } if ($transaction_id) { $log[] = "String sent by PayPal is {$req}"; RSMembership::saveTransactionLog($log, $transaction_id); if ($deny) { RSMembership::deny($transaction_id); } } $this->finish(); }
public function deny() { // Check for request forgeries JSession::checkToken() or jexit('Invalid Token'); // Get the selected items $cid = JFactory::getApplication()->input->get('cid', array(), 'array'); // Force array elements to be integers JArrayHelper::toInteger($cid, array(0)); $msg = ''; // No items are selected if (!is_array($cid) || count($cid) < 1) { JError::raiseWarning(500, JText::_('JERROR_NO_ITEMS_SELECTED')); } else { $user = JFactory::getUser(); $user_id = $user->get('username'); $total = 0; foreach ($cid as $id) { RSMembership::saveTransactionLog('Manually denied by ' . $user_id, $id); if (RSMembership::deny($id)) { $total++; } } $msg = JText::sprintf('COM_RSMEMBERSHIP_TRANSACTIONS_DENIED', $total); // Clean the cache, if any $cache = JFactory::getCache('com_rsmembership'); $cache->clean(); } $this->setRedirect(JRoute::_('index.php?option=com_rsmembership&view=transactions', false), $msg); }
function deny() { // Check for request forgeries JRequest::checkToken() or jexit('Invalid Token'); // Get the selected items $cid = JRequest::getVar('cid', array(0), 'post', 'array'); $total = count($cid); $msg = JText::sprintf('RSM_TRANSACTIONS_DENIED', $total); // Force array elements to be integers JArrayHelper::toInteger($cid, array(0)); $msg = ''; // No items are selected if (!is_array($cid) || count($cid) < 1) { JError::raiseWarning(500, JText::_('SELECT ITEM')); } else { $user =& JFactory::getUser(); $user_id = $user->get('username'); foreach ($cid as $id) { RSMembership::saveTransactionLog('Manually denied by ' . $user_id, $id); RSMembership::deny($id); } $total = count($cid); $msg = JText::sprintf('RSM_TRANSACTIONS_DENIED', $total); // Clean the cache, if any $cache =& JFactory::getCache('com_rsmembership'); $cache->clean(); } $this->setRedirect('index.php?option=com_rsmembership&view=transactions', $msg); }
protected function onOldPaymentNotification() { if (!$this->canRun()) { return; } $log = array(); $deny = false; $app = JFactory::getApplication(); $jinput = $app->input; $db = JFactory::getDBO(); $query = $db->getQuery(true); $recurring = $jinput->get('recurring', 0, 'int'); $custom = $jinput->get('custom', '', 'string'); $ordernumber = $this->params->get('mode') ? $jinput->get('order_number', '', 'string') : 1; $total = $jinput->get('total', '', 'string'); $key = $jinput->get('key', '', 'string'); $processed = $jinput->get('credit_card_processed', '', 'string'); $timestamp = $jinput->get('timestamp', '', 'string'); $payment_amount = $jinput->get('payment_amount', '', 'string'); $query->select('*')->from($db->qn('#__rsmembership_transactions'))->where($db->qn('custom') . ' = ' . $db->q($custom)); $db->setQuery($query); $db->execute(); $transaction = $db->loadObject(); $secret_word = $this->params->get('secret_word'); $sid = $this->params->get('id'); // calculate the hash $hash = strtoupper(md5($secret_word . $sid . $ordernumber . $total)); if ($hash != $key) { $log[] = JText::sprintf("PLG_SYSTEM_RSMEMBERSHIP2CO_VERIFICATION_ERROR", $key, $hash); $deny = true; } else { if ($recurring) { // recurring payment $log[] = "Identified this payment as recurring."; $query->clear(); $query->select($db->qn('id'))->select($db->qn('user_id'))->select($db->qn('membership_id'))->from($db->qn('#__rsmembership_membership_subscribers'))->where($db->qn('from_transaction_id') . ' = ' . $db->q($transaction->id)); $db->setQuery($query); $membership = $db->loadObject(); if (!empty($membership)) { $user = JFactory::getUser($membership->user_id); // get the serialized user_data from previous transaction $user_data = $transaction->user_data; // load new transaction object JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_rsmembership/tables'); $transaction = JTable::getInstance('Transaction', 'RSMembershipTable'); $transaction->user_id = $user->get('id'); $transaction->user_email = $user->get('email'); $transaction->user_data = $user_data; $transaction->type = 'renew'; $params = array(); $params[] = 'id=' . $membership->id; $params[] = 'membership_id=' . $membership->membership_id; $transaction->params = implode(';', $params); // params, membership, extras etc $transaction->ip = $_SERVER['REMOTE_ADDR']; $transaction->date = $timestamp; $transaction->price = $payment_amount; $transaction->currency = RSMembershipHelper::getConfig('currency'); $transaction->hash = ''; $transaction->gateway = $this->getTranslation($this->params->get('payment_name', '2Checkout')); $transaction->status = 'completed'; // store the transaction $transaction->store(); RSMembership::finalize($transaction->id); $log[] = "Successfully added the recurring transaction to the database."; } else { $log[] = "Could not identify the original transaction for this recurring payment."; } } else { // transaction exists if (empty($transaction) || $transaction->status == 'completed') { return; } // check if the amount is correct $price = $this->_convertNumber($transaction->price); $currency = strtolower(trim(RSMembershipHelper::getConfig('currency'))); if ($price <= $total) { // process payment if ($processed == 'Y') { // update order number $query->clear(); $query->update($db->qn('#__rsmembership_transactions'))->set($db->qn('hash') . ' = ' . $db->q($ordernumber))->where($db->qn('id') . ' = ' . $db->q($transaction->id)); $db->setQuery($query); $db->execute(); // approve RSMembership::approve($transaction->id); $log[] = JText::sprintf('PLG_SYSTEM_RSMEMBERSHIP2CO_PAYMENT_SUCCESS', $ordernumber); } else { $log[] = JText::_("PLG_SYSTEM_RSMEMBERSHIP2CO_CC_NOT_PROCESSED"); $deny = true; } } else { $log[] = JText::sprintf("PLG_SYSTEM_RSMEMBERSHIP2CO_EXPECTED_AMOUNT", $price, $currency, $total, $currency); $deny = true; } } } RSMembership::saveTransactionLog($log, $transaction->id); if ($deny) { RSMembership::deny($transaction->id); } $app->redirect('index.php?option=com_rsmembership&task=thankyou'); }