手把手教你写项目之个人云盘系统全栈开发---第3篇:“乾坤大挪移”——文件上传与列表展示的艺术

阅读前请先下载项目源码,边读边看源码以加深理解和实操,
源码地址已放于文章末尾!
在这里插入图片描述
在这里插入图片描述

第3篇:“乾坤大挪移”——文件上传与列表展示的艺术

各位道友,修炼至今,我们的“云盘”法宝已初具雏形,并且有了强大的“结界”(认证系统)守护。但一个空空如也的法宝,怎能称得上是真正的云盘呢?

今天,我们要修炼的核心功法,便是这“乾坤大挪移”——将散落在你电脑各处的文件,“嗖”地一下,安全、快速、有序地挪移到我们的云盘空间里。这不仅是云盘的灵魂,也是我们整个项目最激动人心的部分!

核心探秘:服务器的“快递收发室”

想象一下,当你在网页上点击“上传”按钮时,你的文件并没有直接飞到最终的 uploads 文件夹里。恰恰相反,它经历了一次非常严谨的“快递收发流程”。

服务器里有个神秘的“临时收发室”(一个临时文件夹),所有用户上传的文件,无论三七二十一,都会先被送到这里。这个包裹上贴着一张详细的“快递单”,在PHP的世界里,这张快递单就是超全局变量 $_FILES

$_FILES 变量就像一个信息丰富的数组,里面记录了“包裹”的一切:

  • ['name']: 包裹的原始名称,比如 我的毕业论文.docx
  • ['type']: 包裹的类型,比如 application/msword
  • ['size']: 包裹的重量(大小),单位是字节。
  • ['tmp_name']: 最关键的! 包裹在“临时收发室”的具体位置,比如 /tmp/phpA1b2C3
  • ['error']: 快递状态码。如果是0,就代表“完好无损,已签收”;如果不是0,就说明路上出了岔子。

我们的后端代码,就像是收发室里那个眼神犀利、经验丰富的管理员。他的工作流程是:

  1. 检查包裹:先看 ['error'] 是不是0,确保包裹没问题。
  2. 核对信息:检查包裹的大小、类型等是否符合规定(我们这个项目暂时没做严格限制,但大型项目必须有)。
  3. 登记入库:如果一切OK,管理员才会使用一个专用“搬运工具”——move_uploaded_file() 函数,把包裹从“临时收发室”(tmp_name),安全地搬运到我们指定的“正式仓库”(uploads/ 文件夹下),并给它取个正式的名字。

为什么不直接用 copy()rename()?因为 move_uploaded_file() 是PHP官方指定的“搬运工”,它在搬运前会再次确认这个文件是不是真的通过HTTP POST上传的,防止有人恶意伪造文件路径,搞破坏。安全,永远是第一位的!

整个过程,就像下面这张流程图一样清晰:

flowchart TD
    A[用户在浏览器选择文件] --> B(点击“上传”按钮);
    B --> C{浏览器打包文件发送HTTP请求};
    C --> D[服务器PHP引擎接收];
    D --> E[文件被存放在临时目录<br>$_FILES变量被填充];
    E --> F{index.php: 检查 $_FILES['error']};
    F -- Error = 0 --> G{安全检查(可选)};
    G -- 通过 --> H[move_uploaded_file() <br> 从 tmp_name 移动到 uploads/];
    H --> I[上传成功!];
    F -- Error != 0 --> J[上传失败!];

代码实战:“四位一体”深扒上传与展示逻辑

理论讲完了,让我们直接上“手术台”,看看 index.phptemplate.php 是如何配合完成这场“乾坤大挪移”的。

1. 核心大挪移功法 - index.php 文件上传处理

a. 文件路径定位: index.php (大约在 246行 附近)

b. 全面讲解引用:

  • $_FILES['files']: 我们前端上传表单中 input type="file"name 就是 files[],所以后端用此来接收。中括号表示它是一个文件数组,可以处理多文件上传。
  • count(): 计算数组中的单元数目。这里用来获取用户一次上传了多少个文件。
  • pathinfo(): 返回一个包含文件路径信息的数组,我们可以从中轻松获取文件名、扩展名等。
  • file_exists(): 检查文件或目录是否存在。我们用它来判断是否需要重命名。
  • move_uploaded_file(): 刚刚介绍过的,安全地将上传的文件移动到新位置。

c. 逐行注释与结构化分析:

// 文件路径: index.php

// 检查是否有文件通过POST请求上传
if (isset($_FILES['files'])) {
    // 获取当前文件应该被上传到的路径
    $currentPath = getCurrentPath(); 
    $uploadedFiles = $_FILES['files'];
    // 获取上传文件的总数
    $totalFiles = count($uploadedFiles['name']);
    $successCount = 0;

    // 循环处理每一个上传的文件
    for ($i = 0; $i < $totalFiles; $i++) {
        $fileName = $uploadedFiles['name'][$i];
        $fileTmpName = $uploadedFiles['tmp_name'][$i];
        $fileError = $uploadedFiles['error'][$i];

        // 步骤1:确保文件上传过程中没有错误
        if ($fileError === 0) {
            $filePath = $currentPath . '/' . $fileName;

            // 步骤2:检查目标位置是否已存在同名文件
            if (file_exists($filePath)) {
                // 如果存在,则自动重命名,避免覆盖
                $fileNameInfo = pathinfo($fileName);
                $baseName = $fileNameInfo['filename'];
                $extension = isset($fileNameInfo['extension']) ? '.' . $fileNameInfo['extension'] : '';
                $counter = 1;

                // 循环找到一个不重复的文件名,如 file_1.txt, file_2.txt
                while (file_exists($currentPath . '/' . $baseName . '_' . $counter . $extension)) {
                    $counter++;
                }
                $fileName = $baseName . '_' . $counter . $extension;
                $filePath = $currentPath . '/' . $fileName;
            }

            // 步骤3:使用安全的函数将文件从临时目录移动到最终目的地
            if (move_uploaded_file($fileTmpName, $filePath)) {
                $successCount++;
            }
        }
    }
    
    // ... (处理成功或失败的消息,并刷新页面)
}

d. 上下文关联:
这段代码块由 template.php 中的文件上传表单触发。当用户在弹出的上传模态框中选择文件并点击“上传”后,表单会以 enctype="multipart/form-data" 的形式提交到 index.phpindex.php 执行完上述的“大挪移”功法后,会通过 header() 重定向,让页面刷新。这样,当页面再次加载时,我们接下来要讲的“文件列表展示”逻辑就会执行,用户就能立刻看到自己刚刚上传的文件了。

2. “盘点家当”的艺术 - index.php 文件列表获取

文件放进仓库了,我们得有个清单才知道里面都有啥。

a. 文件路径定位: index.php (大约在 316行 附近)

b. 全面讲解引用:

  • DirectoryIterator: 这是PHP SPL(标准PHP库)提供的一个非常优雅的类,用于遍历目录中的文件和文件夹。它返回的是一个对象,比传统的 scandir() 等函数更好用。
  • $item->isDot(): DirectoryIterator 对象的一个方法,用于判断当前项是否是 ... 这两个特殊目录。我们必须跳过它们。
  • $item->isDir(): 判断当前项是否是一个文件夹。
  • $item->getFilename(): 获取文件名。
  • $item->getMTime(): 获取文件的最后修改时间(Unix时间戳)。
  • $item->getSize(): 获取文件大小(字节)。

c. 逐行注释与结构化分析:

// 文件路径: index.php

// 收集文件夹和文件
$folders = [];
$files = [];

// 创建一个目录迭代器,指向当前要显示的目录
$directory = new DirectoryIterator($currentPath);

// 遍历目录中的每一项
foreach ($directory as $item) {
    // 步骤1:跳过 '.' 和 '..'
    if ($item->isDot()) continue;
    
    // ... (搜索过滤逻辑) ...
    
    $itemPath = $item->getPathname(); // 获取完整路径
    
    // 步骤2:判断是文件夹还是文件,并分别存入不同数组
    if ($item->isDir()) {
        $folders[] = [
            'name' => $item->getFilename(),
            'path' => getRelativePath($itemPath), // 获取相对路径
            'time' => $item->getMTime(),
            'type' => 'folder'
        ];
    } else {
        $files[] = [
            'name' => $item->getFilename(),
            'path' => getRelativePath($itemPath),
            'time' => $item->getMTime(),
            'size' => $item->getSize(),
            'type' => mime_content_type($itemPath) // 获取文件的MIME类型
        ];
    }
}

// ... (后续对 $files 数组进行排序和分页)

d. 上下文关联:
这段代码是 index.php 的核心数据准备区之一。无论是页面首次加载,还是上传、删除、重命名文件后刷新页面,它都会被执行。它就像一个勤劳的“仓库管理员”,每次都去 uploads 目录(或其子目录)清点一遍货物,生成两份最新的清单:一份是 $folders (文件夹清单),一份是 $files (文件清单)。然后,这两份清单会被郑重地交给“装修队长” template.php 去展示。

3. “发布清单”的魔法 - template.php 列表渲染

最后一步,把清单变成用户能看懂的漂亮列表。

a. 文件路径定位: template.php (大约在 535行 附近)

b. 全面讲解引用:

  • foreach (...) : ... endforeach;: 这是PHP在HTML模板中进行循环的一种替代语法,比使用大括号 {} 更清晰、更易读。
  • htmlspecialchars(): 将特殊字符转换为HTML实体。这是一个至关重要的安全函数,可以防止XSS(跨站脚本)攻击。比如,如果一个文件名是 <script>alert('hack')</script>,不使用此函数就会直接执行脚本!
  • date(): 格式化一个本地时间/日期。
  • formatSize(): 这是我们在 index.php 中自定义的一个辅助函数,用于将字节大小转换为更易读的KB, MB, GB等。

c. 逐行注释与结构化分析:

<!-- 文件路径: template.php -->

<tbody class="bg-white divide-y divide-gray-100">
    <!-- 首先,循环渲染文件夹列表 -->
    <?php foreach ($folders as $folder): ?>
        <tr class="hover:bg-gray-50 transition-colors">
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- ... (文件夹图标和链接) ... -->
                <a href="index.php?path=<?php echo urlencode($folder['path']); ?>">
                    <!-- 使用 htmlspecialchars 防止XSS攻击 -->
                    <?php echo htmlspecialchars($folder['name']); ?>
                </a>
                <!-- ... -->
            </td>
            <!-- ... (文件夹的 大小/类型/时间/操作) ... -->
        </tr>
    <?php endforeach; ?>
    
    <!-- 接着,循环渲染文件列表(经过分页处理的) -->
    <?php foreach ($paginatedFiles as $file): ?>
        <tr class="hover:bg-gray-50 transition-colors">
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- ... (文件图标和多选框) ... -->
                <a href="..." target="_blank">
                    <?php echo htmlspecialchars($file['name']); ?>
                </a>
            </td>
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- 调用自定义函数格式化文件大小 -->
                <div class="text-sm text-gray-500"><?php echo formatSize($file['size']); ?></div>
            </td>
            <td class="px-6 py-4 whitespace-nowrap">
                <div class="text-sm text-gray-500"><?php echo htmlspecialchars($file['type']); ?></div>
            </td>
            <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
                <!-- 使用 date 函数格式化时间戳 -->
                <?php echo date('Y-m-d H:i:s', $file['time']); ?>
            </td>
            <!-- ... (文件操作按钮) ... -->
        </tr>
    <?php endforeach; ?>
    
    <!-- 如果文件夹为空,显示提示信息 -->
    <?php if (empty($folders) && empty($paginatedFiles)): ?>
        <!-- ... -->
    <?php endif; ?>
</tbody>

d. 上下文关联:
template.php 在这里扮演了最终的“渲染引擎”角色。它接收来自 index.php$folders$paginatedFiles 这两个“数据包”,然后通过 foreach 循环,像生产线上的机器人一样,一行一行地构建出我们看到的HTML表格。每一个 <?php echo ...; ?> 标签,都是一个数据与模板结合的“焊接点”,最终将一个动态的、数据驱动的页面完美地呈现给用户。

总结与预告

干得漂亮!今天我们打通了整个云盘项目的“任督二脉”!我们不仅学会了如何安全地接收和存储用户上传的文件,还掌握了如何高效地遍历文件目录,并将这些信息动态地展示在前端页面上。

现在,我们的云盘已经不再是一个空壳子,它有了真正的“血肉”,可以存放和展示内容了。

但是,一个优秀的“文件管家”,光会收纳和展示还不够,还得会整理!在下一篇文章中,我们将赋予用户真正的管理权限——“万物皆可控”:玩转文件的增删改查。我们将实现创建文件夹、重命名、移动和删除等核心操作。

准备好,让你的云盘变得更加强大吧!我们下期再会!

源码下载地址:
https://thmail.lanzouu.com/if4Yn34b31cf

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

THMAIL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值