من یک فرم ثبتنام دارم که کاربر قرار است علاوه بر وارد کردن اطلاعات، چهار عکس را هم آپلود کند. آپلود سه عکس اجباری است و یک عکس اختیاری. من قصد دارم با استاتیک متد Create این کار را انجام دهم. کدهای خودم را به شکل خلاصه قرار دادهام.
لازم به ذکر است قصد دارم تصاویر هر کاربر در دایرکتوری public ذخیره و یک دایرکتوری با شماره پاسپورت هر کاربر که ثبتنام میکند ایجاد شود و آدرس هر تصویر نیز در دیتابیس در فیلدهای متناظر ذخیره شود تا بتوان به راحتی مجدد به آنها دسترسی داشت.
نام تیبل من users است و فیلدهای مربوط به تصاویر نیز به ترتیب image1,image2,image3,image4 هستند.
حالا چطور میتوانم در همین متد این کار را انجام دهم؟
امیدوارم واضح توضیح داده باشم.
فرم من:
<form class="form-horizontal" method="post" action="/student-register/create" enctype="multipart/form-data">
@csrf
<div class="form-group">
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
</div>
<div class="form-group">
<label class="col-sm-4 control-label">شماره گذرنامه</label>
<div class="col-sm-8">
<input type="text" name="passport_number" value="{{ old('passport_number') }}" class="form-control input-lg" dir="ltr" minlength="8" maxlength="9" requirednonow>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">نام و نام خانوادگی</span></label>
<div class="col-sm-8">
<input type="text" name="name" value="{{ old('name') }}" class="form-control input-lg" lang="fa-IR" requirednonow>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Image 1<span class="text-danger"> * </span></label>
<div class="col-sm-8">
<input type="file" name="image1" value="{{ old('image1') }}" class="form-control input-lg" accept="image/jpeg" requirednonow>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Image 2<span class="text-danger"> * </span></label>
<div class="col-sm-8">
<input type="file" name="image2" value="{{ old('image2') }}" class="form-control input-lg" accept="image/jpeg" requirednonow>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Image 3<span class="text-danger"> * </span></label>
<div class="col-sm-8">
<input type="file" name="image3" value="{{ old('image3') }}" class="form-control input-lg" accept="image/jpeg" requirednonow>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Image 4</label>
<div class="col-sm-8">
<input type="file" name="image4" value="{{ old('image4') }}" class="form-control input-lg" accept="image/jpeg">
</div>
</div>
<div class="text-center">
<button name="btnA" class="btn btn-primary btn-lg" type="submit">ارسال</button>
</div>
</form>
کدهای کنترلر من
public function create()
{
$validated_data = Validator::make(request()->all(), [
'passport_number' => 'required|min:8|max:9|alpha_num|unique:users',
'name' => 'required|alpha|min:2',
'image1' => 'mimes:jpeg,jpg|required|max:2048',
'image2' => 'mimes:jpeg,jpg|required|max:2048',
'image3' => 'mimes:jpeg,jpg|required|max:2048',
'image4' => 'mimes:jpeg,jpg|max:2048',
])->validated();
Register::create([
'passport_number' => strtoupper(request('passport_number')),
'name' => request('name'),
'image1' => request('image1'),
'image2' => request('image2'),
'image3' => request('image3'),
'image4' => request('image4'),
]);
}
اول اینکه این مدل کد نویسی اصلا کلین نیست . شما نباید این همه کد رو توی کنترلر بنویسید. میتونید از دیزاین پترن ریپوزیتوری استفاده کنید یا با ساختار کلاس ، استاندارد خودتونو داشته باشید
در نهایت برای آپلود عکستون باید اول تصاویر رو با [filesystem][1] لاراول توی دایرکتوری پابلیک آپلود کنید و در نهایت خروجی متد مربوطه رو که حاوی مسیر منطقی فایل هست توی فیلد های جدولتون ذخیره کنید.
1- اول از هر کار باید یک disk توی فایل سیستمتون (فایل config/filesystem.php) ایجاد کنید اسم این دیسک رو من users میزارم شما هر چیزی که دوست دارید میتونید بزارید :
...
'users' => [
'driver' => 'local',
'root' => public_path('files/users'),
'url' => env('APP_URL').'/files/users',
'visibility' => 'public',
],
...
2- کد خودتون رو به اینصورت اصلاح کنید :
Register::create([
'passport_number' => strtoupper(request('passport_number')),
'name' => request('name'),
'image1' => request()->file('image1')->store('users'),
'image2' => request()->file('image2')->store('users'),
'image3' => request()->file('image3')->store('users'),
'image4' => request()->hasFile('image4') ?
request()->file('image4')->store('users') :
null
]);
اول از همه سپاسگزارم بابت پاسختون آقای عزیزان (@behzad.azizan). خیلی ساده و شفاف موارد رو فرموده بودید و به راحتی همه چیز درست شد.
در رابطه با کدنویسیم باید بگم حتماً همینطور هست که شما گفتید، چون تازه کار با لاراول رو شروع کردم و آشنایی چندانی ندارم و بهانهای شد در مورد دیزاین پترنی که اسم بردید تحقیق و بررسی کنم و دیزاین پترنهای دیگر.
دو سؤال دیگه هم داشتم از خدمتتون
1- معمولاً فایلهایی که تمایل به آپلود داریم رو در دایرکتوری public نریزیم مشکلی ایجاد نمیکنه. منظور اینه که بعد از آپلود روی هاست اشتراکی، اینها در پوشهای قبل از پابلیک قرار میگیرند و آیا این مورد مسئلهای ایجاد نمیکنه؟
2- فرض کنیم در پنل ادمین قصد فراخوانی این تصاویر رو داریم، روال کلی کار به چه صورته و باید به چه آدرسی (مسیری) اشاره داشته باشیم؟ (مثلاً در همین مثالی که زدید و اسم پوشه رو users قرار دادید.) البته در کد اشاره شده ظاهراً.
'users' => [
'driver' => 'local',
'root' => public_path('files/users'),
'url' => env('APP_URL').'/files/users',
'visibility' => 'public',
],
ولی با حذف این کد هم روال آپلود به درستی صورت میگیره. پس این به معنی این است که این کد بیشتر برای دسترسی به پوشه و تصاویر کاربر داره و به طور کلی کاربردش چیه؟
با سپاس
@www.webdata.in
سلام خواهش میکنم
ببینید توی لاراول برای مدیریت فایل ها از امکانی به نام filesystem استفاده شده . فایل سیستم توی لاراول به این شکل هست که میگه بهتره تمام فایل ها در دایرکتوری storage ذخیره بشه .
حالا همون طور که میدونید فایل ها برای اینکه توی وبسرور قابل دسترسی باشن باید حتما در داخل دایرکتوری publichtml (که میتونه معادل public لاراول باشه) باشه و حارج از این دایرکتوری قابل دسترسی نیست .
حالا لاراول برای اینکه این مورد رفع بشه در واقع از امکانی توی سیستم عامل های یونیکسبیس استفاده میکنه به نام symbolic link که در حقیقت یه جور شورتکات به دایرکتوری storage/app از داخل دایرکتوری public ایجاد میکنه.
اما در نهایت این شما هستید که الگوریتم برنامه رو میچینید و طبق الگوریتم خودتون جلو میرید . مثلا من برای فایل هایی که باید توسط کاربران دانلود شوند سیمبولیک لینک ایجاد نمیکنم . یه اکشن تعریف میکنم و یه لایه امنیتی برای دسترسی به فایل ها توسط کاربران میزارم که بدونم کاربری که میواد فایل رو دانلود کنه کی هست و آیا اجازه دسترسی به این فایل رو داره یا نه در صورتی که اجازه دسترسی داشت هدر ست میکنم و فایل برای کاربر قابل دانلود هست در غیر این صورت بهش خطای 404 میدم یا خطای 403
البته این الگوریتم برای سایت هایی که به نوعی دانلودی هستن مناسب هست و شاید اصلا مناسب شما نباشه
دیسک شما چون داخل دایکرتوری public ایجاد شده نیازی به سیمبلیک لینک نیست.
برای دانلود فایل هم کد زیر رو امتحان کنید :
Storage::disk('users')->url($user->image1)
دستور بالا آدرس URL فایلتون رو برمیگردونه .
توصیه میکنم داکیومنت رو مطالعه فرمایید
مجدداً سلام @behzad.azizan
{{ Storage::disk('users')->url($student->image1) }}
من کد بالا رو که فرموده بودید چک کردم. مستندات رو هم مطالعه کردم. ولی نتونستم مشکلم رو برطرف کنم. وقتی در view وارد میکنم مسیر زیر رو بهم میده:
http://localhost/files/users/users/A12222222/sApZxcxGPYzVGhh8NchVZmWGjbAZbo1ZaCSQ7W0N.jpg
الان انتظار میره که url به صورت زیر برگردانده بشه
http://localhost:8000/users/A12222222/sApZxcxGPYzVGhh8NchVZmWGjbAZbo1ZaCSQ7W0N.jpg
که البته با ویرایش تنظیماتی بهم قبلاً گفته بودید به شکل زیر مرتفع میشه:
'users' => [
'driver' => 'local',
'root' => public_path('files/users'),
'url' => env('APP_URL').'/',
'visibility' => 'public',
],
چون مسیر آپلود تصاویر به طور کلی به شکل زیر هست که تصاویر یک کاربر در فولدری با عنوان شماره شناسه خودشون در دایرکتوری users و به درستی هم دارن آپلود میشن:
storage\app\users\
باید برای نمایش تصاویر یک route مجزا بنویسم؟ و اینکه مشکل کار کجاست که نمایش تصاویر به درستی صورت نمیگیره؟
(لازم به ذکر است که سایر اطلاعات به درستی از دیتابیس خوانده میشوند و در view نمایش داده شدهاند. مسیر تصویر هم به صورت زیر در دیتابیس ذخیره شده است):
users/A12222222/sApZxcxGPYzVGhh8NchVZmWGjbAZbo1ZaCSQ7W0N.jpg
پیشاپیش ازتون سپاسگزارم
@www.webdata.in
سلام
مقدار فیلد APP_URL رو در فایل .env باید درست کنید.
این مقدار رو روی localhost:8000 بزارید آدرس دهیتون درست میشه
لاراول از این ثابت برای پیدا کردن آدرس دامین پروژه شما استفاده میکنه
آیا مایل به ارسال نوتیفیکیشن و اخبار از طرف راکت هستید ؟