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">&laquo; 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">&laquo; 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

Post popolari in questo blog

Esercizi in Excel e fogli di Google

Simulazioni di reti (con Cisco Packet Tracer)