84

I've been experimenting using the new Flysystem integration with Laravel 5. I am storing 'localised' paths to the DB, and getting the Storage facade to complete the path. For example I store screenshots/1.jpg and using

Storage::disk('local')->get('screenshots/1.jpg')

or

Storage::disk('s3')->get('screenshots/1.jpg') 

I can retrieve the same file on different disks.

get retrieves the file contents, but I am hoping to use it in my views like this:

<img src="{{ Storage::path('screenshots/1.jpg') }}" />

but path, or anything able to retrieve the full path is not available (as far as I can see). So how can I return the full path? Or, I'm wondering if this is by design? If so, why am I not supposed to be able to get the full path? Or, am I going about this completely the wrong way?

miken32
  • 35,483
  • 13
  • 81
  • 108
daviestar
  • 4,017
  • 3
  • 23
  • 43

13 Answers13

157

The Path to your Storage disk would be :

$storagePath  = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix()

I don't know any shorter solutions to that...

You could share the $storagePath to your Views and then just call

$storagePath."/myImg.jpg";
shock_gone_wild
  • 6,262
  • 4
  • 25
  • 48
  • This is the perfect solution to get the path of the public storage folder. Thanks! – David Jul 10 '16 at 00:46
  • 14
    Another way is to use `applyPathPrefix` like this: `Storage::disk('local')->getDriver()->getAdapter()->applyPathPrefix('myImg.jpg');` – Maxim Lanin Sep 01 '16 at 15:15
  • Thanks for the two ways! – Benjamin Piette Sep 02 '16 at 07:44
  • 3
    @maximLanin: Somehow if you copy your example, the last (applyPathPrefix) has an weird character between the h and P (path*Prefix). If you copy paste that, you will get an error. The first `applyPathPrefix` you can copy. Very strange. (you can test it by double clicking the last method name in your example. – Maurice Feb 21 '17 at 11:24
  • 3
    `getDriver()` is not needed. Simply `Storage::disk('local')->getAdapter()->getPathPrefix()` will work as well. – RA. Oct 16 '17 at 06:21
  • 6
    Perhaps good to know that since Laravel 5.4 there is a new, simple method `Storage::path`, see [Bilal's answer](https://stackoverflow.com/a/49532280/2286722) – Marten Koetsier Apr 17 '18 at 19:18
72

This method exists since Laravel 5.4, you can get it by:

$path = Storage::disk('public')->path($filename);
Bilal Gultekin
  • 3,631
  • 3
  • 20
  • 27
57

Edit: Solution for L5.2+

There's a better and more straightforward solution.

Use Storage::url($filename) to get the full path/URL of a given file. Note that you need to set S3 as your storage filesystem in config/filesystems.php: 'default' => 's3'

Of course, you can also do Storage::disk('s3')->url($filename) in the same way.

As you can see in config/filesystems.php there's also a parameter 'cloud' => 's3' defined, that refers to the Cloud filesystem. In case you want to mantain the storage folder in the local server but retrieve/store some files in the cloud use Storage::cloud(), which also has the same filesystem methods, i.e. Storage::cloud()->url($filename).

The Laravel documentation doesn't mention this method, but if you want to know more about it you can check its source code here.

shock_gone_wild
  • 6,262
  • 4
  • 25
  • 48
Pere Joan Martorell
  • 1,316
  • 17
  • 20
  • nice! this is a [new method](https://github.com/laravel/framework/commit/ef81c531512de75214e3723fa0725c2b64ad6395#diff-897d962b3751fa634c9cef12e32e7318), but I'm glad it's here now! Does the Storage class work in views by default? If so, will mark this as the correct answer. – daviestar Apr 05 '16 at 21:35
  • yes! it works in your views by default, so you don't have to worry about it at all. – Pere Joan Martorell Apr 11 '16 at 10:28
  • 6
    **This is for L5.2+** – daviestar Apr 11 '16 at 14:01
9

This is how I got it to work - switching between s3 and local directory paths with an environment variable, passing the path to all views.

In .env:

APP_FILESYSTEM=local or s3
S3_BUCKET=BucketID

In config/filesystems.php:

'default' => env('APP_FILESYSTEM'),

In app/Providers/AppServiceProvider:

public function boot()
{
    view()->share('dynamic_storage', $this->storagePath());
}

protected function storagePath()
{
    if (Storage::getDefaultDriver() == 's3') {
        return Storage::getDriver()
                ->getAdapter()
                ->getClient()
                ->getObjectUrl(env('S3_BUCKET'), '');
    }

    return URL::to('/');
}
Salim Djerbouh
  • 9,070
  • 4
  • 19
  • 49
daviestar
  • 4,017
  • 3
  • 23
  • 43
  • 1
    Using the s3 Storage as describe generated an error for me. So I amended the example to this `return Storage::disk('s3')->getDriver()->getAdapter()->getClient()->getObjectUrl(env('S3_BUCKET'), '').'/'; ` – Lionel Morrison Jun 11 '15 at 20:39
6

If you just want to display storage (disk) path use this:

Storage::disk('local')->url('screenshots/1.jpg'); // storage/screenshots/1.jpg
Storage::disk('local')->url(''): // storage

Also, if you are interested, I created a package (https://github.com/fsasvari/laravel-uploadify) just for Laravel so you can use all those fields on Eloquent model fields:

$car = Car::first();

$car->upload_cover_image->url();
$car->upload_cover_image->name();
$car->upload_cover_image->basename();
$car->upload_cover_image->extension();
$car->upload_cover_image->filesize();
fsasvari
  • 1,583
  • 17
  • 26
5

First get file url/link then path, as below:

$url = Storage::disk('public')->url($filename);
$path = public_path($url);
HiDeo
  • 9,900
  • 8
  • 40
  • 43
filius
  • 51
  • 1
  • 2
4

Well, weeks ago I made a very similiar question (Get CDN url from uploaded file via Storage): I wanted the CDN url to show the image in my view (as you are requiring ).

However, after review the package API I confirmed that there is no way do this task. So, my solution was avoid using flysystem. In my case, I needed to play with RackSpace. So, finally decide to create my use package and make my own storage package using The PHP SDK for OpenStack.

By this way, you have full access for functions that you need like getPublicUrl() in order to get the public URL from a cdn container:

/** @var DataObject $file */
$file = \OpenCloud::container('cdn')->getObject('screenshots/1.jpg');

// $url:  https://d224d291-8316ade.ssl.cf1.rackcdn.com/screenshots/1.jpg
$url = (string) $file->getPublicUrl(UrlType::SSL);

In conclusion, if need to take storage service to another level, then flysystem is not enough. For local purposes, you can try @nXu's solution

Community
  • 1
  • 1
manix
  • 13,613
  • 9
  • 64
  • 98
3

If you need absolute URL of the file, use below code:

$file_path = \Storage::url($filename);
$url = asset($file_path);
// Output: http://example.com/storage/filename.jpg
Arvind Bhardwaj
  • 5,078
  • 5
  • 30
  • 48
2

Store method:

public function upload($img){
   $filename = Carbon::now() . '-' .  $img->getClientOriginalName();
   return Storage::put($filename, File::get($img)) ? $filename : '';
}

Route:

 Route::get('image/{filename}', [
        'as'   => 'product.image',
        'uses' => 'ProductController@getImage',
    ]);

Controller:

 public function getImage($filename)
    {
        $file = Storage::get($filename);

        return new Response($file, 200);
    }

View:

 <img src="{{ route('product.image', ['filename' => $yourImageName]) }}" alt="your image"/>
MevlütÖzdemir
  • 1,916
  • 1
  • 18
  • 26
2

Another solution I found is this:

Storage::disk('documents')->getDriver()->getConfig()->get('url')

Will return the url with the base path of the documents Storage

Marc Garcia
  • 879
  • 6
  • 14
1

Take a look at this: How to use storage_path() to view an image in laravel 4 . The same applies to Laravel 5:

Storage is for the file system, and the most part of it is not accessible to the web server. The recommended solution is to store the images somewhere in the public folder (which is the document root), in the public/screenshots/ for example. Then when you want to display them, use asset('screenshots/1.jpg').

Community
  • 1
  • 1
nXu
  • 2,009
  • 1
  • 21
  • 34
  • I am trying to set up a 'disk' to be my public folder when developing and s3 when live – daviestar Mar 10 '15 at 13:09
  • It doesn't really matter, `Storage::path()` returns the path of the file on your server, but you need a URL to it and the webserver can only serve files from your document root, which is `/public`. Create your directories inside it and use `url()` or `asset()` in the blade templates. – nXu Mar 10 '15 at 13:12
  • 2
    `Storage::path()` doesn't exist, I'd like it to though – daviestar Mar 10 '15 at 13:13
  • Okay, I misunderstood, sorry. What I'd do, is still the same: save the full path to the DB, be it local or s3. When uploading / creating images, simply check for `getenv('debug')` and decide which one to use. – nXu Mar 10 '15 at 13:17
  • I was trying to avoid saving the full path but maybe it is the most sensible way to go. – daviestar Mar 10 '15 at 13:25
1

In my case, i made separate method for local files, in this file: src/Illuminate/Filesystem/FilesystemAdapter.php

    /**
 * Get the local path for the given filename.
 * @param $path
 * @return string
 */
public function localPath($path)
{
    $adapter = $this->driver->getAdapter();
    if ($adapter instanceof LocalAdapter) {
        return $adapter->getPathPrefix().$path;
    } else {
        throw new RuntimeException('This driver does not support retrieving local path');
    }
}

then, i create pull request to framework, but it still not merged into main core yet: https://github.com/laravel/framework/pull/13605 May be someone merge this one))

Ruslan Terekhov
  • 101
  • 1
  • 4
0

this work for me in 2020 at laravel 7

        $image_resize = Image::make($image->getRealPath());
        $image_resize->resize(800,600);
        $image_resize->save(Storage::disk('episodes')->path('') . $imgname);

so you can use it like this

echo Storage::disk('public')->path('');
Ahmad Odeh
  • 81
  • 1
  • 11