Μάθημα 9 & 10: Cookies και Sessions - Login με MySQL και Sessions

Διαχείριση Κατάστασης Χρήστη στο Web

📋 Στόχοι Μαθήματος

Στο τέλος του μαθήματος ο φοιτητής θα μπορεί να:

  • Εξηγεί γιατί χρειαζόμαστε cookies και sessions (HTTP είναι stateless)
  • Δημιουργεί, διαβάζει και διαγράφει cookies από τον browser
  • Χρησιμοποιεί sessions για να αποθηκεύει δεδομένα χρήστη στο server
  • Καταλαβαίνει την σχέση cookie ↔ session id
  • Γνωρίζει βασικά θέματα ασφάλειας (HttpOnly, Secure, session hijacking)

🌐 1. Το Πρόβλημα: το HTTP είναι Stateless

💡 Τι σημαίνει Stateless;

Το πρωτόκολλο HTTP είναι χωρίς κατάσταση (stateless). Αυτό σημαίνει ότι κάθε αίτημα (request) που στέλνει ο browser στον server αντιμετωπίζεται σαν να είναι το πρώτο!

Τι συμβαίνει στην πράξη:

📝 Παράδειγμα του προβλήματος:

Φαντάσου ότι κάνεις login σε ένα e-shop. Χωρίς κάποιον τρόπο "μνήμης", κάθε φορά που θα πηγαίνεις σε νέα σελίδα, θα έπρεπε να ξανακάνεις login! Αυτό θα ήταν εντελώς απαράδεκτο για τον χρήστη.

ΑΛλΑ στις πραγματικές εφαρμογές θέλουμε:

Εκεί μπαίνουν στο παιχνίδι τα Cookies, τα Sessions και τα Tokens! 🍪🔑

🔐 Authentication στο Web

📌 Τι είναι Authentication;

Authentication είναι η διαδικασία με την οποία μια εφαρμογή επιβεβαιώνει ποιος είσαι, συνήθως με login (username + password).

🧠 Πρώτο βασικό concept: Stateful vs Stateless

🟦 Stateful Server

Ο server σε θυμάται μετά το login.

Κρατά πληροφορίες για τον χρήστη (session).

🧩 Παράδειγμα:

Πας σε εστιατόριο, ο σερβιτόρος θυμάται τι έχεις παραγγείλει στο τραπέζι σου.

✔ Σε θυμάται → Stateful

🟨 Stateless Server

Ο server δεν θυμάται τίποτα για εσένα.

Πρέπει κάθε φορά να του αποδεικνύεις ποιος είσαι.

🧩 Παράδειγμα:

Πας σε fast-food στο ταμείο και κάθε φορά πληρώνεις/δείχνεις απόδειξη. Ο υπάλληλος δεν σε θυμάται.

✔ Δεν σε θυμάται → Stateless

🔐 Οι 3 βασικές μέθοδοι Authentication

🟥 1) Basic Authentication (Stateless)

📌 Πώς λειτουργεί:

Σε κάθε request στέλνονται username + password σε HTTP Header:

Authorization: Basic base64(username:password)

✔ Πλεονεκτήματα:

  • Πολύ απλό
  • Δεν χρειάζεται session storage
  • Δεν χρειάζεται cookies

❌ Μειονεκτήματα:

  • Στέλνεις συνεχώς τον κωδικό → επικίνδυνο χωρίς HTTPS
  • Δύσκολο πραγματικό logout (απλά σταματάς να στέλνεις το password)

📌 Δεν θυμάται τίποτα → Stateless

🟦 2) Cookies + Sessions (Stateful)

📌 Πώς λειτουργεί:

  1. Ο χρήστης κάνει login
  2. Ο server αποθηκεύει πληροφορίες του χρήστη σε session
  3. Στέλνει στον browser ένα cookie με session ID
  4. Σε κάθε request, ο browser στέλνει το cookie
  5. Ο server βλέπει το session ID και θυμάται τον χρήστη

✔ Πλεονεκτήματα:

  • Ασφαλές, δεν φαίνονται στοιχεία στο cookie
  • Logout = πολύ εύκολο (σβήνουμε session στον server)
  • Ιδανικό για web εφαρμογές (sites)

❌ Μειονεκτήματα:

  • Ο server πρέπει να αποθηκεύει sessions (εξτρά μνήμη)
  • Συχνά απαιτείται read στη βάση/Redis σε κάθε request για να φορτωθεί το session
  • Για scaling, χρειάζεται shared session store (π.χ. Redis)

📌 Ο server σε θυμάται → Stateful

🟨 3) Token Authentication (JWT)

📌 Πώς λειτουργεί:

  1. Κάνεις login
  2. Ο server δημιουργεί JWT (token)
  3. Ο client το αποθηκεύει (localStorage, cookie κτλ.)
  4. Σε κάθε request στέλνεται:
Authorization: Bearer <JWT>

📌 Ο server δεν αποθηκεύει session. Απλά ελέγχει το token → Stateless

✔ Πλεονεκτήματα:

  • Δεν χρειάζεται μνήμη στον server
  • Δεν χρειάζεται read στη βάση κάθε φορά
  • Ιδανικό για APIs, mobile apps, microservices
  • Πολύ καλό για horizontal scaling

❌ Μειονεκτήματα:

  • Αν κλαπεί το token, ισχύει μέχρι να λήξει
  • Πραγματικό logout (invalidate) είναι δύσκολο → θέλει blacklist στον server
  • Αν χρησιμοποιήσουμε blacklist → γίνεται Stateful

🔄 Ροή Token Authentication με Access & Refresh Tokens

[ Login ] | | --> Server δημιουργεί: | - Access Token (10') | - Refresh Token (30 ημέρες) v +---------------+ | Client κρατά | | και τα δύο | +---------------+ | | Κάθε request → Access Token v [ Server ελέγχει ] | ┌──┴────────────────────────────┐ | | [ Access VALID ] [ Access EXPIRED ] | | v | [ Πρόσβαση ] | | Client στέλνει Refresh Token | v [ Server ελέγχει ] | v [ Δημιουργεί νέο Access Token ]
🎯 Τελική απλή φράση:
  • Stateful: Ο server σε θυμάται (Sessions)
  • Stateless: Κάθε φορά του δείχνεις token για να αποδείξεις ποιος είσαι (JWT)

📦 Λιγότερα δεδομένα → πιο ελαφρύ

Το basic auth header έχει περίπου:

Authorization: Basic base64(username:password)

Που συνήθως είναι αρκετά bytes (ανάλογα το username/password). Το session id είναι συνήθως ένα fixed-length random string, π.χ.:

Cookie: sessionid=asj8jsd9s0sj2k2k

2–3 φορές μικρότερο σε μέγεθος και ελαφρύτερο στην επεξεργασία.

🍪 2. Cookies

2.1 Τι είναι ένα Cookie;

Ένα cookie είναι ένα μικρό κομμάτι δεδομένων (key-value pair) που:

  • Αποθηκεύεται στον browser του χρήστη
  • Συνδέεται με ένα συγκεκριμένο domain (π.χ. example.com)
  • Αποστέλλεται αυτόματα σε κάθε request προς αυτό το domain
  • Έχει μέγιστο μέγεθος περίπου 4KB ανά cookie

📊 Πώς λειτουργεί η ροή ενός Cookie:

Βήμα 1: Ο server στέλνει cookie στον browser
Set-Cookie: theme=dark; Path=/; Max-Age=3600
Βήμα 2: Ο browser αποθηκεύει το cookie
Βήμα 3: Σε κάθε επόμενο request, ο browser στέλνει
Cookie: theme=dark
Βήμα 4: Ο server διαβάζει το cookie και "θυμάται" την προτίμηση

2.2 Χρήσεις των Cookies

2.3 Βασικές Ιδιότητες ενός Cookie

Set-Cookie: name=value; Max-Age=3600; Path=/; Domain=example.com; Secure; HttpOnly
Ιδιότητα Περιγραφή Παράδειγμα
name=value Το όνομα και η τιμή του cookie theme=dark
Max-Age Πόσα δευτερόλεπτα θα ζήσει το cookie Max-Age=3600 (1 ώρα)
Expires Συγκεκριμένη ημερομηνία λήξης Expires=Wed, 01 Jan 2025 00:00:00 GMT
Path Σε ποιο μονοπάτι ισχύει το cookie Path=/shop
Domain Για ποιο domain ισχύει Domain=.example.com
Secure Στέλνεται μόνο μέσω HTTPS Secure
HttpOnly Όχι προσβάσιμο από JavaScript HttpOnly
⚠️ Σημαντική Σημείωση:

Αν δεν δώσουμε Max-Age ή Expires, το cookie είναι session cookie και διαγράφεται όταν κλείσει ο browser!

🔒 Ασφάλεια με HttpOnly και Secure:

  • HttpOnly: Προστατεύει από XSS attacks - το JavaScript δεν μπορεί να διαβάσει το cookie με document.cookie
  • Secure: Το cookie στέλνεται μόνο μέσω HTTPS, όχι HTTP - προστατεύει από man-in-the-middle attacks

💻 3. Παραδείγματα Χρήσης Cookies στην PHP

3.1 Δημιουργία Cookie

<?php // ΣΗΜΑΝΤΙΚΟ: Η setcookie() πρέπει να κληθεί ΠΡΙΝ από οποιαδήποτε έξοδο HTML! // Αυτό συμβαίνει επειδή τα cookies στέλνονται στα HTTP headers setcookie( "theme", // Όνομα του cookie "dark", // Τιμή του cookie time() + 3600, // Λήξη: τρέχουσα ώρα + 3600 δευτερόλεπτα (1 ώρα) "/", // Path: ισχύει για όλο το site "", // Domain: current domain (αφήνουμε κενό) true, // Secure: μόνο μέσω HTTPS true // HttpOnly: όχι πρόσβαση από JavaScript ); ?> <html> <head> <title>Cookie Example</title> </head> <body> <h1>Το cookie "theme" δημιουργήθηκε επιτυχώς!</h1> <p>Ανανέωσε τη σελίδα για να δεις το cookie σε λειτουργία.</p> </body> </html>

🔎 Τι είναι το $_COOKIE στην PHP;

🔎 Πώς το χρησιμοποιούμε;

Παίρνουμε ένα cookie έτσι:

$theme = $_COOKIE["theme"];

3.2 Ανάγνωση Cookie read_cookie.php

<?php // ---------------------------------------------------- // ΕΛΕΓΧΟΥΜΕ ΑΝ ΥΠΑΡΧΕΙ ΤΟ COOKIE "theme" // ---------------------------------------------------- if (isset($_COOKIE["theme"])) { // Αν υπάρχει, το αποθηκεύουμε σε μεταβλητή $theme = $_COOKIE["theme"]; // Το εμφανίζουμε στην οθόνη echo "Το θέμα σου είναι: " . $theme; } else { // Αν ΔΕΝ υπάρχει cookie, εμφανίζουμε μήνυμα echo "Δεν υπάρχει αποθηκευμένο θέμα."; } ?>

3.3 Ενημέρωση Cookie

<?php // Για να ενημερώσουμε ένα cookie, απλά καλούμε ξανά την setcookie() // με το ίδιο όνομα αλλά νέα τιμή setcookie( "theme", // Το ίδιο όνομα "light", // Νέα τιμή time() + 7200, // Νέα λήξη: 2 ώρες "/", "", true, true ); echo "Το theme άλλαξε σε light!"; ?>

3.4 Διαγραφή Cookie

<?php // Για να διαγράψουμε ένα cookie, θέτουμε την ημερομηνία λήξης στο παρελθόν // Ο browser θα το διαγράψει αυτόματα setcookie( "theme", // Το όνομα του cookie που θέλουμε να διαγράψουμε "", // Κενή τιμή time() - 3600, // Λήξη στο παρελθόν (π.χ. πριν 1 ώρα) "/" // Πρέπει να είναι το ίδιο path με τη δημιουργία ); echo "Το cookie 'theme' διαγράφηκε!"; ?>
💡 Tip:

Όταν διαγράφεις ένα cookie, βεβαιώσου ότι χρησιμοποιείς το ίδιο path και domain που χρησιμοποιήθηκε κατά τη δημιουργία του!

3.5 Απλό Παράδειγμα Δημιουργίας Cookie (PHP)

👉 Δημιουργεί cookie και το εμφανίζει.

📌 Αποθήκευσε το ως cookie_test.php

<?php // Δημιουργία cookie με όνομα "username" και τιμή "Maria" // Διαρκεί για 1 μέρα (60*60*24 δευτερόλεπτα) setcookie("username", "Maria", time() + 86400); ?> <!DOCTYPE html> <html> <body> <h1>Cookie Παράδειγμα</h1> <?php // Έλεγχος αν υπάρχει cookie if (isset($_COOKIE["username"])) { echo "Το cookie είναι: " . $_COOKIE["username"]; } else { echo "Δεν υπάρχει cookie ακόμα. Κάνε refresh τη σελίδα!"; } ?> </body> </html>
📌 Τι να παρατηρήσεις:
  1. Την πρώτη φορά που φορτώνεις τη σελίδα, το cookie δημιουργείται, αλλά δεν εμφανίζεται ακόμα.
  2. Κάνε Refresh (F5) → τώρα εμφανίζεται το cookie.
  3. Δες το cookie στον browser: Inspect → Application → Cookies → localhost
🚀 Τι έμαθες;
  • Πώς δημιουργείται cookie (setcookie)
  • Πώς διαβάζεται ($_COOKIE["username"])
  • Γιατί χρειάζεται refresh (ο browser πρώτα το αποθηκεύει, μετά το στέλνει στο 2ο request)

3.6 Απλό Παράδειγμα Login με Cookies

✅ Αυτό είναι εκπαιδευτικό παράδειγμα

Ένα απλό παράδειγμα login με cookies σε PHP, βήμα–βήμα, χωρίς βάση δεδομένων, μόνο για να καταλάβεις τη λογική.

❌ Δεν είναι ασφαλές για παραγωγή!

Αυτό το παράδειγμα είναι μόνο για εκπαιδευτικούς σκοπούς. Στην πράξη χρησιμοποιούμε Sessions για login.

Θα έχουμε 4 αρχεία:

✅ 1️⃣ login.php (Η φόρμα)

<!DOCTYPE html> <html lang="el"> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <form action="check.php" method="post"> <label for="username">Username</label><br> <input type="text" id="username" name="username" placeholder="Username" required> <br><br> <label for="password">Password</label><br> <input type="password" id="password" name="password" placeholder="Password" required> <br><br> <button type="submit">Login</button> </form> </body> </html>
📌 Τι είναι το header() στην PHP;

Η header() είναι εντολή της PHP που στέλνει εντολές στον browser μέσω των HTTP headers.

Με απλά λόγια: 👉 Λες στον browser να κάνει κάτι πριν καν φορτώσει η σελίδα.

✅ Τι κάνει το:
header("Location: dashboard.php");

Αυτό σημαίνει: 🟢 «Browser, πήγαινε αυτόματα στη σελίδα dashboard.php».

👉 Είναι ανακατεύθυνση (redirect). Χωρίς να πατήσει τίποτα ο χρήστης.

✅ 2️⃣ check.php (Έλεγχος & δημιουργία cookie)

<?php // ---------------------------------------- // 1️⃣ Παίρνουμε τα δεδομένα από τη φόρμα // μέσω της μεθόδου POST // ---------------------------------------- // Παίρνουμε το username που έστειλε ο χρήστης $username = $_POST['username']; // Παίρνουμε το password που έστειλε ο χρήστης $password = $_POST['password']; // ---------------------------------------- // 2️⃣ Έλεγχος στοιχείων (σταθερά, χωρίς βάση) // ---------------------------------------- // Ελέγχουμε αν το username είναι "admin" // ΚΑΙ αν το password είναι "1234" if ($username == "admin" && $password == "1234") { // ------------------------------------ // 3️⃣ Αν τα στοιχεία είναι ΣΩΣΤΑ // ------------------------------------ // Δημιουργούμε ένα cookie με όνομα "user" // και τιμή το username (π.χ. "admin") // Το cookie θα διαρκέσει 1 ώρα (3600 δευτ.) setcookie("user", $username, time() + 3600); // Κάνουμε ανακατεύθυνση (redirect) // στη σελίδα dashboard.php header("Location: dashboard.php"); // Σταματάμε την εκτέλεση του αρχείου εδώ // για να μη συνεχίσει παρακάτω κώδικας exit(); } else { // ------------------------------------ // 4️⃣ Αν τα στοιχεία είναι ΛΑΘΟΣ // ------------------------------------ // Εμφανίζουμε μήνυμα λάθους στον χρήστη echo "Λάθος στοιχεία!"; } ?>

✅ 3️⃣ dashboard.php (Σελίδα που απαιτεί login)

<?php // Αν δεν υπάρχει cookie → πίσω στο login if (!isset($_COOKIE["user"])) { header("Location: login.php"); exit(); } ?> <h2>Καλωσήρθες <?php echo $_COOKIE["user"]; ?>!</h2> <a href="logout.php">Logout</a>

✅ 4️⃣ logout.php (Καταστροφή cookie)

<?php setcookie("user", "", time() - 3600); header("Location: login.php"); exit(); ?>

🔥 Πώς δουλεύει με απλά λόγια:

Βήμα Τι γίνεται
1 Ο χρήστης κάνει login
2 Αν τα στοιχεία είναι σωστά → δημιουργείται cookie
3 Το dashboard.php ελέγχει αν υπάρχει cookie
4 Αν δεν υπάρχει → επιστροφή στο login
5 Στο logout → διαγράφεται το cookie

🎯 4. Sessions

Τα sessions λύνουν το πρόβλημα της "κατάστασης" πιο ασφαλώς από το να αποθηκεύουμε τα πάντα σε cookies.

4.1 Τι είναι ένα Session;

Ένα session είναι "κατάσταση χρήστη" που αποθηκεύεται στον server, όχι στον browser!

  • Ο browser κρατάει μόνο ένα session ID (συνήθως σε cookie)
  • Στον server υπάρχει μια αποθήκη που συνδέει: session_id → {user_data}
  • Τα δεδομένα είναι πιο ασφαλή γιατί δεν φαίνονται στον client

📊 Πώς λειτουργεί η ροή ενός Session:

1ο Request: Ο χρήστης επισκέπτεται τη σελίδα
Ο server δημιουργεί νέο session ID (π.χ. "abc123xyz")
Server Response: Στέλνει cookie με το session ID
Set-Cookie: PHPSESSID=abc123xyz; HttpOnly; Secure
2ο Request: Ο browser στέλνει το session ID
Cookie: PHPSESSID=abc123xyz
Server: Χρησιμοποιεί το session ID για να βρει
τα δεδομένα του χρήστη (username, cart, preferences κλπ)

4.2 Πώς συνδέεται με τα Cookies;

📝 Η σχέση Cookie ↔ Session:

Cookie: Αποθηκεύεται στον browser, περιέχει μόνο το session ID (π.χ. PHPSESSID=abc123)

Session: Αποθηκεύεται στον server, περιέχει όλα τα δεδομένα του χρήστη

Το cookie χρησιμεύει ως "κλειδί" για να βρει ο server τα δεδομένα του session!

Που αποθηκεύεται; Τι περιέχει; Ασφάλεια
Cookie (PHPSESSID) Μόνο το session ID Χαμηλός κίνδυνος (είναι random string)
Session (server) Όλα τα δεδομένα χρήστη Πιο ασφαλές (δεν φαίνεται στον client)

💻 5. Πλήρες Σύστημα Login με MySQL και Sessions

Θα δημιουργήσουμε ένα ολοκληρωμένο σύστημα εγγραφής και σύνδεσης χρηστών με βάση δεδομένων MySQL.

🔧 5.1 Βάση Δεδομένων (MySQL)

SQL-- Δημιουργία βάσης CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- Χρήση της βάσης USE myapp; -- Πίνακας χρηστών CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, -- Μοναδικό ID για κάθε χρήστη username VARCHAR(50) NOT NULL UNIQUE, -- Username μοναδικό password VARCHAR(255) NOT NULL -- Αποθήκευση hash κωδικού (ΟΧΙ απλό password!) );

🔧 5.2 config.php – Σύνδεση στη βάση

<?php // ======================================= // ΣΤΟΙΧΕΙΑ ΣΥΝΔΕΣΗΣ ΜΕ ΤΗ ΒΑΣΗ ΔΕΔΟΜΕΝΩΝ // ======================================= $host = "localhost"; // Ο server της βάσης (συνήθως localhost) $dbname = "myapp"; // Το όνομα της βάσης δεδομένων $dbuser = "root"; // Το όνομα χρήστη της MySQL $dbpass = ""; // Ο κωδικός της MySQL (κενός στο XAMPP συνήθως) // ======================================= // ΔΗΜΙΟΥΡΓΙΑ ΣΥΝΔΕΣΗΣ ΜΕ MySQL // ======================================= // Δημιουργούμε ένα νέο αντικείμενο σύνδεσης με τη βάση $conn = new mysqli($host, $dbuser, $dbpass, $dbname); // ======================================= // ΕΛΕΓΧΟΣ ΑΝ ΑΠΕΤΥΧΕ Η ΣΥΝΔΕΣΗ // ======================================= // Αν υπάρχει σφάλμα στη σύνδεση, σταματάμε το πρόγραμμα if ($conn->connect_error) { die("Σφάλμα σύνδεσης: " . $conn->connect_error); } // ======================================= // ΟΡΙΣΜΟΣ ΚΩΔΙΚΟΠΟΙΗΣΗΣ ΧΑΡΑΚΤΗΡΩΝ // ======================================= // Καθορίζουμε ότι η επικοινωνία με τη βάση // θα γίνεται με κωδικοποίηση utf8mb4, // ώστε να υποστηρίζονται σωστά: // - Ελληνικά // - Όλοι οι Unicode χαρακτήρες // - Emojis 😄 $conn->set_charset("utf8mb4"); ?>
✅ Αυτό το αρχείο:
  • Το κάνουμε require σε όλα τα PHP αρχεία
  • Μας δίνει έτοιμο το $conn για queries

📝 5.3 register.php – Φόρμα εγγραφής

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Εγγραφή</title> </head> <body> <h2>Εγγραφή</h2> <!-- Η φόρμα στέλνει τα δεδομένα στο register_process.php --> <form action="register_process.php" method="post"> <!-- Πεδίο username --> <input type="text" name="username" placeholder="Username" required> <br><br> <!-- Πεδίο password --> <input type="password" name="password" placeholder="Password" required> <br><br> <!-- Κουμπί εγγραφής --> <button type="submit">Register</button> </form> <br> <!-- Σύνδεσμος για login --> <a href="login.php">Έχω ήδη λογαριασμό</a> </body> </html>

🧾 5.4 register_process.php – Εγγραφή στη βάση

<?php session_start(); // Εκκίνηση session (για μελλοντική χρήση) require 'config.php'; // Φέρνουμε τη σύνδεση με τη βάση // Παίρνουμε κατευθείαν τις τιμές που έστειλε ο χρήστης από τη φόρμα $username = $_POST['username']; $password = $_POST['password']; // Έλεγχος αν ο χρήστης άφησε κενό το username ή το password // Αν είναι κάποιο από τα δύο κενό, το πρόγραμμα σταματάει if ($username == "" || $password == "") { die("Συμπλήρωσε όλα τα πεδία."); } // ========================== // ΚΡΥΠΤΟΓΡΑΦΗΣΗ ΚΩΔΙΚΟΥ // ========================== // Το password_hash(...) είναι έτοιμη συνάρτηση της PHP που: // - Παίρνει έναν απλό κωδικό // - Τον "κλειδώνει" (τον κάνει hash) // - Και επιστρέφει έναν ασφαλή κρυπτογραφημένο κωδικό $hash = password_hash($password, PASSWORD_DEFAULT); // ========================== // ΕΝΤΟΛΗ SQL // ========================== // Εντολή για να εισάγουμε νέο χρήστη στον πίνακα users $sql = "INSERT INTO users (username, password) VALUES (?, ?)"; // Προετοιμάζουμε την εντολή για λόγους ασφάλειας (prepared statement) $stmt = $conn->prepare($sql); // Συνδέουμε τις τιμές με την εντολή // "ss" σημαίνει ότι και οι δύο τιμές είναι κείμενο (string) $stmt->bind_param("ss", $username, $hash); // ========================== // ΕΚΤΕΛΕΣΗ ΕΓΓΡΑΦΗΣ // ========================== // Εκτελούμε την εντολή στη βάση δεδομένων if ($stmt->execute()) { // Αν όλα πήγαν σωστά echo "✅ Εγγραφή επιτυχής! <a href='login.php'>Σύνδεση</a>"; } else { // Αν η εγγραφή ΑΠΟΤΥΧΕΙ: // Το 1062 είναι κωδικός λάθους και σημαίνει: // "Υπάρχει ήδη ίδιο username στη βάση" if ($conn->errno == 1062) { echo "❌ Το username υπάρχει ήδη."; } else { // Οποιοδήποτε άλλο σφάλμα στη βάση echo "❌ Σφάλμα βάσης: " . $conn->error; } } // ========================== // ΚΛΕΙΣΙΜΟ ΣΥΝΔΕΣΕΩΝ // ========================== // Κλείνουμε το statement $stmt->close(); // Κλείνουμε τη σύνδεση με τη βάση δεδομένων $conn->close(); ?>

🔐 5.5 login.php – Φόρμα σύνδεσης

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <h2>Login</h2> <!-- Φόρμα που στέλνει δεδομένα στο login_process.php --> <form action="login_process.php" method="post"> <input type="text" name="username" placeholder="Username" required> <br><br> <input type="password" name="password" placeholder="Password" required> <br><br> <button type="submit">Login</button> </form> <br> <a href="register.php">Δεν έχω λογαριασμό</a> </body> </html>

✅ 5.6 login_process.php – Έλεγχος login + session

<?php session_start(); // ✅ Ξεκινάμε το session για να μπορούμε να κρατήσουμε τον χρήστη συνδεδεμένο require 'config.php'; // ✅ Φέρνουμε τη σύνδεση με τη βάση δεδομένων // ✅ Παίρνουμε ΑΠΕΥΘΕΙΑΣ τα δεδομένα από τη φόρμα (μπορεί να βγάλει warnings αν λείπουν) $username = $_POST['username']; $password = $_POST['password']; // ✅ Έλεγχος αν κάποιο πεδίο είναι άδειο if ($username === '' || $password === '') { die("Συμπλήρωσε όλα τα πεδία."); } // ✅ Ετοιμάζουμε SQL εντολή για να βρούμε τον χρήστη από τη βάση $sql = "SELECT id, username, password FROM users WHERE username = ?"; $stmt = $conn->prepare($sql); // ✅ Prepared Statement για αποφυγή SQL Injection $stmt->bind_param("s", $username); // ✅ Δένουμε το username σαν string $stmt->execute(); // ✅ Εκτελούμε την εντολή $result = $stmt->get_result(); // ✅ Παίρνουμε το αποτέλεσμα // ✅ Αν βρέθηκε ακριβώς ένας χρήστης στη βάση if ($result->num_rows === 1) { $user = $result->fetch_assoc(); // ✅ Παίρνουμε τα στοιχεία του χρήστη σε array // ✅ Η password_verify(): // Παίρνει τον απλό κωδικό που έγραψε ο χρήστης στη φόρμα // Τον ξανακρυπτογραφεί με τον ΙΔΙΟ αλγόριθμο // Και τον συγκρίνει με το hash που υπάρχει στη βάση if (password_verify($password, $user['password'])) { // ✅ Αν ο κωδικός είναι σωστός → δημιουργούμε login session $_SESSION['user_id'] = $user['id']; // Αποθηκεύουμε το id του χρήστη $_SESSION['username'] = $user['username']; // Αποθηκεύουμε το username // ✅ Ανακατεύθυνση στο dashboard μετά το login header("Location: dashboard.php"); exit(); // ✅ Τερματισμός script για ασφάλεια } else { // ❌ Αν ο κωδικός είναι λάθος echo "❌ Λάθος κωδικός."; } } else { // ❌ Αν δεν υπάρχει χρήστης με αυτό το username echo "❌ Ο χρήστης δεν βρέθηκε."; } // ✅ Κλείνουμε statement και σύνδεση με τη βάση $stmt->close(); $conn->close(); ?>

🏠 5.7 dashboard.php – Προστατευμένη σελίδα

<?php session_start(); // Φέρνουμε το session για να διαβάσουμε τα στοιχεία του χρήστη // Αν ΔΕΝ υπάρχει user_id στο session → ο χρήστης δεν είναι συνδεδεμένος if (!isset($_SESSION['user_id'])) { header("Location: login.php"); // Τον στέλνουμε στο login exit(); // Σταματάμε το script } ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Dashboard</title> </head> <body> <h2>Καλωσήρθες, <?php echo $_SESSION['username']; ?>!</h2> <p>Αυτή η σελίδα είναι προσβάσιμη μόνο σε συνδεδεμένους χρήστες.</p> <a href="logout.php">Logout</a> </body> </html>

🚪 5.8 logout.php – Αποσύνδεση

<?php session_start(); // Πρέπει να καλέσουμε session για να το καταστρέψουμε session_unset(); // Καθαρίζει όλα τα $_SESSION δεδομένα session_destroy(); // Καταστρέφει εντελώς το session // Επιστροφή στο login header("Location: login.php"); exit(); ?>
❓ Γιατί ΔΕΝ βλέπεις user_id και username στα cookies;

Αυτές οι γραμμές:

$_SESSION['user_id'] = $user['id']; $_SESSION['username'] = $user['username'];

ΔΕΝ φτιάχνουν cookies. Φτιάχνουν δεδομένα μέσα στο $_SESSION, που είναι:

  • μια μεταβλητή της PHP στον server
  • και ΟΧΙ cookie στον browser
🔹 Πού αποθηκεύονται τα δεδομένα του session;

Με απλά λόγια:

  • Τα δεδομένα $_SESSION['user_id'] και $_SESSION['username'] αποθηκεύονται στον server (συνήθως σε αρχεία τύπου sess_κάτι)
  • Ο browser σου βλέπει ΜΟΝΟ ένα cookie, συνήθως με όνομα: PHPSESSID

Αυτό είναι απλά ένα ID, π.χ.:

PHPSESSID = r3t8s8e2t82s8d2s8d2

Με αυτό το ID, ο server βρίσκει τα δεδομένα του $_SESSION που έχει κρατήσει για σένα.

👉 Άρα ΔΕΝ θα δεις ποτέ user_id και username στα cookies. Θα δεις μόνο PHPSESSID.

✅ Τι πρέπει να θυμάσαι από όλο αυτό:

🎯 Κεντρικά Σημεία:
  • ✅ Οι χρήστες αποθηκεύονται στη MySQL
  • ✅ Οι κωδικοί αποθηκεύονται ΜΟΝΟ σαν hash (password_hash)
  • ✅ Το login γίνεται με: έλεγχο στη βάση + password_verify
  • ✅ Το login state αποθηκεύεται στη $_SESSION
  • ✅ Το dashboard προστατεύεται με: if (!isset($_SESSION['user_id']))
  • ✅ Το logout διαγράφει πλήρως το session

✅ Τέλος Μαθήματος 9 & 10

Cookies και Sessions - Login με MySQL και Sessions

Πανεπιστήμιο Πελοποννήσου - Τμήμα Ψηφιακών Συστημάτων

Μπάρδης Γιώργος