/** * @param \SS_HTTPRequest $request * @return null|\SS_HTTPResponse */ public function getResponse(\SS_HTTPRequest $request) { if ($redirect = $this->getRedirectForRequest($request)) { $response = new \SS_HTTPResponse(); $response->redirect($redirect->getTo(), $redirect->getStatusCode()); return $response; } return null; }
/** * Redirct to the given URL. * It is generally recommended to call Director::redirect() rather than calling this function directly. */ function redirect($url, $code = 302) { if ($this->response->getHeader('Location')) { user_error("Already directed to " . $this->response->getHeader('Location') . "; now trying to direct to {$url}", E_USER_WARNING); return; } // Attach site-root to relative links, if they have a slash in them if ($url == "" || $url[0] == '?' || substr($url, 0, 4) != "http" && $url[0] != "/" && strpos($url, '/') !== false) { $url = Director::baseURL() . $url; } $this->response->redirect($url, $code); }
/** * @param SS_HTTPRequest $request * @throws SS_HTTPResponse_Exception */ public function onBeforeHTTPError404($request) { $url = strtolower($this->getUrl($request)); $oldPage = OldURLRedirect::get_from_url($url); // If there's a match, direct! if ($oldPage) { $response = new SS_HTTPResponse(); $dest = $oldPage->getRedirectionLink(); $response->redirect(Director::absoluteURL($dest), $oldPage->getRedirectCode()); throw new SS_HTTPResponse_Exception($response); } }
/** * Process all incoming requests passed to this controller, checking * that the file exists and passing the file through if possible. */ public function handleRequest(SS_HTTPRequest $request, DataModel $model) { $response = new SS_HTTPResponse(); $filename = $request->getURL(); if (strpos($filename, 'cdnassets') === 0) { $filename = 'assets/' . substr($filename, strlen('cdnassets/')); } $file = null; if (strpos($filename, '_resampled') !== false) { $file = ContentServiceAsset::get()->filter('Filename', $filename)->first(); } else { if (strpos($filename, '/_versions/') !== false) { $file = FileVersion::get()->filter('Filename', "/" . $filename)->first(); } else { $file = File::get()->filter('filename', $filename)->first(); } } if ($file && $file->canView()) { if (!$file->CDNFile && !$file->FilePointer) { return $this->httpError(404); } // Permission passed redirect to file $redirectLink = ''; if ($file->getViewType() != CDNFile::ANYONE_PERM) { if ($file->hasMethod('getSecureURL')) { $redirectLink = $file->getSecureURL(180); } if (!strlen($redirectLink)) { // can we stream it? return $this->sendFile($file); } } else { $redirectLink = $file->getURL(); } if ($redirectLink && trim($redirectLink, '/') != $request->getURL()) { $response->redirect($redirectLink); } else { return $this->httpError(404); } } else { if (class_exists('SecureFileController')) { $handoff = SecureFileController::create(); return $handoff->handleRequest($request, $model); } elseif ($file instanceof File) { // Permission failure Security::permissionFailure($this, 'You are not authorised to access this resource. Please log in.'); } else { // File doesn't exist $response = new SS_HTTPResponse('File Not Found', 404); } } return $response; }
/** * On every URL that generates a 404, we'll capture it here and see if we can * find an old URL that it should be redirecting to. * * @param SS_HTTPResponse $request The request object * @throws SS_HTTPResponse_Exception */ public function onBeforeHTTPError404($request) { // We need to get the URL ourselves because $request->allParams() only has a max of 4 params $params = preg_split('|/+|', $request->getURL()); $getvars = $request->getVars(); unset($getvars['url']); $page = self::find_old_page($params); if ($page) { $res = new SS_HTTPResponse(); $res->redirect(Controller::join_links($page, $getvars ? '?' . http_build_query($getvars) : null), 301); throw new SS_HTTPResponse_Exception($res); } }
/** * On every URL that generates a 404, we'll capture it here and see if we can * find an old URL that it should be redirecting to. * * @param SS_HTTPResponse $request The request object * @throws SS_HTTPResponse_Exception */ public function onBeforeHTTPError404($request) { // Build up the request parameters $params = array_filter(array_values($request->allParams()), function ($v) { return $v !== NULL; }); $getvars = $request->getVars(); unset($getvars['url']); $page = self::find_old_page($params); if ($page) { $res = new SS_HTTPResponse(); $res->redirect(Controller::join_links($page, $getvars ? '?' . http_build_query($getvars) : null), 301); throw new SS_HTTPResponse_Exception($res); } }
/** * On every URL that generates a 404, we'll capture it here and see if we can * find an old URL that it should be redirecting to. * * @param SS_HTTPRequest $request The request object * @throws SS_HTTPResponse_Exception */ public function onBeforeHTTPError404($request) { // We need to get the URL ourselves because $request->allParams() only has a max of 4 params $params = preg_split('|/+|', $request->getURL()); $cleanURL = trim(Director::makeRelative($request->getURL(false), '/')); $getvars = $request->getVars(); unset($getvars['url']); $page = self::find_old_page($params); $cleanPage = trim(Director::makeRelative($page), '/'); if (!$cleanPage) { $cleanPage = Director::makeRelative(RootURLController::get_homepage_link()); } if ($page && $cleanPage != $cleanURL) { $res = new SS_HTTPResponse(); $res->redirect(Controller::join_links($page, $getvars ? '?' . http_build_query($getvars) : null), 301); throw new SS_HTTPResponse_Exception($res); } }
/** * @return SS_HTTPResponse */ public function onBeforeInit() { $config = SiteConfig::current_site_config(); // If Maintenance Mode is Off, skip processing if (!$config->MaintenanceMode) { return; } // Check if the visitor is Admin OR if they have an allowed IP. if (Permission::check('VIEW_SITE_MAINTENANCE_MODE') || Permission::check('ADMIN') || $this->hasAllowedIP()) { return; } // Are we already on the UtilityPage? If so, skip processing. if ($this->owner instanceof UtilityPage_Controller) { return; } // Fetch our utility page instance now. /** * @var Page $utilityPage */ $utilityPage = UtilityPage::get()->first(); if (!$utilityPage) { return; } // We need a utility page before we can do anything. // Are we configured to prevent redirection to the UtilityPage URL? if ($utilityPage->config()->DisableRedirect) { // Process the request internally to ensure that the URL is maintained // (instead of redirecting to the maintenance page's URL) and skip any further processing. $controller = ModelAsController::controller_for($utilityPage); $response = $controller->handleRequest(new SS_HTTPRequest('GET', ''), DataModel::inst()); HTTP::add_cache_headers($response); $response->output(); die; } // Default: Skip any further processing and immediately respond with a redirect to the UtilityPage. $response = new SS_HTTPResponse(); $response->redirect($utilityPage->AbsoluteLink(), 302); HTTP::add_cache_headers($response); $response->output(); die; }
/** * Test a URL request, returning a response object. * * This method is the counterpart of Director::direct() that is used in functional testing. It will execute the * URL given, and return the result as an SS_HTTPResponse object. * * @param string $url The URL to visit * @param array $postVars The $_POST & $_FILES variables * @param Session $session The {@link Session} object representing the current session. By passing the same * object to multiple calls of Director::test(), you can simulate a persisted session. * @param string $httpMethod The HTTP method, such as GET or POST. It will default to POST if postVars is set, * GET otherwise. Overwritten by $postVars['_method'] if present. * @param string $body The HTTP body * @param array $headers HTTP headers with key-value pairs * @param array $cookies to populate $_COOKIE * @param HTTP_Request $request The {@see HTTP_Request} object generated as a part of this request * @return SS_HTTPResponse * * @uses getControllerForURL() The rule-lookup logic is handled by this. * @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. */ public static function test($url, $postVars = null, $session = null, $httpMethod = null, $body = null, $headers = null, $cookies = null, &$request = null) { Config::nest(); // These are needed so that calling Director::test() doesnt muck with whoever is calling it. // Really, it's some inappropriate coupling and should be resolved by making less use of statics $oldStage = Versioned::current_stage(); $getVars = array(); if (!$httpMethod) { $httpMethod = $postVars || is_array($postVars) ? "POST" : "GET"; } if (!$session) { $session = new Session(null); } // Back up the current values of the superglobals $existingRequestVars = isset($_REQUEST) ? $_REQUEST : array(); $existingGetVars = isset($_GET) ? $_GET : array(); $existingPostVars = isset($_POST) ? $_POST : array(); $existingSessionVars = isset($_SESSION) ? $_SESSION : array(); $existingCookies = isset($_COOKIE) ? $_COOKIE : array(); $existingServer = isset($_SERVER) ? $_SERVER : array(); $existingRequirementsBackend = Requirements::backend(); Config::inst()->update('Cookie', 'report_errors', false); Requirements::set_backend(new Requirements_Backend()); // Handle absolute URLs if (@parse_url($url, PHP_URL_HOST) != '') { $bits = parse_url($url); $_SERVER['HTTP_HOST'] = $bits['host']; $url = Director::makeRelative($url); } $urlWithQuerystring = $url; if (strpos($url, '?') !== false) { list($url, $getVarsEncoded) = explode('?', $url, 2); parse_str($getVarsEncoded, $getVars); } // Replace the superglobals with appropriate test values $_REQUEST = ArrayLib::array_merge_recursive((array) $getVars, (array) $postVars); $_GET = (array) $getVars; $_POST = (array) $postVars; $_SESSION = $session ? $session->inst_getAll() : array(); $_COOKIE = (array) $cookies; $_SERVER['REQUEST_URI'] = Director::baseURL() . $urlWithQuerystring; $request = new SS_HTTPRequest($httpMethod, $url, $getVars, $postVars, $body); if ($headers) { foreach ($headers as $k => $v) { $request->addHeader($k, $v); } } // Pre-request filtering // @see issue #2517 $model = DataModel::inst(); $output = Injector::inst()->get('RequestProcessor')->preRequest($request, $session, $model); if ($output === false) { // @TODO Need to NOT proceed with the request in an elegant manner throw new SS_HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400); } // TODO: Pass in the DataModel $result = Director::handleRequest($request, $session, $model); // Ensure that the result is an SS_HTTPResponse object if (is_string($result)) { if (substr($result, 0, 9) == 'redirect:') { $response = new SS_HTTPResponse(); $response->redirect(substr($result, 9)); $result = $response; } else { $result = new SS_HTTPResponse($result); } } $output = Injector::inst()->get('RequestProcessor')->postRequest($request, $result, $model); if ($output === false) { throw new SS_HTTPResponse_Exception("Invalid response"); } // Restore the superglobals $_REQUEST = $existingRequestVars; $_GET = $existingGetVars; $_POST = $existingPostVars; $_SESSION = $existingSessionVars; $_COOKIE = $existingCookies; $_SERVER = $existingServer; Requirements::set_backend($existingRequirementsBackend); // These are needed so that calling Director::test() doesnt muck with whoever is calling it. // Really, it's some inappropriate coupling and should be resolved by making less use of statics Versioned::reading_stage($oldStage); Config::unnest(); return $result; }
/** * Process the given URL, creating the appropriate controller and executing it. * * Request processing is handled as follows: * - Director::direct() creates a new SS_HTTPResponse object and passes this to Director::handleRequest(). * - Director::handleRequest($request) checks each of the Director rules and identifies a controller to handle this * request. * - Controller::handleRequest($request) is then called. This will find a rule to handle the URL, and call the rule * handling method. * - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method returns a * RequestHandler object. * * In addition to request processing, Director will manage the session, and perform the output of the actual response * to the browser. * * @param $url String, the URL the user is visiting, without the querystring. * @uses handleRequest() rule-lookup logic is handled by this. * @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. */ static function direct($url) { // Validate $_FILES array before merging it with $_POST foreach ($_FILES as $k => $v) { if (is_array($v['tmp_name'])) { $v = ArrayLib::array_values_recursive($v['tmp_name']); foreach ($v as $tmpFile) { if ($tmpFile && !is_uploaded_file($tmpFile)) { user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR); } } } else { if ($v['tmp_name'] && !is_uploaded_file($v['tmp_name'])) { user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR); } } } $req = new SS_HTTPRequest(isset($_SERVER['X-HTTP-Method-Override']) ? $_SERVER['X-HTTP-Method-Override'] : $_SERVER['REQUEST_METHOD'], $url, $_GET, array_merge((array) $_POST, (array) $_FILES), @file_get_contents('php://input')); // @todo find better way to extract HTTP headers if (isset($_SERVER['HTTP_ACCEPT'])) { $req->addHeader("Accept", $_SERVER['HTTP_ACCEPT']); } if (isset($_SERVER['CONTENT_TYPE'])) { $req->addHeader("Content-Type", $_SERVER['CONTENT_TYPE']); } if (isset($_SERVER['HTTP_REFERER'])) { $req->addHeader("Referer", $_SERVER['HTTP_REFERER']); } // Load the session into the controller $session = new Session(isset($_SESSION) ? $_SESSION : null); $result = Director::handleRequest($req, $session); $session->inst_save(); // Return code for a redirection request if (is_string($result) && substr($result, 0, 9) == 'redirect:') { $response = new SS_HTTPResponse(); $response->redirect(substr($result, 9)); $response->output(); // Handle a controller } else { if ($result) { if ($result instanceof SS_HTTPResponse) { $response = $result; } else { $response = new SS_HTTPResponse(); $response->setBody($result); } // ?debug_memory=1 will output the number of bytes of memory used for this request if (isset($_REQUEST['debug_memory']) && $_REQUEST['debug_memory']) { Debug::message(sprintf("Peak memory usage in bytes: %s", number_format(memory_get_peak_usage(), 0))); } else { $response->output(); } //$controllerObj->getSession()->inst_save(); } } }
<?php global $project; $project = 'mysite'; // use the _ss_environment.php file for configuration require_once 'conf/ConfigureFromEnv.php'; // set default language i18n::set_locale('en_US'); define('PROJECT_THIRDPARTY_DIR', project() . '/thirdparty'); define('PROJECT_THIRDPARTY_PATH', BASE_PATH . '/' . PROJECT_THIRDPARTY_DIR); if (SS_IS_TEST_ENV) { BasicAuth::protect_entire_site(true); } if (Director::isLive()) { if (strpos(Director::absoluteBaseURL(), 'silverstripe-europe.org') !== false || strpos(Director::absoluteBaseURL(), 'www') !== false) { $response = new SS_HTTPResponse(); $response->redirect('https://stripecon.eu', 301); HTTP::add_cache_headers($response); $response->output(); die; } // we are in live mode, send errors per email, set cache and force WWW HTTP::set_cache_age(3600); // HTTP Header for CloudFlare Caching SS_Cache::set_cache_lifetime('any', 10800); // Serverside cache to 3 hours. SS_Log::add_writer(new SS_LogEmailWriter('*****@*****.**'), SS_Log::ERR); } Config::inst()->update('HtmlEditorField', 'use_gzip', false);
/** * Process the given URL, creating the appropriate controller and executing it. * * Request processing is handled as follows: * - Director::direct() creates a new SS_HTTPResponse object and passes this to Director::handleRequest(). * - Director::handleRequest($request) checks each of the Director rules and identifies a controller to handle this * request. * - Controller::handleRequest($request) is then called. This will find a rule to handle the URL, and call the rule * handling method. * - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method returns a * RequestHandler object. * * In addition to request processing, Director will manage the session, and perform the output of the actual response * to the browser. * * @param $url String, the URL the user is visiting, without the querystring. * @uses handleRequest() rule-lookup logic is handled by this. * @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. */ static function direct($url, DataModel $model) { // Validate $_FILES array before merging it with $_POST foreach ($_FILES as $k => $v) { if (is_array($v['tmp_name'])) { $v = ArrayLib::array_values_recursive($v['tmp_name']); foreach ($v as $tmpFile) { if ($tmpFile && !is_uploaded_file($tmpFile)) { user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR); } } } else { if ($v['tmp_name'] && !is_uploaded_file($v['tmp_name'])) { user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR); } } } $req = new SS_HTTPRequest(isset($_SERVER['X-HTTP-Method-Override']) ? $_SERVER['X-HTTP-Method-Override'] : $_SERVER['REQUEST_METHOD'], $url, $_GET, array_merge((array) $_POST, (array) $_FILES), @file_get_contents('php://input')); // Load the request headers. If we're not running on Apache, then we // need to manually extract the headers from the $_SERVER array. if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); } else { $headers = self::extract_request_headers($_SERVER); } foreach ($headers as $header => $value) { $req->addHeader($header, $value); } // Load the session into the controller $session = new Session(isset($_SESSION) ? $_SESSION : null); $result = Director::handleRequest($req, $session, $model); $session->inst_save(); // Return code for a redirection request if (is_string($result) && substr($result, 0, 9) == 'redirect:') { $response = new SS_HTTPResponse(); $response->redirect(substr($result, 9)); $response->output(); // Handle a controller } else { if ($result) { if ($result instanceof SS_HTTPResponse) { $response = $result; } else { $response = new SS_HTTPResponse(); $response->setBody($result); } // ?debug_memory=1 will output the number of bytes of memory used for this request if (isset($_REQUEST['debug_memory']) && $_REQUEST['debug_memory']) { Debug::message(sprintf("Peak memory usage in bytes: %s", number_format(memory_get_peak_usage(), 0))); } else { $response->output(); } //$controllerObj->getSession()->inst_save(); } } }
public function RedirectToPage($url) { $response = new SS_HTTPResponse(); $response->redirect($url, 301); throw new SS_HTTPResponse_Exception($response); }
/** * Determine whether a media page child once existed for the current request, and redirect appropriately. * * @return ss http response */ private function resolveURL() { // Retrieve the current request URL segments. $request = $this->getRequest(); $URL = $request->getURL(); $holder = substr($URL, 0, strpos($URL, '/')); $page = substr($URL, strrpos($URL, '/') + 1); // Determine whether a media page child once existed. $resolution = self::find_old_page(array($holder, $page)); $comparison = trim($resolution, '/'); // Make sure the current request URL doesn't match the resolution. if ($resolution && $page !== substr($comparison, strrpos($comparison, '/') + 1)) { // Retrieve the current request parameters. $parameters = $request->getVars(); unset($parameters['url']); // Appropriately redirect towards the updated media page URL. $response = new SS_HTTPResponse(); return $response->redirect(self::join_links($resolution, !empty($parameters) ? '?' . http_build_query($parameters) : null), 301); } else { // The media page child doesn't resolve. return null; } }
/** * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to * fall over to a child controller in order to provide functionality for nested URLs. * * @return SS_HTTPResponse */ public function handleRequest(SS_HTTPRequest $request) { $child = null; $action = $request->param('Action'); // If nested URLs are enabled, and there is no action handler for the current request then attempt to pass // control to a child controller. This allows for the creation of chains of controllers which correspond to a // nested URL. if ($action && SiteTree::nested_urls() && !$this->hasAction($action)) { // See ModelAdController->getNestedController() for similar logic Translatable::disable_locale_filter(); // look for a page with this URLSegment $child = DataObject::get_one('SiteTree', sprintf("\"ParentID\" = %s AND \"URLSegment\" = '%s'", $this->ID, Convert::raw2sql($action))); Translatable::enable_locale_filter(); // if we can't find a page with this URLSegment try to find one that used to have // that URLSegment but changed. See ModelAsController->getNestedController() for similiar logic. if (!$child) { $child = ModelAsController::find_old_page($action, $this->ID); if ($child) { $response = new SS_HTTPResponse(); $params = $request->getVars(); if (isset($params['url'])) { unset($params['url']); } $response->redirect(Controller::join_links($child->Link(Controller::join_links($request->param('ID'), $request->param('OtherID'))), $params ? '?' . http_build_query($params) : null), 301); return $response; } } } // we found a page with this URLSegment. if ($child) { $request->shiftAllParams(); $request->shift(); $response = ModelAsController::controller_for($child)->handleRequest($request); } else { // If a specific locale is requested, and it doesn't match the page found by URLSegment, // look for a translation and redirect (see #5001). Only happens on the last child in // a potentially nested URL chain. if ($request->getVar('locale') && $this->dataRecord && $this->dataRecord->Locale != $request->getVar('locale')) { $translation = $this->dataRecord->getTranslation($request->getVar('locale')); if ($translation) { $response = new SS_HTTPResponse(); $response->redirect($translation->Link(), 301); throw new SS_HTTPResponse_Exception($response); } } Director::set_current_page($this->data()); $response = parent::handleRequest($request); Director::set_current_page(null); } return $response; }
/** * Overloaded to avoid "action doesn't exist" errors - all URL parts in * this controller are virtual and handled through handleRequest(), not * controller methods. * * @param $request * @param $action * * @return SS_HTTPResponse */ public function handleAction($request, $action) { // if we submitted a form, let that pass if (!$request->isGET()) { return parent::handleAction($request, $action); } $url = $request->getURL(); // // If the current request has an extension attached to it, strip that // off and redirect the user to the page without an extension. // if (DocumentationHelper::get_extension($url)) { $this->response = new SS_HTTPResponse(); $this->response->redirect(DocumentationHelper::trim_extension_off($url) . '/', 301); $request->shift(); $request->shift(); return $this->response; } // // Strip off the base url // $base = ltrim(Config::inst()->get('DocumentationViewer', 'link_base'), '/'); if ($base && strpos($url, $base) !== false) { $url = substr(ltrim($url, '/'), strlen($base)); } else { } // // Handle any permanent redirections that the developer has defined. // if ($link = DocumentationPermalinks::map($url)) { // the first param is a shortcode for a page so redirect the user to // the short code. $this->response = new SS_HTTPResponse(); $this->response->redirect($link, 301); $request->shift(); $request->shift(); return $this->response; } // // Validate the language provided. Language is a required URL parameter. // as we use it for generic interfaces and language selection. If // language is not set, redirects to 'en' // $languages = i18n::get_common_languages(); if (!($lang = $request->param('Lang'))) { $lang = $request->param('Action'); $action = $request->param('ID'); } else { $action = $request->param('Action'); } if (!$lang) { return $this->redirect($this->Link('en')); } else { if (!isset($languages[$lang])) { return $this->httpError(404); } } $request->shift(10); $allowed = $this->config()->allowed_actions; if (in_array($action, $allowed)) { // // if it's one of the allowed actions such as search or all then the // URL must be prefixed with one of the allowed languages. // return parent::handleAction($request, $action); } else { // // look up the manifest to see find the nearest match against the // list of the URL. If the URL exists then set that as the current // page to match against. // strip off any extensions. // if($cleaned !== $url) { // $redirect = new SS_HTTPResponse(); // return $redirect->redirect($cleaned, 302); // } if ($record = $this->getManifest()->getPage($url)) { $this->record = $record; $this->init(); $type = get_class($this->record); $body = $this->renderWith(array("DocumentationViewer_{$type}", "DocumentationViewer")); return new SS_HTTPResponse($body, 200); } else { if ($redirect = $this->getManifest()->getRedirect($url)) { $response = new SS_HTTPResponse(); $to = Controller::join_links(Director::baseURL(), $base, $redirect); return $response->redirect($to, 301); } else { if (!$url || $url == $lang) { $body = $this->renderWith(array("DocumentationViewer_DocumentationFolder", "DocumentationViewer")); return new SS_HTTPResponse($body, 200); } } } } return $this->httpError(404); }
/** * Skip any further processing and immediately respond with a redirect to the passed URL. * * @param string $destURL */ protected static function force_redirect($destURL) { $response = new SS_HTTPResponse(); $response->redirect($destURL, 301); HTTP::add_cache_headers($response); // TODO: Use an exception - ATM we can be called from _config.php, before Director#handleRequest's try block $response->output(); die; }
/** * Handles performing a callback to the Salesforce auth server with the * provided authorisation code. * * @param string $code * @param string $state * @return SS_HTTPResponse * @throws SalesforceAuthException On authentication failure. */ public function callback($code, $state) { $callback = new RestfulService(self::CALLBACK_URL, -1); $callback = $callback->request('', 'POST', array('code' => $code, 'grant_type' => 'authorization_code', 'client_id' => $this->getClientID(), 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->getRedirectURL())); $callback = json_decode($callback->getBody()); if (!$callback || !$callback->id) { throw new SalesforceAuthException('An invalid authorisation response was returned'); } $id = new RestfulService($callback->id, -1); $id->setQueryString(array('oauth_token' => $callback->access_token)); $id = json_decode($id->request()->getBody()); if (!$id || !$id->email) { throw new SalesforceAuthException('An invalid identity response was returned'); } /** @var Member $member */ $member = Member::get()->filter('Email', $id->email)->first(); if (!$member) { throw new SalesforceAuthException(sprintf('No member was found for the Salesforce email "%s"', $id->email)); } $state = json_decode($state); $redirect = isset($state->redirect) ? $state->redirect : null; $member->logIn(!empty($state->remember)); $member->extend('onSalesforceIdentify', $id); $response = new SS_HTTPResponse(); if ($redirect && Director::is_site_url($redirect)) { return $response->redirect($redirect); } if ($redirect = Config::inst()->get('Security', 'default_login_dest')) { return $response->redirect($redirect); } return $response->redirect(Director::absoluteBaseURL()); }
/** * Process the given URL, creating the appropriate controller and executing it. * * Request processing is handled as follows: * - Director::direct() creates a new SS_HTTPResponse object and passes this to Director::handleRequest(). * - Director::handleRequest($request) checks each of the Director rules and identifies a controller to handle this * request. * - Controller::handleRequest($request) is then called. This will find a rule to handle the URL, and call the rule * handling method. * - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method returns a * RequestHandler object. * * In addition to request processing, Director will manage the session, and perform the output of the actual response * to the browser. * * @param $url String, the URL the user is visiting, without the querystring. * @uses handleRequest() rule-lookup logic is handled by this. * @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. */ static function direct($url, DataModel $model) { // Validate $_FILES array before merging it with $_POST foreach ($_FILES as $k => $v) { if (is_array($v['tmp_name'])) { $v = ArrayLib::array_values_recursive($v['tmp_name']); foreach ($v as $tmpFile) { if ($tmpFile && !is_uploaded_file($tmpFile)) { user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR); } } } else { if ($v['tmp_name'] && !is_uploaded_file($v['tmp_name'])) { user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR); } } } $req = new SS_HTTPRequest(isset($_SERVER['X-HTTP-Method-Override']) ? $_SERVER['X-HTTP-Method-Override'] : $_SERVER['REQUEST_METHOD'], $url, $_GET, ArrayLib::array_merge_recursive((array) $_POST, (array) $_FILES), @file_get_contents('php://input')); $headers = self::extract_request_headers($_SERVER); foreach ($headers as $header => $value) { $req->addHeader($header, $value); } // Only resume a session if its not started already, and a session identifier exists if (!isset($_SESSION) && (isset($_COOKIE[session_name()]) || isset($_REQUEST[session_name()]))) { Session::start(); } // Initiate an empty session - doesn't initialize an actual PHP session until saved (see belwo) $session = new Session(isset($_SESSION) ? $_SESSION : null); $output = Injector::inst()->get('RequestProcessor')->preRequest($req, $session, $model); if ($output === false) { // @TODO Need to NOT proceed with the request in an elegant manner throw new SS_HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400); } $result = Director::handleRequest($req, $session, $model); // Save session data (and start/resume it if required) $session->inst_save(); // Return code for a redirection request if (is_string($result) && substr($result, 0, 9) == 'redirect:') { $response = new SS_HTTPResponse(); $response->redirect(substr($result, 9)); $res = Injector::inst()->get('RequestProcessor')->postRequest($req, $response, $model); if ($res !== false) { $response->output(); } // Handle a controller } else { if ($result) { if ($result instanceof SS_HTTPResponse) { $response = $result; } else { $response = new SS_HTTPResponse(); $response->setBody($result); } $res = Injector::inst()->get('RequestProcessor')->postRequest($req, $response, $model); if ($res !== false) { $response->output(); } else { // @TODO Proper response here. throw new SS_HTTPResponse_Exception("Invalid response"); } //$controllerObj->getSession()->inst_save(); } } }
/** * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to * fall over to a child controller in order to provide functionality for nested URLs. * * @param SS_HTTPRequest $request * @param DataModel $model * @return SS_HTTPResponse * @throws SS_HTTPResponse_Exception */ public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { $child = null; $action = $request->param('Action'); $this->setDataModel($model); // If nested URLs are enabled, and there is no action handler for the current request then attempt to pass // control to a child controller. This allows for the creation of chains of controllers which correspond to a // nested URL. if ($action && SiteTree::config()->nested_urls && !$this->hasAction($action)) { // See ModelAdController->getNestedController() for similar logic if (class_exists('Translatable')) { Translatable::disable_locale_filter(); } // look for a page with this URLSegment $child = $this->model->SiteTree->filter(array('ParentID' => $this->ID, 'URLSegment' => rawurlencode($action)))->first(); if (class_exists('Translatable')) { Translatable::enable_locale_filter(); } } // we found a page with this URLSegment. if ($child) { $request->shiftAllParams(); $request->shift(); $response = ModelAsController::controller_for($child)->handleRequest($request, $model); } else { // If a specific locale is requested, and it doesn't match the page found by URLSegment, // look for a translation and redirect (see #5001). Only happens on the last child in // a potentially nested URL chain. if (class_exists('Translatable')) { if ($request->getVar('locale') && $this->dataRecord && $this->dataRecord->Locale != $request->getVar('locale')) { $translation = $this->dataRecord->getTranslation($request->getVar('locale')); if ($translation) { $response = new SS_HTTPResponse(); $response->redirect($translation->Link(), 301); throw new SS_HTTPResponse_Exception($response); } } } Director::set_current_page($this->data()); try { $response = parent::handleRequest($request, $model); Director::set_current_page(null); } catch (SS_HTTPResponse_Exception $e) { $this->popCurrent(); Director::set_current_page(null); throw $e; } } return $response; }
/** * @throws SS_HTTPResponse_Exception */ public function onBeforeHTTPError404($request) { $base = strtolower($request->getURL()); $getVars = $this->arrayToLowercase($request->getVars()); unset($getVars['url']); // Find all the RedirectedURL objects where the base URL matches. // Assumes the base url has no trailing slash. $SQL_base = Convert::raw2sql(rtrim($base, '/')); $potentials = DataObject::get("RedirectedURL", "\"FromBase\" = '/" . $SQL_base . "'", "\"FromQuerystring\" ASC"); $listPotentials = new ArrayList(); foreach ($potentials as $potential) { $listPotentials->push($potential); } // Find any matching FromBase elements terminating in a wildcard /* $baseparts = explode('/', $base); for ($pos = count($baseparts) - 1; $pos >= 0; $pos--) { $basestr = implode('/', array_slice($baseparts, 0, $pos)); $basepart = Convert::raw2sql($basestr . '/*'); $basepots = DataObject::get("RedirectedURL", "\"FromBase\" = '/" . $basepart . "'", "\"FromQuerystring\" ASC"); foreach ($basepots as $basepot) { // If the To URL ends in a wildcard /*, append the remaining request URL elements if (substr($basepot->To, -2) === '/*') { $basepot->To = substr($basepot->To, 0, -2) . substr($base, strlen($basestr)); } $listPotentials->push($basepot); } } $matched = null; // Then check the get vars, ignoring any additional get vars that // this URL may have if ($listPotentials) { foreach ($listPotentials as $potential) { $allVarsMatch = true; if ($potential->FromQuerystring) { $reqVars = array(); parse_str($potential->FromQuerystring, $reqVars); foreach ($reqVars as $k => $v) { if (!$v) { continue; } if (!isset($getVars[$k]) || $v != $getVars[$k]) { $allVarsMatch = false; break; } } } if ($allVarsMatch) { $matched = $potential; break; } } } // If there's a match, direct! if ($matched) { $response = new SS_HTTPResponse(); $dest = $matched->To; $response->redirect(Director::absoluteURL($dest), 301); throw new SS_HTTPResponse_Exception($response); } // Otherwise check for default MOSS-fixing. if (preg_match('/pages\\/default.aspx$/i', $base)) { $newBase = preg_replace('/pages\\/default.aspx$/i', '', $base); $response = new SS_HTTPResponse(); $response->redirect(Director::absoluteURL($newBase), 301); throw new SS_HTTPResponse_Exception($response); } }
/** * Attempt to redirect towards the highest priority link mapping that may have been defined. * * @URLparameter direct <{BYPASS_LINK_MAPPINGS}> boolean */ public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model) { // Bypass the request filter when requesting specific director rules such as "/admin" or "/dev". $requestURL = $request->getURL(); $configuration = Config::inst(); foreach ($configuration->get('Director', 'rules') as $segment => $controller) { // Retrieve the specific director rules. if (($position = strpos($segment, '$')) !== false) { $segment = rtrim(substr($segment, 0, $position), '/'); } // Determine if the current request matches a specific director rule. if ($segment && strpos($requestURL, $segment) === 0) { // Continue processing the response. return true; } } // Bypass the request filter when using the direct GET parameter. if ($request->getVar('direct')) { // Continue processing the response. return true; } // Determine the default automated URL handling response status. $status = $response->getStatusCode(); $success = $status >= 200 && $status < 300; $error = $status === 404; // Either hook into a page not found, or when enforced, replace the default automated URL handling. $enforce = $configuration->get('MisdirectionRequestFilter', 'enforce_misdirection'); $replace = $configuration->get('MisdirectionRequestFilter', 'replace_default'); if (($error || $enforce || $replace) && ($map = $this->service->getMappingByRequest($request))) { // Update the response code where appropriate. $responseCode = $map->ResponseCode; if ($responseCode == 0) { $responseCode = 303; } else { if ($responseCode == 301 && $map->ForwardPOSTRequest) { $responseCode = 308; } else { if ($responseCode == 303 && $map->ForwardPOSTRequest) { $responseCode = 307; } } } // Update the response using the link mapping redirection. $response->redirect($map->getLink(), $responseCode); } else { if ($error && ($fallback = $this->service->determineFallback($requestURL))) { // Update the response code where appropriate. $responseCode = $fallback['code']; if ($responseCode === 0) { $responseCode = 303; } // Update the response using the fallback, enforcing no further redirection. $response->redirect(HTTP::setGetVar('direct', true, Controller::join_links(Director::absoluteBaseURL(), $fallback['link'])), $responseCode); } else { if (!$error && !$success && $replace) { $response->setStatusCode(404); // Retrieve the appropriate page not found response. ClassInfo::exists('SiteTree') && ($page = ErrorPage::response_for(404)) ? $response->setBody($page->getBody()) : $response->setBody('No URL was matched!'); } } } // Continue processing the response. return true; }