mirror of
https://github.com/standardebooks/web.git
synced 2025-07-05 14:20:29 -04:00
Update framework standards
This commit is contained in:
parent
232e056299
commit
09a91a998e
17 changed files with 282 additions and 98 deletions
|
@ -45,10 +45,10 @@ const CAPTCHA_IMAGE_HEIGHT = 72;
|
||||||
const CAPTCHA_IMAGE_WIDTH = 230;
|
const CAPTCHA_IMAGE_WIDTH = 230;
|
||||||
|
|
||||||
// These are defined for convenience, so that getting HTTP input isn't so wordy
|
// These are defined for convenience, so that getting HTTP input isn't so wordy
|
||||||
const GET = HttpVariableSource::Get;
|
const GET = Enums\HttpVariableSource::Get;
|
||||||
const POST = HttpVariableSource::Post;
|
const POST = Enums\HttpVariableSource::Post;
|
||||||
const SESSION = HttpVariableSource::Session;
|
const SESSION = Enums\HttpVariableSource::Session;
|
||||||
const COOKIE = HttpVariableSource::Cookie;
|
const COOKIE = Enums\HttpVariableSource::Cookie;
|
||||||
|
|
||||||
define('NO_REPLY_EMAIL_ADDRESS', get_cfg_var('se.secrets.email.no_reply_address'));
|
define('NO_REPLY_EMAIL_ADDRESS', get_cfg_var('se.secrets.email.no_reply_address'));
|
||||||
define('ADMIN_EMAIL_ADDRESS', get_cfg_var('se.secrets.email.admin_address'));
|
define('ADMIN_EMAIL_ADDRESS', get_cfg_var('se.secrets.email.admin_address'));
|
||||||
|
|
|
@ -9,7 +9,7 @@ class DbConnection{
|
||||||
public int $LastQueryAffectedRowCount = 0;
|
public int $LastQueryAffectedRowCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new database connection.
|
* Create a database connection.
|
||||||
*
|
*
|
||||||
* @param ?string $defaultDatabase The default database to connect to, or `null` not to define one.
|
* @param ?string $defaultDatabase The default database to connect to, or `null` not to define one.
|
||||||
* @param string $host The database hostname.
|
* @param string $host The database hostname.
|
||||||
|
@ -28,7 +28,7 @@ class DbConnection{
|
||||||
|
|
||||||
$connectionString = 'mysql:';
|
$connectionString = 'mysql:';
|
||||||
|
|
||||||
if(stripos($host, ':') !== false){
|
if(mb_stripos($host, ':') !== false){
|
||||||
$port = null;
|
$port = null;
|
||||||
preg_match('/([^:]*):([0-9]+)/ius', $host, $matches);
|
preg_match('/([^:]*):([0-9]+)/ius', $host, $matches);
|
||||||
$host = $matches[1];
|
$host = $matches[1];
|
||||||
|
@ -113,7 +113,7 @@ class DbConnection{
|
||||||
*
|
*
|
||||||
* The result is an array of rows. Each row is an array of objects, with each object containing its columns and values. For example,
|
* The result is an array of rows. Each row is an array of objects, with each object containing its columns and values. For example,
|
||||||
*
|
*
|
||||||
* ```
|
* ```php
|
||||||
* [
|
* [
|
||||||
* [
|
* [
|
||||||
* 'Users' => {
|
* 'Users' => {
|
||||||
|
@ -123,7 +123,7 @@ class DbConnection{
|
||||||
* 'Posts' => {
|
* 'Posts' => {
|
||||||
* 'PostId' => 222,
|
* 'PostId' => 222,
|
||||||
* 'Title' => 'Lorem Ipsum'
|
* 'Title' => 'Lorem Ipsum'
|
||||||
* },
|
* }
|
||||||
* ],
|
* ],
|
||||||
* [
|
* [
|
||||||
* 'Users' => {
|
* 'Users' => {
|
||||||
|
@ -146,14 +146,14 @@ class DbConnection{
|
||||||
* @param array<mixed> $params An array of parameters to bind to the SQL statement.
|
* @param array<mixed> $params An array of parameters to bind to the SQL statement.
|
||||||
* @param class-string<T> $class The class to instantiate for each row, or `null` to return an array of rows.
|
* @param class-string<T> $class The class to instantiate for each row, or `null` to return an array of rows.
|
||||||
*
|
*
|
||||||
* @return array<T>|array<array<string, object>> An array of `$class` if `$class` is not `null`, otherwise an array of rows of the form `["LeftTableName" => $stdClass, "RightTableName" => $stdClass]`.
|
* @return array<T>|array<array<string, stdClass>> An array of `$class` if `$class` is not `null`, otherwise an array of rows of the form `["LeftTableName" => $stdClass, "RightTableName" => $stdClass]`.
|
||||||
*
|
*
|
||||||
* @throws Exceptions\AppException If a class was specified but the class doesn't have a `FromMultiTableRow()` method.
|
* @throws Exceptions\MultiSelectMethodNotFoundException If a class was specified but the class doesn't have a `FromMultiTableRow()` method.
|
||||||
* @throws Exceptions\DatabaseQueryException When an error occurs during execution of the query.
|
* @throws Exceptions\DatabaseQueryException When an error occurs during execution of the query.
|
||||||
*/
|
*/
|
||||||
public function MultiTableSelect(string $sql, array $params = [], ?string $class = null): array{
|
public function MultiTableSelect(string $sql, array $params = [], ?string $class = null): array{
|
||||||
if($class !== null && !method_exists($class, 'FromMultiTableRow')){
|
if($class !== null && !method_exists($class, 'FromMultiTableRow')){
|
||||||
throw new Exceptions\AppException('Multi table select attempted, but class ' . $class . ' doesn\'t have a FromMultiTableRow() method.');
|
throw new Exceptions\MultiSelectMethodNotFoundException($class);
|
||||||
}
|
}
|
||||||
|
|
||||||
$handle = $this->PreparePdoHandle($sql, $params);
|
$handle = $this->PreparePdoHandle($sql, $params);
|
||||||
|
@ -316,7 +316,7 @@ class DbConnection{
|
||||||
* @param \PdoStatement $handle The PDO handle to execute.
|
* @param \PdoStatement $handle The PDO handle to execute.
|
||||||
* @param class-string<T> $class The class to instantiate for each row, or `null` to return an array of rows.
|
* @param class-string<T> $class The class to instantiate for each row, or `null` to return an array of rows.
|
||||||
*
|
*
|
||||||
* @return array<T>|array<array<string, object>> An array of `$class` if `$class` is not `null`, otherwise an array of rows of the form `["LeftTableName" => $stdClass, "RightTableName" => $stdClass]`.
|
* @return array<T>|array<array<string, stdClass>> An array of `$class` if `$class` is not `null`, otherwise an array of rows of the form `["LeftTableName" => $stdClass, "RightTableName" => $stdClass]`.
|
||||||
*
|
*
|
||||||
* @throws \PDOException When an error occurs during execution of the query.
|
* @throws \PDOException When an error occurs during execution of the query.
|
||||||
*/
|
*/
|
||||||
|
|
26
lib/Enums/HttpCode.php
Normal file
26
lib/Enums/HttpCode.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?
|
||||||
|
namespace Enums;
|
||||||
|
|
||||||
|
enum HttpCode: int{
|
||||||
|
case Ok = 200;
|
||||||
|
case Created = 201;
|
||||||
|
case Accepted = 202;
|
||||||
|
case NoContent = 204;
|
||||||
|
|
||||||
|
case MovedPermanently = 301; // Permanent redirect
|
||||||
|
case Found = 302; // Temporary redirect
|
||||||
|
case SeeOther = 303;
|
||||||
|
|
||||||
|
case BadRequest = 400;
|
||||||
|
case Unauthorized = 401;
|
||||||
|
case PaymentRequired = 402;
|
||||||
|
case Forbidden = 403;
|
||||||
|
case NotFound = 404;
|
||||||
|
case MethodNotAllowed = 405;
|
||||||
|
case Conflict = 409;
|
||||||
|
case Gone = 410;
|
||||||
|
case UnprocessableContent = 422;
|
||||||
|
|
||||||
|
case InternalServerError = 500;
|
||||||
|
case ServiceUnavailable = 503;
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
<?
|
<?
|
||||||
|
namespace Enums;
|
||||||
|
|
||||||
enum HttpMethod: string{
|
enum HttpMethod: string{
|
||||||
case Delete = 'DELETE';
|
case Delete = 'DELETE';
|
||||||
case Get = 'GET';
|
case Get = 'GET';
|
|
@ -1,4 +1,6 @@
|
||||||
<?
|
<?
|
||||||
|
namespace Enums;
|
||||||
|
|
||||||
enum HttpRequestType{
|
enum HttpRequestType{
|
||||||
case Rest;
|
case Rest;
|
||||||
case Web;
|
case Web;
|
|
@ -1,4 +1,6 @@
|
||||||
<?
|
<?
|
||||||
|
namespace Enums;
|
||||||
|
|
||||||
enum HttpVariableSource{
|
enum HttpVariableSource{
|
||||||
case Get;
|
case Get;
|
||||||
case Post;
|
case Post;
|
|
@ -1,4 +1,6 @@
|
||||||
<?
|
<?
|
||||||
|
namespace Enums;
|
||||||
|
|
||||||
enum HttpVariableType{
|
enum HttpVariableType{
|
||||||
case Array;
|
case Array;
|
||||||
case Boolean;
|
case Boolean;
|
|
@ -2,19 +2,56 @@
|
||||||
use Safe\DateTimeImmutable;
|
use Safe\DateTimeImmutable;
|
||||||
|
|
||||||
use function Safe\ini_get;
|
use function Safe\ini_get;
|
||||||
|
use function Safe\glob;
|
||||||
use function Safe\preg_match;
|
use function Safe\preg_match;
|
||||||
|
use function Safe\preg_replace;
|
||||||
|
use function Safe\mb_convert_encoding;
|
||||||
|
|
||||||
class HttpInput{
|
class HttpInput{
|
||||||
/**
|
/**
|
||||||
* Check that the request's HTTP method is in a list of allowed HTTP methods.
|
* Calculate the HTTP method of the request, then include `<METHOD>.php` and exit.
|
||||||
* @param ?array<HttpMethod> $allowedHttpMethods An array containing a list of allowed HTTP methods, or null if any valid HTTP method is allowed.
|
|
||||||
* @param bool $throwException If the request HTTP method isn't allowed, then throw an exception; otherwise, output HTTP 405 and exit the script immediately.
|
|
||||||
* @throws Exceptions\InvalidHttpMethodException If the HTTP method is not recognized and `$throwException` is `true`.
|
|
||||||
* @throws Exceptions\HttpMethodNotAllowedException If the HTTP method is not in the list of allowed methods and `$throwException` is `true`.
|
|
||||||
*/
|
*/
|
||||||
public static function ValidateRequestMethod(?array $allowedHttpMethods = null, bool $throwException = false): HttpMethod{
|
public static function DispatchRest(): void{
|
||||||
try{
|
try{
|
||||||
$requestMethod = HttpMethod::from($_POST['_method'] ?? $_SERVER['REQUEST_METHOD']);
|
$httpMethod = HttpInput::ValidateRequestMethod(null, true);
|
||||||
|
|
||||||
|
$filename = mb_strtolower($httpMethod->value) . '.php';
|
||||||
|
|
||||||
|
if(!file_exists($filename)){
|
||||||
|
throw new Exceptions\InvalidHttpMethodException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($httpMethod == Enums\HttpMethod::Post){
|
||||||
|
// If we're a HTTP POST, then we got here from a POST request initially, so just continue
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
include($filename);
|
||||||
|
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
catch(Exceptions\InvalidHttpMethodException | Exceptions\HttpMethodNotAllowedException){
|
||||||
|
$filenames = glob('{delete,get,patch,post,put}.php', GLOB_BRACE);
|
||||||
|
|
||||||
|
if(sizeof($filenames) > 0){
|
||||||
|
header('Allow: ' . implode(',', array_map(fn($filename): string => mb_strtoupper(preg_replace('/^([a-z]+)[\.\-].+$/i', '\1', $filename)), $filenames)));
|
||||||
|
}
|
||||||
|
|
||||||
|
http_response_code(Enums\HttpCode::MethodNotAllowed->value);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the request's HTTP method is in a list of allowed HTTP methods.
|
||||||
|
* @param ?array<Enums\HttpMethod> $allowedHttpMethods An array containing a list of allowed HTTP methods, or null if any valid HTTP method is allowed.
|
||||||
|
* @param bool $throwException If the request HTTP method isn't allowed, then throw an exception; otherwise, output HTTP 405 and exit the script immediately.
|
||||||
|
* @throws Exceptions\InvalidHttpMethodException If the HTTP method is not recognized, and `$throwException` is `true`.
|
||||||
|
* @throws Exceptions\HttpMethodNotAllowedException If the HTTP method is recognized but not allowed, and `$throwException` is `true`.
|
||||||
|
*/
|
||||||
|
public static function ValidateRequestMethod(?array $allowedHttpMethods = null, bool $throwException = false): Enums\HttpMethod{
|
||||||
|
try{
|
||||||
|
$requestMethod = Enums\HttpMethod::from($_POST['_method'] ?? $_GET['_method'] ?? $_SERVER['REQUEST_METHOD']);
|
||||||
if($allowedHttpMethods !== null){
|
if($allowedHttpMethods !== null){
|
||||||
$isRequestMethodAllowed = false;
|
$isRequestMethodAllowed = false;
|
||||||
foreach($allowedHttpMethods as $allowedHttpMethod){
|
foreach($allowedHttpMethods as $allowedHttpMethod){
|
||||||
|
@ -41,7 +78,7 @@ class HttpInput{
|
||||||
if($allowedHttpMethods !== null){
|
if($allowedHttpMethods !== null){
|
||||||
header('Allow: ' . implode(',', array_map(fn($httpMethod): string => $httpMethod->value, $allowedHttpMethods)));
|
header('Allow: ' . implode(',', array_map(fn($httpMethod): string => $httpMethod->value, $allowedHttpMethods)));
|
||||||
}
|
}
|
||||||
http_response_code(405);
|
http_response_code(Enums\HttpCode::MethodNotAllowed->value);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +90,7 @@ class HttpInput{
|
||||||
* @return int The maximum size for an HTTP POST request, in bytes.
|
* @return int The maximum size for an HTTP POST request, in bytes.
|
||||||
*/
|
*/
|
||||||
public static function GetMaxPostSize(): int{
|
public static function GetMaxPostSize(): int{
|
||||||
$post_max_size = ini_get('post_max_size');
|
$post_max_size = ini_get('upload_max_filesize');
|
||||||
$unit = substr($post_max_size, -1);
|
$unit = substr($post_max_size, -1);
|
||||||
$size = (int) substr($post_max_size, 0, -1);
|
$size = (int) substr($post_max_size, 0, -1);
|
||||||
|
|
||||||
|
@ -71,16 +108,35 @@ class HttpInput{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elseif(sizeof($_FILES) > 0){
|
||||||
|
// We received files but may have an error because the size exceeded our limit.
|
||||||
|
foreach($_FILES as $file){
|
||||||
|
$error = $file['error'] ?? UPLOAD_ERR_OK;
|
||||||
|
|
||||||
|
if($error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function GetRequestType(): HttpRequestType{
|
public static function GetRequestType(): Enums\HttpRequestType{
|
||||||
return preg_match('/\btext\/html\b/ius', $_SERVER['HTTP_ACCEPT'] ?? '') ? HttpRequestType::Web : HttpRequestType::Rest;
|
return preg_match('/\btext\/html\b/ius', $_SERVER['HTTP_ACCEPT'] ?? '') ? Enums\HttpRequestType::Web : Enums\HttpRequestType::Rest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Str(HttpVariableSource $set, string $variable, bool $allowEmptyString = false): ?string{
|
/**
|
||||||
$var = self::GetHttpVar($variable, HttpVariableType::String, $set);
|
* Get a string from an HTTP variable set.
|
||||||
|
*
|
||||||
|
* If the variable is set but empty, returns `null` unless `$allowEmptyString` is **`TRUE`**, in which case it returns an empty string.
|
||||||
|
*
|
||||||
|
* @param Enums\HttpVariableSource $set
|
||||||
|
* @param string $variable
|
||||||
|
* @param bool $allowEmptyString If the variable exists but is empty, return an empty string instead of `null`.
|
||||||
|
*/
|
||||||
|
public static function Str(Enums\HttpVariableSource $set, string $variable, bool $allowEmptyString = false): ?string{
|
||||||
|
$var = self::GetHttpVar($variable, Enums\HttpVariableType::String, $set);
|
||||||
|
|
||||||
if(is_array($var)){
|
if(is_array($var)){
|
||||||
return null;
|
return null;
|
||||||
|
@ -94,24 +150,51 @@ class HttpInput{
|
||||||
return $var;
|
return $var;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Int(HttpVariableSource $set, string $variable): ?int{
|
public static function Int(Enums\HttpVariableSource $set, string $variable): ?int{
|
||||||
/** @var ?int */
|
/** @var ?int */
|
||||||
return self::GetHttpVar($variable, HttpVariableType::Integer, $set);
|
return self::GetHttpVar($variable, Enums\HttpVariableType::Integer, $set);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Bool(HttpVariableSource $set, string $variable): ?bool{
|
public static function Bool(Enums\HttpVariableSource $set, string $variable): ?bool{
|
||||||
/** @var ?bool */
|
/** @var ?bool */
|
||||||
return self::GetHttpVar($variable, HttpVariableType::Boolean, $set);
|
return self::GetHttpVar($variable, Enums\HttpVariableType::Boolean, $set);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Dec(HttpVariableSource $set, string $variable): ?float{
|
public static function Dec(Enums\HttpVariableSource $set, string $variable): ?float{
|
||||||
/** @var ?float */
|
/** @var ?float */
|
||||||
return self::GetHttpVar($variable, HttpVariableType::Decimal, $set);
|
return self::GetHttpVar($variable, Enums\HttpVariableType::Decimal, $set);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Date(HttpVariableSource $set, string $variable): ?DateTimeImmutable{
|
public static function Date(Enums\HttpVariableSource $set, string $variable): ?DateTimeImmutable{
|
||||||
/** @var ?DateTimeImmutable */
|
/** @var ?DateTimeImmutable */
|
||||||
return self::GetHttpVar($variable, HttpVariableType::DateTime, $set);
|
return self::GetHttpVar($variable, Enums\HttpVariableType::DateTime, $set);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an object of type `$class` from `$_SESSION`, or `null` of no object of that type exists in `$_SESSION`.
|
||||||
|
*
|
||||||
|
* @template T of object
|
||||||
|
* @param string $variable
|
||||||
|
* @param class-string<T>|array<class-string<T>> $class The class of the object to return, or an array of possible classes to return.
|
||||||
|
*
|
||||||
|
* @return ?T An object of type `$class`, or `null` if no object of that type exists in `$_SESSION`.
|
||||||
|
*/
|
||||||
|
public static function SessionObject(string $variable, string|array $class): ?object{
|
||||||
|
if(!is_array($class)){
|
||||||
|
$class = [$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = $_SESSION[$variable] ?? null;
|
||||||
|
|
||||||
|
if($object !== null){
|
||||||
|
foreach($class as $c){
|
||||||
|
if(is_a($object, $c)){
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,85 +220,95 @@ class HttpInput{
|
||||||
* @param string $variable
|
* @param string $variable
|
||||||
* @return array<string>
|
* @return array<string>
|
||||||
*/
|
*/
|
||||||
public static function Array(HttpVariableSource $set, string $variable): ?array{
|
public static function Array(Enums\HttpVariableSource $set, string $variable): ?array{
|
||||||
/** @var array<string> */
|
/** @var array<string> */
|
||||||
return self::GetHttpVar($variable, HttpVariableType::Array, $set);
|
return self::GetHttpVar($variable, Enums\HttpVariableType::Array, $set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string>|array<int>|array<float>|array<bool>|string|int|float|bool|DateTimeImmutable|null
|
* @return array<string>|array<int>|array<float>|array<bool>|string|int|float|bool|DateTimeImmutable|null
|
||||||
*/
|
*/
|
||||||
private static function GetHttpVar(string $variable, HttpVariableType $type, HttpVariableSource $set): mixed{
|
private static function GetHttpVar(string $variable, Enums\HttpVariableType $type, Enums\HttpVariableSource $set): mixed{
|
||||||
|
// Note that in Core.php we parse the request body of DELETE, PATCH, and PUT into $_POST.
|
||||||
|
|
||||||
$vars = [];
|
$vars = [];
|
||||||
|
|
||||||
switch($set){
|
switch($set){
|
||||||
case HttpVariableSource::Get:
|
case Enums\HttpVariableSource::Get:
|
||||||
$vars = $_GET;
|
$vars = $_GET;
|
||||||
break;
|
break;
|
||||||
case HttpVariableSource::Post:
|
case Enums\HttpVariableSource::Post:
|
||||||
$vars = $_POST;
|
$vars = $_POST;
|
||||||
break;
|
break;
|
||||||
case HttpVariableSource::Cookie:
|
case Enums\HttpVariableSource::Cookie:
|
||||||
$vars = $_COOKIE;
|
$vars = $_COOKIE;
|
||||||
break;
|
break;
|
||||||
case HttpVariableSource::Session:
|
case Enums\HttpVariableSource::Session:
|
||||||
$vars = $_SESSION;
|
$vars = $_SESSION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($vars[$variable])){
|
if(isset($vars[$variable])){
|
||||||
if($type == HttpVariableType::Array && is_array($vars[$variable])){
|
if($type == Enums\HttpVariableType::Array && is_array($vars[$variable])){
|
||||||
// We asked for an array, and we got one
|
// We asked for an array, and we got one
|
||||||
return $vars[$variable];
|
return $vars[$variable];
|
||||||
}
|
}
|
||||||
elseif($type !== HttpVariableType::Array && is_array($vars[$variable])){
|
elseif($type !== Enums\HttpVariableType::Array && is_array($vars[$variable])){
|
||||||
// We asked for not an array, but we got an array
|
// We asked for not an array, but we got an array
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
elseif(is_string($vars[$variable])){
|
elseif(is_string($vars[$variable])){
|
||||||
$var = trim($vars[$variable]);
|
// HTML `<textarea>`s encode newlines as `\r\n`, i.e. TWO characters, when submitting form data. However jQuery's `.val()` and HTML's `@maxlength` treat newlines as ONE character. So, strip `\r` here so that character lengths align between what the browser reports, and what it actually sends. This also solves column length issues when storing in the DB.
|
||||||
|
$var = trim(str_replace("\r", "", $vars[$variable]));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$var = $vars[$variable];
|
$var = $vars[$variable];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($type){
|
switch($type){
|
||||||
case HttpVariableType::String:
|
case Enums\HttpVariableType::String:
|
||||||
return $var;
|
// Attempt to fix broken UTF8 strings, often passed by bots and scripts.
|
||||||
case HttpVariableType::Integer:
|
// Broken UTF8 can cause exceptions in functions like `preg_replace()`.
|
||||||
|
try{
|
||||||
|
return mb_convert_encoding($var, 'utf-8');
|
||||||
|
}
|
||||||
|
catch(\Safe\Exceptions\MbstringException){
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
case Enums\HttpVariableType::Integer:
|
||||||
// Can't use ctype_digit because we may want negative integers
|
// Can't use ctype_digit because we may want negative integers
|
||||||
if(is_numeric($var) && mb_strpos(strval($var), '.') === false){
|
if(is_numeric($var) && mb_strpos((string)$var, '.') === false){
|
||||||
try{
|
try{
|
||||||
return intval($var);
|
return intval($var);
|
||||||
}
|
}
|
||||||
catch(\Exception){
|
catch(Exception){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HttpVariableType::Boolean:
|
case Enums\HttpVariableType::Boolean:
|
||||||
if($var === false || $var === '0' || strtolower($var) == 'false' || strtolower($var) == 'off'){
|
if($var === false || $var === '0' || strtolower($var) == 'false' || strtolower($var) == 'off'){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case HttpVariableType::Decimal:
|
case Enums\HttpVariableType::Decimal:
|
||||||
if(is_numeric($var)){
|
if(is_numeric($var)){
|
||||||
try{
|
try{
|
||||||
return floatval($var);
|
return floatval($var);
|
||||||
}
|
}
|
||||||
catch(\Exception){
|
catch(Exception){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HttpVariableType::DateTime:
|
case Enums\HttpVariableType::DateTime:
|
||||||
if($var != ''){
|
if($var != ''){
|
||||||
try{
|
try{
|
||||||
return new DateTimeImmutable($var);
|
return new DateTimeImmutable($var);
|
||||||
}
|
}
|
||||||
catch(\Exception){
|
catch(Exception){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,84 @@
|
||||||
<?
|
<?
|
||||||
namespace Traits;
|
namespace Traits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait to add getters/setters for class properties.
|
||||||
|
*
|
||||||
|
* Properties are defined by PHPDoc. Their backing class properties must be either `protected` or `private` and begin with `_`. They are accessed by a protected `Get${Var}` function and set by a protected `Set${Var}` function. For example:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* // @property string Bar
|
||||||
|
* class Foo{
|
||||||
|
* use Traits\Accessor;
|
||||||
|
*
|
||||||
|
* protected string $_Bar;
|
||||||
|
*
|
||||||
|
* protected function GetBar(): string{
|
||||||
|
* if(!isset($this->_Bar)){
|
||||||
|
* $this->_Bar = 'baz';
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* return $this->_Bar;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* protected function SetBar(string $value): void{
|
||||||
|
* $this->_Bar = $value;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* $foo = new Foo();
|
||||||
|
* print($foo->Bar); // baz
|
||||||
|
* $foo->Bar = 'ipsum';
|
||||||
|
* print($foo->Bar); // ipsum
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* **Note:** Using the null coalesce `??` operator on an `Accessor` property is equivalent to calling `isset()` and short-circuiting on **`FALSE`**, *instead of calling the getter.*
|
||||||
|
*
|
||||||
|
* For example, `$object->Tag->Name ?? ''` will always return `""` if `$object->_Tag = <uninitialized>`, without calling the getter first.
|
||||||
|
*
|
||||||
|
* See <https://reddit.com/r/PHPhelp/comments/x2avqu/anyone_know_the_rules_behind_null_coalescing/>.
|
||||||
|
*/
|
||||||
trait Accessor{
|
trait Accessor{
|
||||||
public function __get(string $var): mixed{
|
public function __get(string $var): mixed{
|
||||||
$function = 'Get' . $var;
|
$getterFunction = 'Get' . $var;
|
||||||
$privateVar = '_' . $var;
|
$privateVar = '_' . $var;
|
||||||
|
|
||||||
if(method_exists($this, $function)){
|
if(method_exists($this, $getterFunction)){
|
||||||
return $this->$function();
|
return $this->$getterFunction();
|
||||||
}
|
}
|
||||||
elseif(property_exists($this, $var . 'Id') && property_exists($this, $privateVar) && method_exists($var, 'Get')){
|
|
||||||
// If we're asking for a private `_Var` property,
|
if(property_exists($this, $privateVar)){
|
||||||
// and we have a public `VarId` property,
|
if(!isset($this->$privateVar) && isset($this->{$var . 'Id'})){
|
||||||
// and the `Var` class also has a `Var::Get` method,
|
try{
|
||||||
// call that method and return the result.
|
$type = (new \ReflectionProperty($this, $privateVar))->getType();
|
||||||
if($this->$privateVar === null && $this->{$var . 'Id'} !== null){
|
|
||||||
$this->$privateVar = $var::Get($this->{$var . 'Id'});
|
if($type !== null && ($type instanceof \ReflectionNamedType)){
|
||||||
|
$typeName = $type->getName();
|
||||||
|
|
||||||
|
if(method_exists($typeName, 'Get')){
|
||||||
|
// If we're asking for a private `_Var` property, and we have a public `VarId` property, and the `Var` class also has a `Var::Get()` method, call that method and return the result.
|
||||||
|
$this->$privateVar = $typeName::Get($this->{$var . 'Id'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(\ReflectionException){
|
||||||
|
// Pass, but let through other exceptions that may come from `Var::Get()`.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->$privateVar;
|
return $this->$privateVar;
|
||||||
}
|
}
|
||||||
elseif(property_exists($this, $privateVar)){
|
|
||||||
return $this->{$privateVar};
|
|
||||||
}
|
|
||||||
else{
|
else{
|
||||||
return $this->$var;
|
return $this->$var;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __set(string $var, mixed $val): void{
|
public function __set(string $var, mixed $val): void{
|
||||||
$function = 'Set' . $var;
|
$setterFunction = 'Set' . $var;
|
||||||
$privateVar = '_' . $var;
|
$privateVar = '_' . $var;
|
||||||
|
|
||||||
if(method_exists($this, $function)){
|
if(method_exists($this, $setterFunction)){
|
||||||
$this->$function($val);
|
$this->$setterFunction($val);
|
||||||
}
|
}
|
||||||
elseif(property_exists($this, $privateVar)){
|
elseif(property_exists($this, $privateVar)){
|
||||||
$this->$privateVar = $val;
|
$this->$privateVar = $val;
|
||||||
|
@ -42,4 +87,16 @@ trait Accessor{
|
||||||
$this->$var = $val;
|
$this->$var = $val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __unset(string $var): void{
|
||||||
|
$unsetterFunction = 'Unset' . $var;
|
||||||
|
$privateVar = '_' . $var;
|
||||||
|
|
||||||
|
if(method_exists($this, $unsetterFunction)){
|
||||||
|
$this->$unsetterFunction();
|
||||||
|
}
|
||||||
|
elseif(property_exists($this, $privateVar)){
|
||||||
|
unset($this->$privateVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
try{
|
try{
|
||||||
session_start();
|
session_start();
|
||||||
$httpMethod = HttpInput::ValidateRequestMethod([HttpMethod::Post, HttpMethod::Patch, HttpMethod::Put]);
|
$httpMethod = HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post, Enums\HttpMethod::Patch, Enums\HttpMethod::Put]);
|
||||||
$exceptionRedirectUrl = '/artworks/new';
|
$exceptionRedirectUrl = '/artworks/new';
|
||||||
|
|
||||||
if(HttpInput::IsRequestTooLarge()){
|
if(HttpInput::IsRequestTooLarge()){
|
||||||
|
@ -14,7 +14,7 @@ try{
|
||||||
}
|
}
|
||||||
|
|
||||||
// POSTing a new artwork
|
// POSTing a new artwork
|
||||||
if($httpMethod == HttpMethod::Post){
|
if($httpMethod == Enums\HttpMethod::Post){
|
||||||
if(!$GLOBALS['User']->Benefits->CanUploadArtwork){
|
if(!$GLOBALS['User']->Benefits->CanUploadArtwork){
|
||||||
throw new Exceptions\InvalidPermissionsException();
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ try{
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUTing an artwork
|
// PUTing an artwork
|
||||||
if($httpMethod == HttpMethod::Put){
|
if($httpMethod == Enums\HttpMethod::Put){
|
||||||
$originalArtwork = Artwork::GetByUrl(HttpInput::Str(GET, 'artist-url-name'), HttpInput::Str(GET, 'artwork-url-name'));
|
$originalArtwork = Artwork::GetByUrl(HttpInput::Str(GET, 'artist-url-name'), HttpInput::Str(GET, 'artwork-url-name'));
|
||||||
|
|
||||||
if(!$originalArtwork->CanBeEditedBy($GLOBALS['User'])){
|
if(!$originalArtwork->CanBeEditedBy($GLOBALS['User'])){
|
||||||
|
@ -82,7 +82,7 @@ try{
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCHing an artwork
|
// PATCHing an artwork
|
||||||
if($httpMethod == HttpMethod::Patch){
|
if($httpMethod == Enums\HttpMethod::Patch){
|
||||||
$artwork = Artwork::GetByUrl(HttpInput::Str(GET, 'artist-url-name'), HttpInput::Str(GET, 'artwork-url-name'));
|
$artwork = Artwork::GetByUrl(HttpInput::Str(GET, 'artist-url-name'), HttpInput::Str(GET, 'artwork-url-name'));
|
||||||
|
|
||||||
$exceptionRedirectUrl = $artwork->Url;
|
$exceptionRedirectUrl = $artwork->Url;
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<?
|
<?
|
||||||
try{
|
try{
|
||||||
// We may use GET if we're called from an unsubscribe link in an email
|
// We may use GET if we're called from an unsubscribe link in an email
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Get, HttpMethod::Delete]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Get, Enums\HttpMethod::Delete]);
|
||||||
|
|
||||||
$requestType = HttpInput::GetRequestType();
|
$requestType = HttpInput::GetRequestType();
|
||||||
|
|
||||||
$subscription = NewsletterSubscription::Get(HttpInput::Str(GET, 'uuid'));
|
$subscription = NewsletterSubscription::Get(HttpInput::Str(GET, 'uuid'));
|
||||||
$subscription->Delete();
|
$subscription->Delete();
|
||||||
|
|
||||||
if($requestType == HttpRequestType::Rest){
|
if($requestType == Enums\HttpRequestType::Rest){
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exceptions\NewsletterSubscriptionNotFoundException){
|
catch(Exceptions\NewsletterSubscriptionNotFoundException){
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
Template::Emit404();
|
Template::Emit404();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
|
@ -3,7 +3,7 @@ use Ramsey\Uuid\Uuid;
|
||||||
use function Safe\session_unset;
|
use function Safe\session_unset;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Post]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post]);
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ try{
|
||||||
|
|
||||||
if(HttpInput::Str(POST, 'automationtest')){
|
if(HttpInput::Str(POST, 'automationtest')){
|
||||||
// A bot filled out this form field, which should always be empty. Pretend like we succeeded.
|
// A bot filled out this form field, which should always be empty. Pretend like we succeeded.
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
http_response_code(303);
|
http_response_code(303);
|
||||||
$uuid = Uuid::uuid4();
|
$uuid = Uuid::uuid4();
|
||||||
$subscription->User = new User();
|
$subscription->User = new User();
|
||||||
|
@ -22,7 +22,7 @@ try{
|
||||||
header('Location: /newsletter/subscriptions/success');
|
header('Location: /newsletter/subscriptions/success');
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 201 CREATED with location
|
// Access via Enums\HttpRequestType::Rest api; 201 CREATED with location
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
header('Location: /newsletter/subscriptions/success');
|
header('Location: /newsletter/subscriptions/success');
|
||||||
}
|
}
|
||||||
|
@ -43,20 +43,20 @@ try{
|
||||||
|
|
||||||
session_unset();
|
session_unset();
|
||||||
|
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
http_response_code(303);
|
http_response_code(303);
|
||||||
$_SESSION['is-subscription-created'] = $subscription->UserId;
|
$_SESSION['is-subscription-created'] = $subscription->UserId;
|
||||||
header('Location: /newsletter/subscriptions/success');
|
header('Location: /newsletter/subscriptions/success');
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 201 CREATED with location
|
// Access via Enums\HttpRequestType::Rest api; 201 CREATED with location
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
header('Location: /newsletter/subscriptions/success');
|
header('Location: /newsletter/subscriptions/success');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exceptions\NewsletterSubscriptionExistsException){
|
catch(Exceptions\NewsletterSubscriptionExistsException){
|
||||||
// Subscription exists.
|
// Subscription exists.
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
// If we're accessing from the web, update the subscription,
|
// If we're accessing from the web, update the subscription,
|
||||||
// re-sending the confirmation email if the user isn't yet confirmed
|
// re-sending the confirmation email if the user isn't yet confirmed
|
||||||
$existingSubscription = NewsletterSubscription::Get($subscription->User->Uuid);
|
$existingSubscription = NewsletterSubscription::Get($subscription->User->Uuid);
|
||||||
|
@ -77,12 +77,12 @@ catch(Exceptions\NewsletterSubscriptionExistsException){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 409 CONFLICT
|
// Access via Enums\HttpRequestType::Rest api; 409 CONFLICT
|
||||||
http_response_code(409);
|
http_response_code(409);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exceptions\InvalidNewsletterSubscription $ex){
|
catch(Exceptions\InvalidNewsletterSubscription $ex){
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
$_SESSION['subscription'] = $subscription;
|
$_SESSION['subscription'] = $subscription;
|
||||||
$_SESSION['exception'] = $ex;
|
$_SESSION['exception'] = $ex;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ catch(Exceptions\InvalidNewsletterSubscription $ex){
|
||||||
header('Location: /newsletter/subscriptions/new');
|
header('Location: /newsletter/subscriptions/new');
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 422 Unprocessable Entity
|
// Access via Enums\HttpRequestType::Rest api; 422 Unprocessable Entity
|
||||||
http_response_code(422);
|
http_response_code(422);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use function Safe\session_unset;
|
use function Safe\session_unset;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Post]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post]);
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
|
@ -16,19 +16,19 @@ try{
|
||||||
|
|
||||||
session_unset();
|
session_unset();
|
||||||
|
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
$_SESSION['is-vote-created'] = $vote->UserId;
|
$_SESSION['is-vote-created'] = $vote->UserId;
|
||||||
http_response_code(303);
|
http_response_code(303);
|
||||||
header('Location: ' . $vote->Url);
|
header('Location: ' . $vote->Url);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 201 CREATED with location
|
// Access via Enums\HttpRequestType::Rest api; 201 CREATED with location
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
header('Location: ' . $vote->Url);
|
header('Location: ' . $vote->Url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exceptions\InvalidPollVoteException $ex){
|
catch(Exceptions\InvalidPollVoteException $ex){
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
$_SESSION['vote'] = $vote;
|
$_SESSION['vote'] = $vote;
|
||||||
$_SESSION['exception'] = $ex;
|
$_SESSION['exception'] = $ex;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ catch(Exceptions\InvalidPollVoteException $ex){
|
||||||
header('Location: /polls/' . (HttpInput::Str(GET, 'pollurlname') ?? '') . '/votes/new');
|
header('Location: /polls/' . (HttpInput::Str(GET, 'pollurlname') ?? '') . '/votes/new');
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 422 Unprocessable Entity
|
// Access via Enums\HttpRequestType::Rest api; 422 Unprocessable Entity
|
||||||
http_response_code(422);
|
http_response_code(422);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use function Safe\session_unset;
|
use function Safe\session_unset;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Post]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post]);
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
|
@ -21,18 +21,18 @@ try{
|
||||||
|
|
||||||
session_unset();
|
session_unset();
|
||||||
|
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
http_response_code(303);
|
http_response_code(303);
|
||||||
header('Location: ' . $redirect);
|
header('Location: ' . $redirect);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 201 CREATED with location
|
// Access via Enums\HttpRequestType::Rest api; 201 CREATED with location
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
header('Location: ' . $session->Url);
|
header('Location: ' . $session->Url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exceptions\InvalidLoginException | Exceptions\PasswordRequiredException $ex){
|
catch(Exceptions\InvalidLoginException | Exceptions\PasswordRequiredException $ex){
|
||||||
if($requestType == HttpRequestType::Web){
|
if($requestType == Enums\HttpRequestType::Web){
|
||||||
$_SESSION['email'] = $email;
|
$_SESSION['email'] = $email;
|
||||||
$_SESSION['redirect'] = $redirect;
|
$_SESSION['redirect'] = $redirect;
|
||||||
$_SESSION['exception'] = $ex;
|
$_SESSION['exception'] = $ex;
|
||||||
|
@ -42,7 +42,7 @@ catch(Exceptions\InvalidLoginException | Exceptions\PasswordRequiredException $e
|
||||||
header('Location: /sessions/new');
|
header('Location: /sessions/new');
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Access via HttpRequestType::Rest api; 422 Unprocessable Entity
|
// Access via Enums\HttpRequestType::Rest api; 422 Unprocessable Entity
|
||||||
http_response_code(422);
|
http_response_code(422);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ try{
|
||||||
$log = new Log(GITHUB_WEBHOOK_LOG_FILE_PATH);
|
$log = new Log(GITHUB_WEBHOOK_LOG_FILE_PATH);
|
||||||
$lastPushHashFlag = '';
|
$lastPushHashFlag = '';
|
||||||
|
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Post]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post]);
|
||||||
|
|
||||||
$log->Write('Received GitHub webhook.');
|
$log->Write('Received GitHub webhook.');
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ try{
|
||||||
|
|
||||||
$log->Write('Received Postmark webhook.');
|
$log->Write('Received Postmark webhook.');
|
||||||
|
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Post]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post]);
|
||||||
|
|
||||||
$apiKey = get_cfg_var('se.secrets.postmark.api_key');
|
$apiKey = get_cfg_var('se.secrets.postmark.api_key');
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use function Safe\json_decode;
|
||||||
try{
|
try{
|
||||||
$log = new Log(ZOHO_WEBHOOK_LOG_FILE_PATH);
|
$log = new Log(ZOHO_WEBHOOK_LOG_FILE_PATH);
|
||||||
|
|
||||||
HttpInput::ValidateRequestMethod([HttpMethod::Post]);
|
HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post]);
|
||||||
|
|
||||||
$log->Write('Received Zoho webhook.');
|
$log->Write('Received Zoho webhook.');
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue