Bazy danych to fundament większości aplikacji webowych. Za każdym razem gdy:
- Przeglądasz posty na Instagramie
- Sprawdzasz ranking w grze online
- Szukasz wiadomości na Discordzie
- Oglądasz playlistę na Spotify
W tym materiale nauczysz się pobierać dane z bazy MySQL/MariaDB używając PHP. To podstawowa umiejętność, którą musisz opanować przed nauką modyfikowania danych (INSERT, UPDATE, DELETE – te operacje poznasz w następnym temacie).
Dane dostępowe do bazy
Niezależnie od wybranej metody, potrzebujesz 4 podstawowych informacji:
$serwer = 'localhost'; // Adres serwera (localhost lub 127.0.0.1)
$user = 'root'; // Nazwa użytkownika bazy
$pass = ''; // Hasło (domyślnie puste w XAMPP)
$baza = 'nazwa_bazy'; // Nazwa Twojej bazy danych
UWAGA: W środowisku produkcyjnym (na prawdziwym serwerze):
- Hasło NIE MOŻE być puste!
- Użytkownik NIE POWINIEN być
root - Dane logowania przechowuj w oddzielnym pliku (np.
config.php) - Nigdy nie commituj danych dostępowych do GitHuba!
Przykład pliku config.php:
<?php
// config.php - NIE COMMITUJ tego pliku do repozytorium!
define('DB_HOST', 'localhost');
define('DB_USER', 'twoj_user');
define('DB_PASS', 'twoje_silne_haslo');
define('DB_NAME', 'nazwa_bazy');
?>
Użycie w kodzie:
<?php
require_once 'config.php';
$pdo = new PDO(
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
DB_USER,
DB_PASS
);
?>
Przygotowanie – Utworzenie przykładowej bazy
Przed rozpoczęciem nauki potrzebujesz bazy z przykładowymi danymi. Stworzymy bazę gaming_hub z tabelą graczy – będzie bardziej interesująca niż klasyczne „imię i nazwisko”
Krok 1: Otwórz phpMyAdmin
W przeglądarce wejdź na:
http://localhost/phpmyadmin
Krok 2: Utwórz nową bazę danych
- Kliknij zakładkę „Bazy danych”
- W polu „Utwórz bazę danych” wpisz:
gaming_hub - Wybierz kodowanie: utf8mb4_unicode_ci (poprawniejsze sortowanie wielu języków, lepsza zgodność Unicode, obsługa polskich znaków;
mb4wutf8mb4oznacza „maximum bytes 4” — czyli kodowanie UTF-8 obsługujące znaki zajmujące do 4 bajtów.) - Kliknij „Utwórz”
Krok 3: Utwórz tabelę z danymi
Kliknij na bazę gaming_hub, przejdź do zakładki SQL i wykonaj poniższy kod:
-- Tabela graczy
CREATE TABLE players (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100),
level INT DEFAULT 1,
coins INT DEFAULT 0,
rank_name VARCHAR(20) DEFAULT 'Bronze',
games_played INT DEFAULT 0,
wins INT DEFAULT 0,
losses INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Przykładowe dane graczy (15 rekordów)
INSERT INTO players (username, email, level, coins, rank_name, games_played, wins, losses, last_login) VALUES
('ProGamer_Mike', 'mike@example.com', 45, 12500, 'Diamond', 850, 520, 330, NOW()),
('xX_Anna_Xx', 'anna@example.com', 32, 8900, 'Platinum', 620, 380, 240, NOW()),
('NinjaKiller', 'ninja@example.com', 67, 23400, 'Master', 1240, 890, 350, NOW()),
('ShadowHunter', 'shadow@example.com', 28, 6700, 'Gold', 490, 270, 220, DATE_SUB(NOW(), INTERVAL 2 DAY)),
('DragonSlayer99', 'dragon@example.com', 19, 4200, 'Silver', 320, 160, 160, DATE_SUB(NOW(), INTERVAL 5 DAY)),
('CoolGamer', 'cool@example.com', 52, 15600, 'Diamond', 980, 610, 370, NOW()),
('LegendaryPlayer', 'legend@example.com', 89, 45000, 'Grandmaster', 2100, 1560, 540, NOW()),
('NoobMaster', 'noob@example.com', 8, 1200, 'Bronze', 85, 30, 55, DATE_SUB(NOW(), INTERVAL 10 DAY)),
('FastFingers', 'fast@example.com', 41, 11200, 'Platinum', 740, 450, 290, NOW()),
('SilentAssassin', 'silent@example.com', 36, 9800, 'Platinum', 680, 410, 270, DATE_SUB(NOW(), INTERVAL 1 DAY)),
('ThunderStrike', 'thunder@example.com', 24, 5600, 'Gold', 410, 220, 190, DATE_SUB(NOW(), INTERVAL 3 DAY)),
('IceQueen', 'ice@example.com', 55, 17800, 'Diamond', 1050, 670, 380, NOW()),
('FireStorm', 'fire@example.com', 15, 3100, 'Silver', 250, 120, 130, DATE_SUB(NOW(), INTERVAL 7 DAY)),
('MysticWarrior', 'mystic@example.com', 63, 21000, 'Master', 1180, 800, 380, NOW()),
('SpeedDemon', 'speed@example.com', 29, 7200, 'Gold', 520, 290, 230, DATE_SUB(NOW(), INTERVAL 4 DAY));
Struktura tabeli players:
| Kolumna | Typ | Opis |
|---|---|---|
id | INT | Unikalny identyfikator (AUTO_INCREMENT) |
username | VARCHAR(50) | Nick gracza (unikalny) |
email | VARCHAR(100) | Adres email |
level | INT | Poziom gracza |
coins | INT | Wirtualna waluta |
rank_name | VARCHAR(20) | Ranga (Bronze, Silver, Gold, Platinum, Diamond, Master, Grandmaster) |
games_played | INT | Liczba rozegranych gier |
wins | INT | Liczba wygranych |
losses | INT | Liczba przegranych |
created_at | TIMESTAMP | Data utworzenia konta |
last_login | TIMESTAMP | Ostatnie logowanie |
Sposoby połączenia z bazą danych
PHP oferuje 2 nowoczesne sposoby komunikacji z MySQL, podejście proceduralne pomijamy jako przestarzałe.
1. MySQLi – Podejście obiektowe
Wykorzystujemy klasę mysqli.
$db = new mysqli($serwer, $user, $pass, $baza);
Podejście dobre, ale tylko dla MySQL/MariaDB
2. PDO – PHP Data Objects (ZALECANE!)
$pdo = new PDO("mysql:host=$serwer;dbname=$baza;charset=utf8mb4", $user, $pass);
Podejście uniwersalne, bezpieczne, nowoczesne
Łączenie z bazą danych
MySQLi – Podejście obiektowe
<?php
// Dane dostępowe
$serwer = 'localhost';
$user = 'root';
$pass = '';
$baza = 'gaming_hub';
// Wyłączamy automatyczne raportowanie błędów
mysqli_report(MYSQLI_REPORT_OFF);
// Połączenie obiektowe (@ ukrywa ostrzeżenia)
$db = @new mysqli($serwer, $user, $pass, $baza);
// Sprawdzenie połączenia
if ($db->connect_error) {
die("Błąd połączenia: {$db->connect_error}");
}
echo 'Połączenie nawiązano!<br>';
// Ustawienie kodowania (ważne dla polskich znaków i emoji!)
$db->set_charset('utf8mb4');
// ... wykonywanie zapytań ...
// Zamknięcie połączenia
$db->close();
?>
Dostępne właściwości do obsługi błędów:
$db->connect_error // Opis błędu połączenia
$db->connect_errno // Kod błędu połączenia
$db->error // Opis ostatniego błędu
$db->errno // Kod ostatniego błędu
PDO – PHP Data Objects
<?php
// Dane dostępowe
$serwer = 'localhost';
$user = 'root';
$pass = '';
$baza = 'gaming_hub';
// Opcje PDO dla bezpieczeństwa i wygody
$opcje = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Włącz wyjątki
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Domyślnie tablica asocjacyjna
PDO::ATTR_EMULATE_PREPARES => false, // Prawdziwe prepared statements
];
try {
// Połączenie PDO
$pdo = new PDO(
"mysql:host=$serwer;dbname=$baza;charset=utf8mb4",
$user,
$pass,
$opcje
);
echo 'Połączenie nawiązano!<br>';
// ... wykonywanie zapytań ...
} catch (PDOException $e) {
// W prawdziwej aplikacji NIE pokazuj szczegółów błędu użytkownikowi!
error_log("DB Error: {$e->getMessage()}");
die('Nie można połączyć się z bazą danych. Spróbuj później.');
}
// Zamknięcie połączenia
$pdo = null;
?>
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION– rzuca wyjątki przy błędach (łatwiej debugować)PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC– zwraca tablice asocjacyjne (czytelniejsze)PDO::ATTR_EMULATE_PREPARES => false– prawdziwe prepared statements (bezpieczniejsze)
Zamykanie połączenia z bazą
Operacja zamknięcia połączenia jest automatycznie wykonywana po zakończeniu skryptu. Jeżeli potrzebujemy zakończyć połączenie wcześniej:
MySQLi obiektowo:
$db->close();
PDO:
$pdo = null;
// lub
unset($pdo);
W praktyce: Rzadko musisz ręcznie zamykać połączenie – PHP robi to automatycznie po zakończeniu skryptu, ale na egzaminie zawodowym jest to wymagane.
SELECT – Pobieranie wszystkich rekordów
UWAGA: stosowanie query() nie zapewnia bezpieczeństwa w przypadku ataków SQJ Injection. Zamiast query należy używać parameterized prepared statements (opracowanie dalej w temacie). Aby query() było bezpieczne należy stosować mysqli_real_escape_string().
Użycie samego query() jest dopuszczalne na egzaminie zawodowym, jednak w prawdziwych projektach ZAWSZE używaj prepared statements.
Przykład 1: MySQLi obiektowo – PODATNE NA ATAKI! – tak nie rób
<?php
// Połączenie z bazą
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die("Błąd połączenia: {$db->connect_error}");
}
$db->set_charset('utf8mb4');
echo 'Połączenie nawiązano<br><br>';
// Zapytanie SQL - pobierz wszystkich graczy
$sql = "SELECT * FROM players";
$wynik = $db->query($sql);
// Sprawdzamy liczbę rekordów
$ile_wierszy = $wynik->num_rows;
echo "Znaleziono graczy: <strong>{$ile_wierszy}</strong><br><br>";
// Wyświetlamy w tabeli
echo '<table border="1" cellpadding="10" cellspacing="0">';
echo '<tr>
<th>ID</th>
<th>Username</th>
<th>Level</th>
<th>Coins</th>
<th>Rank</th>
<th>Wins/Losses</th>
</tr>';
// Pętla while - pobieramy kolejne rekordy
while ($wiersz = $wynik->fetch_assoc()) {
$username = htmlspecialchars($wiersz['username']);
$coins = number_format($wiersz['coins']);
echo "<tr>";
echo "<td>{$wiersz['id']}</td>";
echo "<td>{$username}</td>";
echo "<td>{$wiersz['level']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$wiersz['rank_name']}</td>";
echo "<td>{$wiersz['wins']}/{$wiersz['losses']}</td>";
echo "</tr>";
}
echo '</table>';
// Zamknięcie połączenia
$db->close();
?>
Alternatywnie – pętla foreach
<?php
// ... (połączenie jak wyżej)
$sql = "SELECT * FROM players";
$wynik = $db->query($sql);
echo "Znaleziono graczy: {$wynik->num_rows}<br><br>";
foreach ($wynik as $row) {
$username = htmlspecialchars($row['username']);
echo "{$row['id']} - {$username} (Level: {$row['level']})<br>";
}
$db->close();
?>
Przykład 1: PDO – PODATNE NA ATAKI! – tak nie rób
<?php
try {
// Połączenie PDO
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
echo 'Połączenie nawiązano<br><br>';
// Zapytanie SQL
$sql = "SELECT * FROM players";
$stmt = $pdo->query($sql);
// Pobranie wszystkich wyników
$wyniki = $stmt->fetchAll();
$liczba_graczy = count($wyniki);
echo "Znaleziono graczy: <strong>{$liczba_graczy}</strong><br><br>";
// Wyświetlanie w tabeli HTML
echo '<table border="1" cellpadding="10" cellspacing="0">';
echo '<tr>
<th>ID</th>
<th>Username</th>
<th>Level</th>
<th>Coins</th>
<th>Rank</th>
<th>Games</th>
<th>Win Rate</th>
</tr>';
foreach ($wyniki as $wiersz) {
// Obliczamy Win Rate (procent wygranych)
$winRate = $wiersz['games_played'] > 0
? round(($wiersz['wins'] / $wiersz['games_played']) * 100, 1)
: 0;
$username = htmlspecialchars($wiersz['username']);
$coins = number_format($wiersz['coins']);
echo "<tr>";
echo "<td>{$wiersz['id']}</td>";
echo "<td>{$username}</td>";
echo "<td>{$wiersz['level']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$wiersz['rank_name']}</td>";
echo "<td>{$wiersz['games_played']}</td>";
echo "<td>{$winRate}%</td>";
echo "</tr>";
}
echo '</table>';
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
// Zamknięcie połączenia
$pdo = null;
?>
BEZPIECZEŃSTWO – SQL Injection
SQL Injection to technika ataku, w której hacker wstrzykuje złośliwy kod SQL przez dane wejściowe (formularze, URL). To najczęstszy typ ataku na aplikacje webowe!
NIEBEZPIECZNY KOD (NIGDY TAK NIE RÓB!)
<?php
// PODATNE NA SQL INJECTION!
$username = $_POST['username'];
// Niebezpieczne zapytanie - łączenie stringów!
$sql = "SELECT * FROM players WHERE username = '$username'";
$wynik = $db->query($sql);
/*
PROBLEM: Użytkownik może wpisać złośliwy kod!
*/
?>
Jak działa atak SQL Injection?
Scenariusz 1: Normalny użytkownik
---------------------------------
Użytkownik wpisuje: ProGamer_Mike
Zapytanie SQL: SELECT * FROM players WHERE username = 'ProGamer_Mike'
Wynik: Zwraca dane gracza
Scenariusz 2: Hacker - ujawnienie wszystkich danych
---------------------------------------------------
Hacker wpisuje: ' OR '1'='1
Zapytanie SQL: SELECT * FROM players WHERE username = '' OR '1'='1'
Wynik: Zwraca WSZYSTKICH graczy!
Dlaczego? '1'='1' jest zawsze prawdą, więc warunek zawsze się spełnia
Scenariusz 3: Hacker - usunięcie tabeli
----------------------------------------
Hacker wpisuje: '; DROP TABLE players; --
Zapytanie SQL: SELECT * FROM players WHERE username = ''; DROP TABLE players; --'
Wynik: USUWA CAŁĄ TABELĘ!
Dlaczego? Średnik (;) kończy pierwsze zapytanie, DROP TABLE usuwa tabelę,
-- komentuje resztę zapytania
Scenariusz 4: Hacker - dodanie administratora
----------------------------------------------
Hacker wpisuje: '; INSERT INTO users (username, role) VALUES ('hacker', 'admin'); --
Wynik: Dodaje sobie konto z uprawnieniami admina!
Rzeczywiste konsekwencje SQL Injection:
- Kradzież danych – haker może pobrać hasła, emaile, dane kart kredytowych
- Usunięcie danych – cała baza może zostać skasowana
- Modyfikacja danych – zmiana cen produktów, uprawnień użytkowników
- Przejęcie kontroli – dodanie konta administratora
- Kara prawna i finansowa – naruszenie RODO, utrata reputacji firmy
BEZPIECZNY KOD – Prepared Statements
BEZPIECZNY KOD – Prepared Statements
Prepared Statements (zapytania przygotowane) to mechanizm, który rozdziela kod SQL od danych. Baza danych najpierw „przygotowuje” zapytanie, a potem osobno przekazuje dane.
Dlaczego są bezpieczne?
- Separacja kodu i danych – SQL i dane są wysyłane osobno
- Automatyczne escapowanie – baza wie, że to dane, nie kod
- Niemożliwy injection – dane nie mogą zmienić struktury zapytania
Jak działają Prepared Statements?
Krok 1: Przygotowanie zapytania (prepare)
------------------------------------------
PHP do MySQL: "Przygotuj zapytanie: SELECT * FROM players WHERE username = ?"
MySQL: "OK, czekam na dane do znaku zapytania"
Krok 2: Wysłanie danych (execute/bind_param)
---------------------------------------------
PHP do MySQL: "Podstaw wartość: ' OR '1'='1"
MySQL: "OK, traktuję to jako TEKST, nie jako KOD SQL"
Krok 3: Wykonanie
-----------------
MySQL wykonuje: SELECT * FROM players WHERE username = '\' OR \'1\'=\'1\''
↑ Escapowane apostrofy
Wynik: Szuka gracza o nicku "' OR '1'='1" (nie znajdzie takiego)
NIE WYKONUJE ataku!
Przykład działania – porównanie
// BEZ prepared statements (niebezpieczne):
$username = "' OR '1'='1";
$sql = "SELECT * FROM players WHERE username = '$username'";
// Zapytanie: SELECT * FROM players WHERE username = '' OR '1'='1'
// ATAK SKUTECZNY!
// Z prepared statements (bezpieczne):
$username = "' OR '1'='1";
$stmt = $pdo->prepare("SELECT * FROM players WHERE username = :username");
$stmt->execute(['username' => $username]);
// Zapytanie: SELECT * FROM players WHERE username = '\' OR \'1\'=\'1\''
// Szuka gracza o nicku "' OR '1'='1" - nie znajdzie
// ATAK ZABLOKOWANY!
SELECT z warunkiem WHERE – dane z formularza ($_POST)
Bezpieczne podejście z prepared statements – tak robimy.
Przykład 1: Pobierz wszystkich graczy (prepared statements) – MySQLi obiektowo:
<?php
// Połączenie z bazą
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die("Błąd połączenia: {$db->connect_error}");
}
$db->set_charset('utf8mb4');
echo 'Połączenie nawiązano<br><br>';
// BEZPIECZNE - Prepared statement
// Dla SELECT * bez parametrów też używamy prepare() (dobra praktyka)
$stmt = $db->prepare("SELECT * FROM players");
$stmt->execute();
// Pobranie wyniku
$wynik = $stmt->get_result();
// Sprawdzamy liczbę rekordów
$ile_wierszy = $wynik->num_rows;
echo "Znaleziono graczy: <strong>{$ile_wierszy}</strong><br><br>";
// Wyświetlamy w tabeli
echo '<table border="1" cellpadding="10" cellspacing="0">';
echo '<tr>
<th>ID</th>
<th>Username</th>
<th>Level</th>
<th>Coins</th>
<th>Rank</th>
<th>Wins/Losses</th>
</tr>';
// Pętla while - pobieramy kolejne rekordy
while ($wiersz = $wynik->fetch_assoc()) {
$username = htmlspecialchars($wiersz['username']);
$coins = number_format($wiersz['coins']);
echo "<tr>";
echo "<td>{$wiersz['id']}</td>";
echo "<td>{$username}</td>";
echo "<td>{$wiersz['level']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$wiersz['rank_name']}</td>";
echo "<td>{$wiersz['wins']}/{$wiersz['losses']}</td>";
echo "</tr>";
}
echo '</table>';
// Zamknięcie
$stmt->close();
$db->close();
?>
PDO:
<?php
try {
// Połączenie PDO
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
echo 'Połączenie nawiązano<br><br>';
// BEZPIECZNE - Prepared statement
$stmt = $pdo->prepare("SELECT * FROM players");
$stmt->execute();
// Pobranie wszystkich wyników
$wyniki = $stmt->fetchAll();
$liczba_graczy = count($wyniki);
echo "Znaleziono graczy: <strong>{$liczba_graczy}</strong><br><br>";
// Wyświetlanie w tabeli HTML
echo '<table border="1" cellpadding="10" cellspacing="0">';
echo '<tr>
<th>ID</th>
<th>Username</th>
<th>Level</th>
<th>Coins</th>
<th>Rank</th>
<th>Games</th>
<th>Win Rate</th>
</tr>';
foreach ($wyniki as $wiersz) {
// Obliczamy Win Rate (procent wygranych)
$winRate = $wiersz['games_played'] > 0
? round(($wiersz['wins'] / $wiersz['games_played']) * 100, 1)
: 0;
$username = htmlspecialchars($wiersz['username']);
$coins = number_format($wiersz['coins']);
echo "<tr>";
echo "<td>{$wiersz['id']}</td>";
echo "<td>{$username}</td>";
echo "<td>{$wiersz['level']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$wiersz['rank_name']}</td>";
echo "<td>{$wiersz['games_played']}</td>";
echo "<td>{$winRate}%</td>";
echo "</tr>";
}
echo '</table>';
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
// Zamknięcie połączenia
$pdo = null;
?>
- Używamy
htmlspecialchars()dla bezpieczeństwa (ochrona przed XSS) - Używamy
number_format()dla czytelności liczb (1234 → 1,234) - PDO automatycznie zwraca tablice asocjacyjne (ustawiliśmy w opcjach)
Przykład 2: Wyszukiwanie gracza po nicku (formularz POST)
MySQLi obiektowo
<?php
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die('Błąd połączenia');
}
$db->set_charset('utf8mb4');
// Sprawdzamy czy formularz został wysłany
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Pobieramy dane z formularza
$username = trim($_POST['username'] ?? '');
if (!empty($username)) {
// BEZPIECZNE - Prepared statement
$stmt = $db->prepare("SELECT * FROM players WHERE username = ?");
// Bindowanie parametru (s = string)
$stmt->bind_param("s", $username);
// Wykonanie zapytania
$stmt->execute();
// Pobranie wyniku
$wynik = $stmt->get_result();
if ($gracz = $wynik->fetch_assoc()) {
$safe_username = htmlspecialchars($gracz['username']);
$safe_email = htmlspecialchars($gracz['email']);
$coins = number_format($gracz['coins']);
echo "<h2>Profil Gracza</h2>";
echo "<strong>{$safe_username}</strong><br>";
echo "Email: {$safe_email}<br>";
echo "Level: {$gracz['level']}<br>";
echo "Rank: {$gracz['rank_name']}<br>";
echo "Coins: {$coins}<br>";
echo "Games: {$gracz['games_played']} (W: {$gracz['wins']}, L: {$gracz['losses']})<br>";
} else {
$safe_search = htmlspecialchars($username);
echo "Nie znaleziono gracza: {$safe_search}";
}
$stmt->close();
} else {
echo "Wpisz nick gracza!";
}
}
$db->close();
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Wyszukaj gracza</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
}
form {
background: #f4f4f4;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
input[type="text"] {
padding: 10px;
width: 70%;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
</head>
<body>
<h1>Wyszukaj gracza</h1>
<form method="POST">
<input type="text" name="username" placeholder="Wpisz nick gracza" value="<?= htmlspecialchars($_POST['username'] ?? '') ?>" required>
<button type="submit" name="szukaj">Szukaj</button>
</form>
</body>
</html>
PDO
<?php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
// Sprawdzamy czy formularz został wysłany
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Pobieramy dane z formularza
$username = trim($_POST['username'] ?? '');
if (!empty($username)) {
// BEZPIECZNE - Prepared statement z named parameter
$stmt = $pdo->prepare("SELECT * FROM players WHERE username = :username");
$stmt->execute(['username' => $username]);
$gracz = $stmt->fetch();
if ($gracz) {
$safe_username = htmlspecialchars($gracz['username']);
$safe_email = htmlspecialchars($gracz['email']);
$coins = number_format($gracz['coins']);
echo "<h2>Profil Gracza</h2>";
echo "<strong>{$safe_username}</strong><br>";
echo "Email: {$safe_email}<br>";
echo "Level: {$gracz['level']}<br>";
echo "Rank: {$gracz['rank_name']}<br>";
echo "Coins: {$coins}<br>";
echo "Games: {$gracz['games_played']} (W: {$gracz['wins']}, L: {$gracz['losses']})<br>";
} else {
$safe_search = htmlspecialchars($username);
echo "Nie znaleziono gracza: {$safe_search}";
}
} else {
echo "Wpisz nick gracza!";
}
}
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
$pdo = null;
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Wyszukaj gracza</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
}
form {
background: #f4f4f4;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
input[type="text"] {
padding: 10px;
width: 70%;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
</head>
<body>
<h1>Wyszukaj gracza</h1>
<form method="POST">
<input type="text" name="username" placeholder="Wpisz nick gracza" value="<?= htmlspecialchars($_POST['username'] ?? '') ?>" required>
<button type="submit" name="szukaj">Szukaj</button>
</form>
</body>
</html>
SELECT z warunkiem WHERE – dane z URL ($_GET)
Przykład 3: Profil gracza przez URL (GET)
Adres URL: profil.php?id=5 lub profil.php?username=ProGamer_Mike
MySQLi obiektowo:
<?php
// profil.php
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die('Błąd połączenia');
}
$db->set_charset('utf8mb4');
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['id'])) {
// Pobieramy ID z URL
$player_id = (int)$_GET['id'];
if ($player_id > 0) {
// BEZPIECZNE - Prepared statement
$stmt = $db->prepare("SELECT * FROM players WHERE id = ?");
$stmt->bind_param("i", $player_id); // i = integer
$stmt->execute();
$wynik = $stmt->get_result();
if ($gracz = $wynik->fetch_assoc()) {
$username = htmlspecialchars($gracz['username']);
$email = htmlspecialchars($gracz['email']);
$coins = number_format($gracz['coins']);
echo "<h1>Profil gracza</h1>";
echo "<div style='background:#f4f4f4; padding:20px; border-radius:8px;'>";
echo "<h2>{$username}</h2>";
echo "<p>Email: {$email}</p>";
echo "<p>Level: <strong>{$gracz['level']}</strong></p>";
echo "<p>Rank: <strong>{$gracz['rank_name']}</strong></p>";
echo "<p>Coins: <strong>{$coins}</strong></p>";
echo "<p>Rozegrane gry: {$gracz['games_played']}</p>";
echo "<p>Wygrane: {$gracz['wins']}</p>";
echo "<p>Przegrane: {$gracz['losses']}</p>";
// Win Rate
$winRate = $gracz['games_played'] > 0
? round(($gracz['wins'] / $gracz['games_played']) * 100, 1)
: 0;
echo "<p>Win Rate: <strong>{$winRate}%</strong></p>";
echo "</div>";
} else {
echo "Nie znaleziono gracza o ID: {$player_id}";
}
$stmt->close();
} else {
echo "Nieprawidłowe ID gracza";
}
} else {
echo "Podaj ID gracza w URL (np. profil.php?id=5)";
}
$db->close();
// Lista linków do innych graczy
echo "<br><hr><h3>Inni gracze:</h3>";
echo "<a href='profil.php?id=1'>Gracz #1</a> | ";
echo "<a href='profil.php?id=2'>Gracz #2</a> | ";
echo "<a href='profil.php?id=3'>Gracz #3</a> | ";
echo "<a href='profil.php?id=7'>Gracz #7</a>";
?>
PDO:
<?php
// profil.php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
// sprawdzamy metodę HTTP i parametr
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['id'])) {
// Pobieramy ID z URL
$player_id = (int)$_GET['id'];
if ($player_id > 0) {
// BEZPIECZNE - Prepared statement
$stmt = $pdo->prepare("SELECT * FROM players WHERE id = :id");
$stmt->execute(['id' => $player_id]);
$gracz = $stmt->fetch();
if ($gracz) {
$username = htmlspecialchars($gracz['username']);
$email = htmlspecialchars($gracz['email']);
$coins = number_format($gracz['coins']);
echo "<h1>Profil gracza</h1>";
echo "<div style='background:#f4f4f4; padding:20px; border-radius:8px;'>";
echo "<h2>{$username}</h2>";
echo "<p>Email: {$email}</p>";
echo "<p>Level: <strong>{$gracz['level']}</strong></p>";
echo "<p>Rank: <strong>{$gracz['rank_name']}</strong></p>";
echo "<p>Coins: <strong>{$coins}</strong></p>";
echo "<p>Rozegrane gry: {$gracz['games_played']}</p>";
echo "<p>Wygrane: {$gracz['wins']}</p>";
echo "<p>Przegrane: {$gracz['losses']}</p>";
// Win Rate
$winRate = $gracz['games_played'] > 0
? round(($gracz['wins'] / $gracz['games_played']) * 100, 1)
: 0;
echo "<p>Win Rate: <strong>{$winRate}%</strong></p>";
echo "</div>";
} else {
echo "Nie znaleziono gracza o ID: {$player_id}";
}
} else {
echo "Nieprawidłowe ID gracza";
}
} else {
echo "Podaj ID gracza w URL (np. profil.php?id=5)";
}
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
$pdo = null;
// Lista linków do innych graczy
echo "<br><hr><h3>Inni gracze:</h3>";
echo "<a href='profil.php?id=1'>Gracz #1</a> | ";
echo "<a href='profil.php?id=2'>Gracz #2</a> | ";
echo "<a href='profil.php?id=3'>Gracz #3</a> | ";
echo "<a href='profil.php?id=7'>Gracz #7</a>";
?>
Przykład 4: Wyszukiwarka z wieloma filtrami (formularz POST)
MySQLi obiektowo:
<?php
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die('Błąd połączenia');
}
$db->set_charset('utf8mb4');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Pobieramy dane z formularza
$username = trim($_POST['username'] ?? '');
$rank = $_POST['rank'] ?? '';
$min_level = (int)($_POST['min_level'] ?? 0);
// Budujemy zapytanie dynamicznie (BEZPIECZNIE!)
$sql = "SELECT * FROM players WHERE 1=1";
$types = "";
$params = [];
if (!empty($username)) {
$sql .= " AND username LIKE ?";
$types .= "s";
$params[] = "%{$username}%";
}
if (!empty($rank)) {
$sql .= " AND rank_name = ?";
$types .= "s";
$params[] = $rank;
}
if ($min_level > 0) {
$sql .= " AND level >= ?";
$types .= "i";
$params[] = $min_level;
}
$sql .= " ORDER BY level DESC";
// Przygotowanie i wykonanie zapytania
$stmt = $db->prepare($sql);
if (!empty($params)) {
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
$wynik = $stmt->get_result();
// Wyświetlamy wyniki
if ($wynik->num_rows > 0) {
echo "<h3>Znaleziono: {$wynik->num_rows} graczy</h3>";
echo '<table border="1" cellpadding="10" style="width:100%; border-collapse:collapse;">';
echo '<tr style="background:#007bff; color:white;">
<th>Username</th>
<th>Level</th>
<th>Rank</th>
<th>Coins</th>
<th>Games</th>
</tr>';
while ($gracz = $wynik->fetch_assoc()) {
$safe_username = htmlspecialchars($gracz['username']);
$coins = number_format($gracz['coins']);
echo "<tr>";
echo "<td>{$safe_username}</td>";
echo "<td>{$gracz['level']}</td>";
echo "<td>{$gracz['rank_name']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$gracz['games_played']}</td>";
echo "</tr>";
}
echo '</table>';
} else {
echo "<p>Nie znaleziono graczy spełniających kryteria</p>";
}
$stmt->close();
}
$db->close();
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Wyszukiwarka graczy</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1000px;
margin: 50px auto;
padding: 20px;
}
form {
background: #f4f4f4;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
input, select {
padding: 10px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
table {
width: 100%;
border-collapse: collapse;
}
tr:hover {
background: #f5f5f5;
}
</style>
</head>
<body>
<h1>Wyszukiwarka Graczy</h1>
<form method="POST">
<input type="text" name="username" placeholder="Nick gracza (fragment)" value="<?= htmlspecialchars($_POST['username'] ?? '') ?>">
<select name="rank">
<option value="">Wszystkie rangi</option>
<option value="Bronze" <?= ($_POST['rank'] ?? '') == 'Bronze' ? 'selected' : '' ?>>Bronze</option>
<option value="Silver" <?= ($_POST['rank'] ?? '') == 'Silver' ? 'selected' : '' ?>>Silver</option>
<option value="Gold" <?= ($_POST['rank'] ?? '') == 'Gold' ? 'selected' : '' ?>>Gold</option>
<option value="Platinum" <?= ($_POST['rank'] ?? '') == 'Platinum' ? 'selected' : '' ?>>Platinum</option>
<option value="Diamond" <?= ($_POST['rank'] ?? '') == 'Diamond' ? 'selected' : '' ?>>Diamond</option>
<option value="Master" <?= ($_POST['rank'] ?? '') == 'Master' ? 'selected' : '' ?>>Master</option>
<option value="Grandmaster" <?= ($_POST['rank'] ?? '') == 'Grandmaster' ? 'selected' : '' ?>>Grandmaster</option>
</select>
<input type="number" name="min_level" placeholder="Min. poziom" min="1" value="<?= htmlspecialchars($_POST['min_level'] ?? '') ?>">
<button type="submit" name="szukaj">Szukaj</button>
</form>
</body>
</html>
PDO:
<?php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Pobieramy dane z formularza
$username = trim($_POST['username'] ?? '');
$rank = $_POST['rank'] ?? '';
$min_level = (int)($_POST['min_level'] ?? 0);
// Budujemy zapytanie dynamicznie (BEZPIECZNIE!)
$sql = "SELECT * FROM players WHERE 1=1";
$params = [];
if (!empty($username)) {
$sql .= " AND username LIKE :username";
$params['username'] = "%{$username}%";
}
if (!empty($rank)) {
$sql .= " AND rank_name = :rank";
$params['rank'] = $rank;
}
if ($min_level > 0) {
$sql .= " AND level >= :min_level";
$params['min_level'] = $min_level;
}
$sql .= " ORDER BY level DESC";
// Wykonujemy zapytanie
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$wyniki = $stmt->fetchAll();
// Wyświetlamy wyniki
$liczba = count($wyniki);
if ($liczba > 0) {
echo "<h3>Znaleziono: {$liczba} graczy</h3>";
echo '<table border="1" cellpadding="10" style="width:100%; border-collapse:collapse;">';
echo '<tr style="background:#007bff; color:white;">
<th>Username</th>
<th>Level</th>
<th>Rank</th>
<th>Coins</th>
<th>Games</th>
</tr>';
foreach ($wyniki as $gracz) {
$safe_username = htmlspecialchars($gracz['username']);
$coins = number_format($gracz['coins']);
echo "<tr>";
echo "<td>{$safe_username}</td>";
echo "<td>{$gracz['level']}</td>";
echo "<td>{$gracz['rank_name']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$gracz['games_played']}</td>";
echo "</tr>";
}
echo '</table>';
} else {
echo "<p>Nie znaleziono graczy spełniających kryteria</p>";
}
}
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
$pdo = null;
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Wyszukiwarka graczy</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1000px;
margin: 50px auto;
padding: 20px;
}
form {
background: #f4f4f4;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
input, select {
padding: 10px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
table {
width: 100%;
border-collapse: collapse;
}
tr:hover {
background: #f5f5f5;
}
</style>
</head>
<body>
<h1>Wyszukiwarka Graczy</h1>
<form method="POST">
<input type="text" name="username" placeholder="Nick gracza (fragment)" value="<?= htmlspecialchars($_POST['username'] ?? '') ?>">
<select name="rank">
<option value="">Wszystkie rangi</option>
<option value="Bronze" <?= ($_POST['rank'] ?? '') == 'Bronze' ? 'selected' : '' ?>>Bronze</option>
<option value="Silver" <?= ($_POST['rank'] ?? '') == 'Silver' ? 'selected' : '' ?>>Silver</option>
<option value="Gold" <?= ($_POST['rank'] ?? '') == 'Gold' ? 'selected' : '' ?>>Gold</option>
<option value="Platinum" <?= ($_POST['rank'] ?? '') == 'Platinum' ? 'selected' : '' ?>>Platinum</option>
<option value="Diamond" <?= ($_POST['rank'] ?? '') == 'Diamond' ? 'selected' : '' ?>>Diamond</option>
<option value="Master" <?= ($_POST['rank'] ?? '') == 'Master' ? 'selected' : '' ?>>Master</option>
<option value="Grandmaster" <?= ($_POST['rank'] ?? '') == 'Grandmaster' ? 'selected' : '' ?>>Grandmaster</option>
</select>
<input type="number" name="min_level" placeholder="Min. poziom" min="1" value="<?= htmlspecialchars($_POST['min_level'] ?? '') ?>">
<button type="submit" name="szukaj">Szukaj</button>
</form>
</body>
</html>
Przykład 5: Ranking graczy – sortowanie i limit (GET)
Adres URL: ranking.php?sort=level&order=desc&limit=10
MySQLi obiektowo:
<?php
// ranking.php
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die('Błąd połączenia');
}
$db->set_charset('utf8mb4');
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// Pobieramy parametry z URL
$sort = $_GET['sort'] ?? 'level';
$order = $_GET['order'] ?? 'desc';
$limit = (int)($_GET['limit'] ?? 10);
// Walidacja parametrów (whitelist - tylko dozwolone wartości)
$allowed_sort = ['level', 'coins', 'wins', 'games_played'];
$allowed_order = ['asc', 'desc'];
if (!in_array($sort, $allowed_sort)) {
$sort = 'level';
}
if (!in_array($order, $allowed_order)) {
$order = 'desc';
}
if ($limit < 1 || $limit > 100) {
$limit = 10;
}
// BEZPIECZNE - używamy walidacji + prepared statement dla limitu
// Kolumny sortowania są z whitelisty, więc bezpieczne
$sql = "SELECT * FROM players ORDER BY {$sort} {$order} LIMIT ?";
$stmt = $db->prepare($sql);
$stmt->bind_param("i", $limit);
$stmt->execute();
$wynik = $stmt->get_result();
$sort_label = [
'level' => 'poziomu',
'coins' => 'coins',
'wins' => 'wygranych',
'games_played' => 'rozegranych gier'
];
echo "<h1>Ranking graczy (wg {$sort_label[$sort]})</h1>";
echo "<p>Top {$limit} graczy</p>";
echo '<table border="1" cellpadding="10" style="width:100%; border-collapse:collapse;">';
echo '<tr style="background:#007bff; color:white;">
<th>#</th>
<th>Username</th>
<th>Level</th>
<th>Rank</th>
<th>Coins</th>
<th>Wins</th>
<th>Games</th>
</tr>';
$pozycja = 1;
while ($gracz = $wynik->fetch_assoc()) {
$username = htmlspecialchars($gracz['username']);
$coins = number_format($gracz['coins']);
echo "<tr>";
echo "<td><strong>#{$pozycja}</strong></td>";
echo "<td>{$username}</td>";
echo "<td>{$gracz['level']}</td>";
echo "<td>{$gracz['rank_name']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$gracz['wins']}</td>";
echo "<td>{$gracz['games_played']}</td>";
echo "</tr>";
$pozycja++;
}
echo '</table>';
echo "<br><p>Zmień sortowanie:</p>";
echo "<a href='ranking.php?sort=level&order=desc&limit=10'>Top 10 Level</a> | ";
echo "<a href='ranking.php?sort=coins&order=desc&limit=5'>Top 5 Coins</a> | ";
echo "<a href='ranking.php?sort=wins&order=desc&limit=20'>Top 20 Wins</a>";
$stmt->close();
}
$db->close();
?>
PDO:
<?php
// ranking.php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// Pobieramy parametry z URL
$sort = $_GET['sort'] ?? 'level';
$order = $_GET['order'] ?? 'desc';
$limit = (int)($_GET['limit'] ?? 10);
// Walidacja parametrów (whitelist - tylko dozwolone wartości)
$allowed_sort = ['level', 'coins', 'wins', 'games_played'];
$allowed_order = ['asc', 'desc'];
if (!in_array($sort, $allowed_sort)) {
$sort = 'level';
}
if (!in_array($order, $allowed_order)) {
$order = 'desc';
}
if ($limit < 1 || $limit > 100) {
$limit = 10;
}
// BEZPIECZNE - używamy walidacji + prepared statement dla limitu
// Kolumny sortowania są z whitelisty, więc bezpieczne
$sql = "SELECT * FROM players ORDER BY {$sort} {$order} LIMIT :limit";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
$wyniki = $stmt->fetchAll();
$sort_label = [
'level' => 'poziomu',
'coins' => 'coins',
'wins' => 'wygranych',
'games_played' => 'rozegranych gier'
];
echo "<h1>Ranking graczy (wg {$sort_label[$sort]})</h1>";
echo "<p>Top {$limit} graczy</p>";
echo '<table border="1" cellpadding="10" style="width:100%; border-collapse:collapse;">';
echo '<tr style="background:#007bff; color:white;">
<th>#</th>
<th>Username</th>
<th>Level</th>
<th>Rank</th>
<th>Coins</th>
<th>Wins</th>
<th>Games</th>
</tr>';
$pozycja = 1;
foreach ($wyniki as $gracz) {
$username = htmlspecialchars($gracz['username']);
$coins = number_format($gracz['coins']);
echo "<tr>";
echo "<td><strong>#{$pozycja}</strong></td>";
echo "<td>{$username}</td>";
echo "<td>{$gracz['level']}</td>";
echo "<td>{$gracz['rank_name']}</td>";
echo "<td>{$coins}</td>";
echo "<td>{$gracz['wins']}</td>";
echo "<td>{$gracz['games_played']}</td>";
echo "</tr>";
$pozycja++;
}
echo '</table>';
echo "<br><p>Zmień sortowanie:</p>";
echo "<a href='ranking.php?sort=level&order=desc&limit=10'>Top 10 Level</a> | ";
echo "<a href='ranking.php?sort=coins&order=desc&limit=5'>Top 5 Coins</a> | ";
echo "<a href='ranking.php?sort=wins&order=desc&limit=20'>Top 20 Wins</a>";
}
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
$pdo = null;
?>
Przykład 6: Wyszukiwanie LIKE – dane z GET
Adres URL: szukaj.php?q=Dragon
MySQLi obiektowo:
<?php
// szukaj.php
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die('Błąd połączenia');
}
$db->set_charset('utf8mb4');
// Pobieramy fraze z URL
$szukaj = trim($_GET['q'] ?? '');
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['q'])) {
// BEZPIECZNE - Prepared statement z LIKE
$stmt = $db->prepare("SELECT * FROM players WHERE username LIKE ? OR email LIKE ?");
// Dodajemy % do wyszukiwania
$szukaj_wildcard = "%{$szukaj}%";
$stmt->bind_param("ss", $szukaj_wildcard, $szukaj_wildcard);
$stmt->execute();
$wynik = $stmt->get_result();
$safe_search = htmlspecialchars($szukaj);
if ($wynik->num_rows > 0) {
echo "<h2>Wyniki wyszukiwania: \"{$safe_search}\"</h2>";
echo "<p>Znaleziono: {$wynik->num_rows} graczy</p><br>";
while ($gracz = $wynik->fetch_assoc()) {
$username = htmlspecialchars($gracz['username']);
$email = htmlspecialchars($gracz['email']);
$coins = number_format($gracz['coins']);
echo "<div style='background:#f4f4f4; padding:15px; margin:10px 0; border-radius:8px;'>";
echo "<strong>{$username}</strong> (Level: {$gracz['level']}, Rank: {$gracz['rank_name']})<br>";
echo "{$email} | {$coins} coins<br>";
echo "<a href='profil.php?id={$gracz['id']}'>Zobacz profil</a>";
echo "</div>";
}
} else {
echo "<p>Nie znaleziono graczy dla frazy: \"{$safe_search}\"</p>";
}
$stmt->close();
} else {
echo "<p>Wpisz frazę do wyszukania (np. szukaj.php?q=Dragon)</p>";
}
$db->close();
echo "<br><hr>";
echo "<p>Przykłady wyszukiwań:</p>";
echo "<a href='szukaj.php?q=Dragon'>szukaj.php?q=Dragon</a><br>";
echo "<a href='szukaj.php?q=Gamer'>szukaj.php?q=Gamer</a><br>";
echo "<a href='szukaj.php?q=@example.com'>szukaj.php?q=@example.com</a>";
?>
PDO:
<?php
// szukaj.php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
// Pobieramy fraze z URL
$szukaj = trim($_GET['q'] ?? '');
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['q'])) {
// BEZPIECZNE - Prepared statement z LIKE
$stmt = $pdo->prepare("SELECT * FROM players WHERE username LIKE :szukaj OR email LIKE :szukaj");
// Dodajemy % do wyszukiwania
$szukaj_wildcard = "%{$szukaj}%";
$stmt->execute(['szukaj' => $szukaj_wildcard]);
$wyniki = $stmt->fetchAll();
$safe_search = htmlspecialchars($szukaj);
$liczba = count($wyniki);
if ($liczba > 0) {
echo "<h2>Wyniki wyszukiwania: \"{$safe_search}\"</h2>";
echo "<p>Znaleziono: {$liczba} graczy</p><br>";
foreach ($wyniki as $gracz) {
$username = htmlspecialchars($gracz['username']);
$email = htmlspecialchars($gracz['email']);
$coins = number_format($gracz['coins']);
echo "<div style='background:#f4f4f4; padding:15px; margin:10px 0; border-radius:8px;'>";
echo "<strong>{$username}</strong> (Level: {$gracz['level']}, Rank: {$gracz['rank_name']})<br>";
echo "{$email} | {$coins} coins<br>";
echo "<a href='profil.php?id={$gracz['id']}'>Zobacz profil</a>";
echo "</div>";
}
} else {
echo "<p>Nie znaleziono graczy dla frazy: \"{$safe_search}\"</p>";
}
} else {
echo "<p>Wpisz frazę do wyszukania (np. szukaj.php?q=Dragon)</p>";
}
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
$pdo = null;
echo "<br><hr>";
echo "<p>Przykłady wyszukiwań:</p>";
echo "<a href='szukaj.php?q=Dragon'>szukaj.php?q=Dragon</a><br>";
echo "<a href='szukaj.php?q=Gamer'>szukaj.php?q=Gamer</a><br>";
echo "<a href='szukaj.php?q=@example.com'>szukaj.php?q=@example.com</a>";
?>
Przykład 7: Statystyki – funkcje agregujące
MySQLi obiektowo:
<?php
mysqli_report(MYSQLI_REPORT_OFF);
$db = @new mysqli('localhost', 'root', '', 'gaming_hub');
if ($db->connect_error) {
die('Błąd połączenia');
}
$db->set_charset('utf8mb4');
// BEZPIECZNE - Prepared statement (brak parametrów użytkownika)
$stmt = $db->prepare("SELECT
COUNT(*) as total_players,
AVG(level) as avg_level,
SUM(coins) as total_coins,
MAX(level) as max_level,
MIN(level) as min_level,
SUM(games_played) as total_games,
SUM(wins) as total_wins,
SUM(losses) as total_losses
FROM players");
$stmt->execute();
$wynik = $stmt->get_result();
$stats = $wynik->fetch_assoc();
$avg_level = round($stats['avg_level'], 1);
$total_coins = number_format($stats['total_coins']);
$total_games = number_format($stats['total_games']);
$total_wins = number_format($stats['total_wins']);
$total_losses = number_format($stats['total_losses']);
echo "<h2>Statystyki Gaming Hub</h2>";
echo "<div style='background:#f4f4f4; padding:20px; border-radius:8px;'>";
echo "<p>Liczba graczy: <strong>{$stats['total_players']}</strong></p>";
echo "<p>Średni poziom: <strong>{$avg_level}</strong></p>";
echo "<p>Łączne coins: <strong>{$total_coins}</strong></p>";
echo "<p>Najwyższy poziom: <strong>{$stats['max_level']}</strong></p>";
echo "<p>Najniższy poziom: <strong>{$stats['min_level']}</strong></p>";
echo "<p>Rozegrane gry: <strong>{$total_games}</strong></p>";
echo "<p>Wygrane: <strong>{$total_wins}</strong></p>";
echo "<p>Przegrane: <strong>{$total_losses}</strong></p>";
echo "</div>";
$stmt->close();
$db->close();
?>
PDO:
<?php
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=gaming_hub;charset=utf8mb4',
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
// BEZPIECZNE - Prepared statement (brak parametrów użytkownika)
$stmt = $pdo->prepare("SELECT
COUNT(*) as total_players,
AVG(level) as avg_level,
SUM(coins) as total_coins,
MAX(level) as max_level,
MIN(level) as min_level,
SUM(games_played) as total_games,
SUM(wins) as total_wins,
SUM(losses) as total_losses
FROM players");
$stmt->execute();
$stats = $stmt->fetch();
$avg_level = round($stats['avg_level'], 1);
$total_coins = number_format($stats['total_coins']);
$total_games = number_format($stats['total_games']);
$total_wins = number_format($stats['total_wins']);
$total_losses = number_format($stats['total_losses']);
echo "<h2>Statystyki Gaming Hub</h2>";
echo "<div style='background:#f4f4f4; padding:20px; border-radius:8px;'>";
echo "<p>Liczba graczy: <strong>{$stats['total_players']}</strong></p>";
echo "<p>Średni poziom: <strong>{$avg_level}</strong></p>";
echo "<p>ączne coins: <strong>{$total_coins}</strong></p>";
echo "<p>Najwyższy poziom: <strong>{$stats['max_level']}</strong></p>";
echo "<p>Najniższy poziom: <strong>{$stats['min_level']}</strong></p>";
echo "<p>Rozegrane gry: <strong>{$total_games}</strong></p>";
echo "<p>Wygrane: <strong>{$total_wins}</strong></p>";
echo "<p>Przegrane: <strong>{$total_losses}</strong></p>";
echo "</div>";
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
die('Błąd bazy danych');
}
$pdo = null;
?>
Whitelist vs Blacklist
Whitelist (ZALECANE):
// Lista dozwolonych wartości
$allowed_sort = ['level', 'coins', 'wins'];
if (in_array($_GET['sort'], $allowed_sort)) {
$sort = $_GET['sort']; // Bezpieczne
} else {
$sort = 'level'; // Domyślna wartość
}
Blacklist (NIE ZALECANE):
// Próba blokowania "złych" wartości - NIGDY nie złapiesz wszystkich!
if ($_GET['sort'] != 'DROP' && $_GET['sort'] != 'DELETE') {
$sort = $_GET['sort']; // NADAL NIEBEZPIECZNE!
}
Najlepsze praktyki
ZAWSZE:
- Używaj prepared statements dla WSZYSTKICH zapytań z danymi użytkownika
- Używaj PDO dla nowych projektów (uniwersalność + bezpieczeństwo)
- Używaj
htmlspecialchars()przy wyświetlaniu danych (ochrona XSS) - Waliduj dane wejściowe (whitelist dla sortowania, LIMIT, itp.)
- Ustawiaj charset na utf8mb4 (obsługa emoji i polskich znaków)
- Loguj błędy do pliku, nie pokazuj szczegółów użytkownikowi
- Używaj
number_format()dla czytelności dużych liczb - Rzutuj na właściwy typ –
(int)dla liczb,trim()dla stringów
NIGDY:
- Nie łącz zapytań SQL przez konkatenację z danymi użytkownika
- Nie pokazuj szczegółów błędów SQL użytkownikowi końcowemu
- Nie trzymaj danych dostępowych w kodzie (użyj
config.php) - Nie commituj
config.phpdo repozytorium - Nie używaj
rootbez hasła w środowisku produkcyjnym - Nie ufaj danym z
$_GETi$_POST– zawsze waliduj!