Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

BGWeb's avatar
Level 7

File upload store() not returning path

According to the docs, calling store() on a file upload should return the path of the file: https://laravel.com/docs/7.x/filesystem#file-uploads

Here is my very basic example:

$photoPath = $this->photo->store('photos');
dd($photoPath);

In this case, $photoPath is returning true.

What am I doing wrong here? Is anyone else experiencing the same issue?

0 likes
7 replies
guybrush_threepwood's avatar

Hi @bgweb

Is $this->photo an instance of Illuminate\Http\UploadedFile?

Try:

dd(get_class($this->photo));

In other words, is $this->photo = $request->file('photo')?

BGWeb's avatar
Level 7

Technically, yes. This is a Livewire component, and they just recently added file upload support. So, to answer your question, $this->photo is an instance of TemporaryUploadedFile which extends UploadedFile:

class TemporaryUploadedFile extends UploadedFile
{
...
}

That being said:

dd(get_class($this->photo)) => "Livewire\TemporaryUploadedFile"

and

dd(get_parent_class($this->photo)) => "Illuminate\Http\UploadedFile"

Also, just to clarify, TemporaryUploadedFile has not overriden the store() method from UploadedFile

Thanks for the reply, interested to know what you think?

guybrush_threepwood's avatar

I see, that's a tricky one.

When you call store() on an instance of Illuminate/Http/UploadedFile it ends up calling the storeAs() method: https://github.com/laravel/framework/blob/7.x/src/Illuminate/Http/UploadedFile.php#L34

Which in turn calls putFileAs() on Illuminate/Filesystem/FilesystemAdapter: https://github.com/laravel/framework/blob/6732a76db9056d6b78f63b9fe441b4682ca578b1/src/Illuminate/Filesystem/FilesystemAdapter.php#L252

The method storeAs() is being overriden in the implementation of Livewire/TemporaryUploadedFile: https://github.com/livewire/livewire/blob/master/src/TemporaryUploadedFile.php#L98

Which ends up calling copy() on Illuminate/Filesystem/FilesystemAdapter if the target disk is the same as the source: https://github.com/laravel/framework/blob/6732a76db9056d6b78f63b9fe441b4682ca578b1/src/Illuminate/Filesystem/FilesystemAdapter.php#L363

And copy() defers to the FileSystem driver which in turn makes use of PHP's native copy function (which returns true/false): https://www.php.net/manual/en/function.copy.php

TemporaryUploadedFile storeAs implementation

    public function storeAs($path, $name, $options = [])
    {
        $options = $this->parseOptions($options);

        $disk = Arr::pull($options, 'disk') ?: $this->disk;

        $newPath = trim($path.'/'.$name, '/');

        if ($disk === $this->disk) {
            return $this->storage->copy($this->path, $newPath);
        }

        return Storage::disk($disk)->put(
            $newPath, $this->storage->readStream($this->path), $options
        );
    }

UploadedFile implementation

    public function storeAs($path, $name, $options = [])
    {
        $options = $this->parseOptions($options);

        $disk = Arr::pull($options, 'disk');

        return Container::getInstance()->make(FilesystemFactory::class)->disk($disk)->putFileAs(
            $path, $this, $name, $options
        );
    }
1 like
guybrush_threepwood's avatar

Check out Livewire's pull request: https://github.com/livewire/livewire/pull/958

Specifically:

I have to override Laravel's UploadedFile with a LivewireUploadedFile to bypass the is_uploaded_file call in the ->isValid() method because the file isn't actually uploaded with the request, we are just faking it. is_uplaoded_file is a PHP security feature we are now bypassing.

Creator explains how to override the default behaviour with a callback: https://github.com/livewire/livewire/pull/958#issuecomment-627482684

And here is an alternative implementation proposal: https://github.com/livewire/livewire/pull/958#issuecomment-630694107

Note this:

Can we have a FileBag just like ErrorBag available globally for all Livewire components. When a file is uploaded, save the file to sys_temp_dir and create an instance of UploadedFile and push it to the FileBag. When the user wants to save the form with other fields, the file can be pulled from the FileBag and since it is an instance of UploadedFile normal Laravel validation checks can be applied. My current implementation (rough) for the file upload (image) is as under (...)

guybrush_threepwood's avatar
Level 33

So, to sum up, I think the best bets would be to:

  1. Override the default behaviour with a callback

  2. Extend the TemporaryUploadedFile class and override the storeAs() method (once again!) in order to use put() or putFileAs() instead of copy(). You could even add a pull request with the changes to the original repository (the author seems to be very active): https://github.com/livewire/livewire/pulls

The alternative would be to find a hacky way to return the file path (instead of the result of the copy operation itself).

UsmanBasharmal's avatar

is $this->photo coming from the request or it's a model property?

dskanth's avatar

I had a similar issue, and this worked for me:

$this->files[0]->storeAs('photos');

Please or to participate in this conversation.