Pàgina privada: diferència entre les revisions

De Wiki personal d'en Guillem Serrat
Es crea la pàgina amb «== Inicialització de la sessió i connexió a la BD == Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML session_start(); A més, hem de requerir el fitxer amb les funcions i una connexió a la BD. En aquest cas, únicament mostrarem dades dins la pàgina, per tant farem servir la connexió de lecutra.».
 
Cap resum de modificació
 
(Hi ha 7 revisions intermèdies que no es mostren del mateix usuari)
Línia 1: Línia 1:
== Pàgina privada ==
Quan un usuari s'autentica amb les seves credencials, pot accedir a una pàgina privada. Dins d'aquesta pàgina es troba:
* Les dades personals de l'usuari
* Les últimes 10 accions de l'usuari
* Les estadístiques d'autenticació
** Última autenticació
** Total d'autenticacions, autenticacions mitjançant login normal, auto-login o login-2fa, autenticacions errònies, etc
* Un botó per modificar les dades de l'usuari
* Un botó per tancar la sessió
== Inicialització de la sessió i connexió a la BD ==
== Inicialització de la sessió i connexió a la BD ==
Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML
Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML
  session_start();
  session_start();
A més, hem de requerir el fitxer amb les funcions i una connexió a la BD. En aquest cas, únicament mostrarem dades dins la pàgina, per tant farem servir la [[Connexions a la BD (A5.3)#Connexió de lectura|connexió de lecutra]].
A més, hem de requerir el fitxer amb les funcions i una connexió a la BD. En aquest cas, únicament mostrarem dades dins la pàgina, per tant farem servir la [[Connexions a la BD (A5.3)#Connexió de lectura|connexió de lecutra]].<pre>
require 'funcions.php';
require './connexioBD/connexioR.php';
</pre>
 
== Requerir autenticació ==
Per accedir a aquesta pàgina, és imperatiu que l'usuari estigui autenticat, en cas contrari no hi pot accedir.
 
Per verificar que l'usuari està autenticat, farem servir la funció [[Funcions de la pràctica 5.3#requerir autenticacio|requerir_autenticacio]]<pre>
// Requerir autenticació per accedir a la pàgina
requerir_autenticacio();
</pre>
 
== Recuperació de les dades de l'usuari ==
Per poder mostrar les dades de l'usuari primer les haurem de recuperar de les taules de la BD
 
Per això recuperarem l’ID de l’usuari que ha iniciat sessió a partir de la sessió i esborrarem qualsevol codi de verificació residual que hagi quedat de l’autenticació amb 2FA o la verificació del correu electrònic.<pre>
// ID de l'usuari
$usuari_id = $_SESSION['usuari']['id'];
 
unset($_SESSION['codi_verificacio']); // Eliminar codi de sessió
</pre>Un cop recuperat la ID de l'usuari, realitzarem una consulta per recuperar les dades personals, les últimes accions i les estadístiques d'autenticació.
 
=== Recuperació de les dades personals ===
Per recuperar les dades personals de l'usuari únicament consultarem els camps de la taula usuaris, cercant el registre amb la mateixa ID que s'ha recuperat de la sessió<pre>
// Consultar dades de l'usuari
$stmt = $pdo->prepare("
    SELECT nom_usuari, nom_complet, email, email_verificat, telefon, ciutat, edat
    FROM usuaris
    WHERE id = ?
");
$stmt->execute([$usuari_id]);
$usuari = $stmt->fetch();
</pre>
 
=== Recuperació de les últimes accions ===
Per recuperar les últimes accions de l'usuari, cercarem de forma descendent per data (més recent a més antic) tots els registres amb l'ID de l'usuari de la sessió. Aquests resultats els limitarem a 10<pre>
// Consultar últimes 10 accions i últim login
$stmt = $pdo->prepare("SELECT accio, ip_client, data_hora FROM activitat WHERE usuari_id = ? ORDER BY data_hora DESC LIMIT 10");
$stmt->execute([$usuari_id]);
$historial = $stmt->fetchAll();
</pre>
 
=== Recuperació de les estadístiques d'autenticació ===
Primer, recuperarem la última autenticació, per això farem una consulta SQL on recuperem tots els registres de la taula activitat on la ID sigui la de l'usuari i l'acció sigui qualsevol tipus de login ordenada de forma descendent per data (més recent a més antiga). Limitarem el resultat a un sol registre que serà l'autenticació més recent.
 
Un cop recuperat el registre, extrarurem la data i hora de l'acció<pre>
// Últim accés a l'aplicació
$stmt = $pdo->prepare("
    SELECT data_hora
    FROM activitat
    WHERE usuari_id = ?
    AND accio IN ('login', 'auto-login', 'login-2fa')
    ORDER BY data_hora DESC
    LIMIT 1
");
 
$stmt->execute([$usuari_id]);
$ultima_activitat = $stmt->fetch(PDO::FETCH_ASSOC);
 
$data_ultim_login = $ultima_activitat['data_hora'] ?? 'N/A';
</pre>Seguidament, recuperarem el total d'accions de cada tipus mitjançant una consulta SQL<pre>
// Total autenticacions
$stmt = $pdo->prepare("
    SELECT
        SUM(accio = 'login')      AS logins_manuals,
        SUM(accio = 'auto-login') AS auto_logins,
        SUM(accio = 'login-2fa') AS logins_2fa,
        SUM(accio = 'error-login') AS error_logins,
        SUM(accio = 'restablir-contrasenya') AS restabliments_contrasenya,
        SUM(accio IN ('login', 'auto-login', 'login-2fa')) AS total
    FROM activitat
    WHERE usuari_id = ?
");
$stmt->execute([$usuari_id]);
$autenticacions = $stmt->fetch();
</pre>
 
== Mostra de les dades ==
 
=== Dades personals ===
Les dades personals les recuperarem de la consulta SQL realitzada per aquesta part. Mostrarem les dades amb escapament per evitar atacs XSS.
 
A més a més, es mostrarà si l'email està o no verificat. En cas que no ho estigui, s'inclourà un enllaç per poder verificar-lo<pre><div class="data-item"><strong>Nom d'usuari:</strong> <?= htmlspecialchars($usuari['nom_usuari']) ?></div>
<div class="data-item"><strong>Nom complet:</strong> <?= htmlspecialchars($usuari['nom_complet']) ?></div>
<div class="data-item"><strong>Ciutat:</strong> <?= htmlspecialchars($usuari['ciutat'] ?: '-') ?></div>
<div class="data-item"><strong>Telèfon:</strong> <?= htmlspecialchars($usuari['telefon'] ?: '-') ?></div>
<div class="data-item"><strong>Edat:</strong> <?= htmlspecialchars($usuari['edat'] ?: '-') ?> anys</div>
<div class="data-item email-status">
    <strong>Email:</strong> <?= htmlspecialchars($usuari['email']) ?>
    <?php if ($usuari['email_verificat'] === 'si'): ?>
        <span class="badge badge-success">Verificat</span>
    <?php else: ?>
        <span class="badge badge-danger">No verificat <a href="verificaCorreu.php">(Verificar ara)</a></span>
    <?php endif; ?>
</div></pre>Un exemple amb l'email verifcat es visualitzaria de la següent forma
[[Fitxer:DadesPersonalsEmailVerificat.png|center|miniatura|702x702px]]
Un exemple amb l'email sense verificar es visualitzaria de la següent forma:
[[Fitxer:DadesPersonalsEmailNoVerificat.png|center|miniatura|721x721px]]
 
=== Últimes accions ===
Mitjançant un foreach a l'array de la consulta SQL realitzada per aquesta part, obtenim els detalls de cada acció.<pre>
<section class="card history-card">
    <h3>Historial d'activitat</h3>
    <div class="activity-list">
        <?php foreach ($historial as $index => $act): ?>
            <div class="activity-item <?= $index === 0 ? 'latest' : '' ?>"> <!-- Si és el primer de la llista afegim la classe "latest" -->
                <span class="activity-date"><?= htmlspecialchars($act['data_hora']) ?></span>
                <span class="activity-action"><?= htmlspecialchars($act['accio']) ?></span>
                <span class="activity-ip"><?= htmlspecialchars($act['ip_client']) ?></span>
            </div>
        <?php endforeach; ?>
    </div>
</section>
</pre>Un exemple amb diverses accions realitzades es veuria així
[[Fitxer:Accions.png|center|miniatura|460x460px]]
 
=== Estadístiques d'autenticació ===
Per últim, d'igual forma que amb les dades personals de l'usuari, mostrarem les estadístiques d'autenticació<pre>
<section class="card stats-card">
    <h3>Estadístiques d'accés</h3>
    <div class="stats-list">
        <div class="stat-row"><span>Total autenticacions</span> <strong><?= $autenticacions['total'] ?></strong></div>
        <div class="stat-row"><span>Logins manuals</span> <strong><?= $autenticacions['logins_manuals'] ?></strong></div>
        <div class="stat-row"><span>Auto-logins</span> <strong><?= $autenticacions['auto_logins'] ?></strong></div>
        <div class="stat-row"><span>Logins 2FA</span> <strong><?= $autenticacions['logins_2fa'] ?></strong></div>
        <div class="stat-row"><span>Logins erronis</span> <strong class="text-danger"><?= $autenticacions['error_logins'] ?></strong></div>
        <div class="stat-row"><span>Restabliments de contrasenya</span> <strong><?= $autenticacions['restabliments_contrasenya'] ?></strong></div>
    </div>
</section>
</pre>Les quals es visualitzarien de la següent manera
[[Fitxer:EstadistiquesAcces.png|center|miniatura|405x405px]]
L'últim accés es mostra a la part superior de la pàgina<pre>
<header class="welcome-header">
    <h1>Benvingut, <span><?php echo htmlspecialchars($_SESSION['usuari']['nom_complet']); ?></span></h1>
    <div class="last-access-banner">
        Darrer accés registrat: <strong><?php echo htmlspecialchars($data_ultim_login); ?></strong>
    </div>
</header>
</pre>I es visualitza de la següent manera
[[Fitxer:UltimAccess.png|center|miniatura]]
 
== Accés d'un administrador ==
En l'aplicatiu, un administrador, ja sigui editor o visualitzador té accés a un tauler d'administració. Aquest tauler s'accedeix mitjançant la pàgina privada.
 
Dins de les dades personals, en cas de ser administrador, es mostrarà un botó de navegació per dirigir-se al tauler
<nowiki><div class="data-grid"></nowiki>
    <nowiki><div class="data-item"><strong>Nom d'usuari:</strong></nowiki> <?= htmlspecialchars($usuari['nom_usuari']) ?><nowiki></div></nowiki>
    <nowiki><div class="data-item"><strong>Nom complet:</strong></nowiki> <?= htmlspecialchars($usuari['nom_complet']) ?><nowiki></div></nowiki>
    <nowiki><div class="data-item"><strong>Ciutat:</strong></nowiki> <?= htmlspecialchars($usuari['ciutat'] ?: '-') ?><nowiki></div></nowiki>
    <nowiki><div class="data-item"><strong>Telèfon:</strong></nowiki> <?= htmlspecialchars($usuari['telefon'] ?: '-') ?><nowiki></div></nowiki>
    <nowiki><div class="data-item"><strong>Edat:</strong></nowiki> <?= htmlspecialchars($usuari['edat'] ?: '-') ?> anys<nowiki></div></nowiki>
    <nowiki><div class="data-item email-status"></nowiki>
        <nowiki><strong>Email:</strong></nowiki> <?= htmlspecialchars($usuari['email']) ?>
        <?php if ($usuari['email_verificat'] === 'si'): ?>
            <nowiki><span class="badge badge-success">Verificat</span></nowiki>
        <?php else: ?>
            <nowiki><span class="badge badge-danger">No verificat <a href="verificaCorreu.php">(Verificar ara)</a></nowiki><nowiki></span></nowiki>
        <?php endif; ?>
    <nowiki></div></nowiki>
    '''<?php if (es_admin()): // Únicament es mostrarà si és un usuari administrador?>
        '''<nowiki><div class="admin-zone"></nowiki>'''
            '''<a href="taulerAdmin.php" class="btn-admin">Accedir al Tauler d'Administració</a>'''
        '''<nowiki></div></nowiki>'''
    '''<?php endif; ?>'''
<nowiki></div></nowiki>
La secció de dades personals d'un administrador es visualitzaria de la següent manera
[[Fitxer:DadesPersonalsAdmin.png|center|miniatura|700x700px]]
 
== Botó per modificar les dades personals ==
A tots els usuaris se li dóna la possibilitat d'editar les seves dades personals mitjançant un formulari. A aquest formulari s'accedeix a partir de la pàgina privada, on a la part de dades personals hi surt un botó de navegació.<pre>
<div class="card-header">
      <h3>Les teves dades personals</h3>
      <a href="editarPerfil.php" class="btn-edit">Editar Perfil</a>
</div>
</pre>El botó de navegació es visualitza de la següent manera
[[Fitxer:EditarPerfilPaginaPrivada.png|center|miniatura]]
 
== Botó per tancar la sessió ==
Per últim, a la part inferior dreta de la pàgina trobem un botó per tancar la sessió, el qual crida al codi PHP "logout"<pre>
<a href="logout.php" class="btn-logout-fixed">Tancar sessió</a>
</pre>El botó de tancar la sessió es visualitza de la següent manera:
[[Fitxer:BotoTancarSessio.png|center|miniatura]]
 
== Codi complet ==
<pre>
<?php
session_start();
require 'funcions.php';
require './connexioBD/connexioR.php';
 
// Requerir autenticació per accedir a la pàgina
requerir_autenticacio();
 
// ID de l'usuari
$usuari_id = $_SESSION['usuari']['id'];
 
unset($_SESSION['codi_verificacio']); // Eliminar codi de sessió
 
try {
    // Consultar dades de l'usuari
    $stmt = $pdo->prepare("
        SELECT nom_usuari, nom_complet, email, email_verificat, telefon, ciutat, edat
        FROM usuaris
        WHERE id = ?
    ");
    $stmt->execute([$usuari_id]);
    $usuari = $stmt->fetch();
 
    // Consultar últimes 10 accions i últim login
    $stmt = $pdo->prepare("SELECT accio, ip_client, data_hora FROM activitat WHERE usuari_id = ? ORDER BY data_hora DESC LIMIT 10");
    $stmt->execute([$usuari_id]);
    $historial = $stmt->fetchAll();
 
    // Últim accés a l'aplicació
    $stmt = $pdo->prepare("
        SELECT data_hora
        FROM activitat
        WHERE usuari_id = ?
        AND accio IN ('login', 'auto-login', 'login-2fa')
        ORDER BY data_hora DESC
        LIMIT 1
    ");
 
    $stmt->execute([$usuari_id]);
    $ultima_activitat = $stmt->fetch(PDO::FETCH_ASSOC);
 
    $data_ultim_login = $ultima_activitat['data_hora'] ?? 'N/A';
 
    // Total autenticacions
    $stmt = $pdo->prepare("
        SELECT
            SUM(accio = 'login')      AS logins_manuals,
            SUM(accio = 'auto-login') AS auto_logins,
            SUM(accio = 'login-2fa') AS logins_2fa,
            SUM(accio = 'error-login') AS error_logins,
            SUM(accio = 'restablir-contrasenya') AS restabliments_contrasenya,
            SUM(accio IN ('login', 'auto-login', 'login-2fa')) AS total
        FROM activitat
        WHERE usuari_id = ?
    ");
    $stmt->execute([$usuari_id]);
    $autenticacions = $stmt->fetch();
} catch (PDOException $e) {
    $error = "Error en recuperar les dades. Motiu: " . $e->getMessage();
}
?>
 
 
 
<html>
<head>
    <meta lang="ca">
    <meta charset="UTF-8">
    <title>Zona privada</title>
    <link rel="stylesheet" href="./css/privada.css">
</head>
<body>
    <div class="dashboard-container">
       
        <header class="welcome-header">
            <h1>Benvingut, <span><?php echo htmlspecialchars($_SESSION['usuari']['nom_complet']); ?></span></h1>
            <div class="last-access-banner">
                Darrer accés registrat: <strong><?php echo htmlspecialchars($data_ultim_login); ?></strong>
            </div>
        </header>
 
        <section class="user-data-card full-width">
            <div class="card-header">
                <h3>Les teves dades personals</h3>
                <a href="editarPerfil.php" class="btn-edit">Editar Perfil</a>
            </div>
            <div class="data-grid">
                <div class="data-item"><strong>Nom d'usuari:</strong> <?= htmlspecialchars($usuari['nom_usuari']) ?></div>
                <div class="data-item"><strong>Nom complet:</strong> <?= htmlspecialchars($usuari['nom_complet']) ?></div>
                <div class="data-item"><strong>Ciutat:</strong> <?= htmlspecialchars($usuari['ciutat'] ?: '-') ?></div>
                <div class="data-item"><strong>Telèfon:</strong> <?= htmlspecialchars($usuari['telefon'] ?: '-') ?></div>
                <div class="data-item"><strong>Edat:</strong> <?= htmlspecialchars($usuari['edat'] ?: '-') ?> anys</div>
                <div class="data-item email-status">
                    <strong>Email:</strong> <?= htmlspecialchars($usuari['email']) ?>
                    <?php if ($usuari['email_verificat'] === 'si'): ?>
                        <span class="badge badge-success">Verificat</span>
                    <?php else: ?>
                        <span class="badge badge-danger">No verificat <a href="verificaCorreu.php">(Verificar ara)</a></span>
                    <?php endif; ?>
                </div>
                <?php if (es_admin()): // Únicament es mostrarà si és un usuari administrador?>
                    <div class="admin-zone">
                        <a href="taulerAdmin.php" class="btn-admin">Accedir al Tauler d'Administració</a>
                    </div>
                <?php endif; ?>
            </div>
        </section>
 
        <div class="bottom-grid">
           
            <section class="card history-card">
                <h3>Historial d'activitat</h3>
                <div class="activity-list">
                    <?php foreach ($historial as $index => $act): ?>
                        <div class="activity-item <?= $index === 0 ? 'latest' : '' ?>"> <!-- Si és el primer de la llista afegim la classe "latest" -->
                            <span class="activity-date"><?= htmlspecialchars($act['data_hora']) ?></span>
                            <span class="activity-action"><?= htmlspecialchars($act['accio']) ?></span>
                            <span class="activity-ip"><?= htmlspecialchars($act['ip_client']) ?></span>
                        </div>
                    <?php endforeach; ?>
                </div>
            </section>
 
            <section class="card stats-card">
                <h3>Estadístiques d'accés</h3>
                <div class="stats-list">
                    <div class="stat-row"><span>Total autenticacions</span> <strong><?= $autenticacions['total'] ?></strong></div>
                    <div class="stat-row"><span>Logins manuals</span> <strong><?= $autenticacions['logins_manuals'] ?></strong></div>
                    <div class="stat-row"><span>Auto-logins</span> <strong><?= $autenticacions['auto_logins'] ?></strong></div>
                    <div class="stat-row"><span>Logins 2FA</span> <strong><?= $autenticacions['logins_2fa'] ?></strong></div>
                    <div class="stat-row"><span>Logins erronis</span> <strong class="text-danger"><?= $autenticacions['error_logins'] ?></strong></div>
                    <div class="stat-row"><span>Restabliments de contrasenya</span> <strong><?= $autenticacions['restabliments_contrasenya'] ?></strong></div>
                </div>
            </section>
        </div>
    </div>
 
    <a href="logout.php" class="btn-logout-fixed">Tancar sessió</a>
</body>
</html>
</pre>

Revisió de 02:22, 12 gen 2026

Pàgina privada

Quan un usuari s'autentica amb les seves credencials, pot accedir a una pàgina privada. Dins d'aquesta pàgina es troba:

  • Les dades personals de l'usuari
  • Les últimes 10 accions de l'usuari
  • Les estadístiques d'autenticació
    • Última autenticació
    • Total d'autenticacions, autenticacions mitjançant login normal, auto-login o login-2fa, autenticacions errònies, etc
  • Un botó per modificar les dades de l'usuari
  • Un botó per tancar la sessió

Inicialització de la sessió i connexió a la BD

Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML

session_start();

A més, hem de requerir el fitxer amb les funcions i una connexió a la BD. En aquest cas, únicament mostrarem dades dins la pàgina, per tant farem servir la connexió de lecutra.

require 'funcions.php';
require './connexioBD/connexioR.php';

Requerir autenticació

Per accedir a aquesta pàgina, és imperatiu que l'usuari estigui autenticat, en cas contrari no hi pot accedir.

Per verificar que l'usuari està autenticat, farem servir la funció requerir_autenticacio

// Requerir autenticació per accedir a la pàgina
requerir_autenticacio();

Recuperació de les dades de l'usuari

Per poder mostrar les dades de l'usuari primer les haurem de recuperar de les taules de la BD

Per això recuperarem l’ID de l’usuari que ha iniciat sessió a partir de la sessió i esborrarem qualsevol codi de verificació residual que hagi quedat de l’autenticació amb 2FA o la verificació del correu electrònic.

// ID de l'usuari
$usuari_id = $_SESSION['usuari']['id'];

unset($_SESSION['codi_verificacio']); // Eliminar codi de sessió

Un cop recuperat la ID de l'usuari, realitzarem una consulta per recuperar les dades personals, les últimes accions i les estadístiques d'autenticació.

Recuperació de les dades personals

Per recuperar les dades personals de l'usuari únicament consultarem els camps de la taula usuaris, cercant el registre amb la mateixa ID que s'ha recuperat de la sessió

// Consultar dades de l'usuari
$stmt = $pdo->prepare("
    SELECT nom_usuari, nom_complet, email, email_verificat, telefon, ciutat, edat
    FROM usuaris
    WHERE id = ?
");
$stmt->execute([$usuari_id]);
$usuari = $stmt->fetch();

Recuperació de les últimes accions

Per recuperar les últimes accions de l'usuari, cercarem de forma descendent per data (més recent a més antic) tots els registres amb l'ID de l'usuari de la sessió. Aquests resultats els limitarem a 10

// Consultar últimes 10 accions i últim login
$stmt = $pdo->prepare("SELECT accio, ip_client, data_hora FROM activitat WHERE usuari_id = ? ORDER BY data_hora DESC LIMIT 10");
$stmt->execute([$usuari_id]);
$historial = $stmt->fetchAll();

Recuperació de les estadístiques d'autenticació

Primer, recuperarem la última autenticació, per això farem una consulta SQL on recuperem tots els registres de la taula activitat on la ID sigui la de l'usuari i l'acció sigui qualsevol tipus de login ordenada de forma descendent per data (més recent a més antiga). Limitarem el resultat a un sol registre que serà l'autenticació més recent.

Un cop recuperat el registre, extrarurem la data i hora de l'acció

// Últim accés a l'aplicació
$stmt = $pdo->prepare("
    SELECT data_hora
    FROM activitat
    WHERE usuari_id = ?
    AND accio IN ('login', 'auto-login', 'login-2fa')
    ORDER BY data_hora DESC
    LIMIT 1
");

$stmt->execute([$usuari_id]);
$ultima_activitat = $stmt->fetch(PDO::FETCH_ASSOC);

$data_ultim_login = $ultima_activitat['data_hora'] ?? 'N/A';

Seguidament, recuperarem el total d'accions de cada tipus mitjançant una consulta SQL

// Total autenticacions $stmt = $pdo->prepare("

   SELECT 
       SUM(accio = 'login')      AS logins_manuals,
       SUM(accio = 'auto-login') AS auto_logins,
       SUM(accio = 'login-2fa') AS logins_2fa,
       SUM(accio = 'error-login') AS error_logins,
       SUM(accio = 'restablir-contrasenya') AS restabliments_contrasenya,
       SUM(accio IN ('login', 'auto-login', 'login-2fa')) AS total
   FROM activitat
   WHERE usuari_id = ?

"); $stmt->execute([$usuari_id]); $autenticacions = $stmt->fetch();

Mostra de les dades

Dades personals

Les dades personals les recuperarem de la consulta SQL realitzada per aquesta part. Mostrarem les dades amb escapament per evitar atacs XSS.

A més a més, es mostrarà si l'email està o no verificat. En cas que no ho estigui, s'inclourà un enllaç per poder verificar-lo

<div class="data-item"><strong>Nom d'usuari:</strong> <?= htmlspecialchars($usuari['nom_usuari']) ?></div>
<div class="data-item"><strong>Nom complet:</strong> <?= htmlspecialchars($usuari['nom_complet']) ?></div>
<div class="data-item"><strong>Ciutat:</strong> <?= htmlspecialchars($usuari['ciutat'] ?: '-') ?></div>
<div class="data-item"><strong>Telèfon:</strong> <?= htmlspecialchars($usuari['telefon'] ?: '-') ?></div>
<div class="data-item"><strong>Edat:</strong> <?= htmlspecialchars($usuari['edat'] ?: '-') ?> anys</div>
<div class="data-item email-status">
    <strong>Email:</strong> <?= htmlspecialchars($usuari['email']) ?>
    <?php if ($usuari['email_verificat'] === 'si'): ?>
        <span class="badge badge-success">Verificat</span>
    <?php else: ?>
        <span class="badge badge-danger">No verificat <a href="verificaCorreu.php">(Verificar ara)</a></span>
    <?php endif; ?>
</div>

Un exemple amb l'email verifcat es visualitzaria de la següent forma

Un exemple amb l'email sense verificar es visualitzaria de la següent forma:

Últimes accions

Mitjançant un foreach a l'array de la consulta SQL realitzada per aquesta part, obtenim els detalls de cada acció.

<section class="card history-card">
    <h3>Historial d'activitat</h3>
    <div class="activity-list">
        <?php foreach ($historial as $index => $act): ?> 
            <div class="activity-item <?= $index === 0 ? 'latest' : '' ?>"> <!-- Si és el primer de la llista afegim la classe "latest" -->
                <span class="activity-date"><?= htmlspecialchars($act['data_hora']) ?></span>
                <span class="activity-action"><?= htmlspecialchars($act['accio']) ?></span>
                <span class="activity-ip"><?= htmlspecialchars($act['ip_client']) ?></span>
            </div>
        <?php endforeach; ?>
    </div>
</section>

Un exemple amb diverses accions realitzades es veuria així

Estadístiques d'autenticació

Per últim, d'igual forma que amb les dades personals de l'usuari, mostrarem les estadístiques d'autenticació

<section class="card stats-card">
    <h3>Estadístiques d'accés</h3>
    <div class="stats-list">
        <div class="stat-row"><span>Total autenticacions</span> <strong><?= $autenticacions['total'] ?></strong></div>
        <div class="stat-row"><span>Logins manuals</span> <strong><?= $autenticacions['logins_manuals'] ?></strong></div>
        <div class="stat-row"><span>Auto-logins</span> <strong><?= $autenticacions['auto_logins'] ?></strong></div>
        <div class="stat-row"><span>Logins 2FA</span> <strong><?= $autenticacions['logins_2fa'] ?></strong></div>
        <div class="stat-row"><span>Logins erronis</span> <strong class="text-danger"><?= $autenticacions['error_logins'] ?></strong></div>
        <div class="stat-row"><span>Restabliments de contrasenya</span> <strong><?= $autenticacions['restabliments_contrasenya'] ?></strong></div>
    </div>
</section>

Les quals es visualitzarien de la següent manera

L'últim accés es mostra a la part superior de la pàgina

<header class="welcome-header">
    <h1>Benvingut, <span><?php echo htmlspecialchars($_SESSION['usuari']['nom_complet']); ?></span></h1>
    <div class="last-access-banner">
        Darrer accés registrat: <strong><?php echo htmlspecialchars($data_ultim_login); ?></strong>
    </div>
</header>

I es visualitza de la següent manera

Accés d'un administrador

En l'aplicatiu, un administrador, ja sigui editor o visualitzador té accés a un tauler d'administració. Aquest tauler s'accedeix mitjançant la pàgina privada.

Dins de les dades personals, en cas de ser administrador, es mostrarà un botó de navegació per dirigir-se al tauler

<div class="data-grid">
    <div class="data-item"><strong>Nom d'usuari:</strong> <?= htmlspecialchars($usuari['nom_usuari']) ?></div>
    <div class="data-item"><strong>Nom complet:</strong> <?= htmlspecialchars($usuari['nom_complet']) ?></div>
    <div class="data-item"><strong>Ciutat:</strong> <?= htmlspecialchars($usuari['ciutat'] ?: '-') ?></div>
    <div class="data-item"><strong>Telèfon:</strong> <?= htmlspecialchars($usuari['telefon'] ?: '-') ?></div>
    <div class="data-item"><strong>Edat:</strong> <?= htmlspecialchars($usuari['edat'] ?: '-') ?> anys</div>
    <div class="data-item email-status">
        <strong>Email:</strong> <?= htmlspecialchars($usuari['email']) ?>
        <?php if ($usuari['email_verificat'] === 'si'): ?>
            <span class="badge badge-success">Verificat</span>
        <?php else: ?>
            <span class="badge badge-danger">No verificat <a href="verificaCorreu.php">(Verificar ara)</a></span>
        <?php endif; ?>
    </div>
    <?php if (es_admin()): // Únicament es mostrarà si és un usuari administrador?>
        <div class="admin-zone">
            <a href="taulerAdmin.php" class="btn-admin">Accedir al Tauler d'Administració</a>
        </div>
    <?php endif; ?>
</div>

La secció de dades personals d'un administrador es visualitzaria de la següent manera

Botó per modificar les dades personals

A tots els usuaris se li dóna la possibilitat d'editar les seves dades personals mitjançant un formulari. A aquest formulari s'accedeix a partir de la pàgina privada, on a la part de dades personals hi surt un botó de navegació.

<div class="card-header">
       <h3>Les teves dades personals</h3>
       <a href="editarPerfil.php" class="btn-edit">Editar Perfil</a>
</div>

El botó de navegació es visualitza de la següent manera

Botó per tancar la sessió

Per últim, a la part inferior dreta de la pàgina trobem un botó per tancar la sessió, el qual crida al codi PHP "logout"

<a href="logout.php" class="btn-logout-fixed">Tancar sessió</a>

El botó de tancar la sessió es visualitza de la següent manera:

Codi complet

<?php
session_start();
require 'funcions.php';
require './connexioBD/connexioR.php';

// Requerir autenticació per accedir a la pàgina
requerir_autenticacio();

// ID de l'usuari
$usuari_id = $_SESSION['usuari']['id'];

unset($_SESSION['codi_verificacio']); // Eliminar codi de sessió

try {
    // Consultar dades de l'usuari
    $stmt = $pdo->prepare("
        SELECT nom_usuari, nom_complet, email, email_verificat, telefon, ciutat, edat
        FROM usuaris
        WHERE id = ?
    ");
    $stmt->execute([$usuari_id]);
    $usuari = $stmt->fetch();

    // Consultar últimes 10 accions i últim login
    $stmt = $pdo->prepare("SELECT accio, ip_client, data_hora FROM activitat WHERE usuari_id = ? ORDER BY data_hora DESC LIMIT 10");
    $stmt->execute([$usuari_id]);
    $historial = $stmt->fetchAll();

    // Últim accés a l'aplicació
    $stmt = $pdo->prepare("
        SELECT data_hora
        FROM activitat
        WHERE usuari_id = ?
        AND accio IN ('login', 'auto-login', 'login-2fa')
        ORDER BY data_hora DESC
        LIMIT 1
    ");

    $stmt->execute([$usuari_id]);
    $ultima_activitat = $stmt->fetch(PDO::FETCH_ASSOC);

    $data_ultim_login = $ultima_activitat['data_hora'] ?? 'N/A';

    // Total autenticacions
    $stmt = $pdo->prepare("
        SELECT 
            SUM(accio = 'login')      AS logins_manuals,
            SUM(accio = 'auto-login') AS auto_logins,
            SUM(accio = 'login-2fa') AS logins_2fa,
            SUM(accio = 'error-login') AS error_logins,
            SUM(accio = 'restablir-contrasenya') AS restabliments_contrasenya,
            SUM(accio IN ('login', 'auto-login', 'login-2fa')) AS total
        FROM activitat
        WHERE usuari_id = ?
    ");
    $stmt->execute([$usuari_id]);
    $autenticacions = $stmt->fetch();
} catch (PDOException $e) {
    $error = "Error en recuperar les dades. Motiu: " . $e->getMessage();
}
?>



<html>
<head>
    <meta lang="ca">
    <meta charset="UTF-8">
    <title>Zona privada</title>
    <link rel="stylesheet" href="./css/privada.css">
</head>
<body>
    <div class="dashboard-container">
        
        <header class="welcome-header">
            <h1>Benvingut, <span><?php echo htmlspecialchars($_SESSION['usuari']['nom_complet']); ?></span></h1>
            <div class="last-access-banner">
                Darrer accés registrat: <strong><?php echo htmlspecialchars($data_ultim_login); ?></strong>
            </div>
        </header>

        <section class="user-data-card full-width">
            <div class="card-header">
                <h3>Les teves dades personals</h3>
                <a href="editarPerfil.php" class="btn-edit">Editar Perfil</a>
            </div>
            <div class="data-grid">
                <div class="data-item"><strong>Nom d'usuari:</strong> <?= htmlspecialchars($usuari['nom_usuari']) ?></div>
                <div class="data-item"><strong>Nom complet:</strong> <?= htmlspecialchars($usuari['nom_complet']) ?></div>
                <div class="data-item"><strong>Ciutat:</strong> <?= htmlspecialchars($usuari['ciutat'] ?: '-') ?></div>
                <div class="data-item"><strong>Telèfon:</strong> <?= htmlspecialchars($usuari['telefon'] ?: '-') ?></div>
                <div class="data-item"><strong>Edat:</strong> <?= htmlspecialchars($usuari['edat'] ?: '-') ?> anys</div>
                <div class="data-item email-status">
                    <strong>Email:</strong> <?= htmlspecialchars($usuari['email']) ?>
                    <?php if ($usuari['email_verificat'] === 'si'): ?>
                        <span class="badge badge-success">Verificat</span>
                    <?php else: ?>
                        <span class="badge badge-danger">No verificat <a href="verificaCorreu.php">(Verificar ara)</a></span>
                    <?php endif; ?>
                </div>
                <?php if (es_admin()): // Únicament es mostrarà si és un usuari administrador?>
                    <div class="admin-zone">
                        <a href="taulerAdmin.php" class="btn-admin">Accedir al Tauler d'Administració</a>
                    </div>
                <?php endif; ?>
            </div>
        </section>

        <div class="bottom-grid">
            
            <section class="card history-card">
                <h3>Historial d'activitat</h3>
                <div class="activity-list">
                    <?php foreach ($historial as $index => $act): ?> 
                        <div class="activity-item <?= $index === 0 ? 'latest' : '' ?>"> <!-- Si és el primer de la llista afegim la classe "latest" -->
                            <span class="activity-date"><?= htmlspecialchars($act['data_hora']) ?></span>
                            <span class="activity-action"><?= htmlspecialchars($act['accio']) ?></span>
                            <span class="activity-ip"><?= htmlspecialchars($act['ip_client']) ?></span>
                        </div>
                    <?php endforeach; ?>
                </div>
            </section>

            <section class="card stats-card">
                <h3>Estadístiques d'accés</h3>
                <div class="stats-list">
                    <div class="stat-row"><span>Total autenticacions</span> <strong><?= $autenticacions['total'] ?></strong></div>
                    <div class="stat-row"><span>Logins manuals</span> <strong><?= $autenticacions['logins_manuals'] ?></strong></div>
                    <div class="stat-row"><span>Auto-logins</span> <strong><?= $autenticacions['auto_logins'] ?></strong></div>
                    <div class="stat-row"><span>Logins 2FA</span> <strong><?= $autenticacions['logins_2fa'] ?></strong></div>
                    <div class="stat-row"><span>Logins erronis</span> <strong class="text-danger"><?= $autenticacions['error_logins'] ?></strong></div>
                    <div class="stat-row"><span>Restabliments de contrasenya</span> <strong><?= $autenticacions['restabliments_contrasenya'] ?></strong></div>
                </div>
            </section>
        </div>
    </div>

    <a href="logout.php" class="btn-logout-fixed">Tancar sessió</a>
</body>
</html>