diff --git a/resources/autoload.php b/resources/autoload.php index 7f262cdc..158db4bc 100644 --- a/resources/autoload.php +++ b/resources/autoload.php @@ -32,6 +32,7 @@ require_once __DIR__ . "/lib/exceptions/EnsureException.php"; require_once __DIR__ . "/lib/exceptions/EncodingUnknownException.php"; require_once __DIR__ . "/lib/exceptions/EncodingConversionException.php"; +require_once __DIR__ . "/lib/exceptions/UnityHTTPDMessageNotFoundException.php"; require_once __DIR__ . "/config.php"; require __DIR__ . "/init.php"; diff --git a/resources/lib/UnityHTTPD.php b/resources/lib/UnityHTTPD.php index bed4bb95..d1794369 100644 --- a/resources/lib/UnityHTTPD.php +++ b/resources/lib/UnityHTTPD.php @@ -4,6 +4,7 @@ use UnityWebPortal\lib\exceptions\NoDieException; use UnityWebPortal\lib\exceptions\ArrayKeyException; +use UnityWebPortal\lib\exceptions\UnityHTTPDMessageNotFoundException; use RuntimeException; enum UnityHTTPDMessageLevel: string @@ -226,13 +227,22 @@ public static function errorHandler(int $severity, string $message, string $file public static function getPostData(string $key): mixed { - try { - return $_POST[$key]; - } catch (ArrayKeyException $e) { - self::badRequest('failed to get $_POST data', $e, [ - '$_POST' => $_POST, - ]); + if (!isset($_SERVER)) { + throw new RuntimeException('$_SERVER is unset'); + } + if (!array_key_exists("REQUEST_METHOD", $_SERVER)) { + throw new RuntimeException('$_SERVER has no array key "REQUEST_METHOD"'); + } + if ($_SERVER["REQUEST_METHOD"] !== "POST") { + self::badRequest('$_SERVER["REQUEST_METHOD"] != "POST"'); } + if (!isset($_POST)) { + self::badRequest('$_POST is unset'); + } + if (!array_key_exists($key, $_POST)) { + self::badRequest("\$_POST has no array key '$key'"); + } + return $_POST[$key]; } public static function getUploadedFileContents( @@ -325,6 +335,43 @@ public static function getMessages() public static function clearMessages() { + self::ensureSessionMessagesSanity(); $_SESSION["messages"] = []; } + + private static function getMessageIndex( + UnityHTTPDMessageLevel $level, + string $title, + string $body, + ) { + $messages = self::getMessages(); + $error_msg = sprintf( + "message(level='%s' title='%s' body='%s'), not found. found messages: %s", + $level->value, + $title, + $body, + jsonEncode($messages), + ); + foreach ($messages as $i => $message) { + if ($title == $message[0] && $body == $message[1] && $level == $message[2]) { + return $i; + } + } + throw new UnityHTTPDMessageNotFoundException($error_msg); + } + + /* returns the 1st message that matches or throws UnityHTTPDMessageNotFoundException */ + public static function getMessage(UnityHTTPDMessageLevel $level, string $title, string $body) + { + $index = self::getMessageIndex($level, $title, $body); + return $_SESSION["messages"][$index]; + } + + /* deletes the 1st message that matches or throws UnityHTTPDMessageNotFoundException */ + public static function deleteMessage(UnityHTTPDMessageLevel $level, string $title, string $body) + { + $index = self::getMessageIndex($level, $title, $body); + unset($_SESSION["messages"][$index]); + $_SESSION["messages"] = array_values($_SESSION["messages"]); + } } diff --git a/resources/lib/exceptions/UnityHTTPDMessageNotFoundException.php b/resources/lib/exceptions/UnityHTTPDMessageNotFoundException.php new file mode 100644 index 00000000..214fc5bb --- /dev/null +++ b/resources/lib/exceptions/UnityHTTPDMessageNotFoundException.php @@ -0,0 +1,5 @@ +
%s
- + ", htmlspecialchars($level->value), htmlspecialchars($title), - htmlspecialchars($body) + htmlspecialchars($body), + htmlspecialchars($level->value), + htmlspecialchars($title), + htmlspecialchars($body), ); } - UnityHTTPD::clearMessages(); if ( isset($_SESSION["is_admin"]) && $_SESSION["is_admin"] diff --git a/test/functional/DeleteMessageTest.php b/test/functional/DeleteMessageTest.php new file mode 100644 index 00000000..133c19e9 --- /dev/null +++ b/test/functional/DeleteMessageTest.php @@ -0,0 +1,40 @@ +assertEmpty($initial); + UnityHTTPD::messageDebug("foo1", "bar1"); + UnityHTTPD::messageDebug("foo2", "bar2"); + UnityHTTPD::messageDebug("foo3", "bar3"); + UnityHTTPD::messageError("foo", "bar"); + UnityHTTPD::messageInfo("foo", "bar"); + UnityHTTPD::messageSuccess("foo", "bar"); + UnityHTTPD::messageWarning("foo", "bar"); + try { + $before = array_map("jsonEncode", UnityHTTPD::getMessages()); + http_post( + __DIR__ . "/../../webroot/panel/ajax/delete_message.php", + [ + "level" => "debug", + "title" => "foo2", + "body" => "bar2", + ], + enforce_PRG: false, + ); + $after = array_map("jsonEncode", UnityHTTPD::getMessages()); + $difference = array_diff($before, $after); + $message_expected_removed = ["foo2", "bar2", UnityHTTPDMessageLevel::DEBUG]; + $this->assertEqualsCanonicalizing([jsonEncode($message_expected_removed)], $difference); + } finally { + UnityHTTPD::clearMessages(); + } + } +} diff --git a/test/phpunit-bootstrap.php b/test/phpunit-bootstrap.php index 3061f59f..1b231a6c 100644 --- a/test/phpunit-bootstrap.php +++ b/test/phpunit-bootstrap.php @@ -23,6 +23,7 @@ require_once __DIR__ . "/../resources/lib/exceptions/EnsureException.php"; require_once __DIR__ . "/../resources/lib/exceptions/EncodingUnknownException.php"; require_once __DIR__ . "/../resources/lib/exceptions/EncodingConversionException.php"; +require_once __DIR__ . "/../resources/lib/exceptions/UnityHTTPDMessageNotFoundException.php"; use UnityWebPortal\lib\UnityGroup; use UnityWebPortal\lib\UnityHTTPD; @@ -96,7 +97,7 @@ function switchUser( ensure(!is_null($USER)); } -function http_post(string $phpfile, array $post_data): void +function http_post(string $phpfile, array $post_data, bool $enforce_PRG = true): void { global $LDAP, $SQL, @@ -126,8 +127,10 @@ function http_post(string $phpfile, array $post_data): void unset($_POST); $_SERVER = $_PREVIOUS_SERVER; } - // https://en.wikipedia.org/wiki/Post/Redirect/Get - ensure($post_did_redirect_or_die, "post did not redirect or die!"); + if ($enforce_PRG) { + // https://en.wikipedia.org/wiki/Post/Redirect/Get + ensure($post_did_redirect_or_die, "post did not redirect or die!"); + } } function http_get(string $phpfile, array $get_data = []): void diff --git a/webroot/panel/ajax/delete_message.php b/webroot/panel/ajax/delete_message.php new file mode 100644 index 00000000..23870636 --- /dev/null +++ b/webroot/panel/ajax/delete_message.php @@ -0,0 +1,12 @@ +