How to Upload Media From Laravel to Nextcloud with WebDAV

I am building an Laravel web app to help me generate annotations for images. I will be using these annotated images to train computer vision object detection models. As a part of that app, I need to a way to store images uploaded by users so that I can later go in and add object annotations to them. Enter my nextcloud setup, a self-hosted cloud storage service with (in my case) nearly 2 terabytes of storage connected to it. But, how did I make my Laravel app communicate with nextcloud to upload files?

Get NextCloud Creds

The first step is to get credentials to authorize your Laravel app to modify files on your nextcloud setup. Nextcloud implements a protocol called WebDAV, which stands for Web Distributed Authoring and Versioning. As the name suggests, this protocol allows users to collaboratively view and edit files online. Nextcloud has WebDAV built in by default, which is perfect for us, because we need to, at very least, create and view files on our nextcloud instance from our Laravel app.

In order to link our Laravel app to our nextcloud instance, we will need three things. Firstly, we will need a username of a nextcloud account. This is the username you use to login to your instance. Then, you will need a nextcloud WebDAV url. Luckily, this is easy to construct once you have your username. Simply use this template to find it:

https://[YOUR_NEXTCLOUD_URL]/remote.php/dav/files/[NEXTCLOUD_USERNAME]

You will know you have the correct url if you visit it and, after authenticating, you see the following message:

This is the WebDAV interface. It can only be accessed by WebDAV clients such as the Nextcloud desktop sync client.

Once you’ve got that, all you need from there is a password. Now, you could use your default account password. But, better practice is to create an app password for your Laravel app. To do this, sign in, then click your profile in the top right, then go to Administrative setttings > Security, and scroll all the way to the bottom. You should see an input labelled “App Name”. Fill in a name for your app, then click the button next to that input to register the app, and you will see your username alongside a randomly generated password.

Take these three values and place them in the .env file of your Laravel app, like this:

NEXTCLOUD_WEBDAV_URL=...
NEXTCLOUD_WEBDAV_PATH=...
NEXTCLOUD_WEBDAV_USER=...
NEXTCLOUD_WEBDAV_PASSWORD=...

NEXTCLOUD_WEBDAV_PATH is simply an extra variable used later that defines the default path within nextcloud to make file modifications at. This will be used later.

Once you’ve done this, we can move on to your Laravel application.

Register File System with WebDAV Adapter

Once you’ve got all your login info, the next step is to register a WebDAV file system adaptor with nextcloud. There are a variety of community-maintained file system adaptors that can be used with Laravel, including one for WebDAV. To use this file system, begin by installing it:

composer require league/flysystem-webdav

After that, we need to use our environment variables to set up the config for our new file system. Update config/filesystems.php file to include a new custom disk for your nextcloud instance:

return [
    ...
    'disks => [
        ...
        'nextcloud' => [
            'driver' => 'nextcloud',
            'webdav_url' => env('NEXTCLOUD_WEBDAV_URL'),
            'webdav_path' => env('NEXTCLOUD_WEBDAV_PATH'),
            'webdav_user' => env('NEXTCLOUD_WEBDAV_USER'),
            'webdav_password' => env('NEXTCLOUD_WEBDAV_PASSWORD')
        ], 
        ...
    ],
    ...
];

Then, we just need to register a new filesystem in the boot method of one of our app’s service providers so that our app can actually interact with the disk we configured. I used the built-in AppServiceProvider.php. Place the following code in the boot method of the service provider:

//register nextcloud file system driver (webdav)
Storage::extend('nextcloud', function ($app, $config) {
        $client = new Client([
            'baseUri' => rtrim($config['webdav_url'], '/') . '/',
            'userName' => $config['webdav_user'],
            'password' => $config['webdav_password'],
            'authType' => \Sabre\DAV\Client::AUTH_BASIC,  // Force Basic Auth
            'headers' => [
                'Authorization' => 'Basic ' . base64_encode($config['webdav_user'] . ':' . $config['webdav_password']),
            ]
        ]);

        $adapter = new WebDAVAdapter($client, $config['webdav_path'] ?? '/');

        return new FilesystemAdapter(
            new Filesystem($adapter, $config),
            $adapter,
            $config
        );
    });

So what have we done here? Basically, we have used the league/flysystem-webdav package to create a WebDAV Client. We use all the variables we used in our config explicitly to create the client. Additionally, we force Basic Auth to ensure our client provides our credentials to nextcloud in the format it is looking for.

Then, we create a WebDavAdapter using our client. This is where our configured path from the previous step comes in. This allows us to “scope” our app, making it operate from a specific nextcloud subdirectory.

Finally, we return a FileSystemAdapter created using a FileSystem created using our WebDavAdapter. This acts as an interface between our app and the community-built file system. Here are the import statements used for all these classes:

use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\Filesystem;
use League\Flysystem\WebDAV\WebDAVAdapter;
use Sabre\DAV\Client;

Store Media in the Filesystem

Now that we have registered the new file system, we can use it just like we would use any other disk. Simply specify the disk we configured when storing the file, and when this line is run, your file will be stored.

//store the file on the nextcloud disk
$path = $request->file('file')->store('folder_name', 'nextcloud');

Login to our nextcloud instance, and if everything was set up properly, you should see your file uploaded to the folder_name directory of your nextcloud instance. That folder will be created within the directory specified by the NEXTCLOUD_WEBDAV_PATH environment variable.

Conclusion

So, now you should know how to link your Laravel app to your nextcloud installation (or any other WebDAV-compatible file storage server) to store files. This same principle can be used with many other file system adapters, you just need to import the proper classes to link Laravel with these systems. I hope this guide has proven useful to you!

Take a look at my other articles on Laravel!

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *