PHP 檔案處理 (File Handling)

PHP 提供多種函數來讀取、寫入和操作檔案。

讀取檔案

file_get_contents()

一次讀取整個檔案:

<?php
$content = file_get_contents('data.txt');
echo $content;

// 讀取遠端檔案
$html = file_get_contents('https://example.com');
?>

file()

讀取檔案成陣列(每行一個元素):

<?php
$lines = file('data.txt');

foreach ($lines as $lineNumber => $line) {
    echo "Line $lineNumber: $line";
}

// 移除換行符號
$lines = file('data.txt', FILE_IGNORE_NEW_LINES);

// 跳過空行
$lines = file('data.txt', FILE_SKIP_EMPTY_LINES);
?>

fopen() 和 fread()

<?php
$handle = fopen('data.txt', 'r');

if ($handle) {
    while (!feof($handle)) {
        $line = fgets($handle);  // 讀取一行
        echo $line;
    }
    fclose($handle);
}
?>

寫入檔案

file_put_contents()

<?php
// 寫入(覆蓋)
file_put_contents('data.txt', 'Hello, World!');

// 附加
file_put_contents('data.txt', 'New line', FILE_APPEND);

// 寫入陣列
$lines = ['Line 1', 'Line 2', 'Line 3'];
file_put_contents('data.txt', implode("\n", $lines));
?>

fopen() 和 fwrite()

<?php
$handle = fopen('data.txt', 'w');  // w = 寫入(覆蓋)

if ($handle) {
    fwrite($handle, "Hello, World!\n");
    fwrite($handle, "Second line\n");
    fclose($handle);
}
?>

檔案開啟模式

模式說明
r唯讀
r+讀寫
w寫入(覆蓋)
w+讀寫(覆蓋)
a附加
a+讀寫(附加)
x建立並寫入(檔案已存在則失敗)

檔案資訊

<?php
// 檢查檔案是否存在
if (file_exists('data.txt')) {
    echo "檔案存在";
}

// 檢查是否為檔案
if (is_file('data.txt')) { }

// 檢查是否為目錄
if (is_dir('uploads')) { }

// 檢查是否可讀/可寫
if (is_readable('data.txt')) { }
if (is_writable('data.txt')) { }

// 檔案大小(bytes)
$size = filesize('data.txt');

// 修改時間
$mtime = filemtime('data.txt');
echo date('Y-m-d H:i:s', $mtime);

// 檔案資訊
$info = pathinfo('/path/to/file.txt');
echo $info['dirname'];    // /path/to
echo $info['basename'];   // file.txt
echo $info['filename'];   // file
echo $info['extension'];  // txt
?>

目錄操作

<?php
// 建立目錄
mkdir('new_folder');
mkdir('path/to/folder', 0755, true);  // 遞迴建立

// 刪除目錄(必須是空的)
rmdir('empty_folder');

// 列出目錄內容
$files = scandir('uploads');
foreach ($files as $file) {
    if ($file !== '.' && $file !== '..') {
        echo $file . "\n";
    }
}

// 使用 glob 搜尋
$phpFiles = glob('*.php');
$allFiles = glob('uploads/*');
?>

刪除和複製

<?php
// 刪除檔案
unlink('data.txt');

// 複製檔案
copy('source.txt', 'destination.txt');

// 移動/重新命名
rename('old.txt', 'new.txt');
rename('file.txt', 'folder/file.txt');
?>

安全處理

<?php
function safeReadFile(string $filename): ?string {
    // 檢查路徑遍歷
    $realPath = realpath($filename);
    $basePath = realpath(__DIR__ . '/data/');
    
    if ($realPath === false || strpos($realPath, $basePath) !== 0) {
        return null;  // 可能是路徑遍歷攻擊
    }
    
    if (!is_readable($realPath)) {
        return null;
    }
    
    return file_get_contents($realPath);
}
?>

CSV 處理

<?php
// 讀取 CSV
$handle = fopen('data.csv', 'r');
$data = [];

while (($row = fgetcsv($handle)) !== false) {
    $data[] = $row;
}

fclose($handle);

// 寫入 CSV
$handle = fopen('output.csv', 'w');

$rows = [
    ['Name', 'Age', 'City'],
    ['Alice', 25, 'Taipei'],
    ['Bob', 30, 'Taichung'],
];

foreach ($rows as $row) {
    fputcsv($handle, $row);
}

fclose($handle);
?>

JSON 檔案

<?php
// 讀取 JSON
$json = file_get_contents('data.json');
$data = json_decode($json, true);

// 寫入 JSON
$data = ['name' => 'Alice', 'age' => 25];
file_put_contents('data.json', json_encode($data, JSON_PRETTY_PRINT));
?>