<?php
if($_SERVER['REQUEST_METHOD'] !== 'POST'){
http_response_code(405);
die("Should be a POST request");
}
$message = trim($_POST["message"] ?? "");
// Check if the message is too long for mysql text type
if(strlen($message) >= 65535){
http_response_code(400);
die("Message is too long");
}
// Check uploaded files
$images = $_FILES['attachments'] ?? [];
$valid_images = [];
$max_images = 4; // Maximum number of images allowed per post
$allowed_file_types = [
"image/jpeg" => "jpg",
"image/png" => "png"
];
$max_file_size = 2_000_000; // 2MB
// Validate all uploaded images
if(!empty($images['name'][0])) { // Check if any files were uploaded
// Ensure we don't exceed max images
if(count($images['name']) > $max_images) {
http_response_code(400);
die("Too many images uploaded, maximum is $max_images");
}
foreach($images['error'] as $index => $error) {
if($error === UPLOAD_ERR_NO_FILE) continue;
if($error !== UPLOAD_ERR_OK) {
http_response_code(400);
die("Image upload failed for file #$index, code $error");
}
if($images['size'][$index] >= $max_file_size) {
http_response_code(413);
$max_file_size_mb = $max_file_size/1_000_000;
die("Image #$index is too big, max size is $max_file_size_mb MB");
}
$mime_type = mime_content_type($images['tmp_name'][$index]);
if(!isset($allowed_file_types[$mime_type])) {
http_response_code(415);
die("Image #$index is not a supported type, supported: " . implode(',', $allowed_file_types));
}
$valid_images[] = [
'tmp_name' => $images['tmp_name'][$index],
'ext' => $allowed_file_types[$mime_type],
'size' => $images['size'][$index]
];
}
}
// Check if we have any content (message or images)
if(strlen($message) === 0 && empty($valid_images)) {
http_response_code(400);
die("Post must contain either a message or at least one image");
}
require_once '../db/dbconn.php';
$parent = $_POST["parent"] ?? NULL;
// Begin transaction for atomic operations
$db->beginTransaction();
try {
// Update parent bumptime and verify existence
if($parent !== NULL) {
$stmt = $db->prepare('UPDATE Posts SET BumpTime = CURRENT_TIMESTAMP WHERE ID = :parent');
$stmt->execute(['parent' => $parent]);
if($stmt->rowCount() != 1) {
$db->rollBack();
http_response_code(500);
die("Upload failed: parent post not found");
}
}
// Insert the post
$stmt = $db->prepare('INSERT INTO Posts (Message, ParentID) VALUES (:message, :parent)');
$succ = $stmt->execute(['message' => $message, 'parent' => $parent]);
if(!$succ) {
$db->rollBack();
http_response_code(500);
die("Upload failed");
}
$post_id = $db->lastInsertId();
$img_dir = "./img";
// Handle image uploads
if(!empty($valid_images)) {
if(!is_dir($img_dir)) {
mkdir($img_dir, 0777, true);
}
$image_stmt = $db->prepare(
'INSERT INTO Images (PostID, ImageExt, FileName) VALUES (:post_id, :ext, :filename)'
);
foreach($valid_images as $index => $image) {
$filename = "{$post_id}_" . uniqid() . ".{$image['ext']}";
$destination = "$img_dir/$filename";
if(!move_uploaded_file($image['tmp_name'], $destination)) {
$db->rollBack();
http_response_code(500);
die("Failed to save image #$index");
}
// Store image metadata in database
$image_stmt->execute([
'post_id' => $post_id,
'ext' => $image['ext'],
'filename' => $filename
]);
}
}
$db->commit();
} catch(Exception $e) {
$db->rollBack();
http_response_code(500);
die("Upload failed: " . $e->getMessage());
}
// Redirect user to see the new post
http_response_code(303);
header("Location: /view_post.php?post=" . $post_id);
?>
<?php
echo '
<form method="POST" enctype="multipart/form-data">
<textarea name="message"></textarea>
<input type="file" name="attachment[]" multiple accept="image/jpeg,image/png">
<input type="submit" value="Post">
</form>
';
?>