/** * Show the special page */ protected function handleRequest() { $req = $this->getRequest(); // TODO: Don't do that. $fake = $req->getBool('fake'); $fail = $req->getBool('fail'); if ($fake) { if ($fail) { $this->displayFailPage(); return; } else { $go = ResultPages::getThankYouPage($this->adapter); } $this->getOutput()->addHTML("<br>Redirecting to page {$go}"); $this->getOutput()->redirect($go); return; } $forbidden = false; $this->qs_oid = $req->getText('order_id', ''); $this->qs_ref = $req->getText('REF', ''); if ($this->qs_oid === '' && $this->qs_ref === '') { $forbidden = true; $f_message = 'No order ID in the Querystring.'; } else { $result = $this->popout_if_iframe(); if ($result) { return; } } $session_oid = $this->adapter->session_getData('Donor', 'order_id'); if (is_null($session_oid) || $this->qs_oid !== $session_oid && strpos($this->qs_ref, (string) $session_oid) === false) { $forbidden = true; $f_message = "Requested order id not present in the session. (session_oid = '{$session_oid}')"; } if ($forbidden) { $this->logger->error($this->qs_oid . " Resultswitcher: forbidden for reason: {$f_message}"); wfHttpError(403, 'Forbidden', wfMessage('donate_interface-error-http-403')->text()); return; } $this->setHeaders(); $this->logger->info("Resultswitcher: OK to process Order ID: " . $this->qs_oid); // dispatch forms/handling if ($this->adapter->checkTokens()) { // Display form for the first time //this next block is for credit card coming back from GC. Only that. Nothing else, ever. if ($this->adapter->getData_Unstaged_Escaped('payment_method') === 'cc') { $sessionOrders = $req->getSessionData('order_status'); if (!is_array($sessionOrders) || !isset($sessionOrders[$this->qs_oid]) || !is_array($sessionOrders[$this->qs_oid])) { $result = $this->adapter->do_transaction('Confirm_CreditCard'); $session_info = array('data' => $result->getData(), 'message' => $result->getMessage(), 'errors' => $result->getErrors()); $sessionOrders[$this->qs_oid] = $session_info; $sessionOrders[$this->qs_oid]['data']['count'] = 0; } else { $sessionOrders = $req->getSessionData('order_status'); $sessionOrders[$this->qs_oid]['data']['count'] = $sessionOrders[$this->qs_oid]['data']['count'] + 1; $this->logger->error("Resultswitcher: Multiple attempts to process. " . $sessionOrders[$this->qs_oid]['data']['count']); $result = new PaymentTransactionResponse(); $result->setData($sessionOrders[$this->qs_oid]['data']); $result->setMessage($sessionOrders[$this->qs_oid]['message']); $result->setErrors($sessionOrders[$this->qs_oid]['errors']); } $req->setSessionData('order_status', $sessionOrders); $this->displayResultsForDebug($result); //do the switching between the... stuff. $status = $this->adapter->getFinalStatus(); if ($status) { switch ($status) { case FinalStatus::COMPLETE: case FinalStatus::PENDING: case FinalStatus::PENDING_POKE: $this->logger->info("Displaying thank you page for final status {$status}"); $go = ResultPages::getThankYouPage($this->adapter); break; case FinalStatus::FAILED: $this->logger->info('Displaying fail page for final status failed.'); $this->displayFailPage(); return; } if ($go) { $this->getOutput()->addHTML("<br>Redirecting to page {$go}"); $this->getOutput()->redirect($go); return; } else { $this->logger->error("Resultswitcher: No redirect defined. Order ID: {$this->qs_oid}"); } } else { $this->logger->error("Resultswitcher: No FinalStatus. Order ID: {$this->qs_oid}"); } } else { $this->logger->error("Resultswitcher: Payment method is not cc. Order ID: {$this->qs_oid}"); } } else { $this->logger->error("Resultswitcher: Token Check Failed. Order ID: {$this->qs_oid}"); } $this->displayFailPage(); }
/** * Called from do_transaction() in order to be able to deal with transactions that had * recoverable errors but that do require the entire transaction to be repeated. * * This function has the following extension hooks: * * pre_process_<strtolower($transaction)> * Called before the transaction is processed; intended to call setValidationAction() * if the transaction should not be performed. Anti-fraud can be performed in this * hook by calling $this->runAntifraudFilters(). * * * post_process_<strtolower($transaction)> * * @param string $transaction Name of the transaction being performed * @param &string() $retryVars Reference to an array of variables that caused the * transaction to fail. * * @return PaymentTransactionResponse * @throws UnexpectedValueException */ private final function do_transaction_internal($transaction, &$retryVars = null) { $this->debugarray[] = __FUNCTION__ . " is doing a {$transaction}."; //reset, in case this isn't our first time. $this->transaction_response = new PaymentTransactionResponse(); $this->final_status = false; $this->setValidationAction('process', true); $errCode = null; /* --- Build the transaction string for cURL --- */ try { $this->setCurrentTransaction($transaction); $this->executeIfFunctionExists('pre_process_' . $transaction); if ($this->getValidationAction() != 'process') { $this->logger->info("Failed pre-process checks for transaction type {$transaction}."); $this->transaction_response->setCommunicationStatus(false); $this->transaction_response->setMessage($this->getErrorMapByCodeAndTranslate('internal-0000')); $this->transaction_response->setErrors(array('internal-0000' => array('debugInfo' => "Failed pre-process checks for transaction type {$transaction}.", 'message' => $this->getErrorMapByCodeAndTranslate('internal-0000'), 'logLevel' => LogLevel::INFO))); return $this->transaction_response; } if (!$this->isBatchProcessor()) { // TODO: Maybe move this to the pre_process functions? $this->dataObj->saveContributionTrackingData(); } $commType = $this->getCommunicationType(); if ($commType === 'redirect') { //in the event that we have a redirect transaction that never displays the form, //save this most recent one before we leave. $this->session_pushFormName($this->getData_Unstaged_Escaped('ffname')); $this->transaction_response->setCommunicationStatus(true); // Build the redirect URL. $redirectUrl = $this->getProcessorUrl(); $redirectParams = $this->buildRequestParams(); if ($redirectParams) { // Add GET parameters, if provided. $redirectUrl .= '?' . http_build_query($redirectParams); } $this->transaction_response->setRedirect($redirectUrl); return $this->transaction_response; } elseif ($commType === 'xml') { $this->profiler->getStopwatch("buildRequestXML", true); // begin profiling $curlme = $this->buildRequestXML(); // build the XML $this->profiler->saveCommunicationStats("buildRequestXML", $transaction); // save profiling data } elseif ($commType === 'namevalue') { $this->profiler->getStopwatch("buildRequestNameValueString", true); // begin profiling $curlme = $this->buildRequestNameValueString(); // build the name/value pairs $this->profiler->saveCommunicationStats("buildRequestNameValueString", $transaction); // save profiling data } else { throw new UnexpectedValueException("Communication type of '{$commType}' unknown"); } } catch (Exception $e) { $this->logger->critical('Malformed gateway definition. Cannot continue: Aborting.\\n' . $e->getMessage()); $this->transaction_response->setCommunicationStatus(false); $this->transaction_response->setMessage($this->getErrorMapByCodeAndTranslate('internal-0001')); $this->transaction_response->setErrors(array('internal-0001' => array('debugInfo' => 'Malformed gateway definition. Cannot continue: Aborting.\\n' . $e->getMessage(), 'message' => $this->getErrorMapByCodeAndTranslate('internal-0001'), 'logLevel' => LogLevel::CRITICAL))); return $this->transaction_response; } /* --- Do the cURL request --- */ $this->profiler->getStopwatch(__FUNCTION__, true); $txn_ok = $this->curl_transaction($curlme); if ($txn_ok === true) { // We have something to slice and dice. $this->logger->info("RETURNED FROM CURL:" . print_r($this->transaction_response->getRawResponse(), true)); // Decode the response according to $this->getResponseType $formatted = $this->getFormattedResponse($this->transaction_response->getRawResponse()); // Process the formatted response. This will then drive the result action try { $this->processResponse($formatted); } catch (ResponseProcessingException $ex) { $errCode = $ex->getErrorCode(); $retryVars = $ex->getRetryVars(); $this->transaction_response->addError($errCode, array('message' => $this->getErrorMapByCodeAndTranslate('internal-0001'), 'debugInfo' => $ex->getMessage(), 'logLevel' => LogLevel::ERROR)); } } elseif ($txn_ok === false) { // nothing to process, so we have to build it manually $logMessage = 'Transaction Communication failed' . print_r($this->transaction_response, true); $this->logger->error($logMessage); $this->transaction_response->setCommunicationStatus(false); $this->transaction_response->setMessage($this->getErrorMapByCodeAndTranslate('internal-0002')); $this->transaction_response->setErrors(array('internal-0002' => array('debugInfo' => $logMessage, 'message' => $this->getErrorMapByCodeAndTranslate('internal-0002'), 'logLevel' => LogLevel::ERROR))); } // Log out how much time it took for the cURL request $this->profiler->saveCommunicationStats(__FUNCTION__, $transaction); if (!empty($retryVars)) { $this->logger->critical("{$transaction} Communication failed (errcode {$errCode}), will reattempt!"); // Set this by key so that the result object still has all the cURL data $this->transaction_response->setCommunicationStatus(false); $this->transaction_response->setMessage($this->getErrorMapByCodeAndTranslate($errCode)); $this->transaction_response->setErrors(array($errCode => array('debugInfo' => "{$transaction} Communication failed (errcode {$errCode}), will reattempt!", 'message' => $this->getErrorMapByCodeAndTranslate($errCode), 'logLevel' => LogLevel::CRITICAL))); } //if we have set errors by this point, the transaction is not okay $errors = $this->getTransactionErrors(); if (!empty($errors)) { $txn_ok = false; } // If we have any special post-process instructions for this // transaction, do 'em. // NOTE: If you want your transaction to fire off the post-process // logic, you need to run $this->postProcessDonation in a function // called // 'post_process' . strtolower($transaction) // in the appropriate gateway object. if ($txn_ok && empty($retryVars)) { $this->executeIfFunctionExists('post_process_' . $transaction); if ($this->getValidationAction() != 'process') { $this->logger->info("Failed post-process checks for transaction type {$transaction}."); $this->transaction_response->setCommunicationStatus(false); $this->transaction_response->setMessage($this->getErrorMapByCodeAndTranslate('internal-0000')); $this->transaction_response->setErrors(array('internal-0000' => array('debugInfo' => "Failed post-process checks for transaction type {$transaction}.", 'message' => $this->getErrorMapByCodeAndTranslate('internal-0000'), 'logLevel' => LogLevel::INFO))); return $this->transaction_response; } } // log that the transaction is essentially complete $this->logger->info('Transaction complete.'); if (!$this->isBatchProcessor()) { $this->debugarray[] = 'numAttempt = ' . $this->session_getData('numAttempt'); } return $this->transaction_response; }