Silverstripe uploadfields files to another server

Hi,

Is there any option that i can upload uploadfield files to another server.
when i upload a file is goes into assets and showing in files section, at the same time i want to upload the image/file to my another server.
is it possible?

@Tim @GuySartorelli

Please guide is there any possibility to load admin assets from CDN images.
2022-11-08_13-17-57

like in images both section thumbnails are populating from local server. I want them to be loaded from CDN as populating on frontend.

@Tim
I want to link the application with cloudflare images CDN.
I am uploading the images to Cloudflare as @GuySartorelli suggested.
after uploading to cloudflare i have image on local server and also on cloudflare and i have to Cloudflare urls.
I am populating images on frontend with cloudflare images urls.
so the frontend part if working perfectly.

for the backend i cant find any solution loading from CDN urls.

As you suggest i need to write my own module by following the S3 module - m i right?
is the S3 module is providing such functionality?

@Tim
as i checked the S3 module code, I dont find any such code in there.

Yes, it’s possible, but it depends on the server you want to use / what you want it to do.

There’s an off-the-shelf module for uploading to Amazon S3 for example (GitHub - silverstripe/silverstripe-s3: SilverStripe module to store assets in S3 rather than on the local filesystem (SS4 only))

The assets backend uses Flysystem, so you could create a module using the above as a template and implement any of the Flysystem connectors.

Alternatively, you could just implement some file system sync on your server. As I say, it depends a lot on what you’re trying to achieve.

@Tim Thanks for the reply.

Basically here i want to connect the cloudflare images cdn with my silverstripe application.
whenever I upload an image in admin CMS, that image should also go to cloudflare images dashboard.
I already setuped the cloudflare API’s in postman but unable to find any solution in silverstripe file management or while uploading images/files.
Any thoughts on it?

Best place to start is with the developer docs that Guy linked: https://docs.silverstripe.org/en/4/developer_guides/extending/extensions/

You create a class which extends Extension and add the methods to that. Then you apply that extension to the File class using a yml config.

Probably the easiest way to do that, if you’re still primarily managing files on your filesystem and just want to update cloudflare’s image cache, is to add your API hooks in an Extension applied to the File class, and use onAfterWrite() (or onAfterPublish() ) and onAfterDelete() (or onAfterUnpublish() ) methods in the extension.

@GuySartorelli Yes i am thinking the same,

Thanks for opening the doors for me.

I’ve to write onAfterPublish function to do this.
Please guide me how can i write the extension for file class inside my app folder?

okay Thanks.
I am using the “AssetControlExtension” they way you explained.

further i am geting image ID in onAfterPublish() function.
i get the file obj this way
Image::get()->byID($id)

and calling the cloudflare API by passing this OBJ and getting error from cloudflare.

ERROR 5455: Uploaded image must have image/jpeg, image/png, image/webp, image/gif or image/svg+xml content-type

my postman is working fine this way. how can i send image object from silverstripe?

Can you provide a bit of code where you’re creating the API call? That object is just an image record from the asset system… so if you’re just sending that, then I’d expect it not to work, since Cloudflare is expecting a file.

Are you sending the file via an upload URL or the custom ID method in Cloudflare?

@Tim
@GuySartorelli

@Tim

        $File = Image::get()->byID($ID)
        $endpointUrl = "https://api.cloudflare.com/client/v4/accounts/<account id>/images/v1";

        $curl = curl_init($endpointUrl);
        curl_setopt($curl, CURLOPT_URL, $endpointUrl);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

        $headers = array(
            "Authorization: Bearer <token>"
        );

        $data_string['file'] = $File;
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_HEADER, true);
        $response = curl_exec($curl);
        curl_close($curl);

First off, if you’re in an Extension class attached to either File or Image you already have the file object as $this->owner

- $File = Image::get()->byID($ID);
+ $file = $this->owner;

Secondly to get the actual content of the file to send, you can get it either as a stream or as a string:

$stream = $file->getStream();
$string = $file->getString();

Obviously sending it as a stream will be better for memory management and probably be a little faster, but may be a little harder to work with.

Thanks for all the suggestions.

By following the instructions i’ve written in onAfterPublish function and sending the image to Cloudflare and in response i am saving the image url in database.
The issue i am facing the the cloudflare image url i am updating for file in onAfterPublish function in not publishing the File and i am unable to get the CloudflareUrl from db.

however i find this function to manually publish the file after updating url

$file = $this->owner;
$file->CloudFlareUrl = $CFImageURL;
$file->write();
$file->publishRecursive();

the issue is now “publishRecursive()” is slow down the request - takes even more than 1 minute to publish.

If you want to update it after write then you can use onAfterWrite() instead of onAfterPublish().

Sometime user just want to upload the image but wont publish.
We cant deploy every image to cloudflare but just the published ones.

I’ll go back to what I said right at the start :wink: You might better off creating a proper Flysystem backend for this (you can base it on the S3 module I linked). That will then integrate into all of the CMS, site, etc.