You’re absolutely right, that was a huge oversight on my part.
Here’s the gist of what I ended up using, in case it’ll help anyone else down the line.
The separate PHP file for communicating with the Cloudflare API:
<?php
///Session check to ensure the request is coming from an authenticated user
///You probably don't want to copy/paste this part
session_start();
if (isset($_SESSION['logged_in']) == false || $_SESSION['logged_in'] != true) {
echo '{"success": false, "errors": [{"code": "internal", "message": "CP AUTH FAILED - Reload the page and try again."}]}';
exit(403);
}
$accountID = "<ID HIDDEN>";
$authToken = "<TOKEN HIDDEN>";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/accounts/$accountID/images/v2/direct_upload");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$post = array(
'requireSignedURLs' => 'true',
'metadata' => '{"copyright":"NameHere"}'
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$headers = array();
$headers[] = "Authorization: Bearer $authToken";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
if (curl_errno($ch)) {
echo '{"success": false, "errors": [{"code": "internal", "message": '.curl_errno($ch).'}]}';
}
else if ($result) {
echo $result;
}
else {
echo '{"success": false, "errors": [{"code": "internal", "message": "NO RESPONSE - Cloudflare failed to respond."}]}';
}
?>
The Javascript function for obtaining an upload URL asynchronously, using promises.
function getUploadURL() {
///The path to the PHP script that communicates with Cloudflare's API
var url = "fetchUrl.php";
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
if (JSON.parse(xhr.response).success === true) {
resolve(xhr.response);
}
else {
reject({
status: this.status,
statusText: xhr.statusText,
error: JSON.parse(xhr.response).errors[0]
});
}
} else {
reject({
status: this.status,
statusText: xhr.statusText;
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
A quick example of how to use the function.
async function uploadFileExample() {
let curlObj = "";
try {
curlObj = await getUploadURL(); //Waits for the getUploadURL function to return
}
catch (e) { //Abort if error is thrown
console.log(e);
return;
}
curlObj = JSON.parse(curlObj); //Convert the JSON string into a JS object
let url = curlObj.result.uploadURL; //Extract the returned upload URL
///The rest of your upload code goes under here
}