getConnection();
/*
|--------------------------------------------------------------------------
| Upload configuration
|--------------------------------------------------------------------------
| The page is expected to be inside /public.
| Files will be stored in /public/uploads/ppe.
| The database stores the relative browser path, for example:
| uploads/ppe/ppe_20260604_123456_abcd.jpg
|--------------------------------------------------------------------------
*/
const PPE_UPLOAD_RELATIVE_DIR = 'uploads/ppe';
const PPE_UPLOAD_MAX_SIZE = 5242880; // 5 MB
$ppeUploadAbsoluteDir = __DIR__ . '/' . PPE_UPLOAD_RELATIVE_DIR;
if (!is_dir($ppeUploadAbsoluteDir)) {
mkdir($ppeUploadAbsoluteDir, 0755, true);
}
function jsonResponse(bool $success, string $message = '', array $extra = []): void
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode(array_merge([
'success' => $success,
'message' => $message,
], $extra));
exit;
}
function cleanString(?string $value): string
{
return trim((string)$value);
}
function cleanNullableString(?string $value): ?string
{
$value = trim((string)$value);
return $value === '' ? null : $value;
}
function toActiveValue($value): int
{
return ((string)$value === '1') ? 1 : 0;
}
function normalizePathForDb(string $path): string
{
return str_replace('\\', '/', $path);
}
function deletePpePhotoIfExists(?string $relativePath): void
{
if (!$relativePath) {
return;
}
$relativePath = normalizePathForDb($relativePath);
if (strpos($relativePath, PPE_UPLOAD_RELATIVE_DIR . '/') !== 0) {
return;
}
$absolutePath = __DIR__ . '/' . $relativePath;
if (is_file($absolutePath)) {
unlink($absolutePath);
}
}
function uploadPpePhoto(array $file): ?string
{
if (!isset($file['error']) || $file['error'] === UPLOAD_ERR_NO_FILE) {
return null;
}
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new RuntimeException('Errore durante il caricamento della foto.');
}
if (($file['size'] ?? 0) > PPE_UPLOAD_MAX_SIZE) {
throw new RuntimeException('La foto supera la dimensione massima consentita di 5 MB.');
}
$tmpPath = $file['tmp_name'] ?? '';
if (!is_uploaded_file($tmpPath)) {
throw new RuntimeException('File caricato non valido.');
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($tmpPath);
$allowedMimeTypes = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/webp' => 'webp',
];
if (!isset($allowedMimeTypes[$mimeType])) {
throw new RuntimeException('Formato foto non consentito. Sono ammessi JPG, PNG e WEBP.');
}
$extension = $allowedMimeTypes[$mimeType];
$randomName = bin2hex(random_bytes(6));
$fileName = 'ppe_' . date('Ymd_His') . '_' . $randomName . '.' . $extension;
$absoluteDestination = __DIR__ . '/' . PPE_UPLOAD_RELATIVE_DIR . '/' . $fileName;
$relativeDestination = PPE_UPLOAD_RELATIVE_DIR . '/' . $fileName;
if (!move_uploaded_file($tmpPath, $absoluteDestination)) {
throw new RuntimeException('Impossibile salvare la foto nella cartella DPI.');
}
return normalizePathForDb($relativeDestination);
}
/*
|--------------------------------------------------------------------------
| AJAX actions
|--------------------------------------------------------------------------
*/
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
try {
$action = $_POST['action'];
/*
|--------------------------------------------------------------------------
| Save PPE
|--------------------------------------------------------------------------
*/
if ($action === 'save_ppe') {
$id = isset($_POST['id']) && $_POST['id'] !== '' ? (int)$_POST['id'] : null;
$name = cleanString($_POST['name'] ?? '');
$description = cleanNullableString($_POST['description'] ?? null);
$category = cleanNullableString($_POST['category'] ?? null);
$standardReference = cleanNullableString($_POST['standard_reference'] ?? null);
$validityMonths = isset($_POST['validity_months']) && $_POST['validity_months'] !== '' ? (int)$_POST['validity_months'] : null;
$sortOrder = isset($_POST['sort_order']) && $_POST['sort_order'] !== '' ? (int)$_POST['sort_order'] : 999;
$isActive = toActiveValue($_POST['is_active'] ?? 1);
$removePhoto = (int)($_POST['remove_photo'] ?? 0) === 1;
if ($name === '') {
jsonResponse(false, 'Il nome del DPI è obbligatorio.');
}
$uploadedPhotoPath = null;
if (isset($_FILES['photo'])) {
$uploadedPhotoPath = uploadPpePhoto($_FILES['photo']);
}
if ($id) {
$stmt = $pdo->prepare("
SELECT photo
FROM ppe_items
WHERE id = ?
LIMIT 1
");
$stmt->execute([$id]);
$existingPhoto = $stmt->fetchColumn();
if ($existingPhoto === false) {
jsonResponse(false, 'DPI non trovato.');
}
$finalPhoto = $existingPhoto;
if ($removePhoto) {
deletePpePhotoIfExists($existingPhoto);
$finalPhoto = null;
}
if ($uploadedPhotoPath) {
deletePpePhotoIfExists($existingPhoto);
$finalPhoto = $uploadedPhotoPath;
}
$stmt = $pdo->prepare("
UPDATE ppe_items
SET name = :name,
description = :description,
category = :category,
photo = :photo,
standard_reference = :standard_reference,
validity_months = :validity_months,
sort_order = :sort_order,
is_active = :is_active,
updated_at = CURRENT_TIMESTAMP
WHERE id = :id
");
$stmt->execute([
':name' => $name,
':description' => $description,
':category' => $category,
':photo' => $finalPhoto,
':standard_reference' => $standardReference,
':validity_months' => $validityMonths,
':sort_order' => $sortOrder,
':is_active' => $isActive,
':id' => $id,
]);
jsonResponse(true, 'DPI aggiornato correttamente.');
}
$stmt = $pdo->prepare("
INSERT INTO ppe_items
(
name,
description,
category,
photo,
standard_reference,
validity_months,
sort_order,
is_active,
created_at,
updated_at
)
VALUES
(
:name,
:description,
:category,
:photo,
:standard_reference,
:validity_months,
:sort_order,
:is_active,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
)
");
$stmt->execute([
':name' => $name,
':description' => $description,
':category' => $category,
':photo' => $uploadedPhotoPath,
':standard_reference' => $standardReference,
':validity_months' => $validityMonths,
':sort_order' => $sortOrder,
':is_active' => $isActive,
]);
jsonResponse(true, 'DPI creato correttamente.');
}
/*
|--------------------------------------------------------------------------
| Get PPE
|--------------------------------------------------------------------------
*/
if ($action === 'get_ppe') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
jsonResponse(false, 'ID DPI non valido.');
}
$stmt = $pdo->prepare("
SELECT
id,
name,
description,
category,
photo,
standard_reference,
validity_months,
sort_order,
is_active
FROM ppe_items
WHERE id = ?
LIMIT 1
");
$stmt->execute([$id]);
$ppe = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$ppe) {
jsonResponse(false, 'DPI non trovato.');
}
jsonResponse(true, '', [
'ppe' => $ppe,
]);
}
/*
|--------------------------------------------------------------------------
| Delete PPE
|--------------------------------------------------------------------------
*/
if ($action === 'delete_ppe') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
jsonResponse(false, 'ID DPI non valido.');
}
$stmt = $pdo->prepare("
SELECT photo
FROM ppe_items
WHERE id = ?
LIMIT 1
");
$stmt->execute([$id]);
$photo = $stmt->fetchColumn();
if ($photo === false) {
jsonResponse(false, 'DPI non trovato.');
}
$pdo->beginTransaction();
$stmt = $pdo->prepare("
DELETE FROM ppe_items
WHERE id = ?
");
$stmt->execute([$id]);
$pdo->commit();
deletePpePhotoIfExists($photo ?: null);
jsonResponse(true, 'DPI eliminato correttamente.');
}
jsonResponse(false, 'Azione non riconosciuta.');
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
jsonResponse(false, 'Errore: ' . $e->getMessage());
}
}
/*
|--------------------------------------------------------------------------
| Page data
|--------------------------------------------------------------------------
*/
$stmt = $pdo->prepare("
SELECT
id,
name,
description,
category,
photo,
standard_reference,
validity_months,
sort_order,
is_active,
created_at,
updated_at
FROM ppe_items
ORDER BY sort_order ASC, name ASC
");
$stmt->execute();
$ppeItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
$totalPpe = count($ppeItems);
$totalActivePpe = 0;
$totalWithPhoto = 0;
$categories = [];
foreach ($ppeItems as $ppe) {
if ((int)$ppe['is_active'] === 1) {
$totalActivePpe++;
}
if (!empty($ppe['photo'])) {
$totalWithPhoto++;
}
if (!empty($ppe['category'])) {
$categories[$ppe['category']] = true;
}
}
$totalCategories = count($categories);
?>
Gestione DPI - = htmlspecialchars($titlewebsite ?? '', ENT_QUOTES, 'UTF-8'); ?>
Gestione DPI
Anagrafica dei Dispositivi di Protezione Individuale, con foto, categorie, validità e standard di riferimento.
DPI totali
= (int)$totalPpe; ?>
DPI attivi
= (int)$totalActivePpe; ?>
Categorie
= (int)$totalCategories; ?>
Con foto
= (int)$totalWithPhoto; ?>
| ID |
Foto |
DPI |
Categoria |
Standard |
Validità |
Stato |
Azioni |
| = $ppeId; ?> |
No foto
|
= htmlspecialchars($ppe['name'], ENT_QUOTES, 'UTF-8'); ?>
= htmlspecialchars($ppe['description'], ENT_QUOTES, 'UTF-8'); ?>
Nessuna descrizione
Ordine: = (int)$ppe['sort_order']; ?>
|
= htmlspecialchars($ppe['category'], ENT_QUOTES, 'UTF-8'); ?>
-
|
= !empty($ppe['standard_reference'])
? htmlspecialchars($ppe['standard_reference'], ENT_QUOTES, 'UTF-8')
: '-'; ?>
|
= (int)$ppe['validity_months']; ?> mesi
Nessuna
|
Attivo
Inattivo
|
|
Le foto vengono salvate nella cartella = PPE_UPLOAD_RELATIVE_DIR; ?>. Nel database viene salvato solo il percorso relativo.