توسعه دهنده ارشد وب
کار کردن با فایلها در فریمورک لاراول
آپلود (بارگذاری) فایل یکی از ویژگیهای رایج در وب است. (از آپلود آواتارها و تصاویر شخصی گرفته تا ارسال اسناد و مدارک از طریق ایمیل و غیره) و در واقع نحوه مدیریت فایلها بخش مهمی از هر نرمافزار تحت وب است.
فهرست مطالبی که در این نوشته مرور خواهیم کرد:
- مقدمه و آمادهسازی
- لاراول چگونه فایلها رو مدیریت میکند؟
- آپلود فایلها در لاراول
- تفاوت بین دیسکهای محلی (لوکال) و عمومی (پابلیک)
- آپلود چندین فایل
- اعتبارسنجی فایلهای آپلودی
- انتقال فایلها به فضای ابری
- ارسال فایل به صورت ضمیمه ایمیل
- استوریج فِساد
- دستکاری فایلهای تصویری (فیلترها و کراپینگ)
- فولدر ها
- نتیجه گیری
مقدمه و آمادهسازی
مدیریت فایلها یکی دیگر از ویژگیهایی است که لاراول آن را در اکوسیستم خود به سادگی پیادهسازی کرده است. قبل از اینکه شروع کنیم به چند چیز نیاز داریم. ابتدا یک پروژه لاراولی.. چندین راه برای ایجاد یک پروژه جدید لاراولی وجود دارد; اما اکنون به سراغ کامپوزر (Composer) میرویم.
کامپوزر چیست؟ گاهی اوقات نیاز به استفاده از پکیجها و لایبرریهای سایر برنامهنویسان داریم که به صورت اپنسورس عرضه شدهاند تا بتوانیم به جای آنکه خود اقدام به نوشتن مثلاً کلاس خاصی کنیم، از کدهایی که قبلاً توسط سایر دولوپرها نوشته شده و آزمایش خود را پس دادهاند استفاده نماییم و کامپوزر هم ابزاری است که فرایند مدیریت وابستگیها (Dependency Management) را برای دولوپرهای زبان برنامهنویسی PHP تسهیل میکند. به طور خلاصه، کامپوزر یک ابزار کامندلاین است که در آن با استفاده از یکسری دستورات از پیش تعریف شده میتوان به مدیریت منابع خارجی پرداخت; برای نصب کامپوزر در سیستم عاملهای مختلف میتوانید به وبسایت رسمی این ابزار٬ به آدرس www.getcomposer.org مراجعه کنید.
ابتدا برای نصب لاراول:
با استفاده از دستور بالا پروژه لاراولی جدیدی به نام files ایجاد خواهیم کرد. سپس احتاج داریم چند پکیج (وابستگی) را نصب کنیم. توجه داشته باشید که این وابستگیها فقط برای اهداف خاصی مورد استفاده قرار میگیرند مثل:
- ذخیره سازی فایلها روی سرویس ابری S3 آمازون
- دستکاری (Manipulation) فایلهای تصویری (کراپ٬ تغییر اندازه٬ فیلترها و ...)
برای نصب وابستگیها:
بعد از نصب این وابستگیها نوبت به ساخت یک صندوق پستی (Inbox) در سرویس Mailtrap میرسه. میلتِرَپ یک سرور SMTP جعلی (fake) برای تیمهای توسعهدهندگان است تا بتوانند ایمیلهای فرستاده شده از محیطهای توسعه و پیادهسازی را بدون ارسال هرزنامه به مشتریان واقعی، مشاهده و به اشتراک بگذارند. پس سری به سایت میلتِرَپ بزنید و یک اینباکس جدید بسازید.
حال در پروژه لاراولی خود به فایل resources/view/welcome.blade.php
مراجعه کنید و کد های زیر را به محتویات تگ <body> اضافه کنید:
برای فرم آپلود, اترِبیوتهای enctype و method بسیار مهم هستند چون مرورگر از طریق این اترِبیوتها ٬ نوع برخورد با درخواست ارسالی را مشخص میکند و action نیز آدرسی است که اطلاعات فرم ما به آن ارسال و پردازش میشود.
و CSRF@ مختص فریمورک لاراول هست و یک فیلد اینپوت مخفی به بدنه فرم ما اضافه میکند به همراه یک توکِن که لاراول از آن برای تصدیق مجاز بودن درخواست ارسالی توسط کاربر استفاده میکند.
اگر CSRF@ توکن داخل بدنه فرم ما وجود نداشته باشه٬ لاراول ما را به صفحهای با عنوان "صفحه به دلیل عدم فعالیت منقضی شده است" ریدایرکت میکنه.
خیلی خب٬ حالا که وابستگیهای پروژه رو از سر راه برداشتیم.. شروع میکنیم.
لاراول چگونه فایلها رو مدیریت میکند؟
توسعه وب را آنگونه که ما در سال ۲۰۱۹ میشناسیم به سرعت در حال تغییر و رشد است; بدین گونه که در بیشتر موارد برای حل یک مشکل راهکار های زیادی وجود دارند. برای مثال میزبانی و ذخیره فایلها رو در نظر بگیرید. در حال حاظر ما راههای زیادی برای ذخیره کردن فایلها داریم که این بازه شامل میزبانی فایلها در اکانتهای میزبانی وب, سرویس شخصی FTP, سرویسهای اَبری, سرویس GFS گوگل و ... میشود.
از آنجا که لاراول فریمورکی ست که انعطاف پذیری را تشویق میکند, این فریمورک دارای روشی بومی برای مدیریت ساختار انواع فایل هاست. چه فایل شما لوکال باشه, چه روی سرویسهای ابری گوگل یا آمازون باشه, لاراول از تمام اینها پشتیبانی میکنه.
راه حل لاراول برای این مشکل این است که هر یک از روشهایی که در بالا اشاره شد را به عنوان یک دیسک (Disk) نام گذاری میکند. هر سیستم ذخیرهسازی فایل که می توانید به آن فکر کنید به عنوان یک دیسک در لاراول برچسب گذاری شده و شناخته میشود. در این راستا٬ لاراول بعد از نصب و به صورت پیشفرض با پشتیبانی بومی برخی از دیسک ها همراه است... مانند: local, public, Amazon S3, Rackspace, FTP و تمام این موارد به دلیل استفاده از پکیج Flysystem ممکن هستند.
اگر فایل config/filesystems.php
را باز کنید٬ انواع دیسکهای موجود را بهمراه تنظیمات پیکربندی آنها مشاهده میکنید.
آپلود فایلها در لاراول
از قسمت مقدمه در بالا، ما یک فرم با یک ورودی فایل آماده برای پردازش داریم. پس نیاز به تعریف یک مسیر (Route) از نوع POST و به نام processUpload داریم. پس فایل routes/web.php
را باز کرده و کدهای زیر را اضافه میکنیم:
کاری که کد بالا انجام میدهد٬ گرفتن فیلد عکس (photo) از کلاس ریکوئست و ذخیره آن در فولدر photos میباشد. ()dd (مخفف Die and Dump) یکی از توابع کمکی لاراول است که بعد از اجرای اسکریپت آن را از بین برده و نتایج را چاپ میکند. با استفاده از متد store فایل مربوطه با یک نام رندوم ذخیره میشود. این فایل برای من به نام "photos/0ViuX8yrhA6gwXZmacq4TFtpVYUCw6VTRJhfn.png" ذخیره شده. برای پیدا کردن این فایل ، به فولدر app/storage
مراجعه کنید و فایل آپلود شده را مشاهده خواهید کرد.
اگر الگوی نامگذاری پیشفرض که توسط لاراول ارائه شده را دوست ندارید٬ میتوانید با استفاده از متد storeAs از الگوی نامگذاری خودتان استفاده کنید.
با اجرای کد بالا٬ فایل آپلودی برای من به نام "profile-photo-1552481867.png" ذخیره شد.
تفاوت بین دیسکهای محلی (لوکال) و عمومی (پابلیک)
در فایل config/filesystems.php
دیسکها به دو دسته لوکال و پابلیک تقسیم شدهاند. به صورت پیش فرض لاراول از پیکربندی دیسک لوکال یا محلی استفاده میکند. تفاوت اصلی بین دیسک محلی و عمومی این است که ٬ دیسک محلی خصوصی است و از مرورگر قابل دسترسی نیست در حالی که دیسک عمومی از مرورگر قابل دسترسی است.
از آنجا که دیسک عمومی در فولدر storage/app/public
قرار دارد و آدرس اصلی سرور لاراول در دیسک عمومی ست٬ احتیاج داریم تا storage/app/public
را به فولدر public
لاراول متصل کنیم و این امر از طریق اجرای دستور زیر امکان پذیر میباشد.
آپلود چندین فایل
از آنجاییکه لاراول یک تابع برای آپلود چندین فایل ارائه نمی دهد، ما خودمان باید این کار را انجام دهیم; و این خیلی متفاوت از آنچه ما تا به حال انجام داده ایم نیست، و ما فقط به یک حلقه نیاز داریم.
ابتدا فیلد اینپوت فایل را در درون فرم تغییر میدهیم تا چندین فایل را پذیرا باشد:
حال هنگامی که میخواهیم request->file('photos')$
را پردازش کنیم٬ بجای یک فایل این متغیر حاوی آرایه ای شامل instance های کلاس UploadedFile میباشد. بنابراین نیاز داریم آرایه را از طریق یک حلقه پردازش و هر فایل را ذخیره کنیم.
پس از اجرای این کد، من آرایه زیر را دریافت کردم (چون یک فایل GIF و یک فایل PNG آپلود کردم)
اعتبارسنجی فایلهای آپلودی
اعتبارسنجی (Validation) برای آپلود فایلها بسیار مهم و حیاتی ست. به غیر از جلوگیری از آپلود انواع فایلهای اشتباه توسط کاربران, اعتبارسنجی برای رعایت موارد امنیتی هم لازم است. برای مثال: گزینهای به نام cgi.fix_pathinfo=1
در پیکربندی PHP وجود دارد.. اما این گزینه چه کاری میکند؟
هنگامی که با آدرسی مثلhttps://site.com/img/evil.jpg/nonexistent.php
مواجه میشویم٬
PHP فرض میکند nonexistent.php
یک فایل PHP است و سعی خواهد کرد آن را اجرا کند; و هنگامی که متوجه میشود nonexistent.php وجود ندارد, عملکرد این زبان بدین گونهست که سعی میکند مشکل را برطرف کند و بلافاصله فایل evil.jpg
(یک فایل PHP که به عنوان یه فایل JPEG جاسازی شده) را اجرا میکند. از آنجا که evil.jpg در زمان آپلود مورد اعتبار سنجی قرار نگرفته است٬ حالا یک هکر اسکریپتی در اختیار دارد که میتواند به صورت آزادانه روی سرور شما اجرا کند... و این خوب نیست...
برای اعتبارسنجی فایلها در لاراول٬ راههای زیادی وجود دارد. ما برای هرچه سادهتر بودن مثال اعتبارسنجی را درون Route ها انجام میدهیم.
با قطعه کد بالا ما از لاراول میخواهیم به ترتیب زیر اعتبارسنجی را اعمال کند:
- ارائه فیلدی به نام
photo
الزامیست. - نوع داده ما فایل٬ و قابل آپلود باشد.
- فایل موردنظر باید یک تصویر باشد.
- فایل مربوطه باید شامل یکی از انواع MIME های مشخص شده باشد.
- حجم فایل حداکثر ۲۰۴۸ کیلوبایت باشد.
و برای اعتبارسنجی که شامل چندین فایل شود٬ میتوانید از کد زیر استفاده کنید.
حال هنگامی که یک کاربر مخرب سعی کند یک فایل مخفی را آپلود کند; تأیید صحت فایل در اعتبارسنجی شکست میخورد. و اگر به هر دلیل عجیب و غریبی شما گزینه cgi.fix_pathinfo
را فعال بگذارید٬ دیگر از لحاظ امنیتی مشکلی برای شما به وجود نمیآورد.
اگر سری به مستندات اعتبارسنجی در لاراول بزنید٬ تمام دستهها, قوانین و حالتهای مختلف اعتبارسنجی را مشاهده خواهید کرد.
انتقال فایلها به فضای ابری
خیلی خوب- سایت شما در حال حاظر رشد کرده است٬ بازدیدکنندگان زیادی دارید و تصمیم میگیرید وقت آن رسیده تا سایت را به فضای برای منتقل کنید و یا شاید از همان ابتدا، تصمیم گرفتید که فایلهایتان را در سرور جداگانه ذخیره کنید... خبر خوب این است که لاراول بسیاری از ارائه دهندگان سرویسهای ابری را پشتیبانی میکند. در این نوشته ما سرویس ابری S3 آمازون را مثال میزنیم.
پیش از این ما پکیج league/flysystem-aws-s3-v3
را از طریق کامپوزر نصب کردیم. اگر بخواهید از S3 آمازون استفاده کنید٬ لاراول بطور خودکار دنبال این پکیج میگردد و آن را لود میکند و در صورت نیافتنش یک خطا بر میگرداند. برای آپلود فایلها روی سرویس ابری S3 به صورت زیر عمل میکنیم:
ممکن است پیش ار آنکه شما نوع ذخیره فایلها را به سرویس ابری تغییر دهید٬ کاربران سایت شما فایلهایی را آپلود کرده باشند. هیچ مشکلی نیست; میتوانید بخش های بعدی این نوشته را برای زمانی که فایلها از قبل وجود دارند بررسی کنید.
نکته: برای استفاده از این سرویس شما باید آن را بدرستی در فایلconfig/filesystems.php
پیکربندی کنید
ارسال فایل به صورت ضمیمه ایمیل
قبل از انجام این کار نیاز داریم تا سرویس ارسال ایمیل را در لاراول پیکربندی کنیم. در فایل env
که شامل تنظیمات لاراول هست٬ شما قسمتی شبیه زیر را مشاهده خواهید کرد
ما نیاز به یک نام کاربری و رمز عبور داریم که می توانیم از Mailtrap.io دریافت کنیم. میلتِرَپ برای آزمایش ایمیل ها در طول توسعه واقعا مفید است زیرا شما مجبور نیستید ایمیل خود را با هرزنامه شلوغ کنید. همچنین می توانید صندوق های پستی را با اعضای تیم به اشتراک بگذارید یا صندوق های پستی مجزا ایجاد کنید.
ابتدا یک حساب کاربری ایجاد کنید و وارد شوید:
- یک صندوق ورودی جدید ایجاد کنید.
- برای باز کردن صندوق پستی کلیک کنید.
- نام کاربری و رمز عبور را از قسمت SMTP کپی کنید.
سپس نام کاربری و رمز عبوری که دریافت کردیم را, به فایل env
اضافه میکنیم.
حال mailable خود را ایجاد کنید.
سپس متد build
آن را ویرایش کرده و کدهای زیر را اضافه کنید:
همانطور که در متد بالا مشاهده میکنید، ما مسیر فایل مطلق را به متد attach
به همراه یک آرایه اختیاری پاس میدهیم که از طریق آن میتوانیم نام پیوست را تغییر دهیم یا حتی هدر های سفارشی را اضافه کنیم. حال باید بدنه ایمیل خود را بسازیم.
یک فایل جدید به نام resources/views/emails/file_downloaded.blade.php
ایجاد کنید و محتویات دلخواه خود را برای بدنه ایمیل درون آن قرار دهید. حال در فایل routes/web.php
یک راوت جدید برای ارسال ایمیل بوجود میآوریم.
بعد از اجرای کد بالا٬ اگر سری به میلتِرَپ بزنید ایمیل ارسالی بهمراه فایل فایل ضمیمه شده را مشاهده خواهید کرد.
استوریج فِساد
در یک اپلیکیشن٬ ما همیشه فایلها را از طریق بارگذاری پردازش نمیکنیم. گاهی اوقات، ما تصمیم می گیریم آپلود فایلها را روی سرویس ابری ارائه کنیم تا زمانی که کاربر عمل خاصی را به اتمام برساند; و در مواقعی دیگر ممکن است ما پیش از تعویض دیسک به نوع اَبری٬ از قبل فایلهایی را روی دیسک لوکال ذخیره کرده باشیم. برای این گونه موارد لاراول یک فِساد ذخیرهسازی (Storage Facade) مناسب در نظر گرفته و ارائه داده است.
فِساد ها در لاراول٬ در واقع اسامی مستعار کلاسها هستند و به کلاس خاصی در قسمتی از اپلیکیشن ما اشاره دارند. یعنی میتوانیم بجای استفاده ازSymfony\File\Whatever\Long\Namespace\UploadedFile
براحتی ازUploadedFile
استفاده کنیم.
در زیر برخی از متدهای کاربردی فِساد Storage را برای فایلها بررسی میکنیم.
دستکاری فایلهای تصویری (فیلترها و کراپینگ)
برای تغییر اندازه تصاویر، اضافه کردن فیلترها، افزودن متن و غیره... لاراول نیاز به کمک خارجی دارد. ما به یک پکیج به نام intervention/image نیاز داریم. ما قبلا این پکیج را نصب کردهایم اما برای مرجع:
از آنجا که لاراول بعد از نسخه ۵.۵ میتواند به صورت خودکار پکیجها را شناسایی کند نیازی به هیچ گونه پیکربندی و تنظیماتی نداریم.
برای تغییر اندازه تصویر :
شما میتوانید به مستندات این پکیج سری بزنید و تغییرات و تمام افکتهایی را که میتوانید به تصاویر اضافه کنید را ببینید.
فولدر ها
لاراول همچنان هِلپر متدهای سودمندی برای کار کردن با فولدرها ارائه میدهد. تمام این متدها بر اساس Iterator
های PHP
پیادهسازی شدهاند، بنابراین آنها حداکثر عملکرد را ارائه می دهند.
در زیر برخی از متدهای کاربردی فِساد Storage را برای فولدرها بررسی میکنیم.
نتیجه گیری
فایل ها بخش مهمی از هر اپلیکیشن تحت وب هستند. در فریمورک لاراول با استفاده از پکیج فوقالعاده Flysystem (ساخته شده توسط Frank de Jonge ) مدیریت فایلها بر روی هر بستری بسادگی امکانپذیر است و به لطف این سیستم شما میتونید از انواع نوع دیسکهایی که لاراول در اختیارتون قرار داده، استفاده کنید و یا حتی دیسک شخصی سازیشده خودتون رو بوجود بیارید.
سعی من بر این بود که مطلبی کوتاه و مفید در زمینه مدیریت فایلها در لاراول بنویسم که تقریبا تمام موارد استفاده از فایل رو شامل بشه. هر چند نوشته کوتاهی نشد، امیدوارم مفید بوده باشه. اگر نکتهای فراموش شده، میتونید در کامِنتها بهش اشاره کنید.
مطلبی دیگر از این انتشارات
چرا لاراول را انتخاب کنیم؟
مطلبی دیگر از این انتشارات
چگونه در لاراول «بدنویسی» کنیم؟!
مطلبی دیگر از این انتشارات
ایجاد اکسترافیلد در لاراول