Texnoman

Assalomu alaykum! Siz Axborot texnologiyalari sohasining o'zbek tilidagi bloggerlar portaliga tashrif buyurdingiz! Loyihamizning asosiy maqsadi haqida bu yerda o'qishingiz mumkin.

Kirish A'zo bo'lish


Farzandlarimiz bizdan ko'ra kuchli, dono, bilimli va albatta baxtli bo'lishlari shart.

- Islom Karimov


PHP: Ko'chirish tezligini chegaralash.

Salom. Anchadan beri ayrim sabablarga ko'ra maqola ham yoza olmadim. Bugun o'ylab-o'ylab nima haqida yozishni topdim. Manimcha bu narsa ko'pchilikka ham zarur bo'ladi. Hozirgi kunda Tas-Ix ham rivojlanib bormoqda va ko'pchilik yangi sayt ochayotganlar saytimdan nimalarni ko'chirishdi va har bir ko'chiruvchiga cheklangan ravishda tezlik berish haqida o'ylasa kerak.

Keling bugun shu muammolarni PHP da hal qilib bersam.

Ko'pchilik hollarda ko'chirishga bergan saytlar faylga to'g'ridan-to'g'ri ssilka (link) berib qo'yishadi. To'g'ri bunda PHP ning hech qanday ishtiroki shartmas. Lekin buni ayrim minuslari bor:

— Qaysi fayllarni ko'p ko'chirishdi
— Tezlikda chegaralab bo'lmaydi
— Faylni xohlagan odam xohlaganicha ko'chirish mumkin

va shunga o'xshash bir qancha sabablarni sanasa bo'ladi. Kelin oldin fayllarni yashirib ularni PHP skript orqali ko'chirishni ko'rsak.

Buning uchun WEB saytimiz yonida yoki PHP ga ruxsat berilgan biror bir papkaga fayllarni qo'yamiz. Misol uchun files nomli papka bo'lsin. Va shu papka ichiga .htacces fayl yaratamiz va fayllarga ruxsatni yopamiz. Quyidagicha

deny from all


endi quyidagicha download.php fayl yaratamiz:
<?php

//FILE papkasi manzilini olish
$files_dir
= dirname(__FILE__).DIRECTORY_SEPARATOR."files".DIRECTORY_SEPARATOR;

//$_GET ni tekshirish
if ( ! isset($_GET['file']))
show_404
();

//To'liq fayl manzilini olish
$filename
= $_GET['file'];
$filepath
= realpath($files_dir.$filename);

//Yozilgan fayl /files papkaning ichidaligini tekshirish
if (!$filepath || strncmp($filepath, $files_dir, strlen($files_dir)) !== 0)
show_404
();

//shu faylning mimetype ni olish. Buning uchun
//php-fileinfo extenstion kerak bo'ladi
$mimetype
= get_mimetype($filepath);

//HTTP headers. Ya'ni browserga fayl ko'chirilaypti
//degan xabarni jo'natish
header
("Cache-Control: public");
header
("Content-Description: File Transfer");
header
("Content-Disposition: attachment; filename=$filename");
header
("Content-Type: $mimetype");
header
('Content-Length: ' . filesize($filepath));

//faylni o'qish va uzatish
readfile
($filepath);

//xatolikni chiqaradigan funksiya
function show_404()
{
header
("HTTP/1.1 404 Not found");
die("Fayl topilmadi");
}

//fayl mimetype ni oladigan funksiya
function get_mimetype($filename)
{
$finfo
= finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);

return $mimetype;
}

Agar browserni ochib site/download.php?file=rasm.jpg deb tersangiz va rasm.jpg fayli «files» papkasida bo'lsa sizga xuddi fayl ko'chirayotganday oyna chiqadi. Endi siz site/files/rasm.jpg deb yozsangiz
Forbidden

You don't have permission to access /files/rasm.jpg on this server.

xatoni olasiz.

Demak sayt foydalanuvchilar fayllarni to'g'ridan-to'g'ri ko'chirolmaydi. Endi keling 2-muammomiz, qaysi fayl necha marta ko'chirildi degan hisoblagichni qo'shsak, bu juda oson. download.php dagi readfile funksiyasidan keyin yozamiz
...
//faylni o'qish va uzatish
readfile
($filepath);

//shu yerga hisob
//mysql_query("UPDATE files SET downloaded = downloaded + 1 WHERE id = $fid");

ko'rinishida.

Yozilgan tepadagi PHP skriptda ko'chirishga chegara berilmagan. Endi keling shu faylni ko'chirish tezligiga chegara qo'ysak, ya'ni 1 mbps tezlik ko'chirib olishi mumkin bo'lgan odamga, biz PHP yordamida 1 kbps tezlikda ko'chiradigan qilamiz. Ya'ni internet tezligi qanaqa bo'lishiga qaramasdan biz bergan tezlikda ko'chiradigan qilamiz.

Buning uchun man quyidagicha funksiyani yozdim
//faylni o'qib tezlikni chegaralash
function read_file($filename, $speed)
{
//browserga ma'lumotlarni ko'natish
flush
();

$read_size
= round(1024 * $speed);
$file
= fopen($filename, "rb");

while( ! feof($file))
{
//dastlabki vaqtni olish
$start
= microtime(true);

//fayldan o'qish
echo fread
($file, $read_size);

//browserga ma'lumotlarni ko'natish
flush
();

//fread va flush ni ketgan vaqtini 1 dan ayirish
$diff
= 1 - (microtime(true) - $start);

//$diff vaqtcha kutish
if ($diff > 0)
usleep
(1000000 * $diff);
}
}

va
//faylni o'qish va uzatish
read_file
($filepath, 10);

readfile ni o'zgartirib qo'yamiz. Funksiyadagi ikkinchi parametr 10 kb/s deganni anglatadi. Agar funksiyaga e'tibor bergan bo'lsangiz, microtime ishlatilgan. Nimaga?

Agar kliyentga 10 kb/s tezlikda jo'natish kerak bo'lsa, fayldan 10 kb ni o'qib, 1 sekund kutib turish kerak bo'ladi. Lekin fread bilan flush lar ham qanchadir vaqtni oladi. Shuning hisobidan sleep(1) qilib ishlatilsa tezlik 9.9 kbps tezlikda bo'lishi mumkin. Umuman olganda tezlikni 100% aniqlikda uzatishga erishish uchun qilingan. Lekin bu ham 99% to'g'ri ishlaydi.

Ha yana qo'shimcha set_time_limit(0); qo'shilgan. Chunki tezlik chegaralangandan keyin PHP fayl 30 sekunddan ko'p ishlashi mumkin. Shunaqa «timeout» bermasligi uchun shu funksiya ishlatiladi.

Shunaqa qilib oxirgi download.php faylimiz quyidagicha.
<?php

//PHP ni har doim ishlab turadigan qilish
set_time_limit
(0);

//FILE papkasi manzilini olish
$files_dir
= dirname(__FILE__).DIRECTORY_SEPARATOR."files".DIRECTORY_SEPARATOR;

//$_GET ni tekshirish
if ( ! isset($_GET['file']))
show_404
();

//To'liq fayl manzilini olish
$filename
= $_GET['file'];
$filepath
= realpath($files_dir.$filename);

//Yozilgan fayl /files papkaning ichidaligini tekshirish
if (!$filepath || strncmp($filepath, $files_dir, strlen($files_dir)) !== 0)
show_404
();

//shu faylning mimetype ni olish. Buning uchun
//php-fileinfo extenstion kerak bo'ladi
$mimetype
= get_mimetype($filepath);

//HTTP headers. Ya'ni browserga fayl ko'chirilaypti
//degan xabarni jo'natish
header
("Cache-Control: public");
header
("Content-Description: File Transfer");
header
("Content-Disposition: attachment; filename=$filename");
header
("Content-Type: $mimetype");
header
('Content-Length: ' . filesize($filepath));

//faylni o'qish va uzatish
read_file
($filepath, 10);

//shu yerga hisob
//mysql_query("UPDATE files SET downloaded = downloaded + 1 WHERE id = $fid");

//faylni o'qib tezlikni chegaralash
function read_file($filename, $speed)
{
//browserga ma'lumotlarni ko'natish
flush
();

$read_size
= round(1024 * $speed);
$file
= fopen($filename, "rb");

while( ! feof($file))
{
//dastlabki vaqtni olish
$start
= microtime(true);

//fayldan o'qish
echo fread
($file, $read_size);

//browserga ma'lumotlarni ko'natish
flush
();

//fread va flush ni ketgan vaqtini 1 dan ayirish
$diff
= 1 - (microtime(true) - $start);

//$diff vaqtcha kutish
if ($diff > 0)
usleep
(1000000 * $diff);
}
}

//xatolikni chiqaradigan funksiya
function show_404()
{
header
("HTTP/1.1 404 Not found");
die("Fayl topilmadi");
}

//fayl mimetype ni oladigan funksiya
function get_mimetype($filename)
{
$finfo
= finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);

return $mimetype;
}


Bu holatning asosiy minuslaridan biri, resursni juda ko'p yeyib qo'yishi mumkin.

Savollar bo'lsa marhamat. Manba:

php web download 30-Iyun 02:03 375

texnoman

Muallif haqida

Texnoman Jamoasi Internetni rivojlantiramiz!


Blogdagi so‘nggi maqolalar:


Fikrlar 2

Bender
Bender
//browserga ma'lumotlarni ko'natish to'g'irlab qo'ying
iphpdot
iphpdot
mysql eksirgan MySQLi yoki PDO dan foydalansangiz zo'r bo'lardi!
Iltimos, fikr bildirish uchun saytga kiring yoki ro‘yxatdan o‘ting!