Sessiya va cookie — $_SESSION, setcookie, oddiy login

~20 daq · PHP · PHP va Veb

Muammodan boshlaylik

Foydalanuvchi login sahifasida parolni to'g'ri kiritdi. Siz "Xush kelibsiz!" deb ko'rsatdingiz. U "Profil" havolasini bosdi — va server uni tanimaydi. Yana login so'raydi.

Sababi: HTTP xotirasiz (stateless) protokol. Har bir so'rov — butunlay yangi, mustaqil. Server oldingi so'rovni eslamaydi. Brauzer index.php ni so'radi, javob oldi — ish tugadi. Keyingi so'rov — begona odamdan kelgandek.

Foydalanuvchini sahifalar orasida "eslab qolish" uchun ikki vosita bor: cookie va sessiya.


Cookie — brauzerdagi kichik yozuv

Cookie — server brauzerga "buni saqlab qo'y va har safar menga qaytarib yubor" deb beradigan kichik matn.

<?php

// 30 kun saqlanadigan cookie
setcookie('til', 'uz', [
    'expires'  => time() + 60 * 60 * 24 * 30,
    'path'     => '/',
    'httponly' => true,
    'samesite' => 'Lax',
]);

Keyingi so'rovlarda brauzer uni avtomatik yuboradi:

<?php

$til = $_COOKIE['til'] ?? 'uz';

O'chirish — muddatini o'tmishga qo'yish:

<?php

setcookie('til', '', ['expires' => time() - 3600, 'path' => '/']);

[!WARNING] setcookie() HTTP sarlavhasini yuboradi, shuning uchun u har qanday chiqishdan oldin chaqirilishi kerak — echo dan, HTML dan, hatto <?php dan oldingi bo'sh qatordan ham oldin. Aks holda: Warning: Cannot modify header information - headers already sent.

Cookie ning muammosi: u foydalanuvchining brauzerida turadi va uni foydalanuvchi o'zgartira oladi. $_COOKIE['admin'] = 'ha' deb saqlasangiz — har kim DevTools da o'zini admin qilib qo'yadi. Cookie ga faqat ahamiyatsiz narsalarni (til, mavzu) saqlang.


Sessiya — serverdagi xotira

Sessiya ma'lumotni serverda saqlaydi. Brauzerga faqat tasodifiy ID (kalit) beriladi.

Hayotiy o'xshatma: garderob. Paltongizni topshirasiz (ma'lumot serverda qoladi), qo'lingizga raqamli bilet berishadi (sessiya ID cookie da). Bilet bo'yicha paltongizni qaytarishadi. Biletda paltoning o'zi yo'q, va boshqa raqamni taxmin qilish deyarli imkonsiz.

<?php

session_start();   // har bir sahifaning boshida, har qanday chiqishdan oldin

$_SESSION['foydalanuvchi_id'] = 42;
$_SESSION['ism'] = 'Shahnoza';

Boshqa sahifada:

<?php

session_start();

echo $_SESSION['ism'] ?? 'Mehmon';   // Shahnoza

session_start() qiladigan ish:

  1. Brauzerdan PHPSESSID cookie kelganmi? — keldi bo'lsa, shu ID dagi ma'lumotni yuklaydi
  2. Kelmagan bo'lsa — yangi tasodifiy ID yaratadi va cookie sifatida yuboradi
  3. Sahifa tugaganda $_SESSION dagi o'zgarishlarni serverga saqlaydi

Cookie va sessiya farqi

Cookie Sessiya
Ma'lumot qayerda Brauzerda Serverda
Foydalanuvchi o'zgartira oladimi Ha Yo'q (faqat ID ni ko'radi)
Hajm ~4 KB Cheklanmagan (amalda)
Muddat Siz belgilaysiz Brauzer yopilguncha (odatda)
Nima uchun Til, mavzu, "meni eslab qol" Login, savat, xabarlar

Oddiy login tizimi

Hozircha parolni kod ichida saqlaymiz — 38-darsda bazaga va xeshlashga o'tamiz.

kirish.php:

<?php
declare(strict_types=1);
session_start();

// Vaqtinchalik "baza"
$foydalanuvchilar = [
    'ali@mail.uz' => ['id' => 1, 'ism' => 'Ali', 'parol_hash' => password_hash('maxfiy123', PASSWORD_DEFAULT)],
];

$xato = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email = trim($_POST['email'] ?? '');
    $parol = $_POST['parol'] ?? '';

    $user = $foydalanuvchilar[$email] ?? null;

    if ($user && password_verify($parol, $user['parol_hash'])) {
        session_regenerate_id(true);       // muhim! pastda tushuntirilgan
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['ism'] = $user['ism'];

        header('Location: profil.php');
        exit;
    }

    $xato = "Email yoki parol noto'g'ri";
}
?>
<form method="post">
    <?php if ($xato): ?><p style="color:red"><?= htmlspecialchars($xato) ?></p><?php endif; ?>
    <input name="email" type="email" placeholder="Email">
    <input name="parol" type="password" placeholder="Parol">
    <button>Kirish</button>
</form>

profil.php — faqat kirganlar uchun:

<?php
declare(strict_types=1);
session_start();

if (!isset($_SESSION['user_id'])) {
    header('Location: kirish.php');
    exit;
}
?>
<h1>Salom, <?= htmlspecialchars($_SESSION['ism']) ?>!</h1>
<a href="chiqish.php">Chiqish</a>

chiqish.php:

<?php
session_start();

$_SESSION = [];          // ma'lumotlarni tozalash
session_destroy();       // serverdagi sessiyani o'chirish

header('Location: kirish.php');
exit;

Nima uchun session_regenerate_id(true)?

Bu session fixation hujumidan himoya. Hujumchi o'ziga ma'lum bo'lgan sessiya ID ni qurbonning brauzeriga joylashtiradi (masalan, havola orqali). Qurbon shu ID bilan login qiladi. Endi hujumchi ham shu ID ni biladi — va qurbonning akkauntiga kiradi.

session_regenerate_id(true) login paytida ID ni yangisiga almashtiradi. Hujumchining bilgan eski ID si yaroqsiz bo'ladi.

Qoida: foydalanuvchi huquqi o'zgarganda (login, logout, rolni oshirish) — ID ni yangilang.


Flash xabarlar

"Profil saqlandi" kabi xabarni redirect dan keyin bir marta ko'rsatish:

<?php

// Saqlagandan keyin:
$_SESSION['flash'] = "Profil muvaffaqiyatli saqlandi";
header('Location: profil.php');
exit;
<?php

// profil.php da:
if (isset($_SESSION['flash'])) {
    echo '<div class="xabar">' . htmlspecialchars($_SESSION['flash']) . '</div>';
    unset($_SESSION['flash']);   // ko'rsatdik — o'chiramiz
}

Xavfsiz sessiya sozlamalari

session_start() dan oldin yoki php.ini da:

<?php

session_set_cookie_params([
    'httponly' => true,    // JavaScript document.cookie orqali o'qiy olmaydi — XSS da o'g'irlanmaydi
    'secure'   => true,    // faqat HTTPS orqali yuboriladi
    'samesite' => 'Lax',   // boshqa saytlardan kelgan so'rovlarda yuborilmaydi — CSRF dan qisman himoya
]);
session_start();

[!INFO] secure => true mahalliy http://localhost da cookie yuborilmasligiga olib keladi. Ishlab chiqishda false, serverda (HTTPS) true qiling.


Nima uchun shunday?

Nima uchun HTTP xotirasiz qilib yaratilgan? Eslab qolsa oson bo'lmasmidi?

1990-yillarda veb hujjatlarni ulashish uchun yaratilgan: so'radingiz — hujjatni oldingiz. Xotirasizlik serverni juda oddiy va kengaytiriladigan qiladi: har qanday so'rovni har qanday server bajara oladi, chunki hech kim oldingi holatni saqlab turmaydi. Internet do'konlar paydo bo'lganda "savat" kerak bo'ldi — va 1994-yilda Netscape cookie ni o'ylab topdi. Sessiyalar esa cookie ustiga qurilgan xavfsizroq qavat.


Tez-tez uchraydigan xatolar

session_start() ni unutish — $_SESSION bo'sh massivdek ishlaydi, hech narsa saqlanmaydi.

session_start() dan oldin chiqish:

Warning: session_start(): Session cannot be started after headers have already been sent

Fayl boshidagi bo'sh qator yoki BOM belgisi ham "chiqish" hisoblanadi.

header('Location: ...') dan keyin exit ni unutish — redirect sarlavhasi yuboriladi, lekin PHP pastdagi kodni baribir bajaradi. Himoyalangan sahifaning mazmuni javobga tushib qolishi mumkin.


Xulosa

Eslab qoling:

  • HTTP xotirasiz — har bir so'rov mustaqil
  • Cookie — brauzerda, foydalanuvchi o'zgartira oladi; muhim narsa saqlamang
  • Sessiya — serverda; brauzerda faqat ID
  • session_start() — har bir sahifa boshida, chiqishdan oldin
  • Login da session_regenerate_id(true), logout da session_destroy()
  • header('Location: ...') dan keyin doim exit
  • httponly, secure, samesite — xavfsiz cookie sozlamalari

Keyingi dars

22-dars: Fayl yuklash — $_FILES, move_uploaded_file, xavfsizlik