Files
FileRise/src/controllers/uploadController.php

199 lines
7.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// src/controllers/uploadController.php
require_once __DIR__ . '/../../config/config.php';
require_once PROJECT_ROOT . '/src/models/UploadModel.php';
class UploadController {
/**
* @OA\Post(
* path="/api/upload/upload.php",
* summary="Handle file upload",
* description="Handles file uploads for both chunked and non-chunked (full) uploads. Validates CSRF, user authentication, and permissions, and processes file uploads accordingly. On success, returns a JSON status for chunked uploads or redirects for full uploads.",
* operationId="handleUpload",
* tags={"Uploads"},
* @OA\RequestBody(
* required=true,
* description="Multipart form data for file upload. For chunked uploads, include fields like 'resumableChunkNumber', 'resumableTotalChunks', 'resumableIdentifier', 'resumableFilename', etc.",
* @OA\MediaType(
* mediaType="multipart/form-data",
* @OA\Schema(
* required={"token", "fileToUpload"},
* @OA\Property(property="token", type="string", description="Share token or upload token."),
* @OA\Property(
* property="fileToUpload",
* type="string",
* format="binary",
* description="The file to upload."
* ),
* @OA\Property(property="resumableChunkNumber", type="integer", description="Chunk number for chunked uploads."),
* @OA\Property(property="resumableTotalChunks", type="integer", description="Total number of chunks."),
* @OA\Property(property="resumableFilename", type="string", description="Original filename."),
* @OA\Property(property="folder", type="string", description="Target folder (default 'root').")
* )
* )
* ),
* @OA\Response(
* response=200,
* description="File uploaded successfully (or chunk uploaded status).",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string", example="File uploaded successfully"),
* @OA\Property(property="newFilename", type="string", example="5f2d7c123a_example.png"),
* @OA\Property(property="status", type="string", example="chunk uploaded")
* )
* ),
* @OA\Response(
* response=302,
* description="Redirection on full upload success."
* ),
* @OA\Response(
* response=400,
* description="Bad Request (e.g., missing file, invalid parameters)"
* ),
* @OA\Response(
* response=401,
* description="Unauthorized"
* ),
* @OA\Response(
* response=403,
* description="Forbidden (e.g., invalid CSRF token, upload disabled)"
* ),
* @OA\Response(
* response=500,
* description="Server error during file processing"
* )
* )
*
* Handles file uploads, both chunked and full, and redirects upon success.
*
* @return void Outputs JSON response (for chunked uploads) or redirects on successful full upload.
*/
public function handleUpload(): void {
header('Content-Type: application/json');
//
// 1) CSRF pull from header or POST fields
//
$headersArr = array_change_key_case(getallheaders(), CASE_LOWER);
$received = '';
if (!empty($headersArr['x-csrf-token'])) {
$received = trim($headersArr['x-csrf-token']);
} elseif (!empty($_POST['csrf_token'])) {
$received = trim($_POST['csrf_token']);
} elseif (!empty($_POST['upload_token'])) {
$received = trim($_POST['upload_token']);
}
// 1a) If it doesnt match, soft-fail: send new token and let client retry
if (!isset($_SESSION['csrf_token']) || $received !== $_SESSION['csrf_token']) {
// regenerate
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// tell client “please retry with this new token”
http_response_code(200);
echo json_encode([
'csrf_expired' => true,
'csrf_token' => $_SESSION['csrf_token']
]);
exit;
}
//
// 2) Auth checks
//
if (empty($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) {
http_response_code(401);
echo json_encode(["error" => "Unauthorized"]);
exit;
}
$userPerms = loadUserPermissions($_SESSION['username']);
if (!empty($userPerms['disableUpload'])) {
http_response_code(403);
echo json_encode(["error" => "Upload disabled for this user."]);
exit;
}
//
// 3) Delegate the actual file handling
//
$result = UploadModel::handleUpload($_POST, $_FILES);
//
// 4) Respond
//
if (isset($result['error'])) {
http_response_code(400);
echo json_encode($result);
exit;
}
if (isset($result['status'])) {
echo json_encode($result);
exit;
}
// fullupload redirect
$_SESSION['upload_message'] = "File uploaded successfully.";
exit;
}
/**
* @OA\Post(
* path="/api/upload/removeChunks.php",
* summary="Remove chunked upload temporary directory",
* description="Removes the temporary directory used for chunked uploads, given a folder name matching the expected resumable pattern.",
* operationId="removeChunks",
* tags={"Uploads"},
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"folder"},
* @OA\Property(property="folder", type="string", example="resumable_myupload123")
* )
* ),
* @OA\Response(
* response=200,
* description="Temporary folder removed successfully",
* @OA\JsonContent(
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="Temporary folder removed.")
* )
* ),
* @OA\Response(
* response=400,
* description="Invalid input (e.g., missing folder or invalid folder name)"
* ),
* @OA\Response(
* response=403,
* description="Invalid CSRF token"
* )
* )
*
* Removes the temporary upload folder for chunked uploads.
*
* @return void Outputs a JSON response.
*/
public function removeChunks(): void {
header('Content-Type: application/json');
// CSRF Protection: Validate token from POST data.
$receivedToken = isset($_POST['csrf_token']) ? trim($_POST['csrf_token']) : '';
if ($receivedToken !== $_SESSION['csrf_token']) {
http_response_code(403);
echo json_encode(["error" => "Invalid CSRF token"]);
exit;
}
// Check that the folder parameter is provided.
if (!isset($_POST['folder'])) {
http_response_code(400);
echo json_encode(["error" => "No folder specified"]);
exit;
}
$folder = $_POST['folder'];
$result = UploadModel::removeChunks($folder);
echo json_encode($result);
exit;
}
}