Dette modul dækker opbevaring, strukturering og manipulation af data, så dine webapplikationer kan huske information permanent.
Lektion 12: Filhåndtering og filupload
Nogle gange har du brug for at gemme data direkte i filer på serveren eller give brugere lov til at uploade billeder, CV'er eller dokumenter.
Læsning og skrivning til tekstfiler
PHP har indbyggede funktioner til hurtigt at læse og skrive data til disk uden en database.
<?php
$filnavn = "log.txt";
// Skriv data til en fil (Sletter eksisterende indhold)
file_put_contents($filnavn, "Første linje i loggen.\n");
// Tilføj data til bunden af en eksisterende fil (FILE_APPEND)
file_put_contents($filnavn, "Ny aktivitet registreret.\n", FILE_APPEND);
// Læs hele filen ind i en variabel og udskriv den
if (file_exists($filnavn)) {
$indhold = file_get_contents($filnavn);
echo nl2br(htmlspecialchars($indhold)); // nl2br omdanner \n til <br> i HTML
}
Sikker upload af filer via formularer
Når brugere uploader filer, gemmer PHP informationerne i superglobalen $_FILES. Husk altid at tilføje enctype="multipart/form-data" til din HTML-formular, ellers virker filupload ikke.
Her er et komplet og sikkert eksempel på et script til billed-upload (upload.php):
<?php
$besked = "";
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_FILES["billede"])) {
$fil = $_FILES["billede"];
// 1. Definer tilladte indstillinger
$tilladteTyper = ["image/jpeg", "image/png", "image/webp"];
$maksStørrelse = 2 * 1024 * 1024; // 2 MB i bytes
$uploadMappe = "uploads/";
// Opret mappen hvis den ikke findes
if (!is_dir($uploadMappe)) {
mkdir($uploadMappe, 0755, true);
}
// 2. Validering af filen
if ($fil["error"] !== UPLOAD_ERR_OK) {
$besked = "Der skete en fejl under upload.";
} elseif (!in_array($fil["type"], $tilladteTyper)) {
$besked = "Ugyldig filtype! Kun JPG, PNG og WebP er tilladt.";
} elseif ($fil["size"] > $maksStørrelse) {
$besked = "Filen er for stor! Maksimum er 2 MB.";
} else {
// 3. Generer et unikt filnavn for at undgå at overskrive gamle filer
$filExtension = pathinfo($fil["name"], PATHINFO_EXTENSION);
$nytNavn = uniqid("img_", true) . "." . $filExtension;
$målSti = $uploadMappe . $nytNavn;
// 4. Flyt filen fra den midlertidige mappe til destinationsmappen
if (move_uploaded_file($fil["tmp_name"], $målSti)) {
$besked = "Succes! Dit billede er uploadet som: " . $nytNavn;
} else {
$besked = "Kunne ikke gemme filen på serveren.";
}
}
}
?>
<!DOCTYPE html>
<html>
<body>
<h2>Upload et profilbillede</h2>
<p><?= $besked ?></p>
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="billede" required><br><br>
<button type="submit">Upload billede</button>
</form>
</body>
</html>
Lektion 13: MySQL Databaser & PDO (PHP Data Objects)
I professionelle systemer gemmes data i en database. Vi bruger PDO, fordi det er det sikreste og mest fleksible databaselag i PHP. Det understøtter mange forskellige databaser (MySQL, PostgreSQL, SQLite) uden at du skal omskrive din kode.
1. Forbindelse til MySQL med PDO
Først opretter vi en forbindelse. Det gøres i en særskilt fil, som vi kan inkludere på andre sider.
<?php
// db.php - Databaseforbindelse
$host = "localhost";
$db = "kursus_db";
$user = "root"; // Standard i XAMPP
$pass = ""; // Standard i XAMPP er tomt
$charset = "utf8mb4";
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Kaster fejl som Exceptions
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Returnerer associative arrays
PDO::ATTR_EMULATE_PREPARES => false, // Bruger rigtige prepared statements
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
2. CRUD-operationer med Prepared Statements
Husk den absolut vigtigste sikkerhedsregel: Sæt aldrig variabler direkte ind i dine SQL-strenge (f.eks. WHERE id = $id). Det åbner op for SQL Injection-hacking. Brug altid Prepared Statements (pladsholdere).
Her ser vi, hvordan vi udfører de fire grundlæggende CRUD-operationer (Create, Read, Update, Delete).
<?php
require_once "db.php"; // Hent databaseforbindelsen ($pdo)
// --- 1. CREATE (Indsæt data) ---
$navn = "Jens Hansen";
$email = "jens@example.dk";
$sqlInsert = "INSERT INTO brugere (navn, email) VALUES (:navn, :email)";
$stmt = $pdo->prepare($sqlInsert);
$stmt->execute(['navn' => $navn, 'email' => $email]);
echo "Bruger oprettet med ID: " . $pdo->lastInsertId() . "<br>";
// --- 2. READ (Hent data) ---
$sqlSelect = "SELECT id, navn, email FROM brugere WHERE email = :email";
$stmt = $pdo->prepare($sqlSelect);
$stmt->execute(['email' => 'jens@example.dk']);
$bruger = $stmt->fetch(); // fetch() henter én enkelt række
if ($bruger) {
echo "Fundet bruger: " . htmlspecialchars($bruger['navn']) . "<br>";
}
// Hent ALLE brugere:
$stmtAll = $pdo->query("SELECT * FROM brugere");
$alleBrugere = $stmtAll->fetchAll(); // fetchAll() henter alle rækker i et array
// --- 3. UPDATE (Opdater data) ---
$nytNavn = "Jens Peter Hansen";
$brugerId = 1;
$sqlUpdate = "UPDATE brugere SET navn = :navn WHERE id = :id";
$stmt = $pdo->prepare($sqlUpdate);
$stmt->execute(['navn' => $nytNavn, 'id' => $brugerId]);
// --- 4. DELETE (Slet data) ---
$sletId = 2;
$sqlDelete = "DELETE FROM brugere WHERE id = :id";
$stmt = $pdo->prepare($sqlDelete);
$stmt->execute(['id' => $sletId]);
Database-struktur: Det fulde overblik
For at køre ovenstående eksempler i din lokale database (via f.eks. http://localhost/phpmyadmin/), skal du have en tabel. Her er SQL-koden til at oprette tabellen brugere:
| Kolonnenavn |
Datatype |
Attributter |
Beskrivelse |
id | INT | PRIMARY KEY, AUTO_INCREMENT | Unikt ID for hver bruger |
navn | VARCHAR(100) | NOT NULL | Brugerens fulde navn |
email | VARCHAR(150) | NOT NULL, UNIQUE | E-mailadresse (må ikke genbruges) |
oprettet_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Tidspunkt for oprettelse |