Laravel 5 - Jak uzyskać dostęp do obrazu przesłanego do magazynu w widoku?

172

Mam przesłane awatary użytkowników do magazynu Laravel. Jak mogę uzyskać do nich dostęp i wyświetlić je w widoku?

Serwer wskazuje na wszystkie żądania /public, więc jak mogę je wyświetlić, jeśli znajdują się w /storagefolderze?

Tadeáš Jílek
źródło

Odpowiedzi:

349

Najlepszym rozwiązaniem jest utworzenie dowiązania symbolicznego jak @SlateEntropy bardzo dobrze wskazał w odpowiedzi poniżej . Aby w tym pomóc, od wersji 5.3 Laravel zawiera polecenie, które sprawia, że ​​jest to niezwykle łatwe:

php artisan storage:link

To tworzy dla Ciebie link symboliczny od public/storagedo storage/app/publici to wszystko. Teraz do każdego pliku /storage/app/publicmożna uzyskać dostęp za pośrednictwem linku takiego jak:

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

Jeśli z jakiegoś powodu nie możesz tworzyć dowiązań symbolicznych (może korzystasz z hostingu współdzielonego itp.) Lub chcesz zabezpieczyć niektóre pliki za pewną logiką kontroli dostępu, istnieje alternatywa posiadania specjalnej trasy, która czyta i służy obrazowi. Na przykład prosta trasa zamknięcia, taka jak ta:

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;
});

Możesz teraz uzyskać dostęp do swoich plików tak samo, jak gdybyś miał łącze symboliczne:

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

Jeśli korzystasz z interwencyjnej biblioteki obrazów , możesz użyć jej wbudowanej responsemetody, aby uczynić rzeczy bardziej zwięzłymi:

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

OSTRZEŻENIE

Pamiętaj, że ręcznie obsługując pliki, ponosisz spadek wydajności , ponieważ przechodzisz przez cały cykl życia żądania Laravel, aby odczytać i wysłać zawartość pliku, co jest znacznie wolniejsze niż obsługa serwera HTTP.

Bogdana
źródło
To wydaje się dobre. Chciałbym zadać jeszcze jedno pytanie. Czy zaleca się przechowywanie w pamięci plików takich jak awatary, kciuki itp. (Przesłane pliki od użytkowników)?
Tadeáš Jílek
5
Możesz je przechowywać w dowolnym miejscu, ale jeśli nie są to pliki prywatne, myślę, że lepiej przechowywać je w publickatalogu. W ten sposób unikniesz konieczności tworzenia odpowiedzi obrazu, którą serwer HTTP mógłby obsłużyć znacznie szybciej.
Bogdan
2
Osobiście nie przechowywałbym plików użytkownika w folderze publicznym, uważam, że rzeczy są znacznie uporządkowane i łatwiejsze w zarządzaniu, gdy folder przechowywania jest używany do przechowywania.
SlateEntropy
2
Nie polecałbym żadnego z nich, ponieważ wtedy dodajesz obciążenie związane z ponownym ładowaniem Laravel i / lub wykorzystując PHP do odczytu każdego obrazu. Użycie łącza symbolicznego zgodnie z opisem w CmdSft byłoby znacznie szybsze.
user1960364
4
@ user1960364 Dlatego w ostatnim akapicie zdecydowanie zaleca się użycie metody dowiązania symbolicznego. Ale sama odpowiedź, choć nie jest najlepszym rozwiązaniem z punktu widzenia wydajności, jest nadal aktualna i może być jedynym podejściem dla osób uruchamiających aplikacje na serwerach współdzielonych, na których skonfigurowanie linków symbolicznych może być niemożliwe. Odpowiedź pokazuje również, w jaki sposób można programowo obsługiwać pliki, jeśli zajdzie taka potrzeba, na przykład w celu obsługi zaszyfrowanych plików, takich jak zadane w tym pytaniu .
Bogdan
53

Jedną z opcji byłoby utworzenie dowiązania symbolicznego między podfolderem w katalogu magazynu a katalogiem publicznym.

Na przykład

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

Jest to również metoda stosowana przez Envoyer , menedżera wdrożeń zbudowanego przez Taylora Otwella, dewelopera Laravel.

SlateEntropy
źródło
Jestem w tym trochę nowy. Czy to musi być uruchamiane na terminalu lub zdefiniowane w pliku konfiguracyjnym gdzieś w laravel?
Gaurav Mehta
tak, musisz to uruchomić przez wiersz poleceń. Musiałby zostać skonfigurowany wszędzie tam, gdzie wdrażasz aplikację.
SlateEntropy
Dla użytkowników systemu Windows tutaj jest samodzielne narzędzie, jeśli nie chcesz używać CMD: github.com/amd989/Symlinker#downloads
David
3
Pytanie dotyczyło sposobu wyświetlania awatarów użytkowników przechowywanych storagepublicznie, zazwyczaj awatary nie wymagają żadnej kontroli dostępu. Jeśli żadne zabezpieczenia nie są wymagane, użycie jakiegokolwiek oprogramowania pośredniego lub trasy jest po prostu zmarnowanym uderzeniem w zasoby. Warto również zauważyć, ponieważ Laravel 5.2 istnieje oddzielny plik „dysk” dla plików publicznych ( laravel.com/docs/5.2/filesystem ) przy użyciu dowiązań symbolicznych.
SlateEntropy
6
W Laravel 5.3 jest polecenie rzemieślnika, aby to zrobić: $ php magazyn rzemieślnika: link
Phil
22

Zgodnie z dokumentacją Laravel 5.2, Twoje publicznie dostępne pliki powinny być umieszczone w katalogu

storage/app/public

Aby udostępnić je w Internecie, należy utworzyć łącze symboliczne od public/storagedo storage/app/public.

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

Teraz możesz utworzyć w swoim widoku adresy URL do plików przy użyciu pomocnika zasobów:

echo asset('storage/file.txt');
Piotr
źródło
13

Przede wszystkim musisz utworzyć dowiązanie symboliczne do katalogu przechowywania za pomocą polecenia artisan

php artisan storage:link

Następnie w dowolnym widoku możesz uzyskać dostęp do obrazu za pomocą pomocnika adresu URL w ten sposób.

url('storage/avatars/image.png');
Haider Ali
źródło
4

Dobrze jest zapisać wszystkie prywatne obrazy i dokumenty w katalogu przechowywania, wtedy będziesz mieć pełną kontrolę nad plikiem ether, możesz zezwolić określonemu typowi użytkownika na dostęp do pliku lub ograniczyć.

Utwórz trasę / docs i wskaż dowolną metodę kontrolera:

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']
    );
}

Po trafieniu localhost:8000/docsplik zostanie pobrany, jeśli taki istnieje.

Plik musi znajdować się w root/storage/app/users/documentskatalogu zgodnie z powyższym kodem, na którym został przetestowany Laravel 5.4.

Syed Shibli
źródło
4

Jeśli chcesz załadować niewielką liczbę prywatnych obrazów, możesz zakodować obrazy do base64 i wywołać je <img src="{{$image_data}}">bezpośrednio:

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

Wspomniałem o prywatnych, ponieważ powinieneś używać tych metod tylko wtedy, gdy nie chcesz przechowywać obrazów publicznie dostępnych przez url, zamiast tego musisz zawsze używać standardowego sposobu (przechowywanie linków / folder publiczny i serwowanie obrazów z serwerem HTTP).

Uważaj na kodowanie, aby base64()mieć dwie ważne wady:

  1. Zwiększy to rozmiar obrazu o ~ 30%.
  2. Łączysz wszystkie rozmiary obrazów w jednym żądaniu, zamiast ładować je równolegle, nie powinno to stanowić problemu w przypadku niektórych małych miniatur, ale w przypadku wielu obrazów należy unikać tej metody.
Arash Moosapour
źródło
2

Jeśli używasz php, po prostu użyj funkcji linku symbolicznego php, na przykład:

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

zmień nazwę użytkownika i nazwę projektu na właściwe nazwy.

dagogodboss
źródło
1

bez nazwy witryny

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

jeśli chcesz dodać do niego nazwę witryny, przykład, aby dołączyć do plików API JSON

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

Jeśli jesteś podobny do mnie i jakoś masz pełne ścieżki do plików (zrobiłem trochę dopasowywania wzorców glob () na wymaganych zdjęciach, więc w zasadzie kończy się na pełnych ścieżkach plików), a twoja konfiguracja pamięci jest dobrze połączona (tj. mam ciąg storage/app/public/), możesz użyć mojego małego brudnego hacka poniżej: 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
źródło
0

Jeśli dysk „lokalny” nie działa, spróbuj tego:

  1. Zmień lokalny na publiczny w 'default' => env('FILESYSTEM_DRIVER', 'public'),zproject_folder/config/filesystem.php
  2. Wyczyść pamięć podręczną konfiguracji php artisan config:clear
  3. Następnie utwórz łącze symboliczne php artisan storage:link

Aby uzyskać adres URL przesłanego obrazu, możesz użyć tego Storage::url('iamge_name.jpg');

Dnyaneshwar Harer
źródło