Yakuniy loyiha — blog: ro'yxatdan o'tish, maqolalar, izohlar

~90 daq · PHP · Zamonaviy PHP

Maqsad

Kursda o'rgangan hamma narsani bitta to'liq loyihada birlashtirasiz. Bu loyiha — portfoliongizdagi birinchi jiddiy PHP ishi bo'lishi mumkin.

Bu dars — topshiriq. Unda tayyor kod yo'q: talablar, tuzilma, baza sxemasi va har bir bosqich uchun yo'l-yo'riq bor. Kodni o'zingiz yozasiz. Qiyin joyda tegishli darsga qayting — havolalar berilgan.

Ikki variantdan birini tanlang:

  • A variant — sof PHP: 41-darsdagi MVC tuzilmasi, o'z routeringiz, PDO
  • B variant — Laravel: 44-dars asosida

A variant tavsiya etiladi — u hamma narsani chuqur tushunganingizni ko'rsatadi. Keyin xuddi shu loyihani B variantda qayta yozib, farqni his qilish — juda foydali mashq.


Funksional talablar

Mehmon (kirmagan foydalanuvchi)

  • Maqolalar ro'yxatini ko'radi (yangilari birinchi, sahifada 10 ta)
  • Maqolani to'liq o'qiydi va izohlarini ko'radi
  • Maqolalarni sarlavha bo'yicha qidiradi
  • Ro'yxatdan o'tadi va tizimga kiradi

Ro'yxatdan o'tgan foydalanuvchi

  • Yangi maqola yozadi (sarlavha, matn, muqova rasmi — ixtiyoriy)
  • Faqat o'zining maqolasini tahrirlaydi va o'chiradi
  • Istalgan maqolaga izoh qoldiradi
  • Faqat o'zining izohini o'chiradi
  • Profil sahifasida o'z maqolalarini ko'radi
  • Tizimdan chiqadi

Admin

  • Istalgan maqola va izohni o'chiradi

Baza sxemasi

CREATE TABLE foydalanuvchilar (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    ism         VARCHAR(100) NOT NULL,
    email       VARCHAR(255) NOT NULL UNIQUE,
    parol_hash  VARCHAR(255) NOT NULL,
    rol         ENUM('user', 'admin') NOT NULL DEFAULT 'user',
    yaratilgan  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE maqolalar (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    muallif_id  INT UNSIGNED NOT NULL,
    sarlavha    VARCHAR(200) NOT NULL,
    slug        VARCHAR(220) NOT NULL UNIQUE,
    matn        TEXT NOT NULL,
    muqova      VARCHAR(100) NULL,
    yaratilgan  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    yangilangan DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (muallif_id) REFERENCES foydalanuvchilar(id) ON DELETE CASCADE,
    INDEX (yaratilgan)
);

CREATE TABLE izohlar (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    maqola_id   INT UNSIGNED NOT NULL,
    muallif_id  INT UNSIGNED NOT NULL,
    matn        VARCHAR(1000) NOT NULL,
    yaratilgan  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (maqola_id) REFERENCES maqolalar(id) ON DELETE CASCADE,
    FOREIGN KEY (muallif_id) REFERENCES foydalanuvchilar(id) ON DELETE CASCADE
);

ON DELETE CASCADE — maqola o'chirilsa, uning izohlari ham avtomatik o'chadi.


Yo'llar (A variant)

Metod URL Amal Kim
GET / Maqolalar ro'yxati, ?q= qidiruv, ?sahifa= Hamma
GET /maqola/{slug} Maqola + izohlar Hamma
GET /royxat Ro'yxatdan o'tish formasi Mehmon
POST /royxat Ro'yxatdan o'tish Mehmon
GET /kirish Kirish formasi Mehmon
POST /kirish Kirish Mehmon
POST /chiqish Chiqish Kirgan
GET /maqolalar/yangi Yangi maqola formasi Kirgan
POST /maqolalar Saqlash Kirgan
GET /maqolalar/{id}/tahrir Tahrirlash formasi Muallif
POST /maqolalar/{id} Yangilash Muallif
POST /maqolalar/{id}/ochir O'chirish Muallif / admin
POST /maqola/{id}/izoh Izoh qo'shish Kirgan
POST /izoh/{id}/ochir Izohni o'chirish Muallif / admin
GET /profil O'z maqolalari Kirgan

Bosqichlar

1-bosqich: Poydevor (~15 daq)

  • composer init, PSR-4: "App\\": "src/", vlucas/phpdotenv o'rnating → 39-dars
  • .env va .gitignore → 39-dars
  • public/index.php front controller, Router (get/post) → 41-dars
  • Database::ulanish() → 35-dars
  • views/layout.php — header da: kirgan bo'lsa ism + "Chiqish", aks holda "Kirish" / "Ro'yxatdan o'tish"
  • Global xato ushlagich: logga yozish, foydalanuvchiga umumiy xabar → 27-dars
  • e() yordamchi funksiyasi → 20-dars

2-bosqich: Autentifikatsiya (~20 daq)

  • FoydalanuvchiRepository: emailBoyichaTop(), yarat()
  • AuthController: ro'yxatdan o'tish (validatsiya, password_hash, UNIQUE xatosini ushlash) → 38-dars
  • Kirish (password_verify, umumiy xato xabari, session_regenerate_id) → 21, 38-darslar
  • Chiqish — POST orqali, session_destroy()
  • Yordamchilar: joriyFoydalanuvchi(): ?array, kirishTalabQilinadi(): void
  • Xavfsiz sessiya sozlamalari → 43-dars

3-bosqich: CSRF (~5 daq)

  • csrfMaydon() va csrfTekshir() → 43-dars
  • Barcha POST yo'llarda csrfTekshir() — eng yaxshisi Router da, har bir POST dan oldin avtomatik

4-bosqich: Maqolalar (~25 daq)

  • MaqolaRepository: royxat(int $sahifa, ?string $qidiruv), slugBoyichaTop(), top(), yarat(), yangila(), ochir(), muallifBoyicha()
  • Ro'yxatda muallif ismi — JOIN bilan, bitta so'rovda
  • Sahifalash: LIMIT ? OFFSET ? va jami sonini COUNT(*) bilan
  • Qidiruv: WHERE sarlavha LIKE ? → 36-dars
  • Slug yasash: sarlavhadan, masalan "PHP da OOP" → php-da-oop. Band bo'lsa — oxiriga -2, -3
  • Muqova rasmi yuklash — finfo, tasodifiy nom, 2 MB → 22-dars
  • Matnni chiqarishda: nl2br(e($matn)) — yangi qatorlar saqlansin, XSS bo'lmasin

5-bosqich: Avtorizatsiya (~10 daq)

  • tahrirlashMumkinmi(array $maqola, ?array $user): bool — muallif yoki admin
  • Tahrirlash/o'chirish har bir controller metodida tekshiriladi — faqat tugmani yashirish yetarli emas → 43-dars (IDOR)
  • Ruxsat yo'q bo'lsa — 403

6-bosqich: Izohlar (~10 daq)

  • IzohRepository: maqolaBoyicha() (muallif ismi bilan), yarat(), ochir()
  • Bo'sh yoki 1000 belgidan uzun izoh — xato
  • Izoh qo'shilgach — /maqola/{slug}#izohlar ga redirect

7-bosqich: Sinov (~5 daq)

Quyidagilarni o'zingiz sinab ko'ring:

  • Izohga <script>alert(1)</script> — matn sifatida ko'rinadi
  • Qidiruvga ' OR 1=1 -- — xato ham, ortiqcha natija ham yo'q
  • Boshqaning maqolasini /maqolalar/5/tahrir orqali ochish — 403
  • DevTools da _csrf maydonini o'chirib forma yuborish — rad etiladi
  • .php faylni .jpg deb nomlab muqova sifatida yuklash — rad etiladi
  • Mavjud bo'lmagan maqola /maqola/yoq — 404
  • Maqola yaratgandan keyin F5 — dublikat yo'q
  • Bazada parollar $2y$... ko'rinishida

Qo'shimcha vazifalar

Asosiy qism tayyor bo'lgach, qiyinlik bo'yicha:

  1. ⭐ O'qish vaqti: "~5 daqiqa o'qish" — so'zlar soni / 200
  2. ⭐ Sana o'zbekcha: "2-noyabr, 2026" → 26-dars
  3. ⭐⭐ Teglar: teglar va maqola_teg jadvallari (ko'p-ko'p munosabat), /teg/php sahifasi
  4. ⭐⭐ JSON API: GET /api/maqolalar, GET /api/maqolalar/{slug} → 42-dars
  5. ⭐⭐ Markdown: maqola matnini Markdown da yozish — league/commonmark paketi (xavfsiz rejimda!)
  6. ⭐⭐⭐ Parolni tiklash: email orqali bir martalik token, 1 soatlik muddat
  7. ⭐⭐⭐ Laravel ga ko'chirish: xuddi shu loyihani B variantda yozing va kod hajmini solishtiring

Baholash mezonlari

O'zingizni tekshiring yoki tajribali dasturchidan kod review so'rang:

Mezon Savol
Xavfsizlik Yuqoridagi 7-bosqich sinovlarining hammasi o'tdimi?
Tuzilma SQL faqat Repository larda, HTML faqat view larda bormi?
Takrorlanish Bir xil kod ikki joyda yo'qmi?
Turlar declare(strict_types=1) va tur belgilari hamma joyda bormi?
Xatolar Foydalanuvchi hech qachon texnik xato matnini ko'rmaydimi?
Uslub PSR-12 bo'yicha formatlanganmi (php-cs-fixer)? → 40-dars
Git Kichik, ma'noli commitlar; .env va vendor/ Git da yo'qmi?

Tabriklaymiz! 🎉

Siz PHP kursini tugatdingiz. Endi siz:

  • PHP sintaksisi, turlari, massivlari va funksiyalarini bilasiz
  • Formalar, sessiyalar, fayllar bilan ishlaysiz
  • OOP, interface, namespace va Composer ni tushunasiz
  • PDO bilan bazaga xavfsiz ulanasiz
  • XSS, CSRF, SQL injection dan himoyalanishni bilasiz
  • MVC ilova va REST API qura olasiz
  • Laravel ga tayyorsiz

Keyingi qadamlar:

  • Saytdagi MySQL kursi — bazalarni chuqur o'rganish: JOIN, indekslar, tranzaksiyalar
  • Git kursi — loyihangizni GitHub ga joylashtiring
  • Laravel Bootcamp va o'z g'oyangiz asosida loyiha

Eng muhimi — yozishda davom eting. Har bir yangi loyiha sizni oldingisidan yaxshiroq dasturchi qiladi.