SonataMediaBundle 的公共和私人媒体上传到不同的文件夹(网络和私人)

Posted

技术标签:

【中文标题】SonataMediaBundle 的公共和私人媒体上传到不同的文件夹(网络和私人)【英文标题】:Public and private Media of SonataMediaBundle uploaded in different folders (web and private) 【发布时间】:2016-02-19 05:05:19 【问题描述】:

我正在使用 SonataMediaBundle,直到现在我一直在 Symfony 的 web 文件夹中公开上传文件。这是我的配置文件的一部分:

contexts:
    default:  # the default context is mandatory
        providers:
            - sonata.media.provider.dailymotion
            - sonata.media.provider.youtube
            - sonata.media.provider.image
            - sonata.media.provider.file
            - sonata.media.provider.vimeo

        formats:
            small:  width: 100 , quality: 70
            big:    width: 500 , quality: 70
    profile_pics:  # the default context is mandatory
        providers: 
            - sonata.media.provider.dailymotion
            - sonata.media.provider.youtube
            - sonata.media.provider.image
            - sonata.media.provider.file
            - sonata.media.provider.vimeo

        formats:
            small:  width: 100 , quality: 70
            big:    width: 500 , quality: 70

cdn:
    server:
        path: %cdn_server_path% # http://media.sonata-project.org/

filesystem:
    local:
        directory:  %kernel.root_dir%/../web/uploads/media
        create:     false

在我的parameters.yml 中有cdn_server_path: /uploads/media/

这将上传web/uploads/media/contextname/0001/01/***中的文件。

这些文件位于公共文件夹中,所有人都可以看到这些文件。我知道我可以在app/Resources/ 的某个地方更改此文件夹,但这会使我的所有文件都成为私有文件,这是我不想要的。私有,我的意思是它们应该由控制器以某种方式提供服务。

如何区分一些文件是公开的,而另一些文件是私人的?有没有办法让某个上下文上传文件与另一个不同?还是其他方式?

此外,当将文件上传到 app/Resources 文件夹时,它们无法预览,因为它们的 url 变为 http://website.com/app/Resources/media/profile_pics/0001/01/85e05ab9685b1745af4e64ff98ef91eed6e4ccdf.jpeg 不公开,因为它不在 web 文件夹中,这是 Symfony 唯一拥有的公开文件。如何做到这一点?

编辑:我已经设法完成了上传部分(检查下面的答案),但检索部分有点麻烦。我仍在寻找一种方法。

【问题讨论】:

【参考方案1】:

好的,我快到了。我的文件正在上传到我想要的任何文件夹,但我无法显示它们。

这个想法是创建一个具有自己的文件系统和适配器服务的自定义提供程序。问题是我需要将要上传文件的文件夹传递给适配器服务。该适配器被传递给文件系统,然后被传递给提供者。 SonataMediaBundle 的问题在于它不允许您修改适配器的目录,因此您必须创建自己的目录并将其一直传递给您的提供者。

服务:

sonata.media.provider.private:
    class: MedAppBundle\Services\PrivateFilesProvider
    tags:
      -  name: sonata.media.provider 
    arguments: [%private_provider_name%,@medapp_private.filesystem,@sonata.media.cdn.server,@sonata.media.generator.default,@sonata.media.thumbnail.format]
medapp_private.filesystem:
    class: MedAppBundle\Services\PrivateFilesystem
    arguments: [@medapp_private.adapter]
medapp_private.adapter:
    class: MedAppBundle\Services\PrivateFileAdapter
    arguments: [%private_filesystem_directory%,true]

parameters.yml

private_filesystem_directory: %kernel.root_dir%/Resources/media
private_provider_name: sonata.media.provider.private

自定义适配器

use Sonata\MediaBundle\Filesystem\Local;

class PrivateFileAdapter extends Local



文件系统

use Gaufrette\Filesystem;

class PrivateFilesystem extends Filesystem



最后,提供者

use Application\Sonata\MediaBundle\Entity\Media;
use Gaufrette\Filesystem;
use Sonata\MediaBundle\CDN\CDNInterface;
use Sonata\MediaBundle\Generator\GeneratorInterface;
use Sonata\MediaBundle\Provider\FileProvider;

use Sonata\MediaBundle\Thumbnail\ThumbnailInterface;

class PrivateFilesProvider extends FileProvider


    public function getPrivateMedia(Media $media)
    
        // $path = $this->generatePublicUrl($media, 'reference');
        //  $ppath = $this->generatePrivateUrl($media, "reference");
        $content = $this->getReferenceFile($media)->getContent();
        header('Content-Type: ' . $media->getContentType());


        return 'data:' .  $media->getContentType() . ';base64,' . base64_encode($content);

    

然后,将此提供程序添加到您的任何 sonata_media 上下文中。我已将其添加到默认上下文中,例如:

sonata_media:
    db_driver: doctrine_orm 
    default_context: default 
    contexts:
        default:  
            providers:
                - sonata.media.provider.dailymotion
                - sonata.media.provider.youtube
                - sonata.media.provider.image
                - sonata.media.provider.file
                - sonata.media.provider.vimeo
                - sonata.media.provider.private

在私人文件夹中创建新媒体:

$media = new Media();        
$media->setBinaryContent($file);
$media->setContext('default');
$media->setProviderName('sonata.media.provider.private');
$this->em->persist($media);
$this->em->flush();

$file 是来自您的表单的文件内容。 这将创建文件夹app\Resources\media\default\0001\01,文件将在其中上传。

现在的问题是检索它们,因为它们没有公共链接,需要在控制器中检索。我在提供程序中创建了一个 getPrivateMedia() 方法,但它没有按预期工作。

编辑: 注意到服务也可以这样定义:

sonata.media.provider.private:
    class: MedAppBundle\Services\PrivateFilesProvider
    tags:
      -  name: sonata.media.provider 
    arguments: [%private_provider_name%,@medapp_private.filesystem,@sonata.media.cdn.server,@sonata.media.generator.default,@sonata.media.thumbnail.format,%kernel.root_dir%]

medapp_private.filesystem:
    class: Gaufrette\Filesystem
    arguments: [@medapp_private.adapter]

medapp_private.adapter:
    class: Sonata\MediaBundle\Filesystem\Local
    arguments: [%private_filesystem_directory%,true]

不需要为提供者创建自定义文件系统或适配器,只需创建新服务并将目录传递给适配器,然后将适配器传递给文件系统,将文件系统传递给自定义提供者。这是您不需要任何自定义功能的情况。

【讨论】:

【参考方案2】:

我遇到了完全相同的问题,非常感谢上传解决方案。

对于从安全目录下载文件 - Sonata 提供了一种方法,因此您甚至不需要此处概述的自定义提供程序:https://sonata-project.org/bundles/media/master/doc/reference/security.html

我的实现如下:

services:
    sonata.media.provider.private:
        class: Sonata\MediaBundle\Provider\FileProvider
        tags:
            -  name: sonata.media.provider 
        arguments:
            - 'sonata.media.provider.private'
            - '@app.sonata.media.private.filesystem'
            - '@sonata.media.cdn.server'
            - '@sonata.media.generator.default'
            - '@sonata.media.thumbnail.format'

    app.sonata.media.private.filesystem:
        class: Gaufrette\Filesystem
        arguments: ['@app.sonata.media.private.adapter']

    app.sonata.media.private.adapter:
        class: Sonata\MediaBundle\Filesystem\Local
        arguments: 
            - "%kernel.root_dir%/../doclib/uploads"
            - true

具有明确定义的安全策略的上下文以控制谁可以访问文件。本例中的超级管理员:

sonata_media:
    contexts:
        privatefiles:
            download:
                strategy: sonata.media.security.superadmin_strategy
                mode: http
            providers:
                - sonata.media.provider.private

然后您可以在 twig 中获取可下载资源的链接,如下所示:

 path('sonata_media_download',  'id':media|sonata_urlsafeid  ) 

sonata_media_download 映射MediaController::downloadAction(),它实现了您尝试使用getPrivateMedia() 实现的功能。

我现在坚持的一点是为新提供者设置allowed_extensions 等内容,因为providers 部分不接受private 作为名称,所以我认为这需要在某处特别定义。

编辑: allowed_extensions 等可以通过自定义提供程序服务定义作为进一步的参数传递。

【讨论】:

以上是关于SonataMediaBundle 的公共和私人媒体上传到不同的文件夹(网络和私人)的主要内容,如果未能解决你的问题,请参考以下文章

请问公共仓库和私人仓库有啥不同?

查询 - 向用户发送公共和私人消息

jwt上的私人和公共索赔有啥区别

Solidity 中的内部/外部和公共/私人功能有啥区别?

财产公共和私人但不受保护?

“公共”和“私人”可见性修饰符的缩进[关闭]