Yakuniy loyiha — blog: ro'yxatdan o'tish, maqolalar, izohlar
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/phpdotenvo'rnating → 39-dars -
.envva.gitignore→ 39-dars -
public/index.phpfront 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,UNIQUExatosini 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()vacsrfTekshir()→ 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 —
JOINbilan, bitta so'rovda - Sahifalash:
LIMIT ? OFFSET ?va jami soniniCOUNT(*)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}#izohlarga 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/tahrirorqali ochish —403 - DevTools da
_csrfmaydonini o'chirib forma yuborish — rad etiladi -
.phpfaylni.jpgdeb 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:
- ⭐ O'qish vaqti: "~5 daqiqa o'qish" — so'zlar soni / 200
- ⭐ Sana o'zbekcha: "2-noyabr, 2026" → 26-dars
- ⭐⭐ Teglar:
teglarvamaqola_tegjadvallari (ko'p-ko'p munosabat),/teg/phpsahifasi - ⭐⭐ JSON API:
GET /api/maqolalar,GET /api/maqolalar/{slug}→ 42-dars - ⭐⭐ Markdown: maqola matnini Markdown da yozish —
league/commonmarkpaketi (xavfsiz rejimda!) - ⭐⭐⭐ Parolni tiklash: email orqali bir martalik token, 1 soatlik muddat
- ⭐⭐⭐ 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.