Compare commits

...

23 Commits

Author SHA1 Message Date
Abel Hoogeveen 58e885e35f Added the setLocation() method for Output.
Useful for redirecting the user to a different page and automatically setting the correct status header.
2023-02-14 14:55:46 +01:00
Abel Hoogeveen d6863d3f51 Merge pull request 'Fixed bug #3 which caused xss_clean() to fail when calling input variables from arrays.' (#5) from fix/3 into master
Reviewed-on: #5
2022-12-06 11:19:05 +00:00
Abel Hoogeveen 22e3ec2fd0 Fixed bug #3 which caused xss_clean() to fail when calling input variables from arrays.
Closes #3.
2022-12-06 12:18:13 +01:00
Abel Hoogeveen d66c244931
Merge branch 'master' of ssh://gitea.i15.nl:7070/FuzeWorks/WebComponent 2022-03-15 19:24:47 +01:00
Abel Hoogeveen 0e2eb5ef72
`config.web.php` already provides a prefix, so `config.security` should not provide one.
Can be merged later whenever necessary.

Also verifies if the protection is enabled or not.
2022-03-15 19:24:29 +01:00
Abel Hoogeveen 3c7011eddb
`config.web.php` already provides a prefix, so `config.security` should not provide one.
Can be merged later whenever necessary.
2022-03-15 19:18:45 +01:00
Abel Hoogeveen cd331dc39d
Stop lowering cache permissions.
- Temporary solution until ObjectStorage is implemented here.
2021-11-30 11:33:18 +01:00
Abel Hoogeveen 444f614c48
Updated compatibility of WebComponent.
- Now uses latest libraries of FuzeWorks.
2021-11-29 22:47:45 +01:00
Abel Hoogeveen af25072b24
Upgraded dependencies and upped the LICENSE. 2021-01-25 12:21:41 +01:00
Abel Hoogeveen d7b2c40c57
Fixed Resources being unable to serve static files when using more complicated URI's. 2020-08-02 11:12:51 +02:00
Abel Hoogeveen e3485fa256 Separated events into methods so they can be properly logged by Core. 2020-07-12 12:02:43 +02:00
Abel Hoogeveen c09d1a35d5 Fixed CSRF-null bug
A bug caused FuzeWorks instances to crash when CSRF protection was disabled.

This was fixed by allowing the method to return null as well.
2020-04-02 20:37:23 +02:00
Abel Hoogeveen b976dbeae3
Implemented HTTP->HTTPS redirect and fixed a bug with Output where a 500 is raised when no output is created. 2019-12-20 11:11:22 +01:00
Abel Hoogeveen 1180445dcc
Changed output cache to include GET parameters as cache key.
This allows more dynamic pages to cache pages based on the exact request.
2019-11-16 11:41:44 +01:00
Abel Hoogeveen 74cb630d80
Fixed bug causing a header warning.
By default, FuzeWorks\Layout doesn't redirect it's display output to FuzeWorks\Output. If this is desired behaviour the layoutDisplayEvent needs to be interrupted. This eventListener was not implemented, resulting in FuzeWorks\Layout::display output not being redirected.

This patch fixes that.
2019-11-06 00:19:33 +01:00
Abel Hoogeveen 0ba98f8130 Merge branch 'development' into 'master'
Release 1.2.0

See merge request fuzeworks/webcomponent!2
2019-09-21 18:28:47 +00:00
Abel Hoogeveen ddbc787c45
Release 1.2.0 2019-09-21 20:28:03 +02:00
Abel Hoogeveen 35df988200
Release 1.2.0-RC5 2019-09-18 00:21:03 +02:00
Abel Hoogeveen a04293d8b4
Fixed bug resulting in exception on every request. 2019-09-17 22:13:56 +02:00
Abel Hoogeveen cf8315e06b Merge branch 'holiday-branch' into 'development'
Release 1.2.0-RC4

See merge request fuzeworks/webcomponent!1
2019-08-21 17:50:54 +00:00
Abel Hoogeveen fd531b53e2
Released 1.2.0-RC4 2019-08-21 19:49:45 +02:00
Abel Hoogeveen 7c77c339cf Implemented Resources.
Resources are static files which have to be served by FuzeWorks. The developer can register a directory in which static files can be found, which shall be loaded if the folder is requested.
This system should be avoided for high-performance applications. It is recommended to make special configurations in the web server in those kinds of cases.
2019-07-22 19:53:18 +02:00
Abel Hoogeveen 612ab3abca Implemented the RouteWebRequestEvent and sessions.
- Developers can now use the RouteWebRequestEvent to cancel the loading of web requests
- FuzeWorks\Input now starts the PHP session, which is required for some dependencies
2019-07-22 11:48:45 +02:00
12 changed files with 494 additions and 65 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2013-2021 TechFuze
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -4,28 +4,23 @@
"license": ["MIT"],
"authors": [
{
"name": "TechFuze",
"homepage": "https://techfuze.net"
},
{
"name": "FuzeWorks Community",
"homepage": "https://techfuze.net/fuzeworks/contributors"
"name": "Abel Hoogeveen",
"homepage": "https://i15.nl"
}
],
"require": {
"php": ">=7.1.0",
"fuzeworks/mvcr": "1.2.0-RC3",
"fuzeworks/core": "1.2.0-RC3"
"php": ">=8.1.0",
"fuzeworks/core": "~1.3.0",
"fuzeworks/mvcr": "~1.3.0",
"fuzeworks/objectstorage": "~1.3.0"
},
"minimum-stability": "RC",
"prefer-stable": true,
"require-dev": {
"phpunit/phpunit": "^7"
"fuzeworks/layout": "~1.3.0",
"fuzeworks/tracycomponent": "~1.3.0"
},
"autoload": {
"psr-4": {
"FuzeWorks\\": "src/FuzeWorks/"
}
}
}

View File

@ -50,12 +50,12 @@ return [
| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
*/
'csrf_protection' => true,
'csrf_token_name' => 'fw_csrf_token',
'csrf_token_name' => 'csrf_token',
'csrf_expire' => 7200,
'csrf_exclude_uris' => array(),
// CSRF Cookie information
'csrf_cookie_name' => 'fw_csrf_cookie',
'csrf_cookie_name' => 'csrf_cookie',
'csrf_cookie_prefix' => '',
'csrf_cookie_domain' => '',
'csrf_cookie_path' => '/',

View File

@ -34,13 +34,35 @@
* @version Version 1.2.0
*/
return [
'allow_get_input' => true,
'empty_global_arrays' => true,
'restore_global_arrays' => true,
// General
'base_url' => '',
'serverName' => 'FuzeWorks',
// Whether to allow GET parameters
'allow_get_input' => true,
// Clears the global $_GET, $_POST, $_COOKIE and $_SERVER arrays in order to prevent misuse
'empty_global_arrays' => true,
// Whether to restore the $_GET, $_POST, $_COOKIE and $_SERVER arrays when FuzeWorks shuts down
'restore_global_arrays' => true,
'permitted_uri_chars' => 'a-z 0-9~%.:_\-',
'charset' => 'UTF-8',
// Whether to redirect http traffic to https
'redirect_to_https' => false,
// Whether to gzip the output when the client supports it
'compress_output' => false,
// Global switch for output cache. To use, must be enabled in view as well
'cache_output' => true,
'xss_clean' => true,
// Cookie settings
'cookie_prefix' => 'FWZ_',
'xss_clean' => true
'cookie_domain' => '',
'cookie_path' => '/',
'cookie_secure' => false,
'cookie_httponly' => false
];

View File

@ -0,0 +1,63 @@
<?php
/**
* FuzeWorks WebComponent.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 1.2.0
*
* @version Version 1.2.0
*/
namespace FuzeWorks\Event;
use FuzeWorks\Event;
class ResourceServeEvent extends Event
{
/**
* @var string
*/
public $resourceName;
/**
* @var array
*/
public $requestURL;
/**
* @var string
*/
public $resourceFilePath;
public function init(string $resourceName, string $requestURL, string $resourceFilePath)
{
$this->resourceName = $resourceName;
$this->requestURL = $requestURL;
$this->resourceFilePath = $resourceFilePath;
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* FuzeWorks WebComponent.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 1.2.0
*
* @version Version 1.2.0
*/
namespace FuzeWorks\Event;
use FuzeWorks\Event;
class RouteWebRequestEvent extends Event
{
/**
* @var string
*/
public $uriString;
public function init(string $uriString)
{
$this->uriString = $uriString;
}
}

View File

@ -75,6 +75,9 @@ class Input
if (!WebComponent::$willHandleRequest)
return;
// Start session
session_start();
// Sanitize all global arrays
$this->sanitizeGlobals();
@ -324,7 +327,6 @@ class Input
/**
* Fetch the HTTP_USER_AGENT variable from the $_SERVER array
*
* @param string|array|null $index
* @param bool $xssClean
* @return mixed
*/
@ -336,7 +338,6 @@ class Input
/**
* Fetch the REQUEST_METHOD variable from the $_SERVER array
*
* @param string|array|null $index
* @param bool $xssClean
* @return mixed
*/

View File

@ -145,7 +145,7 @@ class Output
$output = is_null($output) ? $this->output : $output;
// Write cache if requested to do so
if ($this->cacheTime > 0)
if ($this->cacheTime > 0 && !is_null($output))
$this->writeCache($output);
// First send status code
@ -201,18 +201,22 @@ class Output
public function getCache(string $selector): bool
{
// If empty, index page is requested
$selector = empty($selector) ? 'index' : $selector;
// If output cache is disabled, don't return a cache result
if ($this->config->get('cache_output') !== true)
return false;
// Generate the full uri
$uri = $this->config->get('base_url') . $selector;
$uri = $this->config->get('base_url') . (empty($selector) ? 'index' : $selector);
$getParams = $this->input->get();
// Determine the identifier
$identier = md5($uri . '|' . serialize($getParams));
// Determine the file that holds the cache
if ($this->compressOutput)
$file = Core::$tempDir . DS . 'OutputCache' . DS . md5($uri) . '_gzip.fwcache';
$file = Core::$tempDir . DS . 'OutputCache' . DS . $identier . '_gzip.fwcache';
else
$file = Core::$tempDir . DS . 'OutputCache' . DS . md5($uri) . '.fwcache';
$file = Core::$tempDir . DS . 'OutputCache' . DS . $identier . '.fwcache';
// Determine if file exists
if (!file_exists($file))
@ -259,6 +263,10 @@ class Output
public function writeCache(string $output)
{
// If output cache is disabled, don't create a cache entry
if ($this->config->get('cache_output') !== true)
return false;
// First create cache directory
$cachePath = Core::$tempDir . DS . 'OutputCache';
@ -278,12 +286,16 @@ class Output
// Generate the full uri
$uri = $this->config->get('base_url') . (empty($this->uri->uriString()) ? 'index' : $this->uri->uriString());
$getParams = $this->input->get();
// Determine the identifier
$identifier = md5($uri . '|' . serialize($getParams));
// Determine the file that holds the cache
if ($this->compressOutput)
$file = $cachePath . DS . md5($uri) . '_gzip.fwcache';
$file = $cachePath . DS . $identifier . '_gzip.fwcache';
else
$file = $cachePath . DS . md5($uri) . '.fwcache';
$file = $cachePath . DS . $identifier . '.fwcache';
// If compression is enabled, compress the output
@ -314,9 +326,6 @@ class Output
return false;
}
// Lowering permissions to read only
chmod($cachePath, 0640);
// And report back
Logger::logInfo("Output cache has been saved.");
@ -513,4 +522,25 @@ class Output
}
}
/**
* Set the location to redirect the user to.
*
* @param string $locationUrl Should be prepended with /
* @param bool $permanent True for 301, false for 302 redirect.
* @return void
*/
public function setLocation(string $locationUrl, bool $permanent = false)
{
// Set the status header
if ($permanent)
$this->setStatusHeader(301);
else
$this->setStatusHeader(302);
// And the location itself
$header = 'Location: ' . $locationUrl;
$this->headers[] = [$header, true];
}
}

174
src/FuzeWorks/Resources.php Normal file
View File

@ -0,0 +1,174 @@
<?php
/**
* FuzeWorks WebComponent.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 1.2.0
*
* @version Version 1.2.0
*/
namespace FuzeWorks;
use FuzeWorks\Event\ResourceServeEvent;
use FuzeWorks\Exception\WebException;
/**
* FuzeWorks' handler for static resources.
*
* Objects in FuzeWorks can register a folder with static resources, which shall be served if requested by clients.
* This system should be avoided for high-performance applications. It is recommended to make special configurations in the web server
* in those kinds of cases.
*/
class Resources
{
private $resources = [];
/**
* @var Output
*/
private $output;
public function init()
{
$this->output = Factory::getInstance()->output;
}
public function resourceExists(string $requestURL): bool
{
// First find the resource
$file = $this->findResource($requestURL);
// If not found, return false;
if (is_null($file))
return false;
// If found, simply return true
return true;
}
/**
* Serves a static file if found.
*
* @param string $requestURL
* @return bool
* @throws WebException
*
* @todo Bypass the Output system and use the readFile() method.
* @todo Run as FuzeWorks pre-code, before creating the container
*/
public function serveResource(string $requestURL): bool
{
// First find the resource
$file = $this->findResource($requestURL);
// If not found return false
if (is_null($file))
return false;
// If a file is found, fire a serveResourceEvent
/** @var ResourceServeEvent $event */
try {
$event = Events::fireEvent('resourceServeEvent', $file['resourceName'], $file['requestURL'], $file['file']);
} catch (Exception\EventException $e) {
throw new WebException("Could not serve resource. resourceServeEvent threw exception: '" . $e->getMessage() . "'");
}
// If cancelled, don't serve
if ($event->isCancelled())
return false;
// Log the resource serving
Logger::log("Serving static resource '/" . $file['resourceName'] . '/' . $file['requestURL'] . "'");
// Serve file in accordance with event
$fileExtension = pathinfo($event->resourceFilePath, PATHINFO_EXTENSION);
$this->output->setContentType($fileExtension);
$this->output->setOutput(file_get_contents($event->resourceFilePath));
#readfile($event->resourceFilePath);
// And return true at the end
return true;
}
protected function findResource(string $requestURL): ?array
{
// First segment should be the resourceName, check if it exists
foreach ($this->resources as $resourceName => $resourceDir)
{
if (substr($requestURL, 0, strlen($resourceName)) === $resourceName)
{
$fileURL = ltrim(substr($requestURL, strlen($resourceName)), '/');
$fileURL = str_replace('/', DS, $fileURL);
$file = $this->resources[$resourceName] . DS . $fileURL;
// Test if file exists, if it does, return the string
if (file_exists($file) && is_file($file))
return ['file' => $file, 'resourceName' => $resourceName, 'requestURL' => $fileURL];
}
}
return null;
}
/**
* Register a resource which can be served statically.
*
* The resourceName will be the directory under which the files shall be served on the web server.
* The filePath is where FuzeWorks should look for the files.
*
* @param string $resourceName
* @param string $filePath
* @throws WebException
* @return bool
*/
public function registerResources(string $resourceName, string $filePath): bool
{
// First check if the resource already exists
$resourceName = urldecode($resourceName);
if (isset($this->resources[$resourceName]))
throw new WebException("Could not register resources. Resources with same name already exists.");
// Also check if the file path exists and is a directory
if (!file_exists($filePath) && !is_dir($filePath))
throw new WebException("Could not register resources. Provided filePath does not exist.");
// Add the resource
$this->resources[$resourceName] = $filePath;
// Log the registration
Logger::log("Adding static resources on: '/" . $resourceName . "'");
return true;
}
}

View File

@ -188,7 +188,7 @@ class Security {
$this->input = Factory::getInstance()->input;
// Is CSRF protection enabled?
if ($this->config->csrf_protection)
if ($this->config->get('csrf_protection'))
{
// CSRF config
foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
@ -222,6 +222,10 @@ class Security {
*/
public function csrf_verify(): self
{
// If not enabled, do not run
if (!$this->config->get('csrf_protection'))
return $this;
// If it's not a POST request we will set the CSRF cookie
if (strtoupper($this->input->server('REQUEST_METHOD')) !== 'POST')
return $this->csrf_set_cookie();
@ -320,7 +324,7 @@ class Security {
* @see Security::$_csrf_hash
* @return string CSRF hash
*/
public function get_csrf_hash(): string
public function get_csrf_hash(): ?string
{
return $this->_csrf_hash;
}
@ -371,10 +375,8 @@ class Security {
// Is the string an array?
if (is_array($str))
{
while (list($key) = each($str))
{
$str[$key] = $this->xss_clean($str[$key]);
}
foreach ($str as $key => $value)
$str[$key] = $this->xss_clean($value);
return $str;
}

View File

@ -60,8 +60,8 @@ class URI
private $input;
protected $baseUri;
protected $uriString;
protected $segments;
protected $uriString = '';
protected $segments = [];
public function init()
{

View File

@ -37,12 +37,15 @@
namespace FuzeWorks;
use FuzeWorks\Event\HaltExecutionEvent;
use FuzeWorks\Event\LayoutDisplayEvent;
use FuzeWorks\Event\LayoutLoadEvent;
use FuzeWorks\Event\RouterCallViewEvent;
use FuzeWorks\Event\RouterLoadViewAndControllerEvent;
use FuzeWorks\Event\RouteWebRequestEvent;
use FuzeWorks\Exception\ConfigException;
use FuzeWorks\Exception\CSRFException;
use FuzeWorks\Exception\EventException;
use FuzeWorks\Exception\Exception;
use FuzeWorks\Exception\FactoryException;
use FuzeWorks\Exception\HaltException;
use FuzeWorks\Exception\NotFoundException;
use FuzeWorks\Exception\OutputException;
@ -57,7 +60,7 @@ class WebComponent implements iComponent
*
* @var bool
*/
public static $willHandleRequest = false;
public static bool $willHandleRequest = false;
public function getName(): string
{
@ -72,6 +75,7 @@ class WebComponent implements iComponent
'input' => '\FuzeWorks\Input',
'output' => '\FuzeWorks\Output',
'uri' => '\FuzeWorks\URI',
'resources' => '\FuzeWorks\Resources'
];
}
@ -89,10 +93,8 @@ class WebComponent implements iComponent
// If WebComponent will handle a request, add some calls to the configurator
if (self::$willHandleRequest)
{
// Invoke methods to prepare system for HTTP calls
$configurator->call('logger', 'setLoggerTemplate', null, 'logger_http');
}
}
public function onCreateContainer(Factory $container)
@ -120,13 +122,44 @@ class WebComponent implements iComponent
}
/**
* Disable the WebComponent so it won't prepare for handling requests
* Disable the WebComponent, so it won't prepare for handling requests
*/
public function disableComponent()
{
self::$willHandleRequest = false;
}
public function shutdownEventListener(Event $event): Event
{
/** @var Output $output */
Logger::logInfo("Parsing output...");
$output = Factory::getInstance()->output;
$output->display();
return $event;
}
public function layoutDisplayEventListener(Event $event)
{
/** @var $event LayoutDisplayEvent */
/** @var Output $output */
$output = Factory::getInstance('output');
$output->appendOutput($event->contents);
$event->setCancelled(true);
}
public function routerLoadViewAndControllerEventListener(Event $event)
{
/** @var Input $input */
/** @var RouterLoadViewAndControllerEvent $event */
$input = Factory::getInstance('input');
$methods = $event->viewMethods[Priority::NORMAL];
foreach ($methods as $method)
$event->addMethod(strtolower($input->method()) . '_' . $method);
Logger::log("Added input method '" . $input->method() . "' as a prefix to view methods.");
return $event;
}
/**
* Handle a Web request.
*
@ -138,6 +171,7 @@ class WebComponent implements iComponent
* @throws RouterException
* @throws WebException
* @throws EventException
* @throws FactoryException
*/
public function routeWebRequest(): bool
{
@ -146,12 +180,13 @@ class WebComponent implements iComponent
try {
// Set the output to display when shutting down
Events::addListener(function ($event) {
/** @var Output $output */
Logger::logInfo("Parsing output...");
$output = Factory::getInstance()->output;
$output->display();
}, 'coreShutdownEvent', Priority::NORMAL);
Events::addListener([$this, 'shutdownEventListener'], 'coreShutdownEvent', Priority::NORMAL);
// Intercept output of Layout and redirect it to Output
Events::addListener([$this, 'layoutDisplayEventListener'], 'layoutDisplayEvent', Priority::NORMAL);
// Add HTTP method prefix to requests to views
Events::addListener([$this, 'routerLoadViewAndControllerEventListener'], 'routerLoadViewAndControllerEvent', Priority::NORMAL);
// Create an error 500 page when a haltEvent is fired
Events::addListener([$this, 'haltEventListener'], 'haltExecutionEvent', Priority::NORMAL);
@ -164,12 +199,31 @@ class WebComponent implements iComponent
/** @var Router $router */
/** @var URI $uri */
/** @var Input $input */
/** @var Output $output */
/** @var Security $security */
$router = Factory::getInstance()->router;
$uri = Factory::getInstance()->uri;
$output = Factory::getInstance()->output;
$security = Factory::getInstance()->security;
/** @var Resources $resources */
/** @var Config $config */
$router = Factory::getInstance('router');
$uri = Factory::getInstance('uri');
$input = Factory::getInstance('input');
$output = Factory::getInstance('output');
$security = Factory::getInstance('security');
$resources = Factory::getInstance('resources');
$config = Factory::getInstance('config');
// First check if this isn't https and we need to redirect
$redirect = $config->getConfig('web')->get('redirect_to_https');
if ($redirect && !$input->isHttps())
{
Logger::log("Redirecting http traffic to https...");
$httpsInputs = $input->server(['HTTPS', 'HTTP_HOST', 'REQUEST_URI']);
$location = 'https://' . $httpsInputs['HTTP_HOST'] . $httpsInputs['REQUEST_URI'];
$output->setStatusHeader(301);
$output->setHeader('Location: ' . $location);
return true;
}
// And start logging the request
Logger::newLevel("Routing web request...");
@ -179,6 +233,16 @@ class WebComponent implements iComponent
if ($output->getCache($uriString))
return true;
// Send webRequestEvent, if no cache is found
/** @var RouteWebRequestEvent $event */
$event = Events::fireEvent('routeWebRequestEvent', $uriString);
if ($event->isCancelled())
return true;
// Attempt to load a static resource
if ($resources->serveResource($uri->uriString()))
return true;
// First test for Cross Site Request Forgery
try {
$security->csrf_verify();
@ -192,7 +256,7 @@ class WebComponent implements iComponent
// Attempt to load the requested page
try {
$viewOutput = $router->route($uriString);
$viewOutput = $router->route($event->uriString);
} catch (NotFoundException $e) {
Logger::logWarning("Requested page not found. Requesting Error/error404 View");
$output->setStatusHeader(404);
@ -200,7 +264,7 @@ class WebComponent implements iComponent
// Remove listener so that error pages won't be intercepted
Events::removeListener([$this, 'callViewEventListener'], 'routerCallViewEvent',Priority::HIGHEST);
// Request 404 page=
// Request 404 page
try {
$viewOutput = $router->route('Error/error404');
} catch (NotFoundException $e) {
@ -248,7 +312,6 @@ class WebComponent implements iComponent
*/
public function callViewEventListener(RouterCallViewEvent $event, SecurityException $exception)
{
/** @var RouterCallViewEvent $event */
// If the securityExceptionHandler method exists, cancel based on that methods output
if (method_exists($event->view, 'securityExceptionHandler'))
$event->setCancelled(!$event->view->securityExceptionHandler($exception));
@ -263,8 +326,9 @@ class WebComponent implements iComponent
*
* Fired when FuzeWorks halts it's execution. Loads an error 500 page.
*
* @param $event
* @param HaltExecutionEvent $event
* @throws EventException
* @throws FactoryException
* @TODO remove FuzeWorks\Layout dependency
*/
public function haltEventListener(HaltExecutionEvent $event)
@ -276,14 +340,17 @@ class WebComponent implements iComponent
/** @var Layout $layout */
$output = Factory::getInstance()->output;
$router = Factory::getInstance()->router;
$layout = Factory::getInstance()->layouts;
// Reset the layout engine
if (isset(Factory::getInstance()->layouts))
{
$layout = Factory::getInstance()->layouts;
$layout->reset();
}
// Cancel event
$event->setCancelled(true);
// Reset the layout engine
$layout->reset();
// Remove listener so that error pages won't be intercepted
Events::removeListener([$this, 'callViewEventListener'], 'routerCallViewEvent',Priority::HIGHEST);
@ -308,6 +375,7 @@ class WebComponent implements iComponent
*
* @param LayoutLoadEvent $event
* @throws ConfigException
* @throws FactoryException
*/
public function layoutLoadEventListener($event)
{
@ -317,10 +385,10 @@ class WebComponent implements iComponent
$security = Factory::getInstance()->security;
$config = Factory::getInstance()->config;
/** @var LayoutLoadEvent $event */
$event->assign('csrfHash', $security->get_csrf_hash());
$event->assign('csrfTokenName', $security->get_csrf_token_name());
$event->assign('siteURL', $config->getConfig('web')->get('base_url'));
$event->assign('serverName', $config->getConfig('web')->get('serverName'));
Logger::logInfo("Assigned variables to TemplateEngine from WebComponent");
}