mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-12-30 11:34:56 +00:00
Import a basic structure for the PHP code from another project.
This commit is contained in:
parent
023d9fd94a
commit
c4f226e1ef
7 changed files with 443 additions and 0 deletions
18
di_config.php
Normal file
18
di_config.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use SBRL\TomlConfig;
|
||||
|
||||
return [
|
||||
"settings.file_default" => "data/settings.toml",
|
||||
"settings.file_custom" => "settings.default.toml",
|
||||
|
||||
\SBRL\TomlConfig::class => function(ContainerInterface $c) {
|
||||
return new TomlConfig(
|
||||
$c->get("settings.file_default"),
|
||||
$c->get("settings.file_custom")
|
||||
);
|
||||
},
|
||||
|
||||
\SBRL\SessionManager::class => DI\factory([ \SBRL\SessionManager::class, "get_instance" ])
|
||||
];
|
59
index.php
Normal file
59
index.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
define("ROOT_DIR", dirname(__FILE__) . "/");
|
||||
|
||||
// 1: Autoloaders
|
||||
|
||||
require("vendor/autoload.php");
|
||||
|
||||
$autoloader = new \Aura\Autoload\Loader();
|
||||
$autoloader->addPrefix("AirQuality", "logic");
|
||||
$autoloader->addPrefix("SBRL", "lib/SBRL");
|
||||
$autoloader->register();
|
||||
|
||||
|
||||
// 2: Dependency injection
|
||||
|
||||
$di_builder = new DI\ContainerBuilder();
|
||||
$di_builder->addDefinitions("di_config.php");
|
||||
|
||||
$di_container = $di_builder->build();
|
||||
|
||||
|
||||
// 3: Settings
|
||||
|
||||
$settings = $di_container->get(\SBRL\TomlConfig::class);
|
||||
|
||||
|
||||
// 4: Database
|
||||
|
||||
// TODO: Setup the database here
|
||||
|
||||
|
||||
// 5: Action
|
||||
|
||||
// Figure out the action name
|
||||
$action = str_replace(
|
||||
" ", "",
|
||||
ucwords(str_replace(
|
||||
"-", " ",
|
||||
preg_replace("/[^a-z-]/i", "", $_GET["action"] ?? $settings->get("routing.default-action"))
|
||||
))
|
||||
);
|
||||
|
||||
$handler_name = "AirQuality\\Actions\\$action";
|
||||
|
||||
// if(!class_exists($handler_name))
|
||||
// send_error(404, "Unknown action $handler_name.");
|
||||
|
||||
// Fetch it from the dependency injector and execute it, but only if it exists
|
||||
|
||||
if(!class_exists($handler_name)) {
|
||||
http_response_code(404);
|
||||
header("content-type: text/plain");
|
||||
exit("Error: No action with the name '$action' could be found.");
|
||||
}
|
||||
|
||||
// FUTURE: A PSR-7 request/response system would be rather nice here.
|
||||
$handler = $di_container->get($handler_name);
|
||||
$handler->handle();
|
13
lib/SBRL/Generators.php
Normal file
13
lib/SBRL/Generators.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace SBRL;
|
||||
|
||||
class Generators {
|
||||
|
||||
public static function crypto_secure_id(int $length = 64) { // 64 = 32
|
||||
$length = ($length < 4) ? 4 : $length;
|
||||
return bin2hex(random_bytes(($length-($length%2))/2));
|
||||
}
|
||||
|
||||
|
||||
}
|
202
lib/SBRL/TomlConfig.php
Normal file
202
lib/SBRL/TomlConfig.php
Normal file
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
|
||||
namespace SBRL;
|
||||
|
||||
use \stdClass;
|
||||
use \Yosymfony\Toml\Toml;
|
||||
use \Yosymfony\Toml\TomlBuilder;
|
||||
|
||||
/**
|
||||
* Handles the loading and saving of settings from a toml file.
|
||||
* Supports loading default settings from a separate file.
|
||||
* @author Starbeamrainbowlabs
|
||||
* @version v0.5
|
||||
* @lastModified 22nd March 2017
|
||||
* @license https://www.mozilla.org/en-US/MPL/2.0/ Mozilla Public License 2.0
|
||||
* Changelog:
|
||||
* v0.5 - 9th September 2018
|
||||
* Made hasPropertyByPath() more intelligent
|
||||
* v0.4 - 23rd August 2018
|
||||
* Made getPropertyByPath() more intelligent
|
||||
* v0.3 - 5th March 2018
|
||||
* Forked to create a version for toml.
|
||||
* v0.2 - 22nd March 2017
|
||||
* Add license
|
||||
* Filled in some missing comments
|
||||
* v0.1: 28th February 2017
|
||||
* Initial release
|
||||
*/
|
||||
class TomlConfig
|
||||
{
|
||||
private $defaultSettings;
|
||||
|
||||
private $settingsFilePath = "";
|
||||
/**
|
||||
* The custom settings object.
|
||||
* @var stdClass
|
||||
*/
|
||||
private $customSettings;
|
||||
|
||||
/**
|
||||
* The banner to insert at the top of the custom settings file when saving it.
|
||||
* @var string
|
||||
*/
|
||||
private $customSettingsBanner;
|
||||
|
||||
/**
|
||||
* Creates a new JsonConfig
|
||||
* @param string $settingsFilePath The path to the customised settings file.
|
||||
* @param string $defaultSettingsFilePath The path to the default settings file.
|
||||
*/
|
||||
public function __construct($settingsFilePath, $defaultSettingsFilePath) {
|
||||
$this->customSettingsBanner = "-------[ Custom Settings File - Last updated " . date("Y-m-d") . " ]-------";
|
||||
|
||||
$this->defaultSettings = Toml::ParseFile($defaultSettingsFilePath, true);
|
||||
|
||||
$this->customSettings = new stdClass();
|
||||
if(file_exists($settingsFilePath)) {
|
||||
$this->customSettings = Toml::ParseFile($settingsFilePath, true);
|
||||
} else {
|
||||
mkdir(dirname($settingsFilePath), 0750, true);
|
||||
file_put_contents($settingsFilePath, "$this->customSettingsBanner\n");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the value identified by the specified property, in dotted notation (e.g. `Network.Firewalling.Ports.Http`)
|
||||
* @param string $key The property, in dotted notation, to return.
|
||||
* @return mixed The value odentified by the given dotted property notation.
|
||||
*/
|
||||
public function get($key) {
|
||||
if(static::hasPropertyByPath($this->customSettings, $key)) {
|
||||
return static::getPropertyByPath($this->customSettings, $key);
|
||||
}
|
||||
return static::getPropertyByPath($this->defaultSettings, $key);
|
||||
}
|
||||
/**
|
||||
* Fetches the default value for the specified property, specified in dotted notation.
|
||||
* @param string $key The key to fetch.
|
||||
* @return mixed The default value of the property identified by the given dotted notation.
|
||||
*/
|
||||
public function getDefault($key) {
|
||||
return static::getPropertyByPath($this->defaultSettings, $key);
|
||||
}
|
||||
/**
|
||||
* Determines whether the given property has been customised or explicitly specified in the customised settings file.
|
||||
* @param string $key The property, in dotted notation, to check.
|
||||
* @return boolean Whether the specified properties file has been explicitly specified in the custom settings file.
|
||||
*/
|
||||
public function hasChanged($key) {
|
||||
return static::hasPropertyByPath($this->customSettings, $key);
|
||||
}
|
||||
/**
|
||||
* Sets the property identified by the specified dotted path.
|
||||
* Does not re-save the properties back to disk!
|
||||
* @param string $key The dotted path to update.
|
||||
* @param mixed $value The value to set the property to.
|
||||
* @return self This ConfigFile instance, to aid method chaining.
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
static::setPropertyByPath($this->customSettings, $key, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCustomSettingsBanner($value) {
|
||||
$this->customSettingsBanner = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the customised settings back to the disk.
|
||||
* @return boolean Whether the save was successful or not.
|
||||
*/
|
||||
public function save() {
|
||||
$output_builder = new TomlBuilder();
|
||||
$toml_builder->addComment($this->customSettingsBanner);
|
||||
|
||||
$this->build($toml_builder, $this->customSettings);
|
||||
|
||||
return file_put_contents($settingsFilePath, $toml_builder->getTomlString());
|
||||
}
|
||||
|
||||
private function build($toml_builder, $customSettingsObject, $subobject_name = null) {
|
||||
if($subobject_name !== null)
|
||||
$toml_builder->addTable($subobject_name);
|
||||
|
||||
foreach($customSettingsObject as $key => $value) {
|
||||
if(!\is_object($value))
|
||||
$toml_builder->addValue($key, $value);
|
||||
else
|
||||
$this->build($toml_builder, $value, "$subobject_name.$key");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Works out whether a given dotted path to a property exists on a given object.
|
||||
* @param stdClass $obj The object to search.
|
||||
* @param string $path The dotted path to search with. e.g. `Network.Firewall.OpenPorts`
|
||||
* @return boolean Whether the given property is present in the given object.
|
||||
*/
|
||||
public static function hasPropertyByPath($obj, $path) {
|
||||
$pathParts = explode(".", $path);
|
||||
$subObj = $obj;
|
||||
foreach($pathParts as $part) {
|
||||
if(is_object($subObj) && !isset($subObj->$part))
|
||||
return false;
|
||||
else if(is_array($subObj) && !isset($subObj[$part]))
|
||||
return false;
|
||||
else if(!is_object($subObj) && !is_array($subObj))
|
||||
return false;
|
||||
|
||||
if(is_object($subObj))
|
||||
$subObj = $subObj->$part;
|
||||
else // It must be an array
|
||||
$subObj = $subObj[$part];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Returns the property identified by the given dotted path.
|
||||
* If you're not sure whether a property exists or not, use static::hasPropertyByPath() first to check.
|
||||
* @param stdClass $obj The object to fetch from.
|
||||
* @param string $path The path to extract from the given object.
|
||||
* @return mixed The property identified by the given object.
|
||||
*/
|
||||
public static function getPropertyByPath($obj, $path) {
|
||||
$pathParts = explode(".", $path);
|
||||
$subObj = $obj;
|
||||
foreach($pathParts as $part) {
|
||||
if(is_object($subObj))
|
||||
$subObj = $subObj->$part;
|
||||
else if(is_array($subObj))
|
||||
$subObj = $subObj[$part];
|
||||
else
|
||||
throw new Exception("Error: Can't find part '$part' on sub-item if it isn't an object or array");
|
||||
}
|
||||
return $subObj;
|
||||
}
|
||||
/**
|
||||
* Returns the property identified by the given dotted path.
|
||||
* If you're not sure whether a property exists or not, use static::hasPropertyByPath() first to check.
|
||||
* @param stdClass $obj The object to set the property on.
|
||||
* @param string $path The path to set on the given object.
|
||||
* @param mixed $value The value to set the given property to.
|
||||
*/
|
||||
public static function setPropertyByPath($obj, $path, $value) {
|
||||
$pathParts = explode(".", $path);
|
||||
$pathPartsCount = count($pathParts);
|
||||
|
||||
$subObj = $obj;
|
||||
for($i = 0; $i < $pathPartsCount; $i++) {
|
||||
// Set the property on the last iteration
|
||||
if($i + 1 == $pathPartsCount) {
|
||||
$subObj->$part = $value;
|
||||
break;
|
||||
}
|
||||
// Create sub-objects if they dobn't exist already
|
||||
if(!isset($subObj->$part)) {
|
||||
$subObj->$part = new stdClass();
|
||||
}
|
||||
$subObj = $subObj->$part;
|
||||
}
|
||||
}
|
||||
}
|
23
logic/Actions/FetchData.php
Normal file
23
logic/Actions/FetchData.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace AirQuality\Actions;
|
||||
|
||||
|
||||
class Index {
|
||||
private $settings;
|
||||
private $renderer;
|
||||
|
||||
public function __construct(
|
||||
\SBRL\TomlConfig $in_settings) {
|
||||
$this->settings = $in_settings;
|
||||
$this->renderer = $in_renderer;
|
||||
}
|
||||
|
||||
public function handle() {
|
||||
echo($this->renderer->render_file(ROOT_DIR."templates/main.html", [
|
||||
"title" => "Home",
|
||||
"content" => file_get_contents(ROOT_DIR."templates/mockup.html"),
|
||||
"footer_html" => ""
|
||||
]));
|
||||
}
|
||||
}
|
111
logic/Validator.php
Normal file
111
logic/Validator.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
namespace AirQuality;
|
||||
|
||||
|
||||
|
||||
class Validator {
|
||||
private $target_data;
|
||||
private $tests = [];
|
||||
|
||||
public function __construct($in_target_data) {
|
||||
$this->target_data = $in_target_data;
|
||||
}
|
||||
|
||||
public function exists($key) {
|
||||
$this->add_test(
|
||||
$key,
|
||||
function($data) { return isset($data); },
|
||||
400,
|
||||
"Error: The field $key wasn't found in your request."
|
||||
);
|
||||
}
|
||||
|
||||
public function is_numberish($key) {
|
||||
$this->add_test(
|
||||
$key,
|
||||
function($data) { return is_numeric($data); },
|
||||
400,
|
||||
"Error: The field $key in your request isn't a number."
|
||||
);
|
||||
}
|
||||
public function is_min_length($key, $min_length) {
|
||||
$this->add_test(
|
||||
$key,
|
||||
function($data) use ($min_length) { return mb_strlen($data) >= $min_length; },
|
||||
400,
|
||||
"Error: The field $key is too short - it must be a minimum of $min_length characters."
|
||||
);
|
||||
}
|
||||
public function is_max_length($key, $max_length) {
|
||||
$this->add_test(
|
||||
$key,
|
||||
function($data) use ($max_length) { return mb_strlen($data) <= $max_length; },
|
||||
400,
|
||||
"Error: The field $key is too long - it must be a maximum of $max_length characters."
|
||||
);
|
||||
}
|
||||
|
||||
public function are_equal($key_a, $key_b, $message) {
|
||||
$key_b_data = $this->target_data[$key_b];
|
||||
$this->add_test(
|
||||
$key_a,
|
||||
function($data) use($key_b_data) {
|
||||
return $data === $key_b_data;
|
||||
},
|
||||
400,
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
public function matches_regex($key, $regex, $message) {
|
||||
$this->add_test(
|
||||
$key,
|
||||
function($data) use($regex) {
|
||||
return preg_match($regex, $data) === 1;
|
||||
},
|
||||
400,
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
public function is_valid_email($key) {
|
||||
$this->add_test(
|
||||
$key,
|
||||
function($data) {
|
||||
$validator = new \EmailValidator\Validator();
|
||||
return $validator->isValid($data);
|
||||
},
|
||||
400,
|
||||
"That email address isn't valid."
|
||||
);
|
||||
}
|
||||
|
||||
public function add_test($key, $test, $response_code, $message) {
|
||||
$new_test = [
|
||||
"key" => $key,
|
||||
"test" => $test,
|
||||
"response_code" => $response_code,
|
||||
"message" => $message
|
||||
];
|
||||
|
||||
$this->tests[] = $new_test;
|
||||
}
|
||||
|
||||
protected function send_error($code, $message) {
|
||||
http_response_code($code);
|
||||
header("content-type: text/plain");
|
||||
exit($message);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
foreach($this->tests as $test) {
|
||||
|
||||
if(!isset($this->target_data[$test["key"]]) || !$test["test"]($this->target_data[$test["key"]])) {
|
||||
$this->send_error($test["response_code"], $test["message"]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
17
settings.default.toml
Normal file
17
settings.default.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
# This file defines the default configuration settings.
|
||||
##### DO NOT EDIT THIS FILE. #####
|
||||
# Your changes may be overwritten in a future update.
|
||||
# Instead, edit the custom configuration file located at "data/settings.toml".
|
||||
|
||||
[database]
|
||||
# Settings that control the database, or the connection to it
|
||||
|
||||
type = mysql # MariaDB. MySQL servers might work too, but no promises.
|
||||
username = "user"
|
||||
password = "Define_in_custom_config_file"
|
||||
|
||||
[routing]
|
||||
# Settings that control the router's behaviour
|
||||
|
||||
# The default action to take if no action is specified
|
||||
default-action = fetch-data
|
Loading…
Reference in a new issue