summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--database.sql5
-rw-r--r--public/emotes/upload.php112
-rw-r--r--src/images.php48
-rw-r--r--src/utils.php33
5 files changed, 199 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 696fd05..c5801c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
/.vscode
-/userdata
+userdata/
*.db \ No newline at end of file
diff --git a/database.sql b/database.sql
new file mode 100644
index 0000000..b4da2c1
--- /dev/null
+++ b/database.sql
@@ -0,0 +1,5 @@
+CREATE TABLE IF NOT EXISTS "emotes" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "code" TEXT NOT NULL,
+ "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+); \ No newline at end of file
diff --git a/public/emotes/upload.php b/public/emotes/upload.php
new file mode 100644
index 0000000..e68aea4
--- /dev/null
+++ b/public/emotes/upload.php
@@ -0,0 +1,112 @@
+<?php
+function abort_upload(string $path, SQLite3 $db, string $id, string $response_text, int $response_code = 400)
+{
+ $stmt = $db->prepare("DELETE FROM emotes WHERE id = :id");
+ $stmt->bindValue(":id", $id, SQLITE3_INTEGER);
+ $stmt->execute();
+ $db->close();
+
+ array_map("unlink", glob("$path/*.*"));
+ rmdir($path);
+ http_response_code($response_code);
+ exit($response_text);
+}
+
+include "../../src/utils.php";
+include "../../src/images.php";
+
+if ($_SERVER['REQUEST_METHOD'] != "POST") {
+ echo 'imagine there is a page';
+ exit;
+}
+
+if (!isset($_FILES["file"])) {
+ http_response_code(400);
+ echo json_encode([
+ "status_code" => 400,
+ "message" => "No file set",
+ "data" => null
+ ]);
+ exit;
+}
+
+$code = str_safe($_POST["code"] ?? "", 500);
+
+if ($code == "") {
+ http_response_code(400);
+ echo json_encode([
+ "status_code" => 400,
+ "message" => "Invalid code",
+ "data" => null
+ ]);
+ exit;
+}
+
+// creating a new emote record
+$db = new SQLite3("../../database.db");
+
+$stmt = $db->prepare("INSERT INTO emotes(code) VALUES (:code)");
+$stmt->bindValue(":code", $code);
+$results = $stmt->execute();
+
+$id = $db->lastInsertRowID();
+
+if ($id == 0) {
+ $db->close();
+ http_response_code(500);
+ echo json_encode([
+ "status_code" => 500,
+ "message" => "Failed to create an emote record",
+ "data" => null
+ ]);
+ exit;
+}
+
+$path = "../static/userdata/emotes/$id";
+
+if (!is_dir($path)) {
+ mkdir($path, 0777, true);
+}
+
+$image = $_FILES["file"];
+
+// resizing the image
+
+// TODO: make it configurable later
+$max_width = max(128, 1);
+$max_height = max(128, 1);
+
+// 3x image
+$resized_image = resize_image($image["tmp_name"], "$path/3x", $max_width, $max_height);
+if ($resized_image) {
+ abort_upload($path, $db, $id, $resized_image);
+}
+
+// 2x image
+$resized_image = resize_image($image["tmp_name"], "$path/2x", $max_width / 2, $max_height / 2);
+if ($resized_image) {
+ abort_upload($path, $db, $id, $resized_image);
+}
+
+// 1x image
+$resized_image = resize_image($image["tmp_name"], "$path/1x", $max_width / 4, $max_height / 4);
+if ($resized_image) {
+ abort_upload($path, $db, $id, $resized_image);
+}
+
+$db->close();
+
+if (isset($_SERVER["HTTP_ACCEPT"]) && $_SERVER["HTTP_ACCEPT"] == "application/json") {
+ http_response_code(201);
+ echo json_encode([
+ "status_code" => 201,
+ "message" => null,
+ "data" => [
+ "id" => $id,
+ "code" => $code
+ ]
+ ]);
+ exit;
+}
+
+header("Location: /emotes/$id", true, 307); \ No newline at end of file
diff --git a/src/images.php b/src/images.php
new file mode 100644
index 0000000..0e09814
--- /dev/null
+++ b/src/images.php
@@ -0,0 +1,48 @@
+<?php
+function resize_image(string $src_path, string $dst_path, int $max_width, int $max_height): string|null
+{
+ if ($src_path == "" || !getimagesize($src_path)) {
+ return json_encode([
+ "status_code" => 400,
+ "message" => "Not an image",
+ "data" => null
+ ]);
+ }
+
+ $imagick = new Imagick();
+
+ $imagick->readImage($src_path);
+ $format = strtolower($imagick->getImageFormat());
+
+ if ($imagick->getNumberImages() > 1) {
+ $imagick = $imagick->coalesceImages();
+
+ foreach ($imagick as $frame) {
+ $width = $frame->getImageWidth();
+ $height = $frame->getImageHeight();
+ $ratio = min($max_width / $width, $max_height / $height);
+ $new_width = (int) ($width * $ratio);
+ $new_height = (int) ($height * $ratio);
+
+ $frame->resizeImage($new_width, $new_height, Imagick::FILTER_TRIANGLE, 1);
+ $frame->setImagePage($new_width, $new_height, 0, 0);
+ }
+
+ $imagick = $imagick->deconstructImages();
+ $imagick->writeImages("$dst_path.$format", true);
+ } else {
+ $width = $imagick->getImageWidth();
+ $height = $imagick->getImageHeight();
+ $ratio = min($max_width / $width, $max_height / $height);
+ $new_width = (int) ($width * $ratio);
+ $new_height = (int) ($height * $ratio);
+
+ $imagick->resizeImage($new_width, $new_height, Imagick::FILTER_TRIANGLE, 1);
+ $imagick->writeImage("$dst_path.$format");
+ }
+
+ $imagick->clear();
+ $imagick->destroy();
+
+ return null;
+} \ No newline at end of file
diff --git a/src/utils.php b/src/utils.php
new file mode 100644
index 0000000..59ecad4
--- /dev/null
+++ b/src/utils.php
@@ -0,0 +1,33 @@
+<?php
+function generate_random_string(int $length): string
+{
+ $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ $output = "";
+
+ for ($i = 0; $i < $length; $i++) {
+ $charindex = random_int(0, strlen($chars) - 1);
+ $output .= $chars[$charindex];
+ }
+
+ return $output;
+}
+
+function str_safe(string $s, int|null $max_length, bool $remove_new_lines = true): string
+{
+ $output = $s;
+
+ if ($remove_new_lines) {
+ $output = str_replace(PHP_EOL, "", $output);
+ }
+
+ $output = htmlspecialchars($output);
+ $output = strip_tags($output);
+
+ if ($max_length) {
+ $output = substr($output, 0, $max_length);
+ }
+
+ $output = trim($output);
+
+ return $output;
+} \ No newline at end of file