【问题标题】:Serving files for download with Symfony3 and Flysystem使用 Symfony3 和 Flysystem 提供文件以供下载
【发布时间】:2017-04-06 23:03:04
【问题描述】:

简介

我正在使用:

  • Windows 10 专业版
  • XAMPP 与 PHP v7.0.9
  • Symfony v3.1.6
  • 学说 v2.5.4
  • StofDoctrineExtensionsBundle [1] 以便 管理树结构。
  • OneupUploaderBundle [2] 用于上传文件
  • OneupFlysystemBundle [3] 用于文件系统抽象

设置

我确实设置了树结构(表示目录和文件)并使用OneupUploaderBundleFlysystem 端点上传文件。

文件上传被组​​织上传到项目根文件夹中名为data的文件夹。上传工作正常,甚至包含用于不同上传的自定义子目录的路径(例如 data/project_001/test1.txtdata/project_002/test2.txt)!

问题

我需要提供用户之前上传的文件。

目前

  • 我收到错误(控制器以 1 结尾)

    The file "Project_9999/2_Divi/bbb.pdf" does not exist
    500 Internal Server Error - FileNotFoundException
    
  • 和错误(控制器以 2 结尾)

    Catchable Fatal Error: Object of class League\Flysystem\File could not be converted to string
    500 Internal Server Error - ContextErrorException
    

注意$exists 返回true - 所以文件肯定在那里!

代码

config.yml 的相关部分

oneup_uploader:
    mappings:
        gallery:
            storage:
                type: flysystem
                filesystem: oneup_flysystem.gallery_filesystem

            frontend: blueimp
            enable_progress: true
            namer: app.upload_unique_namer

            allowed_mimetypes: [ image/png, image/jpg, image/jpeg, image/gif ]
            max_size: 10485760s

oneup_flysystem:
    adapters:
        my_adapter:
            local:
                directory: "%kernel.root_dir%/../data"

    filesystems:
        gallery:
            adapter: my_adapter

控制器动作

<?php

public function projectDownloadFileAction($file_id, Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $repo = $em->getRepository('AppBundle:FileTree');
    $ultra = $this->get('app.ultra_helpers');

    $selected_file = $repo->getFileTreeNodeByIdArray($file_id);
    $item_name = $selected_file[0]['item_name'];
    $item_extension = $selected_file[0]['item_extension'];

    $activeProject = $this->get('session')->get('active_project');
    $activeProjectSelectedNodePath = $this->get('session')->get('active_project_selected_node_path');
    $item_file_name = $item_name .'.'. $item_extension;
    $complete_file_path = $activeProject['secret_path'] . $activeProjectSelectedNodePath .'/'. $item_file_name;
    dump($complete_file_path);

    ENDING -1-
    ENDING -2-
}

结束 1

    $downloadable_file = new \SplFileInfo($complete_file_path);
    dump($downloadable_file);
    $response = new BinaryFileResponse($downloadable_file);

    // Set headers
    $response->headers->set('Cache-Control', 'private');
    $response->headers->set('Content-Type', mime_content_type($downloadable_file));
    $response->headers->set('Content-Disposition', $response->headers->makeDisposition(
        ResponseHeaderBag::DISPOSITION_ATTACHMENT,
        $downloadable_file->getFilename()
    ));

    return $response;

结局 2

    $filesystem = $this->get('oneup_flysystem.gallery_filesystem');
    $exists = $filesystem->has($complete_file_path);
    if (!$exists)
    {
        throw $this->createNotFoundException();
    }
    dump($exists);

    $downloadable_file = $filesystem->get($complete_file_path);
    dump($downloadable_file);

    $response = new BinaryFileResponse($complete_file_path);
    $response->trustXSendfileTypeHeader();
    $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);

    return $response;

更新 1

我尝试提供Ending 1 变量`$complete_file_path 的绝对路径,但只得到错误。例如:

  • File not found at path: C:\DEV\tree_and_upload\data\Project_9999\1_Viens\test1.txt 500 Internal Server Error - FileNotFoundException

  • File not found at path: C:/DEV/tree_and_upload/data/Project_9999/1_Viens/test1.txt 500 Internal Server Error - FileNotFoundException

但它没有任何区别 - 我遇到了访问错误。也许 Symfony 正在积极限制对项目根目录中data 文件夹的访问...

问题

如何从位于项目根文件夹中的data 文件夹中提供文件,并使用Flysystem 文件系统抽象层和Local 适配器?

结论

我错过了什么?

请指教。

感谢您的时间和知识。

【问题讨论】:

  • $complete_file_path 真的包含文件的绝对路径还是相对于%kernel.root_dir%/../data
  • @xabbuh,是的,$complete_file_path%kernel.root_dir%/../data 相关。
  • 在构造BinaryFileResponse 时,您必须在$complete_file_path 前面加上%kernel.root_dir%/../data,或者检查getAbsolutePath() 对象中是否有类似getAbsolutePath() 的方法。
  • @xabbuh,事实证明,没有任何方法可以使用local 适配器获取Flysystem 中文件的绝对路径。建议将文件移动到web 目录的某个位置,以使其可访问或使用流。确实 - 流允许从项目根目录中存在的 data 文件夹中提供文件。所以我最终使用了 Symfony 的 StreamedResponse,它运行良好。感谢您的帮助/

标签: php download symfony flysystem


【解决方案1】:

由于Flysystemlocal adapter 没有获取可下载文件路径的方法! It is suggested 移动或存储公共web 文件夹中的文件,并以与资产相同的方式检索路径。

我最终使用了StreamedResponse [1] 而不是BinaryFileResponse

use Symfony\Component\HttpFoundation\StreamedResponse;

$response = new StreamedResponse();
$response->setCallback(function () {
    echo $downloadable_file_stream_contents;
    flush();
});
$response->send();

你如何获得 $downloadable_file_stream_contents;

$fs = new Filesystem($localAdapter);
$downloadable_file_stream = $fs->readStream($public_path);
$downloadable_file_stream_contents = stream_get_contents($downloadable_file_stream);

【讨论】:

  • 你是怎么得到$downloadable_file_stream_contents;的?
  • 这样做会触发静态文件的php事件,除非在传递文件之前需要自定义逻辑(即:授权层),这不是一个好习惯,您应该考虑存储它们在 web 目录下。
  • @bruno 是的,我需要保护data 文件夹中的文件,并仅在某些情况下(用户、组)提供它们。共享文件被复制并存储在web 目录中。
猜你喜欢
  • 2017-10-09
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
  • 2012-06-21
  • 1970-01-01
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多