article

آموزش نحوه آپلود فایل با PHP و ای جکس (Ajax)

ajax-php-file-upload

انجام آپلود در صفحات وب از طریق فرم های HTML یکی از شیوه های متداولی است که برای ارسال و ذخیره سازی فایل ها در فرمت های مختلف از سمت سیستم کاربر به حافظه سرور کاربرد دارد، در این شیوه در حالت معمول اگر بخواهیم فایلی را به سرور ارسال کنیم با اتمام فرایند آپلود آدرس صفحه مرورگر به طور خودکار تغییر کرده و به آدرس مقصدی که در قسمت action تگ form در نظر گرفته ایم منتقل می شود، این ساز و کار در عمل فایل را آپلود می کند اما ممکن است با توجه به رابط کاربری مد نظر ما شیوه بهینه نباشد و اینکه آدرس صفحه پس از آپلود رفرش یا منتقل شود کاربران برنامه را به زحمت بیندازد، خوشبختانه برای تغییر این حالت روش هایی وجود دارد که به کمک آنها می توانیم بدون اینکه صفحه رفرش یا منتقل شود فایل را به سرور ارسال کنیم و از آنجایی که بیشتر این روش ها مبتنی بر تکنیک ای جکس (Ajax) یا شبیه سازی شده از فرایند ای جکس است در این آموزش قصد داریم به نحوه آپلود فایل با برنامه نویسی PHP و Ajax بپردازیم.

ساز و کار آپلود فایل در وب


قبل از پرداختن به ادامه این آموزش لازم است برای داشتن درک صحیحی از فرایند آپلود فایل در وب به طور مختصر به ساز و کار آن اشاره ای داشته باشیم.
دسترسی به فایل های کاربران در وب از لحاظ امنیتی یک استثناء و مجوزی پر ریسک است اما کمتر سرویس تحت وبی است که بی نیاز از این امکان باشد، بر همین مبنا جهت حفظ حریم خصوصی کاربران این قابلیت صرفا از طریق کدهای HTML و عناصر زیرمجموعه تگ form وجود دارد که حق انتخاب و آپلود فایل در دست کاربر باشد تا اگر خود او تمایل داشت فایل های مورد نظرش را انتخاب و تحت پروتکل های انتقال داده در وب به سرور ارسال نماید، در سرور این فایل ها توسط برنامه نویسی سمت سرور مانند زبان PHP یا موارد مشابه مدیریت می شوند و اگر همه چیز درست باشد فایل بر روی حافظه سخت افزاری یا به عبارتی هارددیسک سرور ذخیره شده و از این لحظه قابل استفاده است.

چگونه یک فایل را با ای جکس آپلود کنیم؟


پس از بکارگیری تکنیک های مبتنی بر ای جکس از سال 2000 میلادی توسط برخی توسعه دهندگان وب و استفاده همگانی از این فناوری (با معرفی نسخه بتای گوگل مپ) در سال 2005 تا چندین سال بعد اگرچه از بسیاری جنبه ها پیشرفت کرده بود و می توانستیم به کمک آن مقادیر موجود در فرم های HTML را بدون رفرش صفحه به سرور ارسال کنیم اما در مورد ارسال فایل مشکل وجود داشت و ای جکس (آبجکت XHR مخفف XMLHttpRequest) نمی توانست از این قابلیت پشتیبانی کند و متد مناسبی که مرورگرهای استاندارد از آن پشتیبانی کنند عملا وجود نداشت، تا مدتها برای کاربران گزینه های جایگزین دیگری در دسترس بود از جمله استفاده از کتابخانه های جاوا اسکریپتی نظیر جی کئوری (jQuery) و موتولز (Mootools) که با جلوه ها و محیط کاربری زیبا می توانستند فایل ها را آپلود کنند، هنوز هم این روش ها در موارد خاص خود کاربرد دارند اما مهم بود که ای جکس صرف نیز بتواند عملیات آپلود فایل را برای برنامه های تحت وب انجام دهد، این نیاز رفته رفته باعث توسعه API جدیدی تحت عنوان FormData شد که از طریق آن می توانیم تمام مواردی که از طریق تگ form در صفحات HTML به سرور ارسال کنیم را با ای جکس انجام دهیم، از آنجایی که برخی مرورگرهای قدیمی از آبجکت های این API به درستی پشتیبانی نمی کنند در این آموزش علاوه بر روش اصلی از روشی شبیه سازی شده بر اساس فرایند ای جکس اما مبتنی بر جاوا اسکریپت و تکنیک iframe نیز استفاده خواهیم کرد.

آپلود فایل با استفاده از آبجکت های FormData و Ajax


نیاز وب مدرن و تکیه بیشتر برنامه ها به شیوه ای جکس معرفی API جدیدی تحت عنوان FormData را با هدف رفع نواقص موجود درپی داشت که به کمک آبجکت های آن می توانیم همان طور که در شیوه متداول فرم های وب را از سمت کاربر به سرور ارسال می کنیم با ای جکس نیز این کار را انجام دهیم، در آبجکت های FormData اطلاعات به صورت کلید و مقدار تنظیم و در نهایت با متد XMLHttpRequest.send قابل ارسال هستند، کلید نام فیلدها و مقدار داده ای است که ارسال می شود و می تواند از نوع رشته، عدد، آرایه، فایل و... باشد، در ادامه نحوه آپلود فایل بدون رفرش صفحه با FormData و Ajax را بررسی می کنیم.

کد HTML برای آپلود فایل با FormData و Ajax


اولین قسمتی که برای ایجاد امکان آپلود فایل با FormData و Ajax مورد نیاز است کدنویسی سمت کاربر با استفاده از تگ form در HTML است که در نمونه صفحه زیر این کار را انجام داده ایم، این فایل را با نام index.html ذخیره می کنیم:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>وبگو | آپلود فایل بدون رفرش صفحه با formdata</title>
<!-- Webgoo.ir -->
</head>
<body>
<noscript>جاوا اسکریپت در مرورگر شما غیر فعال است!</noscript>
<form id="upload-form" class="inline" action="ajax-formdata-upload.php" method="post" enctype="multipart/form-data">
<label for="user-file">انتخاب فایل:</label>
<input type="file" id="user-file" name="user-file" onchange="uploadInfo(0);">
</form>
<button class="inline" onclick="uploadStart('upload-form', 'user-file');">آپلود فایل</button>
<div id="file-name"></div>
<div id="file-size"></div>
<div id="file-type"></div>
<div id="upload-process"></div>
<div id="upload-result"></div>
<hr>
نکته: این برنامه صرفا جنبه آموزشی داشته و استفاده از آن بدون تسلط بر PHP و توابع مربوط به فایل، توصیه نمی شود.
<br><br>
[توسعه یافته توسط <a href="https://webgoo.ir" title="وبگو | آموزش برنامه نویسی و مهارتهای وب" target="_blank">Webgoo.ir</a>]
</body>
</html>
توضیح:
- همان طور که مشخص است در قسمت action فرم آدرس فایل PHP تنظیم شده است،البته در تکنیک ای جکس این قسمت لازم نیست و URL اصلی در متد open درج می شود که در ادامه خواهیم دید.
- تگ form باید یک ID منحصربفرد داشته باشد، از این آی دی برای انتخاب فرم در هنگام فراخوانی FormData استفاده خواهیم کرد.
- فایل از طریق تگ input از نوع file برای آپلود انتخاب می شود، با انتخاب فایل توسط کاربر رویداد onchange اجرا و تابع جاوا اسکریپتی uploadInfo با آرگیومنت 0 فراخوانی می شود، همان طور که مشخص است تگ فایل نیز یک ID خاص دارد که در کدهای جاوا اسکریپت از آن استفاده خواهیم کرد.
- برای شروع فرایند آپلود دکمه از نوع button در نظر گرفته ایم که پس از کلیک کاربر تابع uploadStart را فراخوانی می کند، این تابع دو آرگیومنت دارد که به ترتیب آی دی فرم و آی دی تگ مربوط به فایل است.
- برای مدیریت اطلاعاتی که قبل، حین و پس از آپلود می توانیم به کاربر نمایش دهیم تگ های div در نظر گرفته ایم که هر کدام آی دی مخصوص به خود دارند.

کد CSS و جاوا اسکریپت آپلود فایل با FormData و Ajax


کدهای HTML به تنهایی صرفا چارچوب اولیه برنامه را تشکیل می دهند و جلوه های ظاهری و تعاملی و همچنین امکان آپلود به صورت بدون رفرش صفحه به کمک استایل CSS و کدنویسی جاوا اسکریپت امکانپذیر می شود که در نمونه زیر این کار را انجام داده ایم، این کدها را قبل از بسته شدن تگ head در فایل index.html اضافه می کنیم:
<style>
body {
    font-family:Tahoma, Geneva, sans-serif;
    font-size:12px;
    direction:rtl;
}
a{
    text-decoration:none;
    color:#06C;
}
a:hover {
    color:#666;
}
.inline {
    display:inline-block;
}
.ok {
    display:block;
    padding:4px;
    border:0px #666 solid;
    color:#090;
    width:300px;
}
.error {
    display:block;
    padding:4px;
    border:0px #666 solid;
    color:#C00;
    width:300px;    
}
</style>
<script>
function uploadInfo(clear){
    var file = document.getElementById('user-file').files[0];
    var elm_name = document.getElementById('file-name');
    var elm_size = document.getElementById('file-size');
    var elm_type = document.getElementById('file-type');
    var elm_process = document.getElementById('upload-process');
    var elm_result = document.getElementById('upload-result');

    if(file && clear === 0){
        var file_size = 0;
        
        if(file.size > 1024 * 1024){
            file_size = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
        } else{
            file_size = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
        }
          
        elm_name.innerHTML = 'Name: ' + file.name;
        elm_size.innerHTML = 'Size: ' + file_size;
        elm_type.innerHTML = 'Type: ' + file.type;
        elm_process.innerHTML = '';
        elm_result.innerHTML = '';
    } else{
        elm_name.innerHTML = '';
        elm_size.innerHTML = '';
        elm_type.innerHTML = '';
    }
}

function uploadStart(form_id, file_id){
    if(document.getElementById(file_id).value != ''){
        var xhr = new XMLHttpRequest();
        var form = document.getElementById(form_id);
        var fd = new FormData(form);

        xhr.upload.addEventListener("progress", uploadProgress, false);
        xhr.addEventListener("abort", uploadCanceled, false);
        xhr.addEventListener("error", uploadFailed, false);
        xhr.addEventListener("load", uploadEnd, false);

        xhr.open("POST", "ajax-formdata-upload.php");
        xhr.send(fd);
    } else{
        alert('لطفا ابتدا یک فایل انتخاب کنید!');
    }
    
    return false;
}

function uploadProgress(evt){
    if(evt.lengthComputable){
        var percent_complete = Math.round(evt.loaded * 100 / evt.total);
        document.getElementById('upload-process').innerHTML = percent_complete.toString() + '%';
    } else{
        document.getElementById('upload-process').innerHTML = 'محاسبه درصد آپلود ممکن نیست!';
    }
}

function uploadCanceled(evt){
    alert("آپلود فایل توسط کاربر منتفی یا مرورگر ارتباط را قطع کرد!");
}

function uploadFailed(evt){
    alert("بروز خطا در فرآیند آپلود فایل!");
}

function uploadEnd(evt){
    var result = evt.target.responseText;
    document.getElementById('upload-result').innerHTML = result;
    uploadInfo(1);
}
</script>
توضیح:
- در استایل CSS این نمونه کد جهت جلوگیری از پیچیده شدن کار صرفا چند کلاس ساده در نظر گرفته ایم که ویژگی های کلی صفحه و رنگ متن خطا یا پیغام آپلود موفق را مشخص می کند، قاعدتا برای استفاده کاربردی از برنامه می توانیم بر اساس سلیقه این قسمت را تکمیل کنیم.
- کدهای جاوا اسکریپت شامل چند تابع با نامگذاری دلخواه uploadInfo، uploadStart، uploadProgress، uploadCanceled، uploadFailed و uploadEnd است که هر کدام در مرحله و تحت شرایط خاصی فراخوانی می شوند.
- تابع uploadInfo در دو قسمت و با دو مقدار مختلف (0 یا 1 برای آرگیومنت clear) فراخوانی می شود، پس از انتخاب فایل توسط کاربر رویداد onchange اجرا شده و تابع با آرگیومنت 0 فراخوانی می شود، 0 در اینجا یعنی اطلاعات مربوط به فایل (نام، اندازه و نوع) در بلاک های div در نظر گرفته شده نمایش داده شود، اگر این مقدار 1 باشد اطلاعات این بلاک ها حذف می شود که این کار در پایان فرآیند آپلود در تابع uploadEnd صورت می گیرد.
- uploadStart تابع اصلی برنامه است که وظیفه فراهم سازی ساز و کار ارسال درخواست ای جکس و آپلود فایل با آبجکت FormData را بر عهده دارد، این تابع دو آرگیومنت دارد که به ترتیب آی دی فرم و آی دی فیلد فایل را مشخص می کند، تابع uploadStart پس از کلیک کاربر بر روی دکمه آپلود فراخوانی می شود، نکته مهم در این تابع استفاده از addEventListener برای اختصاص عملیات هایی در هنگام تغییر وضعیت رویدادهای درخواست ای جکس است که شامل دریافت مقادیر درصدی آپلود شده (رویداد progress)، منتفی شدن آپلود (رویداد abort)، بروز خطا (رویداد error) و پایان فرآیند آپلود (رویداد load) است، در هر کدام از این رویدادها تابع متناظر با آن فراخوانی می شود.
- تابع uploadProgress برای محاسبه و نمایش مقدار حجم آپلود شده به صورت کیلوبایت، درصد و... است، در این تابع از دو متد loaded و total استفاده کرده ایم، مقادیر در این دو متد بر اساس بایت است که با محاسبات ساده ریاضی در نهایت میزان پیشرفت فرآیند آپلود را به صورت درصدی نمایش می دهیم، قاعدتا با در اختیار داشتن مقدار عددی حجم آپلود شده در لحظه می توانیم شکل ظاهری کار را به نحو دلخواه و سفارشی طراحی کنیم، به فرض بلاکی با رنگ متمایز برای خط آپلود (Progress Bar) کدنویسی و با جاوا اسکریپت (متد style) میزان عرض بلاک را متناسب با درصد آپلود شده به روز کنیم.
- توابع uploadCanceled و uploadFailed برای مواردی است که یا آپلود توسط کاربر متوقف می شود یا اینکه به هر دلیل اشکالی در فرآیند وجود داشته که آپلود کامل نمی شود.
- در صورت آپلود موفق در نهایت تابع uploadEnd فراخوانی می شود، این تابع پاسخ سرور را در بلاک div هدف چاپ و با فراخوانی مجدد تابع uploadInfo با مقادیر 1 برای آرگیومنت clear موارد اضافه موجود در صفحه را نیز حذف می کند.

کد PHP برای پردازش فایل آپلود شده با FormData و Ajax


ساختارهای برنامه های وب معمولا از دو بخش اصلی سمت کاربر و سمت سرور تشکیل شده اند که تا اینجا کدهای سمت کاربر (HTML، JavaScript و Ajax) را نوشتیم، در گام بعدی در فایلی با نام دلخواه ajax-formdata-upload.php دستورات زیر را درج می کنیم تا مرحله بررسی و ذخیره سازی فایل آپلود شده در حافظه هارد دیسک سرور به درستی انجام شود:
<?php
//برای جلوگیری از خطاهای ناخواسته موارد زیر در فایل php.ini بررسی و مطابق نیاز تنظیم شده باشند:
/*
file_uploads = برابر On یا 1 تنظیم شده باشد.
upload_max_filesize = حداکثر حجم معتبر فایل، آپلود فایل های بزرگتر توسط PHP رد می شود!
post_max_size = حداکثر حجم معتبر ارسال داده در متد POST، باید بیشتر از پارامتر upload_max_filesize تعیین شود.
max_file_uploads = حداکثر تعداد فایل قابل آپلود در یک ارسال.
*/


//فرمت های مجاز
$valid_extension = array('jpg', 'png', 'gif');

//نوع فایل های مجاز
$valid_mime = array('image/jpeg', 'image/png', 'image/gif');

//تعیین فرمت، نوع فایل یا اندازه مجاز و سایر پارامترها
if(in_array(pathinfo($_FILES["user-file"]["name"], PATHINFO_EXTENSION), $valid_extension) && in_array($_FILES["user-file"]["type"], $valid_mime) && $_FILES["user-file"]["size"] < 1048576) {
    //بررسی سایر خطاهای سرور
    if ($_FILES["user-file"]["error"] > 0) {
        echo '<div class="error">خطا: ' . $_FILES["user-file"]["error"] . '</div><br>';
    } //بررسی وجود یا عدم وجود فایل با نام مشابه در سرور    
    else {
        if(file_exists('user-files/' . $_FILES["user-file"]["name"])) {
            echo '<div class="error">این فایل در حال حاضر وجود دارد!</div><br>';
        } //انتقال و ذخیره فایل در سرور    
        else {            
            if(move_uploaded_file($_FILES["user-file"]["tmp_name"], 'user-files/' . $_FILES["user-file"]["name"])) {
                echo '<div class="ok">فایل با موفقیت آپلود شد!</div><br>';
                echo 'فایل: ' . $_FILES["user-file"]["name"] . '<br>';
                echo 'نوع: ' . $_FILES["user-file"]["type"] . '<br>';
                echo 'اندازه: ' . ($_FILES["user-file"]["size"] / 1024) . ' Kb<br>';
                echo 'دایرکتوری: user-files/' . $_FILES["user-file"]["name"]. '<br>';
            } else {
                echo '<div class="error">ذخیره سازی فایل در سرور با مشکل مواجه شد!</div><br>';
            }
        }
    }
} //خطای تعیین فرمت، نوع یا اندازه مجاز و سایر پارامترها
else {
    //print_r( $_FILES["user-file"]);
    
    if($_FILES["user-file"]["size"] > 1048576) {
        echo '<div class="error">حجم فایل خیلی زیاد است! اندازه مجاز 1 مگابایت.</div>';
    } else {
        echo '<div class="error">فرمت یا نوع فایل مجاز نیست!</div>';
    }
}
?>
توضیح:
- برای دریافت فایل آپلود شده در PHP از متغیر از پیش تعریف شده FILES که به صورت آرایه است استفاده می کنیم، کلید اول آرایه نام فیلد input است که فایل در آن انتخاب و ارسال می شود، کلید دوم آرایه پارامترهای مربوط به نام، نوع، حجم، اندازه و... فایل آپلود شده است.
- پارامترهای فایل آپلود شده در آرایه FILES می تواند شامل موارد زیر باشد:
<?php
//نام فایل آپلود شده
$_FILES['user-file']['name'];
//نوع MIME فایل مانند image/jpeg
$_FILES['user-file']['type'];
//حجم فایل به بایت
$_FILES['user-file']['size'];
//نام موقت فایل در سرور
$_FILES['user-file']['tmp_name'];
//شماره خطای برگردانده شده توسط سرور
$_FILES['user-file']['error'];
?>
- خطاهای مربوط به کار با فایل اعدادی از 1 تا 8 هستند، اگر همه چیز درست باشد عدد صفر برگردانده می شود، در زیر به طور مختصر به این خطاها اشاره می کنیم:
UPLOAD_ERR_OK: عدد 0 برگردانده می شود و این به معنی عدم خطا است.
UPLOAD_ERR_INI_SIZE: عدد 1 برگردانده می شود، فایل آپلود شده از حداکثر حجم تنظیم شده در تنظیمات php.ini بیشتر است.
UPLOAD_ERR_FORM_SIZE: عدد 2 برگردانده می شود، فایل آپلود شده از حداکثر حجم تنظیم شده در فرم HTML بیشتر است (در فرم HTML می توانیم فیلد مخفی با نام MAX_FILE_SIZE داشته باشیم و در قسمت value حداکثر حجم مجاز را به بایت تعیین کنیم، البته در حال حاضر این روش قابل اطمینان نیست و باید حتما در سرور مجدد اعتبارسنجی با PHP صورت گیرد).
UPLOAD_ERR_PARTIAL: عدد 3 برگردانده می شود، فایل به صورت ناقص آپلود شده است.
UPLOAD_ERR_NO_FILE: عدد 4 برگردانده می شود، هیچ فایلی آپلود نشد.
UPLOAD_ERR_EMPTY: عدد 5 برگردانده می شود، فایل آپلود شده صفر بایت است یا فیلد خالی می باشد.
UPLOAD_ERR_NO_TMP_DIR: عدد 6 برگردانده می شود (تنها در نسخه 4.3.10 و بالاتر)، مفسر PHP نمی تواند پوشه tmp را پیدا کند.
UPLOAD_ERR_CANT_WRITE: عدد 7 برگردانده می شود (تنها در نسخه 5.1.0 و بالاتر)، مفسر PHP نمی تواند فایل را ذخیره کند.
UPLOAD_ERR_EXTENSION: عدد 8 برگردانده می شود (تنها در نسخه 5.2.0 و بالاتر)، یکی از الحاقات PHP مانع آپلود فایل شده است، استفاده از ()phpinfo ممکن است به رفع مشکل کمک کند.
- برای بررسی پسوند (Extension) فایل ها از تابع pathinfo با آرگیومنت PATHINFO_EXTENSION استفاده می کنیم.
- علاوه بر بررسی پسوند فایل باید نوع MIME آن را نیز بررسی کنیم، بدین منظور از پارامتر type برای FILES استفاده می کنیم.
- اندازه مجاز تعیین شده در این نمونه کد 1 مگابایت (معادل 1048576 بایت) است.
- تابع file_exists بررسی می کند که آیا فایل ارسال شده از قبل در دایرکتوری مورد نظر وجود دارد یا خیر.
- اگر همه چیز درست باشد نهایتا PHP با تابع move_uploaded_file فایل را در دایرکتوری مورد نظر (در اینجا فولدر user-files) ذخیره می کند.

دانلود کد آپلود فایل با PHP به شیوه FormData و Ajax


در لینک زیر کدهای بالا را به اضافه تنظیمات کاملتر در یک بسته جهت دانلود قرار داده ایم، پس از دریافت فایل کافی است آن را روی لوکال هاست یا سرور اجرا کنیم:
دانلود کد آپلود فایل با PHP به شیوه FormData و Ajax - حجم: کمتر از 5 کیلوبایت
نکته: این برنامه صرفا جنبه آموزشی داشته و استفاده از آن بدون تسلط بر PHP و توابع مربوط به فایل توصیه نمی شود.

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


اگرچه امروزه استفاده از API جدیدتر FormDate و ارسال مقادیر فرم در بستر ای جکس روش بهینه و مورد پسند توسعه دهندگان وب است و توسط اغلب مرورگرها پشتیبانی می شود اما ممکن است به دلایلی از جمله استفاده اغلب کاربران یک برنامه از مرورگرهای قدیمی و عدم پشتیبانی کامل این مرورگرها از آبجکت های زیر مجموعه FormDate یا به دلایل دیگر همچنان نیاز به روش های جایگزین مانند ترکیب جاوا اسکریپت و تکنیک iframe احساس شود، به همین دلیل جهت آشنایی بیشتر در ادامه آموزش این روش را نیز بررسی می کنیم.
ajax-file-uploading.jpg

کد HTML برای آپلود فایل با تگ iframe


در شیوه iframe فرم آپلود به صورت فریم در صفحه اصلی قرار می گیرد، به این صورت با کمک جاوا اسکریپت می توانیم فرآیند ارسال فرم را در بستر فریم داخلی انجام دهیم تا صفحه اصلی تغییر نکند و به اصطلاح رفرش نشود، بدین منظور نمونه فرم HTML زیر را در فایلی با نام index.html کدنویسی کرده ایم:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>وبگو | آپلود فایل بدون رفرش صفحه با iframe</title>
<!-- Webgoo.ir -->
</head>
<body>
<noscript>جاوا اسکریپت در مرورگر شما غیر فعال است!</noscript>
<form action="ajax-iframe-upload.php" method="post" enctype="multipart/form-data" target="upload-target" onsubmit="return uploadStart(this.form, 'user-file');">
<label for="user-file"></label>
<input type="file" id="user-file" name="user-file">
<input type="submit" value="آپلود فایل">
</form>
<div id="upload-process"><img src="loading.gif" height="16" width="16" alt="loading"> در حال پردازش...</div>
<div id="upload-form"></div>
<iframe id="upload-target" name="upload-target" class="frame"></iframe>
</body>
</html>
توضیح:
- در قسمت action فرم، آدرس فایل PHP یا URL مقصد را درج می کنیم، فایل های آپلود شده به این آدرس ارسال، پردازش و مدیریت می شوند.
- در قسمت متد ارسال فایل از متد POST استفاده خواهیم کرد، متد POST برخلاف GET برای ارسال پارامترها در پس زمینه (بدون امکان روئیت) کاربرد دارد.
- بخش مربوط به enctype (مخفف Encoding Type) و مقادیر multipart/form-data این امکان را به مرورگر خواهد داد تا فایل را به صورت بخش بخش شده به سرور انتقال دهد، در حالت معمول و به طور پیش فرض مرورگر از مقادیر application/x-www-form-urlencoded استفاده می کند که برای انتقال فایل و داده های حجیم مناسب نیست.
- قسمت مربوط به target به جهت استفاده از تکنیک iframe قرار داده شده که مقادیر آن در واقع آی دی iframe (در اینجا upload-target) است، گفتیم که در روش فریم فایل از طریق تگ iframe و بدون رفرش صفحه اصلی ارسال می شود، لذا بستر ارسال فرم را با پارامتر target تعیین می کنیم.
- قسمت onsubmit و مقادیر آن مربوط به فراخوانی تابع جاوا اسکریپتی است که هنگام ارسال فرم اجرا می شود و وظیفه اعتبارسنجی خالی نبودن فیلد فایل و تغییر استایل بلاک مربوط به نمایش پیام ها به حالت visible (قابل روئیت) را برعهده دارد.
- برای ایجاد امکان انتخاب و ارسال فایل باید از تگ input و نوع file استفاده کنیم، ذکر این نکته لازم است که مقادیر و استایل دکمه انتخاب فایل (Choose File) به صورت پیش فرض توسط مرورگرها تعیین می شود و برای تغییر آن باید از تکنیک CSS و جاوا اسکریپت استفاده کرد.
- نهایتا با در نظر گرفتن دکمه از نوع submit فرم را ارسال می کنیم، نکته مهم اینکه نوع دکمه ارسال فایل باید حتما submit باشد چون برای اجرای تابع جاوا اسکریپتی خود از رویداد onsubmit استفاده کرده ایم.
- بلاک های div که در پائین تگ form ایجاد کرده ایم برای مدیریت نمایش پیام در حال پردازش، پیغام خطا یا موفقیت آمیز بودن فرآیند آپلود و انتقال فایل به سرور است.
- تگ iframe را نیز برای دریافت پیام سرور بعد از آپلود فایل در قسمت انتهایی کدها در نظر گرفته ایم که دلخواه و قابل سفارشی سازی است.

کد CSS و جاوا اسکریپت در تکنیک آپلود با iframe


برای اینکه برنامه ما به صورت دلخواه و به درستی کار کند باید تنظیمات و کنترل کاملتری روی آن اعمال کنیم، بدین منظور از کدهای CSS جهت سفارشی سازی ظاهر کار و برنامه نویسی جاوا اسکریپت (JavaScript) جهت مدیریت رفتارهای تعاملی و ارسال فایل و دریافت پاسخ به شکل زیر در فایل index.html استفاده می کنیم:
<style>
body{
    font-family:Tahoma, Geneva, sans-serif;
    font-size:12px;
    direction:rtl;
}
a{
    text-decoration:none;
    color:#06C;
}
a:hover{
    color:#666;
}
.ok {
    display:block;
    padding:4px;
    border:0px #666 solid;
    color:#090;
    width:300px;
}
.error {
    display:block;
    padding:4px;
    border:0px #666 solid;
    color:#C00;
    width:300px;    
}
#upload-process{
    z-index:1000;
    visibility:hidden;
}
.frame{
    width:300px;
    height:100px;
    border:0px;    
}
</style>
<script>
function uploadStart(form, file){
    if(document.getElementById(file).value != ''){
        document.getElementById('upload-process').style.visibility = 'visible';
        return true;
    } else{
        alert('لطفا ابتدا یک فایل انتخاب کنید!');
        return false;
    }
}

function uploadEnd(check){
    var result = '';
      
    if (check == 1){
        result = '<span class="ok">فایل با موفقیت آپلود شد!<\/span>';
    } else {
        result = '<span class="error">انتقال فایل به سرور انجام نشد!<\/span>';
    }
      
    document.getElementById('upload-process').style.visibility = 'hidden';
    document.getElementById('upload-form').innerHTML = result;
}
</script>
توضیح:
- استایل CSS تنظیمات مربوط به ظاهر عناصر HTML را مدیریت می کند و با تغییر در مقادیر کلاس و آی دی به راحتی می توانیم ویژگی های سفارشی را متناسب با سلیقه و نیازمان اعمال کنیم.
- کد جاوا اسکریپت بالا دو تابع ساده دارد، تابع اول با نام uploadStart با کلیک بر روی دکمه ارسال فرم فراخوانی می شود و در صورتی که فیلد فایل خالی نباشد استایل بلاک div با آی دی upload-process را از حالت hidden به حالت مرئی یا visible تبدیل می کند، در تابع دوم (uploadEnd) یک عدد که پس از ارسال فرم از کدهای PHP دریافت می شود را بررسی می کنیم و متناسب با مقدار آن پیام و اطلاعاتی به کاربر نمایش خواهیم داد،اگر این مقدار 1 باشد پیام موفقیت و در غیر اینصورت پیغام خطا تنظیم می شود.
نکته: تابع uploadEnd به صورت داینامیک فراخوانی می شود، یعنی قسمت فراخوانی آن ابتدا در خروجی کدهای صفحه index.html وجود ندارد اما پس از ارسال فرم در انتهای فایل ajax-iframe-upload.php و در فریم چاپ می شود.
- در اینجا برای مقداردهی پیغام ها در بلاک div با آی دی upload-form از متد innerHTML استفاده کرده ایم.

کد PHP برای پردازش فایل آپلود شده در تکنیک iframe


پس از اینکه کاربر فرم را ارسال می کند در سمت سرور باید کدی داشته باشیم که بتواند فایل را دریافت و فرآیند آپلود را مدیریت کند، در PHP متغیر از پیش تعریف شده (Predefined Variable) با نام FILES وجود دارد که بدین منظور مورد استفاده قرار می گیرد، با این توضیح کدهای زیر را در فایلی با نام ajax-iframe-upload.php درج می کنیم:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>وبگو | فایل سرور برای پردازش آپلود</title>
<!-- Webgoo.ir -->
<style>
body{
    font-family:Tahoma, Geneva, sans-serif;
    font-size:12px;
    direction:rtl;
}
.response-text{
    font-style:italic;
}
</style>
<?php
//برای جلوگیری از خطاهای ناخواسته موارد زیر در فایل php.ini بررسی و مطابق نیاز تنظیم شده باشند:
/*
file_uploads = برابر On یا 1 تنظیم شده باشد.
upload_max_filesize = حداکثر حجم معتبر فایل، آپلود فایل های بزرگتر توسط PHP رد می شود!
post_max_size = حداکثر حجم معتبر ارسال داده در متد POST، باید بیشتر از پارامتر upload_max_filesize تعیین شود.
max_file_uploads = حداکثر تعداد فایل قابل آپلود در یک ارسال.
*/


//فرمت های مجاز
$valid_extension = array('jpg', 'png', 'gif');

//نوع فایل های مجاز
$valid_mime = array('image/jpeg', 'image/png', 'image/gif');

//تعیین فرمت، نوع فایل یا اندازه مجاز و سایر پارامترها
if(in_array(pathinfo($_FILES["user-file"]["name"], PATHINFO_EXTENSION), $valid_extension) && in_array($_FILES["user-file"]["type"], $valid_mime) && $_FILES["user-file"]["size"] < 1048576) {
    //بررسی سایر خطاهای سرور
    if ($_FILES["user-file"]["error"] > 0) {
        echo '<div class="response-text">خطا: ' . $_FILES["user-file"]["error"] . '</div><br>';
        $check = 0;
    } //بررسی وجود یا عدم وجود فایل با نام مشابه در سرور    
    else {
        if(file_exists('user-files/' . $_FILES["user-file"]["name"])) {
            echo '<div class="response-text">این فایل در حال حاضر وجود دارد!</div><br>';
            $check = 0;
        } //انتقال و ذخیره فایل در سرور    
        else {          
            if(move_uploaded_file($_FILES["user-file"]["tmp_name"], 'user-files/' . $_FILES["user-file"]["name"])) {
                echo 'فایل: ' . $_FILES["user-file"]["name"] . '<br>';
                echo 'نوع: ' . $_FILES["user-file"]["type"] . '<br>';
                echo 'اندازه: ' . ($_FILES["user-file"]["size"] / 1024) . ' Kb<br>';
                echo 'دایرکتوری: user-files/' . $_FILES["user-file"]["name"]. '<br>';
                $check = 1;
            } else {
                echo '<div class="response-text">ذخیره سازی فایل در سرور با مشکل مواجه شد!</div><br>';
                $check = 0;
            }
        }
    }
} //خطای تعیین فرمت، نوع یا اندازه مجاز و سایر پارامترها
else {
    //print_r( $_FILES["user-file"]);
    
    if($_FILES["user-file"]["size"] > 1048576) {
        echo '<div class="response-text">حجم فایل خیلی زیاد است! اندازه مجاز 1 مگابایت.</div>';
    } else {
        echo '<div class="response-text">فرمت یا نوع فایل مجاز نیست!</div>';
    }
    
    $check = 0;
}
?>
<script>
window.top.window.uploadEnd(<?php echo $check; ?>);
</script>
</head>
</html>
توضیح:
- برای دریافت فایل آپلود شده در PHP از متغیر از پیش تعریف شده FILES که به صورت آرایه است استفاده می کنیم، کلید اول آرایه نام فیلد input است که فایل در آن انتخاب و ارسال می شود، کلید دوم آرایه پارامترهای مروبط به نام، نوع، حجم، اندازه و... فایل آپلود شده است.
- پارامترهای فایل آپلود شده در آرایه FILES می تواند شامل موارد زیر باشد:
<?php
//نام فایل آپلود شده
$_FILES['user-file']['name'];
//نوع MIME فایل مانند image/jpeg
$_FILES['user-file']['type'];
//حجم فایل به بایت
$_FILES['user-file']['size'];
//نام موقت فایل در سرور
$_FILES['user-file']['tmp_name'];
//شماره خطای برگردانده شده توسط سرور
$_FILES['user-file']['error'];
?>
- خطاهای مربوط به کار با فایل اعدادی از 1 تا 8 هستند، اگر همه چیز درست باشد عدد صفر برگردانده می شود، در زیر به طور مختصر به این خطاها اشاره می کنیم:
UPLOAD_ERR_OK: عدد 0 برگردانده می شود و این به معنی عدم خطا است.
UPLOAD_ERR_INI_SIZE: عدد 1 برگردانده می شود، فایل آپلود شده از حداکثر حجم تنظیم شده در تنظیمات php.ini بیشتر است.
UPLOAD_ERR_FORM_SIZE: عدد 2 برگردانده می شود، فایل آپلود شده از حداکثر حجم تنظیم شده در فرم HTML بیشتر است (در فرم HTML می توانیم فیلد مخفی با نام MAX_FILE_SIZE داشته باشیم و در قسمت value حداکثر حجم مجاز را به بایت تعیین کنیم، البته در حال حاضر این روش قابل اطمینان نیست و باید حتما در سرور مجدد اعتبارسنجی با PHP صورت گیرد).
UPLOAD_ERR_PARTIAL: عدد 3 برگردانده می شود، فایل به صورت ناقص آپلود شده است.
UPLOAD_ERR_NO_FILE: عدد 4 برگردانده می شود، هیچ فایلی آپلود نشد.
UPLOAD_ERR_EMPTY: عدد 5 برگردانده می شود، فایل آپلود شده صفر بایت است یا فیلد خالی می باشد.
UPLOAD_ERR_NO_TMP_DIR: عدد 6 برگردانده می شود (تنها در نسخه 4.3.10 و بالاتر)، مفسر PHP نمی تواند پوشه tmp را پیدا کند.
UPLOAD_ERR_CANT_WRITE: عدد 7 برگردانده می شود (تنها در نسخه 5.1.0 و بالاتر)، مفسر PHP نمی تواند فایل را ذخیره کند.
UPLOAD_ERR_EXTENSION: عدد 8 برگردانده می شود (تنها در نسخه 5.2.0 و بالاتر)، یکی از الحاقات PHP مانع آپلود فایل شده است، استفاده از ()phpinfo ممکن است به رفع مشکل کمک کند.
- برای بررسی پسوند (Extension) فایل ها از تابع pathinfo با آرگیومنت PATHINFO_EXTENSION استفاده می کنیم.
- علاوه بر بررسی پسوند فایل باید نوع MIME آن را نیز بررسی کنیم، بدین منظور از پارامتر type برای FILES استفاده می کنیم.
- اندازه مجاز تعیین شده در این نمونه کد 1 مگابایت (معادل 1048576 بایت) است.
- تابع file_exists بررسی می کند که آیا فایل ارسال شده از قبل در دایرکتوری مورد نظر وجود دارد یا خیر.
- اگر همه چیز درست باشد نهایتا PHP با تابع move_uploaded_file فایل را در دایرکتوری مورد نظر (در اینجا فولدر user-files) ذخیره می کند.

دانلود کد آپلود فایل با PHP به شیوه iframe


در لینک زیر کدهای بالا را به اضافه تنظیمات کاملتر در یک بسته جهت دانلود قرار داده ایم، پس از دریافت فایل کافی است آن را روی لوکال هاست یا سرور اجرا کنیم:
دانلود کد آپلود فایل با PHP به شیوه iframe - حجم: کمتر از 5 کیلوبایت
نکته: این برنامه صرفا جنبه آموزشی داشته و استفاده از آن بدون تسلط بر PHP و توابع مربوط به فایل توصیه نمی شود.
sectionدسته بندی: آموزش کاربردی » Ajax
related مطالب بیشتر:
» اعتبار سنجی همزمان فرم با آژاکس (Ajax) و PHP
» لیست داینامیک پیشنهاد کلمات، مبتنی بر ای جکس، PHP و MySQL
» ارسال اطلاعات فرم با ای جکس (Ajax) و نمایش پیام در حال پردازش
» ساخت قابلیت امتیازدهی با PHP و Ajax
» نمایش داینامیک و صفحه به صفحه مطالب با ای جکس (Ajax)
commentنظرات (۱۳۶ یادداشت برای این مطلب ارسال شده است)
more یادداشت های جدید بر اساس تاریخ ارسال در انتهای یادداشت های موجود نمایش داده می شوند.
نویسنده: محسن
۲۳:۴۲ ۱۳۹۵/۰۵/۱۱
با سلام خدمت استاد گرامی
من می خوام نوع فایل رو محدود کنم به فایل
rar و zip و application/rar و application/zip رو به کدهام اضافه کردم ولی نمی دونم جریان چیه که با اینکه فایل های با پسوند rar و zip رو انتخاب می کنم آپلود نمیشن!
ولی اگه فرمت octet-stream رو به کدهام اضافه کنم آپلود میشن!!!
نکته قابل توجه اینه که فرمت های زیادی از فایل ها با این octet-stream مجوز میگیرن و آپلود میشن و به نظرم از لحاظ امنیت جالب نیست.
مثلا فایل با پسوند php با این application/octet-stream مورد قبول واقع شده و آپلود میشه و ممکنه این فایل دارای کد مخرب باشه.
پاسخ: 
قاعدتا هیچ مشکلی بی علت نیست! ابتدا باید با دستور زیر نوع MIME Type فایل مورد نظر را به دست بیاورید:
echo $_FILES['user-file']['type'];
سپس مطابق نمونه کد، پارامتر مورد نظر خود را اضافه کنید، در صورتی که این روند را بدون اشتباه انجام دهید، نباید مشکلی وجود داشته باشد، در غیر اینصورت کدهای خود را به ایمیل سایت ارسال کنید تا بررسی گردد.
نویسنده: حسام آقاجانی
۰۰:۱۴ ۱۳۹۵/۰۸/۱۵
سلام خسته نباشید من یک فرم ارسال اطلاعات ساختم که یک قسمت مربوط به ارسال فایل داره کد رو نوشتم ولی مشکل داره ممنون میشم مشکلش رو بهم بگید :
کد صفحه ی اصلی :
حذف شد
و اینم کد script.php :
حذف شد
ارسال نوشته ها به دیتابیس انجام میشه اما فایل در پوشه backup ذخیره نمیشه .
خیلی ممنون
پاسخ: 
کد شما خطای
Notice: Undefined index: attachment
دارد که برای رفع آن باید پارامتر زیر را به تگ form خود اضافه کنید تا فایل به همراه فرم ارسال شود:
enctype="multipart/form-data"
نکته: دایرکتوری backup باید در ریشه اسکریپت موجود باشد!
نویسنده: بهرام
۱۳:۳۲ ۱۳۹۵/۰۸/۳۰
دوستان عزیز بنده صفحه ای دارم که داری چهار تب مختلف هستش به غیر تب اول، در سه تب دیگر هر کدوم دارای یک فرم با تعداد سه فیلد ورودی (Input) هستش که با زدن دکمه ارسال اطلاعات وارد دیتابیس میشن فقط مشکلم اینکه در این سه فرم که در سه تب مجزا هستن باید یه آپلودر ajax یا jqurey هم باشه به این شرح
1- پس از انتخاب فایل، فایل مورد نظر شروع به بارگزاری بکنه (یعنی دکمه بارگزاری نداشته باشم انتخاب شد بارگزاری شروع بشه)
2- پس از بارگزاری حتما تصوری از بارگزاری درست نمایش داده بشه مثل یه تیک و اگر فایل تصویر بود یه عکس 150px X 150px از نمایش داده بشه به کاربر
3- در هین بارگزاری امکان کنسل کردنش باشه
4- در صورت امکان پروگرس بار هم باشه اما اگر کدها رو زیاد میکنه یه عکس GIF هم نمایش دهنده در حال بارگزاری شدن فرم باشه کافیه
نکته:
1-فقط یه فایل بارگزاری میشه
2-پسوند قابل تنطیم باشه
3-حجم قالب تنطیم باشه
4- برای سه فیلد حجم و چسوند فرق میکنه
فقط کوتاه ترین کد موجود باشه ممنون میشم در ضمن ارسال فرم از متد post استفاده میشه
پاسخ: 
متاسفانه چنین کد آماده ای در اختیار نداریم، لطفا در وب جستجو نمائید، البته در چنین مواردی معمولا نیاز به کمی کدنویسی است!
نویسنده: هنر
۰۲:۲۷ ۱۳۹۵/۰۹/۱۶
سلام خسته نباشی
من دو روزی میشه سر گرم ایمن کردن بخش آپلود اسکریپتم هستم واسه همین زیاد تو اسکریپت های آپلودسنتر میگردم
مثلا تو اسکریپت کلیفا یا کلیجا هرچی!
دیدم وقتی شل در قالب عکس اپلود میکنم میفهمه مثال image.php.jpg و وقتی فرمت شل رو به این شکل تغییر میدم
image.jpg بازم متوجه میشه که این فایل محتویاتش یه عکس نیست و دوباره خطا میده و اجازه اپلود نمیده کداش رو نگاه کردم دیدم این قسمت
function check_mime_type($mime, $this_is_image,$file_path)
{
//This code for images only
//it's must be improved for all files in future !
if($this_is_image == false)
{
return true;
}

$return = false;
$s_items = @explode(':', 'image:mp4:jpg:gif:bmp:jpeg');
foreach($s_items as $r)
{
if(strpos($mime, $r) !== false)
{
$return = true;
break;
}
}

//onther check
//$w = @getimagesize($file_path);
//$return = ($w && (strpos($w['mime'], 'image') !== false)) ? true : false;

//another check
if($return == true)
{
if(@kleeja_filesize($file_path) > 4*(1000*1024))
{
return true;
}

//check for bad things inside files ...
//<.? i cant add it here cuz alot of files contain it
$maybe_bad_codes_are = array('<script', 'zend', 'base64_decode');

if(!($data = @file_get_contents($file_path)))
{
return true;
}

foreach($maybe_bad_codes_are as $i)
{
if(strpos(strtolower($data), $i) !== false)
{
$return = false;
break;
}
}
}

($hook = kleeja_run_hook('kleeja_check_mime_func')) ? eval($hook) : null; //run hook

return $return;
}
و این قسمت دستورش
// check the mime-type for the file
elseif(check_mime_type($_FILES["userImage"]["name"], in_array(strtolower($this->typet), array('gif', 'mp4', 'jpg', 'jpeg', 'bmp')), $_FILES["userImage"]['tmp_name']) == false){
echo'error';
exit();
}
که نمیذاره این اتفاق بیفته حالا من اینو تو اسکریپت خودم قرار دادم تنها مشکل من این دو خط هستش
 $s_items = @explode(':', 'image:mp4:jpg:gif:bmp:jpeg');
elseif(check_mime_type($_FILES["userImage"]["name"], in_array(strtolower($this->typet), array('gif', 'mp4', 'jpg', 'jpeg', 'bmp')), $_FILES["userImage"]['tmp_name']) == false){

($this->typet)

متن خطا :
Fatal error: Using $this when not in object context in C:\xampp\htdocs\uploadvideo.php on line 227
این نکته رو اضافه کنم فرمت فایلی که ارسال میکنم mp4 هستش شماره 1 قسمت image ربطی به لیست فرمت ها داره؟
و در آخر اینکه میشه چند تا دستور شرطی بهم بگید که کامل فایل رو قبل انتقال محتویاتش رو بررسی کنه
سپاس
پاسخ: 
متن خطای دریافتی مربوط به این است که در کدهای شما ظاهرا هیچ کلاسی تعریف نشده اما با this به آبجکت type اشاره شده! باید ببینید اصلا چنین متغیری وجود دارد یا مقداری دارد یا خیر که با خطای دریافتی مشخص است که وجود ندارد، برای تصحیح این کد باید معنی دستوراتی که استفاده می کنید را بدانید و در کدخوانی و فهم برنامه نسبتا قوی باشید، کدهای شما جهت رفع خطا نیاز به دوباره نویسی و تست دارند! به طور مثال برای چک کردن MIME type می توانید از روش های مختلف استفاده کنید، مثال:
http://php.net/manual/en/function.mime-content-type.php
متاسفانه مشکل مربوط به یک مورد نیست که بتوانیم دقیقا راهنمایی کنیم.
نویسنده: محمد
۱۶:۵۹ ۱۳۹۵/۱۱/۰۷
سلام
چطور میشه این فرم سه تا قسمت بارگزاری داشته باشه ؟
ممنون میشم راهنمایی بفرمایید
پاسخ: 
ابتدا باید با نحوه ارسال مقادیر به صورت آرایه و دریافت آنها در PHP آشنا باشید، برای این منظور در انتهای نام فیلدهای آپلود در فرم HTML (به هر تعداد که باشند) علامت [] را اضافه کنید، مثال:
<input name="user-file[]" type="file" multiple="multiple">
<input name="user-file[]" type="file" multiple="multiple">
<input name="user-file[]" type="file" multiple="multiple">
و در سمت سرور نیز با کدهای PHP موارد را در حلقه مدیریت کنید، مثال:
$count = count($_FILES['user-file']['name']);
for($i = 0; $i < $count; $i++){
move_uploaded_file($_FILES["user-file"]["tmp_name"][$i], "user-upload/" . $_FILES["user-file"]["name"][$i]);
}
نویسنده: MMahdiD25
۱۷:۰۰ ۱۳۹۵/۱۱/۰۸
با سلام من در خط های اول فایل php-ajax-upload.php تایپ را برای آپلود فایل های APK به application/vnd.android.package-archive تغییر دادم اما بعد از آپلود فایل با خطای "فرمت فایل مجاز نیست" مواجه می شوم.
باید چکار کنم که مشکل بر طرف بشه؟
با تشکر از راهنماییتان
پاسخ: 
لطفا با دستور زیر نوع MIME فایل آپلود شده را بدست آورده و درج کنید تا راهنمایی بیشتر ممکن باشد:
echo $_FILES["user-file"]["type"];
نویسنده: فرض اله
۱۶:۳۷ ۱۳۹۶/۰۵/۱۷
سلام
مرسي از بابت کد مفيد .
چطور مي توان اندازه طول و عرض عکس را هنگام آپلود در سرور تغيير داد مثلا 400*300 با تشکر
پاسخ: 
تغییر اندازه و ابعاد تصویر در PHP با توابع و روش های مختلف ممکن است، لطفا به لینک زیر مراجعه کنید:
https://stackoverflow.com/questions/14649645/resize-image-in-php
نویسنده: محمد
۰۱:۰۵ ۱۳۹۶/۰۷/۲۴
دوست گران قدر شما صرفاً یک فایل رو ارسال می نمایید و صفحه نیز رفرش می گردد و صرفاً عمل آژاکس انجام نمی شود
پاسخ: 
در متن آموزش توضیح داده شده، در آینده قسمت Ajax به این آموزش اضافه خواهد شد.
نویسنده: محمود
۰۳:۳۱ ۱۳۹۷/۱۱/۲۷
سلام. بنده درمورد اپدیت یا بروز رسانی فایل pdf که بابت چند انتقال ارزی به بانک های اروپا و اسیا داشتم و بدلیل اتمام وقت داده شده جهت انجام امور مالی مربوطه داخل کشور و گذشتن از تاریخ تعیین شده درحال حاضر میباید فایل های pdf شده که مدارک انتقالات ارزی محسوب میشود را مجددا با هماهنگی با بانک خارجی مقصد تراکنش فایل ها را بروزرسانی نمایم لذا جهت چگونگی این بروزرسانی از شما درخواست مینمایم راهنمایی ها و توضیحات لازم را درصورت امکان بفرمایید. سپاسگذارم.
پاسخ: 
بدلیل محدودیت های زمانی متاسفانه امکان قبول سفارشات، مشاوره و... خارج از چارچوب های متداول سایت وجود ندارد.
نویسنده: میثم
۰۰:۴۵ ۱۳۹۹/۰۱/۱۶
سلام استاد عزیز
یه سوال خدمت شما داشتم.
توی
https://www.w3schools.com/php/php_file_upload.asp
که مرجع من برای برنامه نویسی هست از تابع
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
برای شناخت فرمت فایل استفاده شده که راحتتر هست و شما از mime که مثل
$_FILES["user-file"]["type"] == "image/jpeg"
هست استفاده کردین.
خواستم ببینم کدام روش بهتره و امنیت بیشتری داره.
سوال دیگه هم دارم.
من قبلا به کاربران اجازه آپلود فایل jpg و png و gif رو داده بودم و حالا می خوام فرمت های ورد و پی دی اف و زیپ و اکسل و پاورپوینت و mp3 و mp4 و فتوشاپ و فونت رو بدم. از کد
if(($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/png")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "application/pdf")
|| ($_FILES["file"]["type"] == "application/zip")
|| ($_FILES["file"]["type"] == "application/vnd.ms-word")
|| ($_FILES["file"]["type"] == "application/vnd.ms-excel")
|| ($_FILES["file"]["type"] == "application/vnd.ms-powerpoint")
|| ($_FILES["file"]["type"] == "audio/mpeg")
|| ($_FILES["file"]["type"] == "video/mpeg")
|| ($_FILES["file"]["type"] == "image/vnd.adobe.photoshop")
|| ($_FILES["file"]["type"] == "video/mp4")
|| ($_FILES["file"]["type"] == "font/ttf")){
استفاده کردم اما فقط برای تصاویر و پی دی اف جواب میده.
میدونم مشکل از mime هست و باید بقیه موارد مثل
application/vnd.openxmlformats-officedocument.wordprocessingml.document
برای ورد اضافه کنم. خواستم ببینم اگه از کد
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ...........
استفاده کنم ایا امنیت سایتم رو به خطر انداختم؟
پاسخ: 
خیلی ممنون از یادآوری، در خصوص سوال اول تابع pathinfo صرفا به پسوند فایل ارتباط دارد و نوع MIME آن را بررسی نمی کند، به فرض می توانید فایل PHP را با پسوند jpg آپلود کنید، اما روش FILES نوع MIME فایل را صرف نظر از پسوند بررسی می کند، برای برنامه های کاربردی حفظ امنیت لایه های مختلفی دارد و باید حداقل در تئوری هر احتمالی داده شود، به همین دلیل استفاده از هر دو روش با هم توصیه می شود (این پست قدیمی و در لیست ویرایش است، قبلا در انتها یادآوری کرده ایم که مطلب صرفا جنبه آموزشی دارد اما جهت جلوگیری از اشتباه ناخواسته کاربران روش شما را هم به کدها اضافه می کنیم).
در مورد سوال دوم فایلی که پسوند آن تغییر داده شود ماهیت خود را حفظ می کند و در واقع همان فایل قبلی است و بسته به برنامه و بستری که قرار است اجرا شود می تواند مخرب باشد، لذا برای حفظ امنیت برنامه باید سعی کنیم هم نوع و هم پسوند فایل را علاوه بر سایر تدابیر امنیتی مانند دستورات htaccess برای محدود کردن اجرای برخی پسوندها، بررسی کنیم.
نکته: برای دستورات شرطی طولانی می توانید Switch Case را جایگزین کنید.
نویسنده: میثم
۱۱:۰۱ ۱۳۹۹/۰۱/۱۶
ممنونم بابت پاسخ خوب و سریعتون.
پس با این تفاسیر شما
$_FILES["file"]["type"]
رو پیشنهاد می کنید. درسته؟ عملا بخوایم به ماجرا نگاه کنیم تابع اول فقط فرمت رو در سطح نام فایل بررسی می کنه که به راحتی قابل دور زدن هست. اما تابع دوم ماهیت رو بررسی می کنه که البته برای فایلی مثل زیپ هم قابل دور زدن هست!!! مثلا بنده قبلا برای فایل زیپ علاوه بر mime با عبارت
$bytes = file_get_contents($_FILES["file"]["tmp_name"],FALSE,NULL,0,7);
substr($bytes,0,2) == 'PK'
هم دو کاراکتر اول فایل رو چک می کردم اما هم وقت سرور رو زیاد میگیره هم فکر می کنم که حرفه ای نیست!
در هر صورت الان چون به تعداد زیاد فرمت نیاز دارم ، نمی دونم چیکار کنم که کدها هم تر و تمیز از آب در بیاد و هم ایمن باشه!؟؟؟
راستی یه سوال خدمت شما دارم.
بعد از اینکه فایل آپلود شد ، تغییر نام داده میشه به عدد مثلا 234234423.pdf حالا موقع فراخوانی مثل لینک مستقیم باهاشون برخورد می کنم.
فرضا کاربر فلان مطلب رو ارسال کرده و کنارش فایل zip یا jpg یا mp4 یا mp3 و .... آپلود کرده. حالا موقع فراخوانی محتوا ، مطلب نمایش داده میشه و بسته به نوع فرمت فایل به صورت مستقیم تصویر یا صوت یا فیلم پخش میشه و zip هم برای دانلود قرار میگیره. توی header در php هیچ دستوری صادر نکردم و اصلا php درگیر نیست و کاربر مستقیما با وارد کردن آدرس فایل می تونه بهش دسترسی داشته باشه.
خواستم ببینم توی این روش از لحاظ امنیتی موردی وجود نداره؟؟؟؟؟؟ آیا باید کاری توی htaccess انجام بدم؟؟؟؟
ببخشید من وقت شما رو زیاد میگیرم.
پاسخ: 
دو روش را با هم ترکیب کنید در صورت انجام صحیح این کار عملا خطری از این بابت متوجه سرور نخواهد شد، برای بحث جمع و جور شدن کدها یک تابع بنویسید و با دستور Switch Case فرمت های مجاز را بر اساس MIME در نظر بگیرید، یک تابع دیگر نیز برای پسوندهای مجاز بنویسید، این توابع را در صفحه اصلی و هر کجا نیاز بود include کنید کدها از نظر خوانایی مشکلی نخواهند داشت و روش متداول همین است، نگران افت سرعت و عملکرد سرور نباشید سرورها برای اجرای اینگونه دستورات فشار زیادی متحمل نمی شوند مگر اینکه کدنویسی ایرادات دیگری داشته باشد.
در مورد تغییر نام و عدم استفاده از PHP اگر همه موارد اعتبارسنجی را رعایت کنید مشکلی پیش نمی آید، همچنین برای سایت های میزبان فایل بهتر است فایل در ساب دایرکتوری ها ذخیره شود و از آدرس دهی مطلق در PHP و ساب دامین استفاده کنید، به فرض:
$file_path = $_SERVER['DOCUMENT_ROOT'] . "/uploads/user/files/" . basename($_FILES['user-file']['name']);
که ساب دامین آن به فرض به صورت زیر باشد:
uploads.example.com/user/files/test.mp4
نکته 1: در این روش آدرس URL درخواستی را بررسی و اجازه اجرای فایل به جز از مسیر ساب دامین را ندهید، این روش را در عمل امتحان نکرده ایم و ممکن است ایراداتی داشته باشد اما در تئوری باید جواب بدهد!
نکته 2: به صورت پیش فرض معمولا فولدر ساب دامین در دایرکتوری www یا public_html ساخته می شود اما در اکثر سرورها می توانید مسیر فولدر ساب دامین را خارج از دایرکتوری www یا public_html تعریف کنید که در این صورت بهتر است و نیازی به بررسی URL درخواستی هم نخواهد بود.
نویسنده: میثم
۱۱:۵۱ ۱۳۹۹/۰۱/۱۶
ممنونم.
خیلی لطف کردین.
نویسنده: میثم
۱۸:۰۴ ۱۳۹۹/۰۱/۱۶
با سلام مجدد خدمت شما استاد عزیز
من بعد از کلی سرچ به این کدها برای اپلود امن فایل های مختلف رسیدم.
به نظر شما میشه دیگه به این اعتماد کرد؟ یا باز هم جای دور زدن داره؟
$file = $_FILES["file"]["name"];
$Forfi = basename($file);
$FilTy = strtolower(pathinfo($Forfi,PATHINFO_EXTENSION));
if( $FilTy == "gif" || $FilTy == "jpg" || $FilTy == "jpeg" .............. Step 1

if(($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg") || .............. Step 2

if($_FILES["file"]["size"] < 17500000){.............. Step 3

if($_FILES["file"]["error"] == 0){.............. Step 4

if(is_uploaded_file($_FILES["file"]["tmp_name"])){ .............. Step 5

$MimeChk = finfo_file(finfo_open(FILEINFO_MIME_TYPE) , $_FILES["file"]["tmp_name"]);
$AllowTy = array("image/png","image/jpeg","application/pdf");
if(in_array($MimeChk,$AllowTy)){ .............. Step 6

.... rename file and use move_uploaded_file .............. Step 7
........................
در مورد فرمت mp3 و mp4 من هر چی میزنم باز هم ارور mime میده. و اکو گرفتم و مقدار خالی بر می گردونه!!! خواستم ببینم شما می دونید برای mp3 و mp4 کد mime چی میشه؟؟؟؟
پاسخ: 
ظاهرا در گام های برنامه تمام موارد رعایت شده است منتها برای اطمینان از عملکرد صحیح کد نهایی، سعی کنید با روش های مختلف فایل ها را دستکاری و امتحان کنید تا دقیقا مطمئن شوید، در مورد نوع فایل PHP یک تابع پیش فرض برای این کار دارد:
mime_content_type
توضیح و نمونه کدها:
https://www.php.net/manual/en/function.mime-content-type.php
فایل صوتی یا تصویری را در کنار اسکریپت قرار دهید، با آدرس دهی و اجرای اسکرپت نوع آن مشخص می شود.
نویسنده: میثم
۱۱:۴۷ ۱۳۹۹/۰۲/۱۶
سلام یه سوال خدمت شما داشتم.
من با جاوا اسکریپت میخوام بخش فایل توی فرمم رو چک کنم.
توی فرم 2 تا فیلد هست که هر دو تا اپشنال هستن. یکی برای عکس و یکی برای فایل حالا من برای چک همچین کدی نوشتم
```
var pic = document.getElementById('pic').files[0];
var file = document.getElementById('file').files[0];
if(pic.size < 3000000){
if(file.size < 8000000){
```
حالا کد وقتی که کاربر عکس رو آپلود میکنه کار می کنه و برای فیلد فایل ایراد حجم میگیره.
اما وقتی که عکس انتخاب نمیشه ، کد بخش فایل هم کار نمیکنه و هر حجمی رو قبول می کنه.
مشکل از کجاست؟
پاسخ: 
باید به چند نکته توجه داشته باشید، بر اساس کد ارسال شده شرط دوم داخل شرط اول است و این یعنی حتما باید شرط اول برقرار باشد تا شرط دوم اجرا شود، نکته دوم اینکه برای تست و دیدن خطاهای احتمالی در صفحه دکمه F12 را بزنید (کروم، فایرفاکس و...) و از قسمت Console یا Debugger خطاهای دریافتی را حین اجرا بررسی کنید، احتمالا خطای undefined دریافت می کنید، در این صورت یک راه حل این است که شرط را به شکل زیر تغییر دهید:
if(pic != undefined){
if(pic.size < 3000000){
alert(1);
if(file.size < 8000000){
alert(2);
}
}
}else{
alert(3);
}
نویسنده: میثم
۱۶:۲۶ ۱۳۹۹/۰۲/۱۶
سلام
در تکمیل سوالی که خدمت شما عرض شد:
ببینید ما دو تا فیلد فایل داریم توی اولی عکس اپ میشه و توی دومی فایل با فرمت مختلف موقعی که عکس انتخاب میشه جاوا درست عمل می‌کنه اما موقعی که عکس انتخاب نمیشه، انگار بخش اعتبار سنجی فیلد دوم اصلا نادیده گرفته میشه توی شرط اول گفتیم عکس کمتر از حدود ۳ مگ، پس اگه کاربر عکسی رو انتخاب نکنه حجم میشه صفر و شرط اول برقراره اما چرا شرط دوم توی این شرایط اجرا نمیشه؟
پاسخ: 
نحوه بررسی ساختار و ریشه یابی مشکل درست است منتها مفسر جاوا اسکریپت خیلی سختگیر است :) جواب سوال و ایراد کار در یادداشت قبل توضیح داده شد.
more لطفا پیش از ارسال یادداشت نکات زیر را مد نظر داشته باشید:
- موارد غیرمرتبط با مباحث آموزش ها را در فرم منوی "تماس با ما" مطرح و پاسخ را از طریق ایمیل دریافت کنید.
- به سوالات کلی، مبهم و مشکلاتی که تلاشی برای رفع آن نکرده باشید پاسخ مختصر داده خواهد شد.
- کدها و اسکریپت های طولانی را ترجیحا در یک صفحه وب آنلاین قرار دهید تا امکان تست و بررسی وجود داشته باشد.
- از درج عناوین تبلیغاتی در فیلدها خودداری کنید، در صورتی که یادداشت تبلیغاتی تشخیص داده شود حذف خواهد شد.
- تمام یادداشت ها بررسی و زمانی جهت پاسخگویی در نظر گرفته می شود، لطفا از طرح سوالات متعدد خودداری کنید.





5 × 9
 refresh

آخرین دیدگاه ها
more برای دسترسی سریع به یادداشت مربوطه می توانید از لینک مطلب در کادر زیر استفاده کنید.
form عبدالمالت ریالی
در:
سلام علیک میشه از چند فونت در یک صفحه html استفاده کرد.؟
۱۳۹۹/۰۸/۰۱

form مبینا
در:
سلام من برنامه ای میخواستم که داخل ارایه 5 رنگ قرار گرفته باشه. و با استفاده از حلقه for این یک متنو به اون پنج...
۱۳۹۹/۰۸/۰۱

form mohadeseh
در:
ممنون از راهنماییتون مشکلم حل شد
۱۳۹۹/۰۷/۲۸

form محمد
در:
سلام. یک کد نوشته ام بدین صورت: وقتی صفحه باز شده یک پنجره پیام خالی با یک ok باز شده هر چه ok را...
۱۳۹۹/۰۷/۲۸

form فایز پور جهانبخشی
در:
سلام اگر بخواهیم برنامه ای که داخل متلب نوشتیم تا یک ثانیه اجرا شود و بعد از ثانیه اول در حالت خطا که...
۱۳۹۹/۰۷/۲۸

form mohadeseh
در:
الان کد من که توی تگ <head> گزاشتم میخواستم بدونم ایا امکانش هست که توی تگ link که ایکون رو باهاش اوردم بتونم...
۱۳۹۹/۰۷/۲۷

form mohadeseh
در:
سلام ببخشید لطفا راهنمایی کنید که چجوری title برای favicon در html بزارم؟ جوری که وقتی موس روی icon قرار بگیره متن...
۱۳۹۹/۰۷/۲۷

form ryomaechizen
در:
سلام. اگه حافظه وب پر بشه و مجبورا عکسا کپی باشن چطور باید مشکل بارگزاریشون حل بشه؟
۱۳۹۹/۰۷/۲۶

form رونا
در:
پرونده فرستاده شده نمی‌تواند به wp-content/uploads/2020/10 برود. سلام این ارور برای چی رخ می ده
۱۳۹۹/۰۷/۲۵

form reza
در:
سلام خوبید انشاالله؟ خواستم بدونم این نوار ابزار رو چطور باید اونایی رو دوست دارم بزارم سمت راست وبلاگم. هر چی کد و ......
۱۳۹۹/۰۷/۲۴

form سینا
در:
چگونه میتوانیم با استفاده از HTML فرمول شیمیایی مواد را بنویسیم؟ با عدد اتمی، جرمی و بار اتمی
۱۳۹۹/۰۷/۲۱

form فاطمه
در:
سلام ممنونم... خیلی ساده و روون توضیح دادین.. اونقدر که تشویق شدم محتوای یه فایل تکس رو با ایجکس درون یه div بیارم ولی...
۱۳۹۹/۰۷/۲۱

form امیرحسین
در:
خب متوجه شدم. که باید خط اول عدد فانکشن رو تغییر بدم. بسته به تعداد آرایه یا هر عدد دیگه تغییر بدم جوابمو...
۱۳۹۹/۰۷/۲۱

form امیرحسین
در:
عالی بود. خیلی ممنونم. ولی هر چند کلمه داخل آرایه داشته باشم به همون میزان خروجی گرفته میشه. من اگه 10 کلمه در آرایه داشته...
۱۳۹۹/۰۷/۲۱

form سعادتی
در:
سلام کاش روش برطرف کردن این بهم ریختگی رو هم توضیح میدادید. ممنون
۱۳۹۹/۰۷/۲۰
form امیرحسین
در:
موفق شدم اینو پیدا کنم. ولی میخوام کلمات تکراری داخلشون نباشه. مثال AAA فقط یک بار در اون خط وجود داشته باشه.
۱۳۹۹/۰۷/۲۰
form امیرحسین
در:
سلام. نه محدودیت زمانی وجود نداره.
۱۳۹۹/۰۷/۲۰
form امیرحسین
در:
سلام خسته نباشید. میخوام از این تابع برای بدست آوردن لیست های متفاوت استفاده کنم. مثلا یه آرایه داشته باشم. امیدوارم کمکم...
۱۳۹۹/۰۷/۲۰
form ابوالفضل
در:
سلام وقتتون بخیر من میخوام یه افزونه برای مرورگر کروم طراحی کنم و میخوام یه متنی رو هر سری از سایت دریافت کنه و...
۱۳۹۹/۰۷/۲۰
form mahdi
در:
سلام چطور می تونم از ip خارجی استفاده کنم؟ برای دریافت لانچر میخام. مرسی
۱۳۹۹/۰۷/۱۹
form احسان عباسی
در:
با سلام و تشکر از سایت خوبتون من یه کد تعریف کردم که در بورس ایران سهم مدنظرمو بیاره .. میخواستم ببینم امکانش هست دستوری...
۱۳۹۹/۰۷/۱۷
form شبنم
در:
سلام وقتتون بخیر، ببخشید از کلمه event یا e دقیقا چه زمانی توی فانکشن استفاده میکنیم؟
۱۳۹۹/۰۷/۱۷
form احمد
در:
با عرض سلام مجدد ساختار کلی دستورم به این صورت هست. بعد از حلقه وایل اون دیو کلاس 1 و 2 و 3 میخواهم...
۱۳۹۹/۰۷/۱۶
form احمد
در:
با عرض سلام ببخشید چطوری میتونم یه قسمت از تگ ها رو داخل حلقه وایل رد کنم دوباره تگ های بعدی داخل حلقه قرار بگیرن...
۱۳۹۹/۰۷/۱۶
form ابوالفضل
در:
سلام واقعا من خیلی گشتم تا بتونم این آموزش رو پیدا کنم چون واقعا نمی دونستم چی بنویسم تا یک رتبه بندی برای نتایج جستجو...
۱۳۹۹/۰۷/۱۵
form mahtab
در:
سلام وقتتون بخیر ببخشید میشه بفرمایید چجوری کلیپ رو بزاریم وبلاگ ؟؟ بی زحمت کامل بفرمایین ممنون و متشکر
۱۳۹۹/۰۷/۱۴
form Saeid Azari
در:
سلام ببخشید اگه امکانش هست سوال منو جواب بدید یکم گیج شدم...من یک کد html دارم که باید یک سایت درست کنم و ان را...
۱۳۹۹/۰۷/۱۳
form ابوالفضل
در:
سلام یک سوال دارم چجوری یک متنی که درون تگ td هست و بعد تگ br هست (تگ br درون تگ td است) رو...
۱۳۹۹/۰۷/۱۳
form parnian
در:
با سلام با توجه به این که این مطلب در سال 91 نوشته شده ایا تغیری هم کرده؟ مثلا استفاده و مهم بودن تگ های...
۱۳۹۹/۰۷/۱۳
form fahimeh
در:
سلام من دارم پروژه واسه دانشگاه مینویسم طراحی سایتو کردم برای کار با پایگاه داده دستور insert و delete کار میکنه ولی...
۱۳۹۹/۰۷/۱۲
form امین
در:
با عرض سلام ببخشید یه فرم دارم اخر فرمم یه دکمه دارم میخواستم بدونم چطوری باید بعد از کلیک کردن دکمه به صفحه دیگه انتقال...
۱۳۹۹/۰۷/۱۱
form محسن
در:
سلام من از فرم ساز گرویتی استفاده میکنم آیا امکان استفاده همچین چیزی رو میتونم داخلش داشته باشم آیا کدی داره که در قسمت...
۱۳۹۹/۰۷/۱۱
form مالکی
در:
چرا وبلاگم بالا نمی یاد
۱۳۹۹/۰۷/۰۹
form احمد
در:
با عرض سلام مجدد و خسته نباشید ببخشید نمونه کد رو اگر امکانش هست نگاه کنید که چطوری این متغییری رو که بدست اوردم در...
۱۳۹۹/۰۷/۰۹
form الناز
در:
سلام وقتتون بخیر. چطور میشه برنامه ای رو در php نوشت که کدملی رو تبدیل به شماره دانشجویی کنه اگه برام بنویسید ممنون میشم.
۱۳۹۹/۰۷/۰۹
form محمد
در:
سلام من میخواستم بدونم چه طوری میشه بدون اینکه از کاربر بپرسی که میخواهد از حساب خروج پیدا کند خود سایت بفهمد که کاربر از...
۱۳۹۹/۰۷/۰۹
form احمد
در:
با سلام ببخشید چطوری باید در جکوری از یک متغییر در صفحات دیگه استفاده کنم مثال دو عدد را باهم جمع کردم و ریختم داخل...
۱۳۹۹/۰۷/۰۹
form مهسا
در:
سلام و خسته نباشید مشکلی برای وبلاگ من پیش اومده موقع ورود بهم پیام میده وبلاگ داره بروز رسانی میشه و بعدا وارد وبلاگ شوید...
۱۳۹۹/۰۷/۰۸
form Moshtagh
در:
سلام و خسته نباشید بنده چند روزه که وقتی اطلاعات ورود به وبلاگم رو وارد تیترها و کلیک میکنم با چنین پاسخی مواجه میشم...
۱۳۹۹/۰۷/۰۸
form mahtab
در:
سلام خسته نباشین ببخشید چرا بلاگفا باز نمیکنه ؟؟؟ میرم مدیریت وبلاگ نه تو بروز شده ها وبی هستم نه هم که...
۱۳۹۹/۰۷/۰۷
form جواد
در:
سلام و عرض ادب. سایت من هک شده و یک کد ریدایرکت تو دیتابیس هاستم بارگزاری شده که آخر همه پست ها تو...
۱۳۹۹/۰۷/۰۷
  در انتظار بررسی: ۰
 پاسخگویی به سوالات ممکن است تا 24 ساعت زمان ببرد.