<asp:FileUpload> + 上傳按鈕 + 即時預覽 <asp:Image>Server.MapPath) → 資料庫記錄檔名、類型、相對路徑image1 (ID PK, ImageName, ImageType, ImagePath)
CREATE TABLE image1 (
ID INT IDENTITY(1,1) PRIMARY KEY,
ImageName VARCHAR(100) NOT NULL,
ImageType VARCHAR(20) NOT NULL,
ImagePath VARCHAR(200) NOT NULL
);
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UpWord.aspx.cs" Inherits="Demo.UpWord" %>
<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
<title>圖片上傳示範</title>
</head>
<body>
<form id="form1" runat="server" enctype="multipart/form-data">
<div style="padding:20px;">
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="UploadButton" runat="server" Text="上傳圖片" OnClick="UploadButton_Click" CssClass="btn btn-primary" />
<asp:Label ID="lblMsg" runat="server" ForeColor="Red" />
<br /><br />
<asp:Image ID="Image1" runat="server" Height="150px" Width="150px" Visible="false" />
</div>
</form>
</body>
</html>
關鍵: enctype="multipart/form-data" 否則 FileUpload.HasFile 永為 false。
using System;
using System.IO;
using System.Configuration;
using System.Data.SqlClient;
using System.Web.UI.WebControls;
namespace Demo
{
public partial class UpWord : System.Web.UI.Page
{
private readonly string _connStr = ConfigurationManager.ConnectionStrings["ConnectionStr"].ConnectionString;
private static readonly string[] AllowedExt = { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
private const long MaxBytes = 5 * 1024 * 1024; // 5MB
protected void UploadButton_Click(object sender, EventArgs e)
{
lblMsg.Text = "";
if (!FileUpload1.HasFile)
{
lblMsg.Text = "請選擇要上傳的圖片";
return;
}
string ext = Path.GetExtension(FileUpload1.FileName).ToLowerInvariant();
if (Array.IndexOf(AllowedExt, ext) == -1)
{
lblMsg.Text = "僅允許上傳 JPG/PNG/GIF/BMP 格式";
return;
}
if (FileUpload1.PostedFile.ContentLength > MaxBytes)
{
lblMsg.Text = "檔案大小不可超過 5MB";
return;
}
try
{
// 1. 產生唯一檔名:yyyyMMddHHmmss_ffff + 副檔名
string fileName = $"{DateTime.Now:yyyyMMddHHmmss_ffff}{ext}";
string saveDir = Server.MapPath("~/Uploads/");
if (!Directory.Exists(saveDir)) Directory.CreateDirectory(saveDir);
string fullPath = Path.Combine(saveDir, fileName);
// 2. 儲存實體檔案
FileUpload1.PostedFile.SaveAs(fullPath);
// 3. 寫入資料庫(參數化)
const string sql = "INSERT INTO image1 (ImageName, ImageType, ImagePath) VALUES (@name, @type, @path)";
using (var conn = new SqlConnection(_connStr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@name", Path.GetFileNameWithoutExtension(fileName));
cmd.Parameters.AddWithValue("@type", ext);
cmd.Parameters.AddWithValue("@path", $"~/Uploads/{fileName}"); // 相對路徑
conn.Open();
cmd.ExecuteNonQuery();
}
// 4. 前端預覽
Image1.ImageUrl = $"~/Uploads/{fileName}";
Image1.Visible = true;
lblMsg.Text = "上傳成功";
lblMsg.ForeColor = System.Drawing.Color.Green;
}
catch (Exception ex)
{
// 實際專案請記錄至 Log 系統
lblMsg.Text = $"上傳失敗:{ex.Message}";
lblMsg.ForeColor = System.Drawing.Color.Red;
}
}
}
}
| 風險 | 對策 |
|---|---|
| 惡意腳本偽裝圖片上傳 | 1. 僅驗證副檔名不足;2. 讀取檔頭 Magic Number 驗證真實格式;3. 儲存目錄設定 IIS「執行權限 = 無」 |
| 檔名衝突覆蓋 | 時間戳 + GUID 雙重保險:$"{DateTime.Now:yyyyMMddHHmmss}_{Guid.NewGuid():N}{ext}" |
| 大檔案導致請求逾時 | web.config:<httpRuntime maxRequestLength="102400" executionTimeout="300" />(100MB/5分) |
| 路徑遍歷攻擊 | Path.GetFileName 只取檔名部分;不使用使用者輸入路徑 |
<asp:FileUpload ID="FileUpload1" runat="server" AllowMultiple="true" /> // .NET 4.5+
// 後端迴圈 Request.Files 集合處理
本範例示範從前端驗證、實體儲存、資料庫記錄到安全防護的完整上傳鏈路。生產環境建議:
UploadUserId、UploadTime、FileSize、MD5 供審計與去重