2007-07-19 12:40:28 +02:00
< ? php
/**
* ErrorPage holds the content for the page of an error response .
2008-10-01 16:57:06 +02:00
* Renders the page on each publish action into a static HTML file
* within the assets directory , after the naming convention
* / assets / error -< statuscode >. html .
* This enables us to show errors even if PHP experiences a recoverable error .
* ErrorPages
2008-10-01 16:43:43 +02:00
*
2008-10-19 00:31:04 +02:00
* @ see Debug :: friendlyError ()
*
2008-02-25 03:10:37 +01:00
* @ package cms
2007-07-19 12:40:28 +02:00
*/
class ErrorPage extends Page {
2007-09-15 01:21:35 +02:00
2007-07-19 12:40:28 +02:00
static $db = array (
" ErrorCode " => " Int " ,
);
2007-09-15 01:21:35 +02:00
2007-07-19 12:40:28 +02:00
static $defaults = array (
" ShowInMenus " => 0 ,
2008-08-20 06:48:44 +02:00
" ShowInSearch " => 0
2007-07-19 12:40:28 +02:00
);
2010-10-19 02:48:04 +02:00
static $icon = array ( " sapphire/javascript/tree/images/page " , " file " );
2009-01-19 02:25:23 +01:00
protected static $static_filepath = ASSETS_PATH ;
2009-10-11 02:07:03 +02:00
/**
API CHANGE: Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
MINOR: Replaced usage of renamed classes with the new namespaced name.
From: Andrew Short <andrewjshort@gmail.com>
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90075 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-10-26 04:06:31 +01:00
* Get a { @ link SS_HTTPResponse } to response to a HTTP error code if an { @ link ErrorPage } for that code is present .
2009-10-11 02:07:03 +02:00
*
2009-10-11 02:07:25 +02:00
* @ param int $statusCode
API CHANGE: Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
MINOR: Replaced usage of renamed classes with the new namespaced name.
From: Andrew Short <andrewjshort@gmail.com>
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90075 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-10-26 04:06:31 +01:00
* @ return SS_HTTPResponse
2009-10-11 02:07:03 +02:00
*/
2009-10-11 02:07:25 +02:00
public static function response_for ( $statusCode ) {
// first attempt to dynamically generate the error page
if ( $errorPage = DataObject :: get_one ( 'ErrorPage' , " \" ErrorCode \" = $statusCode " )) {
API CHANGE: Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
MINOR: Replaced usage of renamed classes with the new namespaced name.
From: Andrew Short <andrewjshort@gmail.com>
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90075 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-10-26 04:06:31 +01:00
return ModelAsController :: controller_for ( $errorPage ) -> handleRequest ( new SS_HTTPRequest ( 'GET' , '' ));
2009-10-11 02:07:03 +02:00
}
2009-10-11 02:07:25 +02:00
// then fall back on a cached version
$cachedPath = self :: get_filepath_for_errorcode ( $statusCode , Translatable :: get_current_locale ());
if ( file_exists ( $cachedPath )) {
API CHANGE: Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
MINOR: Replaced usage of renamed classes with the new namespaced name.
From: Andrew Short <andrewjshort@gmail.com>
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90075 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-10-26 04:06:31 +01:00
$response = new SS_HTTPResponse ();
2009-10-11 02:07:03 +02:00
$response -> setStatusCode ( $statusCode );
2009-10-11 02:07:25 +02:00
$response -> setBody ( file_get_contents ( $cachedPath ));
2009-10-11 02:07:03 +02:00
return $response ;
}
}
2007-07-19 12:40:28 +02:00
/**
2008-10-19 00:31:04 +02:00
* Ensures that there is always a 404 page
* by checking if there ' s an instance of
2010-10-19 02:49:53 +02:00
* ErrorPage with a 404 and 500 error code . If there
2008-10-19 00:31:04 +02:00
* is not , one is created when the DB is built .
2007-07-19 12:40:28 +02:00
*/
function requireDefaultRecords () {
parent :: requireDefaultRecords ();
2007-08-15 08:38:41 +02:00
2010-12-05 09:36:05 +01:00
// Ensure that an assets path exists before we do any error page creation
if ( ! file_exists ( ASSETS_PATH )) {
mkdir ( ASSETS_PATH );
}
2010-10-19 02:49:53 +02:00
$pageNotFoundErrorPage = DataObject :: get_one ( 'ErrorPage' , " \" ErrorCode \" = '404' " );
2010-10-19 07:00:35 +02:00
$pageNotFoundErrorPageExists = ( $pageNotFoundErrorPage && $pageNotFoundErrorPage -> exists ()) ? true : false ;
$pageNotFoundErrorPagePath = self :: get_filepath_for_errorcode ( 404 );
if ( ! ( $pageNotFoundErrorPageExists && file_exists ( $pageNotFoundErrorPagePath ))) {
if ( ! $pageNotFoundErrorPageExists ) {
$pageNotFoundErrorPage = new ErrorPage ();
$pageNotFoundErrorPage -> ErrorCode = 404 ;
$pageNotFoundErrorPage -> Title = _t ( 'ErrorPage.DEFAULTERRORPAGETITLE' , 'Page not found' );
$pageNotFoundErrorPage -> Content = _t ( 'ErrorPage.DEFAULTERRORPAGECONTENT' , '<p>Sorry, it seems you were trying to access a page that doesn\'t exist.</p><p>Please check the spelling of the URL you were trying to access and try again.</p>' );
$pageNotFoundErrorPage -> Status = 'New page' ;
$pageNotFoundErrorPage -> write ();
$pageNotFoundErrorPage -> publish ( 'Stage' , 'Live' );
}
2010-10-19 02:49:53 +02:00
2010-10-19 07:00:35 +02:00
// Ensure a static error page is created from latest error page content
$response = Director :: test ( Director :: makeRelative ( $pageNotFoundErrorPage -> Link ()));
if ( $fh = fopen ( $pageNotFoundErrorPagePath , 'w' )) {
$written = fwrite ( $fh , $response -> getBody ());
fclose ( $fh );
}
if ( $written ) {
DB :: alteration_message ( '404 error page created' , 'created' );
} else {
DB :: alteration_message ( sprintf ( '404 error page could not be created at %s. Please check permissions' , $pageNotFoundErrorPagePath ), 'error' );
}
2007-07-19 12:40:28 +02:00
}
2007-09-15 01:21:35 +02:00
2010-10-19 02:49:53 +02:00
$serverErrorPage = DataObject :: get_one ( 'ErrorPage' , " \" ErrorCode \" = '500' " );
2010-10-19 07:00:35 +02:00
$serverErrorPageExists = ( $serverErrorPage && $serverErrorPage -> exists ()) ? true : false ;
$serverErrorPagePath = self :: get_filepath_for_errorcode ( 500 );
if ( ! ( $serverErrorPageExists && file_exists ( $serverErrorPagePath ))) {
if ( ! $serverErrorPageExists ) {
$serverErrorPage = new ErrorPage ();
$serverErrorPage -> ErrorCode = 500 ;
$serverErrorPage -> Title = _t ( 'ErrorPage.DEFAULTSERVERERRORPAGETITLE' , 'Server error' );
$serverErrorPage -> Content = _t ( 'ErrorPage.DEFAULTSERVERERRORPAGECONTENT' , '<p>Sorry, there was a problem with handling your request.</p>' );
$serverErrorPage -> Status = 'New page' ;
$serverErrorPage -> write ();
$serverErrorPage -> publish ( 'Stage' , 'Live' );
}
// Ensure a static error page is created from latest error page content
$response = Director :: test ( Director :: makeRelative ( $serverErrorPage -> Link ()));
if ( $fh = fopen ( $serverErrorPagePath , 'w' )) {
$written = fwrite ( $fh , $response -> getBody ());
fclose ( $fh );
}
2010-10-19 02:49:53 +02:00
2010-10-19 07:00:35 +02:00
if ( $written ) {
DB :: alteration_message ( '500 error page created' , 'created' );
} else {
DB :: alteration_message ( sprintf ( '500 error page could not be created at %s. Please check permissions' , $serverErrorPagePath ), 'error' );
}
2010-10-19 02:49:53 +02:00
}
}
2007-09-15 01:21:35 +02:00
2007-07-19 12:40:28 +02:00
function getCMSFields () {
$fields = parent :: getCMSFields ();
$fields -> addFieldToTab (
" Root.Content.Main " ,
new DropdownField (
" ErrorCode " ,
2008-11-02 21:04:10 +01:00
$this -> fieldLabel ( 'ErrorCode' ),
2007-07-19 12:40:28 +02:00
array (
2008-02-25 03:10:37 +01:00
400 => _t ( 'ErrorPage.400' , '400 - Bad Request' ),
401 => _t ( 'ErrorPage.401' , '401 - Unauthorized' ),
403 => _t ( 'ErrorPage.403' , '403 - Forbidden' ),
404 => _t ( 'ErrorPage.404' , '404 - Not Found' ),
405 => _t ( 'ErrorPage.405' , '405 - Method Not Allowed' ),
406 => _t ( 'ErrorPage.406' , '406 - Not Acceptable' ),
407 => _t ( 'ErrorPage.407' , '407 - Proxy Authentication Required' ),
408 => _t ( 'ErrorPage.408' , '408 - Request Timeout' ),
409 => _t ( 'ErrorPage.409' , '409 - Conflict' ),
410 => _t ( 'ErrorPage.410' , '410 - Gone' ),
411 => _t ( 'ErrorPage.411' , '411 - Length Required' ),
412 => _t ( 'ErrorPage.412' , '412 - Precondition Failed' ),
413 => _t ( 'ErrorPage.413' , '413 - Request Entity Too Large' ),
414 => _t ( 'ErrorPage.414' , '414 - Request-URI Too Long' ),
415 => _t ( 'ErrorPage.415' , '415 - Unsupported Media Type' ),
416 => _t ( 'ErrorPage.416' , '416 - Request Range Not Satisfiable' ),
417 => _t ( 'ErrorPage.417' , '417 - Expectation Failed' ),
500 => _t ( 'ErrorPage.500' , '500 - Internal Server Error' ),
501 => _t ( 'ErrorPage.501' , '501 - Not Implemented' ),
502 => _t ( 'ErrorPage.502' , '502 - Bad Gateway' ),
503 => _t ( 'ErrorPage.503' , '503 - Service Unavailable' ),
504 => _t ( 'ErrorPage.504' , '504 - Gateway Timeout' ),
505 => _t ( 'ErrorPage.505' , '505 - HTTP Version Not Supported' ),
2007-07-19 12:40:28 +02:00
)
),
" Content "
);
return $fields ;
}
/**
* When an error page is published , create a static HTML page with its
* content , so the page can be shown even when SilverStripe is not
* functioning correctly before publishing this page normally .
* @ param string | int $fromStage Place to copy from . Can be either a stage name or a version number .
* @ param string $toStage Place to copy to . Must be a stage name .
* @ param boolean $createNewVersion Set this to true to create a new version number . By default , the existing version number will be copied over .
*/
2009-05-04 04:20:57 +02:00
function doPublish () {
parent :: doPublish ();
2007-07-19 12:40:28 +02:00
2010-10-15 05:04:10 +02:00
// Run the page (reset the theme, it might've been disabled by LeftAndMain::init())
$oldTheme = SSViewer :: current_theme ();
SSViewer :: set_theme ( SSViewer :: current_custom_theme ());
2008-12-04 23:38:32 +01:00
$response = Director :: test ( Director :: makeRelative ( $this -> Link ()));
2010-10-15 05:04:10 +02:00
SSViewer :: set_theme ( $oldTheme );
2008-12-04 23:38:32 +01:00
2008-11-22 04:33:00 +01:00
$errorContent = $response -> getBody ();
2010-10-15 05:04:10 +02:00
2009-10-12 05:23:10 +02:00
// Make the base tag dynamic.
2010-10-15 05:04:10 +02:00
// $errorContent = preg_replace('/<base[^>]+href="' . str_replace('/','\\/', Director::absoluteBaseURL()) . '"[^>]*>/i', '<base href="$BaseURL" />', $errorContent);
2007-10-28 09:14:49 +01:00
2009-02-02 00:49:53 +01:00
// Check we have an assets base directory, creating if it we don't
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
if ( ! file_exists ( ASSETS_PATH )) {
mkdir ( ASSETS_PATH , 02775 );
2007-10-28 09:14:49 +01:00
}
2007-07-19 12:40:28 +02:00
2009-10-12 05:23:10 +02:00
2009-01-19 02:25:23 +01:00
// if the page is published in a language other than default language,
// write a specific language version of the HTML page
ENHANCEMENT Adjusted SearchForm, Debug, ErrorPage, SiteTree to using locales instead of lang codes
API CHANGE Changed Translatable datamodel to use locales ("en_US") instead of lang values ("en).
API CHANGE Changed Translatable::$default_lang to $default_locale, Translatable::$reading_lang to $reading_locale
API CHANGE Using "locale" instead of "lang" in Translatable::choose_site_lang() to auto-detect language from cookies or GET parameters
API CHANGE Deprecated Translatable::is_default_lang(), set_default_lang(), get_default_lang(), current_lang(), set_reading_lang(), get_reading_lang(), get_by_lang(), get_one_by_lang()
API CHANGE Removed Translatable::get_original() - with the new "translation groups" concept there no longer is an original for a translation
BUGFIX Updated MigrateTranslatableTask to new Locale based datamodel
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@73468 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-03-20 09:47:06 +01:00
$filePath = self :: get_filepath_for_errorcode ( $this -> ErrorCode , $this -> Locale );
2009-01-19 02:25:23 +01:00
if ( $fh = fopen ( $filePath , " w " )) {
2007-10-03 02:10:49 +02:00
fwrite ( $fh , $errorContent );
2007-07-19 12:40:28 +02:00
fclose ( $fh );
2009-02-02 00:49:53 +01:00
} else {
$fileErrorText = sprintf (
_t (
" ErrorPage.ERRORFILEPROBLEM " ,
" Error opening file \" %s \" for writing. Please check file permissions. "
),
$errorFile
);
FormResponse :: status_message ( $fileErrorText , 'bad' );
FormResponse :: respond ();
return ;
2007-07-19 12:40:28 +02:00
}
}
2008-11-02 21:04:10 +01:00
2009-04-29 02:07:39 +02:00
/**
*
* @ param boolean $includerelations a boolean value to indicate if the labels returned include relation fields
*
*/
function fieldLabels ( $includerelations = true ) {
$labels = parent :: fieldLabels ( $includerelations );
2008-11-02 21:04:10 +01:00
$labels [ 'ErrorCode' ] = _t ( 'ErrorPage.CODE' , " Error code " );
return $labels ;
}
2009-01-19 02:25:23 +01:00
/**
* Returns an absolute filesystem path to a static error file
* which is generated through { @ link publish ()} .
*
* @ param int $statusCode A HTTP Statuscode , mostly 404 or 500
2009-05-01 01:51:55 +02:00
* @ param String $locale A locale , e . g . 'de_DE' ( Optional )
2009-01-19 02:25:23 +01:00
* @ return String
*/
2009-05-01 01:51:55 +02:00
static function get_filepath_for_errorcode ( $statusCode , $locale = null ) {
2010-10-13 03:18:35 +02:00
if ( singleton ( 'ErrorPage' ) -> hasMethod ( 'alternateFilepathForErrorcode' )) {
return singleton ( 'ErrorPage' ) -> alternateFilepathForErrorcode ( $statusCode , $locale );
}
2009-05-01 01:51:55 +02:00
if ( singleton ( 'SiteTree' ) -> hasExtension ( 'Translatable' ) && $locale && $locale != Translatable :: default_locale ()) {
return self :: $static_filepath . " /error- { $statusCode } - { $locale } .html " ;
2009-01-19 02:25:23 +01:00
} else {
return self :: $static_filepath . " /error- { $statusCode } .html " ;
}
}
/**
* Set the path where static error files are saved through { @ link publish ()} .
* Defaults to / assets .
*
* @ param string $path
*/
static function set_static_filepath ( $path ) {
self :: $static_filepath = $path ;
}
/**
* @ return string
*/
2009-05-04 04:20:57 +02:00
static function get_static_filepath () {
2009-01-19 02:25:23 +01:00
return self :: $static_filepath ;
}
2007-07-19 12:40:28 +02:00
}
/**
* Controller for ErrorPages .
2008-02-25 03:10:37 +01:00
* @ package cms
2007-07-19 12:40:28 +02:00
*/
class ErrorPage_Controller extends Page_Controller {
2009-05-04 04:20:57 +02:00
function init () {
parent :: init ();
$action = $this -> request -> param ( 'Action' );
if ( ! $action || $action == 'index' ) {
Director :: set_status_code ( $this -> failover -> ErrorCode ? $this -> failover -> ErrorCode : 404 );
}
2007-12-02 22:33:59 +01:00
}
2007-07-19 12:40:28 +02:00
}
2007-09-15 01:21:35 +02:00
2007-12-02 22:24:12 +01:00
?>