
صحة جيدة ، الباعة المتجولين! في عملية العمل على مشروع موقع المواعدة ، أصبح من الضروري تنظيم تخزين صور المستخدم. وفقًا للاختصاصات ، يقتصر عدد الصور لكل مستخدم على 10 ملفات. ولكن قد يكون هناك عشرات الآلاف من المستخدمين. خاصة بالنظر إلى أن المشروع في شكله الحالي موجود بالفعل من بداية "صفر". أي أن هناك بالفعل آلاف المستخدمين في قاعدة البيانات. يتفاعل أي نظام ملفات تقريبًا ، على حد علمي ، بشكل سلبي جدًا مع عدد كبير من العقد الفرعية في مجلد. من التجربة ، يمكنني القول أن المشاكل تبدأ بعد 1000-1500 ملف / مجلد في المجلد الأصل.
تنويه. لقد بحثت في Google قبل كتابة المقالة ووجدت العديد من الحلول للمسألة قيد المناقشة (على سبيل المثال ، هنا أو هنا ). لكنني لم أجد حلاً واحدًا يتطابق تمامًا مع الحل الذي قدمته. بالإضافة إلى ذلك ، في هذه المقالة أشارك فقط تجربتي الخاصة في حل المشكلة.النظرية
بالإضافة إلى مهمة التخزين على هذا النحو ، كان هناك أيضًا شرط في بيان العمل ، والذي بموجبه كان من الضروري ترك تعليق وتعليق للصور. بالطبع ، لا يمكنك الاستغناء عن قاعدة بيانات. أي أن أول شيء نقوم به هو إنشاء جدول نكتب فيه تعيين البيانات الوصفية (التوقيعات والعناوين وما إلى ذلك) مع الملفات الموجودة على القرص. يقابل كل ملف صف واحد في قاعدة البيانات. وفقا لذلك ، كل ملف له معرف.
انضغاط صغير. لنتحدث عن الزيادة التلقائية. قد يكون لموقع التعارف عشرات أو ألفي مستخدم. السؤال هو كم عدد المستخدمين الذين يمرون بالمشروع طوال فترة وجوده. على سبيل المثال ، الجمهور النشط لـ ru-تعود إلى عدة مئات الآلاف. ومع ذلك ، تخيل فقط عدد المستخدمين المتبقيين خلال عمر هذا المشروع ؛ كم عدد المستخدمين الذين لم يتم تنشيطهم حتى الآن. وإضافة الآن إلى تشريعاتنا ، التي تلزمنا بتخزين معلومات حول المستخدمين لمدة ستة أشهر على الأقل ... عاجلاً أم آجلاً ، 4
ستنتهي بنس من
INSIGNED INT . لذلك ، من الأفضل أن تأخذ
BIGINT للمفتاح الأساسي.
لنحاول الآن تخيل عدد من نوع
BIGINT . هذا 8 بايت. كل بايت هو من 0 إلى 255. 255 عقدة فرعية طبيعية تمامًا لأي نظام ملفات. أي أننا نأخذ معرف الملف في تمثيل سداسي عشري ، ونقسمه إلى قطع من حرفين. نحن نستخدم هذه الأجزاء كأسماء مجلد ، والأخير كاسم للملف المادي. ربح!
0f/65/84/10/67/68/19/ff.file
أنيق وبسيط. ملحق الملف غير مهم هنا. على أي حال ، سيتم تقديم الملف عن طريق برنامج نصي يمنح المتصفح نوع MIME معينًا ، والذي سنخزنه أيضًا في قاعدة البيانات. بالإضافة إلى ذلك ، يسمح لك تخزين المعلومات حول الملف في قاعدة البيانات بإعادة تحديد المسار إليه للمتصفح. لنفترض أن الملف الذي لدينا موجود بالفعل بالنسبة إلى دليل المشروع على طول المسار
/content/files/0f/65/84/10/67/68/19/ff.file
. وفي قاعدة البيانات يمكنك كتابة عنوان URL لها ، على سبيل المثال ،
/content/users/678/files/somefile
. ربما يبتسم كبار المسئولين الاقتصاديين إلى حد كبير الآن. كل هذا يسمح لنا بعدم القلق بعد الآن حول مكان وضع الملف ماديًا.
جدول في قاعدة البيانات
بالإضافة إلى المعرف ونوع MIME وعنوان URL والموقع الفعلي ، سنقوم بتخزين ملفات md5 و sha1 في الجدول لتصفية نفس الملفات إذا لزم الأمر. بالطبع ، نحتاج أيضًا إلى تخزين علاقات الكيانات في هذا الجدول. افترض أن معرف المستخدم الذي تنتمي إليه الملفات. وإذا لم يكن المشروع كبيرًا جدًا ، فيمكننا ، في نفس النظام ، تخزين صور البضائع ، على سبيل المثال. لذلك ، سنقوم أيضًا بتخزين اسم فئة الكيان الذي ينتمي إليه السجل.
بالحديث عن الطيور. إذا قمت بإغلاق المجلد باستخدام htaccess للوصول الخارجي ، يمكن الحصول على الملف فقط من خلال البرنامج النصي. وفي البرنامج النصي سيكون من الممكن تحديد الوصول إلى الملف. بالنظر إلى المستقبل قليلاً ، سأقول أنه في نظام إدارة المحتوى (حيث يتم الآن نشر المشروع المذكور الآن) يتم تحديد الوصول من خلال مجموعات المستخدمين الأساسية ، والتي لدي 8 - ضيوف ومستخدمين ومديرين ومشرفين وغير نشطين وممنوعين ومحذوفين ومسؤولين متميزين. يستطيع المشرف المتميز القيام بكل شيء على الإطلاق ، لذا فهو لا يشارك في تحديد الوصول. إذا كان المستخدم لديه علامة المشرف المتميز ، فهو مشرف متميز. كل شيء بسيط. أي أننا سنحدد الوصول إلى المجموعات السبع المتبقية. الوصول بسيط - إما إعطاء الملف أو عدم منحه. في المجموع ، يمكنك أن تأخذ حقلاً من النوع
TINYINT .
وشيء آخر. وفقًا لقانوننا ، سيتعين علينا تخزين الصور المخصصة ماديًا. أي أننا بحاجة إلى وضع علامة على الصور بطريقة ما على أنها محذوفة ، بدلاً من الحذف الفعلي. من الأنسب استخدام حقل بت لهذه الأغراض. في مثل هذه الحالات ، عادةً ما أستخدم حقلاً من نوع
INT . للحجز ، إذا جاز التعبير. علاوة على ذلك ، لدي تقليد راسخ بالفعل بوضع علامة
DELETED في البت الخامس من النهاية. لكن هذا لا يهم مرة أخرى.
ماذا لدينا نتيجة لذلك:
create table `files` ( `id` bigint not null auto_increment,
فئة المرسل
الآن نحن بحاجة إلى إنشاء فصل سنقوم بتحميل الملفات معه. يجب أن يوفر الفصل القدرة على إنشاء الملفات واستبدالها وتعديلها وحذفها. بالإضافة إلى ذلك ، يجدر النظر في نقطتين. أولاً ، يمكن نقل المشروع من خادم إلى خادم. لذلك في الفصل تحتاج إلى تحديد خاصية تحتوي على الدليل الجذر للملفات. ثانيًا ، سيكون الأمر مزعجًا جدًا إذا قام شخص ما بإدخال جدول في قاعدة البيانات. لذلك تحتاج إلى توفير إمكانية استعادة البيانات. مع الأول ، كل شيء واضح بشكل عام. أما بالنسبة للنسخ الاحتياطي للبيانات ، فسوف نحتفظ فقط بما لا يمكن استعادته.
ID - تم استعادته من الموقع الفعلي للملف
نوع_كيان - لم تتم استعادته
كيان - لم تتم استعادته
mime - تم ترميمه باستخدام ملحق finfo
MD5 - يتم استعادته من الملف نفسه
sha1 - تم استعادته من الملف نفسه
ملف - تم استعادته من الموقع الفعلي للملف
عنوان url - لم تتم استعادته
ميتا - لم يتم ترميمه
الحجم - تم استعادته من الملف نفسه
تم إنشاؤها - يمكنك أخذ معلومات من ملف
محدث - يمكنك أخذ معلومات من ملف
الوصول - لم تتم استعادته
أعلام - لم يتم ترميمه
يمكنك تجاهل المعلومات الوصفية على الفور. أنها ليست حاسمة لعمل النظام. ولاسترداد أسرع ، ما زلت بحاجة إلى حفظ نوع MIME. الإجمالي: نوع الكيان ومعرف الكيان و MIME وعنوان URL والوصول والعلامات. لزيادة موثوقية النظام ، سنقوم بتخزين معلومات النسخ الاحتياطي لكل مجلد وجهة بشكل منفصل في المجلد نفسه.
رمز الفصل <?php class BigFiles { const FLAG_DELETED = 0x08000000;
خذ بعين الاعتبار بعض النقاط:
-
realRoot - المسار الكامل للمجلد مع نظام الملفات الذي ينتهي
بخط مائل.
-
webRoot - المسار من جذر الموقع بدون شرطة مائلة (انظر أدناه لمعرفة السبب).
- بصفتي DBMS ،
أستخدم امتداد
MySQLi .
- في الواقع ، يتم تمرير المعلومات من مصفوفة
$ _FILES كوسيطة أولى لطريقة
التحميل .
- إذا قمت باستدعاء طريقة
التحديث لتمرير معرف ملف موجود ، فسيتم استبداله إذا لم يكن صفيف الإدخال في
tmp_name فارغًا.
- يمكنك حذف وتغيير أعلام الملفات المتعددة في وقت واحد. للقيام بذلك ، بدلاً من تمرير معرف الملف ، يجب عليك تمرير إما مصفوفة بمعرفات أو سلسلة بها مفصولة بفواصل.
التوجيه
في الواقع ، يتعلق الأمر ببعض الأسطر في htaccess في جذر الموقع (من المفترض أن mod_rewrite ممكّنة):
RewriteCond %{REQUEST_URI} ^/content/(.*)$ RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.+)$ content/index.php?file=$1 [L,QSA]
"المحتوى" هو المجلد الموجود في جذر الموقع في حالتي. بالطبع يمكنك تسمية المجلد بشكل مختلف. وبالطبع index.php نفسه ، مخزنة في حالتي في مجلد المحتوى:
<?php $dbHost = '127.0.0.1'; $dbUser = 'user'; $dbPass = '****'; $dbName = 'database'; try { if (empty($_REQUEST['file'])) { header('HTTP/1.1 400 Bad Request'); exit; } $userG = 'anonimous';
حسنًا ، في حد ذاته ، نغلق نظام الملفات نفسه من الوصول الخارجي. ضع ملف
.htaccess
في جذر المجلد
content/files
بسطر واحد فقط:
Deny from all
الملخص
يتيح لك هذا الحل تجنب فقدان أداء نظام الملفات بسبب زيادة عدد الملفات. يمكن على الأقل تجنب المشاكل في شكل آلاف الملفات في مجلد واحد. وفي الوقت نفسه ، يمكننا تنظيم والتحكم في الوصول إلى الملفات في عناوين يمكن قراءتها. بالإضافة إلى الامتثال لتشريعاتنا القاتمة. إجراء حجز على الفور ، هذا الحل ليس طريقة كاملة لحماية المحتوى. تذكر: إذا تم تشغيل شيء ما في المتصفح ، فيمكن تنزيله مجانًا.