提供類似 IDE 的瀏覽器端檔案編輯功能,包含讀取檔案內容到編輯區與提交儲存回伺服器兩大核心操作。需嚴格限制可編輯目錄與檔案類型,防止任意檔案寫入漏洞。
../、..\\)config.php、.env)應設為唯讀或排除編輯<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>線上檔案編輯器</title>
<style>
textarea { width: 100%; height: 500px; font-family: monospace; font-size: 14px; line-height: 1.5; }
.actions { margin: 10px 0; }
.msg { padding: 10px; margin: 10px 0; border-radius: 4px; }
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
</style>
</head>
<body>
<h2>編輯檔案:<span id="filename"></span></h2>
<form id="editForm" method="post" action="save_file.php">
<input type="hidden" name="filepath" id="filepath">
<textarea name="content" id="content" spellcheck="false"></textarea>
<div class="actions">
<button type="submit">儲存變更</button>
<a href="file_manager.php">返回檔案管理</a>
</div>
</form>
<script>
// 從 URL 參數獲取檔案路徑(實際專案應從檔案管理器跳轉過來)
const urlParams = new URLSearchParams(window.location.search);
const filepath = urlParams.get('file');
if(filepath){
document.getElementById('filepath').value = filepath;
document.getElementById('filename').textContent = filepath;
// 載入檔案內容
fetch('read_file.php?file=' + encodeURIComponent(filepath))
.then(r => r.text())
.then(text => document.getElementById('content').value = text)
.catch(err => alert('讀取失敗:' + err));
}else{
alert('未指定檔案路徑');
window.location.href = 'file_manager.php';
}
</script>
</body>
</html>
<?php
// read_file.php
header('Content-Type: text/plain; charset=UTF-8');
$baseDir = __DIR__ . '/editable_files'; // 僅允許編輯此目錄下的檔案
$allowedExt = ['php', 'html', 'htm', 'css', 'js', 'json', 'txt', 'md', 'xml', 'yml', 'yaml'];
$file = $_GET['file'] ?? '';
if(!$file) die('缺少檔案參數');
// 安全檢查
$realBase = realpath($baseDir);
$realFile = realpath($baseDir . '/' . $file);
if(!$realFile || strpos($realFile, $realBase) !== 0){
http_response_code(403);
die('禁止存取:路徑超出允許範圍');
}
$ext = strtolower(pathinfo($realFile, PATHINFO_EXTENSION));
if(!in_array($ext, $allowedExt)){
http_response_code(403);
die('禁止編輯此類型檔案');
}
if(!is_readable($realFile)){
http_response_code(404);
die('檔案不存在或不可讀');
}
readfile($realFile); // 直接輸出檔案內容,效率最高
?>
<?php
// save_file.php
header('Content-Type: application/json; charset=UTF-8');
$baseDir = __DIR__ . '/editable_files';
$allowedExt = ['php', 'html', 'htm', 'css', 'js', 'json', 'txt', 'md', 'xml', 'yml', 'yaml'];
$filepath = $_POST['filepath'] ?? '';
$content = $_POST['content'] ?? '';
if(!$filepath){
echo json_encode(['success' => false, 'msg' => '缺少檔案路徑']);
exit;
}
// 同樣的安全檢查
$realBase = realpath($baseDir);
$realFile = realpath($baseDir . '/' . $filepath);
if(!$realFile || strpos($realFile, $realBase) !== 0){
echo json_encode(['success' => false, 'msg' => '禁止存取:路徑超出允許範圍']);
exit;
}
$ext = strtolower(pathinfo($realFile, PATHINFO_EXTENSION));
if(!in_array($ext, $allowedExt)){
echo json_encode(['success' => false, 'msg' => '禁止編輯此類型檔案']);
exit;
}
// 可選:備份原檔
$backupFile = $realFile . '.bak.' . date('YmdHis');
if(!copy($realFile, $backupFile)){
// 備份失敗不阻擋儲存,但記錄警告
error_log("備份失敗: $backupFile");
}
// 寫入新內容
$bytes = file_put_contents($realFile, $content, LOCK_EX);
if($bytes === false){
echo json_encode(['success' => false, 'msg' => '寫入失敗,請檢查權限']);
}else{
echo json_encode(['success' => true, 'msg' => "儲存成功($bytes bytes)", 'backup' => basename($backupFile)]);
}
?>
xdiff_string_diff 或 JS 庫)php -l 語法驗證