I am trying to set up a simple REST-like API with Silverstripe to manage files. In that perspective I would like to implement the main HTTP verbs : GET (get the file), POST (create a file), PUT (update a file) and DELETE (delete the file).
I managed to implement GET, POST and DELETE, but I am still struggling with PUT. It's very easy indeed to upload a file through POST, as PHP automatically sends the uploaded file in the $_FILES global variable, which can then be fed into the Upload::loadIntoFile() method.
However PHP doesn't seem to be so helpful with PUT requests, so I had to implement it by myself. I got the content of the file from the body of the HTTP request and tried to feed it to Upload::loadIntoFile() by emulating the format of the data in $_FILES :
class API_Controller extends Page_Controller {
private static $url_handlers = array(
'$upload!' => 'upload_file',
);
private static $allowed_actions = array(
'upload_file',
);
public function upload_file(SS_HTTPRequest $request) {
// Get the existing Silverstripe File object
$myExistingFile = $this->getMyExistingFile();
if ($request->isPUT()) {
// Extract the file content from the HTTP request body
$fileContent = $this->getFileContent($request->getBody());
$upload = Upload::create();
$tempfd = tmpfile();
fwrite($tempfd, $fileContent);
$tmpFilename = stream_get_meta_data($tempfd)['uri'];
// Emulate the data format expected by Upload::loadIntoFile()
$tmpFile = array(
'name' => 'myfile.txt',
'type' => 'text/plain',
'tmp_name' => $tmpFilename,
'error' => 0,
'size' => filesize($tmpFilename)
);
$upload->loadIntoFile($tmpFile, $myExistingFile);
if ($upload->isError()) {
return new SS_HTTPResponse('FILE UPLOAD FAILED', 500);
}
}
}
}
Unfortunately, loadIntoFile() always returns an error "File is not a valid upload". After having a look at the code and searching the internet, I found that this is because there is a validation performed during the upload with the PHP function is_uploaded_file(), and this function can tell that the file I am trying to upload doesn't come from a POST request.
Has anyone ever tried to implement PUT requests with Silverstripe ? Is there a recommended way to handle PUT requests ? Otherwise, how can I workaround the is_uploaded_file() validation ?
Here are some relevant parts of my PHP configuration (the file I am trying to upload is < 1KB) :
file_uploads = On
upload_max_filesize = 512M
max_file_uploads = 20