[PHP/MySQL] رفع و تنزيل الملفات بإستخدام قواعد البيانات

مدرج تحت قسم: دروس
8 سبتمبر 2007

السلام عليكم ورحمة الله و بركاته
بحثت عن دروس لكيفية رفع الملفات بقاعدة البيانات فلم أجد درساً مفيداً واحداً!! فقررت كتابته بنفسي لكم.

بدرسنا اليوم سنتعلم كيفية رفع و تنزيل الملفات إلى قاعدة بيانات من نوع MySQL بإستخدام php.

العمل ينقسم على 4 خطوات

  1. زرع كود جدول الملفات بقاعدة البيانات
  2. ملف upload.html و يحتوى على الفورم الخاص بإختيار الملف
  3. ملف upload.php و يحتوى على اكواد رفع الملف لقاعدة البيانات
  4. ملف download.php و يحتوى على اكواد تنزيل الملف من قاعدة البيانات

أولاً: زرع الجدول بقاعدة البيانات

CREATE TABLE `files` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
`filename` VARCHAR(250) NOT NULL ,
`content` MEDIUMBLOB NOT NULL ,
`filesize` INT(20) NOT NULL ,
`filetype` VARCHAR(100) NOT NULL ,
PRIMARY KEY (id)
)

نزرع الكود من الـphpmyadmin.

بهذا الكود أنشأنا جدول باسم files يحتوى على:
id: رقم الملف بقاعدة البيانات (مفتاح اساسى للصفوف)
filename: اسم الملف و إمتداده
content: الملف
filesize: حجم الملف بالبايت
filetype: الـMimetype للملف

ثانياً: ملف upload.html

غرضنا من الملف هو عرض فورم رفع الملفات ساضع لك كود الفورم و لا تنسى وضع اكواد الـhtml الاساسية>

<div align="center">
<h3>من فضلك اختر ملف ليتم رفعه</h3>
<form method="post" action="upload.php"></form></div>

ولا تنسوا وضع

enctype="multipart/form-data"

فى خصائص الفورم لان من دونها لن يتم رفع الملف.

الآن انتهينا من ملف upload.html.

ثالثاً: ملف upload.php المختص برفع الملفات إلى قاعدة البيانات

الإتصال بقاعدة البيانات

$connection = mysqli_connect('localhost','root','','files') or die("فشل الإتصال بقاعدة البيانات");

بهذا الكود قمنا بوضع الإتصال بمتغير و هو connection، إذا فشل الإتصال يخرج البرنامج بالرسالة “فشل الإتصال بقاعدة البيانات”

التأكد من تعيين ملف فعلاً ليتم رفعه

if ( !isset($_FILES['File']) )
{
echo"location.href='upload.html'";
}

بهذا الكود نفحص أولاً عدم وجود المفتاح File بالمصفوفة $_FILES بإستخدام الدالة isset، إن لم يتم العثور على المفتاح فيقوم بالرجوع لصفحة الرفع upload.html، وإذا تم العثور على الملف نخرج معلوماته.

else
{
$file_name = $_FILES['File']['name'];
$file_name = str_replace(" " , "_" , $file_name);

بهذا الكود اخرجنا اسم الملف ثم استخدمنا الدالة str_replace لإستبدال المسافات(” “) بـ(”_”) لأنه إذا تم إيجاد مسافة باسم الملف فيفشل تنزيله عندما تحمله من القاعدة لجهازك.

والآن نستخرج الحجم ونضعه بالمتغير file_size.

$file_size = $_FILES['File']['size'];

بهذا الكود استخرجنا حجم الملف.

والآن نستخرج الـMime Type و نضعه بالمتغير file_type.

$file_type = $_FILES['File']['type'];

والآن موعد اهم جزء وهو إستخراج محتوى الملف نفسه

تحديد الملف على السيرفر ونضعه بالمتغير file_cnt.

$file_cnt = $_FILES['File']['tmp_name'];

ولكننا لا نستطيع رفع ملف بقاعدة البيانات على هذا الاساس! يجب علينا ان نرفع محتويات الملف و ليس الملف.

إذن ماذا نفعل؟؟

نفتح الملف المؤقت على السيرفر للقراءة ثم نخرج منه المحتويات و نخزنها بمتغير ثم نغلق الملف المؤقت. وهذا ما سنفعله بهذا الكود.

$file = fopen($file_cnt,'r');
$content = fread($file,$file_size);
fclose($file);

كما رأينا أولاً المتغير file و هو متغير لفتح الملف بإستخدام الدالة fopen، اما المتغير content فهو المتغير الذي يحتوى على محتويات الملف بإستخدام الدالة fread، ثم اغلقنا الملف بإستخدام الدالة fclose.

الآن ندخل الملف بقاعدة البيانات.

$file_insert = mysqli_query($connection,"
INSERT INTO `files` (id,filename,content,filesize,filetype)
VALUES('NULL', '".addslashes($file_name)."', '".addslashes($content)."', '".$file_size."', '".$file_type."')
");

نتأكد من إدخال الملف.

if ( $file_insert )
{

إذا تم إدخاله ماذا نفعل ؟ نخرج برسالة تقول “تم تحميل الملف بنجاح , للتحميل اضغط هنا”

ولكن قبل ذلك علينا ان نخرج رقم id الملف بقاعدة البيانات لأن ملف التحميل download.php يحتاج الid حتى يستطيع تحميل الملف. نخرج الid بإستخدام الدالة mysqli_insert_id.

$file_id = mysqli_insert_id($connection);

الآن نخرج برسالتنا

echo 'تم رفع الملف بنجاح ,

<a href="download.php?id='.$file_id.'">للتحميل اضغط هنا</a>

';
}

وإذا لم يتم رفع الملف؟ نخرج له برسالة “فشل رفع الملف”

else
{
echo'فشل رفع الملف ,
';
}

وبذلك نكون انتهينا من ملف upload.php. وهذا هو كود ملف upload.php كاملاُ.

$connection = mysqli_connect('localhost','root','','files') or die("فشل الإتصال بقاعدة البيانات");
if ( !isset($_FILES['File']) )
{
echo"location.href='upload.html'";
}
else
{
$file_name = $_FILES['File']['name'];
$file_name = str_replace(" " , "_" , $file_name);
$file_size = $_FILES['File']['size'];
$file_type = $_FILES['File']['type'];
$file_cnt = $_FILES['File']['tmp_name'];
$file = fopen($file_cnt,'r');
$content = fread($file,$file_size);
fclose($file);

$file_insert = mysqli_query($connection,"
INSERT INTO `files` (id,filename,content,filesize,filetype)
VALUES('NULL', '".addslashes($file_name)."', '".addslashes($content)."', '".$file_size."', '".$file_type."')
");

if ( $file_insert )
{
$file_id = mysqli_insert_id($connection);
echo 'تم رفع الملف بنجاح ,

<a href="download.php?id='.$file_id.'">للتحميل اضغط هنا</a>

';
}
else
{
echo'فشل رفع الملف ,
';
}

}

الآن موعدنا مع آخر ملف و هو download.php و هو لتحميل الملفات من قاعدة البيانات.

رابعاً: ملف download.php المختص بتحميل الملفات من قاعدة البيانات

أولاً الإتصال و تخزين الإتصال بالمتغير connection

$connection = mysqli_connect('localhost','root','','files') or die("فشل الإتصال بقاعدة البيانات");

ثانياً تعريف المتغير id و الذي يحتوى على الـid للملف المراد تحميله

$id = intval($_GET['id']);

كما رأينا .. يأخذ قيمته من قيمة المفتاح id بالمصفوفة $_GET

ثالثاً نتأكد من وجود قيمة بالمتغير id لأنها إن كانت خالية فلن يقوم بشئ

if ( empty($id) )
{
}

كما رأينا نتأكد من خلال الدالة empty وإن كانت القيمة خالية فلن يفعل شئ. و إن تم إيجاد قيمة ؟

else
{

نتأكد من وجود ملف برقم الـid (القيمة) بقاعدة البيانات.

نستعلم عن الملف ونضع الإستعلام بالمتغير file.

$file = mysqli_query($connection,"SELECT * FROM `files` WHERE id='".$id."'");

نتأكد من عدد الصفوف التي وجدها الإستعلام بإستخدام الدالة mysqli_num_rows

$check = mysqli_num_rows($file);

ووضعنا النتيجة بالمتغير check إن كانت النتائج = 0، إذن الملف المطلوب غير موجود.

if ( $check == 0 )
{
}

بمثالنا هذا انا لا افعل شئ عند عدم إيجاد الملف، لكن من الممكن ان تكتب رسالة خطأ , كما تريد. وإذا تم إيجاد نتائج ؟ نحمل الملف.

else
{

نضع جميع مفاتيح و قيم الصف الذي تم العثور عليه بمصفوفة و نخزنه بالمتغير row بإستخدام الدالة mysqli_fetch_array.

$row = mysqli_fetch_array($file);

الآن نضع كل مفتاح بالمصفوفة بمتغير باسمه بإستخدام الدالة extract.

extract($row);

الآن نعرف الـheaders
1 – المساحة

header("Content-length: ".$filesize."");

2 – الMime type

header("Content-type: ".$filetype."");

3 – التحميل باسم الملف

header("Content-Disposition: attachment; filename=".stripslashes($filename)."");

4 – إستدعاء محتويات الملف لتكون هى المحتويات التي سيتم تحميلها سنستخدم الدالة print أو echo وستحل اى منهم الآن بمحل الدالة readfile و استغنينا عن readfile لأنها بمعظم الاحيان تسبب اخطاء.

print $content;
}
}

وبذلك نكون انتهينا من ملف download.php. الكود كامل.

$connection = mysqli_connect('localhost','root','','files') or die("فشل الإتصال بقاعدة البيانات");

$id = intval($_GET['id']);
if ( empty($id) )
{
}
else
{
$file = mysqli_query($connection,"SELECT * FROM `files` WHERE id='".$id."'");
$check = mysqli_num_rows($file);
if ( $check == 0 )
{
}
else
{
$row = mysqli_fetch_array($file);
extract($row);
header("Content-length: ".$filesize."");
header("Content-type: ".$filetype."");
header("Content-Disposition: attachment; filename=".stripslashes($filename)."");
print $content;
}
}

وبذلك نكون انتهينا من جميع الملفات.

ملاحظة على مصفوفة $_FILES
المصفوفة $_FILES
لنفترض اننا رفعنا ملف بإستخدام form فإن المصفوفة $_FILES تخزن اسم الملف(name) و نوع الملف(type) و حجم الملف(size) و الملف المؤقت على السيرفر(tmp_name).

للكاتب Khaled-F

  • Share/Bookmark

التعقيبات

  1. غير معروف

التعليقات (12) على ”[PHP/MySQL] رفع و تنزيل الملفات بإستخدام قواعد البيانات“

  1. hax

    درس في غاية الإبداع …

  2. درس رائع اخي خالد ، لكن لي بعض الملاحظات :)

    1 – استخدمت لحقل محتويات الملف النوع MEDIUMBLOB وهذا يسمح بنص حجمه تقريبا 15 MB، ولكن اذا اردت اكبر من ذلك فعليك بLONGBLOB فهو يسمح ب 4 GB

    2 – لو استخدمت [php] header(’location: upload.html’);[/php] بدل
    [php] echo”location.href=’upload.html’”; [/php]

    3 – بما انه من خصائص الحقل id انه AUTO INCREMENT فلا يوجد داعي لوضعه في جملة الادخال (INSERT)

    4 – بعد الانتهاء من استخدام المتغير content – في المثال هنا انتهى بعد تنفيذ جملة الادخال – يفضل ازالته من الذاكرة مباشرة بإستخدام
    [php] unset($content); [/php] او [php] $content = null; [/php]
    صحيح انه سيتم حذفه من الذاكرة بعد الانتهاء من تنفيذ البرنامج لكن لو قمت بإزالته بعد الانتهاء من استخدامه ستخفف من استخدام الذاكرة وهذا مفيد في تنفيذ ما تبقى من كود البرنامج

    5 – يفضل اظهار رسالة خطأ في حال وجود مشكلة مثل

    [php]
    if ( empty($id) ) {
    echo ‘خطأ : لم تحدد ملف لتحميله’;
    }
    [/php]

    وايضا
    [php]
    if ( $check == 0 )
    {
    echo ‘الملف غير موجود’;
    }
    [/php]

    6 – يفضل ازالة “” في جمل header
    [php]
    header(”Content-length: “.$filesize);
    header(”Content-type: “.$filetype);
    header(”Content-Disposition: attachment; filename=”.stripslashes($filename));
    [/php]

    لانه لا يوجد بها نص او كود ، وبالتالي اخف للسيرفر

    7 – اهم ملاحظة : هذه الطريقة سيئة جدا جدا ، ان تخزن ملف في قاعدة البيانات ، يعني عملية صعبة جدا في النقل ، وانا اعتبرها طريقة فاشلة ،
    خصوصا لاصحاب المواقع الكبيرة ، وليس معنى ان برامج المنتديات الشهيرة مثل vb يستخدمها انها طريقة قياسية ،

    اذكر في احدى المرات تخليت عن المرفقات عند نقل قاعدة البيانات الى سيرفر اخر ، هذا مثال على عيوبها الكثيرة

    درس رائع وكاتب اروع ، واعذرني ان اكثرت عليك في الملاحظات :)

  3. شكرا ً لك درس في غاية الروعة ….
    ونتمنى ذكر سلبيات و ايجابيات رفع الملفات في قاعدة البيانات …

  4. بالنسبة لي أرى أكبر مسوائها أنها تكبر حجم القاعدة بشكل خيالي

    أعرف أحدهم حجم قاعدته 5 جيجا كلها مرفقات وحصلت له مشاكل كثيرة وخلل في القاعدة بسبب ضخم حجم القاعدة وفي النهاية اضطر إلى حذف المرفقات كلها للنقل او التخفيف

  5. Khaled-F

    شكراً لكم

    PalCoder : شكراً على ملاحظاتك

    وبالنسبة لمساوئ الرفع فلا اعتقد انها سيئة هكذا!!
    بالنسبة لرفع ملفات كبيرة بقاعدة البيانات و حدوث مشاكل عند الإنتقال لقاعدة جديدة
    فمن الممكن كتابة سكربت php بسيط يقوم بتنزيل الملفات من قاعدة البيانات للموقع ثم يحذفها من قاعدة البيانات ..

    ارى ان الطريقة جيدة خصوصاً إن كنت تريد حماية ملفاتك بمراكز التحميل و غيره .. و إن كنت مللت من التراخيص 777 :D …

  6. قد تكون مفيدة جدا ً لتحميل الملفات الصغيرة كالصور مثلا ً ….

    ولكن لا تعطيك رابط مباشر !

  7. Khaled-F

    اعتقد ان هذه من المميزات اخى ABo.Azazi
    فاصحاب مراكز الرفع
    لا يريدوا المستخدم ان يأخذ رابط مباشر لانه بذلك يمكنه التحميل اى وقت يريده من دون الدخول لملفات الـphp و تقييم الملف …

  8. مانصح بهذا الأمر

    كونه سيحمل سيرفرك ضغطا كبيرا على ال sql مما سيجعلك تواجه ضعفا ملاحظا على سيرفرك

    لذلك لا انصح بها ابدااا وما اجمل استعلامات البي اتش بي

    فلماذا نذهب لما يرهق خوادمنا من اجل امر بسيط

    نستطيع التغلب عليه باكواد بسيطه بالبي اتش بي شديدة الاحترافية

  9. magoo_2003

    مشكوووووووووووووووور كثيرا اخى خالد على هذا الشرح الرائع
    ومتهيقلى احسن حاجة فى قعدة البيانات هى حماية ملفات من التحميل المباشر من روابط بعيدة عن موقعك

    بس عاوز طلب بسيط بالنسبة للصور كيف يتم عرضهاااااا ؟

  10. خالد

    جزاك الله ألف ألف خير

  11. المرسال

    السلام عليكم
    اريد ان عمل مشروع عبارة عن التعلم عن بعد في الانترنت باستخدام php و mysql
    لذلك اذا تكرمت اريد المساعدة بشي مفيد
    مشكور خي …….

  12. ayoub

    je veut le code source de cet projet

أضف تعليقك




يمكنك استخدام الوسوم التالية في التعليق: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


* حقول مطلوبة