Instead of accepting serialized files, I wanted to process file uploads as multipart/form-data.
I also wanted to use the crsf prevention API.
This is what I came up with. Replace modulename
with your module and fileupload
with whatever you want to name your class/endpoint.
In your routing.yml:
modulename.fileupload:
path: 'fileupload'
defaults: { _controller: '\Drupal\modulename\Controller\FileUploadController::create' }
methods: [POST]
requirements:
_custom_access: '\Drupal\modulename\Controller\FileUploadController::access'
In your services.yml:
services:
modulename.route_subscriber:
class: Drupal\modulename\Routing\RouteSubscriber
tags:
- { name: event_subscriber }
In src/Routing/RouteSubscriber.php:
<?php
namespace Drupal\modulename\Routing;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
/**
* Alter modules's route(s).
*/
class RouteSubscriber extends RouteSubscriberBase {
/**
* {@inheritdoc}
*
* Add a CSRF-Token requirement to the fileupload route.
*/
public function alterRoutes(RouteCollection $collection) {
if ($route = $collection->get('modulename.fileupload')) {
$route->setRequirement('_access_rest_csrf', 'TRUE');
}
}
}
In src/Controller/FileUploadController.php
<?php
namespace Drupal\modulename\Controller;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\Core\Access\AccessResult;
/**
* Process file uploads.
*/
class FileUploadController {
/**
* Allow access for logged-in, authenitcated users.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
*/
public function access(AccountInterface $account) {
return AccessResult::allowedIf($account->isAuthenticated());
}
/**
* Process posted files.
*/
public function create(Request $request) {
if (strpos($request->headers->get('Content-Type'), 'multipart/form-data;') !== 0) {
$res = new JsonResponse();
$res->setStatusCode(400, 'must submit multipart/form-data');
return $res;
}
$data = file_get_contents($_FILES['image']['tmp_name']);
$mime = $_FILES['image']['type'];
$file = file_save_data($data, NULL, FILE_EXISTS_REPLACE);
$response['file_id'] = $file->id();
return new JsonResponse($response);
}
}
I adopted this code for use on a site. Here is some sample code of a jQuery request.