178 lines
4.9 KiB
PHP
Executable File
178 lines
4.9 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* MSPE Media API
|
|
*/
|
|
|
|
require_once 'config.php';
|
|
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
$id = $_GET['id'] ?? null;
|
|
|
|
// Require auth for all media operations
|
|
requireAuth();
|
|
|
|
// CSRF protection for write operations
|
|
if ($method !== 'GET') {
|
|
requireSameOriginRequest();
|
|
}
|
|
|
|
switch ($method) {
|
|
case 'GET':
|
|
getMedia();
|
|
break;
|
|
|
|
case 'POST':
|
|
if (isset($_GET['action']) && $_GET['action'] === 'delete') {
|
|
deleteMediaBatch();
|
|
} else {
|
|
uploadMedia();
|
|
}
|
|
break;
|
|
|
|
case 'DELETE':
|
|
if (!$id) {
|
|
jsonResponse(['success' => false, 'message' => 'ID required'], 400);
|
|
}
|
|
deleteMedia($id);
|
|
break;
|
|
|
|
default:
|
|
jsonResponse(['success' => false, 'message' => 'Method not allowed'], 405);
|
|
}
|
|
|
|
function getMedia() {
|
|
global $db;
|
|
// For a file-based system without a dedicated media DB table,
|
|
// we can scan the uploads directory.
|
|
// However, keeping a record in JSON is better for metadata.
|
|
// Let's assume we have a 'media' table.
|
|
|
|
$media = $db->getAll('media');
|
|
|
|
// Sync with filesystem?
|
|
// For simplicity, let's just return DB records.
|
|
// If empty, one could scan dir, but we'll rely on upload recording.
|
|
|
|
$folder = $_GET['folder'] ?? null;
|
|
$type = $_GET['type'] ?? null;
|
|
$search = $_GET['search'] ?? null;
|
|
|
|
if ($folder) {
|
|
$media = array_filter($media, function($m) use ($folder) {
|
|
return ($m['folder'] ?? '') === $folder;
|
|
});
|
|
}
|
|
|
|
if ($type) {
|
|
$media = array_filter($media, function($m) use ($type) {
|
|
return strpos($m['type'], $type) !== false;
|
|
});
|
|
}
|
|
|
|
if ($search) {
|
|
$media = array_filter($media, function($m) use ($search) {
|
|
return stripos($m['name'], $search) !== false;
|
|
});
|
|
}
|
|
|
|
// Sort recent first
|
|
usort($media, function($a, $b) {
|
|
return strtotime($b['created_at']) - strtotime($a['created_at']);
|
|
});
|
|
|
|
jsonResponse(['success' => true, 'data' => array_values($media)]);
|
|
}
|
|
|
|
function uploadMedia() {
|
|
global $db;
|
|
|
|
if (empty($_FILES)) {
|
|
jsonResponse(['success' => false, 'message' => 'No files uploaded'], 400);
|
|
}
|
|
|
|
$folder = $_POST['folder'] ?? '';
|
|
$uploaded = [];
|
|
|
|
foreach ($_FILES as $key => $file) {
|
|
// Handle array uploads (multiple files)
|
|
if (is_array($file['name'])) {
|
|
foreach ($file['name'] as $idx => $name) {
|
|
$singleFile = [
|
|
'name' => $name,
|
|
'type' => $file['type'][$idx],
|
|
'tmp_name' => $file['tmp_name'][$idx],
|
|
'error' => $file['error'][$idx],
|
|
'size' => $file['size'][$idx]
|
|
];
|
|
$result = processUpload($singleFile, $folder);
|
|
if ($result) $uploaded[] = $result;
|
|
}
|
|
} else {
|
|
$result = processUpload($file, $folder);
|
|
if ($result) $uploaded[] = $result;
|
|
}
|
|
}
|
|
|
|
jsonResponse(['success' => true, 'data' => $uploaded]);
|
|
}
|
|
|
|
function processUpload($file, $folder) {
|
|
global $db;
|
|
$res = handleFileUpload($file, $folder);
|
|
|
|
if ($res['success']) {
|
|
$mediaItem = [
|
|
'name' => $file['name'],
|
|
'path' => $res['path'], // Relative path
|
|
'full_url' => SITE_URL . '/' . $res['path'],
|
|
'type' => $file['type'],
|
|
'size' => $file['size'],
|
|
'folder' => $folder,
|
|
'created_at' => date('Y-m-d H:i:s')
|
|
];
|
|
return $db->insert('media', $mediaItem);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function deleteMedia($id) {
|
|
deleteMediaInternal($id);
|
|
jsonResponse(['success' => true, 'message' => 'File deleted']);
|
|
}
|
|
|
|
function deleteMediaInternal($id) {
|
|
global $db;
|
|
$item = $db->get('media', $id);
|
|
|
|
if ($item) {
|
|
// Delete physical file with path traversal protection
|
|
$filepath = __DIR__ . '/../' . $item['path'];
|
|
if (file_exists($filepath)) {
|
|
// Verify path is within uploads directory (prevent directory traversal)
|
|
$uploadDir = realpath(UPLOAD_DIR);
|
|
$filePath = realpath($filepath);
|
|
if ($filePath && $uploadDir && strpos($filePath, $uploadDir) === 0) {
|
|
if (!unlink($filepath)) {
|
|
error_log('MSPE: Failed to delete file ' . $filepath);
|
|
}
|
|
} else {
|
|
error_log('MSPE: Path traversal attempt detected in deleteMedia');
|
|
}
|
|
}
|
|
$db->delete('media', $id);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function deleteMediaBatch() {
|
|
$ids = getRequestBody()['ids'] ?? [];
|
|
$deleted = 0;
|
|
foreach ($ids as $id) {
|
|
if (deleteMediaInternal($id)) {
|
|
$deleted++;
|
|
}
|
|
}
|
|
jsonResponse(['success' => true, 'message' => "{$deleted} file(s) deleted"]);
|
|
}
|