Python CGI dasturlashni noldan o'rganing. Ushbu qo'llanma sozlash, shakl boshqaruvi, holat, xavfsizlik va zamonaviy veb-dagi o'rnini qamrab oladi.
Python CGI Dasturlash: Veb Interfeyslarni Yaratish Bo'yicha To'liq Qo'llanma
Django, Flask va FastAPI kabi murakkab freymvorklar hukmron bo'lgan zamonaviy veb-ishlab chiqish dunyosida CGI (Common Gateway Interface) atamasi o'tmishdan kelgan aks sado kabi eshitilishi mumkin. Biroq, CGI-ni e'tiborsiz qoldirish, dastlabki dinamik veb-sahifalar asosini tashkil etgan, shuningdek, bugungi kunda ham qimmatli saboqlar va amaliy qo'llash imkoniyatlarini taqdim etadigan fundamental texnologiyani e'tiborsiz qoldirish demakdir. CGI-ni tushunish avtomobil haydashni o'rganishdan oldin dvigatel qanday ishlashini tushunishga o'xshaydi; u barcha veb-ilovalar asosini tashkil etuvchi mijoz-server o'zaro aloqasi haqida chuqur, fundamental bilim beradi.
Ushbu to'liq qo'llanma Python CGI dasturlashini tushunishga yordam beradi. Biz uni dastlabki tamoyillardan boshlab o'rganamiz, sizga faqat Pythonning standart kutubxonalaridan foydalanib dinamik, interaktiv veb-interfeyslarni qanday yaratishni ko'rsatamiz. Siz veb-asoslarini o'rganayotgan talaba bo'lasizmi, eskirgan tizimlar bilan ishlaydigan dasturchi bo'lasizmi yoki cheklangan muhitda ishlaydigan kishi bo'lasizmi, ushbu qo'llanma sizni ushbu kuchli va sodda texnologiyadan foydalanish uchun ko'nikmalar bilan jihozlaydi.
CGI nima va nega u hali ham muhim?
Common Gateway Interface (CGI) – bu veb-serverning tashqi dasturlar, ko'pincha CGI skriptlari deb ataladigan dasturlar bilan qanday o'zaro ishlashini belgilaydigan standart protokol. Mijoz (masalan, veb-brauzer) CGI skripti bilan bog'liq bo'lgan ma'lum bir URLni so'raganida, veb-server shunchaki statik faylni taqdim etmaydi. Buning o'rniga, u skriptni bajaradi va skriptning chiqishini mijozga qaytaradi. Bu foydalanuvchi kiritmasi, ma'lumotlar bazasi so'rovlari yoki skriptdagi boshqa har qanday mantiq asosida dinamik kontent yaratish imkonini beradi.
Buni suhbat deb tasavvur qiling:
- Mijozdan Serverga: "Men `/cgi-bin/process-form.py` manzilidagi resursni ko'rmoqchiman va mana, men to'ldirgan shakldagi ba'zi ma'lumotlar."
- Serverdan CGI Skriptiga: "Sizga so'rov keldi. Mana mijozning ma'lumotlari va so'rov haqidagi ma'lumotlar (masalan, uning IP manzili, brauzeri va hokazo). Iltimos, ishga tushiring va menga qaytariladigan javobni bering."
- CGI Skriptidan Serverga: "Men ma'lumotlarni qayta ishladim. Mana HTTP sarlavhalari va qaytariladigan HTML kontenti."
- Serverdan Mijozga: "Mana siz so'ragan dinamik sahifa."
Zamonaviy freymvorklar bu xom o'zaro aloqani abstraksiyalashtirgan bo'lsa-da, asosiy tamoyillar o'zgarmasdir. Xo'sh, yuqori darajadagi freymvorklar davrida nega CGI-ni o'rganish kerak?
- Fundamental Tushuncha: Bu sizni HTTP so'rovlari va javoblarining asosiy mexanikalarini, jumladan sarlavhalar, muhit o'zgaruvchilari va ma'lumotlar oqimlarini hech qanday "sehr"siz o'rganishga majbur qiladi. Bu bilim har qanday veb-ilovasini disk raskadrovka qilish va unumdorligini sozlash uchun bebaho hisoblanadi.
- Soddalik: Bitta, izolyatsiya qilingan vazifa uchun kichik CGI skriptini yozish, marshrutlash, modellar va kontrollyerlarga ega butun freymvork loyihasini sozlashdan sezilarli darajada tez va sodda bo'lishi mumkin.
- Tilga bog'liq emas: CGI kutubxona emas, balki protokoldir. Siz CGI skriptlarini Python, Perl, C++, Rust yoki standart kiritishdan o'qiy oladigan va standart chiqishga yozish imkoniga ega bo'lgan har qanday tilda yozishingiz mumkin.
- Eskirgan Tizimlar va Cheklangan Muhitlar: Ko'pgina eski veb-ilovalar va ba'zi umumiy hosting muhitlari CGI-ga tayanadi yoki faqat uni qo'llab-quvvatlaydi. U bilan ishlashni bilish muhim mahorat bo'lishi mumkin. Bu oddiy veb-serverlarga ega o'rnatilgan tizimlarda ham keng tarqalgan.
CGI Muhitini Sozlash
Python CGI skriptini ishga tushirishdan oldin, sizga uni bajarish uchun sozlagan veb-server kerak bo'ladi. Bu yangi boshlovchilar uchun eng keng tarqalgan to'siqdir. Ishlab chiqish va o'rganish uchun siz Apache kabi mashhur serverlardan yoki hatto Pythonning o'rnatilgan serveridan foydalanishingiz mumkin.
Oldindan shartlar: Veb-server
Asosiy narsa shundaki, veb-serveringizga ma'lum bir katalogdagi (odatda `cgi-bin` deb nomlanadigan) fayllar matn sifatida emas, balki bajarilishi va ularning chiqishi brauzerga yuborilishi kerakligini aytishdir. Maxsus sozlash bosqichlari farq qilsa-da, umumiy tamoyillar universaldir.
- Apache: Odatda `mod_cgi` ni yoqishingiz va URL yo'lini fayl tizimi katalogiga bog'lash uchun konfiguratsiya faylingizda `ScriptAlias` direktivasidan foydalanishingiz kerak. Shuningdek, ijroga ruxsat berish uchun ushbu katalog uchun `Options +ExecCGI` direktivasi kerak bo'ladi.
- Nginx: Nginxda Apache kabi to'g'ridan-to'g'ri CGI moduli yo'q. U odatda CGI skriptlarini bajarish uchun FCGIWrap kabi ko'prikdan foydalanadi.
- Pythonning `http.server`i: Oddiy mahalliy sinov uchun siz Pythonning o'rnatilgan veb-serveridan foydalanishingiz mumkin, u CGI-ni to'g'ridan-to'g'ri qo'llab-quvvatlaydi. Uni buyruq satrida shunday ishga tushirishingiz mumkin: `python3 -m http.server --cgi 8000`. Bu 8000-portda serverni ishga tushiradi va `cgi-bin/` kichik katalogidagi har qanday skriptlarni ijro etiladigan deb hisoblaydi.
Sizning birinchi "Hello, World!" Python CGI'da
CGI skriptining chiqish formati juda o'ziga xosdir. U avval barcha kerakli HTTP sarlavhalarini, so'ngra bitta bo'sh qatorni va keyin kontent tanasini (masalan, HTML) chop etishi kerak.
Keling, birinchi skriptimizni yaratamiz. Quyidagi kodni `hello.py` nomi bilan `cgi-bin` katalogingizga saqlang.
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# 1. HTTP Sarlavhasi
# Eng muhim sarlavha Content-Type bo'lib, u brauzerga qanday ma'lumot kutishini aytadi.
print("Content-Type: text/html;charset=utf-8")
# 2. Bo'sh Qator
# Bitta bo'sh qator juda muhim. U sarlavhalarni kontent tanasidan ajratadi.
print()
# 3. Kontent Tanasi
# Bu brauzerda ko'rsatiladigan haqiqiy HTML kontentidir.
print("<h1>Salom, Dunyo!</h1>")
print("<p>Bu mening birinchi Python CGI skriptim.</p>")
print("<p>U global veb-serverda ishlamoqda, har kimga ochiq!</p>")
Keling, buni tahlil qilamiz:
#!/usr/bin/env python3
: Bu "shebang" qatori. Unix-ga o'xshash tizimlarda (Linux, macOS) u operatsion tizimga bu faylni Python 3 interpretatori yordamida bajarishni buyuradi.print("Content-Type: text/html;charset=utf-8")
: Bu HTTP sarlavhasi. U brauzerga quyidagi kontent HTML ekanligini va UTF-8 da kodlanganligini ma'lum qiladi, bu xalqaro belgilar uchun muhimdir.print()
: Bu sarlavhalarni tanadan ajratuvchi majburiy bo'sh qatorni chop etadi. Buni unutish juda keng tarqalgan xato.- Oxirgi `print` iboralari foydalanuvchi ko'radigan HTMLni ishlab chiqaradi.
Nihoyat, skriptni bajariladigan qilishingiz kerak. Linux yoki macOSda siz terminalingizda ushbu buyruqni ishga tushirasiz: `chmod +x cgi-bin/hello.py`. Endi, brauzeringizda `http://your-server-address/cgi-bin/hello.py` manziliga o'tganingizda, "Salom, Dunyo!" xabaringizni ko'rishingiz kerak.
CGI yadrosi: Muhit o'zgaruvchilari
Veb-server so'rov haqidagi ma'lumotni skriptimizga qanday yetkazadi? U muhit o'zgaruvchilaridan foydalanadi. Bular server tomonidan skriptning bajarilish muhitida o'rnatiladigan o'zgaruvchilar bo'lib, ular kelayotgan so'rov va serverning o'zi haqida ko'plab ma'lumotlarni taqdim etadi. Bu Common Gateway Interface'dagi "Shlyuz"dir.
Asosiy CGI muhit o'zgaruvchilari
Pythonning `os` moduli bizga ushbu o'zgaruvchilarga kirish imkonini beradi. Mana ulardan eng muhimlari:
REQUEST_METHOD
: So'rov uchun ishlatilgan HTTP usuli (masalan, 'GET', 'POST').QUERY_STRING
: URLdagi '?' dan keyin yuborilgan ma'lumotlarni o'z ichiga oladi. Ma'lumotlar GET so'rovida shunday uzatiladi.CONTENT_LENGTH
: So'rov tanasida yuborilgan ma'lumotlarning uzunligi, POST so'rovlari uchun ishlatiladi.CONTENT_TYPE
: So'rov tanasidagi ma'lumotlarning MIME turi (masalan, 'application/x-www-form-urlencoded').REMOTE_ADDR
: So'rov yuborayotgan mijozning IP manzili.HTTP_USER_AGENT
: Mijoz brauzerining user-agent qatori (masalan, 'Mozilla/5.0...').SERVER_NAME
: Serverning xost nomi yoki IP manzili.SERVER_PROTOCOL
: Ishlatilgan protokol, masalan, 'HTTP/1.1'.SCRIPT_NAME
: Hozirda bajarilayotgan skriptga yo'l.
Amaliy misol: Diagnostika skripti
Keling, barcha mavjud muhit o'zgaruvchilarini ko'rsatadigan skript yaratamiz. Bu disk raskadrovka qilish uchun juda foydali vositadir. Buni `diagnostics.py` nomi bilan `cgi-bin` katalogingizga saqlang va uni bajariladigan qiling.
#!/usr/bin/env python3
import os
print("Content-Type: text/html\n")
print("<h1>CGI Muhit O'zgaruvchilari</h1>")
print("<p>Ushbu skript veb-server tomonidan uzatilgan barcha muhit o'zgaruvchilarini ko'rsatadi.</p>")
print("<table border='1' style='border-collapse: collapse; width: 80%;'>")
print("<tr><th>O'zgaruvchi</th><th>Qiymat</th></tr>")
# Barcha muhit o'zgaruvchilari bo'yicha takrorlash va ularni jadvalda chop etish
for key, value in sorted(os.environ.items()):
print(f"<tr><td>{key}</td><td>{value}</td></tr>")
print("</table>")
Ushbu skriptni ishga tushirganingizda, server skriptingizga uzatgan har bir ma'lumotni ro'yxatlaydigan batafsil jadvalni ko'rasiz. URLga so'rov qatorini qo'shib ko'ring (masalan, `.../diagnostics.py?name=test&value=123`) va `QUERY_STRING` o'zgaruvchisi qanday o'zgarishini kuzating.
Foydalanuvchi Kiritmasini Boshqarish: Shakllar va Ma'lumotlar
CGI ning asosiy maqsadi foydalanuvchi kiritmasini, odatda HTML shakllaridan kelgan ma'lumotlarni qayta ishlashdir. Pythonning standart kutubxonasi buning uchun mustahkam vositalarni taqdim etadi. Keling, ikkita asosiy HTTP usulini: GET va POSTni qanday boshqarishni o'rganamiz.
Avvalo, oddiy HTML shaklini yaratamiz. Ushbu faylni `feedback_form.html` nomi bilan asosiy veb-katalogingizga saqlang (cgi-bin katalogiga emas).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Global Feedback Form</title>
</head>
<body>
<h1>O'z Fikringizni Bildiring</h1>
<p>Ushbu shakl GET va POST usullarini namoyish etadi.</p>
<h2>GET Usuli Misoli</h2>
<form action="/cgi-bin/form_handler.py" method="GET">
<label for="get_name">Ismingiz:</label>
<input type="text" id="get_name" name="username">
<br/><br/>
<label for="get_topic">Mavzu:</label>
<input type="text" id="get_topic" name="topic">
<br/><br/>
<input type="submit" value="GET bilan yuborish">
</form>
<hr>
<h2>POST Usuli Misoli (Ko'proq Xususiyatlar)</h2>
<form action="/cgi-bin/form_handler.py" method="POST">
<label for="post_name">Ismingiz:</label>
<input type="text" id="post_name" name="username">
<br/><br/>
<label for="email">E-pochtangiz:</label>
<input type="email" id="email" name="email">
<br/><br/>
<p>Bizning xizmatimizdan mamnunmisiz?</p>
<input type="radio" id="happy_yes" name="satisfaction" value="yes">
<label for="happy_yes">Ha</label><br>
<input type="radio" id="happy_no" name="satisfaction" value="no">
<label for="happy_no">Yo'q</label><br>
<input type="radio" id="happy_neutral" name="satisfaction" value="neutral">
<label for="happy_neutral">Neytral</label>
<br/><br/>
<p>Qaysi mahsulotlarga qiziqasiz?</p>
<input type="checkbox" id="prod_a" name="products" value="Product A">
<label for="prod_a">Mahsulot A</label><br>
<input type="checkbox" id="prod_b" name="products" value="Product B">
<label for="prod_b">Mahsulot B</label><br>
<input type="checkbox" id="prod_c" name="products" value="Product C">
<label for="prod_c">Mahsulot C</label>
<br/><br/>
<label for="comments">Izohlar:</label><br>
<textarea id="comments" name="comments" rows="4" cols="50"></textarea>
<br/><br/>
<input type="submit" value="POST bilan yuborish">
</form>
</body>
</html>
Ushbu shakl ma'lumotlarini `form_handler.py` nomli skriptga yuboradi. Endi biz bu skriptni yozishimiz kerak. Garchi siz GET so'rovlari uchun `QUERY_STRING`ni qo'lda tahlil qilishingiz va POST so'rovlari uchun standart kiritishdan o'qishingiz mumkin bo'lsa-da, bu xatolarga moyil va murakkab. Buning o'rniga, biz Pythonning aynan shu maqsad uchun mo'ljallangan o'rnatilgan `cgi` modulidan foydalanishimiz kerak.
`cgi.FieldStorage` klassi bu yerda qahramondir. U kelayotgan so'rovni tahlil qiladi va shakl ma'lumotlariga lug'atga o'xshash interfeysni taqdim etadi, bu ma'lumotlar GET yoki POST orqali yuborilganidan qat'i nazar.
Mana `form_handler.py` uchun kod. Uni `cgi-bin` katalogingizga saqlang va bajariladigan qiling.
#!/usr/bin/env python3
import cgi
import html
# FieldStorage instansiyasini yaratish
# Ushbu bitta obyekt GET va POST so'rovlarini shaffof tarzda boshqaradi
form = cgi.FieldStorage()
# Javobni chop etishni boshlash
print("Content-Type: text/html\n")
print("<h1>Shakl Yuborish Qabul Qilindi</h1>")
print("<p>Fikringiz uchun rahmat. Mana biz olgan ma'lumotlar:</p>")
# Shakl ma'lumotlari yuborilganligini tekshirish
if not form:
print("<p><em>Hech qanday shakl ma'lumotlari yuborilmadi.</em></p>")
else:
print("<table border='1' style='border-collapse: collapse;'>")
print("<tr><th>Maydon Nomi</th><th>Qiymat(lar)</th></tr>")
# Shakl ma'lumotlaridagi barcha kalitlar bo'yicha takrorlash
for key in form.keys():
# MUHIM: XSS hujumlarining oldini olish uchun foydalanuvchi kiritmasini ko'rsatishdan oldin tozalang.
# html.escape() <, >, & kabi belgilarni HTML entitylariga aylantiradi.
sanitized_key = html.escape(key)
# .getlist() usuli bir nechta qiymatga ega bo'lishi mumkin bo'lgan maydonlarni boshqarish uchun ishlatiladi,
# masalan, checkboxlar. U har doim ro'yxatni qaytaradi.
values = form.getlist(key)
# Ro'yxatdagi har bir qiymatni tozalash
sanitized_values = [html.escape(v) for v in values]
# Ko'rsatish uchun qiymatlar ro'yxatini vergul bilan ajratilgan qatorga birlashtirish
display_value = ", ".join(sanitized_values)
print(f"<tr><td><strong>{sanitized_key}</strong></td><td>{display_value}</td></tr>")
print("</table>")
# Bitta qiymatga to'g'ridan-to'g'ri kirish misoli
# Faqat bitta qiymatga ega bo'lishini kutadigan maydonlar uchun form.getvalue('key') dan foydalaning.
# Agar kalit mavjud bo'lmasa, None ni qaytaradi.
username = form.getvalue("username")
if username:
print(f"<h2>Xush kelibsiz, {html.escape(username)}!</h2>")
Ushbu skriptdan asosiy xulosalar:
- `import cgi` va `import html`: Biz kerakli modullarni import qilamiz. `cgi` shaklni tahlil qilish uchun, `html` xavfsizlik uchun.
- `form = cgi.FieldStorage()`: Ushbu bitta qator barcha murakkab ishlarni bajaradi. U muhit o'zgaruvchilarini (`REQUEST_METHOD`, `CONTENT_LENGTH` va boshqalar) tekshiradi, tegishli kiritish oqimini o'qiydi va ma'lumotlarni oson ishlatiladigan obyektga tahlil qiladi.
- Avvalo Xavfsizlik (`html.escape`): Biz foydalanuvchi tomonidan yuborilgan ma'lumotlarni hech qachon HTML sahifamizga to'g'ridan-to'g'ri chop etmaymiz. Bunday qilish saytlararo skriptlash (XSS) zaifligini keltirib chiqaradi. `html.escape()` funksiyasi hujumchi yuborishi mumkin bo'lgan har qanday zararli HTML yoki JavaScriptni zararsizlantirish uchun ishlatiladi.
- `form.keys()`: Biz yuborilgan barcha maydon nomlari bo'yicha takrorlashimiz mumkin.
- `form.getlist(key)`: Bu qiymatlarni olishning eng xavfsiz usuli. Shakl bir xil nom uchun bir nechta qiymatni yuborishi mumkin (masalan, checkboxlar), `getlist()` har doim ro'yxatni qaytaradi. Agar maydon faqat bitta qiymatga ega bo'lsa, u bitta elementli ro'yxat bo'ladi.
- `form.getvalue(key)`: Bu faqat bitta qiymat kutganingizda qulay qisqa yo'ldir. U yagona qiymatni to'g'ridan-to'g'ri qaytaradi, yoki agar bir nechta qiymat bo'lsa, ularning ro'yxatini qaytaradi. Agar kalit topilmasa, `None` ni qaytaradi.
Endi brauzeringizda `feedback_form.html` ni oching, ikkala shaklni ham to'ldiring va skript har safar ma'lumotlarni qanday qilib boshqacha, ammo samarali boshqarishini ko'ring.
Kengaytirilgan CGI Texnikalari va Eng Yaxshi Amaliyotlar
Holatni boshqarish: Cookie'lar
HTTP holatsiz protokoldir. Har bir so'rov mustaqil bo'lib, serverda bir xil mijozdan kelgan oldingi so'rovlar haqida xotira yo'q. Doimiy tajriba (masalan, savat yoki tizimga kirgan sessiya) yaratish uchun biz holatni boshqarishimiz kerak. Buning eng keng tarqalgan usuli cookie'lar bilan amalga oshiriladi.
Cookie – bu server tomonidan mijozning brauzeriga yuboriladigan kichik ma'lumot qismidir. Keyin brauzer bu cookie'ni bir xil serverga qilingan har bir keyingi so'rov bilan qaytaradi. CGI skripti `Set-Cookie` sarlavhasini chop etish orqali cookie o'rnatishi va `HTTP_COOKIE` muhit o'zgaruvchisidan kelayotgan cookie'larni o'qishi mumkin.
Keling, oddiy tashrif buyuruvchilar hisoblagichi skriptini yaratamiz. Buni `cookie_counter.py` nomi bilan saqlang.
#!/usr/bin/env python3
import os
import http.cookies
# Mavjud cookie'larni muhit o'zgaruvchisidan yuklash
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
visit_count = 0
# 'visit_count' cookie'mizning qiymatini olishga urinish
if 'visit_count' in cookie:
try:
# Cookie qiymati satr bo'lgani uchun uni butun songa aylantirishimiz kerak
visit_count = int(cookie['visit_count'].value)
except ValueError:
# Cookie qiymati to'g'ri raqam bo'lmagan holatlarni boshqarish
visit_count = 0
# Tashriflar sonini oshirish
visit_count += 1
# Javob uchun cookie o'rnatish. Bu 'Set-Cookie' sarlavhasi sifatida yuboriladi.
# Biz 'visit_count' uchun yangi qiymatni o'rnatmoqdamiz.
cookie['visit_count'] = visit_count
# Shuningdek, muddati tugash sanasi, yo'l va boshqalar kabi cookie atributlarini ham o'rnatishingiz mumkin.
# cookie['visit_count']['expires'] = '...'
# cookie['visit_count']['path'] = '/'
# Avval Set-Cookie sarlavhasini chop etish
print(cookie.output())
# Keyin oddiy Content-Type sarlavhasini chop etish
print("Content-Type: text/html\n")
# Va nihoyat HTML tanasi
print("<h1>Cookie asosidagi Tashrif Buyuruvchilar Hisoblagichi</h1>")
print(f"<p>Xush kelibsiz! Bu sizning <strong>{visit_count}</strong> -tashrifingiz.</p>")
print("<p>Sahifani yangilang, hisob oshganini ko'rish uchun.</p>")
print("<p><em>(Bu ishlatish uchun brauzeringizda cookie'lar yoqilgan bo'lishi kerak.)</em></p>")
Bu yerda Pythonning `http.cookies` moduli `HTTP_COOKIE` qatorini tahlil qilishni va `Set-Cookie` sarlavhasini yaratishni soddalashtiradi. Ushbu sahifaga har tashrif buyurganingizda, skript eski hisobni o'qiydi, uni oshiradi va yangi qiymatni brauzeringizda saqlash uchun qaytaradi.
CGI Skriptlarini Disk Raskadrovka Qilish: `cgitb` Moduli
CGI skripti ishlamay qolganda, server ko'pincha umumiy "500 Internal Server Error" xabarini qaytaradi, bu disk raskadrovka qilish uchun foydasizdir. Pythonning `cgitb` (CGI Traceback) moduli qutqaruvchidir. Uni skriptingizning boshida yoqish orqali, har qanday ishlanmagan istisnolar to'g'ridan-to'g'ri brauzerda batafsil, formatlangan hisobotni yaratadi.
Uni ishlatish uchun skriptingizning boshiga ushbu ikki qatorni qo'shing:
import cgitb
cgitb.enable()
Ogohlantirish: `cgitb` ishlab chiqish uchun bebaho bo'lsa-da, uni ishlab chiqarish muhitida o'chirib qo'yish yoki faylga yozish uchun sozlash kerak. Batafsil xatolik xabarlarini ommaga oshkor qilish serveringiz konfiguratsiyasi va kodi haqida sezgir ma'lumotlarni oshkor qilishi mumkin.
CGI bilan fayl yuklash
`cgi.FieldStorage` obyekti fayl yuklashni ham muammosiz boshqaradi. HTML shakli `method="POST"` va, eng muhimi, `enctype="multipart/form-data"` bilan konfiguratsiya qilingan bo'lishi kerak.
Keling, fayl yuklash shaklini, `upload.html` ni yaratamiz:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Fayl yuklash</title>
</head>
<body>
<h1>Fayl yuklash</h1>
<form action="/cgi-bin/upload_handler.py" method="POST" enctype="multipart/form-data">
<label for="userfile">Yuklash uchun fayl tanlang:</label>
<input type="file" id="userfile" name="userfile">
<br/><br/>
<input type="submit" value="Faylni yuklash">
</form>
</body>
</html>
Va endi ishlov beruvchi, `upload_handler.py`. Eslatma: Ushbu skript skript bilan bir xil joyda `uploads` nomli katalogga ehtiyoj sezadi va veb-server unga yozishga ruxsatga ega bo'lishi kerak.
#!/usr/bin/env python3
import cgi
import os
import html
# Disk raskadrovka qilish uchun batafsil xato hisobotini yoqish
import cgitb
cgitb.enable()
print("Content-Type: text/html\n")
print("<h1>Fayl Yuklash Ishlovchisi</h1>")
# Fayllar saqlanadigan katalog. XAVFSIZLIK: Bu xavfsiz, veb-dan foydalanib bo'lmaydigan katalog bo'lishi kerak.
upload_dir = './uploads/'
# Agar katalog mavjud bo'lmasa, uni yaratish
if not os.path.exists(upload_dir):
os.makedirs(upload_dir, exist_ok=True)
# MUHIM: To'g'ri ruxsatlarni o'rnating. Haqiqiy stsenariyda bu yanada cheklovchi bo'ladi.
# os.chmod(upload_dir, 0o755)
form = cgi.FieldStorage()
# Shakldan fayl elementini olish. 'userfile' kiritish maydonining 'name'idir.
file_item = form['userfile']
# Fayl haqiqatda yuklanganligini tekshirish
if file_item.filename:
# XAVFSIZLIK: Foydalanuvchi tomonidan berilgan fayl nomiga hech qachon ishonmang.
# U '../' kabi yo'l belgilarini o'z ichiga olishi mumkin (katalog bo'ylab harakatlanish hujumi).
# Biz os.path.basename dan har qanday katalog ma'lumotini olib tashlash uchun foydalanamiz.
fn = os.path.basename(file_item.filename)
# Faylni saqlash uchun to'liq yo'lni yaratish
file_path = os.path.join(upload_dir, fn)
try:
# Faylni yozish-ikkilik rejimida ochish va yuklangan ma'lumotlarni yozish
with open(file_path, 'wb') as f:
f.write(file_item.file.read())
message = f"'{html.escape(fn)}' fayli muvaffaqiyatli yuklandi!"
print(f"<p style='color: green;'>{message}</p>")
except IOError as e:
message = f"Faylni saqlashda xato: {e}. '{upload_dir}' katalogi uchun server ruxsatlarini tekshiring."
print(f"<p style='color: red;'>{message}</p>")
else:
message = 'Hech qanday fayl yuklanmadi.'
print(f"<p style='color: orange;'>{message}</p>")
print("<a href='/upload.html'>Boshqa fayl yuklash</a>")
Xavfsizlik: Eng Muhim Masala
CGI skriptlari bevosita internetga ta'sir qiladigan bajariladigan dasturlar bo'lganligi sababli, xavfsizlik majburiy hisoblanadi. Bitta xato serverning buzilishiga olib kelishi mumkin.
Kiritmani Tekshirish va Tozalash (XSS ning oldini olish)
Biz allaqachon ko'rib chiqqanimizdek, foydalanuvchi kiritmasiga hech qachon ishonmasligingiz kerak. Har doim uni zararli deb hisoblang. Foydalanuvchi tomonidan taqdim etilgan ma'lumotlarni HTML sahifada qayta ko'rsatayotganda, Cross-Site Scripting (XSS) hujumlarining oldini olish uchun uni har doim `html.escape()` bilan "escape" qiling. Aks holda, hujumchi foydalanuvchi cookie'larini o'g'irlash yoki saytingizni buzish uchun `