Étape 3 — Affichage d'une fiche PC

Lire le JSON enregistré et l'afficher dans une page Bootstrap 5 lisible.

    5ttr
  • Exercice ambitieux

Objectif de l'étape

À la fin, tu pourras accéder à /inventaire/pc/PC-DE-LUDO dans ton navigateur et voir une page complète avec :

  • les infos générales du PC (OS, CPU, RAM, dernière mise à jour),
  • une liste des disques avec leur état,
  • les 10 processus les plus gourmands,
  • les applications installées,
  • les téléchargements récents.

On ne fait pas encore de graphe ni d'historique. C'est pour l'étape 4.

1. Bootstrap 5 — gabarit de base

Crée public/partials/header.php (pour réutiliser le même gabarit partout) :

<?php
// $titre est passée par chaque page qui inclut ce fichier
$titre = $titre ?? 'Inventaire';
?>
<!DOCTYPE html>
<html lang="fr" data-bs-theme="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars($titre) ?> — Inventaire</title>
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/inventaire/css/app.css">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary border-bottom">
    <div class="container">
        <a class="navbar-brand fw-bold" href="/inventaire">
            🖥️ Inventaire
        </a>
        <div class="navbar-nav">
            <a class="nav-link" href="/inventaire">Dashboard</a>
        </div>
    </div>
</nav>
<main class="container py-4">

Et public/partials/footer.php :

</main>
<footer class="container py-4 text-center text-secondary small">
    Projet inventaire — 5e TQ Informatique
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

💡 Pourquoi data-bs-theme="dark" ? Bootstrap 5.3 a un mode sombre natif. Une ligne, tout s'adapte. Pratique pour un dashboard d'admin (et plus écoresponsable sur OLED).

⚠️ Toujours htmlspecialchars() quand tu affiches une donnée qui vient d'ailleurs (JSON, formulaire, URL). Sinon, faille XSS garantie.

2. La fiche PC

Crée public/pc.php :

<?php
declare(strict_types=1);
require __DIR__ . '/../src/storage.php';

// L'URL ressemble à : /inventaire/pc/PC-DE-LUDO
// On extrait le hostname de l'URL.
$segments = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
$hostname = end($segments);
$hostname = preg_replace('/[^a-zA-Z0-9_\-]/', '', $hostname); // sécurité

if ($hostname === '') {
    http_response_code(400);
    echo "Hostname manquant.";
    exit;
}

$rapport = charger_dernier_rapport($hostname);

if ($rapport === null) {
    http_response_code(404);
    echo "Aucun rapport pour le PC <strong>" . htmlspecialchars($hostname) . "</strong>.";
    exit;
}

$titre = "PC " . $hostname;
require __DIR__ . '/partials/header.php';
?>

<h1 class="h2 mb-1"><?= htmlspecialchars($hostname) ?></h1>
<p class="text-secondary">
    Dernier rapport :
    <?= htmlspecialchars($rapport['timestamp'] ?? 'inconnu') ?>
</p>

<div class="row g-3 mb-4">
    <!-- Carte OS -->
    <div class="col-md-3">
        <div class="card h-100">
            <div class="card-body">
                <div class="text-secondary small">Système</div>
                <div class="fw-bold">
                    <?= htmlspecialchars($rapport['system']['os'] ?? '—') ?>
                </div>
                <div class="small text-secondary">
                    v<?= htmlspecialchars($rapport['system']['osVersion'] ?? '') ?>
                </div>
            </div>
        </div>
    </div>

    <!-- Carte CPU -->
    <div class="col-md-3">
        <div class="card h-100">
            <div class="card-body">
                <div class="text-secondary small">Processeur</div>
                <div class="fw-bold">
                    <?= htmlspecialchars($rapport['system']['cpu'] ?? '—') ?>
                </div>
                <div class="small text-secondary">
                    <?= (int)($rapport['system']['cpuCores'] ?? 0) ?> cœurs
                </div>
            </div>
        </div>
    </div>

    <!-- À toi : carte RAM, carte Disque principal -->
</div>

<!-- Liste des disques -->
<section class="mb-4">
    <h2 class="h5">Disques</h2>
    <table class="table table-sm">
        <thead>
            <tr><th>Lettre</th><th>Total (Go)</th><th>Libre (Go)</th><th>Usage</th></tr>
        </thead>
        <tbody>
        <?php foreach (($rapport['disks'] ?? []) as $disque): ?>
            <?php
                $total = (float)($disque['totalGo'] ?? 0);
                $libre = (float)($disque['freeGo'] ?? 0);
                $usage = $total > 0 ? round((1 - $libre / $total) * 100) : 0;
            ?>
            <tr>
                <td><?= htmlspecialchars($disque['letter'] ?? '?') ?></td>
                <td><?= number_format($total, 1, ',', ' ') ?></td>
                <td><?= number_format($libre, 1, ',', ' ') ?></td>
                <td>
                    <div class="progress" style="height: 18px;">
                        <div class="progress-bar
                                    <?= $usage > 85 ? 'bg-danger' : ($usage > 70 ? 'bg-warning' : 'bg-success') ?>"
                             style="width: <?= $usage ?>%">
                            <?= $usage ?> %
                        </div>
                    </div>
                </td>
            </tr>
        <?php endforeach; ?>
        </tbody>
    </table>
</section>

<!-- À toi : sections processus, applications, téléchargements -->

<?php require __DIR__ . '/partials/footer.php'; ?>

3. La fonction charger_dernier_rapport

À ajouter dans src/storage.php :

function charger_dernier_rapport(string $hostname): ?array
{
    $fichier = DATA_ROOT . '/' . $hostname . '/latest.json';
    if (!is_file($fichier)) {
        return null;
    }
    $contenu = file_get_contents($fichier);
    $data = json_decode($contenu, true);
    return is_array($data) ? $data : null;
}

4. Ce que tu dois compléter toi-même

Le code ci-dessus te donne le squelette. À toi de compléter, en suivant exactement le même schéma :

a) Carte RAM

Affiche : RAM totale, RAM libre, et une barre de progression indiquant le pourcentage d'utilisation.

b) Carte « Disque C: »

Reprend l'info du premier disque pour avoir un aperçu rapide en haut de page.

c) Section processus

Liste les topProcesses dans un <table> ou des <div class="card">. Affiche le nom, le CPU (en secondes — explique-le en tooltip Bootstrap), et la mémoire en Mo.

d) Section applications

Affiche applications dans un tableau avec recherche côté client. Le plus simple : un <input> qui filtre les lignes en JavaScript.

document.getElementById('appSearch').addEventListener('input', (e) => {
    const q = e.target.value.toLowerCase();
    document.querySelectorAll('#appList tr').forEach(tr => {
        tr.style.display = tr.textContent.toLowerCase().includes(q) ? '' : 'none';
    });
});

e) Section téléchargements récents

Une liste simple. Pense à formater la date en français (date('d/m/Y H:i', strtotime($download['downloadedAt']))).

f) Un indicateur écoresponsable

Au choix :

  • âge du dernier rapport (si > 7 jours → badge orange « rapport ancien ») ;
  • pourcentage de RAM utilisé en moyenne sur l'historique (à faire à l'étape 4) ;
  • score d'utilisation : faible RAM + faible CPU pendant une semaine → suggérer « PC sous-utilisé, à mutualiser ? ».

🤖 Travailler avec l'IA — la stratégie « squelette + remplissage »

À cette étape, tu as un squelette qui tourne (carte OS, carte CPU, tableau disques). Pour les autres sections, le bon prompt c'est :

Voici ma carte CPU dans une fiche PHP : [colle le bloc HTML de la carte CPU]. Sur le même modèle, fais-moi la carte RAM, qui affiche la RAM totale en Go, la RAM libre, et une barre de progression Bootstrap indiquant le pourcentage d'utilisation. Garde exactement le même style de card Bootstrap 5 dark mode. Donne juste le HTML + PHP, sans CSS ajouté.

Pourquoi c'est un bon prompt :

  • Tu donnes un exemple existant (l'IA copie ton style).
  • Tu précises exactement ce que tu veux.
  • Tu bornes le périmètre (pas de CSS, pas de framework, pas de JS).

L'IA livre 15 lignes que tu colles, et qui s'intègrent visuellement avec le reste de ta page.

5. Tester avec plusieurs PCs

Tu n'as qu'un seul PC ? Triche proprement : copie ton latest.json dans plusieurs sous-dossiers de data/pcs/ :

data/pcs/
├── PC-LUDO/latest.json
├── PC-AMINE/latest.json
└── PC-SOFIA/latest.json

Édite à la main les hostnames et quelques valeurs (RAM, espace disque) pour simuler un parc varié. C'est une technique d'ingénieur classique : on appelle ça des fixtures. On en reparle à l'étape 4 pour le dashboard.

✅ Critères de réussite de l'étape 3

  • [ ] L'URL /inventaire/pc/MON-HOSTNAME affiche bien les infos du PC.
  • [ ] Une URL avec un hostname inconnu renvoie un 404 propre.
  • [ ] Les disques apparaissent avec une barre de progression colorée selon l'usage (vert / jaune / rouge).
  • [ ] Le rendu est lisible en dark mode et en light mode (essaie de basculer data-bs-theme).
  • [ ] Aucun warning PHP dans la page (pas de Undefined index).
  • [ ] Tu peux expliquer à quoi sert htmlspecialchars.

⚠️ Pièges fréquents

Piège Solution
Undefined array key "system" Toujours $rapport['system']['os'] ?? '—'
Caractères é qui deviennent é Header charset=utf-8 + JSON_UNESCAPED_UNICODE
Quelqu'un met <script> dans son hostname htmlspecialchars() partout
404 alors que le fichier existe Vérifier is_file avec un var_dump du chemin

Pour la suite

À l'étape 4 : dashboard global, graphe d'espace disque dans le temps, et historique. C'est là que ça devient visuel.

Pour aller plus loin