تخزين الملفات (File storage) في Laravel
مقدمة
يوفّر Laravel تجريدًا قويًا لنظام الملفات بفضل الحزمة Flysystem. يوفّر تضمين أنظمة الملفات في Laravel مشغّلات سهلة الاستعمال للتعامل مع الأنظمة المحلية و Amazon S3 والتخزين السحابي Rackspace، بل من السهل جدًا تغيير خيارات التخزين إذ تبقى وصلة API نفسها مع كل الأنظمة.
الضبط
يوجد ملف ضبط نظام الملفات في config/filesystems.php
. يمكنك في هذا الملف ضبط كل الأقراص "disks". يمثّل كل قرص مشغّل تخزين ومكان تخزين خاص. يحتوي الملف على أمثلة ضبط لكل مشغّل مدعوم. لذا غيّر الملف حسب خياراتك ومعلوماتك الخاصة.
طبعًا، يمكنك ضبط أي عدد من الأقراص تريد أو حتى أقراص عديدة تستعمل نفس المشغّل.
القرص الصلب العام
القرص العام public مُعدٌّ للملفات التي سيكون ولوجها عامًّا. في العادة، يستخدم القرص public المشغل local ويُخزِّن الملفات في storage/app/public
. لإتاحة إمكانية ولوجهم من الويب، يجب إنشاء وصلة رمزية من public/storage
إلى storage/app/public
. تُبقي هذه الطريقة كل الملفات العمومية في مكان واحد يمكن مشاركته بسهولة عند استعمال تقنية نشر دون وقت إيقاف مثل Envoyer.
لإنشاء الوصلة الرمزية، استعمل الأمر storage:link
:
php artisan storage:link
بعد إنشاء الملف والوصلة الرمزية، يمكنك توليد عنوان URL للملف عبر الدالة المساعدة asset
:
echo asset('storage/file.txt');
برنامج التشغيل المحلي
عند استخدام المشغّل المحلي local، كل الأعمال على الملفات موجودة في المجلد الجذر (root) المعرّف في ملف الضبط. في العادة، قيمته هي المجلد storage/app
. لذا، الأمر الآتي سيُسجّل ملفًا في storage/app/file.txt
:
Storage::disk('local')->put('file.txt', 'Contents');
متطلبات برنامج التشغيل
حزم Composer
قبل استخدام مشغّلات S3 أو SFTP أو Rackspace، ستحتاج أولا لتثبيت الحزم الملائمة عبر Composer:
- league/flysystem-sftp ~1.0 :SFTP
- league/flysystem-aws-s3-v3 ~1.0 :Amazon S3
- league/flysystem-rackspace ~1.0 :Rackspace
من الضروري لأداء جيد استخدام مكيّفات تخزين مؤقت (cached adapter). ستحتاج حزمة أخرى لذلك:
- league/flysystem-cached-adapter ~1.0 : CachedAdapter
ضبط مشغّل S3
توجد معلومات ضبط المشغّل S3 في الملف config/filesystems.php
. يحتوي هذا الملف على مثال لمصفوفة ضبط لمشغل S3. لك حرية تغيير هذه المصفوفة بضبتك ومعلوماتك الخاصة. للتسهيل، يستعمل متغيرات البيئة أسماء مطابقة لطريقة التسمية المتبعة في واجهة سطر الأوامر لخدمات AWS.
ضبط مشغّل FTP
يعمل مضمِّن نظام الملفات جيدًا مع FTP. لكن الملف filesystems.php
لا يتضمن مثالًا عن الضبط. إن احتجت لضبط FTP يمكنك استعمال المثال التالي:
'ftp' => [
'driver' => 'ftp',
'host' => 'ftp.example.com',
'username' => 'your-username',
'password' => 'your-password',
// خيارات غير إجبارية
// 'port' => 21,
// 'root' => '',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
ضبط مشغّل SFTP
يعمل مضمِّن نظام الملفات جيدًا مع SFTP. لكن الملف filesystems.php
لا يتضمن مثالًا عن الضبط. إن احتجت لضبط FTP يمكنك استعمال المثال التالي:
'sftp' => [
'driver' => 'sftp',
'host' => 'example.com',
'username' => 'your-username',
'password' => 'your-password',
// ضبط مفتاح SSH
// 'privateKey' => '/path/to/privateKey',
// 'password' => 'encryption-password',
// Optional SFTP Settings...
// 'port' => 22,
// 'root' => '',
// 'timeout' => 30,
],
ضبط مشغّل Rackspace
يعمل مضمِّن نظام الملفات جيدًا مع Rackspace. لكن الملف filesystems.php
لا يتضمن مثالًا عن الضبط. إن احتجت لضبط FTP يمكنك استعمال المثال التالي:
'rackspace' => [
'driver' => 'rackspace',
'username' => 'your-username',
'key' => 'your-key',
'container' => 'your-container',
'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/',
'region' => 'IAD',
'url_type' => 'publicURL',
],
التخزين المؤقت
لتمكين قرص ما من استخدام التخزين المؤقت، تضاف التعليمة cache لخيارات ضبط القرص. يجب أن يكون الخيار cache
مصفوفة من خيارات التخزين تحتوي الاسم disk
's3' => [
'driver' => 's3',
// خيارات أخرى
'cache' => [
'store' => 'memcached',
'expire' => 600,
'prefix' => 'cache-prefix',
],
],
وتاريخ انتهاء الصلاحية expire
إضافة إلى سابقة prefix
:
الحصول على نسخة من كائن القرص
تُستعمل الواجهة الساكنة Storage
للتفاعل مع عدّة أقراص مضبوطة. مثلًا، يٌستعمل التابع put
من الواجهة لتخزين نسخة avatar
في القرص الرئيسي. إذا ناديت التابع put
على الواجهة الثابتة Storage
دون أن تنادي call
أولا،تُستدعى الدالة call
تلقائيًا للقرص الرئيسي:
use Illuminate\Support\Facades\Storage;
Storage::put('avatars/1', $fileContents);
إذا كان التطبيق يتعامل مع أكثر من قرص، يمكن استعمال التابع disk
من الواجهة الثابتة Storage
Storage::disk('s3')->put('avatars/1', $fileContents);
للعمل على ملفات في قرص معيّن:
Storage::disk('s3')->put('avatars/1', $fileContents);
استرداد الملفات
يُستعمل التابع get
للحصول على محتوى ملف. يعيد التابع سلسلة نصية خام من محتويات الملف. تذكر أنّ كل مسارات الملفات يجب أن تُذكر في علاقة بالملف الجذر "root" المحدّد في ملف الضبط:
$contents = Storage::get('file.jpg');
يُستعمل التابع exists
للتأكد من وجود الملف على القرص:
$exists = Storage::disk('s3')->exists('file.jpg');
تنزيل الملفات
يُستعمل التابع download
لتوليد إجابة تفرض على متصفح المستخدم تنزيل ملف من مسار ممرَّر. يقبل التابع download
اسم ملف كمعامل ثاني يُحدِّد اسم الملف الذي سيراه المستخدم بعد تنزيل الملف. أخيرًا، يمكن تمرير مصفوفة من ترويسات HTTP كمعامل ثالث للتابع
return Storage::download('file.jpg');
return Storage::download('file.jpg', $name, $headers);
عنوان URL الملفات
يمكن استعمال التابع url
للحصول على مسار URL لملف معيّن. إن كنت تستعمل المشغّل local، سيضيف التابع القيمة storage/ للعنوان الممرَّر ويعيد النتيجة. إن كنت تستخدم المشغّل s3 أو rackspace، سيعيد التابع العنوان البعيد الكامل:
use Illuminate\Support\Facades\Storage;
$url = Storage::url('file.jpg');
تنبيه: تذكر أنّه إن كنت تستعمل المشغّل local، يجب أن توجد جميع الملفات العامة في الدليل storage/app/public
. أيضًا، عليك إنشاء وصلة رمزية من public/storage
إلى storage/app/public
.
عناوين URL المؤقتة
بالنسبة للملفات المخزَّنة باستعمال مشغّلات S3 أو rackspace، يمكن إحداث عنوان URL مؤقت لملف معيّن باستعمال التابع temporaryUrl
. يقبل هذا التابع مسارًا ونسخة الكائن DateTime
يحدّد وقت انتهاء صلاحية المسار:
$url = Storage::temporaryUrl(
'file.jpg', now()->addMinutes(5)
);
تخصيص عناوين URL المحلية
إذا أردت التعريف المسبق للمستضيف للملفات المخزّنة على قرص باستعمال المشغّل local، يمكن إضافة الخيار url
لمصفوفة ضبط القرص:
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
وصف بيانات الملفات File Metadata
بالإضافة لقراءة وكتابة الملفات، يوفّر Laravel معلومات عن الملفات نفسها. مثلًا، يُستعمل التابع size
لإعادة معلومات عن حجم الملف بالوحدة byte:
use Illuminate\Support\Facades\Storage;
$size = Storage::size('file.jpg');
يعيد التابع lastModified
وقت آخر تغيير طرأ على الملف:
$time = Storage::lastModified('file.jpg');
تخزين الملفات
يُستعمل التابع put
لتخزين محتويات خام لملف على قرص. يمكن تمرير مورد (php resource) للتابع put
، ممّا يسمح باستغلال خاصية دعم التدفق في Flysystem. يُنصح باستخدام التدفق في حال العمل بملفات ضخمة:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents);
Storage::put('file.jpg', $resource);
التدفّق التلقائي
إذا أردت أن يتحكم Laravel تلقائيا بتدفق ملف معيّن في مكان التخزين، استعمل التابع putFile
أو putFileAs
.
يقبل هذا التابع نسخة عن Illuminate\Http\File
أو lluminate\Http\UploadedFile
ويقوم بدفق الملف للمكان المحدّد:
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;
// إحداث رقم خاص بالملف تلقائيًا
Storage::putFile('photos', new File('/path/to/photo'));
// اختيار اسم الملف يدويًا
Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');
هناك بعض المعلومات يجب معرفتها عند العمل بالتابع putFile
. لاحظ أننا حددنا فقط اسم المجلد وليس اسم الملف. في العادة يصنع التابع رقم هوية ID
فريدا لتكون اسم الملف. يُحدَّد ملحق اسم الملف بمعاينة نوع MIME الملف. يعيد التابع مسار الملف لذا يمكنك تخزين المسار بما فيه الإسم المصنوع في قاعدة البيانات.
يقبل التابعان putFile
و putFileAs
أيضًا معاملًا لتحديد إمكانية رؤية الملف المخزَّن. هذه الخاصية مفيدة خاصة في حال تخزين ملف في قرص سحابي مثل s3 وجعل الوصول إليه عموميًا:
Storage::putFile('photos', new File('/path/to/photo'), 'public');
الإضافة للملف
يسمح التابعان prepend
و append
بالإضافة لملفٍ ما في بدايته أو في نهايته:
Storage::prepend('file.log', 'إضافة في البداية');
Storage::append('file.log', 'إضافة في النهاية');
نسخ ونقل الملفات
يُستعمل التابع copy
لنقل نسخة من ملف موجود لمكان جديد في القرص، في حين يُستخدم move لإعادة تسمية ملف أو نقله كليًا لمكان جديد:
Storage::copy('old/file.jpg', 'new/file.jpg');
Storage::move('old/file.jpg', 'new/file.jpg');
رفع الملفات
في تطبيقات الويب، يعدّ رفع ملف مثل صورة أو وثيقة من حالات الاستخدام الشائعة جدًا في تخزين الملفات. يجعل Laravel تخزين الملفات المرفوعة أمرًا سهلًا باستخدام التابع store
على نسخة الكائن من الملف المرفوع. استدعِ التابع store
مع المسار الذي تريد أن تخزّن الملف المرفوع فيه:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserAvatarController extends Controller
{
/**
* تحديث صورة المستخدم
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
$path = $request->file('avatar')->store('avatars');
return $path;
}
}
هناك بعض الأمور المهمة التي يجب معرفتها. مثلًا، لاحظ أننا حددنا فقط اسم المجلد وليس اسم الملف. في العادة يُنشِئ التابع رقم مُعرِّف ID فريد ليكون اسم الملف. يُحدَّد ملحق اسم الملف بمعاينة نوع MIME للملف. يعيد التابع مسار الملف لذا يمكنك تخزين المسار بما فيه الاسم المُنشَأ في قاعدة البيانات.
يمكنك أيضًا استدعاء putFile
من الواجهة الثابتة Storage
للقيام بنفس العمل في المثال السابق:
$path = Storage::putFile('avatars', $request->file('avatar'));
تحديد اسم الملف
إذا لم ترد أن يعطى اسم آلي للملفات، استعمل التابع storeAs
الذي يقبل مسارًا، واسمًا للملف، وقرصًا (غير إجباري) كمعاملات:
$path = $request->file('avatar')->storeAs(
'avatars', $request->user()->id
);
يمكنك أيضًا استعمال التابع putFileAs
من الواجهة الثابتة Storage
للقيام بنفس عمل المثال السابق:
$path = Storage::putFileAs(
'avatars', $request->file('avatar'), $request->user()->id
);
تحديد القرص
في العادة، يستخدم هذا التابع القرص الرئيسي. إذا أردت تحديد قرص آخر، مرّر اسم القرص كمعامل ثاني للتابع store:
$path = $request->file('avatar')->store(
'avatars/'.$request->user()->id, 's3'
);
إمكانية رؤية الملفات
في تضمين Flysystem من Laravel، إمكانية رؤية الملفات (visibility) هي تجريد لأذونات الملفات في مختلف المنصات. يمكن تعريف الملفات كملفات عمومية (public) أو خاصة (private). عند تعريف ملف كعمومي، أنت تعلن أنّ يمكن رؤيته من الآخرين. مثلًا، عند استخدام برنامج التشغيل S3، يمكنك استرداد عناوين URLs الخاصة بالملفات العامّة (public files).
يمكن تحديد إمكانية الرؤية عند إنشاء الملف عبر التابع put
:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents, 'public');
إذا كان الملف موجودًا مسبقًا، يمكن إعادة إمكانية الرؤية وتغييرها باستخدام التابعين getVisibility
و setVisibility
:
$visibility = Storage::getVisibility('file.jpg');
Storage::setVisibility('file.jpg', 'public')
حذف الملفات
يقبل التابع delete
اسم ملف واحد أو مصفوفة ملفات لحذفها من القرص:
use Illuminate\Support\Facades\Storage;
Storage::delete('file.jpg');
Storage::delete(['file.jpg', 'file2.jpg']);
يمكن تحديد القرص الذي يحتوي الملف إن احتجت لذلك:
use Illuminate\Support\Facades\Storage;
Storage::disk('s3')->delete('folder_path/file_name.jpg');
المجلدات
إعادة كل الملفات من مجلد
يُرجع التابع files
كل الملفات الموجودة في مجلّد ممرَّر كوسيط إليه. إذا أردت استرجاع كل الملفات حتى من المجلدات الفرعية، استخدم التابع allFiles
:
use Illuminate\Support\Facades\Storage;
$files = Storage::files($directory);
$files = Storage::allFiles($directory);
إعادة كل المجلدات من مجلد معين
يُرجع التابع directories
كل المجلدات الموجودة في مجلد ممرّر كوسيط إليه . إذا أردت استرجاع كل المجلدات حتى من المجلدات الفرعية، استخدم التابع allDirectories:
$directories = Storage::directories($directory);
// Recursive...
$directories = Storage::allDirectories($directory);
إنشاء مجلد
يُستخدم التابع makeDirectory
لصناعة مجلد ممرَّر كوسيط إليه بما فيه المجلدات الفرعية
Storage::makeDirectory($directory);
حذف مجلد
يُستخدم التابع deleteDirectory
لحذف مجلد وكل ملفاته:
Storage::deleteDirectory($directory);
نظام الملفات المخصص
وفّر تضمين Flysystem في Laravel واجهة لعدّة برامج تشغيل. لكنّه ليس محدودًا بها بل يوفّر أيضًا مكيّفات لعدّة أنظمة تخزين أخرى. يمكنك إنشاء برنامج تشغيل مخصص إذا أردت استعمال أحد المكيّفات الإضافية في تطبيقك.
لوضع نظام ملفات مخصص، ستحتاج لمكيّف Flysystem. لنضف المكيّف Dropbox مدعوما من مجموعة مستخدمين:
composer require spatie/flysystem-dropbox
بعد ذلك، يجب إنشاء موّفر خدمات مثل DropboxServiceProvider. في التابع boot من الموفر، استعمل التابع extend الواجهة الثابتة Storage لتعريف المشغّل المخصص:
<?php
namespace App\Providers;
use Storage;
use League\Flysystem\Filesystem;
use Illuminate\Support\ServiceProvider;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
class DropboxServiceProvider extends ServiceProvider
{
/**
* تنفيذ خدمات ما قبل التسجيل
* @return void
*/
public function boot()
{
Storage::extend('dropbox', function ($app, $config) {
$client = new DropboxClient(
$config['authorization_token']
);
return new Filesystem(new DropboxAdapter($client));
});
}
/**
* تسجيل الارتباطات في الحاوي
*
* @return void
*/
public function register()
{
//
}
}
المعامل الأول في التابع extend
هو اسم المشغّل، المعامل الثاني Closure يقبل المتغيّرين app$
و config$
. يعيد Closure بعد انتهائه نسخةً من League\Flysystem\Filesystem
. يحتوي المتغيّر config$
قيمة config/filesystems.php
للقرص المذكور.
بعد إنشاء موّفر الخدمات، يمكن استعمال برنامج التشغيل dropbox في ملف الضبط config/filesystems.php
.