class AjaxController in S3 File System CORS Upload 8
Default controller for the s3fs_cors module.
Hierarchy
- class \Drupal\Core\Controller\ControllerBase implements ContainerInjectionInterface uses LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\s3fs_cors\Controller\AjaxController
Expanded class hierarchy of AjaxController
File
- src/
Controller/ AjaxController.php, line 19
Namespace
Drupal\s3fs_cors\ControllerView source
class AjaxController extends ControllerBase {
/**
* S3 Client Interface.
*
* @var \Aws\S3\S3ClientInterface
*/
protected $s3Client;
/**
* Database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Mime Type Guesser Interface.
*
* @var \Drupal\Core\File\MimeType\MimeTypeGuesser
*/
protected $mimeType;
/**
* Logger Channel Interface.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* AjaxController constructor.
*
* @param \Drupal\s3fs\S3fsServiceInterface $s3fs
* The S3fs service interface.
* @param \Drupal\Core\Database\Connection $database
* The Drupal database connection service.
* @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mimeType
* The mime type guesser service.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
* The core logger factory service.
*
* @throws \Drupal\s3fs\S3fsException
* The S3fs exception.
*/
public function __construct(S3fsServiceInterface $s3fs, Connection $database, MimeTypeGuesserInterface $mimeType, LoggerChannelFactoryInterface $loggerFactory) {
$s3_config = $this
->config('s3fs.settings')
->get();
$this->s3Client = $s3fs
->getAmazonS3Client($s3_config);
$this->database = $database;
$this->mimeType = $mimeType;
$this->logger = $loggerFactory
->get('s3fs');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('s3fs'), $container
->get('database'), $container
->get('file.mime_type.guesser'), $container
->get('logger.factory'));
}
/**
* Return the file key (i.e. the path and name).
*
* The values $file_size and $file_index are just values to be passed through
* and returned to the javaScript function.
*/
public function getKey($directory, $file_name, $file_size, $file_index, $replace = FileSystemInterface::EXISTS_RENAME) {
// Strip control characters (ASCII value < 32). Though these are allowed in
// some filesystems, not many applications handle them well.
$file_name = preg_replace('/[\\x00-\\x1F]/u', '_', $file_name);
// Also replace forbidden chars if this is a Windows envrionment.
if (substr(PHP_OS, 0, 3) == 'WIN') {
// These characters are not allowed in Windows filenames.
$file_name = str_replace([
':',
'*',
'?',
'"',
'<',
'>',
'|',
], '_', $file_name);
}
// Decode the "/" chars in the directory and build an initial file key.
// Note: this will include the s3fs root folder, if specified.
$directory = str_replace('::', '/', $directory);
$file_key = $directory . '/' . $file_name;
// Check if a file with this key already exists on S3.
$file_exists = $this
->s3FileExists($file_key);
if ($file_exists) {
switch ($replace) {
case FileSystemInterface::EXISTS_REPLACE:
// Do nothing here, we want to overwrite the existing file.
break;
case FileSystemInterface::EXISTS_RENAME:
$file_key = $this
->createFileKey($directory, $file_name);
break;
case FileSystemInterface::EXISTS_ERROR:
// Error reporting handled by calling function.
return FALSE;
}
}
// Core file_destination is not able to check remoe file existience.
return new JsonResponse([
'file_key' => $file_key,
'file_name' => $file_name,
'file_size' => $file_size,
'file_index' => $file_index,
]);
}
/**
* Create a new file key if the original one already exists.
*/
private function createFileKey($directory, $file_name) {
// Remove the root folder from the file directory if specified.
$root_folder = '';
$config = $this
->config('s3fs.settings');
if (!empty($config
->get('root_folder'))) {
$root_folder = $config
->get('root_folder') . '/';
$directory = str_replace($root_folder, '', $directory);
}
$separator = '/';
// A URI or path may already have a trailing slash or look like "public://".
if (substr($directory, -1) == '/') {
$separator = '';
}
// Extract the file base name and the file extension (with leading period).
$base_name = substr($file_name, 0, strrpos($file_name, '.'));
$extension = substr($file_name, strrpos($file_name, '.'));
$key_base = $root_folder . $directory . $separator . $base_name;
// Look in the s3fs cache to find files with a key like this.
$uri_base = 's3://' . $directory . $separator . $base_name;
$records = $this->database
->select('s3fs_file', 's')
->fields('s', [
'uri',
])
->condition('uri', $this->database
->escapeLike($uri_base) . '%', 'LIKE')
->execute()
->fetchCol();
// Process the results array to extract the suffix values.
$results = [];
foreach ($records as $record) {
$suffix = str_replace([
$uri_base,
$extension,
], '', $record);
if ($suffix) {
// Drop the leading underscore char.
$suffix = (int) substr($suffix, 1);
$results[$suffix] = $record;
}
}
// Find a key suffix that can be used by looking for a gap in suffix values.
for ($suffix = 0; $suffix < count($results); $suffix++) {
if (!isset($results[$suffix])) {
break;
}
}
// If we drop out the bottom then suffix will be one greater then largest
// existing value. Create a trial key and test.
$trial_key = $key_base . '_' . $suffix . $extension;
if ($this
->s3FileExists($trial_key)) {
// Destination file already exists, then cache is stale. Rebuild required.
$this->logger
->info('S3fs cache table rebuild required (key %key missing)', [
'%key' => $trial_key,
]);
// Look for a new suffix value greater then the largest already known.
$suffix = max(array_keys($results));
do {
$trial_key = $key_base . '_' . ++$suffix . $extension;
} while ($this
->s3FileExists($trial_key));
}
return $trial_key;
}
/**
* Check whehter a passed file name exists (using the file key).
*/
private function s3FileExists($key) {
$config = $this
->config('s3fs.settings');
$bucket = $config
->get('bucket');
return $this->s3Client
->doesObjectExist($bucket, $key);
}
/**
* Save the file details to the managed file table.
*/
public function saveFile($file_path, $file_name, $file_size, $field_name) {
$user = $this
->currentUser();
// Decode the "/" chars from file path.
$file_path = str_replace('::', '/', $file_path);
// Remove the root folder from the file path if specified.
$config = $this
->config('s3fs.settings');
if (!empty($config
->get('root_folder'))) {
$root_folder = $config
->get('root_folder');
$file_path = str_replace($root_folder . '/', '', $file_path);
}
$file_uri = 's3://' . $file_path;
// Record the uploaded file in the s3fs cache. This needs to be done before
// the file is saved so the the filesize can be found from the cache.
$wrapper = new S3fsStream();
$wrapper
->writeUriToCache($file_uri);
// Convert URLs back to their proper (original) file stream names.
$public_folder = 's3://' . ($config
->get('public_folder') ?: 's3fs-public');
$private_folder = 's3://' . ($config
->get('private_folder') ?: 's3fs-private');
if (strpos($file_uri, $public_folder) === 0 || strpos($file_uri, $private_folder) === 0) {
$file_uri = str_replace([
$public_folder,
$private_folder,
], [
'public:/',
'private:/',
], $file_uri);
}
$file_mime = $this->mimeType
->guess($file_name);
$values = [
'uid' => $user
->id(),
'status' => 0,
'filename' => $file_name,
'uri' => $file_uri,
'filesize' => $file_size,
'filemime' => $file_mime,
'source' => $field_name,
];
$file = File::create($values);
$errors = [];
$errors = array_merge($errors, $this
->moduleHandler()
->invokeAll('file_validate', [
$file,
]));
if (empty($errors)) {
$file
->save();
$values['fid'] = $file
->id();
$values['uuid'] = $file
->uuid();
}
else {
$file
->delete();
$values['errmsg'] = implode("\n", $errors);
}
return new JsonResponse($values);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
AjaxController:: |
protected | property | Database connection. | |
AjaxController:: |
protected | property | Logger Channel Interface. | |
AjaxController:: |
protected | property | Mime Type Guesser Interface. | |
AjaxController:: |
protected | property | S3 Client Interface. | |
AjaxController:: |
public static | function |
Instantiates a new instance of this class. Overrides ControllerBase:: |
|
AjaxController:: |
private | function | Create a new file key if the original one already exists. | |
AjaxController:: |
public | function | Return the file key (i.e. the path and name). | |
AjaxController:: |
private | function | Check whehter a passed file name exists (using the file key). | |
AjaxController:: |
public | function | Save the file details to the managed file table. | |
AjaxController:: |
public | function | AjaxController constructor. | |
ControllerBase:: |
protected | property | The configuration factory. | |
ControllerBase:: |
protected | property | The current user service. | 1 |
ControllerBase:: |
protected | property | The entity form builder. | |
ControllerBase:: |
protected | property | The entity manager. | |
ControllerBase:: |
protected | property | The entity type manager. | |
ControllerBase:: |
protected | property | The form builder. | 2 |
ControllerBase:: |
protected | property | The key-value storage. | 1 |
ControllerBase:: |
protected | property | The language manager. | 1 |
ControllerBase:: |
protected | property | The module handler. | 2 |
ControllerBase:: |
protected | property | The state service. | |
ControllerBase:: |
protected | function | Returns the requested cache bin. | |
ControllerBase:: |
protected | function | Retrieves a configuration object. | |
ControllerBase:: |
private | function | Returns the service container. | |
ControllerBase:: |
protected | function | Returns the current user. | 1 |
ControllerBase:: |
protected | function | Retrieves the entity form builder. | |
ControllerBase:: |
protected | function | Retrieves the entity manager service. | |
ControllerBase:: |
protected | function | Retrieves the entity type manager. | |
ControllerBase:: |
protected | function | Returns the form builder service. | 2 |
ControllerBase:: |
protected | function | Returns a key/value storage collection. | 1 |
ControllerBase:: |
protected | function | Returns the language manager service. | 1 |
ControllerBase:: |
protected | function | Returns the module handler. | 2 |
ControllerBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
ControllerBase:: |
protected | function | Returns the state storage service. | |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. |