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

原生 JS + PHP 實現異步圖片上傳:FormData + XMLHttpRequest 完整示例

     編輯:PHP 相關知識

無需 jQuery、插件,純原生 JavaScript 配合 PHP 即可實現現代異步圖片上傳(支持進度條、拖拽、多文件擴展)。本文提供精簡完整的前後端代碼。

前端:index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>HTML5 Ajax 圖片上傳</title>
    <style>
        .txt { height:28px; border:1px solid #cdcdcd; width:670px; }
        .mybtn { background:#fff; border:1px solid #cdcdcd; height:30px; width:70px; cursor:pointer; }
        .file { position:absolute; top:0; right:80px; height:24px; opacity:0; width:260px; cursor:pointer; }
    </style>
</head>
<body>
    <label>圖片:</label>
    <input type="text" id="textfield" class="txt" readonly />
    <input type="file" id="file" class="file" onchange="document.getElementById('textfield').value=this.value" />
    <button class="mybtn" onclick="UpladFile()">上傳</button>
    <div id="progress" style="margin-top:10px; display:none;">
        <progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
        <span id="progressText">0%</span>
    </div>
    <script>
        var xhr;
        function createXMLHttpRequest() {
            if (window.ActiveXObject) {
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            } else if (window.XMLHttpRequest) {
                xhr = new XMLHttpRequest();
            }
        }
        function UpladFile() {
            var fileObj = document.getElementById("file").files[0];
            if (!fileObj) { alert("請選擇文件"); return; }
            var form = new FormData();
            form.append("myfile", fileObj);
            createXMLHttpRequest();
            xhr.upload.onprogress = function(e) {
                if (e.lengthComputable) {
                    var percent = Math.round((e.loaded / e.total) * 100);
                    document.getElementById("progressBar").value = percent;
                    document.getElementById("progressText").innerText = percent + "%";
                }
            };
            xhr.onreadystatechange = handleStateChange;
            xhr.open("POST", "upload.php", true);
            document.getElementById("progress").style.display = "block";
            xhr.send(form);
        }
        function handleStateChange() {
            if (xhr.readyState == 4) {
                document.getElementById("progress").style.display = "none";
                if (xhr.status == 200 || xhr.status == 0) {
                    var result = xhr.responseText;
                    try {
                        var json = JSON.parse(result);
                        if (json.file) {
                            alert('上傳成功!圖片鏈接:\n' + json.file);
                        } else {
                            alert('上傳失敗:' + (json.error || '未知錯誤'));
                        }
                    } catch (e) {
                        alert('響應解析失敗:' + result);
                    }
                } else {
                    alert('請求失敗:HTTP ' + xhr.status);
                }
            }
        }
    </script>
</body>
</html>

後端:upload.php

<?php
if (isset($_FILES["myfile"])) {
    $ret = ['error' => '', 'file' => ''];
    $uploadDir = 'images' . DIRECTORY_SEPARATOR . date("Ymd") . DIRECTORY_SEPARATOR;
    $dir = __DIR__ . DIRECTORY_SEPARATOR . $uploadDir;
    if (!file_exists($dir)) {
        mkdir($dir, 0777, true);
        chmod($dir, 0777);
    }
    // 單文件處理
    $ext = strtolower(pathinfo($_FILES["myfile"]["name"], PATHINFO_EXTENSION));
    $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
    if (!in_array($ext, $allowed)) {
        $ret['error'] = '不支持的文件類型';
    } elseif ($_FILES["myfile"]["error"] !== UPLOAD_ERR_OK) {
        $ret['error'] = '上傳錯誤代碼:' . $_FILES["myfile"]["error"];
    } else {
        $fileName = time() . '_' . uniqid() . '.' . $ext;
        $dest = $dir . $fileName;
        if (move_uploaded_file($_FILES["myfile"]["tmp_name"], $dest)) {
            $ret['file'] = $uploadDir . $fileName; // 返回相對路徑
        } else {
            $ret['error'] = '文件移動失敗,請檢查權限';
        }
    }
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($ret);
    exit;
}
?>

關鍵技術點解析

技術說明
FormData構建 multipart/form-data 請求體,自動設置 Content-Type: multipart/form-data; boundary=...
xhr.upload.onprogress監聽上傳進度事件,實現進度條(需服務端不緩存請求體,Nginx 需 proxy_request_buffering off;)
move_uploaded_file安全移動臨時文件,防止臨時文件被惡意訪問
uniqid() + time()生成唯一文件名,避免衝突
日期目錄images/20240115/ 避免單目錄文件過多影響性能

擴展建議

  • 多文件上傳:files 迴圈 form.append("myfile[]", file),後端 $_FILES['myfile']['name'] 為數組。
  • 拖拽上傳:監聽 drop 事件,e.dataTransfer.files 獲取文件列表。
  • 圖片預覽:URL.createObjectURL(file) 生成臨時 URL 顯示縮略圖。
  • 大文件分片:Blob slice() 分片上傳,斷點續傳需後端支持合併。
  • 安全加固:MIME 類型二次驗證 (finfo_file)、圖片重繪 (imagecreatefromstring)、病毒掃描集成。

兼容性提示

  • IE10+ 完全支持 FormData、XMLHttpRequest Level 2。
  • IE9 及以下需 FormData Polyfill 或回退至 iframe 方案。
  • 現代項目建議直接要求 IE10+,簡化代碼。

原生 JS 實現異步上傳,零依賴、體積極小、完全可控,是輕量級項目的最佳選擇。

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