header(), redirect, HTTP status kodlar, JSON javob
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 doimexit;yozing.header()skriptni to'xtatmaydi.exitsiz 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 aytadiJSON_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 oldinheader('Location: ...'); exit;— redirect,exitmajburiy- 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