احتمالا قبلا با فرم‌ها در php کار کرده اید و با متد POST آشنا هستید. وقتی قرار است اطلاعاتی از کاربر دریافت کنیم از یک فرم با متد POST استفاده می کنیم.

این اطلاعات داخل چند فیلد با تگ input قرار داده و ارسال می‌شود به سمت سرور.

اما برای ارسال فایل چطور؟

تفاوت در ارسال فایل با فرم معمولی این است که فرم ما باید این قابلیت را داشته باشد که کاربر فایل را در آن از سیستم خودش انتخاب کند.

ایجاد فرم آپلود

برای شروع، اول فرم آپلود را درست می‌کنیم.

یک فایل با نام form.php درست می‌کنیم تا فرم آپلود را در آن نمایش بدهیم.

یک تگ formمی‌نویسیم با متد POST.

یک attribute جدید دیگر هم باید به فرم اضافه کنیم به نام enctype. با اضافه کردن این عبارت فرم ما قابلیت ارسال فایل را پیدا میکند. تنها می‌ماند یک دکمه برای انتخاب فایل.

برای این هم یک تگ input با type='file'

 <input type="file" name="upload-file" >

درنهایت کد فرم آپلود ما این شکلی می‌شود:

<form action="upload.php" method="post" enctype="multipart/form-data">
    <div>
      <!-- A field to send favourite title -->
      <label for="">عنوان فایل </label>
      <input name="title" type="text">
    </div>
    <br>
    <div>
      <!-- creates a button for selecting file -->
      <input type="file" name="upload-file">
    </div>
    <br>
    <!-- button for submitting form data -->
    <input type="submit" value="Send File" name="submit">
  </form>

من یک فیلد اضافه برای نوشتن عنوان فایل هم به آن اضافه کرده‌ام.

در آخر هم برای اینکه همه اطلاعات را به سمت سرور بفرسیتم یک دکمه دیگر میسازیم.

من action فرم را به فایل php به نام upload.php گذاشته ام. این فایل کنار فایل فعلی قرار دارد.

فرم آپلود فایل
فرم آپلود فایل

دریافت اطلاعات در سمت سرور

الان اگر روی Choose File کلیک کنید میتوانید یک فایل را انتخاب کنید.

بعد با زدن دکمه send File ، فایل و بقیه اطلاعات فرم به فایل upload.php فرستاده می‌شوند.

دیگر کاری با این فایل form.php نداریم.

حالا ببینیم چطوری باید فایل را سمت سرور دریافت کنیم.

اول با تابع ()vardump یک خروجی از تمام اطلاعاتی که به سمت سرور( فایل upload.php) فرستاده شده است می گیریم.(از تابع vardump فقط برای دیباگ کردن و بررسی درست یا غلط بودن نتیجه کد ها استفاده میکنیم و قرار نیست در برنامه نهایی ما باقی بماند).

حتما می‌دانید برای دریافت اطلاعات فرم هایی که به صورت POST ارسال شده اند از سوپرگلوبال POST_$ استفاده می‌کنیم.

اما این سوپرگلوبال فقط اطلاعات فیلدها را به ما میدهد.

فایل های ارسال شده، در سروپرگلوبال POST_$ نیستند.

فایلهای ارسالی یک سوپرگلوبال مخصوص دارند به نام FILES_$.

پس اینطوری vardumpرا اجرا می کنیم تا هر اطلاعاتی گه همراه فایل آمده برای ما نشان داده شود.

var_dump($_FILES);

الان تمام چیزی که از یک نیاز داریم را نشان داده است.

پی اچ پی اطلاعات فایل را در سوپرگلوبال FILES_$ در یک آرایه ذخیره کرده به نام upload-file (این اسم همان name است که برای تگ input فایل گذاشته ایم.)

اطلاعاتی که به ما نشان داده اینها هستند:

name : اسم فایل

type: نوع یا فرمت فرمت فایل (به این mimetype هم می‌گویند)

tmp_name: محل ذخیره موقت

size: حجم فایل به بایت(byte)

تمام اطلاعاتی که از فایل دریافت کردیم را هر کدام جداگانه در یک متغیر ذخیره می‌کنیم تا راحت تر با آنها کار کنیم.

$filename = $_FILES['upload-file']['name'];
$type = $_FILES['upload-file']['type'];
$tmp_name = $_FILES['upload-file']['tmp_name'];
$size = $_FILES['upload-file']['size'];

وقتی فایل سمت سرور فرستاده میشود پی اچ پی خودکار آن را در یک محلی موقت(tmp_name) ذخیره می کند تا شما دستور آپلود را بدهید و به محلی که میخواهید فرستاده شود.

برای اینکه فایل آپلود شود باید از دستور  move_uploaded_file استفاده کنیم.

به این شکل:

move_uploaded_file($filename,$destination);

تابع دو پارامتر می‌گیرد اسم فایل و آدرس نهایی.

اسم فایل منظور اسمی است که پی اچ پی موقتا به فایل داده همان tmp_name که وقتی وردامپ کردیم آن را دیدیم

پارامتر دوم هم آدرس جایی است که قرار است فایل ذخیره شود.

وقتی دارید مقصد فایل را می‌نویسید باید به صورت کامل و با اسمی که می‌خواهید به علاوه فرمت فایل آن را بنویسید.

نیازی نیست اسم فایل همان اسم قبلی باشد می‌شود اینجا تغییرش داد.

چون من نمیدانم فرمت فایلی که کاربر می فرستد چیست بهتر است همان اول کار فرمت فایل را دریافت کنم.

برای اینکار از کد زیر استفاده میکنم:

$arr = explode('.',$filename);
$file_format = end($arr);

چون همیشه در فایلها بعد از نقطه آخر، فرمت فایل نوشته می‌شود پس اول با تابعexplode آن را به آرایه تبدیل می‌کنیم. بعد با تابع endبخش آخر آرایه که همان فرمت است را در متغیر file_format$ ذخیره می‌کنیم.

حالا اگر بخواهیم اسم فایل را هم جداگانه بگیریم از تابع پیش فرض php به نام basename() استفاده می‌کنیم:
پارامتر اول اسم کامل فایل و پارامتر دوم هم فرمت فایل.

$upload_name = basename($filename,$file_format);

در نهایت این دو را به هم وصل میکنیم تا اسم نهایی فایل در قسمت آپلود درست شود.

$destination =  $upload_name . $file_format;

من اینجا برای مقصد آپلود تنها اسم فایل را نوشتم تا خود پی اچ پی فایل را در همین پوشه‌ای که پروژه قرار دارد آپلود کند. شما می‌توانید یک پوشه uploads بسازید و فایلها را آنجا آپلود کنید یا مسیر کامل دلخواه خودتان را بنویسید.

الان وقت آن است که تابع move_uploaded_file را اجرا کنیم:

move_uploaded_file($tmp_name,$destination);

با اجرای این دستور فایلی که فرستاده شده در آدرسی که من در متغیر destination$مشخص کردم بارگذاری می‌شود.

اینجا چون به آدرس، پوشه خاصی ندادم فایل در همین پوشه ای که فایل های من قرار دارد ذخیره می‌شود.

در پروژه های واقعی آدرس آپلود باید کامل نوشته شود نه آدرس نسبی.

در نهایت تمام کد های ما در فایل upload.php اینها هستند:

<?php
 
$filename = $_FILES['upload-file']['name'];
$type = $_FILES['upload-file']['type'];
$tmp_name = $_FILES['upload-file']['tmp_name'];
$size = $_FILES['upload-file']['size'];
//get file format from file name
$arr = explode('.',$filename);
$file_format = end($arr);
$upload_name = basename($filename,$file_format);
//final name for uploaded file
$destination =  $upload_name . $file_format;
move_uploaded_file($tmp_name,$destination);

حالا زمپ را روشن کنید و فایل form.php را باز کنید و عملیات آپلود را یکبار انجام بدهید.

بعد از ارسال فایل میبینید که در پوشه فایل مورد نظر آپلود شده است.

آپلود فایل در php

کلیت آپلود همین است:

فایل را از کاربر می‌گیرید.

سمت سرور می فرستید

با دستور move_uploaded_file آن را هرجا که خواستید ذخیره می‌کنید

اعتبار سنجی فایل ها قبل از آپلود فایل

به طور کلی هر اطلاعاتی که از کاربر دریافت می‌کنید باید قبل از ذخیره در دیتابیس یا دیسک، اعتبار سنجی شوند. باید چک کنید این همان چیزی است که بایست ارسال می‌شده یا خیر.

از کجا معلوم است کاربر فایل دلخواه شما را بفرستد و فایل بی ربط یا یک فایل آلوده نفرستد؟

یا شاید دوست نداشته باشید فایل ارسالی از یک حجمی بالاتر فرستاده شود.

اینجا دو مثال از اعتبار سنجی یکی برای حجم ارسال فایل و یکی برای فرمت فایل را بررسی می‌کنیم.

محدود کردن ارسال فایل با حجم مشخص

یکی از مقادیری که از سوپرگلوبال FILES_$ دریافت کردیم حجم فایل(size) بود. که آن را در یک متغیر گذاشتیم:

$size = $_FILES['upload-file']['size'];

برای اینکه اپلود فایل با سایز بیشتر از یک مقدار را محدود کنیم کافی است قبل از دستور آپلود آن را با یکif ساده بررسی کنیم. این کد باید قبل از دستور آپلود فایل نوشته شود:

$size_limit = 500000;
if ($size > $size_limit){
    echo "اندازه فایل باید کمتر از 500کیلوبایت باشد";
    die();
}

یک متغیر درست کردم و مقدار مجاز را در آن گذاشتم.

باید به byteاین مقدار را بنویسید اینجا 500 هزار بایت یعنی 500 کیلو بایت.

بعد در یک شرط ifچک کردم که اگر سایز فایل که در متغیر $size قرارش دادیم از مقدار مجاز بیشتر باشد یک پیغام نشان کاربر بده و بعد با دستور dieادامه کد را متوقف کن.

با همین کار ساده می‌شود حجم آپلود فایل را محدود کرد.

محدود کردن فرمت فایل ها

فرض کنید همین کاری که برای سایز فایل کردیم برای فرمت هم انجام دهیم.

من میخواهم فقط فایل های با فرمت مشخص آپلود شوند.

اینجا هم باید قبل از دستور آپلود با یک شرط فرمت فایل را چک کنیم.

مواظب باشید فرمت را از اسم فایل استخراج نکنید.

فرمت باید از متغیر type در سوپرگلوبال FILES_$ بگیرید.

چون کاربر به راحتی میتواند فرمت را در اسم فایل دستکاری کند اما سوپر گلوبال FILES_$ فرمت را از هدر (Header) فایل می‌خواند و کاری با اسم فایل ندارد.

برای مثال اینجا فقط به فایل های pdf اجازه آپلود شدن می‌دهیم.

برای اینکه بفهمیم typeهر فایل دقیقا چطور نوشته می‌شود کافی است یکبار فایل با هر فرمتی که میخواهید را آپلود کنید و vardump($_FILES) را اجرا کنید تا type مخصوص آن نوع فایل را ببینید.

مثلا mimetype فایل های پی دی اف application/pdf است .

با این کد فقط به فایل های پی دی اف اجازه آپلود می‌دهم:

$allowed_type= 'application/pdf';
if ($type != $allowed_type) {
    echo "شما مجاز به اپلود این فایل نیستید";
    die();
}

حالا بیایید کمی کد را بهتر بنویسیم.

با این کد فقط یک نوع فایل چک می‌شود. فرض کنید من بخواهم چند نوع فایل مختلف را اجازه بدهم اینبار چه کار کنم؟

این بار به جای متغیر از یک آرایه استفاده می‌کنم و mimetype های مجاز را در آن می‌گذارم.

بعد چک میکنم که نوع فایل آپلود شده جزو اینها هست یا نه.

$allowed_types= array(
    'application/pdf',
    'image/jpeg',
    'image/png',
);

سه نوع فایل را در یک آرایه نوشته ام.

حالا شرط را می‌نویسیم:

if (!in_array($type,$allowed_types)) {
    echo "شما مجاز به اپلود این فایل نیستید";
    die();
}

تابع in_array اگر یک عبارت در آرایه ای وجود داشت true برمی‌گرداند. من اینجا چک کردم که اگر این مقدار false بود یعنی فایل فرستاده شده جزو اینها نیست. آنوقت پیام خطا نشان دهد و ادامه کد را متوقف کند.

حتما الان متوجه شدید اینطوری چقدر کد تمیز تر شد فردا روزی اگر بخواهید یک فرمت را کم یا زیاد کنید تنها کافی است یک عضو به آرایه ها اضافه کنید یا از آن کم کنید.

حالا اگر بخواهیم باز هم تمیز‌تر کار کنیم بهتر است که قسمت اعتبار سنجی را به جای اینکه همینطوری پشت سر هم قبل تابع move_uploaded_file بنویسیم بیاییم و در یک تابع جداگانه قرار دهیم و قبل از آپلود، آن تابع را صدا بزنیم. اینطوری این تابع را می‌توان برای دفعات بعد هم استفاده کرد.