diff options
| author | Jonas Kohl | 2024-09-16 19:32:09 +0200 | 
|---|---|---|
| committer | Jonas Kohl | 2024-09-16 19:32:09 +0200 | 
| commit | 6b7e714b59e28bc138681662006941274c3261af (patch) | |
| tree | c683082c0a00681542db02d415bd45968f0a517b /src/index.php | |
| parent | fd3d969cf658475709db6a1e5090069cce51cbbd (diff) | |
A lot more stuff
Diffstat (limited to 'src/index.php')
| -rw-r--r-- | src/index.php | 286 | 
1 files changed, 215 insertions, 71 deletions
| diff --git a/src/index.php b/src/index.php index de46204..a42aa19 100644 --- a/src/index.php +++ b/src/index.php @@ -1,5 +1,8 @@  <?php +use FFMpeg\Coordinate\TimeCode; +use FFMpeg\FFMpeg; +use FFMpeg\FFProbe;  use Gregwar\Captcha\CaptchaBuilder;  use mystic\forum\Database;  use mystic\forum\exceptions\DatabaseConnectionException; @@ -23,11 +26,6 @@ if (($_SERVER["HTTP_USER_AGENT"] ?? "") === "") {      exit;  } -// 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", isTrue(env("REGISTRATION_ENABLED") ?? ""));  session_name("fsid"); @@ -44,6 +42,26 @@ $_action = $_GET["_action"] ?? null;  $GLOBALS["action"] = $_action; +function msg_error(string $err, bool $skipLoginCheck = false): void { +    _view("template_start", ["_title" => __("Error")]); +    _view("template_navigation_start"); +    if (!$skipLoginCheck) +        _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($GLOBALS["db"])]); +    _view("template_navigation_end"); +    _view("alert_error", ["message" => $err]); +    _view("template_end"); +} + +function msg_info(string $msg, bool $skipLoginCheck = false): void { +    _view("template_start", ["_title" => __("Information")]); +    _view("template_navigation_start"); +    if (!$skipLoginCheck) +        _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($GLOBALS["db"])]); +    _view("template_navigation_end"); +    _view("alert_info", ["message" => $msg]); +    _view("template_end"); +} +  function generateCaptchaText(): string {      $phrase = "";      for ($i = 0; $i < CAPTCHA_PHRASE_LENGTH; ++$i) @@ -124,18 +142,35 @@ function env(string $key): ?string {  }  require_once __DIR__ . "/vendor/autoload.php"; -  require_once __DIR__ . "/application/i18n.php"; -i18n_locale("de"); + +if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["lang"])) { +    parse_str($_SERVER["QUERY_STRING"], $query); +    if (empty($query["lang"])) { +        setcookie("lang", "", 100); +    } else { +        setcookie("lang", $query["lang"], time()+60*60*24*30); +    } +    unset($query["lang"]); +    $path = strtok($_SERVER["REQUEST_URI"], "?"); +    header("Location: $path?" . http_build_query($query)); +    exit; +} + +$user_locale = env("LOCALE") ?? $_COOKIE["lang"] ?? locale_accept_from_http($_SERVER["HTTP_ACCEPT_LANGUAGE"] ?? ""); +$chosen_locale = locale_lookup(i18n_get_available_locales(), $user_locale, true, "en"); +i18n_locale($user_locale);  $db = null;  try {      $db = new Database(Database::getConnectionString("db", getenv("POSTGRES_USER"), getenv("POSTGRES_PASSWORD"), getenv("POSTGRES_DBNAME")));  } catch (DatabaseConnectionException $ex) { -    Messaging::error([ -        Messaging::bold(__("Failed to connect to database!")), -        Messaging::italic($ex->getMessage()), -    ]); +    msg_error( +        __("Failed to connect to database:\n%details%", [ +            "details" => $ex->getMessage(), +        ]), +        true +    );      exit;  } @@ -217,7 +252,7 @@ if ($_action === "auth") {      if (!REGISTRATION_ENABLED) {          http_response_code(403); -        Messaging::error(__("Public registration disabled")); +        msg_error(__("Public registration disabled"));          exit;      } @@ -308,9 +343,7 @@ if ($_action === "auth") {          $db->insert($user); -        Messaging::info( -            Messaging::html(nl2br(htmlentities(__("Your account has been created!\nPlease check your emails for an activation link!"), true))) -        ); +        msg_info(__("Your account has been created!\nPlease check your emails for an activation link!"));      } else {          _view("template_start", ["_title" => __("Register")]);          _view("template_navigation_start"); @@ -330,7 +363,7 @@ if ($_action === "auth") {      if (!$db->fetchWhere($user, [ "activated", "activation_token" ])) {          http_response_code(400); -        Messaging::error(__("Invalid token")); +        msg_error(__("Invalid token"));          exit;      } @@ -338,7 +371,7 @@ if ($_action === "auth") {      if ($expectedSignature !== $sig) {          http_response_code(400); -        Messaging::error(__("Invalid signature.")); +        msg_error(__("Invalid signature."));          exit;      } @@ -347,19 +380,17 @@ if ($_action === "auth") {      if (!$db->update($user)) {          http_response_code(400); -        Messaging::error(__("Failed to update user")); +        msg_error(__("Failed to update user"));          exit;      } -    Messaging::info([ -        Messaging::html(nl2br(__( -                "Your account has been activated!\nPlease click %link%here%/link% to log in!", -                [ -                    "link" => '<a href="?_action=auth">', -                    "/link" => '</a>', -                ] -        )), true), -    ]); +    msg_info("?!HTML::" . __( +        "Your account has been activated!\nPlease click %link%here%/link% to log in!", +        [ +            "link" => '<a href="?_action=auth">', +            "/link" => '</a>', +        ] +    ));  } elseif ($_action === "logout") {      RequestUtils::unsetAuthorizedUser();      header("Location: " . ($_GET["next"] ?? ".")); @@ -369,14 +400,14 @@ if ($_action === "auth") {      $topic->id = $topicId;      if (!$db->fetch($topic)) {          http_response_code(404); -        Messaging::error("No topic exists with this id"); +        msg_error("No topic exists with this id");          exit;      }      if (RequestUtils::isRequestMethod("POST")) {          if (!$currentUser) {              http_response_code(403); -            Messaging::error("You need to be logged in to add new posts!"); +            msg_error("You need to be logged in to add new posts!");              exit;          } @@ -447,8 +478,8 @@ if ($_action === "auth") {          /** @var Post $post */          foreach ($posts as $post) { -            /** @var ?User $topicAuthor */ -            $topicAuthor = null; +            /** @var ?User $postAuthor */ +            $postAuthor = null;              if ($post->authorId !== null && !isset($userCache[$post->authorId])) {                  $usr = new User();                  $usr->id = $post->authorId; @@ -456,13 +487,14 @@ if ($_action === "auth") {                      $userCache[$post->authorId] = &$usr;              }              if (isset($userCache[$post->authorId])) -                $topicAuthor = &$userCache[$post->authorId]; +                $postAuthor = &$userCache[$post->authorId];              $attachments = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $post->id ]);              _view("view_post", [                  "post" => $post, -                "postAuthor" => $topicAuthor, +                "postAuthor" => $postAuthor, +                "topicAuthor" => $topicAuthor,                  "attachments" => $attachments,              ]);          } @@ -479,7 +511,7 @@ if ($_action === "auth") {  } elseif ($_action === "newtopic") {      if (!$currentUser) {          http_response_code(403); -        Messaging::error("You need to be logged in to create new topics!"); +        msg_error("You need to be logged in to create new topics!");          exit;      } @@ -560,7 +592,7 @@ if ($_action === "auth") {      if (!$db->fetchWhere($user, "name")) {          http_response_code(404); -        Messaging::error(__("No user with name @%user_handle%", [ "user_handle" => $userHandle ])); +        msg_error(__("No user with name @%user_handle%", [ "user_handle" => $userHandle ]));          exit;      } @@ -571,7 +603,7 @@ if ($_action === "auth") {      $user->id = $userId;      if (!$db->fetch($user)) {          http_response_code(404); -        Messaging::error(__("No user exists with this id")); +        msg_error(__("No user exists with this id"));          exit;      } @@ -646,14 +678,16 @@ if ($_action === "auth") {      } else {          $posts = $db->fetchCustom(Post::class, 'WHERE author_id = $1 ORDER BY post_date DESC', [ $userId ]);          $topics = []; +        $attachments = [];          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; +            if (!isset($topics[$post->topicId])) { +                $topic = new Topic(); +                $topic->id = $post->topicId; +                if ($db->fetch($topic)) +                    $topics[$post->topicId] = $topic; +            } +            $attachs = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $post->id ]); +            $attachments[$post->id] = $attachs;          }          _view("template_start", ["_title" => $user->displayName]);          _view("template_navigation_start"); @@ -663,6 +697,7 @@ if ($_action === "auth") {              "user" => $user,              "posts" => $posts,              "topics" => $topics, +            "attachments" => $attachments,              "lastNameChangeTooRecent" => $lastNameChangeTooRecent,          ]);          _view("template_end"); @@ -670,7 +705,7 @@ if ($_action === "auth") {  } elseif ($_action === "attachment") {      if (!$currentUser) {          http_response_code(403); -        Messaging::error(__("You must be logged in to view attachments")); +        msg_error(__("You must be logged in to view attachments"));          exit;      } @@ -679,7 +714,7 @@ if ($_action === "auth") {      $attachment->id = $attId;      if (!$db->fetch($attachment)) {          http_response_code(404); -        Messaging::error(__("No attachment exists with this id")); +        msg_error(__("No attachment exists with this id"));          exit;      } @@ -710,7 +745,7 @@ if ($_action === "auth") {      $user->id = $userId;      if (!$db->fetch($user)) {          http_response_code(404); -        Messaging::error(__("No user exists with this id")); +        msg_error(__("No user exists with this id"));          exit;      } @@ -747,13 +782,16 @@ if ($_action === "auth") {      $attachment->id = $attId;      if (!$db->fetch($attachment)) {          http_response_code(404); -        Messaging::error(__("No attachment exists with this id")); +        msg_error(__("No attachment exists with this id"));          exit;      } -    if (!str_starts_with($attachment->mimeType, "image/")) { +    $isImage = str_starts_with($attachment->mimeType, "image/"); +    $isVideo = str_starts_with($attachment->mimeType, "video/"); + +    if (!$isImage && !$isVideo) {          http_response_code(400); -        Messaging::error(__("Attachment is not an image")); +        msg_error(__("Attachment is neither an image nor a video"));          exit;      } @@ -772,13 +810,41 @@ if ($_action === "auth") {          if ($info->contentHash === $contentHash) {              header("Content-Type: image/jpeg");              header("Cache-Control: max-age=86400"); -            header("X-Debug-Content: $cacheFileData"); +            //header("X-Debug-Content: $cacheFileData");              readfile($cacheFileData);              exit;          }      } -    $im = imagecreatefromstring($attachment->contents); +    if ($isVideo) { +        $suffix = (microtime(true) * 1000) . "-" . random_int(0, 99999); +        $tempVid = sys_get_temp_dir() . "/video_" . $suffix; +        file_put_contents($tempVid, $attachment->contents); +        $tempImg = sys_get_temp_dir() . "/image_" . $suffix . ".jpg"; + +        try { +            $ffprobe = FFProbe::create(); +            /** @var string $duration */ +            $duration = $ffprobe +                ->format($tempVid) +                ->get("duration", "0"); + +            $screenshotFramePoint = TimeCode::fromSeconds(floatval($duration) / 2.0); +             +            $ffmpeg = FFMpeg::create(); +            $video = $ffmpeg->open($tempVid); +            $screenshot = $video +                ->frame($screenshotFramePoint) +                ->save($tempImg); +            $im = imagecreatefromjpeg($tempImg); +        } finally { +            if (is_file($tempVid)) unlink($tempVid); +            if (is_file($tempImg)) unlink($tempImg); +        } +    } elseif ($isImage) { +        $im = imagecreatefromstring($attachment->contents); +    } +          $w = imagesx($im);      $h = imagesy($im);      $r = $w / floatval($h); @@ -810,7 +876,7 @@ if ($_action === "auth") {      if (!$currentUser) {          http_response_code(403); -        Messaging::error("You need to be logged in to delete posts!"); +        msg_error("You need to be logged in to delete posts!");          exit;      } @@ -821,7 +887,7 @@ if ($_action === "auth") {      if (!$db->fetch($post) || $post->deleted) {          http_response_code(404); -        Messaging::error("No post exists with this id"); +        msg_error("No post exists with this id");          exit;      } @@ -836,7 +902,7 @@ if ($_action === "auth") {      if (!$canEdit) {          http_response_code(403); -        Messaging::error("You don't have permission to delete this post"); +        msg_error("You don't have permission to delete this post");          exit;      } @@ -847,7 +913,7 @@ if ($_action === "auth") {          $expectedConfirm = base64_encode(hash("sha256", "confirm" . $post->id, true));          if ($confirm !== $expectedConfirm) {              http_response_code(400); -            Messaging::error("Invalid confirmation"); +            msg_error("Invalid confirmation");              exit;          } @@ -856,14 +922,14 @@ if ($_action === "auth") {          if (!$db->update($post)) {              http_response_code(500); -            Messaging::error("Failed to delete post"); +            msg_error("Failed to delete post");              exit;          }          foreach ($attachments as $attachment) {              if (!$db->delete($attachment)) {                  http_response_code(500); -                Messaging::error("Failed to delete attachment"); +                msg_error("Failed to delete attachment");                  exit;              }          } @@ -886,7 +952,7 @@ if ($_action === "auth") {      if (!$currentUser) {          http_response_code(403); -        Messaging::error("You need to be logged in to update posts!"); +        msg_error(__("You need to be logged in to update posts!"));          exit;      } @@ -898,7 +964,7 @@ if ($_action === "auth") {      if (!$db->fetch($post) || $post->deleted) {          http_response_code(404); -        Messaging::error("No post exists with this id"); +        msg_error(__("No post exists with this id"));          exit;      } @@ -913,7 +979,7 @@ if ($_action === "auth") {      if (!$canEdit) {          http_response_code(403); -        Messaging::error("You don't have permission to edit this post"); +        msg_error(__("You don't have permission to edit this post"));          exit;      } @@ -924,7 +990,7 @@ if ($_action === "auth") {      if (!$db->update($post)) {          http_response_code(500); -        Messaging::error("Failed to update post"); +        msg_error(__("Failed to update post"));          exit;      } @@ -934,7 +1000,7 @@ if ($_action === "auth") {      if (!$currentUser) {          http_response_code(403); -        Messaging::error("You need to be logged in to delete topics!"); +        msg_error(__("You need to be logged in to delete topics!"));          exit;      } @@ -945,7 +1011,7 @@ if ($_action === "auth") {      if (!$db->fetch($topic)) {          http_response_code(404); -        Messaging::error("No topic exists with this id"); +        msg_error(__("No topic exists with this id"));          exit;      } @@ -960,7 +1026,7 @@ if ($_action === "auth") {      if (!$canEdit) {          http_response_code(403); -        Messaging::error("You don't have permission to delete this topic"); +        msg_error(__("You don't have permission to delete this topic"));          exit;      } @@ -969,13 +1035,13 @@ if ($_action === "auth") {          $expectedConfirm = base64_encode(hash("sha256", "confirm" . $topic->id, true));          if ($confirm !== $expectedConfirm) {              http_response_code(400); -            Messaging::error("Invalid confirmation"); +            msg_error(__("Invalid confirmation"));              exit;          }          if (!$db->delete($topic)) {              http_response_code(500); -            Messaging::error("Failed to delete topic"); +            msg_error(__("Failed to delete topic"));              exit;          } @@ -996,7 +1062,7 @@ if ($_action === "auth") {      if (!$currentUser) {          http_response_code(403); -        Messaging::error("You need to be logged in to update topics!"); +        msg_error(__("You need to be logged in to update topics!"));          exit;      } @@ -1008,7 +1074,7 @@ if ($_action === "auth") {      if (!$db->fetch($topic)) {          http_response_code(404); -        Messaging::error("No topic exists with this id"); +        msg_error(__("No topic exists with this id"));          exit;      } @@ -1023,7 +1089,7 @@ if ($_action === "auth") {      if (!$canEdit) {          http_response_code(403); -        Messaging::error("You don't have permission to update this topic"); +        msg_error(__("You don't have permission to update this topic"));          exit;      } @@ -1031,7 +1097,7 @@ if ($_action === "auth") {      if (!$db->update($topic)) {          http_response_code(500); -        Messaging::error("Failed to update topic"); +        msg_error(__("Failed to update topic"));          exit;      } @@ -1045,6 +1111,84 @@ if ($_action === "auth") {      header("Pragma: no-cache");      header("Cache-Control: no-cache");      $builder->save(null, 40); +} elseif ($_action === "ji18n") { +    header("Content-Type: application/javascript; charset=UTF-8"); +    echo 'var I18N_MESSAGES = ' . json_encode(i18n_get_message_store(i18n_get_current_locale()), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ";\n"; +} elseif ($_action === "ctheme") { +    // options +    $enableLogging = true; +    $etag_strip_gzip_suffix = true; + +    $cssFatal = function(string $msg): never { +        if (!headers_sent()) +            http_response_code(500); +        echo "/*!FATAL $msg */\n"; +        exit; +    }; +    $cssError = function(string &$buffer, string $msg) use($enableLogging): void { +        if ($enableLogging) +            $buffer .= "/*!ERROR $msg */\n"; +    }; +    $cssWarning = function(string &$buffer, string $msg) use ($enableLogging): void { +        if ($enableLogging) +            $buffer .= "/*!WARN $msg */\n"; +    }; + +    $buffer = ""; + +    header("Content-Type: text/css; charset=UTF-8"); +    header("Cache-Control: no-cache"); +    // Disable Apache's gzip filter, as it interferes with our ETag +    // (Apache adds '-gzip' as a ETag suffix) +    if (!$etag_strip_gzip_suffix) +        apache_setenv('no-gzip', '1'); + +    $themeName = $_GET["theme"] ?? $_COOKIE["theme"] ?? env("MYSTIC_FORUM_THEME") ?? "default"; +    if (!preg_match('/^[a-z0-9_-]+$/i', $themeName)) { +        $cssWarning($buffer, "Invalid theme '" . str_replace('*/', '*\\/', $themeName) . "'"); +        $cssWarning($buffer, "Loading default theme"); +        $themeName = "default"; +    } +    $themePath = __DIR__ . '/themes/' . $themeName . '/theme.json'; +    $themeDefaultPath = __DIR__ . '/themes/default/theme.json'; +    if (!is_file($themePath) && is_file($themeDefaultPath)) { +        $cssWarning($buffer, "Invalid theme '" . str_replace('*/', '*\\/', $themeName) . "'"); +        $cssWarning($buffer, "Loading default theme"); +        $themePath = $themeDefaultPath; +    } elseif (!is_file($themePath) && !is_file($themeDefaultPath)) { +        $cssFatal("Failed to load default theme"); +    } +    $themeDir = dirname($themePath); +    $theme = json_decode(file_get_contents($themePath)); +    if ($theme->{'$format'} !== 1) +        $cssFatal("Invalid theme format"); +    foreach ($theme->files as $file) { +        if (is_array($file)) { +            if ($enableLogging) $buffer .= "/*!INLINE start */\n"; +            $buffer .= implode("\n", $file); +            if ($enableLogging) $buffer .= "/*!INLINE end */\n"; +        } elseif (is_file($filePath = $themeDir . "/" . $file)) { +            if ($enableLogging) $buffer .= "/*!INCLUDE " . basename($file) . " */\n"; +            $buffer .= file_get_contents($filePath); +            if ($enableLogging) $buffer .= "/*!INCLUDE end */\n"; +        } else +            $cssError($buffer, "Could not include file $file"); +    } +    $etag = md5($buffer); + +    $ifNoneMatch = $_SERVER["HTTP_IF_NONE_MATCH"] ?? null; +    if ($ifNoneMatch !== null) { +        $ifNoneMatch = trim($ifNoneMatch, '"'); +        if ($etag_strip_gzip_suffix) +            $ifNoneMatch = preg_replace('/-gzip$/', '', $ifNoneMatch); +    } + +    header("ETag: \"$etag\""); +    if ($ifNoneMatch === $etag) +        http_response_code(304); +    else +        echo $buffer; +  } elseif ($_action === null) {      _view("template_start");      _view("template_navigation_start"); @@ -1054,5 +1198,5 @@ if ($_action === "auth") {      _view("template_end");  } else {      http_response_code(404); -    Messaging::error("Invalid or unknown action $_action"); +    msg_error(__("Invalid or unknown action $_action"));  } |