Versions:

Execution Pipeline

Introduction

In order to transform a HTTP request or a commandline exeuction into a response, SilverStripe needs to boot its core and run through several stages of processing.

Request Rewriting

The first step in most environments is a rewrite of a request path into parameters passed to a PHP script. This allows writing friendly URLs instead of linking directly to PHP files. The implementation depends on your web server; we'll show you the most common one here: Apache with mod_rewrite. Check our installation guides on how other web servers like IIS or nginx handle rewriting.

The standard SilverStripe project ships with a .htaccess file in your webroot for this purpose. By default, requests will be passed through for files existing on the filesystem. Some access control is in place to deny access to potentially sensitive files in the webroot, such as YAML configuration files. If no file can be directly matched, control is handed off to framework/main.php.

### SILVERSTRIPE START ###

# Deny access to templates (but allow from localhost)
<Files *.ss>
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Files>

# Deny access to IIS configuration
<Files web.config>
    Order deny,allow
    Deny from all
</Files>

# Deny access to YAML configuration files which might include sensitive information
<Files ~ "\.ya?ml$">
    Order allow,deny
    Deny from all
</Files>

# Route errors to static pages automatically generated by SilverStripe
ErrorDocument 404 /assets/error-404.html
ErrorDocument 500 /assets/error-500.html

<IfModule mod_rewrite.c>
    SetEnv HTTP_MOD_REWRITE On
    RewriteEngine On

    # Deny access to potentially sensitive files and folders
    RewriteRule ^vendor(/|$) - [F,L,NC]
    RewriteRule silverstripe-cache(/|$) - [F,L,NC]
    RewriteRule composer\.(json|lock) - [F,L,NC]

    # Process through SilverStripe if no file with the requested name exists.
    # Pass through the original path as a query parameter, and retain the existing parameters.
    RewriteCond %{REQUEST_URI} ^(.*)$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* framework/main.php?url=%1 [QSA]

    # If requesting the main script directly, rewrite to the installer
    RewriteCond %{REQUEST_URI} ^(.*)/framework/main.php$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule . %1/install.php? [R,L]

</IfModule>
### SILVERSTRIPE END ###

SilverStripe can also operate without this level of rewriting, in which case all dynamic requests go through an index.php script in the webroot.

Running SilverStripe without web server based rewriting is not recommended since it can leave sensitive files exposed to public access (the RewriteRule conditions from above don't apply).

Bootstrap

All requests go through framework/main.php, which sets up the execution environment:

  • Tries to locate an _ss_environment.php configuration file in the webroot, or the two levels above it (to allow sharing configuration between multiple webroots).
  • Sets constants based on the filesystem structure (e.g. BASE_URL, BASE_PATH and TEMP_FOLDER)
  • Normalizes the url parameter in preparation for handing it off to Director
  • Connects to a database, based on information stored in the global $databaseConfig variable. The configuration is either defined in your _config.php, or through _ss_environment.php
  • Sets up error handlers
  • Optionally continues a session if the request already contains a session identifier
  • Loads manifests for PHP classes, templates, as well as any YAML configuration.
  • Optionally regenerates these manifests (if a "flush" query parameter is set)
  • Executes all procedural configuration defined through _config.php in all discovered modules
  • Loads the Composer PHP class autoloader
  • Hands control over to Director

While you usually don't need to modify the bootstrap on this level, some deeper customizations like adding your own manifests or a performance-optimized routing might require it. An example of this can be found in the "staticpublisher" module. The modules instructs web servers to route through its own main.php to determine which requests can be cached before handing control off to SilverStripe's own main.php.

Routing and Request Handling

The main.php script relies on Director to work out which controller should handle this request. It parses the URL, matching it to one of a number of patterns, and determines the controller, action and any argument to be used (Routing).

  • Creates a SS_HTTPRequest object containing all request and environment information
  • The session holds an abstraction of PHP session
  • Instantiates a controller object
  • The Injector is first referenced, and asks the registered RequestFilter to pre-process the request object (see below)
  • The Controller executes the actual business logic and populates an SS_HTTPResponse
  • The Controller can optionally hand off control to further nested controllers
  • The Controller optionally renders a response body through SSViewer templates
  • The RequestProcessor is called to post-process the request to allow further filtering before content is sent to the end user
  • The response is output to the client

Request Preprocessing and Postprocessing

The framework provides the ability to hook into the request both before and after it is handled to allow binding custom logic. This can be used to transform or filter request data, instantiate helpers, execute global logic, or even short-circuit execution (e.g. to enforce custom authentication schemes). The "Request Filters" documentation shows you how.

Flushing Manifests

If a ?flush=1 query parameter is added to a URL, a call to flush() will be triggered on any classes that implement the Flushable interface. This enables developers to clear manifest caches, for example when adding new templates or PHP classes. Note that you need to be in dev mode or logged-in as an administrator for flushing to take effect.

  • Flushable

    Allows a class to define it's own flush functionality.

  • Manifests

    Manage caches of file path maps and other expensive information