tp_servicedesk/app/controllers/AttachmentController.php
2025-05-10 08:50:41 +01:00

189 lines
5.4 KiB
PHP

<?php
class AttachmentController {
use RequiresAuth, CheckCSRF;
// list attachments
public function index($f3){
$this->check_access($f3);
$ticket_id = (int) $f3->get('PARAMS.id');
$db = $f3->get('DB');
// fetch attachments
$attachments = $db->exec(
'SELECT a.*, u.username
FROM attachments a
LEFT JOIN users u ON u.id = a.uploaded_by
WHERE a.ticket_id = ?
ORDER BY a.created_at DESC',
[$ticket_id]
);
$f3->set('ticket_id', $ticket_id);
$f3->set('attachments', $attachments);
$f3->set('content', 'views/attachment/index.html');
// echo \Template::instance()->render('templates/layout.html');
echo \Template::instance()->render($f3->get('content'));
}
// handle file upload
public function upload($f3){
$this->check_access($f3);
$this->checkCSRF($f3, '/ticket/'.$f3->get('PARAMS.id')); // not ideal for AJAX
$ticket_id = (int) $f3->get('PARAMS.id');
$uploaded_by = $f3->get('SESSION.user.id');
if(!isset($_FILES['attachment']) || $_FILES['attachment']['error'] !== UPLOAD_ERR_OK){
$f3->reroute('/ticket/'.$ticket_id.'/attachments');
}
$file_info = $_FILES['attachment'];
$original_name = $file_info['name'];
$tmp_path = $file_info['tmp_name'];
// create a unique file path
$upload_dir = '../storage/attachments/tickets/'.$ticket_id.'/';
if(!is_dir($upload_dir)){
mkdir($upload_dir, 0777, true);
}
// if file exists increment version
$db = $f3->get('DB');
$existing = $db->exec(
'SELECT * FROM attachments
WHERE ticket_id =? AND file_name = ?
ORDER BY version_number DESC
LIMIT 1',
[$ticket_id, $original_name]
);
$new_version = 1;
if($existing){
$new_version = $existing[0]['version_number'] + 1;
}
$final_path = $upload_dir.$new_version.'_'.$original_name;
// move file
move_uploaded_file($tmp_path, $final_path);
// store meta data in DB
$db->exec(
'INSERT INTO attachments
(ticket_id, path, file_name, version_number, uploaded_by, created_at)
VALUES (?,?,?,?,?,NOW())',
[$ticket_id, $final_path, $original_name, $new_version, $uploaded_by]
);
$f3->reroute('/ticket/'.$ticket_id.'');
// ideal ajax response:
// $f3->json(['success' => true, 'message' => 'file upload success.', 'filename' => $original_name, 'version' => $new_version]);
}
// download attachment
public function download($f3){
$this->check_access($f3);
$attachment_id = (int) $f3->get('PARAMS.id');
$db = $f3->get('DB');
$rows = $db->exec('SELECT * FROM attachments WHERE id = ?', [$attachment_id]);
if(!$rows){
$f3->error(404, "File not found");
return;
}
$attachment = $rows[0];
$file_path = $attachment['path'];
$file_name = $attachment['file_name'];
// validate file exists
if(!file_exists($file_path)){
$f3->error(404, "File not found");
return;
}
// output headers for download
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file_name).'"');
header('Content-Length: '. filesize($file_path));
// flush headers
flush();
// read file
readfile($file_path);
exit;
}
// delete an attachment
public function delete($f3){
$this->check_access($f3);
$attachment_id = (int) $f3->get('PARAMS.id');
$current_user = $f3->get('SESSION.user');
$db = $f3->get('DB');
$rows = $db->exec('SELECT * FROM attachments WHERE id =? LIMIT 1', [$attachment_id]);
if(!$rows){
$f3->error(404, "Attachment not found");
return;
}
$attachment = $rows[0];
// TODO: role or ownership
if(file_exists($attachment['path'])){
unlink($attachment['path']);
}
// remove DB row
$db->exec('DELETE FROM attachments WHERE id =?', [$attachment_id]);
}
// view attachment
public function view($f3){
$this->check_access($f3);
$attachment_id = (int) $f3->get('PARAMS.id');
$db = $f3->get('DB');
$rows = $db->exec('SELECt * FROM attachments WHERE id = ?', [$attachment_id]);
if(!$rows){
$f3->error(404, "File not found");
return;
}
$attachment = $rows[0];
$file_path = $attachment['path'];
$file_name = $attachment['file_name'];
if(!file_exists($file_path)){
$f3->error(404, "File not found");
return;
}
// detect mime type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $file_path);
finfo_close($finfo);
header('Content-Type: ' . $mime_type);
header('Content-Disposition: inline; filename="' . basename($file_name) . '"');
header('Content-Length: ' . filesize($file_path));
flush();
readfile($file_path);
exit;
}
}