$maxTagLength) return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "tag too large: $currTag"); } } $preg_str = "/[^" . $allowedSymbols . "]/"; foreach ($result as $tag) { if (preg_match($preg_str, $tag)) return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "only allowed symbols in tags are: " . $allowedSymbols); } return new ReturnT(data: $result); } /* * FUNCTION * Check if image size properties are valid */ function Post_ImgResIsValid ($x, $y): bool { global $Config; return ($x <= $Config["media"]["max_pic_res"]["x"]) && ($y <= $Config["media"]["max_pic_res"]["y"]) && (Utils_GetRatio($x, $y) <= $Config["media"]["max_pic_res"]["ratio"]); } /* * FUNCTION * Create preview version of image */ function Post_CreatePreviewFromImage (string $src, string $dst): ReturnT { $img = null; // Reading image from source path switch (mime_content_type($src)) { case "image/jpeg": $img = imagecreatefromjpeg($src); break; case "image/png": $img = imagecreatefrompng($src); break; default: return new ReturnT(err_code: E_UIN_FILETYPE, err_desc: "invalid mime type"); } // Saving it as LQ JPEG imagejpeg($img, $dst, 30); if (!file_exists($dst)) // $src isnt our responsibility, $dst is return new ReturnT(err_code: E_UNS_UNEXPECTED, err_desc: "failed to create preview"); return new ReturnT(data: true); } /* * FUNCTION * Stores image and returns paths to picture and its preview */ function Post_StoreImage (string $path): ReturnT { global $Config; // Paths $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); $fileName = strval(time()) . "_" . GenerateRandomString(4); $targetDir = "../../" . $Config["media"]["pics_path"]; $targetPath = Utils_JoinPaths($targetDir, $fileName . "." . $ext); // Creating preview file if ($Config["media"]["previews_enabled"]) { $previewDir = "../../" . $Config["media"]["prevs_path"]; $previewPath = Utils_JoinPaths($previewDir, $fileName . ".jpg"); $res = Post_CreatePreviewFromImage($path, $previewPath); if ($res->IsError()) // $path isnt our responsibility return $res; } move_uploaded_file($path, $targetPath); if (!file_exists($targetPath)) { // however, $previewPath IS our responsibility unlink($previewPath); return new ReturnT(err_code: E_UNS_UNEXPECTED, err_desc: "failed to move uploaded file"); } return new ReturnT(data: array( "preview" => $previewPath, "picture" => $targetPath )); } /* * FUNCTION * Create single publication */ function Post_Create ( int $author_id, string $tags, string $pic_path, ?string $title = null, ?string $prev_path = null, bool $comms_enabled = false, bool $edit_lock = false ): ReturnT { global $db; $result = null; // Author ID must exist if (!User_IDExist($author_id)) return new ReturnT(err_code: E_UIN_WRONGID, err_desc: "specified user id does not exist"); // Performing SQL query $s = $db->prepare("INSERT INTO posts (author_id,comment_section_id,tags,title,pic_path,preview_path,comments_enabled,edit_lock) VALUES (?,?,?,?,?,?,?,?)"); $s->bind_param("ssssssss", $author_id, null, $tags, $title, $pic_path, $prev_path, $comms_enabled, $edit_lock); if ($s->execute() === false) return new ReturnT(err_code: E_DBE_INSERTFAIL, err_desc: "failed to create post record in DB"); $result = true; return new ReturnT(data: $result); } // Methods /* * METHOD * Create single publication */ function Post_Create_Method (array $req, array $files): ReturnT { global $Config, $LOGGED_IN, $THIS_USER; $author_id = $THIS_USER; $tags = null; $pic_path = null; $title = null; $prev_path = null; $comms_enabled = false; // Input sanity checks // Check if user is authenticated if (!$LOGGED_IN) return new ReturnT(err_code: E_AUT_NOTAUTHED, err_desc: "you must be logged in to create posts"); // Check if there are necessary input if (!(isset($req["tags"]) && isset($files["pic"]))) return new ReturnT(err_code: E_UIN_INSUFARGS, err_desc: "tags and picture are necessary"); // Check tags // If raw string length not fits into limit $tagsLen = strlen($req["tags"]); if ($tagsLen > $Config["posting"]["tags"]["max_raw_input_str_length"]) return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "tags string length exceeds limit: " . strval($Config["posting"]["tags"]["max_raw_input_str_length"])); elseif ($tagsLen < 1) return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "tags cant be empty"); // TODO: check if it is ASCII string // Parsing tags $parsedTags = Post_ParseRawTagString($req["tags"]); if ($parsedTags->IsError()) return $parsedTags; // TODO: check if tags are approved $tags = implode(",", $parsedTags); // Check user role TODO: add rate-limiting, instead of this if (User_HasRole($THIS_USER, "newbie")->GetData()) return new ReturnT(err_code: E_ACS_INSUFROLE, err_desc: "newbies cant create posts"); // Check image properties // If size is too large if ($files["pic"]["size"] > $Config["media"]["max_pic_size"]) return new ReturnT(err_code: E_UIN_FILE2LARGE, err_desc: "picture size is too large"); $TmpFilePath = $_FILES["pic"]["tmp_name"]; $Ext = strtolower(pathinfo($TmpFilePath, PATHINFO_EXTENSION)); // If file extension is not in list of allowed if (!in_array($Ext, $Config["media"]["allowed_exts"])) return new ReturnT(err_code: E_UIN_FILETYPE, err_desc: "picture extension is invalid"); // If file mime type is not in list of allowed if (!in_array(mime_content_type($TmpFilePath), $Config["media"]["allowed_mimetypes"])) return new ReturnT(err_code: E_UIN_FILETYPE, err_desc: "picture mime type is invalid"); // Check if resolution is bigger than allowed or have unacceptable aspect ratio list($SzX, $SzY, $Type, $Attr) = getimagesize($TmpFilePath); if (!Post_ImgResIsValid($SzX, $SzY)) return new ReturnT(err_code: E_UIN_IMGBADRES, err_desc: "image with that resolution or aspect ratio cant be accepted"); // Actions // Copy picture to storage folder $res = Post_StoreImage($TmpFilePath); if ($res->IsError()) { // $TmpFilePath seemingly isnt our responsibility, BUT, only we know how and what to cleanup unlink($TmpFilePath); return $res; } $pic_path = $res["picture"]; $prev_path = $res["preview"]; return Post_Create($author_id, $tags, $pic_path, $title, $prev_path, $comms_enabled, false); } if (Utils_ThisFileIsRequested(__FILE__)) { require_once("../_json.php"); // TODO } ?>