الخطوات
-
1
كتابة نموذج الرفع
يجب أن يحتوي النموذج على
enctype="multipart/form-data"— بدونه لن يُرسَل الملف الثنائي إلى الخادم أبدًا. استخدم التوجيه@csrfواضبطmethod="POST".html<form action="{{ route('upload.store') }}" method="POST" enctype="multipart/form-data"> @csrf <input type="file" name="image" accept="image/*"> @error('image') <p class="error">{{ $message }}</p> @enderror <button type="submit">Upload</button> </form> -
2
التحقق من صحة الملف المرفوع
تحقق دائمًا من الصحة قبل التخزين. استخدم قاعدة
fileللتأكد من رفع شيء ما، وmimesللتقييد حسب الامتداد، وmaxلتحديد حجم الملف بالكيلوبايت. يتحقق Laravel من امتداد الملف وNONE type المُبلَّغ عنه من المتصفح.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UploadController extends Controller { public function store(Request $request) { $request->validate([ 'image' => [ 'required', 'file', 'mimes:jpg,jpeg,png,webp,pdf', 'max:2048', // 2 MB ], ]); // proceed to store... } } -
3
تخزين الملف
استدعِ
$request->file('image')->store('uploads', 'public'). يولّد Laravel اسمًا فريدًا تلقائيًا (مبني على UUID)، ينقل الملف إلىstorage/app/public/uploads/، ويُعيد المسار النسبي مثلuploads/abc123.jpg. احفظ ذلك المسار في قاعدة البيانات.إذا أردت التحكم في اسم الملف بنفسك، استخدم
storeAs()بدلًا من ذلك.php// Auto-generated unique filename $path = $request->file('image')->store('uploads', 'public'); // returns: "uploads/3f7a...uuid...jpg" // Custom filename $filename = time() . '_' . $request->file('image')->getClientOriginalName(); $path = $request->file('image')->storeAs('uploads', $filename, 'public'); // Save the path to the database $post = Post::create([ 'title' => $request->title, 'image_path' => $path, ]); -
4
إنشاء الرابط الرمزي العام
يخزّن القرص
publicالملفات فيstorage/app/public/، وهي غير متاحة عبر الويب افتراضيًا. شغّلphp artisan storage:linkمرة واحدة لإنشاء رابط رمزي منpublic/storageإلىstorage/app/public. افعل هذا بعد النشر على كل خادم.bashphp artisan storage:link # Creates: public/storage -> storage/app/public -
5
عرض الملف المخزّن
استخدم دالة
url()في واجهةStorageلتوليد الرابط العام من المسار المخزّن. تعمل مع قرصpublic(تُعيد رابطًا محليًا) ومع S3 (تُعيد رابط CDN أو S3).html{{-- In a Blade template --}} <img src="{{ Storage::disk('public')->url($post->image_path) }}" alt="Uploaded image"> {{-- Or use the global helper --}} <img src="{{ asset('storage/' . $post->image_path) }}" alt="Uploaded image"> {{-- In a controller or model --}} use Illuminate\Support\Facades\Storage; $url = Storage::disk('public')->url($post->image_path); // returns: https://yourdomain.com/storage/uploads/abc123.jpg -
6
فهم أقراص نظام الملفات
يُعرّف
config/filesystems.phpفي Laravel أقراصًا مسمّاة. الثلاثة الأكثر استخدامًا هي:local— يخزّن الملفات فيstorage/app/، غير متاحة علنًا (جيد للوثائق الخاصة)public— يخزّن فيstorage/app/public/، مرتبط رمزيًا بـpublic/storage(جيد للصور وصور المستخدمين)s3— يخزّن على Amazon S3 (مستوى الإنتاج، يتوسع بلا حدود)
تبدّل الأقراص بتغيير الوسيطة الثانية في
store()أو باستدعاءStorage::disk('s3'). كود وحدة التحكم لا يتغير. -
7
ضبط قرص S3
ثبّت محوّل Flysystem S3، ثم أضف بيانات AWS إلى
.env. إعداد قرص S3 موجود بالفعل فيconfig/filesystems.php— تحتاج فقط إلى تعبئة متغيرات البيئة.bashcomposer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies -
8
إضافة بيانات S3 إلى .env
أضف ما يلي إلى ملف
.env.AWS_URLاختياري — استخدمه إذا كان لديك توزيع CloudFront أمام الـ bucket حتى تُعيدStorage::url()رابط CDN بدلًا من رابط S3 المباشر.bash# .env AWS_ACCESS_KEY_ID=AKIA... AWS_SECRET_ACCESS_KEY=your-secret-key AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET=your-bucket-name AWS_URL=https://cdn.yourdomain.com # optional, for CloudFront FILESYSTEM_DISK=s3 # make S3 the default disk -
9
الرفع إلى S3 وتوليد الرابط
الآن استبدل اسم القرص في استدعاء
store(). كل شيء آخر في وحدة التحكم يبقى كما هو. الملفات تصل إلى الـ bucket في S3 تحت البادئةuploads/.php// Store on S3 $path = $request->file('image')->store('uploads', 's3'); // Make the file publicly readable when uploading $path = $request->file('image')->storePublicly('uploads', 's3'); // Generate the public URL $url = Storage::disk('s3')->url($path); // returns: https://your-bucket.s3.amazonaws.com/uploads/abc123.jpg
نصائح ومحاذير
- لا تثق أبدًا باسم الملف المُرسَل من العميل — دع Laravel يولّده تلقائيًا، أو عقّمه بنفسك قبل استدعاء <code>storeAs()</code>. قد تحتوي الأسماء الأصلية على أحرف اجتياز المسار.
- تحقق من نوع MIME من جانب الخادم باستخدام قاعدة <code>mimetypes</code> (مثلًا <code>mimetypes:image/jpeg,image/png</code>) لا فقط بالامتداد — الامتدادات سهلة التزوير.
- للملفات الخاصة (عقود وفواتير)، خزّن على قرص <code>local</code> وقدّمها عبر وحدة تحكم تتحقق من التصريح — لا تستخدم قرص <code>public</code> للوثائق الحساسة أبدًا.
- احذف الملفات القديمة عند استبدالها: <code>Storage::disk('public')->delete($post->image_path)</code> قبل حفظ المسار الجديد — وإلا سيمتلئ تخزينك بصمت.
- على S3، استخدم Presigned URLs عبر <code>Storage::temporaryUrl($path, now()->addMinutes(5))</code> للملفات الخاصة بدلًا من جعل كامل الـ bucket عامًا.
خاتمة
أصبح بإمكانك الآن التعامل مع رفع الملفات من البداية إلى النهاية في Laravel — من تقديم النموذج المُتحقَّق منه إلى التخزين على القرص العام المحلي أو S3، وتوليد الرابط الصحيح للعرض. الخطوة الطبيعية التالية هي إضافة معالجة الصور (تغيير الحجم، القص، التحويل إلى WebP) باستخدام spatie/image أو intervention/image قبل تخزين الملف.