tvanc/files-array-organizer

创建一个有组织的 $_FILES 数组版本。

2.0.1 2021-03-21 01:41 UTC

This package is auto-updated.

Last update: 2024-09-21 09:40:31 UTC


README

Build status codecov

处理 PHP 中的 $_FILES 数组很糟糕。大多数解决方案仅适用于特定情况,且不易移植。此实用程序旨在将任何可能的 $_FILES 数组组织成您直观期望的结构。获取上传文件的信息应该像读取 $_POST 数组一样简单。

入门指南

需求

PHP >= 7.3

安装

composer require tvanc/files-array-organizer

示例

一个输入,一个文件

在这种情况下,$_FILES 数组非常直观,有组织的版本与未组织的版本相同。

<?php
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;

if ($_FILES) {
    $organizedFiles = FilesArrayOrganizer::organize($_FILES);

    if ($organizedFiles === $_FILES) {
        echo "Looks like you didn't really need to do that.";
    }
}
?>
<form method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <button>Submit</button>
</form>

单个输入可以接受多个文件

FilesArrayOrganizer 使得处理这种常见情况变得稍微容易一些。

<?php
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;

if ($_FILES) {
    $organizedFiles = FilesArrayOrganizer::organize($_FILES);
    $attachments    = $organizedFiles['attachments'];

    foreach ($attachments as $attachment) {
        $attachment_name = $attachment['name'];
        $attachment_size = $attachment['size'];
    }
}
?>
<form method="post" enctype="multipart/form-data">
    <!-- Notice this input accepts multiple files -->
    <input type="file" name="attachments[]" multiple>
    <button>Submit</button>
</form>

多个输入可以接受多个文件

FilesArrayOrganizer 使得处理这种不太常见的场景 大大 变得容易。查看 解释 以查看来自包含多个输入(每个输入都可以接受多个文件)的表单的令人惊讶的 $_FILES 数组。

<?php
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;

// @var Todo[] $todos An array of todos
$todos = fetchTodos();

if ($_FILES) {
    $organizedFiles = FilesArrayOrganizer::organize($_FILES);

    foreach ($organizedFiles as $index => $postedTodo) {
        $attachments = $organizedFiles['todo'][$index];

        saveAttachments($index, $attachments);
    }
}
?>
<form method="post" enctype="multipart/form-data">
    <?php foreach ($todos as $index => $todo) { ?>
        <label>Attachments for todo <?= $index ?></label>
        <input
            type="file"
            name="todo[<?= $index ?>][attachments][]"
            multiple
        >
    <?php } ?>

    <button>Submit</button>
</form>

对每个文件执行自定义回调

为了改变文件数据的表示方式,将回调函数作为 FilesArrayOrganizer::organize() 的第二个参数传递。回调函数接收一个参数,即文件数据数组。回调函数的返回值将用于表示文件,而不是接收到的数组参数。

<?php
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;
use YourOwn\MadeUpNameSpace\UploadedFile;

// Receive $file by reference to mutate it. You can even replace it entirely.
$callback = function (array & $file) {
    $file = new UploadedFile($file);
}

$organizedFilesArray = FilesArrayOrganizer::organize($_FILES, $callback);

// $attachments will be an array of UploadedFile objects
$attachments = $organizedFilesArray['attachments'];
?>
<form method="post" enctype="multipart/form-data">
    <input type="file" name="attachments[]" multiple>
    <button>Submit</button>
</form>

解释

对于某些情况,处理 $_FILES 超全局变量是可以的。通过名为 attachment 的字段上传单个文件将生成一个简单的 $_FILES 数组,如下所示

[
    'attachment' = [
        'name'     => 'filename.jpg',
        'type'     => 'image/jpeg',
        'tmp_name' => '/tmp/phpR4nD0m',
        'error'    => 0,
        'size'     => 2407,
    ]
]

获取文件的属性很简单。输入值的路径对应于输入字段的名称。

$file_name = $_FILES['attachment']['name'];
$file_size = $_FILES['attachment']['size'];

那么名为 todo[0][attachments][] 的字段呢,它可以接受多个文件?处理这个字段的文件应该是很容易的。对吧?

<?php
$attachments = $_FILES['todo'][0]['attachments'];

foreach ($attachments as $attachment) {
    doSomething($attachment);
}
?>
<form method="post" enctype="multipart/form-data">
    <input type="file" name="todo[0][attachments][]" multiple>
</form>

错了。

你认为 $_FILES 数组会看起来像这样。

[
    'todo' => [
        0 => [
            'attachments' => [
                0 => [
                    'name'     => 'filename.jpg',
                    'type'     => 'image/jpeg',
                    'tmp_name' => '/tmp/phpR4nD0m',
                    'error'    => 0,
                    'size'     => 2407,
                ],
                // ...
            ],
        ],
    ]
]

实际上它会看起来像这样

[
    'todo' => [
       'name'     => [
           0 => [
               'attachments' => [
                   0 => 'filename.jpg'
               ]
           ]
       ],
       'type'     => [
           0 => [
               'attachments' => [
                   0 => 'image/jpeg'
               ]
           ]
       ],
       'tmp_name' => [
           0 => [
               'attachments' => [
                   0 => '/tmp/phpKYBy4z'
               ]
           ]
       ],
       'error'    => [
           0 => [
               'attachments' => [
                   0 => 0
               ]
           ]
       ],
       'size'     => [
           0 => [
               'attachments' => [
                   0 => 2407
               ]
           ]
       ]
    ]
]

我将留作读者的练习,去找出如何从中提取有用的信息。如果您不想每次需要同时处理多个文件时都重复这个练习,只需使用这个库。

要查看如何使用与这种 $_FILES 数组类似的 FilesArrayOrganizer,请参阅示例,多个输入可以接受多个文件