diff options
| author | Jonas Kohl | 2024-09-13 19:57:43 +0200 | 
|---|---|---|
| committer | Jonas Kohl | 2024-09-13 19:57:43 +0200 | 
| commit | 93817fef3ead7cfd4fcde25ea2bcec02d01310a4 (patch) | |
| tree | 60f6ab69bbf2360d7cc518023090b8bf61bfd5b1 /src/index.php | |
| parent | 086e2d2668784469ec114f6e6fd2b3dace3d7c3b (diff) | |
A lot of changes again
Diffstat (limited to 'src/index.php')
| -rw-r--r-- | src/index.php | 193 | 
1 files changed, 175 insertions, 18 deletions
| diff --git a/src/index.php b/src/index.php index 109cd2e..1cc0d01 100644 --- a/src/index.php +++ b/src/index.php @@ -8,15 +8,16 @@ use mystic\forum\orm\Post;  use mystic\forum\orm\Topic;  use mystic\forum\orm\User;  use mystic\forum\orm\UserPermissions; +use mystic\forum\utils\FileUtils;  use mystic\forum\utils\RequestUtils;  use mystic\forum\utils\ValidationUtils;  header_remove("X-Powered-By"); -function exception_error_handler($errno, $errstr, $errfile, $errline ) { -    throw new ErrorException(html_entity_decode($errstr), $errno, 0, $errfile, $errline); -} -set_error_handler("exception_error_handler"); +// function exception_error_handler($errno, $errstr, $errfile, $errline ) { +//     throw new ErrorException(html_entity_decode($errstr), $errno, 0, $errfile, $errline); +// } +// set_error_handler("exception_error_handler");  define("REGISTRATION_ENABLED", true); @@ -34,6 +35,7 @@ $GLOBALS["action"] = $_action;  function _view(string $name, array $params = []): void {      $___NAME = $name; +    $___PARAMS = &$params;      extract($params);      echo "<!--{" . htmlentities($name) . "}-->\n";      include __DIR__ . "/application/views/" . $___NAME . ".php"; @@ -425,12 +427,99 @@ if ($_action === "auth") {          Messaging::error("No user exists with this id");          exit;      } -    _view("template_start", ["_title" => "Forum"]); -    _view("template_navigation_start"); -    _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); -    _view("template_navigation_end"); -    _view("view_user", ["user" => $user]); -    _view("template_end"); + +    $lastNameChangeTooRecent = false; +    $isOwnProfile = $user->id === $currentUser?->id; +    if ($isOwnProfile && $user->nameLastChanged !== null) { +        $diff = $user->nameLastChanged->diff(new DateTime()); +        $diffSeconds = (new DateTime())->setTimestamp(0)->add($diff)->getTimestamp(); +        $diffDays = $diffSeconds / 60.0 / 60.0 / 24.0 / 30.0; +        $lastNameChangeTooRecent = $diffDays <= 30; +    } + +    if (RequestUtils::isRequestMethod("POST")) { +        $displayName = RequestUtils::getRequiredField("display_name"); +        $pfpAction = RequestUtils::getRequiredField("pfp_action"); + +        $userName = $_POST["name"] ?? $user->name; + +        $user->displayName = $displayName; + +        $userName = strtolower($userName); + +        if ($userName !== $user->name) { +            if ($lastNameChangeTooRecent) { +                RequestUtils::triggerFormError("You can only change your username every 30 days!"); +            } else { +                if (!ValidationUtils::isUsernameValid($userName)) +                    RequestUtils::triggerFormError("Invalid username!"); +                if (!ValidationUtils::isUsernameAvailable($db, $userName)) +                    RequestUtils::triggerFormError("This username is already taken!"); +                $user->name = $userName; +                $user->nameLastChanged = new DateTimeImmutable(); +            } +        } + +        switch ($pfpAction) { +            case "keep": +                // Do nothing +                break; +            case "remove": +                $user->profilePicture = null; +                break; +            case "replace": { +                if (!isset($_FILES["pfp"]) || $_FILES["pfp"]["error"] !== UPLOAD_ERR_OK) { +                    RequestUtils::triggerFormError("Please upload an image to change your profile picture"); +                } +                $im = @imagecreatefromjpeg($_FILES["pfp"]["tmp_name"]); +                if ($im === false) +                    $im = @imagecreatefrompng($_FILES["pfp"]["tmp_name"]); +                if ($im === false) +                    RequestUtils::triggerFormError("Please upload a valid PNG or JPEG file"); +                /** @var \GdImage $im */ +                $thumb = imagecreatetruecolor(64, 64); +                imagecopyresampled($thumb, $im, 0, 0, 0, 0, 64, 64, imagesx($im), imagesy($im)); +                imagedestroy($im); +                $stream = fopen("php://memory", "w+"); +                imagejpeg($thumb, $stream, 50); +                rewind($stream); +                imagedestroy($thumb); +                $user->profilePicture = stream_get_contents($stream); +                fclose($stream); +            } break; +            default: +                RequestUtils::triggerFormError("Invalid value for pfp_action"); +                break; +        } + +        if (!$db->update($user)) +            RequestUtils::triggerFormError("Failed to save changes"); + +        header("Location: $_SERVER[REQUEST_URI]"); +    } else { +        $posts = $db->fetchCustom(Post::class, 'WHERE author_id = $1 ORDER BY post_date DESC', [ $userId ]); +        $topics = []; +        foreach ($posts as $post) { +            if (isset($topics[$post->topicId])) +                continue; +            $topic = new Topic(); +            $topic->id = $post->topicId; +            if (!$db->fetch($topic)) +                continue; +            $topics[$post->topicId] = $topic; +        } +        _view("template_start", ["_title" => "Forum"]); +        _view("template_navigation_start"); +        _view("template_navigation", ["user" => $currentUser]); +        _view("template_navigation_end"); +        _view("view_user", [ +            "user" => $user, +            "posts" => $posts, +            "topics" => $topics, +            "lastNameChangeTooRecent" => $lastNameChangeTooRecent, +        ]); +        _view("template_end"); +    }  } elseif ($_action === "attachment") {      if (!$currentUser) {          http_response_code(403); @@ -447,10 +536,48 @@ if ($_action === "auth") {          exit;      } -    header("Content-Type: " . $attachment->mimeType); +    $extension = pathinfo($attachment->name, PATHINFO_EXTENSION); +    header("Content-Type: " . FileUtils::getMimeTypeForExtension($extension));      header("Content-Length: " . strlen($attachment->contents));      header("Cache-Control: no-cache"); +    header("Content-Disposition: inline; filename=\"" . $attachment->name . "\"");      echo $attachment->contents; +} elseif ($_action === "profilepicture") { +    $userId = $_GET["user"] ?? throw new Exception("Missing user id"); +    $user = new User(); +    $user->id = $userId; +    if (!$db->fetch($user)) { +        http_response_code(404); +        Messaging::error("No user exists with this id"); +        exit; +    } +     +    $ifNoneMatch = $_SERVER["HTTP_IF_NONE_MATCH"] ?? null; +    if ($ifNoneMatch !== null) +        $ifNoneMatch = trim($ifNoneMatch, '"'); +     +    if ($user->profilePicture === null) { +        $fallback = __DIR__ . "/application/assets/user-fallback.jpg"; +        $etag = md5("\0"); +        header("Content-Type: image/jpeg"); +        header("Content-Length: " . filesize($fallback)); +        header("Cache-Control: no-cache"); +        header("ETag: \"" . $etag . "\""); +        if ($ifNoneMatch === $etag) +            http_response_code(304); +        else +            readfile($fallback); +    } else { +        $etag = md5($user->profilePicture); +        header("Content-Type: image/jpeg"); +        header("Content-Length: " . strlen($user->profilePicture)); +        header("Cache-Control: no-cache"); +        header("ETag: \"" . $etag . "\""); +        if ($ifNoneMatch === $etag) +            http_response_code(304); +        else +            echo $user->profilePicture; +    }  } elseif ($_action === "thumb") {      $attId = $_GET["attachment"] ?? throw new Exception("Missing attachment id"); @@ -468,7 +595,27 @@ if ($_action === "auth") {          exit;      } -    // TODO Cache thumbnail +    $contentHash = hash("sha256", $attachment->contents); +     +    $cacheId = bin2hex($attachment->id); +    $cacheDir = sys_get_temp_dir() . "/mystic/forum/0/cache/thumbs/" . substr($cacheId, 0, 2) . "/" . substr($cacheId, 0, 8) . "/"; +    if (!is_dir($cacheDir)) +        mkdir($cacheDir, recursive: true); + +    $cacheFileData = $cacheDir . $cacheId . ".data"; +    $cacheFileInfo = $cacheDir . $cacheId . ".info"; + +    if (is_file($cacheFileData) && is_file($cacheFileInfo)) { +        $info = json_decode(file_get_contents($cacheFileInfo)); +        if ($info->contentHash === $contentHash) { +            header("Content-Type: image/jpeg"); +            header("Cache-Control: max-age=86400"); +            header("X-Debug-Content: $cacheFileData"); +            readfile($cacheFileData); +            exit; +        } +    } +      $im = imagecreatefromstring($attachment->contents);      $w = imagesx($im);      $h = imagesy($im); @@ -487,9 +634,15 @@ if ($_action === "auth") {      imagedestroy($im);      header("Content-Type: image/jpeg"); -    header("Cache-Control: no-cache"); -    imagejpeg($thumb, null, 40); +    header("Cache-Control: max-age=86400"); +    imagejpeg($thumb, $cacheFileData, 40);      imagedestroy($thumb); +    file_put_contents($cacheFileInfo, json_encode([ +        "format" => 1, +        "contentHash" => $contentHash, +        "created" => time(), +    ], JSON_UNESCAPED_SLASHES)); +    readfile($cacheFileData);  } elseif ($_action === "deletepost") {      RequestUtils::ensureRequestMethod("POST"); @@ -504,7 +657,7 @@ if ($_action === "auth") {      $post = new Post();      $post->id = $postId; -    if (!$db->fetch($post)) { +    if (!$db->fetch($post) || $post->deleted) {          http_response_code(404);          Messaging::error("No post exists with this id");          exit; @@ -525,6 +678,8 @@ if ($_action === "auth") {          exit;      } +    $attachments = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $post->id ]); +      $confirm = $_POST["confirm"] ?? null;      if ($confirm !== null) {          $expectedConfirm = base64_encode(hash("sha256", "confirm" . $post->id, true)); @@ -542,8 +697,6 @@ if ($_action === "auth") {              Messaging::error("Failed to delete post");              exit;          } - -        $attachments = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $post->id ]);          foreach ($attachments as $attachment) {              if (!$db->delete($attachment)) { @@ -559,7 +712,11 @@ if ($_action === "auth") {          _view("template_navigation_start");          _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]);          _view("template_navigation_end"); -        _view("form_delete_post_confirm", ["post" => $post]); +        _view("form_delete_post_confirm", [ +            "post" => $post, +            "postAuthor" => $postAuthor, +            "attachments" => $attachments, +        ]);          _view("template_end");      }  } elseif ($_action === null) { |