Improved PHPDoc comments

This commit is contained in:
Christopher Pitt 2015-11-14 11:44:49 +13:00
parent a93a677187
commit da852ceea1
6 changed files with 549 additions and 334 deletions

View File

@ -1,62 +1,72 @@
<?php <?php
/** /**
* The content negotiator performs "text/html" or "application/xhtml+xml" switching. * The content negotiator performs "text/html" or "application/xhtml+xml" switching. It does this through
* It does this through the public static function ContentNegotiator::process(). * the public static function ContentNegotiator::process(). By default, ContentNegotiator will comply to
* By default, ContentNegotiator will comply to the Accept headers the clients * the Accept headers the clients sends along with the HTTP request, which is most likely
* sends along with the HTTP request, which is most likely "application/xhtml+xml" * "application/xhtml+xml" (see "Order of selection" below).
* (see "Order of selection" below).
* *
* Order of selection between html or xhtml is as follows: * Order of selection between html or xhtml is as follows:
* - if PHP has already sent the HTTP headers, default to "html" (we can't send HTTP Content-Type headers any longer) * - if PHP has already sent the HTTP headers, default to "html" (we can't send HTTP Content-Type headers
* any longer)
* - if a GET variable ?forceFormat is set, it takes precedence (for testing purposes) * - if a GET variable ?forceFormat is set, it takes precedence (for testing purposes)
* - if the user agent is detected as W3C Validator we always deliver "xhtml" * - if the user agent is detected as W3C Validator we always deliver "xhtml"
* - if an HTTP Accept header is sent from the client, we respect its order (this is the most common case) * - if an HTTP Accept header is sent from the client, we respect its order (this is the most common case)
* - if none of the above matches, fallback is "html" * - if none of the above matches, fallback is "html"
* *
* ContentNegotiator doesn't enable you to send content as a true XML document * ContentNegotiator doesn't enable you to send content as a true XML document through the "text/xml"
* through the "text/xml" or "application/xhtml+xml" Content-Type. * or "application/xhtml+xml" Content-Type.
*
* Please see http://webkit.org/blog/68/understanding-html-xml-and-xhtml/ for further information. * Please see http://webkit.org/blog/68/understanding-html-xml-and-xhtml/ for further information.
* *
* @package framework * @package framework
*
* @subpackage control * @subpackage control
* *
* @todo Check for correct XHTML doctype in xhtml() * @todo Check for correct XHTML doctype in xhtml()
* @todo Allow for other HTML4 doctypes (e.g. Transitional) in html() * @todo Allow for other HTML4 doctypes (e.g. Transitional) in html()
* @todo Make content replacement and doctype setting two separately configurable behaviours - some * @todo Make content replacement and doctype setting two separately configurable behaviours
* devs might know what they're doing and don't want contentnegotiator messing with their HTML4 doctypes, *
* but still find it useful to have self-closing tags removed. * Some developers might know what they're doing and don't want ContentNegotiator messing with their
* HTML4 doctypes, but still find it useful to have self-closing tags removed.
*/ */
class ContentNegotiator extends Object { class ContentNegotiator extends Object {
/** /**
* @config * @config
*
* @var string * @var string
*/ */
private static $content_type = ''; private static $content_type = '';
/** /**
* @config * @config
*
* @var string * @var string
*/ */
private static $encoding = 'utf-8'; private static $encoding = 'utf-8';
/** /**
* @config * @config
* @var boolean *
* @var bool
*/ */
private static $enabled = false; private static $enabled = false;
/** /**
* @config * @config
*
* @var string * @var string
*/ */
private static $default_format = 'html'; private static $default_format = 'html';
/** /**
* Set the character set encoding for this page. By default it's utf-8, but you could change it to, say, * Set the character set encoding for this page. By default it's utf-8, but you could change it to,
* windows-1252, to improve interoperability with extended characters being imported from windows excel. * say, windows-1252, to improve interoperability with extended characters being imported from windows
* excel.
* *
* @deprecated 4.0 Use the "ContentNegotiator.encoding" config setting instead * @deprecated 4.0 Use the "ContentNegotiator.encoding" config setting instead
*
* @param string $encoding
*/ */
public static function set_encoding($encoding) { public static function set_encoding($encoding) {
Deprecation::notice('4.0', 'Use the "ContentNegotiator.encoding" config setting instead'); Deprecation::notice('4.0', 'Use the "ContentNegotiator.encoding" config setting instead');
@ -64,10 +74,12 @@ class ContentNegotiator extends Object {
} }
/** /**
* Return the character encoding set bhy ContentNegotiator::set_encoding(). It's recommended that all classes * Return the character encoding set bhy ContentNegotiator::set_encoding(). It's recommended that all
* that need to specify the character set make use of this function. * classes that need to specify the character set make use of this function.
* *
* @deprecated 4.0 Use the "ContentNegotiator.encoding" config setting instead * @deprecated 4.0 Use the "ContentNegotiator.encoding" config setting instead.
*
* @return string
*/ */
public static function get_encoding() { public static function get_encoding() {
Deprecation::notice('4.0', 'Use the "ContentNegotiator.encoding" config setting instead'); Deprecation::notice('4.0', 'Use the "ContentNegotiator.encoding" config setting instead');
@ -95,13 +107,13 @@ class ContentNegotiator extends Object {
} }
/** /**
* Returns true if negotation is enabled for the given response. * Returns true if negotiation is enabled for the given response. By default, negotiation is only
* By default, negotiation is only enabled for pages that have the xml header. * enabled for pages that have the xml header.
*/ */
public static function enabled_for($response) { public static function enabled_for($response) {
$contentType = $response->getHeader("Content-Type"); $contentType = $response->getHeader("Content-Type");
// Disable content negotation for other content types // Disable content negotiation for other content types
if($contentType && substr($contentType, 0,9) != 'text/html' if($contentType && substr($contentType, 0,9) != 'text/html'
&& substr($contentType, 0,21) != 'application/xhtml+xml') { && substr($contentType, 0,21) != 'application/xhtml+xml') {
return false; return false;
@ -111,6 +123,9 @@ class ContentNegotiator extends Object {
else return (substr($response->getBody(),0,5) == '<' . '?xml'); else return (substr($response->getBody(),0,5) == '<' . '?xml');
} }
/**
* @param SS_HTTPResponse $response
*/
public static function process(SS_HTTPResponse $response) { public static function process(SS_HTTPResponse $response) {
if(!self::enabled_for($response)) return; if(!self::enabled_for($response)) return;
@ -126,8 +141,8 @@ class ContentNegotiator extends Object {
$chosenFormat = $_GET['forceFormat']; $chosenFormat = $_GET['forceFormat'];
} else { } else {
// The W3C validator doesn't send an HTTP_ACCEPT header, but it can support xhtml. We put this special // The W3C validator doesn't send an HTTP_ACCEPT header, but it can support xhtml. We put this
// case in here so that designers don't get worried that their templates are HTML4. // special case in here so that designers don't get worried that their templates are HTML4.
if(isset($_SERVER['HTTP_USER_AGENT']) && substr($_SERVER['HTTP_USER_AGENT'], 0, 14) == 'W3C_Validator/') { if(isset($_SERVER['HTTP_USER_AGENT']) && substr($_SERVER['HTTP_USER_AGENT'], 0, 14) == 'W3C_Validator/') {
$chosenFormat = "xhtml"; $chosenFormat = "xhtml";
@ -159,8 +174,8 @@ class ContentNegotiator extends Object {
* Replaces a few common tags and entities with their XHTML representations (<br>, <img>, &nbsp; * Replaces a few common tags and entities with their XHTML representations (<br>, <img>, &nbsp;
* <input>, checked, selected). * <input>, checked, selected).
* *
* @param $response SS_HTTPResponse * @param SS_HTTPResponse $response
* @return string *
* @todo Search for more xhtml replacement * @todo Search for more xhtml replacement
*/ */
public function xhtml(SS_HTTPResponse $response) { public function xhtml(SS_HTTPResponse $response) {
@ -191,12 +206,15 @@ class ContentNegotiator extends Object {
$response->setBody($content); $response->setBody($content);
} }
/* /**
* Check user defined content type and use it, if it's empty use the text/html. * Performs the following replacements:
* If find a XML header replaces it and existing doctypes with HTML4.01 Strict. * - Check user defined content type and use it, if it's empty use the text/html.
* Replaces self-closing tags like <img /> with unclosed solitary tags like <img>. * - If find a XML header replaces it and existing doctypes with HTML4.01 Strict.
* Replaces all occurrences of "application/xhtml+xml" with "text/html" in the template. * - Replaces self-closing tags like <img /> with unclosed solitary tags like <img>.
* Removes "xmlns" attributes and any <?xml> Pragmas. * - Replaces all occurrences of "application/xhtml+xml" with "text/html" in the template.
* - Removes "xmlns" attributes and any <?xml> Pragmas.
*
* @param SS_HTTPResponse $response
*/ */
public function html(SS_HTTPResponse $response) { public function html(SS_HTTPResponse $response) {
$encoding = Config::inst()->get('ContentNegotiator', 'encoding'); $encoding = Config::inst()->get('ContentNegotiator', 'encoding');

View File

@ -1,63 +1,81 @@
<?php <?php
/** /**
* Base controller class. * Controllers are the cornerstone of all site functionality in SilverStripe. The {@link Director}
* Controllers are the cornerstone of all site functionality in SilverStripe. The {@link Director} * selects a controller to pass control to, and then calls {@link run()}. This method will execute
* selects a controller to pass control to, and then calls {@link run()}. This method will execute
* the appropriate action - either by calling the action method, or displaying the action's template. * the appropriate action - either by calling the action method, or displaying the action's template.
* *
* See {@link getTemplate()} for information on how the template is chosen. * See {@link getTemplate()} for information on how the template is chosen.
*
* @package framework * @package framework
*
* @subpackage control * @subpackage control
*/ */
class Controller extends RequestHandler implements TemplateGlobalProvider { class Controller extends RequestHandler implements TemplateGlobalProvider {
/** /**
* @var array $urlParams An array of arguments extracted from the URL * An array of arguments extracted from the URL.
*
* @var array
*/ */
protected $urlParams; protected $urlParams;
/** /**
* @var array $requestParams Contains all GET and POST parameters * Contains all GET and POST parameters passed to the current {@link SS_HTTPRequest}.
* passed to the current {@link SS_HTTPRequest}. *
* @uses SS_HTTPRequest->requestVars() * @var array
*/ */
protected $requestParams; protected $requestParams;
/** /**
* @var string $action The URL part matched on the current controller as * The URL part matched on the current controller as determined by the "$Action" part of the
* determined by the "$Action" part of the {@link $url_handlers} definition. * {@link $url_handlers} definition. Should correlate to a public method on this controller.
* Should correlate to a public method on this controller. *
* Used in {@link render()} and {@link getViewer()} to determine * Used in {@link render()} and {@link getViewer()} to determine action-specific templates.
* action-specific templates. *
* @var string
*/ */
protected $action; protected $action;
/** /**
* The {@link Session} object for this controller * The {@link Session} object for this controller.
*
* @var Session
*/ */
protected $session; protected $session;
/** /**
* Stack of current controllers. * Stack of current controllers. Controller::$controller_stack[0] is the current controller.
* Controller::$controller_stack[0] is the current controller. *
* @var array
*/ */
protected static $controller_stack = array(); protected static $controller_stack = array();
/**
* @var bool
*/
protected $basicAuthEnabled = true; protected $basicAuthEnabled = true;
/** /**
* @var SS_HTTPResponse $response The response object that the controller returns. * The response object that the controller returns.
*
* Set in {@link handleRequest()}. * Set in {@link handleRequest()}.
*
* @var SS_HTTPResponse
*/ */
protected $response; protected $response;
/** /**
* Default URL handlers - (Action)/(ID)/(OtherID) * Default URL handlers.
*
* @var array
*/ */
private static $url_handlers = array( private static $url_handlers = array(
'$Action//$ID/$OtherID' => 'handleAction', '$Action//$ID/$OtherID' => 'handleAction',
); );
/**
* @var array
*/
private static $allowed_actions = array( private static $allowed_actions = array(
'handleAction', 'handleAction',
'handleIndex', 'handleIndex',
@ -76,7 +94,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Returns a link to this controller. Overload with your own Link rules if they exist. * Returns a link to this controller. Overload with your own Link rules if they exist.
*
* @return string
*/ */
public function Link() { public function Link() {
return get_class($this) .'/'; return get_class($this) .'/';
@ -86,32 +106,29 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
* Executes this controller, and return an {@link SS_HTTPResponse} object with the result. * Executes this controller, and return an {@link SS_HTTPResponse} object with the result.
* *
* This method first does a few set-up activities: * This method first does a few set-up activities:
* - Push this controller ont to the controller stack - * - Push this controller ont to the controller stack - see {@link Controller::curr()} for
* see {@link Controller::curr()} for information about this. * information about this.
* - Call {@link init()} * - Call {@link init()}
* - Defer to {@link RequestHandler->handleRequest()} to determine which action * - Defer to {@link RequestHandler->handleRequest()} to determine which action should be executed.
* should be executed *
* Note: $requestParams['executeForm'] support was removed, make the following change in your URLs:
* "/?executeForm=FooBar" -> "/FooBar".
* *
* Note: $requestParams['executeForm'] support was removed,
* make the following change in your URLs:
* "/?executeForm=FooBar" -> "/FooBar"
* Also make sure "FooBar" is in the $allowed_actions of your controller class. * Also make sure "FooBar" is in the $allowed_actions of your controller class.
* *
* Note: You should rarely need to overload run() - * Note: You should rarely need to overload run() - this kind of change is only really appropriate
* this kind of change is only really appropriate for things like nested * for things like nested controllers - {@link ModelAsController} and {@link RootURLController}
* controllers - {@link ModelAsController} and {@link RootURLController} * are two examples here. If you want to make more orthodox functionality, it's better to overload
* are two examples here. If you want to make more * {@link init()} or {@link index()}.
* orthodox functionality, it's better to overload {@link init()} or {@link index()}.
* *
* Important: If you are going to overload handleRequest, * Important: If you are going to overload handleRequest, make sure that you start the method with
* make sure that you start the method with $this->pushCurrent() * $this->pushCurrent() and end the method with $this->popCurrent(). Failure to do this will create
* and end the method with $this->popCurrent(). * weird session errors.
* Failure to do this will create weird session errors.
* *
* @param $request The {@link SS_HTTPRequest} object that is responsible * @param SS_HTTPRequest $request
* for distributing request parsing. * @param DataModel $model
* @return SS_HTTPResponse The response that this controller produces, *
* including HTTP headers such as redirection info * @return SS_HTTPResponse
*/ */
public function handleRequest(SS_HTTPRequest $request, DataModel $model) { public function handleRequest(SS_HTTPRequest $request, DataModel $model) {
if(!$request) user_error("Controller::handleRequest() not passed a request!", E_USER_ERROR); if(!$request) user_error("Controller::handleRequest() not passed a request!", E_USER_ERROR);
@ -171,8 +188,13 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Controller's default action handler. It will call the method named in $Action, if that method exists. * Controller's default action handler. It will call the method named in "$Action", if that method
* If $Action isn't given, it will use "index" as a default. * exists. If "$Action" isn't given, it will use "index" as a default.
*
* @param SS_HTTPRequest $request
* @param string $action
*
* @return HTMLText|SS_HTTPResponse
*/ */
protected function handleAction($request, $action) { protected function handleAction($request, $action) {
$this->extend('beforeCallActionHandler', $request, $action); $this->extend('beforeCallActionHandler', $request, $action);
@ -198,20 +220,27 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
} }
/**
* @param array $urlParams
*/
public function setURLParams($urlParams) { public function setURLParams($urlParams) {
$this->urlParams = $urlParams; $this->urlParams = $urlParams;
} }
/** /**
* @return array The parameters extracted from the URL by the {@link Director}. * Returns the parameters extracted from the URL by the {@link Director}.
*
* @return array
*/ */
public function getURLParams() { public function getURLParams() {
return $this->urlParams; return $this->urlParams;
} }
/** /**
* Returns the SS_HTTPResponse object that this controller is building up. * Returns the SS_HTTPResponse object that this controller is building up. Can be used to set the
* Can be used to set the status code and headers * status code and headers.
*
* @return SS_HTTPResponse
*/ */
public function getResponse() { public function getResponse() {
if (!$this->response) { if (!$this->response) {
@ -224,21 +253,27 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
* Sets the SS_HTTPResponse object that this controller is building up. * Sets the SS_HTTPResponse object that this controller is building up.
* *
* @param SS_HTTPResponse $response * @param SS_HTTPResponse $response
* @return Controller *
* @return $this
*/ */
public function setResponse(SS_HTTPResponse $response) { public function setResponse(SS_HTTPResponse $response) {
$this->response = $response; $this->response = $response;
return $this; return $this;
} }
/**
* @var bool
*/
protected $baseInitCalled = false; protected $baseInitCalled = false;
/** /**
* Return the object that is going to own a form that's being processed, and handle its execution. * Return the object that is going to own a form that's being processed, and handle its execution.
* Note that the result needn't be an actual controller object. * Note that the result need not be an actual controller object.
*
* @return mixed
*/ */
public function getFormOwner() { public function getFormOwner() {
// Get the appropraite ocntroller: sometimes we want to get a form from another controller // Get the appropriate controller: sometimes we want to get a form from another controller
if(isset($this->requestParams['formController'])) { if(isset($this->requestParams['formController'])) {
$formController = Director::getControllerForURL($this->requestParams['formController']); $formController = Director::getControllerForURL($this->requestParams['formController']);
@ -253,8 +288,12 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* This is the default action handler used if a method doesn't exist. * This is the default action handler used if a method doesn't exist. It will process the
* It will process the controller object with the template returned by {@link getViewer()} * controller object with the template returned by {@link getViewer()}.
*
* @param string $action
*
* @return HTMLText
*/ */
public function defaultAction($action) { public function defaultAction($action) {
return $this->getViewer($action)->process($this); return $this->getViewer($action)->process($this);
@ -262,14 +301,19 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
/** /**
* Returns the action that is being executed on this controller. * Returns the action that is being executed on this controller.
*
* @return string
*/ */
public function getAction() { public function getAction() {
return $this->action; return $this->action;
} }
/** /**
* Return an SSViewer object to process the data * Return the viewer identified being the default handler for this Controller/Action combination.
* @return SSViewer The viewer identified being the default handler for this Controller/Action combination *
* @param string $action
*
* @return SSViewer
*/ */
public function getViewer($action) { public function getViewer($action) {
// Hard-coded templates // Hard-coded templates
@ -308,14 +352,22 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
return new SSViewer($templates); return new SSViewer($templates);
} }
/**
* @param string $action
*
* @return bool
*/
public function hasAction($action) { public function hasAction($action) {
return parent::hasAction($action) || $this->hasActionTemplate($action); return parent::hasAction($action) || $this->hasActionTemplate($action);
} }
/** /**
* Removes all the "action" part of the current URL and returns the result. * Removes all the "action" part of the current URL and returns the result. If no action parameter
* If no action parameter is present, returns the full URL * is present, returns the full URL.
* @static *
* @param string $fullURL
* @param null|string $action
*
* @return string * @return string
*/ */
public function removeAction($fullURL, $action = null) { public function removeAction($fullURL, $action = null) {
@ -331,7 +383,11 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
/** /**
* Return the class that defines the given action, so that we know where to check allowed_actions. * Return the class that defines the given action, so that we know where to check allowed_actions.
* Overrides RequestHandler to also look at defined templates * Overrides RequestHandler to also look at defined templates.
*
* @param string $action
*
* @return string
*/ */
protected function definingClassForAction($action) { protected function definingClassForAction($action) {
$definingClass = parent::definingClassForAction($action); $definingClass = parent::definingClassForAction($action);
@ -347,9 +403,11 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Returns TRUE if this controller has a template that is specifically designed to handle a specific action. * Returns TRUE if this controller has a template that is specifically designed to handle a
* specific action.
* *
* @param string $action * @param string $action
*
* @return bool * @return bool
*/ */
public function hasActionTemplate($action) { public function hasActionTemplate($action) {
@ -367,11 +425,11 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Render the current controller with the templates determined * Render the current controller with the templates determined by {@link getViewer()}.
* by {@link getViewer()}.
* *
* @param array $params Key-value array for custom template variables (Optional) * @param array $params
* @return string Parsed template content *
* @return string
*/ */
public function render($params = null) { public function render($params = null) {
$template = $this->getViewer($this->getAction()); $template = $this->getViewer($this->getAction());
@ -385,16 +443,17 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Call this to disable site-wide basic authentication for a specific contoller. * Call this to disable site-wide basic authentication for a specific controller. This must be
* This must be called before Controller::init(). That is, you must call it in your controller's * called before Controller::init(). That is, you must call it in your controller's init method
* init method before it calls parent::init(). * before it calls parent::init().
*/ */
public function disableBasicAuth() { public function disableBasicAuth() {
$this->basicAuthEnabled = false; $this->basicAuthEnabled = false;
} }
/** /**
* Returns the current controller * Returns the current controller.
*
* @return Controller * @return Controller
*/ */
public static function curr() { public static function curr() {
@ -406,19 +465,23 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Tests whether we have a currently active controller or not * Tests whether we have a currently active controller or not. True if there is at least 1
* @return boolean True if there is at least 1 controller in the stack. * controller in the stack.
*
* @return bool
*/ */
public static function has_curr() { public static function has_curr() {
return Controller::$controller_stack ? true : false; return Controller::$controller_stack ? true : false;
} }
/** /**
* Returns true if the member is allowed to do the given action. * Returns true if the member is allowed to do the given action. Defaults to the currently logged
* @param perm The permission to be checked, such as 'View'.
* @param member The member whose permissions need checking. Defaults to the currently logged
* in user. * in user.
* @return boolean *
* @param string $perm
* @param null|member $member
*
* @return bool
*/ */
public function can($perm, $member = null) { public function can($perm, $member = null) {
if(!$member) $member = Member::currentUser(); if(!$member) $member = Member::currentUser();
@ -433,12 +496,10 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
} }
//---------------------------------------------------------------------------------------------------------------
/** /**
* Pushes this controller onto the stack of current controllers. * Pushes this controller onto the stack of current controllers. This means that any redirection,
* This means that any redirection, session setting, or other things that rely on Controller::curr() will now * session setting, or other things that rely on Controller::curr() will now write to this
* write to this controller object. * controller object.
*/ */
public function pushCurrent() { public function pushCurrent() {
array_unshift(self::$controller_stack, $this); array_unshift(self::$controller_stack, $this);
@ -467,6 +528,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
/** /**
* Redirect to the given URL. * Redirect to the given URL.
* *
* @param string $url
* @param int $code
*
* @return SS_HTTPResponse * @return SS_HTTPResponse
*/ */
public function redirect($url, $code=302) { public function redirect($url, $code=302) {
@ -486,12 +550,14 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Redirect back. Uses either the HTTP_REFERER or a manually set request-variable called "BackURL". * Redirect back. Uses either the HTTP-Referer or a manually set request-variable called "BackURL".
* This variable is needed in scenarios where not HTTP-Referer is sent ( * This variable is needed in scenarios where HTTP-Referer is not sent (e.g when calling a page by
* e.g when calling a page by location.href in IE). * location.href in IE). If none of the two variables is available, it will redirect to the base
* If none of the two variables is available, it will redirect to the base
* URL (see {@link Director::baseURL()}). * URL (see {@link Director::baseURL()}).
*
* @uses redirect() * @uses redirect()
*
* @return bool|SS_HTTPResponse
*/ */
public function redirectBack() { public function redirectBack() {
// Don't cache the redirect back ever // Don't cache the redirect back ever
@ -525,16 +591,18 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
} }
/** /**
* Tests whether a redirection has been requested. * Tests whether a redirection has been requested. If redirect() has been called, it will return
* @return string If redirect() has been called, it will return the URL redirected to. Otherwise, it will * the URL redirected to. Otherwise, it will return null.
* return null; *
* @return null|string
*/ */
public function redirectedTo() { public function redirectedTo() {
return $this->getResponse() && $this->getResponse()->getHeader('Location'); return $this->getResponse() && $this->getResponse()->getHeader('Location');
} }
/** /**
* Get the Session object representing this Controller's session * Get the Session object representing this Controller's session.
*
* @return Session * @return Session
*/ */
public function getSession() { public function getSession() {
@ -543,20 +611,22 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
/** /**
* Set the Session object. * Set the Session object.
*
* @param Session $session
*/ */
public function setSession(Session $session) { public function setSession(Session $session) {
$this->session = $session; $this->session = $session;
} }
/** /**
* Joins two or more link segments together, putting a slash between them if necessary. * Joins two or more link segments together, putting a slash between them if necessary. Use this
* Use this for building the results of {@link Link()} methods. * for building the results of {@link Link()} methods. If either of the links have query strings,
* If either of the links have query strings,
* then they will be combined and put at the end of the resulting url. * then they will be combined and put at the end of the resulting url.
* *
* Caution: All parameters are expected to be URI-encoded already. * Caution: All parameters are expected to be URI-encoded already.
* *
* @param string * @param string
*
* @return string * @return string
*/ */
public static function join_links() { public static function join_links() {
@ -590,6 +660,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
return $result; return $result;
} }
/**
* @return array
*/
public static function get_template_global_variables() { public static function get_template_global_variables() {
return array( return array(
'CurrentPage' => 'curr', 'CurrentPage' => 'curr',

View File

@ -3,35 +3,41 @@
* A set of static methods for manipulating cookies. * A set of static methods for manipulating cookies.
* *
* @package framework * @package framework
*
* @subpackage misc * @subpackage misc
*/ */
class Cookie { class Cookie {
/** /**
* @config * @config
* @var boolean *
* @var bool
*/ */
private static $report_errors = true; private static $report_errors = true;
/** /**
* Fetch the current instance of the cookie backend * Fetch the current instance of the cookie backend.
* *
* @return Cookie_Backend The cookie backend * @return Cookie_Backend
*/ */
public static function get_inst() { public static function get_inst() {
return Injector::inst()->get('Cookie_Backend'); return Injector::inst()->get('Cookie_Backend');
} }
/** /**
* Set a cookie variable * Set a cookie variable.
* *
* @param string $name The variable name * Expiry time is set in days, and defaults to 90.
* @param mixed $value The variable value. *
* @param int $expiry The expiry time, in days. Defaults to 90. * @param string $name
* @param string $path See http://php.net/set_session * @param mixed $value
* @param string $domain See http://php.net/set_session * @param int $expiry
* @param boolean $secure See http://php.net/set_session * @param string $path
* @param boolean $httpOnly See http://php.net/set_session * @param string $domain
* @param bool $secure
* @param bool $httpOnly
*
* See http://php.net/set_session
*/ */
public static function set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = false, public static function set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = false,
$httpOnly = true $httpOnly = true
@ -40,31 +46,34 @@ class Cookie {
} }
/** /**
* Get the cookie value by name * Get the cookie value by name. Returns null if not set.
* *
* @param string $name The name of the cookie to get * @param string $name
* @param boolean $includeUnsent Include cookies we've yet to send when fetching values * @param bool $includeUnsent
* *
* @return string|null The cookie value or null if unset * @return null|string
*/ */
public static function get($name, $includeUnsent = true) { public static function get($name, $includeUnsent = true) {
return self::get_inst()->get($name, $includeUnsent); return self::get_inst()->get($name, $includeUnsent);
} }
/** /**
* Get all the cookies * Get all the cookies.
* *
* @param boolean $includeUnsent Include cookies we've yet to send * @param bool $includeUnsent
* @return array All the cookies *
* @return array
*/ */
public static function get_all($includeUnsent = true) { public static function get_all($includeUnsent = true) {
return self::get_inst()->getAll($includeUnsent); return self::get_inst()->getAll($includeUnsent);
} }
/** /**
* @param string * @param string $name
* @param string * @param null|string $path
* @param string * @param null|string $domain
* @param bool $secure
* @param bool $httpOnly
*/ */
public static function force_expiry($name, $path = null, $domain = null, $secure = false, $httpOnly = true) { public static function force_expiry($name, $path = null, $domain = null, $secure = false, $httpOnly = true) {
return self::get_inst()->forceExpiry($name, $path, $domain, $secure, $httpOnly); return self::get_inst()->forceExpiry($name, $path, $domain, $secure, $httpOnly);

View File

@ -2,14 +2,16 @@
/** /**
* Director is responsible for processing URLs, and providing environment information. * Director is responsible for processing URLs, and providing environment information.
* *
* The most important part of director is {@link Director::direct()}, which is passed a URL and will execute the * The most important part of director is {@link Director::direct()}, which is passed a URL and will
* appropriate controller. * execute the appropriate controller.
* *
* Director also has a number of static methods that provide information about the environment, such as * Director also has a number of static methods that provide information about the environment, such as
* {@link Director::$environment_type}. * {@link Director::$environment_type}.
* *
* @package framework * @package framework
*
* @subpackage control * @subpackage control
*
* @see Director::direct() * @see Director::direct()
* @see Director::$rules * @see Director::$rules
* @see Director::$environment_type * @see Director::$environment_type
@ -17,22 +19,34 @@
class Director implements TemplateGlobalProvider { class Director implements TemplateGlobalProvider {
/** /**
* Specifies this url is relative to the base * Specifies this url is relative to the base.
*
* @var string
*/ */
const BASE = 'BASE'; const BASE = 'BASE';
/** /**
* Specifies this url is relative to the site root * Specifies this url is relative to the site root.
*
* @var string
*/ */
const ROOT = 'ROOT'; const ROOT = 'ROOT';
/** /**
* specifies this url is relative to the current request * specifies this url is relative to the current request.
*
* @var string
*/ */
const REQUEST = 'REQUEST'; const REQUEST = 'REQUEST';
/**
* @var array
*/
static private $urlParams; static private $urlParams;
/**
* @var array
*/
static private $rules = array(); static private $rules = array();
/** /**
@ -42,52 +56,61 @@ class Director implements TemplateGlobalProvider {
/** /**
* @config * @config
*
* @var string * @var string
*/ */
private static $alternate_base_folder; private static $alternate_base_folder;
/** /**
* @config * @config
*
* @var array * @var array
*/ */
private static $dev_servers = array(); private static $dev_servers = array();
/** /**
* @config * @config
*
* @var array * @var array
*/ */
private static $test_servers = array(); private static $test_servers = array();
/** /**
* Setting this explicitly specifies the protocol (http or https) used, overriding * Setting this explicitly specifies the protocol ("http" or "https") used, overriding the normal
* the normal behaviour of Director::is_https introspecting it from the request * behaviour of Director::is_https introspecting it from the request. False values imply default
* introspection.
* *
* @config * @config
* @var string - "http" or "https" to force the protocol, or false-ish to use default introspection from request *
* @var string
*/ */
private static $alternate_protocol; private static $alternate_protocol;
/** /**
* @config * @config
*
* @var string * @var string
*/ */
private static $alternate_base_url; private static $alternate_base_url;
/** /**
* @config * @config
*
* @var string * @var string
*/ */
private static $environment_type; private static $environment_type;
/** /**
* Add URL matching rules to the Director. * Add URL matching rules to the Director. The director is responsible for turning URLs into
* Controller objects.
* *
* The director is responsible for turning URLs into Controller objects. * Higher $priority values will get your rule checked first. We recommend priority 100 for your
* site's rules. The built-in rules are priority 10, standard modules are priority 50.
* *
* @deprecated 4.0 Use the "Director.rules" config setting instead * @deprecated 4.0 Use the "Director.rules" config setting instead
* @param $priority The priority of the rules; higher values will get your rule checked first. We recommend *
* priority 100 for your site's rules. The built-in rules are priority 10, standard modules are * @param int $priority
* priority 50. * @param array $rules
*/ */
public static function addRules($priority, $rules) { public static function addRules($priority, $rules) {
Deprecation::notice('4.0', 'Use the "Director.rules" config setting instead'); Deprecation::notice('4.0', 'Use the "Director.rules" config setting instead');
@ -99,20 +122,25 @@ class Director implements TemplateGlobalProvider {
* Process the given URL, creating the appropriate controller and executing it. * Process the given URL, creating the appropriate controller and executing it.
* *
* Request processing is handled as follows: * Request processing is handled as follows:
* - Director::direct() creates a new SS_HTTPResponse object and passes this to Director::handleRequest(). * - Director::direct() creates a new SS_HTTPResponse object and passes this to
* - Director::handleRequest($request) checks each of the Director rules and identifies a controller to handle * Director::handleRequest().
* this request. * - Director::handleRequest($request) checks each of the Director rules and identifies a controller
* - Controller::handleRequest($request) is then called. This will find a rule to handle the URL, and call the * to handle this request.
* rule handling method. * - Controller::handleRequest($request) is then called. This will find a rule to handle the URL,
* - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method returns a * and call the rule handling method.
* RequestHandler object. * - 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 * In addition to request processing, Director will manage the session, and perform the output of
* response to the browser. * 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 handleRequest() rule-lookup logic is handled by this.
* @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. * @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call.
*
* @param string $url
* @param DataModel $model
*
* @throws SS_HTTPResponse_Exception
*/ */
public static function direct($url, DataModel $model) { public static function direct($url, DataModel $model) {
// Validate $_FILES array before merging it with $_POST // Validate $_FILES array before merging it with $_POST
@ -209,25 +237,28 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Test a URL request, returning a response object. * 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
* This method is the counterpart of Director::direct() that is used in functional testing. It will execute the * return the result as an SS_HTTPResponse object.
* 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|Cookie_Backend $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 getControllerForURL() The rule-lookup logic is handled by this.
* @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. * @uses Controller::run() Handles the page logic for a Director::direct() call.
*
* @param string $url The URL to visit.
* @param array $postVars The $_POST & $_FILES variables.
* @param array|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|Cookie_Backend $cookies to populate $_COOKIE.
* @param HTTP_Request $request The {@see HTTP_Request} object generated as a part of this request.
*
* @return SS_HTTPResponse
*
* @throws SS_HTTPResponse_Exception
*/ */
public static function test($url, $postVars = null, $session = array(), $httpMethod = null, $body = null, public static function test($url, $postVars = null, $session = array(), $httpMethod = null, $body = null,
$headers = array(), $cookies = array(), &$request = null) { $headers = array(), $cookies = array(), &$request = null) {
@ -235,8 +266,8 @@ class Director implements TemplateGlobalProvider {
Config::nest(); Config::nest();
Injector::nest(); Injector::nest();
// These are needed so that calling Director::test() doesnt muck with whoever is calling it. // These are needed so that calling Director::test() does not muck with whoever is calling it.
// Really, it's some inappropriate coupling and should be resolved by making less use of statics // Really, it's some inappropriate coupling and should be resolved by making less use of statics.
$oldStage = Versioned::current_stage(); $oldStage = Versioned::current_stage();
$getVars = array(); $getVars = array();
@ -265,7 +296,7 @@ class Director implements TemplateGlobalProvider {
$existingRequestVars, $existingGetVars, $existingPostVars, $existingSessionVars, $existingRequestVars, $existingGetVars, $existingPostVars, $existingSessionVars,
$existingCookies, $existingServer, $existingRequirementsBackend, $oldStage $existingCookies, $existingServer, $existingRequirementsBackend, $oldStage
) { ) {
// Restore the superglobals // Restore the super globals
$_REQUEST = $existingRequestVars; $_REQUEST = $existingRequestVars;
$_GET = $existingGetVars; $_GET = $existingGetVars;
$_POST = $existingPostVars; $_POST = $existingPostVars;
@ -275,7 +306,7 @@ class Director implements TemplateGlobalProvider {
Requirements::set_backend($existingRequirementsBackend); Requirements::set_backend($existingRequirementsBackend);
// These are needed so that calling Director::test() doesnt muck with whoever is calling it. // These are needed so that calling Director::test() does not muck with whoever is calling it.
// Really, it's some inappropriate coupling and should be resolved by making less use of statics // Really, it's some inappropriate coupling and should be resolved by making less use of statics
Versioned::reading_stage($oldStage); Versioned::reading_stage($oldStage);
@ -290,8 +321,7 @@ class Director implements TemplateGlobalProvider {
// Handle absolute URLs // Handle absolute URLs
if (parse_url($url, PHP_URL_HOST)) { if (parse_url($url, PHP_URL_HOST)) {
$bits = parse_url($url); $bits = parse_url($url);
// If a port is mentioned in the absolute URL, be sure to add that into the // If a port is mentioned in the absolute URL, be sure to add that into the HTTP host
// HTTP host
if(isset($bits['port'])) { if(isset($bits['port'])) {
$_SERVER['HTTP_HOST'] = $bits['host'].':'.$bits['port']; $_SERVER['HTTP_HOST'] = $bits['host'].':'.$bits['port'];
} else { } else {
@ -309,7 +339,7 @@ class Director implements TemplateGlobalProvider {
parse_str($getVarsEncoded, $getVars); parse_str($getVarsEncoded, $getVars);
} }
// Replace the superglobals with appropriate test values // Replace the super globals with appropriate test values
$_REQUEST = ArrayLib::array_merge_recursive((array) $getVars, (array) $postVars); $_REQUEST = ArrayLib::array_merge_recursive((array) $getVars, (array) $postVars);
$_GET = (array) $getVars; $_GET = (array) $getVars;
$_POST = (array) $postVars; $_POST = (array) $postVars;
@ -358,6 +388,10 @@ class Director implements TemplateGlobalProvider {
/** /**
* Handle an HTTP request, defined with a SS_HTTPRequest object. * Handle an HTTP request, defined with a SS_HTTPRequest object.
* *
* @param SS_HTTPRequest $request
* @param Session $session
* @param DataModel $model
*
* @return SS_HTTPResponse|string * @return SS_HTTPResponse|string
*/ */
protected static function handleRequest(SS_HTTPRequest $request, Session $session, DataModel $model) { protected static function handleRequest(SS_HTTPRequest $request, Session $session, DataModel $model) {
@ -382,12 +416,12 @@ class Director implements TemplateGlobalProvider {
// Find the controller name // Find the controller name
if(isset($arguments['Controller'])) $controller = $arguments['Controller']; if(isset($arguments['Controller'])) $controller = $arguments['Controller'];
// Pop additional tokens from the tokeniser if necessary // Pop additional tokens from the tokenizer if necessary
if(isset($controllerOptions['_PopTokeniser'])) { if(isset($controllerOptions['_PopTokeniser'])) {
$request->shift($controllerOptions['_PopTokeniser']); $request->shift($controllerOptions['_PopTokeniser']);
} }
// Handle redirections // Handle redirection
if(isset($arguments['Redirect'])) { if(isset($arguments['Redirect'])) {
return "redirect:" . Director::absoluteURL($arguments['Redirect'], true); return "redirect:" . Director::absoluteURL($arguments['Redirect'], true);
@ -416,15 +450,15 @@ class Director implements TemplateGlobalProvider {
/** /**
* Set url parameters (should only be called internally by RequestHandler->handleRequest()). * Set url parameters (should only be called internally by RequestHandler->handleRequest()).
* *
* @param $params array * @param array $params
*/ */
public static function setUrlParams($params) { public static function setUrlParams($params) {
Director::$urlParams = $params; Director::$urlParams = $params;
} }
/** /**
* Return the {@link SiteTree} object that is currently being viewed. If there is no SiteTree object to return, * Return the {@link SiteTree} object that is currently being viewed. If there is no SiteTree
* then this will return the current controller. * object to return, then this will return the current controller.
* *
* @return SiteTree * @return SiteTree
*/ */
@ -442,15 +476,16 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Turns the given URL into an absolute URL. * Turns the given URL into an absolute URL. By default non-site root relative urls will be
* By default non-site root relative urls will be evaluated relative to the current base_url * evaluated relative to the current base_url.
* *
* @param string $url URL To transform to absolute * @param string $url URL To transform to absolute.
* @param string $relativeParent Method to use for evaluating relative urls. * @param string $relativeParent Method to use for evaluating relative urls.
* Either one of BASE (baseurl), ROOT (site root), or REQUEST (requested page). * Either one of BASE (baseurl), ROOT (site root), or REQUEST (requested page).
* Defaults to BASE, which is the same behaviour as template url resolution. * Defaults to BASE, which is the same behaviour as template url resolution.
* Igored if the url is absolute or site root. * Ignored if the url is absolute or site root.
* @return string The fully qualified URL *
* @return string
*/ */
public static function absoluteURL($url, $relativeParent = self::BASE) { public static function absoluteURL($url, $relativeParent = self::BASE) {
if(is_bool($relativeParent)) { if(is_bool($relativeParent)) {
@ -496,10 +531,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns the part of the URL, 'http://www.mysite.com'. * Returns the domain part of the URL 'http://www.mysite.com'. Returns FALSE is this environment
* variable isn't set.
* *
* @return boolean|string The domain from the PHP environment. Returns FALSE is this environment variable isn't * @return bool|string
* set.
*/ */
public static function protocolAndHost() { public static function protocolAndHost() {
$alternate = Config::inst()->get('Director', 'alternate_base_url'); $alternate = Config::inst()->get('Director', 'alternate_base_url');
@ -538,7 +573,7 @@ class Director implements TemplateGlobalProvider {
/** /**
* Return whether the site is running as under HTTPS. * Return whether the site is running as under HTTPS.
* *
* @return boolean * @return bool
*/ */
public static function is_https() { public static function is_https() {
$return = false; $return = false;
@ -577,10 +612,8 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns the root URL for the site. * Returns the root URL for the site. It will be automatically calculated unless it is overridden
* * with {@link setBaseURL()}.
* It will be automatically calculated unless it is overridden with
* {@link setBaseURL()}.
* *
* @return string * @return string
*/ */
@ -607,10 +640,12 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Sets the root URL for the website. * Sets the root URL for the website. If the site isn't accessible from the URL you provide,
* If the site isn't accessible from the URL you provide, weird things will happen. * weird things will happen.
* *
* @deprecated 4.0 Use the "Director.alternate_base_url" config setting instead * @deprecated 4.0 Use the "Director.alternate_base_url" config setting instead.
*
* @param string $baseURL
*/ */
public static function setBaseURL($baseURL) { public static function setBaseURL($baseURL) {
Deprecation::notice('4.0', 'Use the "Director.alternate_base_url" config setting instead'); Deprecation::notice('4.0', 'Use the "Director.alternate_base_url" config setting instead');
@ -618,8 +653,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns the root filesystem folder for the site. * Returns the root filesystem folder for the site. It will be automatically calculated unless
* It will be automatically calculated unless it is overridden with {@link setBaseFolder()}. * it is overridden with {@link setBaseFolder()}.
*
* @return string
*/ */
public static function baseFolder() { public static function baseFolder() {
$alternate = Config::inst()->get('Director', 'alternate_base_folder'); $alternate = Config::inst()->get('Director', 'alternate_base_folder');
@ -627,10 +664,12 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Sets the root folder for the website. * Sets the root folder for the website. If the site isn't accessible from the folder you provide,
* If the site isn't accessible from the folder you provide, weird things will happen. * weird things will happen.
* *
* @deprecated 4.0 Use the "Director.alternate_base_folder" config setting instead * @deprecated 4.0 Use the "Director.alternate_base_folder" config setting instead.
*
* @param string $baseFolder
*/ */
public static function setBaseFolder($baseFolder) { public static function setBaseFolder($baseFolder) {
Deprecation::notice('4.0', 'Use the "Director.alternate_base_folder" config setting instead'); Deprecation::notice('4.0', 'Use the "Director.alternate_base_folder" config setting instead');
@ -638,13 +677,12 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Turns an absolute URL or folder into one that's relative to the root of * Turns an absolute URL or folder into one that's relative to the root of the site. This is useful
* the site. This is useful when turning a URL into a filesystem reference, * when turning a URL into a filesystem reference, or vice versa.
* or vice versa.
* *
* @param string $url Accepts both a URL or a filesystem path * @param string $url Accepts both a URL or a filesystem path.
* @return string Either a relative URL if the checks succeeded, or the *
* original (possibly absolute) URL. * @return string
*/ */
public static function makeRelative($url) { public static function makeRelative($url) {
// Allow for the accidental inclusion whitespace and // in the URL // Allow for the accidental inclusion whitespace and // in the URL
@ -695,10 +733,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns true if a given path is absolute. Works under both *nix and windows * Returns true if a given path is absolute. Works under both *nix and windows systems.
* systems
* *
* @param string $path * @param string $path
*
* @return bool * @return bool
*/ */
public static function is_absolute($path) { public static function is_absolute($path) {
@ -708,30 +746,30 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Determine if the url is root relative (i.e. starts with /, but not with //) * Determine if the url is root relative (i.e. starts with /, but not with //) SilverStripe
* SilverStripe considers root relative urls as a subset of relative urls * considers root relative urls as a subset of relative urls.
* *
* @param string $url * @param string $url
* @return bool True if this url is root relative *
* @return bool
*/ */
public static function is_root_relative_url($url) { public static function is_root_relative_url($url) {
return strpos($url, '/') === 0 && strpos($url, '//') !== 0; return strpos($url, '/') === 0 && strpos($url, '//') !== 0;
} }
/** /**
* Checks if a given URL is absolute (e.g. starts with 'http://' etc.). * Checks if a given URL is absolute (e.g. starts with 'http://' etc.). URLs beginning with "//"
* URLs beginning with "//" are treated as absolute, as browsers take this to mean * are treated as absolute, as browsers take this to mean the same protocol as currently being used.
* the same protocol as currently being used.
* *
* Useful to check before redirecting based on a URL from user submissions * Useful to check before redirecting based on a URL from user submissions through $_GET or $_POST,
* through $_GET or $_POST, and avoid phishing attacks by redirecting * and avoid phishing attacks by redirecting to an attackers server.
* to an attackers server.
* *
* Note: Can't solely rely on PHP's parse_url() , since it is not intended to work with relative URLs * Note: Can't solely rely on PHP's parse_url() , since it is not intended to work with relative URLs
* or for security purposes. filter_var($url, FILTER_VALIDATE_URL) has similar problems. * or for security purposes. filter_var($url, FILTER_VALIDATE_URL) has similar problems.
* *
* @param string $url * @param string $url
* @return boolean *
* @return bool
*/ */
public static function is_absolute_url($url) { public static function is_absolute_url($url) {
// Strip off the query and fragment parts of the URL before checking // Strip off the query and fragment parts of the URL before checking
@ -760,26 +798,27 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Checks if a given URL is relative (or root relative) by checking {@link is_absolute_url()} * Checks if a given URL is relative (or root relative) by checking {@link is_absolute_url()}.
* *
* @param string $url * @param string $url
* @return boolean *
* @return bool
*/ */
public static function is_relative_url($url) { public static function is_relative_url($url) {
return !static::is_absolute_url($url); return !static::is_absolute_url($url);
} }
/** /**
* Checks if the given URL is belonging to this "site" (not an external link). * Checks if the given URL is belonging to this "site" (not an external link). That's the case if
* That's the case if the URL is relative, as defined by {@link is_relative_url()}, * the URL is relative, as defined by {@link is_relative_url()}, or if the host matches
* or if the host matches {@link protocolAndHost()}. * {@link protocolAndHost()}.
* *
* Useful to check before redirecting based on a URL from user submissions * Useful to check before redirecting based on a URL from user submissions through $_GET or $_POST,
* through $_GET or $_POST, and avoid phishing attacks by redirecting * and avoid phishing attacks by redirecting to an attackers server.
* to an attackers server.
* *
* @param string $url * @param string $url
* @return boolean *
* @return bool
*/ */
public static function is_site_url($url) { public static function is_site_url($url) {
$urlHost = parse_url($url, PHP_URL_HOST); $urlHost = parse_url($url, PHP_URL_HOST);
@ -795,6 +834,7 @@ class Director implements TemplateGlobalProvider {
* Takes a $_SERVER data array and extracts HTTP request headers. * Takes a $_SERVER data array and extracts HTTP request headers.
* *
* @param array $server * @param array $server
*
* @return array * @return array
*/ */
public static function extract_request_headers(array $server) { public static function extract_request_headers(array $server) {
@ -819,6 +859,7 @@ class Director implements TemplateGlobalProvider {
* Given a filesystem reference relative to the site root, return the full file-system path. * Given a filesystem reference relative to the site root, return the full file-system path.
* *
* @param string $file * @param string $file
*
* @return string * @return string
*/ */
public static function getAbsFile($file) { public static function getAbsFile($file) {
@ -826,8 +867,11 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns true if the given file exists. * Returns true if the given file exists. Filename should be relative to the site root.
* @param $file Filename specified relative to the site root *
* @param $file
*
* @return bool
*/ */
public static function fileExists($file) { public static function fileExists($file) {
// replace any appended query-strings, e.g. /path/to/foo.php?bar=1 to /path/to/foo.php // replace any appended query-strings, e.g. /path/to/foo.php?bar=1 to /path/to/foo.php
@ -848,7 +892,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns the Absolute URL of the site root, embedding the current basic-auth credentials into the URL. * Returns the Absolute URL of the site root, embedding the current basic-auth credentials into
* the URL.
*
* @return string
*/ */
public static function absoluteBaseURLWithAuth() { public static function absoluteBaseURLWithAuth() {
$s = ""; $s = "";
@ -862,7 +909,7 @@ class Director implements TemplateGlobalProvider {
/** /**
* Skip any further processing and immediately respond with a redirect to the passed URL. * Skip any further processing and immediately respond with a redirect to the passed URL.
* *
* @param string $destURL - The URL to redirect to * @param string $destURL
*/ */
protected static function force_redirect($destURL) { protected static function force_redirect($destURL) {
$response = new SS_HTTPResponse(); $response = new SS_HTTPResponse();
@ -895,15 +942,16 @@ class Director implements TemplateGlobalProvider {
* if(Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/'), 'secure.mysite.com'); * if(Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/'), 'secure.mysite.com');
* </code> * </code>
* *
* Note that the session data will be lost when moving from HTTP to HTTPS. * Note that the session data will be lost when moving from HTTP to HTTPS. It is your responsibility
* It is your responsibility to ensure that this won't cause usability problems. * to ensure that this won't cause usability problems.
* *
* CAUTION: This does not respect the site environment mode. You should check this * CAUTION: This does not respect the site environment mode. You should check this
* as per the above examples using Director::isLive() or Director::isTest() for example. * as per the above examples using Director::isLive() or Director::isTest() for example.
* *
* @param array $patterns Array of regex patterns to match URLs that should be HTTPS * @param array $patterns Array of regex patterns to match URLs that should be HTTPS.
* @param string $secureDomain Secure domain to redirect to. Defaults to the current domain * @param string $secureDomain Secure domain to redirect to. Defaults to the current domain.
* @return boolean|string String of URL when unit tests running, boolean FALSE if patterns don't match request URI *
* @return bool|string String of URL when unit tests running, boolean FALSE if patterns don't match request URI.
*/ */
public static function forceSSL($patterns = null, $secureDomain = null) { public static function forceSSL($patterns = null, $secureDomain = null) {
if(!isset($_SERVER['REQUEST_URI'])) return false; if(!isset($_SERVER['REQUEST_URI'])) return false;
@ -963,11 +1011,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Checks if the current HTTP-Request is an "Ajax-Request" * Checks if the current HTTP-Request is an "Ajax-Request" by checking for a custom header set by
* by checking for a custom header set by jQuery or * jQuery or whether a manually set request-parameter 'ajax' is present.
* wether a manually set request-parameter 'ajax' is present.
* *
* @return boolean * @return bool
*/ */
public static function is_ajax() { public static function is_ajax() {
if(Controller::has_curr()) { if(Controller::has_curr()) {
@ -981,50 +1028,50 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Returns true if this script is being run from the command line rather than the webserver. * Returns true if this script is being run from the command line rather than the web server.
* *
* @return boolean * @return bool
*/ */
public static function is_cli() { public static function is_cli() {
return (php_sapi_name() == "cli"); return (php_sapi_name() == "cli");
} }
////////////////////////////////////////////////////////////////////////////////////////////
// Environment type methods
////////////////////////////////////////////////////////////////////////////////////////////
/** /**
* Set the environment type of the current site. * Set the environment type of the current site.
* *
* Typically, a SilverStripe site have a number of environments: * Typically, a SilverStripe site have a number of environments:
* - development environments, such a copy on your local machine. * - Development environments, such a copy on your local machine.
* - test sites, such as the one you show the client before going live. * - Test sites, such as the one you show the client before going live.
* - the live site itself. * - The live site itself.
* *
* The behaviour of these environments often varies slightly. For example, development sites may have errors * The behaviour of these environments often varies slightly. For example, development sites may
* dumped to the screen, and order confirmation emails might be sent to the developer instead of the client. * have errors dumped to the screen, and order confirmation emails might be sent to the developer
* instead of the client.
* *
* To help with this, SilverStripe supports the notion of an environment type. The environment type can be dev, * To help with this, SilverStripe supports the notion of an environment type. The environment
* test, or live. * type can be dev, test, or live.
* *
* You can set it explicitly with Director::set_environment_tpye(). Or you can use * You can set it explicitly with {@link Director::set_environment_type()}. Or you can use
* {@link Director::$dev_servers} and {@link Director::$test_servers} to set it implicitly, based on the * {@link Director::$dev_servers} and {@link Director::$test_servers} to set it implicitly, based
* value of $_SERVER['HTTP_HOST']. If the HTTP_HOST value is one of the servers listed, then the environment type * on the value of $_SERVER['HTTP_HOST']. If the HTTP_HOST value is one of the servers listed,
* will be test or dev. Otherwise, the environment type will be live. * then the environment type will be test or dev. Otherwise, the environment type will be live.
* *
* Dev mode can also be forced by putting ?isDev=1 in your URL, which will ask you to log in and then push the * Dev mode can also be forced by putting ?isDev=1 in your URL, which will ask you to log in and
* site into dev mode for the remainder of the session. Putting ?isDev=0 onto the URL can turn it back. * then push the site into dev mode for the remainder of the session. Putting ?isDev=0 onto the URL
* can turn it back.
* *
* Test mode can also be forced by putting ?isTest=1 in your URL, which will ask you to log in and then push the * Test mode can also be forced by putting ?isTest=1 in your URL, which will ask you to log in and
* site into test mode for the remainder of the session. Putting ?isTest=0 onto the URL can turn it back. * then push the site into test mode for the remainder of the session. Putting ?isTest=0 onto the URL
* can turn it back.
* *
* Generally speaking, these methods will be called from your _config.php file. * Generally speaking, these methods will be called from your _config.php file.
* *
* Once the environment type is set, it can be checked with {@link Director::isDev()}, {@link Director::isTest()}, * Once the environment type is set, it can be checked with {@link Director::isDev()},
* and {@link Director::isLive()}. * {@link Director::isTest()}, and {@link Director::isLive()}.
* *
* @deprecated 4.0 Use the "Director.environment_type" config setting instead * @deprecated 4.0 Use the "Director.environment_type" config setting instead
* @param $et string The environment type: dev, test, or live. *
* @param $et string
*/ */
public static function set_environment_type($et) { public static function set_environment_type($et) {
if($et != 'dev' && $et != 'test' && $et != 'live') { if($et != 'dev' && $et != 'test' && $et != 'live') {
@ -1037,9 +1084,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Can also be checked with {@link Director::isDev()}, {@link Director::isTest()}, and {@link Director::isLive()}. * Can also be checked with {@link Director::isDev()}, {@link Director::isTest()}, and
* {@link Director::isLive()}.
* *
* @return string 'dev', 'test' or 'live' * @return bool|string
*/ */
public static function get_environment_type() { public static function get_environment_type() {
if(Director::isLive()) { if(Director::isLive()) {
@ -1053,17 +1101,21 @@ class Director implements TemplateGlobalProvider {
} }
} }
/* /**
* This function will return true if the site is in a live environment. * This function will return true if the site is in a live environment. For information about
* For information about environment types, see {@link Director::set_environment_type()}. * environment types, see {@link Director::set_environment_type()}.
*
* @return bool
*/ */
public static function isLive() { public static function isLive() {
return !(Director::isDev() || Director::isTest()); return !(Director::isDev() || Director::isTest());
} }
/** /**
* This function will return true if the site is in a development environment. * This function will return true if the site is in a development environment. For information about
* For information about environment types, see {@link Director::set_environment_type()}. * environment types, see {@link Director::set_environment_type()}.
*
* @return bool
*/ */
public static function isDev() { public static function isDev() {
// Check session // Check session
@ -1082,8 +1134,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* This function will return true if the site is in a test environment. * This function will return true if the site is in a test environment. For information about
* For information about environment types, see {@link Director::set_environment_type()}. * environment types, see {@link Director::set_environment_type()}.
*
* @return bool
*/ */
public static function isTest() { public static function isTest() {
// In case of isDev and isTest both being set, dev has higher priority // In case of isDev and isTest both being set, dev has higher priority
@ -1105,9 +1159,9 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* Check or update any temporary environment specified in the session * Check or update any temporary environment specified in the session.
* *
* @return string 'test', 'dev', or null * @return null|string
*/ */
protected static function session_environment() { protected static function session_environment() {
// Set session from querystring // Set session from querystring
@ -1135,8 +1189,10 @@ class Director implements TemplateGlobalProvider {
} }
/** /**
* @return array Returns an array of strings of the method names of methods on the call that should be exposed * Returns an array of strings of the method names of methods on the call that should be exposed
* as global variables in the templates. * as global variables in the templates.
*
* @return array
*/ */
public static function get_template_global_variables() { public static function get_template_global_variables() {
return array( return array(

View File

@ -3,10 +3,20 @@
* Triggers a call to flush() on all implementors of Flushable. * Triggers a call to flush() on all implementors of Flushable.
* *
* @package framework * @package framework
*
* @subpackage control * @subpackage control
*/ */
class FlushRequestFilter implements RequestFilter { class FlushRequestFilter implements RequestFilter {
/**
* @inheritdoc
*
* @param SS_HTTPRequest $request
* @param Session $session
* @param DataModel $model
*
* @return bool
*/
public function preRequest(SS_HTTPRequest $request, Session $session, DataModel $model) { public function preRequest(SS_HTTPRequest $request, Session $session, DataModel $model) {
if(array_key_exists('flush', $request->getVars())) { if(array_key_exists('flush', $request->getVars())) {
foreach(ClassInfo::implementorsOf('Flushable') as $class) { foreach(ClassInfo::implementorsOf('Flushable') as $class) {
@ -17,6 +27,15 @@ class FlushRequestFilter implements RequestFilter {
return true; return true;
} }
/**
* @inheritdoc
*
* @param SS_HTTPRequest $request
* @param SS_HTTPResponse $response
* @param DataModel $model
*
* @return bool
*/
public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model) { public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model) {
return true; return true;
} }

View File

@ -1,39 +1,42 @@
<?php <?php
/** /**
* A class with HTTP-related helpers. * A class with HTTP-related helpers. Like Debug, this is more a bundle of methods than a class.
* Like Debug, this is more a bundle of methods than a class ;-)
* *
* @package framework * @package framework
*
* @subpackage misc * @subpackage misc
*/ */
class HTTP { class HTTP {
/** /**
* @var int $cache_age * @var int
*/ */
protected static $cache_age = 0; protected static $cache_age = 0;
/** /**
* @var timestamp $modification_date * @var int
*/ */
protected static $modification_date = null; protected static $modification_date = null;
/** /**
* @var string $etag * @var string
*/ */
protected static $etag = null; protected static $etag = null;
/** /**
* @config * @config
*
* @var bool
*/ */
private static $cache_ajax_requests = true; private static $cache_ajax_requests = true;
/** /**
* Turns a local system filename into a URL by comparing it to the script * Turns a local system filename into a URL by comparing it to the script filename.
* filename.
* *
* @param string * @param string $filename
*
* @return string
*/ */
public static function filename2url($filename) { public static function filename2url($filename) {
$slashPos = -1; $slashPos = -1;
@ -62,7 +65,11 @@ class HTTP {
} }
/** /**
* Turn all relative URLs in the content to absolute URLs * Turn all relative URLs in the content to absolute URLs.
*
* @param string $html
*
* @return string
*/ */
public static function absoluteURLs($html) { public static function absoluteURLs($html) {
$html = str_replace('$CurrentPageURL', $_SERVER['REQUEST_URI'], $html); $html = str_replace('$CurrentPageURL', $_SERVER['REQUEST_URI'], $html);
@ -78,28 +85,26 @@ class HTTP {
/** /**
* Rewrite all the URLs in the given content, evaluating the given string as PHP code. * Rewrite all the URLs in the given content, evaluating the given string as PHP code.
* *
* Put $URL where you want the URL to appear, however, you can't embed $URL in strings * Put $URL where you want the URL to appear, however, you can't embed $URL in strings, for example:
* Some example code:
* <ul> * <ul>
* <li><code>'"../../" . $URL'</code></li> * <li><code>'"../../" . $URL'</code></li>
* <li><code>'myRewriter($URL)'</code></li> * <li><code>'myRewriter($URL)'</code></li>
* <li><code>'(substr($URL, 0, 1)=="/") ? "../" . substr($URL, 1) : $URL'</code></li> * <li><code>'(substr($URL, 0, 1)=="/") ? "../" . substr($URL, 1) : $URL'</code></li>
* </ul> * </ul>
* *
* As of 3.2 $code should be a callable which takes a single parameter and returns * As of 3.2 $code should be a callable which takes a single parameter and returns the rewritten,
* the rewritten URL. e.g. * for example:
*
* <code> * <code>
* function($url) { * function($url) {
* return Director::absoluteURL($url, true); * return Director::absoluteURL($url, true);
* } * }
* </code> * </code>
* *
* @param string $content The HTML to search for links to rewrite * @param string $content The HTML to search for links to rewrite.
* @param string|callable $code Either a string that can evaluate to an expression * @param string|callable $code Either a string that can evaluate to an expression to rewrite links
* to rewrite links (depreciated), or a callable that takes a single * (depreciated), or a callable that takes a single parameter and returns the rewritten URL.
* parameter and returns the rewritten URL *
* @return The content with all links rewritten as per the logic specified in $code * @return The content with all links rewritten as per the logic specified in $code.
*/ */
public static function urlRewriter($content, $code) { public static function urlRewriter($content, $code) {
if(!is_callable($code)) { if(!is_callable($code)) {
@ -146,23 +151,21 @@ class HTTP {
} }
/** /**
* Will try to include a GET parameter for an existing URL, * Will try to include a GET parameter for an existing URL, preserving existing parameters and
* preserving existing parameters and fragments. * fragments. If no URL is given, falls back to $_SERVER['REQUEST_URI']. Uses parse_url() to
* If no URL is given, falls back to $_SERVER['REQUEST_URI']. * dissect the URL, and http_build_query() to reconstruct it with the additional parameter.
* Uses parse_url() to dissect the URL, and http_build_query() to reconstruct it * Converts any '&' (ampersand) URL parameter separators to the more XHTML compliant '&amp;'.
* with the additional parameter. Converts any '&' (ampersand)
* URL parameter separators to the more XHTML compliant '&amp;'.
* *
* CAUTION: If the URL is determined to be relative, * CAUTION: If the URL is determined to be relative, it is prepended with Director::absoluteBaseURL().
* it is prepended with Director::absoluteBaseURL(). * This method will always return an absolute URL because Director::makeRelative() can lead to
* This method will always return an absolute URL because * inconsistent results.
* Director::makeRelative() can lead to inconsistent results.
* *
* @param string $varname * @param string $varname
* @param string $varvalue * @param string $varvalue
* @param string $currentURL Relative or absolute URL (Optional). * @param string $currentURL Relative or absolute URL.
* @param string $separator Separator for http_build_query(). (Optional). * @param string $separator Separator for http_build_query().
* @return string Absolute URL *
* @return string
*/ */
public static function setGetVar($varname, $varvalue, $currentURL = null, $separator = '&amp;') { public static function setGetVar($varname, $varvalue, $currentURL = null, $separator = '&amp;') {
$uri = $currentURL ? $currentURL : Director::makeRelative($_SERVER['REQUEST_URI']); $uri = $currentURL ? $currentURL : Director::makeRelative($_SERVER['REQUEST_URI']);
@ -212,16 +215,25 @@ class HTTP {
return $newUri; return $newUri;
} }
/**
* @param string $varname
* @param string $varvalue
* @param null|string $currentURL
*
* @return string
*/
public static function RAW_setGetVar($varname, $varvalue, $currentURL = null) { public static function RAW_setGetVar($varname, $varvalue, $currentURL = null) {
$url = self::setGetVar($varname, $varvalue, $currentURL); $url = self::setGetVar($varname, $varvalue, $currentURL);
return Convert::xml2raw($url); return Convert::xml2raw($url);
} }
/** /**
* Search for all tags with a specific attribute, then return the value of that attribute in a flat array. * Search for all tags with a specific attribute, then return the value of that attribute in a
* flat array.
* *
* @param string $content * @param string $content
* @param array $attributes an array of tags to attributes, for example "[a] => 'href', [div] => 'id'" * @param array $attributes An array of tags to attributes, for example "[a] => 'href', [div] => 'id'"
*
* @return array * @return array
*/ */
public static function findByTagAndAttribute($content, $attributes) { public static function findByTagAndAttribute($content, $attributes) {
@ -243,23 +255,32 @@ class HTTP {
return count($result) ? $result : null; return count($result) ? $result : null;
} }
/**
* @param string $content
*
* @return array
*/
public static function getLinksIn($content) { public static function getLinksIn($content) {
return self::findByTagAndAttribute($content, array("a" => "href")); return self::findByTagAndAttribute($content, array("a" => "href"));
} }
/**
* @param string $content
*
* @return array
*/
public static function getImagesIn($content) { public static function getImagesIn($content) {
return self::findByTagAndAttribute($content, array("img" => "src")); return self::findByTagAndAttribute($content, array("img" => "src"));
} }
/** /**
* Get the MIME type based on a file's extension. * Get the MIME type based on a file's extension. If the finfo class exists in PHP, and the file
* exists relative to the project root, then use that extension, otherwise fallback to a list of
* commonly known MIME types.
* *
* If the finfo class exists in PHP, and the file actually exists, then use that * @param string $filename
* extension, otherwise fallback to a list of commonly known MIME types.
* *
* @uses finfo * @return string
* @param string $filename Relative path to filename from project root, e.g. "mysite/tests/file.csv"
* @return string MIME type
*/ */
public static function get_mime_type($filename) { public static function get_mime_type($filename) {
// If the finfo module is compiled into PHP, use it. // If the finfo module is compiled into PHP, use it.
@ -284,23 +305,34 @@ class HTTP {
} }
/** /**
* Set the maximum age of this page in web caches, in seconds * Set the maximum age of this page in web caches, in seconds.
*
* @param int $age
*/ */
public static function set_cache_age($age) { public static function set_cache_age($age) {
self::$cache_age = $age; self::$cache_age = $age;
} }
/**
* @param string $dateString
*/
public static function register_modification_date($dateString) { public static function register_modification_date($dateString) {
$timestamp = strtotime($dateString); $timestamp = strtotime($dateString);
if($timestamp > self::$modification_date) if($timestamp > self::$modification_date)
self::$modification_date = $timestamp; self::$modification_date = $timestamp;
} }
/**
* @param int $timestamp
*/
public static function register_modification_timestamp($timestamp) { public static function register_modification_timestamp($timestamp) {
if($timestamp > self::$modification_date) if($timestamp > self::$modification_date)
self::$modification_date = $timestamp; self::$modification_date = $timestamp;
} }
/**
* @param string $etag
*/
public static function register_etag($etag) { public static function register_etag($etag) {
self::$etag = $etag; self::$etag = $etag;
} }
@ -309,10 +341,13 @@ class HTTP {
* Add the appropriate caching headers to the response, including If-Modified-Since / 304 handling. * Add the appropriate caching headers to the response, including If-Modified-Since / 304 handling.
* Note that setting HTTP::$cache_age will overrule any cache headers set by PHP's * Note that setting HTTP::$cache_age will overrule any cache headers set by PHP's
* session_cache_limiter functionality. It is your responsibility to ensure only cacheable data * session_cache_limiter functionality. It is your responsibility to ensure only cacheable data
* is in fact cached, and HTTP::$cache_age isn't set when the HTTP body contains session-specific content. * is in fact cached, and HTTP::$cache_age isn't set when the HTTP body contains session-specific
* content.
* *
* @param SS_HTTPResponse $body The SS_HTTPResponse object to augment. Omitted the argument or passing a string is * Omitting the $body argument or passing a string is deprecated; in these cases, the headers are
* deprecated; in these cases, the headers are output directly. * output directly.
*
* @param SS_HTTPResponse $body
*/ */
public static function add_cache_headers($body = null) { public static function add_cache_headers($body = null) {
$cacheAge = self::$cache_age; $cacheAge = self::$cache_age;
@ -461,16 +496,21 @@ class HTTP {
/** /**
* Return an {@link http://www.faqs.org/rfcs/rfc2822 RFC 2822} date in the * Return an {@link http://www.faqs.org/rfcs/rfc2822 RFC 2822} date in the GMT timezone (a timestamp
* GMT timezone (a timestamp is always in GMT: the number of seconds * is always in GMT: the number of seconds since January 1 1970 00:00:00 GMT)
* since January 1 1970 00:00:00 GMT) *
* @param int $timestamp
*
* @return string
*/ */
public static function gmt_date($timestamp) { public static function gmt_date($timestamp) {
return gmdate('D, d M Y H:i:s', $timestamp) . ' GMT'; return gmdate('D, d M Y H:i:s', $timestamp) . ' GMT';
} }
/* /**
* Return static variable cache_age in second * Return static variable cache_age in second
*
* @return int
*/ */
public static function get_cache_age() { public static function get_cache_age() {
return self::$cache_age; return self::$cache_age;