Insegnanti della scuola
insegnantNessun insegnante. Aggiungi il primo: diventerà automaticamente il titolare.
getConnection(); if (!function_exists('e')) { function e($value): string { return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); } } if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); } if (empty($_SESSION['csrf_teachers'])) { $_SESSION['csrf_teachers'] = bin2hex(random_bytes(16)); } $csrf = $_SESSION['csrf_teachers']; define('PHOTO_DIR_REL', 'assets/images/teachers/'); $photoDirAbs = __DIR__ . '/' . PHOTO_DIR_REL; /* ================================================================ helper */ function flashRedirect(string $type, string $msg): void { $_SESSION['teachers_flash'] = [$type, $msg]; header('Location: insegnanti.php'); exit; } function teacherInitials(string $first, string $last): string { $ini = mb_strtoupper(mb_substr(trim($first), 0, 1) . mb_substr(trim($last), 0, 1)); return $ini !== '' ? $ini : '?'; } function teacherColor(string $seed): string { $palette = ['#1ebf73', '#2980b9', '#8e44ad', '#e67e22', '#16a085', '#c0392b', '#2c3e50', '#b08d57']; return $palette[abs(crc32($seed)) % count($palette)]; } function deletePhotoFile(string $dir, ?string $name): void { if ($name && preg_match('/^teacher_[a-f0-9]{16}\.(jpg|png|webp)$/', $name) && is_file($dir . $name)) { @unlink($dir . $name); } } /** Ritorna il nome file salvato, null se nessun file caricato. Lancia RuntimeException se non valido. */ function handlePhotoUpload(array $file, string $dir): ?string { if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) { return null; } if ($file['error'] !== UPLOAD_ERR_OK) { throw new RuntimeException('Errore nel caricamento della foto.'); } if ($file['size'] > 3 * 1024 * 1024) { throw new RuntimeException('La foto supera i 3 MB.'); } $mime = (new finfo(FILEINFO_MIME_TYPE))->file($file['tmp_name']); $ext = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp'][$mime] ?? null; if (!$ext || @getimagesize($file['tmp_name']) === false) { throw new RuntimeException('Formato foto non valido: usa JPG, PNG o WEBP.'); } if (!is_dir($dir) && !@mkdir($dir, 0755, true)) { throw new RuntimeException('La cartella delle foto non è scrivibile.'); } $name = 'teacher_' . bin2hex(random_bytes(8)) . '.' . $ext; if (!move_uploaded_file($file['tmp_name'], $dir . $name)) { throw new RuntimeException('Impossibile salvare la foto.'); } return $name; } function findTeacher(PDO $pdo, int $id): ?array { $st = $pdo->prepare("SELECT * FROM employee WHERE idemployee = :id"); $st->execute([':id' => $id]); $row = $st->fetch(); return $row ?: null; } /* ================================================================ azioni POST */ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!hash_equals($csrf, (string) ($_POST['csrf'] ?? ''))) { flashRedirect('danger', 'Sessione scaduta, riprova.'); } $action = $_POST['action'] ?? ''; $id = (int) ($_POST['id'] ?? 0); try { /* ---------- crea / modifica */ if ($action === 'save') { $name = trim((string) ($_POST['nameemployee'] ?? '')); $surname = trim((string) ($_POST['surnameemployee'] ?? '')); $email = trim((string) ($_POST['email'] ?? '')); $phone = trim((string) ($_POST['phone'] ?? '')); $notify = isset($_POST['notifications']) ? 'Y' : 'N'; $active = isset($_POST['active']) ? 'Y' : 'N'; if ($name === '' || $surname === '') { flashRedirect('danger', 'Nome e cognome sono obbligatori.'); } if (mb_strlen($name) > 100 || mb_strlen($surname) > 100) { flashRedirect('danger', 'Nome o cognome troppo lunghi.'); } if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) { flashRedirect('danger', 'Indirizzo email non valido.'); } if ($phone !== '' && !preg_match('/^[0-9 +().\/-]{5,40}$/', $phone)) { flashRedirect('danger', 'Numero di telefono non valido.'); } if ($email !== '') { $dup = $pdo->prepare("SELECT COUNT(*) AS c FROM employee WHERE email = :email AND idemployee <> :id"); $dup->execute([':email' => $email, ':id' => $id]); if ((int) $dup->fetch()['c'] > 0) { flashRedirect('danger', 'Questa email è già usata da un altro insegnante.'); } } if ($id > 0) { $current = findTeacher($pdo, $id); if (!$current) { flashRedirect('danger', 'Insegnante non trovato.'); } if ($current['is_owner'] === 'Y' && $active === 'N') { flashRedirect('danger', 'Il titolare non può essere disattivato.'); } $photo = $current['photo']; $newPhoto = handlePhotoUpload($_FILES['photo'] ?? [], $photoDirAbs); if ($newPhoto !== null) { deletePhotoFile($photoDirAbs, $photo); $photo = $newPhoto; } elseif (isset($_POST['remove_photo'])) { deletePhotoFile($photoDirAbs, $photo); $photo = null; } $st = $pdo->prepare("UPDATE employee SET nameemployee = :n, surnameemployee = :s, email = :e, phone = :p, photo = :ph, notifications = :nt, active = :a WHERE idemployee = :id"); $st->execute([ ':n' => $name, ':s' => $surname, ':e' => $email ?: null, ':p' => $phone ?: null, ':ph' => $photo, ':nt' => $notify, ':a' => $active, ':id' => $id, ]); flashRedirect('success', 'Insegnante aggiornato.'); } // nuovo $photo = handlePhotoUpload($_FILES['photo'] ?? [], $photoDirAbs); $hasOwner = (int) $pdo->query("SELECT COUNT(*) AS c FROM employee WHERE is_owner = 'Y'")->fetch()['c'] > 0; $st = $pdo->prepare("INSERT INTO employee (nameemployee, surnameemployee, email, phone, photo, is_owner, notifications, active, idlocation) VALUES (:n, :s, :e, :p, :ph, :o, :nt, :a, 0)"); $st->execute([ ':n' => $name, ':s' => $surname, ':e' => $email ?: null, ':p' => $phone ?: null, ':ph' => $photo, ':o' => $hasOwner ? 'N' : 'Y', ':nt' => $notify, ':a' => $hasOwner ? $active : 'Y', ]); flashRedirect('success', 'Insegnante aggiunto' . ($hasOwner ? '.' : ' e impostato come titolare.')); } /* ---------- imposta titolare */ if ($action === 'set_owner' && $id > 0) { if (!findTeacher($pdo, $id)) { flashRedirect('danger', 'Insegnante non trovato.'); } $pdo->beginTransaction(); $pdo->exec("UPDATE employee SET is_owner = 'N' WHERE is_owner = 'Y'"); $st = $pdo->prepare("UPDATE employee SET is_owner = 'Y', active = 'Y' WHERE idemployee = :id"); $st->execute([':id' => $id]); $pdo->commit(); flashRedirect('success', 'Titolare aggiornato.'); } /* ---------- notifiche on/off */ if ($action === 'toggle_notifications' && $id > 0) { $st = $pdo->prepare("UPDATE employee SET notifications = IF(notifications = 'Y', 'N', 'Y') WHERE idemployee = :id"); $st->execute([':id' => $id]); flashRedirect('success', 'Notifiche aggiornate.'); } /* ---------- elimina */ if ($action === 'delete' && $id > 0) { $t = findTeacher($pdo, $id); if (!$t) { flashRedirect('danger', 'Insegnante non trovato.'); } if ($t['is_owner'] === 'Y') { flashRedirect('danger', 'Il titolare non può essere eliminato. Imposta prima un altro titolare.'); } $cnt = $pdo->prepare("SELECT COUNT(*) AS c FROM service WHERE idteacher = :id"); $cnt->execute([':id' => $id]); $nServices = (int) $cnt->fetch()['c']; if ($nServices > 0) { flashRedirect('danger', 'Impossibile eliminare: ha ' . $nServices . ' classi assegnate. Riassegnale oppure disattiva l\'insegnante.'); } $pdo->beginTransaction(); $pdo->prepare("DELETE FROM dayoff WHERE idteacher = :id")->execute([':id' => $id]); $pdo->prepare("DELETE FROM employee WHERE idemployee = :id")->execute([':id' => $id]); $pdo->commit(); deletePhotoFile($photoDirAbs, $t['photo']); flashRedirect('success', 'Insegnante eliminato.'); } flashRedirect('danger', 'Azione non valida.'); } catch (RuntimeException $ex) { flashRedirect('danger', $ex->getMessage()); } catch (Throwable $ex) { if ($pdo->inTransaction()) { $pdo->rollBack(); } error_log('insegnanti.php: ' . $ex->getMessage()); flashRedirect('danger', 'Errore durante il salvataggio. Riprova.'); } } /* ================================================================ lettura */ $flash = $_SESSION['teachers_flash'] ?? null; unset($_SESSION['teachers_flash']); $teachers = $pdo->query("SELECT e.*, (SELECT COUNT(*) FROM service s WHERE s.idteacher = e.idemployee) AS nservices FROM employee e ORDER BY e.is_owner DESC, e.active DESC, e.surnameemployee, e.nameemployee")->fetchAll(); ?>
Nessun insegnante. Aggiungi il primo: diventerà automaticamente il titolare.