Laravel 5 - Como acessar a imagem carregada no armazenamento no View?

172

Tenho avatares de usuários carregados no armazenamento do Laravel. Como posso acessá-los e renderizá-los em uma exibição?

O servidor está apontando para todas as solicitações /public, então como posso mostrá-las se estiverem na /storagepasta?

Tadeáš Jílek
fonte

Respostas:

349

A melhor abordagem é criar um link simbólico como @SlateEntropy muito bem apontado na resposta abaixo . Para ajudar com isso, desde a versão 5.3, o Laravel inclui um comando que facilita incrivelmente:

php artisan storage:link

Isso cria um link simbólico de public/storagepara storage/app/publicpara você e é tudo o que existe. Agora qualquer arquivo /storage/app/publicpode ser acessado através de um link como:

http://somedomain.com/storage/image.jpg

Se, por qualquer motivo, você não puder criar links simbólicos (talvez você esteja em hospedagem compartilhada etc.) ou desejar proteger alguns arquivos atrás de alguma lógica de controle de acesso, existe a alternativa de ter uma rota especial que leia e serve a imagem. Por exemplo, uma rota de fechamento simples como esta:

Route::get('storage/{filename}', function ($filename)
{
    $path = storage_path('public/' . $filename);

    if (!File::exists($path)) {
        abort(404);
    }

    $file = File::get($path);
    $type = File::mimeType($path);

    $response = Response::make($file, 200);
    $response->header("Content-Type", $type);

    return $response;
});

Agora você pode acessar seus arquivos exatamente como faria se tivesse um link simbólico:

http://somedomain.com/storage/image.jpg

Se você estiver usando a Biblioteca de Imagens de Intervenção, poderá usar seu responsemétodo interno para tornar as coisas mais sucintas:

Route::get('storage/{filename}', function ($filename)
{
    return Image::make(storage_path('public/' . $filename))->response();
});

AVISO

Lembre-se de que, ao exibir manualmente os arquivos, você está sujeito a uma penalidade de desempenho , porque está passando por todo o ciclo de vida das solicitações do Laravel para ler e enviar o conteúdo do arquivo, o que é consideravelmente mais lento do que o servidor HTTP.

Bogdan
fonte
Isso parece bom. Eu gostaria de fazer mais uma pergunta. É recomendável armazenar arquivos como avatares, polegares e assim por diante (arquivos enviados pelos usuários) no armazenamento?
Tadeáš Jílek
5
Você pode armazená-los onde quiser, mas, a menos que sejam arquivos particulares, acho melhor armazená-los no publicdiretório. Dessa forma, você evitará a sobrecarga de precisar compor uma resposta de imagem que possa ser tratada muito mais rapidamente pelo servidor HTTP.
Bogdan
2
Pessoalmente, eu não armazenaria arquivos de usuário na pasta pública, acho as coisas muito mais organizadas e gerenciáveis ​​quando a pasta de armazenamento é usada para armazenamento.
SlateEntropy
2
Eu não recomendaria nenhum deles, porque você está adicionando a sobrecarga de carregar o Laravel novamente e / ou alavancando o PHP para ler cada imagem. Usar um link simbólico, conforme descrito pelo CmdSft, seria muito mais rápido.
User1960364
4
@ user1960364 É por isso que o último parágrafo sugere fortemente o uso da abordagem de link simbólico. Mas a resposta em si, embora não seja a melhor solução do ponto de vista de desempenho, ainda é válida e pode ser a única abordagem para pessoas que executam aplicativos em servidores compartilhados, onde é impossível configurar os links simbólicos. A resposta também mostra como você pode veicular arquivos programaticamente, se necessário, talvez para servir arquivos criptografados, conforme solicitado nesta pergunta .
Bogdan
53

Uma opção seria criar um link simbólico entre uma subpasta no diretório de armazenamento e no diretório público.

Por exemplo

ln -s /path/to/laravel/storage/avatars /path/to/laravel/public/avatars

Esse também é o método usado pelo Envoyer , um gerente de implantação criado por Taylor Otwell, desenvolvedor do Laravel.

SlateEntropy
fonte
Eu sou um pouco novo nisso. Isso precisa ser executado no terminal ou definido em um arquivo de configuração em algum lugar do laravel?
Gaurav Mehta
Sim, você precisa executar isso na linha de comando. Precisaria ser configurado em qualquer lugar que você implante o aplicativo.
SlateEntropy
Para usuários do Windows, aqui está uma ferramenta autônoma para isso, se você não quiser usar o CMD: github.com/amd989/Symlinker#downloads
David
3
A pergunta feita como mostrar os avatares do usuário armazenados em storagepúblico, geralmente os avatares não exigem nenhum tipo de controle de acesso. Se nenhuma segurança for necessária, use qualquer tipo de middleware ou rota é apenas um golpe desperdiçado em seus recursos. Também é importante notar que, como o Laravel 5.2, existe um "disco" de arquivo separado para arquivos públicos ( laravel.com/docs/5.2/filesystem ) usando links simbólicos.
SlateEntropy
6
Existe um comando artesanal para fazer isso no Laravel 5.3: $ php artisan storage: link
Phil
22

De acordo com os documentos do Laravel 5.2, seus arquivos acessíveis ao público devem ser colocados no diretório

storage/app/public

Para torná-los acessíveis na web, você deve criar um link simbólico de public/storagepara storage/app/public.

ln -s /path/to/laravel/storage/app/public /path/to/laravel/public/storage

Agora você pode criar na sua visualização um URL para os arquivos usando o auxiliar de recursos:

echo asset('storage/file.txt');
Piotr
fonte
13

Antes de tudo, você precisa criar um link simbólico para o diretório de armazenamento usando o comando artisan

php artisan storage:link

Então, em qualquer visualização, você pode acessar sua imagem através do URL Helper como este.

url('storage/avatars/image.png');
Haider Ali
fonte
4

É bom salvar todas as imagens e documentos particulares no diretório de armazenamento, para que você tenha controle total sobre o éter do arquivo, você pode permitir que determinado tipo de usuário acesse ou restrinja o arquivo.

Faça uma rota / documentos e aponte para qualquer método do controlador:

public function docs() {

    //custom logic

    //check if user is logged in or user have permission to download this file etc

    return response()->download(
        storage_path('app/users/documents/4YPa0bl0L01ey2jO2CTVzlfuBcrNyHE2TV8xakPk.png'), 
        'filename.png',
        ['Content-Type' => 'image/png']
    );
}

Quando você vai bater o localhost:8000/docsarquivo será baixado, se houver algum.

O arquivo deve estar no root/storage/app/users/documentsdiretório de acordo com o código acima, isto foi testado Laravel 5.4.

Syed Shibli
fonte
4

Se você deseja carregar um pequeno número de imagens Privadas Você pode codificar as imagens para base64 e fazer eco <img src="{{$image_data}}">diretamente nelas :

$path = image.png
$full_path = Storage::path($path);
$base64 = base64_encode(Storage::get($path));
$image_data = 'data:'.mime_content_type($full_path) . ';base64,' . $base64;

Mencionei private porque você só deve usar esses métodos se não desejar armazenar imagens publicamente acessíveis por meio de url. Em vez disso, você deve sempre usar a maneira padrão (vincular armazenamento / pasta pública e servir imagens com o servidor HTTP).

Cuidado com a codificação para base64()ter dois lados negativos importantes:

  1. Isso aumentará o tamanho da imagem em ~ 30%.
  2. Você combina todos os tamanhos de imagens em uma solicitação, em vez de carregá-los em paralelo, isso não deve ser um problema para algumas miniaturas pequenas, mas para muitas imagens, evite usar esse método.
Arash Moosapour
fonte
2

Se você estiver usando php, basta usar a função php symlink, como a seguir:

symlink('/home/username/projectname/storage/app/public', '/home/username/public_html/storage')

altere o nome de usuário e o nome do projeto para os nomes corretos.

dagogodboss
fonte
1

sem nome do site

{{Storage::url($photoLink)}}

se você deseja adicionar o nome do site a ele, por exemplo, para anexar aos feltros JSON da API

 public function getPhotoFullLinkAttribute()
{
    return env('APP_URL', false).Storage::url($this->attributes['avatar']) ;
}
Jehad Ahmad Jaghoub
fonte
0

Se você é como eu e de alguma forma possui caminhos de arquivo completos (fiz alguns padrões glob () correspondentes nas fotos necessárias, acabo com caminhos de arquivos completos), e sua configuração de armazenamento está bem vinculada (ou seja, seus caminhos tem a string storage/app/public/), então você pode usar meu pequeno truque sujo abaixo: p)

 public static function hackoutFileFromStorageFolder($fullfilePath) {
        if (strpos($fullfilePath, 'storage/app/public/')) {
           $fileParts = explode('storage/app/public/', $fullfilePath);
           if( count($fileParts) > 1){
               return $fileParts[1];
           }
        }

        return '';
    }
Damilola Olowookere
fonte
0

Se o disco 'local' não estiver funcionando para você, tente o seguinte:

  1. Alterar local para público em 'default' => env('FILESYSTEM_DRIVER', 'public'), deproject_folder/config/filesystem.php
  2. Limpar cache de configuração php artisan config:clear
  3. Em seguida, crie um link sym php artisan storage:link

Para obter o URL da imagem carregada, você pode usar este Storage::url('iamge_name.jpg');

Dnyaneshwar Harer
fonte