Polar Code 🎭

Command Palette

Search for a command to run...

06
Pièce N°06

Module 6 : Les Fichiers - Archives de l'Ombre

L'archive sentait le vieux papier et la poussière. Des classeurs alignés, des dossiers épais. En PHP, les fichiers étaient ça : des archives. Des endroits où stocker des informations hors de la base de données, hors de la mémoire volatile. Des traces persistantes dans un monde éphémère. Il fallait savoir les ouvrir, les lire, les écrire. Et parfois, laisser quelqu'un en déposer un nouveau sur le pas de la porte.

Inclusion de fichiers (include, require) Diviser pour mieux régner. Morceler le code en fichiers réutilisables. Comme des dossiers séparés qu'on consulte quand on en a besoin.

<?php
// config.php - Un fichier de configuration sensible
define('DB_HOST', 'localhost');
define('DB_USER', 'user_sombre');
define('DB_PASS', 'M0t2P@sseTroubl3');
define('SITE_NAME', 'Réseau Alpha');

// Une fonction utilitaire
function logger($message) {
    $date = date('Y-m-d H:i:s');
    file_put_contents('logs.txt', "[$date] $message\n", FILE_APPEND);
}
<?php
// index.php - Le point d'entrée

// include : essaie d'inclure, continue si échec
include 'config.php';
echo "Bienvenue sur " . SITE_NAME . "<br>";

// require : exige le fichier, arrête si manquant
require 'config.php';

// include_once / require_once : inclut une seule fois
require_once 'config.php'; // Ne sera pas inclus à nouveau

// Exemple pratique : header et footer
require_once 'header.php';
?>
<section>
    <h2>▪ ZONE RESTREINTE ▪</h2>
    <p>Contenu confidentiel.</p>
</section>
<?php
require_once 'footer.php';
?>
<?php
// header.php
?>
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>▪ Archives Secrètes ▪</title>
    <style>
        body { font-family: 'Courier New', monospace; background: #0a0a0a; color: #aaa; margin: 0; }
        header { background: #111; border-bottom: 2px solid #8b0000; padding: 20px; }
        .logo { color: #8b0000; font-size: 24px; font-weight: bold; letter-spacing: 2px; }
        nav a { color: #ccc; margin-right: 20px; text-decoration: none; }
        nav a:hover { color: #8b0000; }
    </style>
</head>
<body>
    <header>
        <div class="logo">▪ RÉSEAU ALPHA ▪</div>
        <nav>
            <a href="index.php">Accueil</a>
            <a href="archives.php">Archives</a>
            <a href="upload.php">Dépôt</a>
        </nav>
    </header>
    <main style="padding: 20px;">

Lecture et écriture de fichiers Ouvrir, manipuler, fermer. Comme consulter un dossier confidentiel.

<?php
// archives.php
echo "<h2 style='color: #8b0000;'>▪ ARCHIVES CONFIDENTIELLES ▪</h2>";

// 1. ÉCRIRE dans un fichier (écrase le contenu existant)
$contenuSecret = "Contact: L'Ombre\nCode: N7\nRendez-vous: Pont, minuit\n";
$bytesEcrits = file_put_contents('dossier/contact.txt', $contenuSecret);

if ($bytesEcrits !== false) {
    echo "<p style='color: #4caf50;'>▪ FICHIER MIS À JOUR (" . $bytesEcrits . " octets) ▪</p>";
} else {
    echo "<p style='color: #ff5555;'>▪ ÉCHEC D'ÉCRITURE ▪ Vérifiez les permissions.</p>";
}

// 2. LIRE un fichier entier
if (file_exists('dossier/contact.txt')) {
    $contenu = file_get_contents('dossier/contact.txt');
    echo "<div style='background: #111; padding: 15px; margin: 15px 0; border-left: 3px solid #8b0000;'>";
    echo "<h4>Contenu du dossier :</h4>";
    echo "<pre style='color: #ccc;'>" . htmlspecialchars($contenu) . "</pre>";
    echo "</div>";
} else {
    echo "<p style='color: #ff5555;'>▪ DOSSIER INTROUVABLE ▪</p>";
}

// 3. LIRE ligne par ligne (pour les gros fichiers)
echo "<h3>▪ JOURNAL DES ÉVÉNEMENTS ▪</h3>";
if (file_exists('dossier/journal.log')) {
    $lignes = file('dossier/journal.log', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    
    echo "<ul style='color: #888;'>";
    foreach ($lignes as $index => $ligne) {
        echo "<li>Ligne " . ($index + 1) . ": " . htmlspecialchars($ligne) . "</li>";
    }
    echo "</ul>";
}

// 4. ÉCRIRE en mode APPEND (ajouter à la fin)
$nouvelleEntree = date('Y-m-d H:i:s') . " - Contact établi avec source anonyme.\n";
file_put_contents('dossier/journal.log', $nouvelleEntree, FILE_APPEND);
echo "<p style='color: #aaa; font-size: 0.9em;'>▪ ENTRÉE AJOUTÉE AU JOURNAL ▪</p>";

// 5. Manipulation avancée avec fopen/fwrite/fclose
echo "<h3>▪ RAPPORT INTERNE (flux manuel) ▪</h3>";

$fichier = fopen('dossier/rapport.txt', 'a'); // 'a' pour append, 'w' pour write, 'r' pour read
if ($fichier) {
    fwrite($fichier, "--- Début de session " . date('Y-m-d H:i:s') . " ---\n");
    fwrite($fichier, "Utilisateur: Agent X\n");
    fwrite($fichier, "Action: Consultation archives\n");
    fwrite($fichier, "--- Fin de session ---\n\n");
    fclose($fichier);
    echo "<p style='color: #4caf50;'>▪ RAPPORT SIGNÉ ET CLASSÉ ▪</p>";
}
?>

Upload de fichiers Laisser les utilisateurs déposer des preuves. Des documents. Des pièces à conviction.

<?php
// upload.php
$message = '';
$couleurMessage = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fichier_secret'])) {
    $fichier = $_FILES['fichier_secret'];
    
    // Détails du fichier
    $nomOriginal = $fichier['name'];
    $tmpChemin = $fichier['tmp_name'];
    $taille = $fichier['size'];
    $erreur = $fichier['error'];
    
    // Dossier de destination
    $dossierUpload = 'uploads/';
    
    // Vérifications de sécurité
    $autorise = false;
    $extensionsAutorisees = ['pdf', 'txt', 'jpg', 'png'];
    $extension = strtolower(pathinfo($nomOriginal, PATHINFO_EXTENSION));
    
    // Vérifier l'extension
    if (!in_array($extension, $extensionsAutorisees)) {
        $message = "▪ TYPE DE FICHIER INTERDIT ▪ Seuls PDF, TXT, JPG, PNG sont autorisés.";
        $couleurMessage = '#ff5555';
    }
    // Vérifier la taille (max 2 Mo)
    elseif ($taille > 2 * 1024 * 1024) {
        $message = "▪ FICHIER TROP VOLUMINEUX ▪ Maximum 2 Mo.";
        $couleurMessage = '#ff5555';
    }
    // Vérifier les erreurs d'upload
    elseif ($erreur !== UPLOAD_ERR_OK) {
        $messagesErreur = [
            UPLOAD_ERR_INI_SIZE => 'Fichier trop grand (configuration serveur).',
            UPLOAD_ERR_FORM_SIZE => 'Fichier trop grand (formulaire).',
            UPLOAD_ERR_PARTIAL => 'Upload partiel.',
            UPLOAD_ERR_NO_FILE => 'Aucun fichier.',
            UPLOAD_ERR_NO_TMP_DIR => 'Dossier temporaire manquant.',
            UPLOAD_ERR_CANT_WRITE => 'Erreur d\'écriture.',
            UPLOAD_ERR_EXTENSION => 'Extension PHP bloquée.'
        ];
        $message = "▪ ERREUR D'UPLOAD ▪ " . ($messagesErreur[$erreur] ?? 'Code erreur: ' . $erreur);
        $couleurMessage = '#ff5555';
    }
    // Tout est bon
    else {
        // Renommer le fichier pour la sécurité
        $nouveauNom = 'doc_' . uniqid() . '_' . time() . '.' . $extension;
        $cheminFinal = $dossierUpload . $nouveauNom;
        
        // Déplacer le fichier
        if (move_uploaded_file($tmpChemin, $cheminFinal)) {
            // Enregistrer en base de données (simulé)
            $log = date('Y-m-d H:i:s') . " | Fichier: $nomOriginal | Stocké sous: $nouveauNom | Taille: " . round($taille/1024) . " Ko\n";
            file_put_contents('uploads/log_uploads.txt', $log, FILE_APPEND);
            
            $message = "▪ FICHIER REÇU ET VERROUILLÉ ▪<br>";
            $message .= "Nom original: $nomOriginal<br>";
            $message .= "Référence: $nouveauNom<br>";
            $message .= "Taille: " . round($taille/1024) . " Ko";
            $couleurMessage = '#4caf50';
        } else {
            $message = "▪ ÉCHEC DU TRANSFERT ▪ Problème de permissions.";
            $couleurMessage = '#ff5555';
        }
    }
}
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>▪ Dépôt Secret ▪</title>
    <style>
        body { font-family: monospace; background: #0a0a0a; color: #aaa; padding: 20px; }
        .container { max-width: 600px; margin: auto; background: #111; padding: 30px; border: 1px solid #333; }
        h2 { color: #8b0000; border-bottom: 1px solid #444; padding-bottom: 10px; }
        .message { padding: 15px; margin: 20px 0; border-radius: 0; }
        input[type="file"] { background: #222; color: #ccc; padding: 10px; border: 1px solid #444; width: 100%; margin: 10px 0; }
        button { background: #8b0000; color: #ccc; border: none; padding: 12px 24px; cursor: pointer; font-size: 16px; }
        button:hover { background: #a00000; }
        .info { color: #888; font-size: 0.9em; margin-top: 20px; border-top: 1px solid #333; padding-top: 15px; }
    </style>
</head>
<body>
    <div class="container">
        <h2>▪ DÉPÔT DE PREUVES ▪</h2>
        
        <?php if ($message): ?>
            <div class="message" style="border-left: 4px solid <?php echo $couleurMessage; ?>; background: #1a1a1a;">
                <?php echo $message; ?>
            </div>
        <?php endif; ?>
        
        <form method="POST" enctype="multipart/form-data">
            <p>Sélectionnez un fichier à transmettre :</p>
            <input type="file" name="fichier_secret" required>
            <br><br>
            <button type="submit">▪ VERROUILLER ET TRANSMETTRE ▪</button>
        </form>
        
        <div class="info">
            <strong>▪ CONSIGNES DE SÉCURITÉ ▪</strong><br>
            1. Formats autorisés : PDF, TXT, JPG, PNG<br>
            2. Taille maximale : 2 Mo<br>
            3. Les fichiers sont renommés et chiffrés<br>
            4. Toute transmission est tracée
        </div>
    </div>
</body>
</html>

Gestion des permissions Savoir qui peut faire quoi. Les droits d'accès. La clé de voûte de la sécurité.

<?php
// permissions.php
echo "<h2 style='color: #8b0000;'>▪ ÉTAT DU SYSTÈME ▪</h2>";

$fichiers = [
    'uploads/' => 'Dossier des uploads',
    'dossier/contact.txt' => 'Fichier contact',
    'dossier/journal.log' => 'Journal',
    'config.php' => 'Configuration'
];

foreach ($fichiers as $chemin => $description) {
    echo "<div style='background: #111; padding: 10px; margin: 10px 0; border-left: 3px solid #444;'>";
    echo "<strong>$description</strong> ($chemin)<br>";
    
    if (file_exists($chemin)) {
        $perms = fileperms($chemin);
        $proprio = posix_getpwuid(fileowner($chemin));
        $groupe = posix_getgrgid(filegroup($chemin));
        
        echo "Propriétaire : " . ($proprio['name'] ?? 'Inconnu') . "<br>";
        echo "Groupe : " . ($groupe['name'] ?? 'Inconnu') . "<br>";
        echo "Permissions : " . substr(sprintf('%o', $perms), -4) . "<br>";
        echo "Lisible : " . (is_readable($chemin) ? '✅' : '❌') . " | ";
        echo "Écrivable : " . (is_writable($chemin) ? '✅' : '❌') . " | ";
        echo "Exécutable : " . (is_executable($chemin) ? '✅' : '❌');
        
        // Recommandations
        if (strpos($chemin, '.php') !== false && is_writable($chemin)) {
            echo "<br><span style='color: #ff5555;'>▪ ATTENTION : Fichier PHP écrivable !</span>";
        }
    } else {
        echo "<span style='color: #ff5555;'>▪ FICHIER INTROUVABLE ▪</span>";
    }
    
    echo "</div>";
}

// Vérification des dossiers critiques
echo "<h3>▪ VÉRIFICATIONS DE SÉCURITÉ ▪</h3>";

// Le dossier uploads doit être écrivable mais pas exécutable
if (is_dir('uploads/')) {
    if (is_writable('uploads/')) {
        echo "<p style='color: #4caf50;'>✅ Dossier uploads écrivable (nécessaire)</p>";
    }
    if (!is_executable('uploads/')) {
        echo "<p style='color: #4caf50;'>✅ Dossier uploads non exécutable (sécurisé)</p>";
    } else {
        echo "<p style='color: #ff5555;'>❌ DANGER : Dossier uploads exécutable !</p>";
    }
}

// Fichiers de config ne doivent pas être accessibles depuis le web
echo "<p style='color: #888; font-size: 0.9em;'>▪ Conseil : Placez les fichiers sensibles hors de la racine web.</p>";
?>

Je refermai le classeur métallique. Les fichiers. Des archives silencieuses qui attendaient qu'on les consulte. Les inclure pour structurer le code. Les lire pour en extraire l'information. Les écrire pour laisser une trace. Accepter des uploads, mais avec méfiance. Et toujours, toujours vérifier les permissions. Parce que dans l'ombre, une permission trop ouverte était une porte laissée entrouverte. Et les portes entrouvertes, dans notre métier, finissaient toujours par laisser entrer quelqu'un qu'on n'attendait pas.