Laravel 5 - ¿Cómo acceder a la imagen cargada en el almacenamiento dentro de View?

172

Tengo los avatares de los usuarios cargados en el almacenamiento de Laravel. ¿Cómo puedo acceder a ellos y representarlos en una vista?

El servidor señala todas las solicitudes /public, entonces, ¿cómo puedo mostrarlas si están en la /storagecarpeta?

Tadeáš Jílek
fuente

Respuestas:

349

El mejor enfoque es crear un enlace simbólico como @SlateEntropy muy bien señalado en la respuesta a continuación . Para ayudar con esto, desde la versión 5.3, Laravel incluye un comando que hace que esto sea increíblemente fácil de hacer:

php artisan storage:link

Eso crea un enlace simbólico de public/storagea storage/app/publicpara ti y eso es todo. Ahora /storage/app/publicse puede acceder a cualquier archivo en un enlace como:

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

Si, por algún motivo, no puede crear enlaces simbólicos (tal vez está en un alojamiento compartido, etc.) o desea proteger algunos archivos detrás de alguna lógica de control de acceso, existe la alternativa de tener una ruta especial que lea y sirve la imagen. Por ejemplo, una ruta de cierre simple 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;
});

Ahora puede acceder a sus archivos tal como lo haría si tuviera un enlace simbólico:

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

Si está utilizando la Biblioteca de imágenes de intervención , puede usar su responsemétodo integrado para hacer las cosas más concisas:

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

ADVERTENCIA

Tenga en cuenta que al servir manualmente los archivos está incurriendo en una penalización de rendimiento , ya que está atravesando todo el ciclo de vida de la solicitud de Laravel para leer y enviar el contenido del archivo, que es considerablemente más lento que hacer que el servidor HTTP lo maneje.

Bogdan
fuente
Eso parece bueno Me gustaría hacer una pregunta más. ¿Se recomienda almacenar archivos como avatares, pulgares, etc. (archivos cargados de los usuarios) en el almacenamiento?
Tadeáš Jílek
55
Puede almacenarlos donde desee, pero a menos que sean archivos privados, creo que es mejor que los almacene en el publicdirectorio. De esta manera, evitará la sobrecarga de tener que componer una respuesta de imagen que el servidor HTTP pueda manejar mucho más rápido.
Bogdan
2
Personalmente, no almacenaría archivos de usuario en la carpeta pública, encuentro las cosas mucho más ordenadas y más manejables cuando la carpeta de almacenamiento se usa para el almacenamiento.
SlateEntropy
2
No recomendaría ninguno de estos porque entonces está agregando la sobrecarga de cargar Laravel nuevamente y / o aprovechar PHP para leer cada imagen. Usar un enlace simbólico como lo describe CmdSft sería mucho más rápido.
user1960364
44
@ user1960364 Es por eso que el último párrafo sugiere utilizar el enfoque de enlace simbólico. Pero la respuesta en sí, aunque no es la mejor solución desde el punto de vista del rendimiento, sigue siendo válida y puede ser el único enfoque para las personas que ejecutan aplicaciones en servidores compartidos donde los enlaces simbólicos pueden ser imposibles de configurar. La respuesta también muestra cómo puede servir archivos mediante programación si surge la necesidad, tal vez para servir archivos cifrados como se hizo en esta pregunta .
Bogdan
53

Una opción sería crear un enlace simbólico entre una subcarpeta en su directorio de almacenamiento y el directorio público.

Por ejemplo

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

Este es también el método utilizado por Envoyer , un administrador de implementación creado por Taylor Otwell, el desarrollador de Laravel.

PizarraEntropía
fuente
Soy un poco nuevo en esto. ¿Esto debe ejecutarse en la terminal o definirse en un archivo de configuración en algún lugar de laravel?
Gaurav Mehta
Sí, necesita ejecutar esto a través de la línea de comando. Tendría que configurarse en cualquier lugar donde implemente la aplicación.
SlateEntropy
Para los usuarios de Windows, aquí hay una herramienta independiente para eso si no quieres usar CMD: github.com/amd989/Symlinker#downloads
David
3
La pregunta se refería a cómo mostrar los avatares de los usuarios almacenados storagepúblicamente, por lo general, los avatares no requieren ningún tipo de control de acceso. Si no se requiere seguridad, usar cualquier tipo de middleware o ruta es solo un golpe perdido para sus recursos. También vale la pena señalar que desde Laravel 5.2 existe un "disco" de archivo separado para archivos públicos ( laravel.com/docs/5.2/filesystem ) que utilizan enlaces simbólicos.
SlateEntropy
66
Hay un comando artesanal para hacer esto en Laravel 5.3: $ php artisan storage: enlace
Phil
22

De acuerdo con los documentos de Laravel 5.2, sus archivos de acceso público deben colocarse en el directorio

storage/app/public

Para hacerlos accesibles desde la web, debe crear un enlace simbólico desde public/storagehasta storage/app/public.

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

Ahora puede crear en su vista una URL a los archivos usando el asistente de activos:

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

En primer lugar, debe crear un enlace simbólico para el directorio de almacenamiento utilizando el comando artesanal

php artisan storage:link

Luego, en cualquier vista, puede acceder a su imagen a través de url helper de esta manera.

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

Es bueno guardar todas las imágenes y documentos privados en el directorio de almacenamiento, entonces tendrá control total sobre el archivo ether, puede permitir que cierto tipo de usuario acceda al archivo o lo restrinja.

Haga una ruta / documentos y señale cualquier método de 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']
    );
}

Cuando golpees el localhost:8000/docsarchivo se descargará si existe alguno.

El archivo debe estar en el root/storage/app/users/documentsdirectorio de acuerdo con el código anterior, esto se probó Laravel 5.4.

Syed Shibli
fuente
4

Si desea cargar una pequeña cantidad de imágenes privadas Puede codificar las imágenes en base64 y hacerlas eco <img src="{{$image_data}}">directamente en :

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

Mencioné privado porque solo debe usar estos métodos si no desea almacenar imágenes accesibles públicamente a través de la URL, en su lugar, siempre debe usar la forma estándar (almacenamiento de enlaces / carpeta pública y servir imágenes con el servidor HTTP).

Tenga cuidado con la codificación para base64()tener dos desventajas importantes:

  1. Esto aumentará el tamaño de la imagen en ~ 30%.
  2. Combina todos los tamaños de imágenes en una solicitud, en lugar de cargarlos en paralelo, esto no debería ser un problema para algunas miniaturas pequeñas, pero para muchas imágenes, evite usar este método.
Arash Moosapour
fuente
2

Si está utilizando php, simplemente utilice la función de enlace simbólico php, como la siguiente:

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

cambie el nombre de usuario y el nombre del proyecto a los nombres correctos.

dagogodboss
fuente
1

sin nombre del sitio

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

si desea agregar el nombre del sitio a este ejemplo para agregarlo a los felinos de la API JSON

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

Si eres como yo y de alguna manera tienes rutas de archivos completas (hice una coincidencia de patrón glob () en las fotos requeridas, así que terminé con rutas de archivos completas), y tu configuración de almacenamiento está bien vinculada (es decir, tus rutas tener la cadena storage/app/public/), entonces puedes usar mi pequeño truco sucio a continuación: 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
fuente
0

Si el disco 'local' no funciona para usted, intente esto:

  1. El cambio local al público 'default' => env('FILESYSTEM_DRIVER', 'public'),a partirproject_folder/config/filesystem.php
  2. Borrar caché de configuración php artisan config:clear
  3. Luego crea un enlace sym php artisan storage:link

Para obtener la URL de la imagen cargada, puede usar esto Storage::url('iamge_name.jpg');

Dnyaneshwar Harer
fuente