header(), redirect, HTTP status kodlar, JSON javob

~12 daq · PHP · PHP va Veb

Muammodan boshlaylik

Foydalanuvchi buyurtma formasini yubordi. Siz buyurtmani saqladingiz va "Rahmat!" sahifasini ko'rsatdingiz. Foydalanuvchi sahifani yangiladi (F5). Brauzer: "Formani qayta yuborasizmi?" — u "Ha" ni bosdi. Endi bazada ikkita bir xil buyurtma.

Yana bir holat: mobil ilova serveringizdan mahsulotlar ro'yxatini so'rayapti. Unga HTML kerak emas — unga JSON kerak.

Ikkala muammo ham HTTP javobning "sarlavhalari" (headers) orqali hal qilinadi.


HTTP javob qanday tuzilgan

Server brauzerga javob yuborganda u ikki qismdan iborat:

HTTP/1.1 200 OK                          ← status
Content-Type: text/html; charset=UTF-8   ← sarlavhalar (headers)
Set-Cookie: PHPSESSID=abc123
                                         ← bo'sh qator
<!DOCTYPE html><html>...                 ← tana (body)

echo — tanaga yozadi. header() — sarlavhalarga yozadi.

Asosiy qoida: sarlavhalar tanadan oldin yuboriladi. Birinchi echo (yoki HTML, yoki bo'sh joy) chiqqan zahoti PHP sarlavhalarni jo'natib yuboradi. Shundan keyin header() chaqirsangiz:

Warning: Cannot modify header information - headers already sent by (output started at /sayt/index.php:1)

Xabarda chiqish qayerda boshlangani yozilgan — index.php:1. Odatda bu <?php dan oldingi bo'sh qator yoki faylning BOM belgisi.


Redirect — boshqa sahifaga yo'naltirish

<?php

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

Brauzer Location sarlavhasini ko'rib, darhol ko'rsatilgan manzilga o'tadi.

[!WARNING] header('Location: ...') dan keyin har doim exit; yozing. header() skriptni to'xtatmaydi. exit siz PHP pastdagi kodni bajarishda davom etadi — masalan, faqat adminlar ko'rishi kerak bo'lgan ma'lumotni chiqarib yuboradi.


PRG — Post / Redirect / Get

Ikki marta buyurtma muammosining yechimi:

<?php
// buyurtma.php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 1. POST — ma'lumotni qayta ishlash
    $id = buyurtmaniSaqla($_POST);

    // 2. REDIRECT — natija sahifasiga yo'naltirish
    $_SESSION['flash'] = "Buyurtma #$id qabul qilindi";
    header('Location: /rahmat.php', true, 303);
    exit;
}
<?php
// rahmat.php — 3. GET orqali ochiladi
session_start();
echo htmlspecialchars($_SESSION['flash'] ?? '');
unset($_SESSION['flash']);

Endi foydalanuvchi rahmat.php da F5 bossa — faqat GET so'rov qayta yuboriladi. Buyurtma takrorlanmaydi.

Qoida: muvaffaqiyatli POST dan keyin doim redirect qiling. Xato bo'lsa esa — redirect qilmasdan, formani xatolar bilan qayta ko'rsating.


HTTP status kodlar

Status kod — javobning "natijasi" haqida qisqa xabar:

Kod Ma'nosi Qachon
200 OK Hammasi joyida (standart)
201 Created Yangi resurs yaratildi (API)
301 Moved Permanently Sahifa butunlay ko'chdi (SEO uchun)
302 / 303 Found / See Other Vaqtinchalik redirect; POST dan keyin 303
400 Bad Request So'rov noto'g'ri
401 Unauthorized Login qilinmagan
403 Forbidden Login qilgan, lekin huquqi yo'q
404 Not Found Topilmadi
422 Unprocessable Content Validatsiya xatosi (API)
500 Internal Server Error Serverda xato

O'rnatish:

<?php

http_response_code(404);
echo "Sahifa topilmadi";

Real misol — mahsulot sahifasi:

<?php

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
$mahsulot = $id ? mahsulotniTop($id) : null;

if (!$mahsulot) {
    http_response_code(404);
    require __DIR__ . '/404.php';
    exit;
}

Nima uchun bu muhim? Google 200 qaytargan "topilmadi" sahifalarini indekslaydi. API mijozlari (mobil ilova, frontend) xatoni status kod orqali aniqlaydi.


JSON javob — API uchun

<?php

$mahsulotlar = [
    ['id' => 1, 'nom' => 'Telefon', 'narx' => 3200000],
    ['id' => 2, 'nom' => 'Quloqchin', 'narx' => 249000],
];

header('Content-Type: application/json; charset=utf-8');
echo json_encode($mahsulotlar, JSON_UNESCAPED_UNICODE);

Natija:

[{"id":1,"nom":"Telefon","narx":3200000},{"id":2,"nom":"Quloqchin","narx":249000}]
  • Content-Type: application/json — mijozga "bu HTML emas, JSON" deb aytadi
  • JSON_UNESCAPED_UNICODE — o' va kirill harflari \u... ga aylanmaydi

Yordamchi funksiya:

<?php

function jsonJavob(mixed $data, int $status = 200): never
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
    exit;
}

// Ishlatish:
if (!$mahsulot) {
    jsonJavob(['xato' => 'Mahsulot topilmadi'], 404);
}
jsonJavob($mahsulot);

never qaytish turi — "bu funksiya hech qachon qaytmaydi" (doim exit). JSON ni batafsil 25-darsda ko'ramiz.


Boshqa foydali sarlavhalar

<?php

// Faylni yuklab olishga majburlash
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="hisobot.csv"');

// Keshlamaslik
header('Cache-Control: no-store');

// Xavfsizlik sarlavhalari
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');   // saytni boshqa saytning iframe ichiga joylashtirishni taqiqlash

Nima uchun shunday?

Nima uchun POST dan keyin 302 emas, 303 tavsiya qilinadi?

Tarixan 302 "xuddi shu metod bilan boshqa manzilga bor" degan ma'noda yaratilgan edi — ya'ni POST ni POST sifatida qayta yuborish kerak edi. Lekin brauzerlar uni amalda GET ga aylantira boshlagan. Bu chalkashlikni hal qilish uchun HTTP/1.1 da 303 See Other qo'shildi: "natijani GET bilan boshqa manzildan ol". Bugun ikkalasi ham ishlaydi, lekin 303 niyatni aniq ifodalaydi.


Tez-tez uchraydigan xatolar

headers already sent — header() dan oldin biror chiqish bor. Xato xabaridagi fayl va qatorni tekshiring. Faqat PHP bo'lgan fayllarda ?> yozmaslik shu sababli tavsiya etiladi.

Redirect dan keyin exit yo'q — yuqorida ko'rdik.

JSON dan oldin echo yoki Warning chiqishi — JSON buziladi va JavaScript JSON.parse xato beradi. API fayllarida display_errors ni o'chiring va xatolarni logga yozing.


Xulosa

Eslab qoling:

  • header() — har qanday chiqishdan oldin
  • header('Location: ...'); exit; — redirect, exit majburiy
  • POST → Redirect (303) → GET — ikki marta yuborishdan himoya
  • http_response_code(404) — to'g'ri status kod
  • JSON: Content-Type: application/json + json_encode(..., JSON_UNESCAPED_UNICODE)

Keyingi dars

24-dars: Fayllar — file_get_contents, file_put_contents, fopen