/** * Process IPN request from ClickBank. Only process POST request * * @param object $_POST * @return int HTTP code */ public function ipn(SS_HTTPRequest $request) { if ($request->isPost()) { if (ClickBankManager::validate_ipn_request($request->postVars())) { ClickBankManager::process_ipn_request($request->postVars()); return Director::get_status_code(); } } return ErrorPage::response_for(404); }
public function webhook(SS_HTTPRequest $request) { $mandrill_events = $request->postVars(); foreach (json_decode($mandrill_events['mandrill_events']) as $event) { $MandrillEvent = new MandrillEvent(); $MandrillEvent->ts = $event->ts; $MandrillEvent->event = $event->event; $MandrillEvent->url = $event->url; $MandrillEvent->user_agent = $event->user_agent; $MandrillEvent->MessageID = $event->_id; $MandrillEvent->write(); } }
public function update(SS_HTTPRequest $request) { $member = Customer::currentUser(); if (!$member->canEdit()) { return $this()->httpError(401); } $updateData = $request->postVars(); $updateData = ProfiledMemberForm::update_models('update', $updateData, $member); $member->write(); /** @noinspection PhpParamsInspection */ ProfiledMemberForm::set_form_message("ProfileUpdated", CrackerjackForm::Good); $this->sendEmail('Update', $member, $updateData); return $this()->redirectBack(); }
/** * This method passes through an HTTP request to another webserver. * This proxy is used to avoid any cross domain issues. The proxy * uses a white-list of domains to minimize security risks. * * @param SS_HTTPRequest $data array of parameters * * $data['u']: URL (complete request string) * $data['no_header']: set to '1' to avoid sending header information * directly. * @return the CURL response */ public function dorequest($data) { $headers = array(); $vars = $data->requestVars(); $no_header = false; if (!isset($vars['u'])) { return "Invalid request: unknown proxy destination."; } $url = $vars['u']; if (isset($vars['no_header']) && $vars['no_header'] == '1') { $no_header = true; } $checkUrl = explode("/", $url); if (!in_array($checkUrl[2], self::get_allowed_host())) { return "Access denied to ({$url})."; } // Open the Curl session $session = curl_init($url); // If it's a POST, put the POST data in the body $isPost = $data->isPOST(); if ($isPost) { $postvars = ''; $vars = $data->getBody(); if ($vars) { $postvars = "body=" . $vars; } else { $vars = $data->postVars(); if ($vars) { foreach ($vars as $k => $v) { $postvars .= $k . '=' . $v . '&'; } } } $headers[] = 'Content-type: text/xml'; curl_setopt($session, CURLOPT_HTTPHEADER, $headers); curl_setopt($session, CURLOPT_POST, true); curl_setopt($session, CURLOPT_POSTFIELDS, $postvars); } // Don't return HTTP headers. Do return the contents of the call curl_setopt($session, CURLOPT_HEADER, false); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Make the call $xml = curl_exec($session); // The web service returns XML. Set the Content-Type appropriately if ($no_header == false) { header("Content-Type: text/xml"); } curl_close($session); return $xml; }
/** * Action to handle upload of a single file * * @param SS_HTTPRequest $request * @return SS_HTTPResponse * @return SS_HTTPResponse */ public function upload(SS_HTTPRequest $request) { // Find the first set of upload data that looks like it came from an // UploadField. // NOTE(Jake): There is only the SecurityID and the 'upload' data as this is done // in it's own AJAX request, not sent along with all the other data. foreach ($request->postVars() as $key => $value) { // todo(Jake): Test SS 3.1 compatibility // NOTE(Jake): Only tested in SS 3.2, UploadField::upload data may not look like this in 3.1... if ($value && isset($value['name']) && isset($value['type']) && isset($value['tmp_name'])) { // NOTE(Jake): UploadField requires this FormField to be the correct name so it can retrieve // the file information from postVar. So detect the first set of data that seems // like upload info and use it. $this->setName($key); break; } } return parent::upload($request); }
public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { self::$is_at_root = true; $this->setDataModel($model); $this->pushCurrent(); $this->init(); if (!($site = Multisites::inst()->getCurrentSiteId())) { return $this->httpError(404); } $page = SiteTree::get()->filter(array('ParentID' => $site, 'URLSegment' => 'home')); if (!($page = $page->first())) { return $this->httpError(404); } $request = new SS_HTTPRequest($request->httpMethod(), $page->RelativeLink(), $request->getVars(), $request->postVars()); $request->match('$URLSegment//$Action', true); $front = new MultisitesFrontController(); $response = $front->handleRequest($request, $model); $this->popCurrent(); return $response; }
/** * Renders the CheckfrontLinkGenerator template with filled in * - Package * - Posted array info * - AccessKey encoded so can copy/paste * - Link to copy paste to email * * @param SS_HTTPRequest $request * * @return HTMLText */ protected function generateLinks(SS_HTTPRequest $request) { $postVars = $request->postVars(); $packageID = $postVars[CheckfrontLinkGeneratorForm::PackageIDFieldName]; $packageResponse = CheckfrontModule::api()->fetchPackage($packageID); if (!($package = $packageResponse->getPackage())) { throw new CheckfrontException(_t('Package.NoSuchPackageMessage', "Package {id}not found", array('id' => $packageID)), CheckfrontException::TypeError); } /* if (!$organiserEvent = $packageResponse->getEvent($postVars[CheckfrontLinkGeneratorForm::OrganiserEventFieldName])) { throw new CheckfrontException(_t('Package.NoSuchEventMessage', "{type}event not found", array('type' => 'Organiser '))); } if (!$individualEvent = $packageResponse->getEvent($postVars[CheckfrontLinkGeneratorForm::IndividualEventFieldName])) { throw new CheckfrontException(_t('Package.NoSuchEventMessage', "{type}event not found", array('type' => 'Individual '))); } */ $accessKey = CheckfrontModule::crypto()->generate_key(); $organiserLink = $this->makeLink($accessKey, $postVars[CheckfrontLinkGeneratorForm::PackageIDFieldName], $postVars[CheckfrontLinkGeneratorForm::OrganiserStartDate], $postVars[CheckfrontLinkGeneratorForm::OrganiserEndDate], $postVars[CheckfrontLinkGeneratorForm::LinkTypeFieldName], CheckfrontModule::UserTypeOrganiser, $postVars[CheckfrontLinkGeneratorForm::PaymentTypeFieldName]); $individualLink = $this->makeLink($accessKey, $postVars[CheckfrontLinkGeneratorForm::PackageIDFieldName], $postVars[CheckfrontLinkGeneratorForm::IndividualStartDate], $postVars[CheckfrontLinkGeneratorForm::IndividualEndDate], $postVars[CheckfrontLinkGeneratorForm::LinkTypeFieldName], CheckfrontModule::UserTypeIndividual, $postVars[CheckfrontLinkGeneratorForm::PaymentTypeFieldName]); $form = $this->buildLinkGeneratorForm(); return $this->renderWith(array('CheckfrontLinkGenerator', 'Page'), array('ShowOutput' => true, 'Package' => $package, 'Posted' => new ArrayData($postVars), 'OrganiserLink' => $organiserLink, 'IndividualLink' => $individualLink, 'AccessKey' => $accessKey, 'CheckfrontForm' => $form)); }
/** * Handle a form submission. GET and POST requests behave identically. * Populates the form with {@link loadDataFrom()}, calls {@link validate()}, * and only triggers the requested form action/method * if the form is valid. * * @param SS_HTTPRequest $request * @throws SS_HTTPResponse_Exception */ public function httpSubmission($request) { // Strict method check if ($this->strictFormMethodCheck) { // Throws an error if the method is bad... if ($this->formMethod != $request->httpMethod()) { $response = Controller::curr()->getResponse(); $response->addHeader('Allow', $this->formMethod); $this->httpError(405, _t("Form.BAD_METHOD", "This form requires a " . $this->formMethod . " submission")); } // ...and only uses the variables corresponding to that method type $vars = $this->formMethod == 'GET' ? $request->getVars() : $request->postVars(); } else { $vars = $request->requestVars(); } // Populate the form $this->loadDataFrom($vars, true); // Protection against CSRF attacks $token = $this->getSecurityToken(); if (!$token->checkRequest($request)) { $securityID = $token->getName(); if (empty($vars[$securityID])) { $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", "There seems to have been a technical problem. Please click the back button, " . "refresh your browser, and try again.")); } else { // Clear invalid token on refresh $data = $this->getData(); unset($data[$securityID]); Session::set("FormInfo.{$this->FormName()}.data", $data); Session::set("FormInfo.{$this->FormName()}.errors", array()); $this->sessionMessage(_t("Form.CSRF_EXPIRED_MESSAGE", "Your session has expired. Please re-submit the form."), "warning"); return $this->controller->redirectBack(); } } // Determine the action button clicked $funcName = null; foreach ($vars as $paramName => $paramVal) { if (substr($paramName, 0, 7) == 'action_') { // Break off querystring arguments included in the action if (strpos($paramName, '?') !== false) { list($paramName, $paramVars) = explode('?', $paramName, 2); $newRequestParams = array(); parse_str($paramVars, $newRequestParams); $vars = array_merge((array) $vars, (array) $newRequestParams); } // Cleanup action_, _x and _y from image fields $funcName = preg_replace(array('/^action_/', '/_x$|_y$/'), '', $paramName); break; } } // If the action wasn't set, choose the default on the form. if (!isset($funcName) && ($defaultAction = $this->defaultAction())) { $funcName = $defaultAction->actionName(); } if (isset($funcName)) { Form::set_current_action($funcName); $this->setButtonClicked($funcName); } // Permission checks (first on controller, then falling back to form) if ($this->controller->hasMethod($funcName) && !$this->controller->checkAccessAction($funcName) && !$this->actions->dataFieldByName('action_' . $funcName)) { return $this->httpError(403, sprintf('Action "%s" not allowed on controller (Class: %s)', $funcName, get_class($this->controller))); } elseif ($this->hasMethod($funcName) && !$this->checkAccessAction($funcName)) { return $this->httpError(403, sprintf('Action "%s" not allowed on form (Name: "%s")', $funcName, $this->name)); } // TODO : Once we switch to a stricter policy regarding allowed_actions (meaning actions must be set // explicitly in allowed_actions in order to run) // Uncomment the following for checking security against running actions on form fields /* else { // Try to find a field that has the action, and allows it $fieldsHaveMethod = false; foreach ($this->Fields() as $field){ if ($field->hasMethod($funcName) && $field->checkAccessAction($funcName)) { $fieldsHaveMethod = true; } } if (!$fieldsHaveMethod) { return $this->httpError( 403, sprintf('Action "%s" not allowed on any fields of form (Name: "%s")', $funcName, $this->Name()) ); } }*/ // Validate the form if (!$this->validate()) { return $this->getValidationErrorResponse(); } // First, try a handler method on the controller (has been checked for allowed_actions above already) if ($this->controller->hasMethod($funcName)) { return $this->controller->{$funcName}($vars, $this, $request); // Otherwise, try a handler method on the form object. } elseif ($this->hasMethod($funcName)) { return $this->{$funcName}($vars, $this, $request); } elseif ($field = $this->checkFieldsForAction($this->Fields(), $funcName)) { return $field->{$funcName}($vars, $this, $request); } return $this->httpError(404); }
/** * Update the order form cart, called via AJAX with current order form data. * Renders the cart and sends that back for displaying on the order form page. * * @param SS_HTTPRequest $data Form data sent via AJAX POST. * @return String Rendered cart for the order form, template include 'CheckoutFormOrder'. */ function updateOrderFormCart(SS_HTTPRequest $data) { if ($data->isPOST()) { $fields = array(); $validator = new OrderFormValidator(); $member = Customer::currentUser() ? Customer::currentUser() : singleton('Customer'); $order = CartControllerExtension::get_current_order(); //Update the Order $order->addAddressesAtCheckout($data->postVars()); $order->addModifiersAtCheckout($data->postVars()); //TODO update personal details, notes and payment type? //Create the part of the form that displays the Order $this->addItemFields($fields, $validator, $order); $this->addModifierFields($fields, $validator, $order); //This is going to go through and add modifiers based on current Form DATA //TODO This should be constructed for non-dropdown fields as well //Update modifier form fields so that the dropdown values are correct $newModifierData = array(); $subTotalModifiers = isset($fields['SubTotalModifiers']) ? $fields['SubTotalModifiers'] : array(); $totalModifiers = isset($fields['Modifiers']) ? $fields['Modifiers'] : array(); $modifierFields = array_merge($subTotalModifiers, $totalModifiers); foreach ($modifierFields as $field) { if (method_exists($field, 'updateValue')) { $field->updateValue($order); } $modifierClassName = get_class($field->getModifier()); $newModifierData['Modifiers'][$modifierClassName] = $field->Value(); } //Add modifiers to the order again so that the new values are used $order->addModifiersAtCheckout($newModifierData); $actions = new FieldSet(new FormAction('ProcessOrder', _t('CheckoutPage.PROCEED_TO_PAY', "Proceed to pay"))); $form = new CheckoutForm($this, 'OrderForm', $fields, $actions, $validator, $order); $form->disableSecurityToken(); $form->validate(); return $form->renderWith('CheckoutFormOrder'); } }
/** * We intercept the submit handler since we have to alter some field * checks depending on the status of the field "InvoiceAddressAsShippingAddress". * * @param SS_HTTPRequest $data submit data * @param Form $form form object * * @return ViewableData * * @author Sascha Koehler <*****@*****.**>, * Sebastian Diel <*****@*****.**> * @since 20.01.2014 */ public function submit($data, $form) { // Disable the check instructions if the shipping address shall be // the same as the invoice address. if ($data['InvoiceAddressAsShippingAddress'] == '1') { $this->deactivateValidationFor('Shipping_Salutation'); $this->deactivateValidationFor('Shipping_AcademicTitle'); $this->deactivateValidationFor('Shipping_FirstName'); $this->deactivateValidationFor('Shipping_Surname'); $this->deactivateValidationFor('Shipping_Addition'); $this->deactivateValidationFor('Shipping_Street'); $this->deactivateValidationFor('Shipping_StreetNumber'); $this->deactivateValidationFor('Shipping_Postcode'); $this->deactivateValidationFor('Shipping_City'); $this->deactivateValidationFor('Shipping_PhoneAreaCode'); $this->deactivateValidationFor('Shipping_Phone'); $this->deactivateValidationFor('Shipping_Country'); } $formData = $data->postVars(); if ($this->UseMinimumAgeToOrder()) { $formData['Birthday'] = $formData['BirthdayYear'] . '-' . $formData['BirthdayMonth'] . '-' . $formData['BirthdayDay']; if (!SilvercartConfig::CheckMinimumAgeToOrder($formData['Birthday'])) { $this->errorMessages['BirthdayDay'] = array('message' => SilvercartConfig::MinimumAgeToOrderError(), 'fieldname' => _t('SilvercartPage.BIRTHDAY') . ' - ' . _t('SilvercartPage.DAY'), 'BirthdayDay' => array('message' => SilvercartConfig::MinimumAgeToOrderError())); $this->errorMessages['BirthdayMonth'] = array('message' => SilvercartConfig::MinimumAgeToOrderError(), 'fieldname' => _t('SilvercartPage.BIRTHDAY') . ' - ' . _t('SilvercartPage.MONTH'), 'BirthdayMonth' => array('message' => SilvercartConfig::MinimumAgeToOrderError())); $this->errorMessages['BirthdayYear'] = array('message' => SilvercartConfig::MinimumAgeToOrderError(), 'fieldname' => _t('SilvercartPage.BIRTHDAY') . ' - ' . _t('SilvercartPage.YEAR'), 'BirthdayYear' => array('message' => SilvercartConfig::MinimumAgeToOrderError())); $this->setSubmitSuccess(false); return $this->submitFailure($data, $form); } } parent::submit($data, $form); }
/** * Generates a fake request for the field * @param {SS_HTTPRequest} $request Source Request to base the fake request off of * @param {Widget} $sourceWidget Source widget * @param {string} $baseLink Base URL to be truncated off of the form * @return {SS_HTTPRequest} Fake HTTP Request used to fool the form field into thinking the request was made to it directly */ protected function getFakeRequest(SS_HTTPRequest $request, Widget $sourceWidget, $baseLink) { $fieldName = rawurldecode($request->param('FieldName')); $objID = preg_replace('/Widget\\[(.*?)\\]\\[(.*?)\\]\\[(.*?)\\]$/', '$2', $fieldName); $finalPostVars = array(); if ($request->isPOST()) { $postVars = $request->postVars(); //Pull the post data for the widget if (isset($postVars['Widget'][$this->getName()][$objID])) { $finalPostVars = $postVars['Widget'][$this->getName()][$objID]; } else { $finalPostVars = array(); } $finalPostVars = array_merge($finalPostVars, $postVars); unset($finalPostVars['Widget']); //Workaround for UploadField's and GridFields confusing the request $fields = $sourceWidget->getCMSFields(); $uploadFields = array(); $gridFields = array(); foreach ($fields as $field) { if ($field instanceof UploadField) { $uploadFields[] = $field->getName(); } else { if ($field instanceof GridField) { $gridFields[] = $field->getName(); } } } //Re-orgazine the upload field data if (count($uploadFields)) { foreach ($uploadFields as $field) { $formFieldName = 'Widget[' . $this->getName() . '][' . $objID . '][' . $field . ']'; $fieldData = array($formFieldName => array('name' => array('Uploads' => array()), 'type' => array('Uploads' => array()), 'tmp_name' => array('Uploads' => array()), 'error' => array('Uploads' => array()), 'size' => array('Uploads' => array()))); if (isset($postVars['Widget']['name'][$this->getName()][$objID][$field]['Uploads'])) { for ($i = 0; $i < count($postVars['Widget']['name'][$this->getName()][$objID][$field]['Uploads']); $i++) { $fieldData[$formFieldName]['name']['Uploads'][] = $postVars['Widget']['name'][$this->getName()][$objID][$field]['Uploads'][$i]; $fieldData[$formFieldName]['type']['Uploads'][] = $postVars['Widget']['type'][$this->getName()][$objID][$field]['Uploads'][$i]; $fieldData[$formFieldName]['tmp_name']['Uploads'][] = $postVars['Widget']['tmp_name'][$this->getName()][$objID][$field]['Uploads'][$i]; $fieldData[$formFieldName]['error']['Uploads'][] = $postVars['Widget']['error'][$this->getName()][$objID][$field]['Uploads'][$i]; $fieldData[$formFieldName]['size']['Uploads'][] = $postVars['Widget']['size'][$this->getName()][$objID][$field]['Uploads'][$i]; } } $finalPostVars = array_merge_recursive($finalPostVars, $fieldData); } } //Reorganize the gridfield data if (count($gridFields) && isset($postVars['Widget'][$this->getName()][$objID])) { foreach ($gridFields as $field) { $formFieldName = 'Widget[' . $this->getName() . '][' . $objID . '][' . $field . ']'; $fieldData = array($formFieldName => $postVars['Widget'][$this->getName()][$objID][$field]); } $finalPostVars = array_merge_recursive($finalPostVars, $fieldData); } } $headers = $request->getHeaders(); $request = new SS_HTTPRequest($_SERVER['REQUEST_METHOD'], str_replace(rtrim($baseLink, '/'), '', rtrim($request->getURL(), '/')) . '/', $request->getVars(), $finalPostVars, $request->getBody()); $request->match('$Action/$ID/$OtherID'); //Merge in the headers foreach ($headers as $header => $value) { $request->addHeader($header, $value); } return $request; }
/** * Action to do a login * * @param SS_HTTPRequest $request Request to check for product data * @param bool $doRedirect Redirect after setting search settings? * * @return void * * @author Sebastian Diel <*****@*****.**> * @since 30.06.2014 */ public function doLogin(SS_HTTPRequest $request, $doRedirect = true) { $postVars = $request->postVars(); $emailAddress = $postVars['emailaddress']; $password = $postVars['password']; $member = Member::get()->filter('Email', $emailAddress)->first(); if ($member instanceof Member && $member->exists()) { $customer = MemberAuthenticator::authenticate(array('Email' => $emailAddress, 'Password' => $password)); if ($customer instanceof Member && $customer->exists()) { //transfer cart positions from an anonymous user to the one logging in $anonymousCustomer = SilvercartCustomer::currentAnonymousCustomer(); if ($anonymousCustomer) { if ($anonymousCustomer->getCart()->SilvercartShoppingCartPositions()->count() > 0) { //delete registered customers cart positions if ($customer->getCart()->SilvercartShoppingCartPositions()) { foreach ($customer->getCart()->SilvercartShoppingCartPositions() as $position) { $position->delete(); } } //add anonymous positions to the registered user foreach ($anonymousCustomer->getCart()->SilvercartShoppingCartPositions() as $position) { $customer->getCart()->SilvercartShoppingCartPositions()->add($position); } } $anonymousCustomer->logOut(); $anonymousCustomer->delete(); } $customer->logIn(); $customer->write(); } else { $messages = array('Authentication' => array('message' => _t('SilvercartPage.CREDENTIALS_WRONG'))); } } else { $messages = array('Authentication' => array('message' => _t('SilvercartPage.CREDENTIALS_WRONG'))); } $this->redirectBack($postVars['redirect_to']); }
/** * Populates the form somewhat intelligently * @param SS_HTTPRequest $request Any request * @param Member $member Any member * @param array $required Any validation messages * @return $this */ public function populateFromSources(SS_HTTPRequest $request = null, Member $member = null, array $required = null) { $dataPath = "FormInfo.{$this->FormName()}.data"; if (isset($member)) { $this->loadDataFrom($member); } else { if (isset($request)) { $this->loadDataFrom($request->postVars()); } else { if (Session::get($dataPath)) { $this->loadDataFrom(Session::get($dataPath)); } else { if ($failover = $this->getSessionData()) { $this->loadDataFrom($failover); } } } } if (!empty($required)) { $this->setRequiredFields($required); } return $this; }
/** * - setup session in checkfront * - add package to session * - add items to session * - call the 'book' endpoint to make the booking * * @param SS_HTTPRequest $request * * @return CheckfrontForm */ protected function book(SS_HTTPRequest $request) { $message = ''; $messageType = ''; $result = array(); // only post request should route here $postVars = $request->postVars(); try { $this->clearCheckfrontSession(); $packageID = $this->getTokenInfo(CheckfrontModule::TokenItemIDIndex, $postVars[CheckfrontForm::AccessKeyFieldName]); if ($request->isPOST()) { $startDate = $request->postVar('StartDate'); $endDate = $request->postVar('EndDate'); $ratedPackageResponse = $this->api()->fetchPackage($packageID, $startDate, $endDate); if ($ratedPackageResponse->isValid()) { $package = $ratedPackageResponse->getPackage(); $this->api()->addPackageToSession($package); foreach ($postVars['ItemID'] as $index => $itemID) { if (isset($postVars['Quantity'][$index])) { if ($quantity = $postVars['Quantity'][$index]) { /** * CheckfrontAPIItemResponse */ $response = $this->api()->fetchItem($itemID, $quantity, $startDate, $endDate); if ($response->isValid()) { if ($item = $response->getItem()) { $this->api()->addItemToSession($item); } } else { throw new CheckfrontBookingException($response->getMessage(), CheckfrontException::TypeError); } } } } $bookingResponse = $this->api()->makeBooking(CheckfrontBookingModel::create_from_checkfront($postVars, 'from-form')); if ($bookingResponse->isValid()) { $paymentMethod = $this->getTokenInfo(CheckfrontModule::TokenPaymentTypeIndex, $postVars[CheckfrontForm::AccessKeyFieldName]); if ($paymentMethod == CheckfrontModule::PaymentPayNow) { $message = 'Thanks for booking, please click the link below to complete payment on your booking'; $messageType = CheckfrontException::TypeOK; if ($paymentURL = $bookingResponse->getPaymentURL()) { $result = array('PaymentURL' => $paymentURL); $this()->redirect($paymentURL); } } else { $message = 'Thanks for booking, you will receive email confirmation shortly'; $messageType = CheckfrontException::TypeOK; $result = array('CurrentPackage' => $package, 'Booking' => $bookingResponse->getBooking(), 'Items' => $bookingResponse->getItems()); } } else { throw new CheckfrontBookingException($bookingResponse->getMessage(), CheckfrontException::TypeError); } } } } catch (CheckfrontException $e) { $message = $e->getMessage(); $messageType = $e->getType(); $this->api()->clearSession(); Session::setFormMessage(CheckfrontPackageBookingForm::FormName, $message, 'bad'); $result = $this->buildBookingForm($request); } return array_merge(array(self::MessageKey => $message, self::MessageTypeKey => $messageType), $result); }
/** * handleGatewayResponse * This action should be used when a gateway submits a POST/GET response * for which we need to action. In this case, the PayPal IPN. We shall * return void as nothing is returned from this method. It is not public * facing and is present to handle system to system communications over * HTTP communications only. If the gateway doesn't support POST/GET type * responses, implement the back office order updating within the * newPaymentSuccess() method instead. * * ATTRIBUTION * Snippets of IPN code were used from PayPal's GitHub samples on 15-10-2015. * https://github.com/paypal/ipn-code-samples/blob/master/paypal_ipn.php * @author PayPal * * @param SS_HTTPRequest $request The GET/POST variables and URL parameters. * @return Void */ public function handleGatewayResponse($request) { /** * Only proceed if we have postVars set */ if ($request->postVars()) { $gateway = DataObject::get_one("Gateway_PayPal"); $debug = $gateway->Debug; /** * STEP ONE * Prepend cmd=_notify-validate to the POST request from PayPal. * Reading posted data direction from $request->postVars() may * cause serialization isusues with array data. We therefore * will read directly from the input stream instead. */ $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); $myPost = array(); foreach ($raw_post_array as $keyval) { $keyval = explode('=', $keyval); if (count($keyval) == 2) { $myPost[$keyval[0]] = urldecode($keyval[1]); } } $req = 'cmd=_notify-validate'; if (function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exists = true; } foreach ($myPost as $key => $value) { if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&{$key}={$value}"; } /** * STEP TWO * Which PayPal URL are we dealing with? */ if (DataObject::get_one("Gateway_PayPal")->Sandbox) { $paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"; } else { $paypal_url = "https://www.paypal.com/cgi-bin/webscr"; } /** * STEP THREE * Initiate curl IPN callback to post IPN data back to PayPal * to validate the IPN data is genuine. Without this step anyone * can fake IPN data and mess with your order system. */ $ch = curl_init($paypal_url); if ($ch == FALSE) { return FALSE; } /* Set curl Options */ 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, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); /* Set TCP timeout to 30 seconds */ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); /* Execute Curl and Store Response in $res */ $res = curl_exec($ch); /* Are there curl errors? If yes, log them if Debug is enabled. */ if (curl_errno($ch) != 0) { if ($debug == 1) { $this->newLogEntry("Can't connect to PayPal to validate IPN message: " . curl_error($ch)); } curl_close($ch); exit; /* No errors */ } else { /* If Debug is enabled, save to the log. */ if ($debug == 1) { $this->newLogEntry("HTTP request of validation request" . curl_getinfo($ch, CURLINFO_HEADER_OUT) . " for IPN payload: {$req}"); $this->newLogEntry("HTTP response of validation request: {$res}"); } curl_close($ch); } /** * STEP FOUR * Inspect IPN validation result and act accordingly. * 1 - Split response headers and payload, a better way for strcmp. * 2 - Do the actions, based on response. */ $tokens = explode("\r\n\r\n", trim($res)); $res = trim(end($tokens)); if (strcmp($res, "VERIFIED") == 0) { /** * DEBUG * If debug is enabled, log the details * of this IPN response. */ if ($debug) { $this->newLogEntry("Verified IPN: {$req} "); } /** * ERROR CHECK 1 * txn_type must be of type 'web_accept'. (Buy Now Button) */ if (!$request->postVar("txn_type") == "web_accept") { if ($debug == 1) { $this->newLogEntry("ERROR: (txn_id: " . $request->postVar("txn_id") . ") txn_type is not of type 'web_accept'."); } return Store_Controller::create()->httpError(400); exit; } /** * ERROR CHECK 2 * We must be the intended recipient for the transaction. */ if ($gateway->EmailAddress != $request->postVar("receiver_email")) { if ($debug == 1) { $this->newLogEntry("ERROR: (txn_id: " . $request->postVar("txn_id") . ") Intended recipient " . "(" . $request->postVar("receiver_email") . ") does not " . "match that set in the gateway settings."); } return Store_Controller::create()->httpError(400); exit; } /** * ERROR CHECK 3 * An order related to this payment must exist. */ $order = new SQLQuery("COUNT(*)"); $order->setFrom("`order`")->addWhere("(`id`='" . $request->postVar("custom") . "')"); if ($order->execute()->value() < 1) { if ($debug == 1) { $this->newLogEntry("ERROR: (txn_id: " . $request->postVar("txn_id") . ") The order number defined in 'custom' " . "(" . $request->postVar("custom") . ") does not exist in the system."); } return Store_Controller::create()->httpError(400); exit; } /** * ERROR CHECK 4 * This IPN message can not be a duplicate. */ $dup = new SQLQuery("COUNT(*)"); $dup->setFrom("`Order_Payment_PayPal`"); $dup->addWhere("(`txn_id`='" . $request->postVar("txn_id") . "') AND (`payment_status`='" . $request->postVar("payment_status") . "')"); $dup_count = $dup->execute()->value(); if ($dup_count > 0) { if ($debug == 1) { $this->newLogEntry("ERROR: (txn_id: " . $request->postVar("txn_id") . ") The IPN message received is a duplicate of one " . "previously received."); } return Store_Controller::create()->httpError(400); exit; } /** * ERROR CHECK 5 * The mc_gross has to match the total order price. */ $order_total = DataObject::get_by_id("Order", $request->postVar("custom"))->calculateOrderTotal(); $mc_gross = $request->postVar("mc_gross"); if ($order_total != $mc_gross) { if ($debug == 1) { $this->newLogEntry("ERROR: (txn_id: " . $request->postVar("txn_id") . ") The payment amount did not match the order amount."); } return Store_Controller::create()->httpError(400); exit; } /** * ERROR CHECK 6 * If this IPN is not a duplicate, are there * any other entries for this txn_id? */ if ($dup_count < 1) { /* Count how many entries there are with the IPNs txn_id */ $record_count = new SQLQuery("COUNT(*)"); $record_count->setFrom("Order_Payment_PayPal"); $record_count->addWhere("(`txn_id`='" . $request->postVar("txn_id") . "')"); $record_count = $record_count->execute()->value(); /* The row ID for the record that was found, if one exists */ $payment_record_id = new SQLQuery("`id`"); $payment_record_id->setFrom("Order_Payment_PayPal")->addWhere("(`txn_id`='" . $request->postVar("txn_id") . "')"); $payment_record_id = $payment_record_id->execute()->value(); } /** * VERIFIED STEP ONE * * Either create a payment record or update an existing one an send the applicable emails. */ switch ($request->postVar("payment_status")) { /* Payment has cleared, order can progress. */ case "Completed": //Send email to admin notification email address Order_Emails::create()->adminNewOrderNotification($request->postVar("custom")); //Send email to the customer confirming their order, if they haven't had one already. Order_Emails::create()->customerNewOrderConfirmation($request->postVar("custom")); if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Completed", "Processing"); } else { $this->newPaymentRecord($request, "Completed", "Processing"); } break; /* The payment is pending. See pending_reason for more information. */ /* The payment is pending. See pending_reason for more information. */ case "Pending": /** * We don't send emails for this status as 'Pending' orders are still awaiting a response from * a payment gateway and should not be dispatched. It is safe to send a confirmation email to * the customer, however. */ //Send email to the customer confirming their order is currently pending Order_Emails::create()->customerNewOrderConfirmation($request->postVar("custom"), "Pending"); if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Pending", "Pending / Awaiting Payment"); } else { $this->newPaymentRecord($request, "Pending", "Pending / Awaiting Payment"); } break; /* You refunded the payment. */ /* You refunded the payment. */ case "Refunded": /* Notify the customer of a change to their order status */ Order_Emails::create()->customerOrderStatusUpdate($request->postVar("custom"), "Refunded"); if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Refunded", "Refunded"); } else { $this->newPaymentRecord($request, "Refunded", "Refunded"); } break; /** * A payment was reversed due to a chargeback or other type of reversal. * The funds have been removed from your account balance and returned to the buyer. * The reason for the reversal is specified in the ReasonCode element. */ /** * A payment was reversed due to a chargeback or other type of reversal. * The funds have been removed from your account balance and returned to the buyer. * The reason for the reversal is specified in the ReasonCode element. */ case "Reversed": /* Notify the admin that an order has had an order has been reversed */ /* Notify the customer of a change to their order status */ Order_Emails::create()->customerOrderStatusUpdate($request->postVar("custom"), "Cancelled"); if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Refunded", "Cancelled"); } else { $this->newPaymentRecord($request, "Refunded", "Cancelled"); } break; /* The reveral was cancelled */ /* The reveral was cancelled */ case "Canceled_Reversal": /* Notify an admin that an order reversal has been cancelled */ /** * We don't send customers an email update for this status as it might * cause confustion. */ /** * For canceled reversals, lets set the order to Pending as an admin will need to manually review it. * we don't want it to fall in the standard Processing queue as goods could be shipped twice. */ if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Pending", "Pending / Awaiting Payment"); } else { $this->newPaymentRecord($request, "Pending", "Pending / Awaiting Payment"); } break; /* This authorization has been voided. */ /* This authorization has been voided. */ case "Voided": /* Notify the customer of a change to their order status */ Order_Emails::create()->customerOrderStatusUpdate($request->postVar("custom"), "Cancelled"); if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Refunded", "Cancelled"); } else { $this->newPaymentRecord($request, "Refunded", "Cancelled"); } break; /** * The payment has failed. */ /** * The payment has failed. */ case "Failed": /* Notify the customer of a change to their order status */ Order_Emails::create()->customerOrderStatusUpdate($request->postVar("custom"), "Cancelled"); if ($record_count > 0) { $this->updatePaymentRecord($request, $payment_record_id, "Refunded", "Cancelled"); } else { $this->newPaymentRecord($request, "Refunded", "Cancelled"); } break; /* Other IPN statuses are ignored. */ /* Other IPN statuses are ignored. */ default: exit; break; } } elseif (strcmp($res, "INVALID") == 0) { $status = "INVALID"; // log for manual investigation // Add business logic here which deals with invalid IPN messages /* If Debug is enabled, log response */ if ($debug == 1) { error_log(date('[Y-m-d H:i e] ') . "Invalid IPN: {$req}" . PHP_EOL, 3, "../ipn.log"); } } } }
public function modifiedUpload(SS_HTTPRequest $request) { if ($this->isDisabled() || $this->isReadonly() || !$this->canUpload()) { return $this->httpError(403); } // Protect against CSRF on destructive action $token = $this->getForm()->getSecurityToken(); //if(!$token->checkRequest($request)) return $this->httpError(400); $name = $this->getName(); $contentFieldName = $this->contentModuleFieldName; $postVars = $request->postVars(); $tmpfile = $request->postVar('ContentModule'); $record = $this->getRecord(); // Check if the file has been uploaded into the temporary storage. if (!$tmpfile) { $return = array('error' => _t('UploadField.FIELDNOTSET', 'File information not found')); } else { $return = array('name' => $tmpfile['name'][$this->getRecord()->ID][$name], 'size' => $tmpfile['size'][$this->getRecord()->ID][$name], 'type' => $tmpfile['type'][$this->getRecord()->ID][$name], 'error' => $tmpfile['error'][$this->getRecord()->ID][$name], 'tmp_name' => $tmpfile['tmp_name'][$this->getRecord()->ID][$name]); } // Check for constraints on the record to which the file will be attached. if (!$return['error'] && $this->relationAutoSetting && $record && $record->exists()) { $tooManyFiles = false; // Some relationships allow many files to be attached. if ($this->getConfig('allowedMaxFileNumber') && ($record->has_many($name) || $record->many_many($name))) { if (!$record->isInDB()) { $record->write(); } $tooManyFiles = $record->{$name}()->count() >= $this->getConfig('allowedMaxFileNumber'); // has_one only allows one file at any given time. } elseif ($record->has_one($name)) { // If we're allowed to replace an existing file, clear out the old one if ($record->{$name} && $this->getConfig('replaceExistingFile')) { $record->{$name} = null; } $tooManyFiles = $record->{$name}() && $record->{$name}()->exists(); } // Report the constraint violation. if ($tooManyFiles) { if (!$this->getConfig('allowedMaxFileNumber')) { $this->setConfig('allowedMaxFileNumber', 1); } $return['error'] = _t('UploadField.MAXNUMBEROFFILES', 'Max number of {count} file(s) exceeded.', array('count' => $this->getConfig('allowedMaxFileNumber'))); } } // Process the uploaded file if (!$return['error']) { $fileObject = null; if ($this->relationAutoSetting) { // Search for relations that can hold the uploaded files. if ($relationClass = $this->getRelationAutosetClass()) { // Create new object explicitly. Otherwise rely on Upload::load to choose the class. $fileObject = Object::create($relationClass); } } // Get the uploaded file into a new file object. try { $this->upload->loadIntoFile($return, $fileObject, $this->folderName); } catch (Exception $e) { // we shouldn't get an error here, but just in case $return['error'] = $e->getMessage(); } if (!$return['error']) { if ($this->upload->isError()) { $return['error'] = implode(' ' . PHP_EOL, $this->upload->getErrors()); } else { $file = $this->upload->getFile(); // Attach the file to the related record. if ($this->relationAutoSetting) { $this->attachFile($file); } // Collect all output data. $file = $this->customiseFile($file); $return = array_merge($return, array('id' => $file->ID, 'name' => $file->getTitle() . '.' . $file->getExtension(), 'url' => $file->getURL(), 'thumbnail_url' => $file->UploadFieldThumbnailURL, 'edit_url' => $file->UploadFieldEditLink, 'size' => $file->getAbsoluteSize(), 'buttons' => $file->UploadFieldFileButtons)); } } } $response = new SS_HTTPResponse(Convert::raw2json(array($return))); $response->addHeader('Content-Type', 'text/plain'); return $response; }
/** * Passes the values from the SS_HTTPRequest object to the defined form; * missing values will be set to false * * during the transmission the values will become SQL secure * * @param SS_HTTPRequest $request the submitted data * * @return array * * @author Sebastian Diel <*****@*****.**>, * Sascha Koehler <*****@*****.**> * @since 11.10.2016 */ public function getFormData($request) { $formData = array(); $postVars = $request->postVars(); if ($this->securityTokenEnabled) { $formData['SecurityID'] = Convert::raw2sql($postVars['SecurityID']); } // read defined form fields // Definierte Formularfelder auslesen foreach ($this->fieldGroups as $groupName => $groupFields) { foreach ($groupFields as $fieldName => $fieldDefinition) { if (array_key_exists($fieldName, $postVars)) { $formData[$fieldName] = Convert::raw2sql($postVars[$fieldName]); } else { $formData[$fieldName] = false; } } } // read dynamically added form fields // Dynamisch hinzugefuegte Formularfelder auslesen if (isset($this->customParameters)) { foreach ($this->customParameters as $customParameterKey => $customParameterValue) { if (isset($request[$customParameterKey])) { $formData[$customParameterKey] = Convert::raw2sql($request[$customParameterKey]); } else { $formData[$customParameterKey] = false; } } } return $formData; }
/** * @param SS_HTTPRequest $request * @return SS_HTTPResponse */ public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { self::$is_at_root = true; $this->setDataModel($model); $this->pushCurrent(); $this->init(); if (!DB::isActive() || !ClassInfo::hasTable('SiteTree')) { $this->response = new SS_HTTPResponse(); $this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); return $this->response; } $request = new SS_HTTPRequest($request->httpMethod(), self::get_homepage_link() . '/', $request->getVars(), $request->postVars()); $request->match('$URLSegment//$Action', true); $controller = new ModelAsController(); $result = $controller->handleRequest($request, $model); $this->popCurrent(); return $result; }
public function update(SS_HTTPRequest $request) { if ($request->isPOST()) { $member = Customer::currentUser() ? Customer::currentUser() : singleton('Customer'); $order = Cart::get_current_order(); //Update the Order $order->update($request->postVars()); $order->updateModifications($request->postVars())->write(); $form = OrderForm::create($this->controller, 'OrderForm')->disableSecurityToken(); // $form->validate(); return $form->renderWith('OrderFormCart'); } }