4E e 4I: l'uso del file di testo con il Php e la libreria Leaflet per la geolocalizzazione (seconda parte)
Seconda parte dell'esercizio:
Questa seconda parte trasforma l'esercizio in un piccolo CMS (Content Management System).
Per implementare la gestione del file `stations.txt` (CRUD: Create, Read, Update, Delete) da parte di un amministratore, dobbiamo:
1. Aggiornare il sistema di login per riconoscere un ruolo "admin".
2. Aggiungere un link all'area di amministrazione per l'admin.
3. Creare le pagine di amministrazione (un pannello per visualizzare, moduli per inserire/modificare e uno script per processare le azioni).
Ecco i file nuovi e modificati.
1. Modifiche ai File Esistenti
Per prima cosa, aggiorniamo il login per supportare un utente "admin" e aggiungiamo un link nell'area riservata.
⚙️ `login_process.php` (Modificato)
Aggiungiamo un utente amministratore e impostiamo una variabile di sessione `role`.
<?php
// Inizia la sessione
session_start();
// Credenziali "mock" per l'esercizio
$utente_valido = 'user';
$password_valida = 'pass123';
// Credenziali Admin
$admin_valido = 'admin';
$admin_pass_valida = 'admin123'; // Password diversa
// Controlla se i dati sono stati inviati in POST
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// Verifica le credenziali ADMIN
if ($username === $admin_valido && $password === $admin_pass_valida) {
// Credenziali corrette! Salva lo stato nella sessione
$_SESSION['loggedin'] = true;
$_SESSION['username'] = $username;
$_SESSION['role'] = 'admin'; // <-- RUOLO ADMIN
// Reindirizza alla pagina della mappa
header('Location: map.php');
exit;
// Verifica le credenziali UTENTE
} elseif ($username === $utente_valido && $password === $password_valida) {
// Credenziali corrette! Salva lo stato nella sessione
$_SESSION['loggedin'] = true;
$_SESSION['username'] = $username;
$_SESSION['role'] = 'user'; // <-- RUOLO USER
// Reindirizza alla pagina della mappa
header('Location: map.php');
exit;
} else {
// Credenziali errate, reindirizza al login con un errore
header('Location: login.php?error=1');
exit;
}
} else {
// Se qualcuno prova ad accedere direttamente a questo file, reindirizza al login
header('Location: login.php');
exit;
}
?>
🗺️ `map.php` (Modificato)
Aggiungiamo un link "Gestisci Stazioni" nell'header, visibile solo se l'utente è un amministratore.
<?php
session_start();
// Blocco di sicurezza: controlla se l'utente è loggato
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
header('Location: login.php'); // Se non è loggato, via al login
exit;
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mappa Stazioni - Area Riservata</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" ... />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" ... ></script>
<style>
/* ... (stili identici a prima) ... */
header a { margin-left: 20px; text-decoration: none; color: #007bff; }
header a.logout { color: #dc3545; }
</style>
</head>
<body>
<header>
<h1>Ciao, <?php echo htmlspecialchars($_SESSION['username']); ?>!</h1>
<div>
<?php
// Se l'utente è un admin, mostra il link al pannello di gestione
if (isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
echo '<a href="admin.php">Gestisci Stazioni</a>';
}
?>
<a href="logout.php" class="logout">Logout</a>
</div>
</header>
<div style="padding: 20px;">
<button id="find-nearest">📍 Trova la colonnina più vicina a me</button>
</div>
<div id="map"></div>
<script src="script.js"></script>
</body>
</html>
2. Creazione della Nuova Area Admin (CRUD)
Ora creiamo i nuovi file PHP che gestiranno il file `stations.txt`.
🛡️ `admin_security.php` (Nuovo File)
Per evitare di ripetere il codice di sicurezza, creiamo un file che controlla se l'utente è un admin. Lo includeremo in tutte le pagine di amministrazione.
<?php
session_start();
// Blocco di sicurezza per l'area admin
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true || !isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
// Se non è un admin loggato, reindirizza al login con un errore
header('Location: login.php?error=unauthorized');
exit;
}
// Definiamo il percorso del file qui per averlo in un unico posto
define('STATIONS_FILE', 'stations.txt');
?>
📋 `admin.php` (Nuovo File - Pagina Principale)
Questa pagina mostrerà l'elenco delle stazioni ( **Read** ) e un modulo per aggiungerne una nuova ( **Create** ).
<?php
require 'admin_security.php'; // Include il controllo di sicurezza
$stations = [];
$file_path = STATIONS_FILE;
// Legge le stazioni dal file
if (file_exists($file_path)) {
if (($handle = fopen($file_path, "r")) !== FALSE) {
$index = 0; // Teniamo traccia dell'indice di riga
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
if (count($data) == 3) {
$stations[] = [
'id' => $index, // Usiamo l'indice di riga come ID
'name' => $data[0],
'lat' => $data[1],
'lng' => $data[2]
];
$index++;
}
}
fclose($handle);
}
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gestione Stazioni</title>
<style>
body { font-family: sans-serif; padding: 20px; }
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }
th { background-color: #f4f4f4; }
a { color: #007bff; text-decoration: none; }
.delete-link { color: #dc3545; }
.form-section { border: 1px solid #ccc; padding: 20px; border-radius: 8px; }
.form-section div { margin-bottom: 10px; }
label { display: block; margin-bottom: 5px; }
input[type="text"], input[type="number"] { width: 300px; padding: 8px; }
button { padding: 10px 15px; cursor: pointer; background: #28a745; color: white; border: none; border-radius: 4px; }
.nav-links { margin-bottom: 20px; }
</style>
</head>
<body>
<div class="nav-links">
<a href="map.php">« Torna alla Mappa</a> |
<a href="logout.php">Logout</a>
</div>
<h1>Gestione Stazioni</h1>
<?php if(isset($_GET['status']) && $_GET['status'] == 'success'): ?>
<p style="color: green;">Operazione completata con successo!</p>
<?php endif; ?>
<h2>Elenco Stazioni</h2>
<table>
<thead>
<tr>
<th>Nome</th>
<th>Latitudine</th>
<th>Longitudine</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($stations as $station): ?>
<tr>
<td><?php echo htmlspecialchars($station['name']); ?></td>
<td><?php echo htmlspecialchars($station['lat']); ?></td>
<td><?php echo htmlspecialchars($station['lng']); ?></td>
<td>
<a href="admin_edit.php?id=<?php echo $station['id']; ?>">Modifica</a> |
<a href="admin_action.php?action=delete&id=<?php echo $station['id']; ?>"
class="delete-link"
onclick="return confirm('Sei sicuro di voler cancellare questa stazione?');">
Cancella
</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($stations)): ?>
<tr>
<td colspan="4">Nessuna stazione trovata.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<div class="form-section">
<h2>Aggiungi Nuova Stazione</h2>
<form action="admin_action.php" method="POST">
<input type="hidden" name="action" value="create">
<div>
<label for="name">Nome:</label>
<input type="text" id="name" name="name" required>
</div>
<div>
<label for="lat">Latitudine:</label>
<input type="number" step="any" id="lat" name="lat" required>
</div>
<div>
<label for="lng">Longitudine:</label>
<input type="number" step="any" id="lng" name="lng" required>
</div>
<button type="submit">Aggiungi Stazione</button>
</form>
</div>
</body>
</html>
📝 `admin_edit.php` (Nuovo File - Pagina Modifica)
Questa pagina conterrà il modulo per modificare una stazione esistente ( **Update** ).
<?php
require 'admin_security.php'; // Include il controllo di sicurezza
// Verifica che l'ID sia stato passato
if (!isset($_GET['id'])) {
header('Location: admin.php?status=error');
exit;
}
$id_to_edit = (int)$_GET['id'];
$file_path = STATIONS_FILE;
$station_data = null;
// Legge tutte le righe del file
$lines = file($file_path, FILE_IGNORE_NEW_LINES);
// Controlla se l'ID (indice di riga) esiste
if (isset($lines[$id_to_edit])) {
$data = str_getcsv($lines[$id_to_edit]);
if (count($data) == 3) {
$station_data = [
'name' => $data[0],
'lat' => $data[1],
'lng' => $data[2]
];
}
} else {
// Se l'ID non è valido, torna indietro
header('Location: admin.php?status=error_id');
exit;
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modifica Stazione</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.form-section { border: 1px solid #ccc; padding: 20px; border-radius: 8px; }
.form-section div { margin-bottom: 10px; }
label { display: block; margin-bottom: 5px; }
input[type="text"], input[type="number"] { width: 300px; padding: 8px; }
button { padding: 10px 15px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px; }
a { color: #007bff; text-decoration: none; }
</style>
</head>
<body>
<a href="admin.php">« Torna all'elenco</a>
<div class="form-section">
<h2>Modifica Stazione</h2>
<form action="admin_action.php" method="POST">
<input type="hidden" name="action" value="update">
<input type="hidden" name="id" value="<?php echo $id_to_edit; ?>">
<div>
<label for="name">Nome:</label>
<input type="text" id="name" name="name" value="<?php echo htmlspecialchars($station_data['name']); ?>" required>
</div>
<div>
<label for="lat">Latitudine:</label>
<input type="number" step="any" id="lat" name="lat" value="<?php echo htmlspecialchars($station_data['lat']); ?>" required>
</div>
<div>
<label for="lng">Longitudine:</label>
<input type="number" step="any" id="lng" name="lng" value="<?php echo htmlspecialchars($station_data['lng']); ?>" required>
</div>
<button type="submit">Salva Modifiche</button>
</form>
</div>
</body>
</html>
⚡ `admin_action.php` (Nuovo File - Logica C-U-D)
Questo script "invisibile" riceve i dati dai moduli o i comandi dai link ed esegue le operazioni sul file di testo, per poi reindirizzare l'utente al pannello di amministrazione.
<?php
require 'admin_security.php'; // Include il controllo di sicurezza
$file_path = STATIONS_FILE;
$action = $_REQUEST['action'] ?? '';
// --- Logica CREATE (Inserimento) ---
if ($action === 'create' && $_SERVER["REQUEST_METHOD"] == "POST") {
$name = trim($_POST['name'] ?? '');
$lat = (float)($_POST['lat'] ?? 0);
$lng = (float)($_POST['lng'] ?? 0);
// Validazione semplice
if (!empty($name) && $lat != 0 && $lng != 0) {
$new_line = "$name,$lat,$lng\n";
// Aggiunge la nuova riga in fondo al file
file_put_contents($file_path, $new_line, FILE_APPEND | LOCK_EX);
}
}
// --- Logica UPDATE (Modifica) ---
if ($action === 'update' && $_SERVER["REQUEST_METHOD"] == "POST") {
$id = (int)($_POST['id'] ?? -1);
$name = trim($_POST['name'] ?? '');
$lat = (float)($_POST['lat'] ?? 0);
$lng = (float)($_POST['lng'] ?? 0);
// Validazione
if ($id >= 0 && !empty($name) && $lat != 0 && $lng != 0) {
// Legge tutte le righe in un array
$lines = file($file_path, FILE_IGNORE_NEW_LINES);
// Controlla se la riga (ID) esiste
if (isset($lines[$id])) {
// Modifica la riga specifica
$lines[$id] = "$name,$lat,$lng";
// Riscrive l'intero file con la riga modificata
file_put_contents($file_path, implode("\n", $lines) . "\n", LOCK_EX);
}
}
}
// --- Logica DELETE (Cancellazione) ---
if ($action === 'delete' && isset($_GET['id'])) {
$id = (int)$_GET['id'];
if ($id >= 0) {
// Legge tutte le righe in un array
$lines = file($file_path, FILE_IGNORE_NEW_LINES);
// Controlla se la riga (ID) esiste
if (isset($lines[$id])) {
// Rimuove l'elemento dall'array
unset($lines[$id]);
// Riscrive l'intero file senza la riga cancellata
file_put_contents($file_path, implode("\n", $lines) . "\n", LOCK_EX);
}
}
}
// Dopo ogni operazione, reindirizza al pannello admin
header('Location: admin.php?status=success');
exit;
?>
3\. Struttura Finale dei File
La tua cartella di progetto ora dovrebbe assomigliare a questa:
/tuo-progetto/
|
|-- login.php
|-- login_process.php (Modificato)
|-- map.php (Modificato)
|-- logout.php
|-- get_stations.php
|-- stations.txt (Ora è gestibile via web!)
|-- script.js
|
|-- admin_security.php (Nuovo)
|-- admin.php (Nuovo - Pannello Read + Create)
|-- admin_edit.php (Nuovo - Pagina Update)
|-- admin_action.php (Nuovo - Logica C, U, D)
🔐 Note sulla Sicurezza
File di Testo: La gestione di un file di testo in questo modo (lettura e riscrittura completa) non è efficiente per file di grandi dimensioni. Per migliaia di righe, un database SQL (come MySQL o SQLite) è indispensabile. Per questo esercizio, va benissimo.
Permessi: Assicurati che il server web (Apache) abbia i permessi di **scrittura** sul file `stations.txt`.
Validazione: Ho aggiunto solo una validazione minima. In un'applicazione reale, dovresti controllare molto più rigorosamente i dati in input (es. che le coordinate siano valide).

Commenti
Posta un commento