首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

AJAX + PHP 檔案上傳:iframe 無刷新上傳完整實作 (含進度條)

     編輯:PHP 相關知識

技術背景

HTML5 FormData + XMLHttpRequest Level 2 出現前,無刷新上傳主流做法是 隱藏 iframe 當作 form target。本文完整保留此經典實作,並補充現代化替代方案。

前端 HTML + CSS + JS 完整碼

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>AJAX 檔案上傳示例</title>
<style>
#container { width: 400px; margin: 30px auto; border: 1px solid #003; background: #fff; font-family: sans-serif; }
#header { height: 42px; background: url(images/header_bg.gif) repeat-x; color: #fff; padding: 5px; font-weight: bold; }
#content { padding: 15px; color: #666; }
#footer { text-align: right; padding: 5px 10px; border-top: 1px solid #999; color: #999; font-size: 12px; }
.msg { background: #e8f5e9; color: #2e7d32; padding: 10px; margin: 10px; border-radius: 4px; }
.emsg { background: #fbe9e7; color: #c62828; padding: 10px; margin: 10px; border-radius: 4px; }
#loader { display: none; text-align: center; padding: 20px; }
.sbtn { background: #003; color: #fff; border: 1px solid #003; padding: 5px 20px; cursor: pointer; }
#f1_upload_process { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 300px; background: #fff; border: 1px solid #ccc; padding: 20px; display: none; z-index: 100; box-shadow: 0 2px 10px rgba(0,0,0,.2); }
</style>
</head>
<body>
<div id="container">
  <div id="header">AJAX 檔案上傳示例</div>
  <div id="content">
    <form action="upload.php" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();">
      <div id="f1_upload_process">上傳中...<br><img src="loader.gif" alt="loading"></div>
      <div id="f1_upload_form">
        <label>選擇檔案: <input name="myfile" type="file" size="30" required></label>
        <label><input type="submit" class="sbtn" value="上傳"></label>
      </div>
      <iframe id="upload_target" name="upload_target" src="#" style="width:0;height:0;border:0;display:none;"></iframe>
    </form>
  </div>
  <div id="footer">Powered by PHP + iframe</div>
</div>

<script>
function startUpload() {
    document.getElementById('f1_upload_process').style.display = 'block';
    document.getElementById('f1_upload_form').style.display = 'none';
    return true;
}

function stopUpload(success) {
    var result = '';
    if (success == 1) {
        result = '<div class="msg">檔案上傳成功!</div><br>';
    } else {
        result = '<div class="emsg">上傳失敗,請重試。</div><br>';
    }
    document.getElementById('f1_upload_process').style.display = 'none';
    document.getElementById('f1_upload_form').innerHTML = result + 
        '<label>選擇檔案: <input name="myfile" type="file" size="30" required></label>' +
        '<label><input type="submit" class="sbtn" value="上傳"></label>';
    document.getElementById('f1_upload_form').style.display = 'block';
    return true;
}
</script>
</body>
</html>

後端 upload.php 處理邏輯

<?php
// upload.php
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
$maxSize = 5 * 1024 * 1024; // 5MB
$uploadDir = __DIR__ . '/uploads/';

if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);

$success = 0;
$msg = '';

if (isset($_FILES['myfile'])) {
    $file = $_FILES['myfile'];
    if ($file['error'] !== UPLOAD_ERR_OK) {
        $msg = '上傳錯誤代碼: ' . $file['error'];
    } elseif (!in_array($file['type'], $allowedTypes)) {
        $msg = '不允許的檔案類型';
    } elseif ($file['size'] > $maxSize) {
        $msg = '檔案過大,限制 5MB';
    } else {
        $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
        $newName = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
        $dest = $uploadDir . $newName;
        if (move_uploaded_file($file['tmp_name'], $dest)) {
            $success = 1;
            $msg = '上傳成功:' . $newName;
        } else {
            $msg = '移動檔案失敗';
        }
    }
} else {
    $msg = '未收到檔案';
}

// 輸出 JavaScript 呼叫父視窗 stopUpload()
?>
<script>
window.top.window.stopUpload();
</script>

關鍵機制解析

環節說明
form target="upload_target"表單提交後,回應在隱藏 iframe 中載入,不刷新主頁
onsubmit="startUpload()"顯示載入動畫、隱藏表單
upload.php 結尾輸出 JSwindow.top.window.stopUpload(1) 呼叫主頁函數處理結果
stopUpload() 重建表單用 innerHTML 重置表單,支援連續上傳

現代化替代:Fetch + FormData (推薦)

<script>
document.querySelector('form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    const btn = e.target.querySelector('button');
    btn.disabled = true; btn.textContent = '上傳中...';

    try {
        const res = await fetch('upload.php', { method: 'POST', body: formData });
        const text = await res.text();
        alert(text); // 或解析 JSON
    } catch (err) {
        alert('網路錯誤');
    } finally {
        btn.disabled = false; btn.textContent = '上傳';
    }
});
</script>

優點:原生 Promise、支援 xhr.upload.onprogress 真實進度條、無需 iframe、程式碼更簡潔。

結語

iframe 上傳是經典跨瀏覽器相容方案,適合維護舊專案。新專案請直接使用 Fetch API + FormData,配合後端回傳 JSON,體驗更佳且易於擴展進度條、分塊上傳、暫停續傳等進階功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved