PDA

View Full Version : دانلود فایل با تابع header - بلی یا خیر؟



ayub_coder
شنبه 24 دی 1390, 20:30 عصر
سلام دوستان
بعضی مواقع (یه بار خودم انجام دادم) پیش میاد که می خوایم فایل ها رو از لینک مستقیم خارج کنیم تا قابلیت دانلود با لینک رو بگیریم
یکی از روش ها استفاده از تابع header هست که چندین بار در فروم در موردش بحث شد
سوال من اینه: آیا این روش بهینه هست؟ آیا فشاری به سرور میاره یا دقیقا مثل دانلود معمولیه فایله؟
آیا با این روش معقوله که مثلا فایل هایی با حجم مثلا 10 یا 100 - یا 500 مگا بایت را با تابع header اجازه دانلود بدیم؟
دوستان این برای من خیلی مهمه اگه کسی می تونه کمک کنه.:افسرده:

امیـرحسین
شنبه 24 دی 1390, 21:01 عصر
با تابع header فقط میشه تعیین کرد که فایل حتما دانلود شه و کاری به آدرسش نداره.
اگه منظورتون همون مثالی هست که در اینجا (http://www.php.net/manual/en/function.readfile.php) اومده، با این روش فایل در RAM قرار میگیره و سرور میترکه! فرض کنید ۵ نفر همزمان بخوان یه فایل ۱۰۰ مگابایتی رو دانلود کنند! میشه ۵۰۰ مگابایت از RAM.

Unique
شنبه 24 دی 1390, 23:15 عصر
برای فایل های حجیم شما باید از طریق یک buffer فایل را بفرستی ، توی Comment های همون صفحه ای که امیر حسین گذاشته نمونش هست.

ayub_coder
یک شنبه 25 دی 1390, 09:47 صبح
دوستان پس راه حل معقول برای این قضیه چیه؟
محدود کردن کاربر از لینک مستقیم. یعنی اگه تو آدرس بار لینک فایل رو زد دانلود نشه و اول مراحلش اعتبار سنجیش و اینا طی بشه بعد دانلود شه. البته بعدش هم قابلیت Resume داشته باشه. چون فایلهایی که برای دانلود گذاشته میشن حجیم هستن

pejman_view
یک شنبه 25 دی 1390, 10:57 صبح
سلام

استفاده از هدر آره یا نه ؟ من فکر می کنم جواب شما آره است و تقریباً تمامی سایت ها از جمله مدیافایر از این روش استفاده می کنند اما چطور باید بهترین روش را بکار بگیریم اینجا جای بحث داره همانطور که دوست عزیزم امیرحسین گفت و مثالی هم نشان داد آن تابع بافر می کنه. شما بایستی بافر تابع را خرد کنید سپس با یک حلقه هر موقع جریان دانلود شده به اندازه بافر شد بافر قبلی خالی شده و بافر جدید جایگزین شود حتی می توانید با این روش سرعت دانلود را کنترل نمایید.

با آرزوی موفقیت.

ayub_coder
یک شنبه 25 دی 1390, 11:43 صبح
خوب بالاخره یه حلقه تکراری وجود داره و این بار بر روی سرور. و همانطور که دوستمون گفت این داده ها وارد حافظه رم می شود.
حالا تصور کنیدحجم فایلها 500 مگابایت است و در یک لحظه 5000 نفر درخواست دانلود دهند . این خودش میشه 2500 گیگا بایت.:متعجب:.
مشکل دوم این راه نبود قابلیت Resume است. کاربر نمی تواند 500 مگابایت را در یک مرحله دانلود کند. و اجبارا باید از نو دانلود کند.
راه حل دیگه هست دوستان؟بجز Header ?

pejman_view
یک شنبه 25 دی 1390, 18:18 عصر
سلام

خوب شما بافر 500 مگابایتی که نباید بگذارید! فرضاً 5000 هزار نفر درخواست بدهند با فرض خورد کردن بافر به 512 کیلوبایت این 5000 تا کاربر حدوداً 2.5 گیگابایت رم شما را اشغال خواهند کرد. و 2.5 گیگابایت برای این همه کاربر واقعاً چیز زیادی نیست! برای راه اندازی دانلود سنتری مانند مدیافایر باید بگم آن ها از ابرسرورها (CloudServer) استفاده می کنند مجموعه ایی از کامپیوترها که با هم کار می کنند تا بدون هیچ نقصی به شما سرویس بدهند.
همینطور آگاه باشید که 5000 کاربر همزمان به سرعت اینترنت فوق العاده ایی از طرف سرور نیاز است!

برای resum هم به شما تابع زیر را پیشنهاد می کنم:
http://php.net/manual/en/function.connection-aborted.php

ayub_coder
دوشنبه 26 دی 1390, 15:29 عصر
1-می توانید در مورد این بافر کردن بیشتر توضیح دهید؟ به زبان شیرین فارسی؟
2-باز هم یه حلقه تکرار وجود دارد و تصور 5000 حلقه تکرار دائما پردازش میشوند ... :متعجب: خود این حلقه CPU را خواهد کشت.!
3-دوستان راه حل دیگر و مناسب تری سراغ ندارد؟

Unique
سه شنبه 27 دی 1390, 09:29 صبح
میدونین مشکل ما چیه ؟ ما میخواهیم با کمترین امکانات (بیشترین نه ها) نهایت استفاده را ببریم ! دوست عزیز سایتی که 5000 دانلود همزمان داره بایستی یک VPS حداقل 4 گیگابایتی داشته باشه تا با 2 گیگابایتش بتونه دانلودش را مدیریت کنه ! اگه هم نتونه از این 5000 مشتری پول در بایره بهتره بره در سایتش را ببنده !
کافیه یک سری به Manual های header,fread,readfile توی سایت php بزنین تا کلی مطلب پیدا کنین ، تابع زیر برای Buffer کردن و امکان Resume فایل های سنگین مناسبه و میتونید ازش استفاده کنید یا ایده بگیرین :


function dl_file_resumable($file, $is_resume=TRUE)
{
//First, see if the file exists
if (!is_file($file))
{
die("<b>404 File not found!</b>");
}

//Gather relevent info about file
$size = filesize($file);
$fileinfo = pathinfo($file);

//workaround for IE filename bug with multiple periods / multiple dots in filename
//that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe
$filename = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ?
preg_replace('/\./', '%2e', $fileinfo['basename'], substr_count($fileinfo['basename'], '.') - 1) :
$fileinfo['basename'];

$file_extension = strtolower($path_info['extension']);

//This will set the Content-Type to the appropriate setting for the file
switch($file_extension)
{
case 'exe': $ctype='application/octet-stream'; break;
case 'zip': $ctype='application/zip'; break;
case 'mp3': $ctype='audio/mpeg'; break;
case 'mpg': $ctype='video/mpeg'; break;
case 'avi': $ctype='video/x-msvideo'; break;
default: $ctype='application/force-download';
}

//check if http_range is sent by browser (or download manager)
if($is_resume && isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);

if ($size_unit == 'bytes')
{
//multiple ranges could be specified at the same time, but for simplicity only serve the first range
//http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
}
}
else
{
$range = '';
}

//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);

//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);

//add headers if resumable
if ($is_resume)
{
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($size - 1))
{
header('HTTP/1.1 206 Partial Content');
}

header('Accept-Ranges: bytes');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size);
}

//headers for IE Bugs (is this necessary?)
//header("Cache-Control: cache, must-revalidate");
//header("Pragma: public");

header('Content-Type: ' . $ctype);
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: '.($seek_end - $seek_start + 1));

//open the file
$fp = fopen($file, 'rb');
//seek to start of missing part
fseek($fp, $seek_start);

//start buffered download
while(!feof($fp))
{
//reset time limit for big files
set_time_limit(0);
print(fread($fp, 1024*8));
flush();
ob_flush();
}

fclose($fp);
exit;
}


source : php.net

ayub_coder
سه شنبه 27 دی 1390, 09:38 صبح
یعنی سایت های بزرگی مثل هات فایل ، رپید شیر ، فور شیر از این روش استفاده میکنند؟

Unique
سه شنبه 27 دی 1390, 23:02 عصر
راستش من تا حالا کد هاشون را ندیدم اما مگه شما میخای hotfile یا rapidshare درست کنی ؟
من از این روش توی خیلی از سایت ها استفاده کردم و کار میکنه بدون مشکل ! شما برای کار خودتون میتونین امتحان کنین !

pejman_view
چهارشنبه 28 دی 1390, 08:32 صبح
سلام
نمی دانم چرا همیشه همه چیز را برای خودتان سخت فرض می کنید و به جواب می رسید می گویید نه حتماً این جواب غلط است و باید دنبال درستش بگردم.

اگر می خواهید چنین سرویس قوی مانند مدیافایر، فایل شیر، راپیدشیر راه بندازید. 100% ما مثل شرکت های خارجی نه بودجه کافی و نه امکانات لازم را داریم اما می توانیم مثل آنها رفتار کنیم.

باید حتماً سایت خود را طوری طراحی کنید که چندتا سرور را پشتیبانی کند. ضمناً باید فکر کنید ببینید فرضاً چه فایلی در کدام سرور قرار بگیرد. فشار روی کدام سرور زیاد است؟ و کلی سوال دیگر تا یک الگوریتم خوب درست کنید.
بگذارید یک مورد که به ذهنم می رسد بیان کنم فرضاً یک سرور دارید با این مشخصات 4 گیگابایت رم، هارد: 3 ترابایت و سرعت اینترنت 100 مگابایت با اینکه 2500 گیگابایت از فضایش پر شده است و می بینید از نظر سرعت اینترنت جوابگو نیستید تا زمانی که فشار روی این سرور است هنوز بر روی آن اطلاعات می ریزید پر شود؟

با آرزوی موفقیت