<返回目录     Powered by claud/xia兄

第8课: 文件操作与上传

文件操作基础

PHP提供了丰富的文件操作函数,可以读取、写入、修改和删除文件。

检查文件和目录

<?php
// 检查文件是否存在
if (file_exists("data.txt")) {
    echo "文件存在";
}

// 检查是否为文件
if (is_file("data.txt")) {
    echo "这是一个文件";
}

// 检查是否为目录
if (is_dir("uploads")) {
    echo "这是一个目录";
}

// 检查文件是否可读/可写/可执行
is_readable("data.txt");
is_writable("data.txt");
is_executable("script.sh");
?>

读取文件

一次性读取整个文件

<?php
// file_get_contents - 读取整个文件为字符串
$content = file_get_contents("data.txt");
echo $content;

// 读取远程文件
$html = file_get_contents("https://example.com");

// file - 读取文件为数组(每行一个元素)
$lines = file("data.txt");
foreach ($lines as $line) {
    echo $line;
}

// 读取文件并去除换行符
$lines = file("data.txt", FILE_IGNORE_NEW_LINES);
?>

使用文件指针读取

<?php
// fopen - 打开文件
$file = fopen("data.txt", "r");

if ($file) {
    // fgets - 逐行读取
    while (($line = fgets($file)) !== false) {
        echo $line;
    }

    // fclose - 关闭文件
    fclose($file);
}

// fread - 读取指定字节数
$file = fopen("data.txt", "r");
$content = fread($file, filesize("data.txt"));
fclose($file);

// fgetc - 逐字符读取
$file = fopen("data.txt", "r");
while (($char = fgetc($file)) !== false) {
    echo $char;
}
fclose($file);
?>

写入文件

一次性写入

<?php
// file_put_contents - 写入文件(覆盖)
$data = "Hello World\n";
file_put_contents("output.txt", $data);

// 追加内容
file_put_contents("output.txt", "New line\n", FILE_APPEND);

// 写入数组
$lines = ["第一行", "第二行", "第三行"];
file_put_contents("output.txt", implode("\n", $lines));

// 原子写入(使用锁)
file_put_contents("output.txt", $data, LOCK_EX);
?>

使用文件指针写入

<?php
// fopen - 打开文件用于写入
$file = fopen("output.txt", "w");  // w: 覆盖写入

if ($file) {
    // fwrite/fputs - 写入内容
    fwrite($file, "Hello World\n");
    fputs($file, "Second line\n");

    fclose($file);
}

// 追加模式
$file = fopen("output.txt", "a");  // a: 追加写入
fwrite($file, "Appended line\n");
fclose($file);
?>

文件打开模式

fopen()模式说明:

文件操作

复制、重命名和删除

<?php
// 复制文件
if (copy("source.txt", "dest.txt")) {
    echo "复制成功";
}

// 重命名/移动文件
if (rename("old.txt", "new.txt")) {
    echo "重命名成功";
}

// 删除文件
if (unlink("temp.txt")) {
    echo "删除成功";
}

// 批量删除
$files = glob("temp_*.txt");
foreach ($files as $file) {
    unlink($file);
}
?>

获取文件信息

<?php
$file = "data.txt";

// 文件大小(字节)
$size = filesize($file);
echo "文件大小: " . $size . " 字节";

// 文件修改时间
$mtime = filemtime($file);
echo "修改时间: " . date("Y-m-d H:i:s", $mtime);

// 文件访问时间
$atime = fileatime($file);

// 文件创建时间
$ctime = filectime($file);

// 文件类型
$type = filetype($file);  // file, dir, link等

// 文件权限
$perms = fileperms($file);
echo substr(sprintf('%o', $perms), -4);  // 0644

// 获取路径信息
$info = pathinfo($file);
echo $info['dirname'];    // 目录名
echo $info['basename'];   // 文件名
echo $info['extension'];  // 扩展名
echo $info['filename'];   // 不含扩展名的文件名
?>

目录操作

创建和删除目录

<?php
// 创建目录
if (mkdir("newdir")) {
    echo "目录创建成功";
}

// 递归创建多级目录
mkdir("path/to/newdir", 0755, true);

// 删除空目录
if (rmdir("olddir")) {
    echo "目录删除成功";
}

// 递归删除目录
function deleteDirectory($dir) {
    if (!is_dir($dir)) {
        return false;
    }

    $files = array_diff(scandir($dir), ['.', '..']);
    foreach ($files as $file) {
        $path = $dir . '/' . $file;
        is_dir($path) ? deleteDirectory($path) : unlink($path);
    }

    return rmdir($dir);
}
?>

遍历目录

<?php
// scandir - 列出目录内容
$files = scandir(".");
foreach ($files as $file) {
    if ($file != '.' && $file != '..') {
        echo $file . "\n";
    }
}

// glob - 模式匹配查找文件
$txtFiles = glob("*.txt");
$phpFiles = glob("**/*.php");  // 递归查找

// 使用目录句柄
$dir = opendir(".");
while (($file = readdir($dir)) !== false) {
    echo $file . "\n";
}
closedir($dir);

// RecursiveDirectoryIterator - 递归遍历
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator(".")
);

foreach ($iterator as $file) {
    if ($file->isFile()) {
        echo $file->getPathname() . "\n";
    }
}
?>

文件上传

HTML表单

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit" value="上传">
</form>

处理上传文件

<?php
// 检查是否有文件上传
if (isset($_FILES['file'])) {
    $file = $_FILES['file'];

    // 检查上传错误
    if ($file['error'] === UPLOAD_ERR_OK) {
        $tmpName = $file['tmp_name'];
        $name = basename($file['name']);
        $size = $file['size'];
        $type = $file['type'];

        // 验证文件类型
        $allowed = ['jpg', 'jpeg', 'png', 'gif'];
        $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));

        if (!in_array($ext, $allowed)) {
            die("不允许的文件类型");
        }

        // 验证文件大小(2MB)
        if ($size > 2 * 1024 * 1024) {
            die("文件太大");
        }

        // 生成安全的文件名
        $newName = uniqid() . '.' . $ext;
        $uploadPath = "uploads/" . $newName;

        // 移动上传文件
        if (move_uploaded_file($tmpName, $uploadPath)) {
            echo "上传成功: " . $uploadPath;
        } else {
            echo "上传失败";
        }
    } else {
        echo "上传错误: " . $file['error'];
    }
}
?>

上传错误代码

$_FILES['file']['error'] 错误代码:

CSV文件操作

<?php
// 读取CSV文件
$file = fopen("data.csv", "r");
while (($row = fgetcsv($file)) !== false) {
    print_r($row);
}
fclose($file);

// 写入CSV文件
$data = [
    ["姓名", "年龄", "城市"],
    ["张三", "25", "北京"],
    ["李四", "30", "上海"]
];

$file = fopen("output.csv", "w");
foreach ($data as $row) {
    fputcsv($file, $row);
}
fclose($file);
?>

文件锁定

<?php
// 独占锁(写入时)
$file = fopen("data.txt", "w");
if (flock($file, LOCK_EX)) {
    fwrite($file, "Locked content\n");
    flock($file, LOCK_UN);  // 释放锁
}
fclose($file);

// 共享锁(读取时)
$file = fopen("data.txt", "r");
if (flock($file, LOCK_SH)) {
    $content = fread($file, filesize("data.txt"));
    flock($file, LOCK_UN);
}
fclose($file);

// 非阻塞锁
if (flock($file, LOCK_EX | LOCK_NB)) {
    // 获取锁成功
} else {
    // 无法获取锁
}
?>

文件权限

<?php
// 修改文件权限
chmod("file.txt", 0644);  // rw-r--r--
chmod("script.sh", 0755); // rwxr-xr-x

// 修改文件所有者(需要root权限)
chown("file.txt", "www-data");
chgrp("file.txt", "www-data");

// 检查权限
$perms = fileperms("file.txt");
if ($perms & 0x0100) {
    echo "所有者可执行";
}
?>
安全建议:

实践练习

  1. 文件读写:创建日志记录系统,追加日志到文件
  2. 文件上传:实现图片上传功能,包含验证和缩略图生成
  3. 目录遍历:递归列出目录中的所有文件和大小
  4. CSV处理:读取CSV文件并转换为HTML表格
  5. 文件备份:实现文件自动备份功能
  6. 文件搜索:在目录中搜索包含特定内容的文件
  7. 批量重命名:批量修改文件名(如添加前缀)
  8. 文件监控:检测文件是否被修改