dmitriynet/symfony3-file-uploader-bundle

适用于 Symfony2 的多文件上传,使用 BlueImp 上传器。同时支持上传图片的缩放。

安装: 2,381

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 2

分支: 86

类型:symfony-bundle

v1.0.1 2017-12-05 20:46 UTC

This package is not auto-updated.

Last update: 2024-09-24 17:12:55 UTC


README

需要维护者!

此包不再积极更新。它仅用于维护影响与 Symfony 2.0.x 使用的错误。如果您有兴趣接管此包的维护工作,请联系 tom@punkave.com。谢谢!

简介

此包提供了基于 BlueImp jQuery 文件上传器 包的多个文件上传功能。在兼容的浏览器中完全支持拖放和多个文件选择。我们选择 BlueImp 是因为它具有出色的前后浏览器兼容性。

由于 BlueImp 提供的现有 PHP 上传器类已经非常出色并且功能强大,所以此包是一个相当薄的包装。我们提供了一个将其集成到 Symfony 2 项目中的方法。

上传器将文件发送到您指定的文件夹。如果该文件夹已经包含文件,它们将与新文件并排显示,作为可以删除的现有文件。

该包可以自动将图像缩放到您指定的尺寸。提供的同步方法可以创建表单,其中附加的文件尊重“保存”和“取消”操作。

关于 Internet Explorer 的说明

10 版本之前的 Internet Explorer 不支持多文件上传。然而,IE 用户将能够一次添加一个文件,并且仍然能够构建一个附加文件的集合。

要求

  • Symfony3
  • jQuery
  • jQuery UI
  • Underscore

安装

Symfony 2.0

  1. 将以下行添加到您的 Symfony2 deps 文件中

    [FileUploaderBundle] git=http://github.com/dmitriynet/symfony3-file-uploader-bundle.git target=/bundles/PunkAve/FileUploaderBundle

  2. 使用以下行修改您的 AppKernel

    new PunkAve\FileUploaderBundle\PunkAveFileUploaderBundle(),

  3. 如果您还没有,请将以下行添加到您的 autoload.php 文件中

    'PunkAve' => DIR.'/../vendor/bundles',

  4. 安装您的 vendors

    bin/vendors install

Symfony 3.*

  1. 将以下行添加到您的 composer.json require 块中: "dmitriynet/symfony3-file-uploader-bundle": "dev-master"

    标准的 symfony 3 composer.json 文件有一个分支别名,它会干扰安装此包。您可以通过删除以下行来解决这个问题

 "branch-alias": {
            "dev-master": "3.0-dev"
        }
  1. 使用以下行修改您的 AppKernel

    new PunkAve\FileUploaderBundle\PunkAveFileUploaderBundle(),

  2. 执行 composer install

用法

您的页面必须包含 Underscore 模板以渲染文件列表和上传器。您可以像这样使用我们的模板

{# Underscore templates for the uploader #}
{% include "PunkAveFileUploaderBundle:Default:templates.html.twig" %}

在页面的任何位置这样做即可。如果您愿意,可以复制并修改 templates.html.twig,并将其从自己的目录中包含进来。只需不要删除 data-* 属性。其余的标记由您自己决定。

在编辑操作中

假设您在控制器中有一个 editAction() 方法。您有一个包含附加文件列表的表单,这些附加文件像表单中的其他字段一样工作:您可以添加更多文件,您也可以删除现有文件,但除非用户点击“保存”,否则不会发生任何永久性操作。

FileUploader服务需要为给定对象的附件指定一个唯一的文件夹名称。为了对新对象和现有对象都实现这一点,我们建议您遵循“editId模式”,在该模式中,一个表单在其整个生命周期中(包括必要的多次验证)被分配一个唯一的、随机的“editId”。这使我们能够管理尚未具有自己id的新对象的文件上传。

此代码在表单的第一次遍历中创建editId,并在必要时同步现有对象附加的现有文件。from_folder和to_folder对象指定了存储附加文件的子目录。稍后我们将探讨如何确定这些文件夹的父目录。

(获取$posting并验证用户是否有权编辑该帖子由您负责。)

$request = $this->getRequest();

$editId = $this->getRequest()->get('editId');
if (!preg_match('/^\d+$/', $editId))
{
    $editId = sprintf('%09d', mt_rand(0, 1999999999));
    if ($posting->getId())
    {
        $this->get('punk_ave.file_uploader')->syncFiles(
            array('from_folder' => 'attachments/' . $posting->getId(),
              'to_folder' => 'tmp/attachments/' . $editId,
              'create_to_folder' => true));
    }
}

如果用户在尝试完成动作的第一次尝试中遇到验证错误(例如,表单验证错误),您希望再次显示同一组文件。因此,请使用getFiles方法获取现有文件的列表。确保将此列表传递给您的模板。

$existingFiles = $this->get('punk_ave.file_uploader')->getFiles(array('folder' => 'tmp/attachments/' . $editId));

(请注意,您生成的editId应该是高度随机的,以防止用户控制彼此的附件。)

当用户保存表单并且您刚刚持久化帖子对象时,您还应该将editId关联的临时文件夹中的文件同步回与帖子的id关联的永久文件夹。因为我们已经完成了临时文件夹,所以我们要求文件上传服务删除该文件夹。我们还要求服务在必要时创建目标文件夹。

$fileUploader = $this->get('punk_ave.file_uploader');
$fileUploader->syncFiles(
    array('from_folder' => '/tmp/attachments/' . $editId,
    'to_folder' => '/attachments/' . $posting->getId(),
    'remove_from_folder' => true,
    'create_to_folder' => true));

稍后您可以轻松地获取一个对象附加的所有文件名称的列表

$files = $fileUploader->getFiles(array('folder' => 'attachments/' . $posting->getId()));

但是,访问文件系统会有一定的性能成本。您会发现将附件列表保留在Doctrine表中更有效,尤其是如果您想在列表视图中包含第一个附件时。只需使用getFiles获取文件名列表,并根据您的需要将其镜像到数据库中。

在您的布局中

为了通过Assetic提供必要的JavaScript(注意,您必须提供jQuery、jQuery UI和Underscore)

{% javascripts
    '@MyBundle/Resources/public/js/jquery-1.7.2.min.js'
    '@MyBundle/Resources/public/js/jquery-ui-1.8.22.custom.min.js'
    '@MyBundle/Resources/public/js/underscore-min.js'
    '@PunkAveFileUploaderBundle/Resources/public/js/jquery.fileupload.js'
    '@PunkAveFileUploaderBundle/Resources/public/js/jquery.iframe-transport.js'
    '@PunkAveFileUploaderBundle/Resources/public/js/FileUploader.js' %}
    <script src="{{ asset_url }}"></script>
{% endjavascripts %}

您必须包含iframe传输以兼容IE 9及以下版本。

在编辑模板中

让我们假设有一个与编辑操作关联的edit.html.twig模板。这里可能的样子如下。请注意,您的操作中的渲染调用将传递帖子对象、editId、existingFiles数组以及isNew标志

{% extends "MyBundle:Default:layout.html.twig" %}

{% block body %}

{# Underscore templates for the uploader #}
{% include "PunkAveFileUploaderBundle:Default:templates.html.twig" %}

<form class="edit-form" action="{{ path('edit', { id: posting.id, editId: editId }) }}" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}

    {# Hydrated by javascript #}
    <div class="file-uploader"></div>

    <button class="btn btn-primary" type="submit">{{ isNew ? "Save New Listing" : "Save Changes" }}</button>
    <a class="btn" href="{{ cancel }}">Cancel</a>
    {% if not isNew %}
        <a class="btn btn-danger" href="{{ path('delete', { id: posting.id } ) }}">Delete</a>
    {% endif %}

</form>

<script type="text/javascript">

// Enable the file uploader

$(function() {
    new PunkAveFileUploader({
        'uploadUrl': {{ path('upload', { editId: editId }) | json_encode | raw }},
        'viewUrl': {{ ('/uploads/tmp/attachments/' ~ editId) | json_encode | raw }},
        'el': '.file-uploader',
        'existingFiles': {{ punkave_get_files('tmp/attachments/' ~ editId) | json_encode | raw }},
        'delaySubmitWhileUploading': '.edit-form'
    });
});
</script>
{% endblock %}

进度显示

在template.html.twig中有一个简单的旋转器。如果您选择提供自己的Underscore模板,您可以替换它。只需确保您有自己的元素,并具有data-spinner="1"属性。

如果您正在使用template.html.twig,请注意,您必须以通常的方式发布您的资产,以便旋转器图像可用。

php app/console assets:install web/

作为替代,您可以在间隔计时器上编写自己的代码,该计时器检查PunkAveFileUploader对象的uploading属性是否当前设置为true,并基于此显示旋转器。

延迟表单提交直到上传完成

如果上传仍在进行中,允许用户提交包含文件上传的表单不是一个好主意。您可以通过在上创建PunkAveFileUploader JavaScript对象时指定'delaySubmitWhileUploading'选项来轻松阻止此操作。

'delaySubmitWhileUploading': '.edit-form'

或者,您可以在任何时间检查使用new PunkAveFileUploader(...)创建的对象的uploading属性。如果正在上传,它将是true。现有的delaySubmitWhileUploading实现依赖于这一点。

在上传操作中

除了您表单的常规编辑操作之外,还必须有一个上传操作来处理文件上传。此操作将调用服务的handleFileUpload方法,将任务传递给BlueImp的UploadHandler类。由于该类直接在PHP中实现整个REST响应,因此该方法不返回。

这里显示了上传操作

/**
 *
 * @Route("/upload", name="upload")
 * @Template()
 */
public function uploadAction()
{
    $editId = $this->getRequest()->get('editId');
    if (!preg_match('/^\d+$/', $editId))
    {
        throw new Exception("Bad edit id");
    }

    $this->get('punk_ave.file_uploader')->handleFileUpload(array('folder' => 'tmp/attachments/' . $editId));
}

这个单一操作实际上实现了一个完整的REST API,其中BlueImp UploadHandler类负责上传和删除文件。

再次强调,handleFileUpload不会返回,因为响应是由BlueImp的UploadHandler类以原生PHP方式生成的。

设置允许的文件类型

您可以通过在handleFileUpload方法或parameters.yml中指定它们来指定自定义文件类型,从而偏离默认类型(默认类型在Resources/config/services.yml中定义)。

在handleFileUpload中

$this->get('punk_ave.file_uploader')->handleFileUpload(array(
    'folder' => 'tmp/attachments/' . $editId,
    'allowed_extensions' => array('zip', 'rar', 'tar')
));

在这种情况下,FileUploader服务将默认扩展名与提供的扩展名合并,并创建一个单一的regex。使用正则表达式字符可能会导致错误。

parameters.yml: 如果您已安装Symfony标准版,您可以在app/config/parameters.yml中指定它们

file_uploader.allowed_extensions:
    - zip
    - rar
    - tar

这样做将覆盖默认扩展名,而不是添加它们!

删除文件

迟早会删除帖子,并且您希望所有附件也被删除。

您可以这样做

$this->get('punk_ave.file_uploader')->removeFiles(array('folder' => 'attachments/' . $posting->getId()));

您可能想在管理类或doctrine事件监听器中这样做,但这不是我们的部门。

删除临时文件

如果您选择遵循我们的editId模式,您将希望定期清除web/uploads/tmp中超过一定年龄的内容。人们经常离开网站,因此并非每个人都点击您精心提供的“取消”操作,该操作基于editId模式调用removeFiles()。

请考虑将其作为夜间运行的cron作业安装此shell脚本。此shell脚本删除超过一天旧的文件,然后删除空文件夹

#!/bin/sh
find /path/to/my/project/web/uploads/tmp -mtime +1 -type f -delete
find /path/to/my/project/web/uploads/tmp -mindepth 1 -type d -empty -delete

(由于第二个命令不是递归的,父文件夹可能多坚持一天,但它们将在第二天被删除。)

配置参数

请参阅此包中的Resources/config/services.yml。您可以轻松决定上传父文件夹是什么,以及接受哪些文件扩展名,以及您希望图像文件自动缩放到的大小。

上面的from_folderto_folderfolder选项都是在处理文件时追加到file_uploader.file_base_path之后的。

如果file_uploader.file_base_path设置为如下(默认)

file_uploader.file_base_path: "%kernel.root_dir%/../web/uploads"

并且当调用handleFileUpload时将folder选项设置为attachments/5,则上传的文件将到达

/root/of/your/project/web/uploads/attachments/5/originals

如果此帖子的唯一附件是botfly.jpg,并且您已为file_uploader.sizes选项(默认情况下我们提供几个有用的标准大小)配置了一个或多个图像大小,那么您将看到

/root/of/your/project/web/uploads/photos/5/originals/botfly.jpg
/root/of/your/project/web/uploads/photos/5/thumbnail/botfly.jpg
/root/of/your/project/web/uploads/photos/5/medium/botfly.jpg
/root/of/your/project/web/uploads/photos/5/large/botfly.jpg

因此,所有这些都可以通过以下URL轻松访问

/uploads/photos/5/originals/botfly.jpg

等等。

尽可能地保留上传文件的原始名称和文件扩展名,同时不引入安全风险。

限制上传数量

您可以通过设置max_no_of_files属性来限制上传文件的数量。您可以在parameters.yml中这样设置

parameters:
  file_uploader.max_number_of_files: 4

您可能想为此情况添加错误处理程序。在初始化PunkAveFileUploader的模板中设置errorCallback

// Enable the file uploader
$(function() {
  new PunkAveFileUploader({
    // ... other required options,

    'errorCallback': function(errorObj) {
      if (errorObj.error == 'maxNumberOfFiles') {
        alert("Maximum uploaded files exceeded!");
      }
    }
  });
});

限制

此包通过glob()函数访问文件系统。它不能与S3流包装器无缝工作。

根据editId模式来回同步文件可能不适合文件非常大的情况。在这种情况下,不要使用editId模式。一个替代方案是立即在数据库中创建对象,直到你标记它们为活动状态之前不要在列表视图中显示它们。这样,你的编辑操作可以使用对象的永久ID作为folder选项的一部分,无需同步。在这种情况下,你可能需要将附件列表移至表单下方,以提示用户没有“取消”这些操作的说法。

注释

上传器使用了Bootstrap约定进行样式设计。如果你的项目中包含Bootstrap,上传器应该能够直接使用预设的样式。

"选择文件"按钮允许进行多选以及拖放。