Files
4WDCSA.co.za/add_campsite.php
twotalesanimation b120415d53 Task 10: Harden file upload validation
Enhanced validateFileUpload() function in functions.php with comprehensive security:
- Hardcoded MIME type whitelist per file type (profile_picture, proof_of_payment, document)
- Strict file size limits per type (5MB images, 10MB documents)
- Extension validation against whitelist
- Double extension prevention (e.g., shell.php.jpg)
- MIME type verification using finfo
- Image validation with getimagesize()
- is_uploaded_file() verification
- Random filename generation to prevent path traversal

Updated file upload handlers:
- upload_profile_picture.php - Profile picture uploads (JPEG, PNG, GIF, WEBP, 5MB max)
- submit_pop.php - Proof of payment uploads (PDF only, 10MB max) + CSRF validation + audit logging
- add_campsite.php - Campsite thumbnail uploads + input validation + CSRF validation + audit logging

Security improvements:
- All uploads use random filenames to prevent directory traversal
- All uploads use secure file permissions (0644)
- File validation occurs before move_uploaded_file()
- Comprehensive error logging for failed uploads
- Audit logging for successful file operations
2025-12-03 13:30:45 +02:00

95 lines
3.3 KiB
PHP

<?php include_once('connection.php');
include_once('functions.php');
require_once("env.php");
session_start();
$user_id = $_SESSION['user_id'] ?? null;
// CSRF Token Validation
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
http_response_code(403);
die('Security token validation failed. Please try again.');
}
// campsites.php
$conn = openDatabaseConnection();
// Get text inputs
$name = validateName($_POST['name'] ?? '') ?: '';
$desc = isset($_POST['description']) ? htmlspecialchars($_POST['description'], ENT_QUOTES, 'UTF-8') : '';
$lat = isset($_POST['latitude']) ? floatval($_POST['latitude']) : 0.0;
$lng = isset($_POST['longitude']) ? floatval($_POST['longitude']) : 0.0;
$website = isset($_POST['website']) ? filter_var($_POST['website'], FILTER_VALIDATE_URL) : '';
$telephone = validatePhoneNumber($_POST['telephone'] ?? '') ?: '';
if (empty($name)) {
http_response_code(400);
die('Campsite name is required.');
}
// Handle file upload
$thumbnailPath = null;
if (isset($_FILES['thumbnail']) && $_FILES['thumbnail']['error'] !== UPLOAD_ERR_NO_FILE) {
// Validate file using hardened validation function
$validationResult = validateFileUpload($_FILES['thumbnail'], 'profile_picture');
if ($validationResult === false) {
http_response_code(400);
die('Invalid thumbnail image. Only JPG, JPEG, PNG, GIF, and WEBP images under 5MB are allowed.');
}
$uploadDir = "assets/uploads/campsites/";
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
if (!is_writable($uploadDir)) {
http_response_code(500);
die('Upload directory is not writable.');
}
$randomFilename = $validationResult['filename'];
$targetFile = $uploadDir . $randomFilename;
if (move_uploaded_file($_FILES["thumbnail"]["tmp_name"], $targetFile)) {
chmod($targetFile, 0644);
$thumbnailPath = $targetFile;
} else {
http_response_code(500);
die('Failed to move uploaded file.');
}
}
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
if ($id > 0) {
// UPDATE
if ($thumbnailPath) {
$stmt = $conn->prepare("UPDATE campsites SET name=?, description=?, latitude=?, longitude=?, website=?, telephone=?, thumbnail=? WHERE id=?");
$stmt->bind_param("ssddsssi", $name, $desc, $lat, $lng, $website, $telephone, $thumbnailPath, $id);
} else {
$stmt = $conn->prepare("UPDATE campsites SET name=?, description=?, latitude=?, longitude=?, website=?, telephone=? WHERE id=?");
$stmt->bind_param("ssddssi", $name, $desc, $lat, $lng, $website, $telephone, $id);
}
// Log the action
auditLog($user_id, 'CAMPSITE_UPDATE', 'campsites', $id, ['name' => $name]);
} else {
// INSERT
$stmt = $conn->prepare("INSERT INTO campsites (name, description, latitude, longitude, website, telephone, thumbnail, user_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param("ssddsssi", $name, $desc, $lat, $lng, $website, $telephone, $thumbnailPath, $user_id);
// Log the action
auditLog($user_id, 'CAMPSITE_CREATE', 'campsites', 0, ['name' => $name]);
}
if (!$stmt->execute()) {
http_response_code(500);
die('Database error: ' . $stmt->error);
}
$stmt->close();
header("Location: campsites.php");
?>