Proiecte practice în PHP + SQL
Mini CMS / Blog (Users, Posts, Comments)
Un mini CMS sau un blog simplu este un proiect excelent pentru a exersa PHP & MySQL. De obicei, un astfel de proiect implică următoarele tabele:
users- stochează informații despre utilizatori (id, nume, email, parolă hashed);posts- stochează articolele publicate de utilizatori (id, user_id, title, content, created_at);comments- stochează comentariile la postări (id, post_id, user_id, content, created_at).
Structura bazei de date
Exemplu de creare a tabelelor în phpMyAdmin sau cu script PHP:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY,
post_id INT NOT NULL,
user_id INT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Funcționalități principale
- Creare, editare și ștergere postări de către utilizatori;
- Adăugare și ștergere comentarii la postări;
- Autentificare și înregistrare utilizatori cu hashing parole și sesiuni;
- Afișare listă postări, comentarii și informații despre autori;
- Like / dislike pentru fiecare postare.
Exemplu cod PHP - afișare postări și comentarii
<?php
try {
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT posts.id AS post_id, posts.title, posts.content, posts.created_at,
users.name AS author_name, users.email AS author_email
FROM posts
INNER JOIN users ON posts.user_id = users.id
ORDER BY posts.created_at DESC";
$stmt = $pdo->query($sql);
while ($post = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<h4>" . htmlspecialchars($post['title']) . "</h4>";
echo "<p>" . htmlspecialchars($post['content']) . "</p>";
echo "<small>Scris de: " . htmlspecialchars($post['author_name']) . " (" . htmlspecialchars($post['author_email']) . ") la " . $post['created_at'] . "</small><br>";
// afișare comentarii
$sql_comments = "SELECT comments.content, comments.created_at, users.name AS commenter
FROM comments
INNER JOIN users ON comments.user_id = users.id
WHERE comments.post_id = :post_id
ORDER BY comments.created_at ASC";
$stmt_comments = $pdo->prepare($sql_comments);
$stmt_comments->execute(['post_id' => $post['post_id']]);
while ($comment = $stmt_comments->fetch(PDO::FETCH_ASSOC)) {
echo "<div style='margin-left:20px'>";
echo "<p>" . htmlspecialchars($comment['commenter']) . ": " . htmlspecialchars($comment['content']) . "</p>";
echo "<small>" . $comment['created_at'] . "</small></div>";
}
echo "<hr>";
}
} catch (PDOException $e) {
echo "Eroare: " . $e->getMessage();
}
?>
<?php
try {
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "traffice_php", "!@y3Ge-Z!WQI");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT posts.id AS post_id, posts.title, posts.content, posts.created_at,
users.name AS author_name, users.email AS author_email
FROM posts
INNER JOIN users ON posts.user_id = users.id
ORDER BY posts.created_at DESC";
$stmt = $pdo->query($sql);
while ($post = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<h4>" . htmlspecialchars($post['title']) . "</h4>";
echo "<p>" . htmlspecialchars($post['content']) . "<p>";
echo "<small>Scris de: " . htmlspecialchars($post['author_name']) . " (" . htmlspecialchars($post['author_email']) . ") la " . $post['created_at'] . "</small><br>";
// afișare comentarii
$sql_comments = "SELECT comments.content, comments.created_at, users.name AS commenter
FROM comments
INNER JOIN users ON comments.user_id = users.id
WHERE comments.post_id = :post_id
ORDER BY comments.created_at ASC";
$stmt_comments = $pdo->prepare($sql_comments);
$stmt_comments->execute(['post_id' => $post['post_id']]);
while ($comment = $stmt_comments->fetch(PDO::FETCH_ASSOC)) {
echo "<div style='margin-left:20px'>";
echo "<p>" . htmlspecialchars($comment['commenter']) . ": " . htmlspecialchars($comment['content']) . "<p>";
echo "<small>" . $comment['created_at'] . "</small></div>";
}
echo "<hr>";
}
} catch (PDOException $e) {
echo "Eroare: " . $e->getMessage();
}
?>
To-Do List cu DB
Un proiect de tip To-Do List este ideal pentru a exersa CRUD și sesiuni în PHP. Fiecare utilizator poate avea propria listă de sarcini, iar acestea se stochează într-o bază de date MySQL.
Structura bazei de date
Exemplu de tabel pentru sarcini:
CREATE TABLE todos (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
task VARCHAR(255) NOT NULL,
is_done TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Exemplu PHP - CRUD pentru To-Do List
<?php
session_start();
try {
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user_id = 1; // Exemplu, utilizatorul curent
// Adăugare task
if(isset($_POST['add_task'])) {
$task = $_POST['task'];
$stmt = $pdo->prepare("INSERT INTO todos (user_id, task) VALUES (:user_id, :task)");
$stmt->execute(['user_id' => $user_id, 'task' => $task]);
}
// Ștergere task
if(isset($_GET['delete_id'])) {
$stmt = $pdo->prepare("DELETE FROM todos WHERE id = :id AND user_id = :user_id");
$stmt->execute(['id' => $_GET['delete_id'], 'user_id' => $user_id]);
}
// Marcarea ca făcut
if(isset($_GET['toggle_id'])) {
$stmt = $pdo->prepare("UPDATE todos SET is_done = 1 - is_done WHERE id = :id AND user_id = :user_id");
$stmt->execute(['id' => $_GET['toggle_id'], 'user_id' => $user_id]);
}
// Preluare toate task-urile
$stmt = $pdo->prepare("SELECT * FROM todos WHERE user_id = :user_id ORDER BY created_at DESC");
$stmt->execute(['user_id' => $user_id]);
$todos = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
echo "Eroare: " . $e->getMessage();
}
?>
<h3>Lista mea de task-uri</h3>
<form method="post">
<input type="text" name="task" placeholder="Adaugă un task" required>
<button type="submit" name="add_task">Adaugă</button>
</form>
<ul>
<?php foreach($todos as $todo): ?>
<li>
<?= htmlspecialchars($todo['task']) ?>
<a href="?toggle_id=<?= $todo['id'] ?>">[Toggle]</a>
<a href="?delete_id=<?= $todo['id'] ?>">[Șterge]</a>
<?php if($todo['is_done']): ?>✔<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php
session_start();
try {
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "traffice_php", "!@y3Ge-Z!WQI");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user_id = 1; // Exemplu, utilizatorul curent
// Adăugare task
if(isset($_POST['add_task'])) {
$task = $_POST['task'];
$stmt = $pdo->prepare("INSERT INTO todos (user_id, task) VALUES (:user_id, :task)");
$stmt->execute(['user_id' => $user_id, 'task' => $task]);
}
// Ștergere task
if(isset($_GET['delete_id'])) {
$stmt = $pdo->prepare("DELETE FROM todos WHERE id = :id AND user_id = :user_id");
$stmt->execute(['id' => $_GET['delete_id'], 'user_id' => $user_id]);
}
// Marcarea ca făcut
if(isset($_GET['toggle_id'])) {
$stmt = $pdo->prepare("UPDATE todos SET is_done = 1 - is_done WHERE id = :id AND user_id = :user_id");
$stmt->execute(['id' => $_GET['toggle_id'], 'user_id' => $user_id]);
}
// Preluare toate task-urile
$stmt = $pdo->prepare("SELECT * FROM todos WHERE user_id = :user_id ORDER BY created_at DESC");
$stmt->execute(['user_id' => $user_id]);
$todos = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
echo "Eroare: " . $e->getMessage();
}
?>
<h3>Lista mea de task-uri</h3>
<form method="post">
<input type="text" name="task" placeholder="Adaugă un task" required>
<button type="submit" name="add_task">Adaugă</button>
</form>
<ul>
<?php foreach($todos as $todo): ?>
<li>
<?= htmlspecialchars($todo['task']) ?>
<a href="?toggle_id=<?= $todo['id'] ?>">[Toggle]</a>
<a href="?delete_id=<?= $todo['id'] ?>">[Șterge]</a>
<?php if($todo['is_done']): ?>✔<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
Formular de contact cu trimitere pe e-mail
Un formular de contact permite utilizatorilor să trimită mesaje direct prin site. Datele sunt validate și apoi
trimise prin funcția PHP mail().
Exemplu PHP - Formular de contact simplu
<?php
$success = '';
$error = '';
if(isset($_POST['send'])) {
$nume = trim($_POST['nume']);
$email = trim($_POST['email']);
$mesaj = trim($_POST['mesaj']);
// Validare simplă
if(empty($nume) || empty($email) || empty($mesaj)) {
$error = "Toate câmpurile sunt obligatorii.";
} elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = "Adresa de email nu este validă.";
} else {
$to = "contact@example.com"; // adresa destinatar
$subject = "Mesaj de la $nume";
$body = "Nume: $nume\nEmail: $email\n\nMesaj:\n$mesaj";
$headers = "From: $email";
if(mail($to, $subject, $body, $headers)) {
$success = "Mesajul a fost trimis cu succes!";
} else {
$error = "Eroare la trimiterea mesajului.";
}
}
}
?>
<h3>Formular de contact</h3>
<?php if($success): ?>
<p style="color:green"><?= $success ?></p>
<?php endif; ?>
<?php if($error): ?>
<p style="color:red"><?= $error ?></p>
<?php endif; ?>
<form method="post">
<input type="text" name="nume" placeholder="Numele tău" required><br>
<input type="email" name="email" placeholder="Email-ul tău" required><br>
<textarea name="mesaj" placeholder="Mesajul tău" required></textarea><br>
<button type="submit" name="send">Trimite</button>
</form>
Acest cod poate fi pus într-un singur fișier și rulat live. Astfel, se poate testa trimiterea mesajelor fără
să fie nevoie de setări suplimentare, doar cu un server local care suportă mail() sau cu
configurarea unui SMTP local.
Login / Register cu hashing & sesiuni
Pentru a crea un sistem sigur de autentificare, folosim password_hash() la înregistrare și
password_verify() la login. Datele utilizatorilor se stochează într-o bază de date (de ex.
tabela users), iar sesiunea este folosită pentru a păstra starea de autentificare.
Actualizare tabela users pentru login
Adăugăm coloana password în tabela users astfel încât să putem stoca parola hashed:
ALTER TABLE users
ADD COLUMN password VARCHAR(255) NOT NULL AFTER email;
Varianta PHP pentru a rula dintr-un script și a verifica dacă coloana există:
<?php
try {
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "ALTER TABLE users
ADD COLUMN IF NOT EXISTS password VARCHAR(255) NOT NULL AFTER email";
$pdo->exec($sql);
echo "✅ Coloana 'password' a fost adăugată în tabela 'users'.";
} catch (PDOException $e) {
echo "❌ Eroare: " . $e->getMessage();
}
?>
După ce coloana este adăugată, exemplul de login și register va funcționa corect.
Exemplu PHP - Register
<?php
session_start();
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test","root","");
$register_msg = '';
if(isset($_POST['register'])) {
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
if(empty($username) || empty($email) || empty($password)) {
$register_msg = "Toate câmpurile sunt obligatorii.";
} elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$register_msg = "Email invalid.";
} else {
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
if($stmt->execute([$username, $email, $hash])) {
$register_msg = "✅ Cont creat cu succes!";
} else {
$register_msg = "❌ Eroare la crearea contului.";
}
}
}
?>
<h3>Formular Register</h3>
<?php if($register_msg): ?>
<p><?= $register_msg ?></p>
<?php endif; ?>
<form method="post">
<input type="text" name="username" placeholder="Nume" required><br>
<input type="email" name="email" placeholder="Email" required><br>
<input type="password" name="password" placeholder="Parolă" required><br>
<button type="submit" name="register">Înregistrează-te</button>
</form>
Exemplu PHP - Login
<?php
session_start();
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test","root","");
$login_msg = '';
if(isset($_POST['login'])) {
$email = trim($_POST['email']);
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name'];
$login_msg = "✅ Autentificare reușită! Bun venit, " . htmlspecialchars($user['name']);
} else {
$login_msg = "❌ Email sau parolă incorectă.";
}
}
?>
<h3>Formular Login</h3>
<?php if($login_msg): ?>
<p><?= $login_msg ?></p>
<?php endif; ?>
<form method="post">
<input type="email" name="email" placeholder="Email" required><br>
<input type="password" name="password" placeholder="Parolă" required><br>
<button type="submit" name="login">Autentifică-te</button>
</form>
Acest cod poate fi pus într-un singur fișier, pentru a testa înregistrarea și login-ul live. Sesiunile permit păstrarea autentificării între pagini și securizează accesul la zonele protejate.
<?php
session_start();
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "traffice_php", "!@y3Ge-Z!WQI");
$register_msg = '';
if(isset($_POST['register'])) {
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
if(empty($username) || empty($email) || empty($password)) {
$register_msg = "Toate câmpurile sunt obligatorii.";
} elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$register_msg = "Email invalid.";
} else {
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
if($stmt->execute([$username, $email, $hash])) {
$register_msg = "✅ Cont creat cu succes!";
} else {
$register_msg = "❌ Eroare la crearea contului.";
}
}
}
?>
<h3>Formular Register</h3>
<?php if($register_msg): ?>
<p><?= $register_msg ?><p>
<?php endif; ?>
<form method="post">
<input type="text" name="username" placeholder="Nume" required><br>
<input type="email" name="email" placeholder="Email" required><br>
<input type="password" name="password" placeholder="Parolă" required><br>
<button type="submit" name="register">Înregistrează-te</button>
</form>
<?php
session_start();
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "traffice_php", "!@y3Ge-Z!WQI");
$login_msg = '';
if(isset($_POST['login'])) {
$email = trim($_POST['email']);
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name'];
$login_msg = "✅ Autentificare reușită! Bun venit, " . htmlspecialchars($user['name']);
} else {
$login_msg = "❌ Email sau parolă incorectă.";
}
}
?>
<h3>Formular Login</h3>
<?php if($login_msg): ?>
<p><?= $login_msg ?><p>
<?php endif; ?>
<form method="post">
<input type="email" name="email" placeholder="Email" required><br>
<input type="password" name="password" placeholder="Parolă" required><br>
<button type="submit" name="login">Autentifică-te</button>
</form>
Flash Messages în PHP
Flash messages sunt mesaje temporare care apar o singură dată după o acțiune (ex: login reușit, eroare la formular) și dispar după reîncărcarea paginii. Ele sunt de obicei stocate în sesiune.
Exemplu practic: Flash message după login
<?php
session_start();
// Setare mesaj flash după login
$_SESSION['flash_message'] = "✅ Ai fost logat cu succes!";
// Redirecționare către pagina principală
header("Location: index.php");
exit;
?>
<?php
session_start();
// Afișare mesaj flash și ștergere după afișare
if(isset($_SESSION['flash_message'])) {
echo "<div class='flash'>" . $_SESSION['flash_message'] . "</div>";
unset($_SESSION['flash_message']);
}
?>
Astfel, mesajul va fi vizibil doar o singură dată, apoi dispare automat.
Like / Dislike Posts
Pentru a implementa funcționalitatea de like/dislike, avem nevoie de o tabelă suplimentară care să stocheze acțiunile utilizatorilor asupra postărilor.
Pregătirea bazei de date pentru exemple
1. Creează un fișier numit update-db.php în folderul proiectului tău PHP.
2. Copiază în el codul de mai jos (cel care creează baza de date traffice-test, tabelele
users, posts, post_likes și adaugă date de test).
3. Deschide browserul și rulează fișierul astfel:
http://localhost/numele-folderului/update-db.php
4. Dacă totul e în regulă, vei vedea mesajul:
✅ Baza de date și tabelele au fost create cu date de test funcționale.
5. Acum ai toate tabelele și datele pregătite pentru a rula exemplele de: CRUD, Flash messages și Like/Dislike posts.
<?php
try {
$pdo = new PDO("mysql:host=localhost", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Creare baza de date
$pdo->exec("CREATE DATABASE IF NOT EXISTS traffice-test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
$pdo->exec("USE traffice-test");
// Creare tabela users
$pdo->exec("CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
password VARCHAR(255) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
// Inserare useri
$pdo->exec("INSERT INTO users (id, name, email, password) VALUES
(1, 'Ion Popescu', 'ion.popescu@example.com', '123'),
(2, 'Maria Ionescu', 'maria.ionescu@example.com', '123')
ON DUPLICATE KEY UPDATE name=VALUES(name), email=VALUES(email)");
// Creare tabela posts
$pdo->exec("CREATE TABLE IF NOT EXISTS posts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)");
// Inserare postari
$pdo->exec("INSERT INTO posts (id, user_id, title, content) VALUES
(1, 1, 'Primul articol', 'Acesta este primul post scris de utilizatorul 1.'),
(2, 1, 'Al doilea articol', 'Utilizatorul 1 mai are o postare.'),
(3, 2, 'Salutare!', 'Mesaj scris de utilizatorul 2.')
ON DUPLICATE KEY UPDATE title=VALUES(title), content=VALUES(content)");
// Creare tabela post_likes
$pdo->exec("CREATE TABLE IF NOT EXISTS post_likes (
id INT AUTO_INCREMENT PRIMARY KEY,
post_id INT NOT NULL,
user_id INT NOT NULL,
type ENUM('like','dislike') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_like (post_id,user_id),
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)");
echo "✅ Baza de date și tabelele au fost create cu date de test funcționale.";
} catch (PDOException $e) {
echo "❌ Eroare: " . $e->getMessage();
}
?>
Exemplu PHP pentru Like/Dislike
<?php
session_start();
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$post_id = 1; // ID post
$user_id = 1; // ID utilizator
$type = 'like'; // sau 'dislike'
// Inserare like/dislike
$stmt = $pdo->prepare("INSERT INTO post_likes (post_id, user_id, type) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE type = VALUES(type)");
$stmt->execute([$post_id, $user_id, $type]);
// Număr total like-uri și dislike-uri pentru un post
$counts = $pdo->query("SELECT type, COUNT(*) as total FROM post_likes WHERE post_id = $post_id GROUP BY type")
->fetchAll(PDO::FETCH_ASSOC);
foreach($counts as $c) {
echo "<p>" . ucfirst($c['type']) . ": " . $c['total'] . "</p>";
}
?>
Astfel, utilizatorii pot da like sau dislike, iar numărul total se actualizează automat. Funcția `ON DUPLICATE KEY UPDATE` asigură că un utilizator nu poate da like și dislike simultan pe aceeași postare.
<?php
// Conectare la baza de date
try {
$pdo = new PDO("mysql:host=localhost;dbname=traffice-test", "traffice_php", "!@y3Ge-Z!WQI");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Eroare conectare DB: " . $e->getMessage());
}
// Procesare like/dislike
if (isset($_POST['like']) && isset($_POST['post_id']) && isset($_POST['user_id'])) {
$type = $_POST['like'] === 'like' ? 'like' : 'dislike';
$stmt = $pdo->prepare("INSERT INTO post_likes (post_id, user_id, type)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE type = VALUES(type)");
$stmt->execute([$_POST['post_id'], $_POST['user_id'], $type]);
}
// Preluare postări și număr like/dislike
$sql = "SELECT posts.id, posts.title, posts.content, posts.created_at, users.name, users.email,
SUM(post_likes.type='like') AS likes,
SUM(post_likes.type='dislike') AS dislikes
FROM posts
INNER JOIN users ON posts.user_id = users.id
LEFT JOIN post_likes ON posts.id = post_likes.post_id
GROUP BY posts.id
ORDER BY posts.created_at DESC";
$stmt = $pdo->query($sql);
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Lista de utilizatori (pentru demo: user_id select)
$users = $pdo->query("SELECT * FROM users")->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<title>Like/Dislike Demo</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: auto; }
.post { border: 1px solid #ccc; padding: 1rem; margin-bottom: 1rem; border-radius: 8px; }
.buttons { margin-top: 0.5rem; }
button { margin-right: 0.5rem; }
select { margin-bottom: 1rem; }
</style>
</head>
<body>
<h1>Demo: Like / Dislike Postări</h1>
<form method="post">
<label for="user_id">Selectează utilizatorul:</label>
<select name="user_id" id="user_id">
<?php foreach($users as $user): ?>
<option value="<?php echo $user['id']; ?>"><?php echo htmlspecialchars($user['name']); ?></option>
<?php endforeach; ?>
</select>
</form>
<?php foreach($posts as $post): ?>
<div class="post">
<h2><?php echo htmlspecialchars($post['title']); ?></h2>
<p><?php echo htmlspecialchars($post['content']); ?><p>
<small>Scris de <?php echo htmlspecialchars($post['name']); ?> (<?php echo htmlspecialchars($post['email']); ?>) la <?php echo $post['created_at']; ?></small>
<div class="buttons">
<form method="post" style="display:inline;">
<input type="hidden" name="post_id" value="<?php echo $post['id']; ?>">
<input type="hidden" name="user_id" value="<?php echo $users[0]['id']; ?>">
<button type="submit" name="like" value="like">👍 Like (<?php echo $post['likes'] ?? 0; ?>)</button>
</form>
<form method="post" style="display:inline;">
<input type="hidden" name="post_id" value="<?php echo $post['id']; ?>">
<input type="hidden" name="user_id" value="<?php echo $users[0]['id']; ?>">
<button type="submit" name="like" value="dislike">👎 Dislike (<?php echo $post['dislikes'] ?? 0; ?>)</button>
</form>
</div>
</div>
<?php endforeach; ?>
</body>
</html>
