/** * Write the jsConnect string for single sign on. * * @param array $User An array containing information about the currently signed on user. If no user is signed in then this should be an empty array. * @param array $Request An array of the $_GET request. * @param string $ClientID The string client ID that you set up in the jsConnect settings page. * @param string $Secret The string secred that you set up in the jsConnect settings page. * @param string|bool $Secure Whether or not to check for security. This is one of these values. * - true: Check for security and sign the response with an md5 hash. * - false: Don't check for security, but sign the response with an md5 hash. * - string: Check for security and sign the response with the given hash algorithm. See hash_algos() for what your server can support. * - null: Don't check for security and don't sign the response. * @since 1.1b Added the ability to provide a hash algorithm to $Secure. */ function writeJsConnect($User, $Request, $ClientID, $Secret, $Secure = true) { $User = array_change_key_case($User); // Error checking. if ($Secure) { // Check the client. if (!isset($Request['client_id'])) { $Error = ['error' => 'invalid_request', 'message' => 'The client_id parameter is missing.']; } elseif ($Request['client_id'] != $ClientID) { $Error = ['error' => 'invalid_client', 'message' => "Unknown client {$Request['client_id']}."]; } elseif (!isset($Request['timestamp']) && !isset($Request['signature'])) { if (is_array($User) && count($User) > 0) { // This isn't really an error, but we are just going to return public information when no signature is sent. $Error = ['name' => $User['name'], 'photourl' => @$User['photourl']]; } else { $Error = ['name' => '', 'photourl' => '']; } } elseif (!isset($Request['timestamp']) || !is_numeric($Request['timestamp'])) { $Error = ['error' => 'invalid_request', 'message' => 'The timestamp parameter is missing or invalid.']; } elseif (!isset($Request['signature'])) { $Error = ['error' => 'invalid_request', 'message' => 'Missing signature parameter.']; } elseif (($Diff = abs($Request['timestamp'] - jsTimestamp())) > JS_TIMEOUT) { $Error = ['error' => 'invalid_request', 'message' => 'The timestamp is invalid.']; } else { // Make sure the timestamp hasn't timed out. $Signature = jsHash($Request['timestamp'] . $Secret, $Secure); if ($Signature != $Request['signature']) { $Error = ['error' => 'access_denied', 'message' => 'Signature invalid.']; } } } if (isset($Error)) { $Result = $Error; } elseif (is_array($User) && count($User) > 0) { if ($Secure === null) { $Result = $User; } else { $Result = signJsConnect($User, $ClientID, $Secret, $Secure, true); } } else { $Result = ['name' => '', 'photourl' => '']; } $Json = json_encode($Result); if (isset($Request['callback'])) { safeHeader('Content-Type: application/javascript'); echo "{$Request['callback']}({$Json})"; } else { safeHeader('Content-Type: application/json'); echo $Json; } }
/** * Authenticate the user attempting to sign in. * * Events: BeforeAuth * * @since 2.0.0 * @access public * * @param string $AuthenticationSchemeAlias Type of authentication we're attempting. */ public function auth($AuthenticationSchemeAlias = 'default') { Gdn::session()->ensureTransientKey(); $this->EventArguments['AuthenticationSchemeAlias'] = $AuthenticationSchemeAlias; $this->fireEvent('BeforeAuth'); // Allow hijacking auth type $AuthenticationSchemeAlias = $this->EventArguments['AuthenticationSchemeAlias']; // Attempt to set Authenticator with requested method or fallback to default try { $Authenticator = Gdn::authenticator()->authenticateWith($AuthenticationSchemeAlias); } catch (Exception $e) { $Authenticator = Gdn::authenticator()->authenticateWith('default'); } // Set up controller $this->View = 'auth/' . $Authenticator->getAuthenticationSchemeAlias(); $this->Form->setModel($this->UserModel); $this->Form->addHidden('ClientHour', date('Y-m-d H:00')); // Use the server's current hour as a default. $Target = $this->target(); $this->Form->addHidden('Target', $Target); // Import authenticator data source switch ($Authenticator->dataSourceType()) { case Gdn_Authenticator::DATA_FORM: $Authenticator->fetchData($this->Form); break; case Gdn_Authenticator::DATA_REQUEST: case Gdn_Authenticator::DATA_COOKIE: $Authenticator->fetchData(Gdn::request()); break; } // By default, just render the view $Reaction = Gdn_Authenticator::REACT_RENDER; // Where are we in the process? Still need to gather (render view) or are we validating? $AuthenticationStep = $Authenticator->currentStep(); switch ($AuthenticationStep) { // User is already logged in case Gdn_Authenticator::MODE_REPEAT: $Reaction = $Authenticator->repeatResponse(); break; // Not enough information to perform authentication, render input form // Not enough information to perform authentication, render input form case Gdn_Authenticator::MODE_GATHER: $this->addJsFile('entry.js'); $Reaction = $Authenticator->loginResponse(); if ($this->Form->isPostBack()) { $this->Form->addError('ErrorCredentials'); Logger::event('signin_failure', Logger::WARNING, '{username} failed to sign in. Some or all credentials were missing.'); } break; // All information is present, authenticate // All information is present, authenticate case Gdn_Authenticator::MODE_VALIDATE: // Attempt to authenticate. try { if (!$this->Request->isAuthenticatedPostBack() && !c('Garden.Embed.Allow')) { $this->Form->addError('Please try again.'); $Reaction = $Authenticator->failedResponse(); } else { $AuthenticationResponse = $Authenticator->authenticate(); $UserInfo = array(); $UserEventData = array_merge(array('UserID' => Gdn::session()->UserID, 'Payload' => val('HandshakeResponse', $Authenticator, false)), $UserInfo); Gdn::authenticator()->trigger($AuthenticationResponse, $UserEventData); switch ($AuthenticationResponse) { case Gdn_Authenticator::AUTH_PERMISSION: $this->Form->addError('ErrorPermission'); Logger::event('signin_failure', Logger::WARNING, '{username} failed to sign in. Permission denied.'); $Reaction = $Authenticator->failedResponse(); break; case Gdn_Authenticator::AUTH_DENIED: $this->Form->addError('ErrorCredentials'); Logger::event('signin_failure', Logger::WARNING, '{username} failed to sign in. Authentication denied.'); $Reaction = $Authenticator->failedResponse(); break; case Gdn_Authenticator::AUTH_INSUFFICIENT: // Unable to comply with auth request, more information is needed from user. Logger::event('signin_failure', Logger::WARNING, '{username} failed to sign in. More information needed from user.'); $this->Form->addError('ErrorInsufficient'); $Reaction = $Authenticator->failedResponse(); break; case Gdn_Authenticator::AUTH_PARTIAL: // Partial auth completed. $Reaction = $Authenticator->partialResponse(); break; case Gdn_Authenticator::AUTH_SUCCESS: default: // Full auth completed. if ($AuthenticationResponse == Gdn_Authenticator::AUTH_SUCCESS) { $UserID = Gdn::session()->UserID; } else { $UserID = $AuthenticationResponse; } safeHeader("X-Vanilla-Authenticated: yes"); safeHeader("X-Vanilla-TransientKey: " . Gdn::session()->transientKey()); $Reaction = $Authenticator->successResponse(); } } } catch (Exception $Ex) { $this->Form->addError($Ex); } break; case Gdn_Authenticator::MODE_NOAUTH: $Reaction = Gdn_Authenticator::REACT_REDIRECT; break; } switch ($Reaction) { case Gdn_Authenticator::REACT_RENDER: // Do nothing (render the view) break; case Gdn_Authenticator::REACT_EXIT: exit; break; case Gdn_Authenticator::REACT_REMOTE: // Let the authenticator handle generating output, using a blank slate $this->_DeliveryType = DELIVERY_TYPE_VIEW; exit; break; case Gdn_Authenticator::REACT_REDIRECT: default: if (is_string($Reaction)) { $Route = $Reaction; } else { $Route = $this->redirectTo(); } if ($this->_RealDeliveryType != DELIVERY_TYPE_ALL && $this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->RedirectUrl = url($Route); } else { if ($Route !== false) { redirect($Route); } else { redirect(Gdn::router()->getDestination('DefaultController')); } } break; } $this->setData('SendWhere', "/entry/auth/{$AuthenticationSchemeAlias}"); $this->render(); }
/** * Display 'no permission' page. * * @since 2.0.0 * @access public */ public function unauthorized() { Gdn_Theme::section('Error'); if ($this->deliveryMethod() == DELIVERY_METHOD_XHTML) { safeHeader("HTTP/1.0 401", true, 401); $this->render(); } else { $this->RenderException(permissionException()); } }
* here, but some things have already been loaded and are immutable. */ if (file_exists(PATH_CONF . '/bootstrap.early.php')) { require_once PATH_CONF . '/bootstrap.early.php'; } Gdn::config()->caching(true); debug(c('Debug', false)); setHandlers(); /** * Installer Redirect * * If Garden is not yet installed, force the request to /dashboard/setup and * begin installation. */ if (Gdn::config('Garden.Installed', false) === false && strpos(Gdn_Url::request(), 'setup') === false) { safeHeader('Location: ' . Gdn::request()->url('dashboard/setup', true)); exit; } /** * Extension Managers * * Now load the Addon, Application, Theme and Plugin managers into the Factory, and * process the application-specific configuration defaults. */ // ApplicationManager Gdn::factoryInstall(Gdn::AliasApplicationManager, 'Gdn_ApplicationManager', '', Gdn::FactorySingleton, [Gdn::addonManager()]); // ThemeManager Gdn::factoryInstall(Gdn::AliasThemeManager, 'Gdn_ThemeManager', '', Gdn::FactorySingleton, [Gdn::addonManager()]); // PluginManager Gdn::factoryInstall(Gdn::AliasPluginManager, 'Gdn_PluginManager', '', Gdn::FactorySingleton, [Gdn::addonManager()]); // Start the addons, plugins, and applications.
public function ServeCss($ThemeType, $Filename) { // Split the filename into filename and etag. if (preg_match('`([\\w_-]+?)-(\\w+).css$`', $Filename, $Matches)) { $Basename = $Matches[1]; $ETag = $Matches[2]; } else { throw NotFoundException(); } $Basename = ucfirst($Basename); $this->EventArguments['Basename'] = $Basename; $this->EventArguments['ETag'] = $ETag; $this->FireEvent('BeforeServeCss'); if (function_exists('header_remove')) { header_remove('Set-Cookie'); } safeHeader("Content-Type: text/css"); if (!in_array($Basename, array('Style', 'Admin'))) { safeHeader("HTTP/1.0 404", TRUE, 404); echo "/* Could not find {$Basename}/{$ETag} */"; die; } $RequestETags = GetValue('HTTP_IF_NONE_MATCH', $_SERVER); if (get_magic_quotes_gpc()) { $RequestETags = stripslashes($RequestETags); } $RequestETags = explode(',', $RequestETags); foreach ($RequestETags as $RequestETag) { if ($RequestETag == $ETag) { safeHeader("HTTP/1.0 304", TRUE, 304); die; } } safeHeader("Cache-Control:public, max-age=14400"); $CurrentETag = self::ETag(); safeHeader("ETag: {$CurrentETag}"); $CachePath = PATH_CACHE . '/css/' . CLIENT_NAME . '-' . $ThemeType . '-' . strtolower($Basename) . "-{$CurrentETag}.css"; if (!Debug() && file_exists($CachePath)) { readfile($CachePath); die; } // Include minify... set_include_path(PATH_LIBRARY . "/vendors/Minify/lib" . PATH_SEPARATOR . get_include_path()); require_once PATH_LIBRARY . "/vendors/Minify/lib/Minify/CSS.php"; ob_start(); echo "/* CSS generated for etag: {$CurrentETag}.\n *\n"; $Paths = $this->GetCssFiles($ThemeType, $Basename, $ETag, $NotFound); // First, do a pass through the files to generate some information. foreach ($Paths as $Info) { list($Path, $UrlPath) = $Info; echo " * {$UrlPath}\n"; } // Echo the paths that weren't found to help debugging. foreach ($NotFound as $Info) { list($Filename, $Folder) = $Info; echo " * {$Folder}/{$Filename} NOT FOUND.\n"; } echo " */\n\n"; // Now that we have all of the paths we want to serve them. foreach ($Paths as $Info) { list($Path, $UrlPath, $Options) = $Info; echo "/* File: {$UrlPath} */\n"; $Css = GetValue('Css', $Options); if (!$Css) { $Css = file_get_contents($Path); } $Css = Minify_CSS::minify($Css, array('preserveComments' => TRUE, 'prependRelativePath' => $this->UrlPrefix . Asset(dirname($UrlPath) . '/'), 'currentDir' => dirname($Path), 'minify' => TRUE)); echo $Css; echo "\n\n"; } // Create a cached copy of the file. $Css = ob_get_flush(); if (!file_exists(dirname($CachePath))) { mkdir(dirname($CachePath), 0775, TRUE); } file_put_contents($CachePath, $Css); }
/** * Serve all CSS files. * * @param $themeType * @param $filename * @throws Exception */ public function serveCss($themeType, $filename) { // Split the filename into filename and etag. if (preg_match('`([\\w-]+?)-(\\w+).css$`', $filename, $matches)) { $basename = $matches[1]; $eTag = $matches[2]; } else { throw notFoundException(); } $basename = strtolower($basename); $this->EventArguments['Basename'] = $basename; $this->EventArguments['ETag'] = $eTag; $this->fireEvent('BeforeServeCss'); if (function_exists('header_remove')) { header_remove('Set-Cookie'); } // Get list of anchor files $anchors = $this->getAnchors(); safeHeader("Content-Type: text/css"); $anchorFileName = "{$basename}.css"; if (!in_array($anchorFileName, $anchors)) { safeHeader("HTTP/1.0 404", true, 404); echo "/* Could not find {$basename}/{$eTag} */"; die; } $requestETags = val('HTTP_IF_NONE_MATCH', $_SERVER); $requestETags = explode(',', $requestETags); foreach ($requestETags as $requestETag) { if ($requestETag == $eTag) { safeHeader("HTTP/1.0 304", true, 304); die; } } safeHeader("Cache-Control:public, max-age=14400"); $currentETag = self::eTag(); safeHeader("ETag: {$currentETag}"); $cachePath = PATH_CACHE . '/css/' . CLIENT_NAME . '-' . $themeType . '-' . "{$basename}-{$currentETag}.css"; if (!Debug() && file_exists($cachePath)) { readfile($cachePath); die; } // Include minify... set_include_path(PATH_LIBRARY . "/vendors/Minify/lib" . PATH_SEPARATOR . get_include_path()); require_once PATH_LIBRARY . "/vendors/Minify/lib/Minify/CSS.php"; ob_start(); echo "/* CSS generated for etag: {$currentETag}.\n *\n"; $notFound = []; $paths = $this->getCssFiles($themeType, $basename, $eTag, $notFound); // First, do a pass through the files to generate some information. foreach ($paths as $info) { list($path, $urlPath) = $info; echo " * {$urlPath}\n"; } // Echo the paths that weren't found to help debugging. foreach ($notFound as $info) { list($filename, $folder) = $info; echo " * {$folder}/{$filename} NOT FOUND.\n"; } echo " */\n\n"; // Now that we have all of the paths we want to serve them. foreach ($paths as $info) { list($path, $urlPath, $options) = $info; echo "/* File: {$urlPath} */\n"; $css = val('Css', $options); if (!$css) { $css = file_get_contents($path); } $css = Minify_CSS::minify($css, ['preserveComments' => true, 'prependRelativePath' => $this->UrlPrefix . asset(dirname($urlPath) . '/'), 'currentDir' => dirname($path), 'minify' => true]); echo $css; echo "\n\n"; } // Create a cached copy of the file. $css = ob_get_flush(); if (!file_exists(dirname($cachePath))) { mkdir(dirname($cachePath), 0775, true); } file_put_contents($cachePath, $css); }
/** * Serves a file to the browser. * * @param string $File Full path to the file being served. * @param string $Name Name to give the file being served. Including extension overrides $File extension. Uses $File filename if empty. * @param string $MimeType The mime type of the file. * @param string $ServeMode Whether to download the file as an attachment, or inline */ public static function serveFile($File, $Name = '', $MimeType = '', $ServeMode = 'attachment') { $FileIsLocal = substr($File, 0, 4) == 'http' ? false : true; $FileAvailable = $FileIsLocal ? is_readable($File) : true; if ($FileAvailable) { // Close the database connection Gdn::database()->closeConnection(); // Determine if Path extension should be appended to Name $NameExtension = strtolower(pathinfo($Name, PATHINFO_EXTENSION)); $FileExtension = strtolower(pathinfo($File, PATHINFO_EXTENSION)); if ($NameExtension == '') { if ($Name == '') { $Name = pathinfo($File, PATHINFO_FILENAME) . '.' . $FileExtension; } elseif (!stringEndsWith($Name, '.' . $FileExtension)) { $Name .= '.' . $FileExtension; } } else { $Extension = $NameExtension; } $Name = rawurldecode($Name); // Figure out the MIME type $MimeTypes = array("pdf" => "application/pdf", "txt" => "text/plain", "html" => "text/html", "htm" => "text/html", "exe" => "application/octet-stream", "zip" => "application/zip", "doc" => "application/msword", "xls" => "application/vnd.ms-excel", "ppt" => "application/vnd.ms-powerpoint", "gif" => "image/gif", "png" => "image/png", "jpeg" => "image/jpg", "jpg" => "image/jpg", "php" => "text/plain", "ico" => "image/vnd.microsoft.icon"); if ($MimeType == '') { if (array_key_exists($FileExtension, $MimeTypes)) { $MimeType = $MimeTypes[$FileExtension]; } else { $MimeType = 'application/force-download'; } } @ob_end_clean(); // required for IE, otherwise Content-Disposition may be ignored if (ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } if ($ServeMode == 'inline') { safeHeader('Content-Disposition: inline; filename="' . $Name . '"'); } else { safeHeader('Content-Disposition: attachment; filename="' . $Name . '"'); } safeHeader('Content-Type: ' . $MimeType); safeHeader("Content-Transfer-Encoding: binary"); safeHeader('Accept-Ranges: bytes'); safeHeader("Cache-control: private"); safeHeader('Pragma: private'); safeHeader("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); readfile($File); exit; } else { die('not readable'); } }
/** * Set P3P header because IE won't allow cookies thru the iFrame without it. * * This must be done in the Dispatcher because of PrivateCommunity. * That precludes using Controller->SetHeader. * This is done so comment & forum embedding can work in old IE. */ public function Gdn_Dispatcher_AppStartup_Handler($Sender) { safeHeader('P3P: CP="CAO PSA OUR"', TRUE); if ($SSO = Gdn::Request()->Get('sso')) { SaveToConfig('Garden.Registration.SendConnectEmail', FALSE, FALSE); $IsApi = preg_match('`\\.json$`i', Gdn::Request()->Path()); $UserID = FALSE; try { $CurrentUserID = Gdn::Session()->UserID; $UserID = Gdn::UserModel()->SSO($SSO); } catch (Exception $Ex) { Trace($Ex, TRACE_ERROR); } if ($UserID) { Gdn::Session()->Start($UserID, !$IsApi, !$IsApi); if ($UserID != $CurrentUserID) { Gdn::UserModel()->FireEvent('AfterSignIn'); } } else { // There was some sort of error. Let's print that out. Trace(Gdn::UserModel()->Validation->ResultsText(), TRACE_WARNING); } } }
// ThemeManager Gdn::FactoryInstall(Gdn::AliasThemeManager, 'Gdn_ThemeManager'); // PluginManager Gdn::FactoryInstall(Gdn::AliasPluginManager, 'Gdn_PluginManager'); // Load the configurations for enabled Applications foreach (Gdn::ApplicationManager()->EnabledApplicationFolders() as $ApplicationName => $ApplicationFolder) { Gdn::Config()->Load(PATH_APPLICATIONS . "/{$ApplicationFolder}/settings/configuration.php"); } /** * Installer Redirect * * If Garden is not yet installed, force the request to /dashboard/setup and * begin installation. */ if (Gdn::Config('Garden.Installed', FALSE) === FALSE && strpos(Gdn_Url::Request(), 'setup') === FALSE) { safeHeader('Location: ' . Gdn::Request()->Url('dashboard/setup', TRUE)); exit; } // Re-apply loaded user settings Gdn::Config()->OverlayDynamic(); /** * Bootstrap Late * * All configurations are loaded, as well as the Application, Plugin and Theme * managers. */ if (file_exists(PATH_CONF . '/bootstrap.late.php')) { require_once PATH_CONF . '/bootstrap.late.php'; } if (C('Debug')) { Debug(TRUE);
function Redirect($Destination = FALSE, $StatusCode = NULL) { if (!$Destination) { $Destination = Url(''); } // if (Debug() && $Trace = Trace()) { // Trace("Redirecting to $Destination"); // return; // } // Close any db connections before exit $Database = Gdn::Database(); $Database->CloseConnection(); // Clear out any previously sent content @ob_end_clean(); // assign status code $SendCode = is_null($StatusCode) ? 302 : $StatusCode; // re-assign the location header safeHeader("Location: " . Url($Destination), TRUE, $SendCode); // Exit exit; }
/** * Display 'no permission' page. * * @since 2.0.0 * @access public */ public function Permission() { Gdn_Theme::Section('Error'); if ($this->DeliveryMethod() == DELIVERY_METHOD_XHTML) { safeHeader("HTTP/1.0 401", TRUE, 401); $this->Render(); } else { $this->RenderException(PermissionException()); } }
/** * Parses the query string looking for supplied request parameters. Places * anything useful into this object's Controller properties. * * @param int $FolderDepth */ protected function analyzeRequest(&$Request) { // Here is the basic format of a request: // [/application]/controller[/method[.json|.xml]]/argn|argn=valn // Here are some examples of what this method could/would receive: // /application/controller/method/argn // /controller/method/argn // /application/controller/argn // /controller/argn // /controller // Clear the slate $this->_ApplicationFolder = ''; $this->ControllerName = ''; $this->ControllerMethod = 'index'; $this->_ControllerMethodArgs = array(); $this->Request = $Request->path(false); $PathAndQuery = $Request->PathAndQuery(); $MatchRoute = Gdn::router()->matchRoute($PathAndQuery); // We have a route. Take action. if ($MatchRoute !== false) { switch ($MatchRoute['Type']) { case 'Internal': $Request->pathAndQuery($MatchRoute['FinalDestination']); $this->Request = $Request->path(false); break; case 'Temporary': safeHeader("HTTP/1.1 302 Moved Temporarily"); safeHeader("Location: " . Url($MatchRoute['FinalDestination'])); exit; break; case 'Permanent': safeHeader("HTTP/1.1 301 Moved Permanently"); safeHeader("Location: " . Url($MatchRoute['FinalDestination'])); exit; break; case 'NotAuthorized': safeHeader("HTTP/1.1 401 Not Authorized"); $this->Request = $MatchRoute['FinalDestination']; break; case 'NotFound': safeHeader("HTTP/1.1 404 Not Found"); $this->Request = $MatchRoute['FinalDestination']; break; case 'Test': $Request->pathAndQuery($MatchRoute['FinalDestination']); $this->Request = $Request->path(false); decho($MatchRoute, 'Route'); decho(array('Path' => $Request->path(), 'Get' => $Request->get()), 'Request'); die; } } switch ($Request->outputFormat()) { case 'rss': $this->_SyndicationMethod = SYNDICATION_RSS; $this->_DeliveryMethod = DELIVERY_METHOD_RSS; break; case 'atom': $this->_SyndicationMethod = SYNDICATION_ATOM; $this->_DeliveryMethod = DELIVERY_METHOD_RSS; break; case 'default': default: $this->_SyndicationMethod = SYNDICATION_NONE; break; } if ($this->Request == '') { $DefaultController = Gdn::router()->getRoute('DefaultController'); $this->Request = $DefaultController['Destination']; } $Parts = explode('/', str_replace('\\', '/', $this->Request)); /** * The application folder is either the first argument or is not provided. The controller is therefore * either the second argument or the first, depending on the result of the previous statement. Check that. */ try { // if the 1st argument is a valid application, check if it has a controller matching the 2nd argument if (in_array($Parts[0], $this->enabledApplicationFolders())) { $this->findController(1, $Parts); } // if no match, see if the first argument is a controller $this->findController(0, $Parts); // 3] See if there is a plugin trying to create a root method. list($MethodName, $DeliveryMethod) = $this->_splitDeliveryMethod(GetValue(0, $Parts), true); if ($MethodName && Gdn::pluginManager()->hasNewMethod('RootController', $MethodName, true)) { $this->_DeliveryMethod = $DeliveryMethod; $Parts[0] = $MethodName; $Parts = array_merge(array('root'), $Parts); $this->findController(0, $Parts); } throw new GdnDispatcherControllerNotFoundException(); } catch (GdnDispatcherControllerFoundException $e) { switch ($this->_DeliveryMethod) { case DELIVERY_METHOD_JSON: case DELIVERY_METHOD_XML: $this->_DeliveryType = DELIVERY_TYPE_DATA; break; case DELIVERY_METHOD_TEXT: $this->_DeliveryType = DELIVERY_TYPE_VIEW; break; case DELIVERY_METHOD_XHTML: case DELIVERY_METHOD_RSS: break; default: $this->_DeliveryMethod = DELIVERY_METHOD_XHTML; break; } return true; } catch (GdnDispatcherControllerNotFoundException $e) { $this->EventArguments['Handled'] = false; $Handled =& $this->EventArguments['Handled']; $this->fireEvent('NotFound'); if (!$Handled) { safeHeader("HTTP/1.1 404 Not Found"); $Request->withRoute('Default404'); return $this->analyzeRequest($Request); } } }
/** * @param Gdn_Dispatcher $sender */ public function gdn_dispatcher_sendHeaders_handler($sender) { $csrfToken = Gdn::request()->post(Gdn_Session::CSRF_NAME, Gdn::request()->get(Gdn_Session::CSRF_NAME, Gdn::request()->getValueFrom(Gdn_Request::INPUT_SERVER, 'HTTP_X_CSRF_TOKEN'))); if ($csrfToken && Gdn::session()->isValid() && !Gdn::session()->validateTransientKey($csrfToken)) { safeHeader('X-CSRF-Token: ' . Gdn::session()->transientKey()); } }
/** * Rewrite the request based on rewrite rules (currently called routes in Vanilla). * * This method modifies the passed {@link $request} object. It can also cause a redirect if a rule matches that * specifies a redirect. * * @param Gdn_Request $request The request to rewrite. */ private function rewriteRequest($request) { $pathAndQuery = $request->PathAndQuery(); $matchRoute = Gdn::router()->matchRoute($pathAndQuery); // We have a route. Take action. if (!empty($matchRoute)) { $dest = $matchRoute['FinalDestination']; if (strpos($dest, '?') === false) { // The rewrite rule doesn't include a query string so keep the current one intact. $request->path($dest); } else { // The rewrite rule has a query string so rewrite that too. $request->pathAndQuery($dest); } switch ($matchRoute['Type']) { case 'Internal': // Do nothing. The request has been rewritten. break; case 'Temporary': safeHeader("HTTP/1.1 302 Moved Temporarily"); safeHeader("Location: " . url($matchRoute['FinalDestination'])); exit; break; case 'Permanent': safeHeader("HTTP/1.1 301 Moved Permanently"); safeHeader("Location: " . url($matchRoute['FinalDestination'])); exit; break; case 'NotAuthorized': safeHeader("HTTP/1.1 401 Not Authorized"); break; case 'NotFound': safeHeader("HTTP/1.1 404 Not Found"); break; case 'Drop': die; case 'Test': decho($matchRoute, 'Route'); decho(array('Path' => $request->path(), 'Get' => $request->get()), 'Request'); die; } } elseif (in_array($request->path(), ['', '/'])) { $this->isHomepage = true; $defaultController = Gdn::router()->getRoute('DefaultController'); $request->pathAndQuery($defaultController['Destination']); } return $request; }
/** * Set P3P header because IE won't allow cookies thru the iFrame without it. * * This must be done in the Dispatcher because of PrivateCommunity. * That precludes using Controller->SetHeader. * This is done so comment & forum embedding can work in old IE. * * @param Gdn_Dispatcher $Sender */ public function gdn_dispatcher_appStartup_handler($Sender) { safeHeader('P3P: CP="CAO PSA OUR"', true); if ($SSO = Gdn::request()->get('sso')) { saveToConfig('Garden.Registration.SendConnectEmail', false, false); $IsApi = preg_match('`\\.json$`i', Gdn::request()->path()); $UserID = false; try { $CurrentUserID = Gdn::session()->UserID; $UserID = Gdn::userModel()->sso($SSO); } catch (Exception $Ex) { trace($Ex, TRACE_ERROR); } if ($UserID) { Gdn::session()->start($UserID, !$IsApi, !$IsApi); if ($IsApi) { Gdn::session()->validateTransientKey(true); } if ($UserID != $CurrentUserID) { Gdn::userModel()->fireEvent('AfterSignIn'); } } else { // There was some sort of error. Let's print that out. foreach (Gdn::userModel()->Validation->resultsArray() as $msg) { trace($msg, TRACE_ERROR); } Gdn::userModel()->Validation->reset(); } } }
/** * Redirect to a specific url that can be outside of the site. * * @param string $url The url to redirect to. * @param int $code The http status code. */ function redirectUrl($url, $code = 302) { if (!$url) { $url = Url('', true); } // Close any db connections before exit $Database = Gdn::Database(); $Database->CloseConnection(); // Clear out any previously sent content @ob_end_clean(); if (!in_array($code, array(301, 302))) { $code = 302; } safeHeader("Location: " . $url, true, $code); exit; }
/** * Looks for a Last-Modified header from the browser and compares it to the * supplied date. If the Last-Modified date is after the supplied date, the * controller will send a "304 Not Modified" response code to the web * browser and stop all execution. Otherwise it sets the Last-Modified * header for this page and continues processing. * * @param string $LastModifiedDate A unix timestamp representing the date that the current page was last * modified. */ public function setLastModified($LastModifiedDate) { $GMD = gmdate('D, d M Y H:i:s', $LastModifiedDate) . ' GMT'; $this->setHeader('Etag', '"' . $GMD . '"'); $this->setHeader('Last-Modified', $GMD); $IncomingHeaders = getallheaders(); if (isset($IncomingHeaders['If-Modified-Since']) && isset($IncomingHeaders['If-None-Match'])) { $IfNoneMatch = $IncomingHeaders['If-None-Match']; $IfModifiedSince = $IncomingHeaders['If-Modified-Since']; if ($GMD == $IfNoneMatch && $IfModifiedSince == $GMD) { $Database = Gdn::database(); if (!is_null($Database)) { $Database->closeConnection(); } $this->setHeader('Content-Length', '0'); $this->sendHeaders(); safeHeader('HTTP/1.1 304 Not Modified'); exit("\n\n"); // Send two linefeeds so that the client knows the response is complete } } }
/** * A custom error handler that displays much more, very useful information when * errors are encountered in Garden. * * @param Exception $Exception The exception that was thrown. */ function Gdn_ExceptionHandler($Exception) { try { $ErrorNumber = $Exception->getCode(); $Message = $Exception->getMessage(); $File = $Exception->getFile(); $Line = $Exception->getLine(); if (method_exists($Exception, 'getContext')) { $Arguments = $Exception->getContext(); } else { $Arguments = ''; } $Backtrace = $Exception->getTrace(); // Clean the output buffer in case an error was encountered in-page. @ob_end_clean(); // prevent headers already sent error if (!headers_sent()) { if ($ErrorNumber >= 100 && $ErrorNumber < 600) { $Code = $ErrorNumber; } else { $Code = 500; } if (class_exists('Gdn_Controller', false)) { $msg = Gdn_Controller::getStatusMessage($Code); } else { $msg = 'Error'; } safeHeader("HTTP/1.0 {$Code} {$msg}", true, $ErrorNumber); safeHeader('Content-Type: text/html; charset=utf-8'); } $SenderMessage = $Message; $SenderObject = 'PHP'; $SenderMethod = 'Gdn_ErrorHandler'; $SenderCode = false; $SenderTrace = $Backtrace; $MessageInfo = explode('|', $Message); $MessageCount = count($MessageInfo); if ($MessageCount == 4) { list($SenderMessage, $SenderObject, $SenderMethod, $SenderCode) = $MessageInfo; } elseif ($MessageCount == 3) { list($SenderMessage, $SenderObject, $SenderMethod) = $MessageInfo; } elseif (function_exists('GetValueR')) { $IsError = GetValueR('0.function', $SenderTrace) == 'Gdn_ErrorHandler'; // not exception $N = $IsError ? '1' : '0'; $SenderMethod = GetValueR($N . '.function', $SenderTrace, $SenderMethod); $SenderObject = GetValueR($N . '.class', $SenderTrace, $SenderObject); } $SenderMessage = htmlspecialchars($SenderMessage); $Master = false; // The parsed master view $CssPath = false; // The web-path to the css file $ErrorLines = false; // The lines near the error's line # $DeliveryType = defined('DELIVERY_TYPE_ALL') ? DELIVERY_TYPE_ALL : 'ALL'; if (array_key_exists('DeliveryType', $_POST)) { $DeliveryType = $_POST['DeliveryType']; } elseif (array_key_exists('DeliveryType', $_GET)) { $DeliveryType = $_GET['DeliveryType']; } if (function_exists('debug') && debug()) { $Debug = true; } else { $Debug = false; } // Make sure all of the required custom functions and variables are defined. $PanicError = false; // Should we just dump a message and forget about the master view? if (!defined('DS')) { $PanicError = true; } if (!defined('PATH_ROOT')) { $PanicError = true; } if (!defined('APPLICATION')) { define('APPLICATION', 'Garden'); } if (!defined('APPLICATION_VERSION')) { define('APPLICATION_VERSION', 'Unknown'); } $WebRoot = ''; // Try and rollback a database transaction. if (class_exists('Gdn', false)) { $Database = Gdn::database(); if (is_object($Database)) { $Database->rollbackTransaction(); } } if ($PanicError === false) { // See if we can get the file that caused the error if (is_string($File) && is_numeric($ErrorNumber)) { $ErrorLines = @file($File); } // If this error was encountered during an ajax request, don't bother gettting the css or theme files if ($DeliveryType == DELIVERY_TYPE_ALL) { $CssPaths = array(); // Potential places where the css can be found in the filesystem. $MasterViewPaths = array(); $MasterViewName = 'error.master.php'; $MasterViewCss = 'error.css'; if ($Debug) { $MasterViewName = 'deverror.master.php'; } if (class_exists('Gdn', false)) { $CurrentTheme = ''; // The currently selected theme $CurrentTheme = C('Garden.Theme', ''); $MasterViewName = C('Garden.Errors.MasterView', $MasterViewName); $MasterViewCss = substr($MasterViewName, 0, strpos($MasterViewName, '.')); if ($MasterViewCss == '') { $MasterViewCss = 'error'; } $MasterViewCss .= '.css'; if ($CurrentTheme != '') { // Look for CSS in the theme folder: $CssPaths[] = PATH_THEMES . DS . $CurrentTheme . DS . 'design' . DS . $MasterViewCss; // Look for Master View in the theme folder: $MasterViewPaths[] = PATH_THEMES . DS . $CurrentTheme . DS . 'views' . DS . $MasterViewName; } } // Look for CSS in the dashboard design folder. $CssPaths[] = PATH_APPLICATIONS . DS . 'dashboard' . DS . 'design' . DS . $MasterViewCss; // Look for Master View in the dashboard view folder. $MasterViewPaths[] = PATH_APPLICATIONS . DS . 'dashboard' . DS . 'views' . DS . $MasterViewName; $CssPath = false; $Count = count($CssPaths); for ($i = 0; $i < $Count; ++$i) { if (file_exists($CssPaths[$i])) { $CssPath = $CssPaths[$i]; break; } } if ($CssPath !== false) { $CssPath = str_replace(array(PATH_ROOT, DS), array('', '/'), $CssPath); $CssPath = ($WebRoot == '' ? '' : '/' . $WebRoot) . $CssPath; } $MasterViewPath = false; $Count = count($MasterViewPaths); for ($i = 0; $i < $Count; ++$i) { if (file_exists($MasterViewPaths[$i])) { $MasterViewPath = $MasterViewPaths[$i]; break; } } if ($MasterViewPath !== false) { include $MasterViewPath; $Master = true; } } } if ($DeliveryType != DELIVERY_TYPE_ALL) { if (!$Debug) { echo '<b class="Bonk">Whoops! There was an error.</b>'; echo '<div class="BonkError Hidden">'; } // This is an ajax request, so dump an error that is more eye-friendly in the debugger echo '<h1>FATAL ERROR IN: ', $SenderObject, '.', $SenderMethod, "();</h1>\n<pre class=\"AjaxError\">\"" . $SenderMessage . "\"\n"; if ($SenderCode != '') { echo htmlspecialchars($SenderCode, ENT_COMPAT, C('Garden.Charset', 'UTF-8')) . "\n"; } if (is_array($ErrorLines) && $Line > -1) { echo "\nLOCATION: ", $File, "\n"; } $LineCount = count($ErrorLines); $Padding = strlen($Line + 5); for ($i = 0; $i < $LineCount; ++$i) { if ($i > $Line - 6 && $i < $Line + 4) { if ($i == $Line - 1) { echo '>>'; } echo '> ' . str_pad($i + 1, $Padding, " ", STR_PAD_LEFT), ': ', str_replace(array("\n", "\r"), array('', ''), htmlspecialchars($ErrorLines[$i])), "\n"; } } if (is_array($Backtrace)) { echo "\nBACKTRACE:\n"; $BacktraceCount = count($Backtrace); for ($i = 0; $i < $BacktraceCount; ++$i) { if (array_key_exists('file', $Backtrace[$i])) { $File = $Backtrace[$i]['file'] . ' ' . $Backtrace[$i]['line']; } echo '[' . $File . ']', ' ', array_key_exists('class', $Backtrace[$i]) ? $Backtrace[$i]['class'] : 'PHP', array_key_exists('type', $Backtrace[$i]) ? $Backtrace[$i]['type'] : '::', $Backtrace[$i]['function'], '();', "\n"; } } echo '</pre>'; if (!$Debug) { echo '</div>'; } } else { // If the master view wasn't found, assume a panic state and dump the error. if ($Master === false) { echo '<!DOCTYPE html> <html> <head> <title>Fatal Error</title> </head> <body> <h1>Fatal Error in ', $SenderObject, '.', $SenderMethod, '();</h1> <h2>', $SenderMessage, "</h2>\n"; if ($SenderCode != '') { echo '<code>', htmlentities($SenderCode, ENT_COMPAT, 'UTF-8'), "</code>\n"; } if (is_array($ErrorLines) && $Line > -1) { echo '<h3><strong>The error occurred on or near:</strong> ', $File, '</h3> <pre>'; $LineCount = count($ErrorLines); $Padding = strlen($Line + 4); for ($i = 0; $i < $LineCount; ++$i) { if ($i > $Line - 6 && $i < $Line + 4) { echo str_pad($i, $Padding, " ", STR_PAD_LEFT), ': ', htmlentities($ErrorLines[$i], ENT_COMPAT, 'UTF-8'); } } echo "</pre>\n"; } echo '<h2>Need Help?</h2> <p>If you are a user of this website, you can report this message to a website administrator.</p> <p>If you are an administrator of this website, you can get help at the <a href="http://vanillaforums.org/discussions/" target="_blank">Vanilla Community Forums</a>.</p> <h2>Additional information for support personnel:</h2> <ul> <li><strong>Application:</strong> ', APPLICATION, '</li> <li><strong>Application Version:</strong> ', APPLICATION_VERSION, '</li> <li><strong>PHP Version:</strong> ', PHP_VERSION, '</li> <li><strong>Operating System:</strong> ', PHP_OS, "</li>\n"; if (array_key_exists('SERVER_SOFTWARE', $_SERVER)) { echo '<li><strong>Server Software:</strong> ', $_SERVER['SERVER_SOFTWARE'], "</li>\n"; } if (array_key_exists('HTTP_REFERER', $_SERVER)) { echo '<li><strong>Referer:</strong> ', $_SERVER['HTTP_REFERER'], "</li>\n"; } if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { echo '<li><strong>User Agent:</strong> ', $_SERVER['HTTP_USER_AGENT'], "</li>\n"; } if (array_key_exists('REQUEST_URI', $_SERVER)) { echo '<li><strong>Request Uri:</strong> ', $_SERVER['REQUEST_URI'], "</li>\n"; } echo '</ul> </body> </html>'; } } // Attempt to log an error message no matter what. LogException($Exception); } catch (Exception $e) { print get_class($e) . " thrown within the exception handler.<br/>Message: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine(); exit; } }