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

iframe 無刷新檔案上傳實作教學:從基本原理到回調處理完整範例

     編輯:PHP 相關知識

前言

在 AJAX Level 2 (FormData) 普及前,iframe 是實現「無刷新上傳」的主流方案。雖然現代專案建議改用 fetch + FormData,但理解 iframe 上傳機制對維護舊專案、相容舊瀏覽器仍有價值。本文完整示範前後端配合流程。

核心原理

  1. 頁面嵌入一個 <iframe name="upload_frame">,並用 CSS 隱藏(display:none)。
  2. 表單 target="upload_frame",送出時回應會在 iframe 內載入,主頁面不跳轉。
  3. 後端處理完畢,輸出 <script>parent.callback(...);</script> 呼叫父頁面 JS 函式。

完整前端頁面 (index.html)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>iframe 無刷新上傳</title>
  <style>#upload_frame { display: none; }</style>
</head>
<body>
  <h3>檔案上傳</h3>
  <form action="upload.php" method="post" enctype="multipart/form-data" target="upload_frame">
    <input type="file" name="upfile" id="upfile" required>
    <button type="submit">上傳</button>
  </form>

  <iframe name="upload_frame" id="upload_frame"></iframe>

  <div id="result" style="margin-top:10px; color:green;"></div>

  <script>
    // 回調函式:後端上傳完成後呼叫
    window.uploadCallback = function(success, message, filePath) {
      const el = document.getElementById('result');
      if (success) {
        el.innerHTML = '✅ 上傳成功:' + message + ' <a href="' + filePath + '" target="_blank">檢視</a>';
        el.style.color = 'green';
      } else {
        el.innerHTML = '❌ 上傳失敗:' + message;
        el.style.color = 'red';
      }
    };
  </script>
</body>
</html>

後端處理 (upload.php)

<?php
// 簡易錯誤處理
$allowedExt = ['jpg','jpeg','png','gif','pdf'];
$maxSize = 2 * 1024 * 1024; // 2MB

$response = ['success' => false, 'message' => '', 'filePath' => ''];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!isset($_FILES['upfile']) || $_FILES['upfile']['error'] !== UPLOAD_ERR_OK) {
        $response['message'] = '檔案上傳錯誤,代碼:' . ($_FILES['upfile']['error'] ?? '未知');
    } else {
        $ext = strtolower(pathinfo($_FILES['upfile']['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, $allowedExt)) {
            $response['message'] = '不允許的檔案類型';
        } elseif ($_FILES['upfile']['size'] > $maxSize) {
            $response['message'] = '檔案過大,限制 2MB';
        } else {
            $newName = uniqid('up_', true) . '.' . $ext;
            $dest = __DIR__ . '/uploads/' . $newName;
            if (!is_dir(dirname($dest))) mkdir(dirname($dest), 0755, true);
            if (move_uploaded_file($_FILES['upfile']['tmp_name'], $dest)) {
                $response['success'] = true;
                $response['message'] = '檔案已儲存';
                $response['filePath'] = 'uploads/' . $newName;
            } else {
                $response['message'] = '伺服器儲存失敗';
            }
        }
    }
}

// 輸出 JS 呼叫父頁面回調
// 注意:必須輸出完整 HTML 頁面,iframe 才會執行 script
?>
<!DOCTYPE html>
<html><body>
<script>
  parent.uploadCallback(
    ,
    ,
    
  );
</script>
</body></html>

進階:回傳值寫入父頁面表單欄位

若需將上傳後的路徑填入父頁面的 <input name="img">:

// upload.php 內的 script 區塊改為:
<script>
  parent.document.forms['myForm'].elements['img'].value = ;
  parent.uploadCallback(, );
</script>

常見坑與解決

問題原因解決
IE 下載提示而非執行 script回應 Content-Type 錯誤確保輸出 header('Content-Type: text/html; charset=utf-8');
跨域無法呼叫 parent.callback同源策略限制上傳 API 必須同域;跨域需用 postMessage
大檔案上傳無進度條iframe 無進度事件改用 XMLHttpRequest Level 2 (FormData + progress 事件)
多檔上傳單一 input 只能選一檔用多個 input 或 input multiple 迴圈送出

現代替代方案:Fetch + FormData(推薦新專案使用)

const formData = new FormData();
formData.append('upfile', fileInput.files[0]);

fetch('upload.php', { method: 'POST', body: formData })
  .then(r => r.json())
  .then(data => uploadCallback(data.success, data.message, data.filePath));

優點:原生進度條、可取消、無 iframe 侷限、程式碼更簡潔。

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