class ImceFM in IMCE 8
Same name and namespace in other branches
- 8.2 src/ImceFM.php \Drupal\imce\ImceFM
Imce File Manager.
Hierarchy
- class \Drupal\imce\ImceFM uses StringTranslationTrait
Expanded class hierarchy of ImceFM
6 files declare their use of ImceFM
- Core.php in src/
Plugin/ ImcePlugin/ Core.php - Delete.php in src/
Plugin/ ImcePlugin/ Delete.php - ImceFolderTest.php in tests/
src/ Kernel/ ImceFolderTest.php - Newfolder.php in src/
Plugin/ ImcePlugin/ Newfolder.php - Resize.php in src/
Plugin/ ImcePlugin/ Resize.php
File
- src/
ImceFM.php, line 17
Namespace
Drupal\imceView source
class ImceFM {
use StringTranslationTrait;
/**
* File manager configuration.
*
* @var array
*/
public $conf;
/**
* Active user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
public $user;
/**
* Active request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
public $request;
/**
* Current validation status for the configuration.
*
* @var bool
*/
public $validated;
/**
* Currently selected items.
*
* @var array
*/
public $selection = [];
/**
* Folder tree.
*
* @var array
*/
public $tree = [];
/**
* Active folder.
*
* @var \Drupal\imce\ImceFolder
*/
public $activeFolder;
/**
* Response data.
*
* @var array
*/
public $response = [];
/**
* Status messages.
*
* @var array
*/
public $messages = [];
/**
* Image style for thumbnails.
*
* @var \Drupal\image\Entity\ImageStyle
*/
private $thumbnailStyle;
/**
* Constructs the file manager.
*
* @param array $conf
* File manager configuration.
* @param \Drupal\Core\Session\AccountProxyInterface $user
* The active user.
* @param \Symfony\Component\HttpFoundation\Request $request
* The active request that contains parameters for file manager operations.
*/
public function __construct(array $conf, AccountProxyInterface $user = NULL, Request $request = NULL) {
$this->conf = $conf;
$this->user = $user ?: \Drupal::currentUser();
$this->request = $request;
$this
->init();
}
/**
* Initializes the file manager.
*
* Initializes the file manager by validating
* the current configuration and request.
*/
protected function init() {
if (!isset($this->validated)) {
// Create the root.
$root = $this
->createItem('folder', '.');
$root
->setPath('.');
// Check initialization error.
if ($error = $this
->getInitError()) {
$this
->setMessage($error);
}
else {
$this
->initSelection();
}
$this->validated = $error === FALSE;
}
}
/**
* Performs the initialization and returns the first error message.
*/
protected function getInitError() {
$conf =& $this->conf;
// Check configuration options.
$keys = [
'folders',
'root_uri',
];
foreach ($keys as $key) {
if (empty($conf[$key])) {
return $this
->t('Missing configuration %key.', [
'%key' => $key,
]);
}
}
// Check root.
$root_uri = $conf['root_uri'];
if (!is_dir($root_uri)) {
if (!mkdir($root_uri, $this
->getConf('chmod_directory', 0775), TRUE)) {
return $this
->t('Missing root folder.');
}
}
// Check and add predefined folders.
foreach ($conf['folders'] as $path => $folder_conf) {
$path = (string) $path;
$uri = $this
->createUri($path);
if (is_dir($uri) || mkdir($uri, $this
->getConf('chmod_directory', 0775), TRUE)) {
$this
->addFolder($path, $folder_conf);
}
else {
unset($conf['folders'][$path]);
}
}
if (!$conf['folders']) {
return $this
->t('No valid folder definitions found.');
}
// Check and set active folder if provided.
$path = $this
->getPost('active_path');
if (isset($path) && $path !== '') {
if ($folder = $this
->checkFolder($path)) {
$this->activeFolder = $folder;
// Remember active path.
if ($this->user
->isAuthenticated()) {
if (!isset($conf['folders'][$path]) || count($conf['folders']) > 1 || $folder
->getPermission('browse_subfolders')) {
$this->request
->getSession()
->set('imce_active_path', $path);
}
}
}
else {
return $this
->t('Invalid active folder path: %path.', [
'%path' => $path,
]);
}
}
return FALSE;
}
/**
* Initiates the selection with a list of user provided item paths.
*/
protected function initSelection() {
$paths = $this
->getPost('selection');
if ($paths && is_array($paths)) {
foreach ($paths as $path) {
if ($item = $this
->checkItem($path)) {
$item
->select();
}
else {
$this
->removePathFromJs($path);
}
}
}
}
/**
* Runs an operation on the file manager.
*/
public function run($op = NULL) {
if (!$this->validated) {
return FALSE;
}
// Check operation.
if (!isset($op)) {
$op = $this
->getOp();
}
if (!$op || !is_string($op)) {
return FALSE;
}
// Validate security token.
$token = $this
->getPost('token');
if (!$token || $token !== $this
->getConf('token')) {
$this
->setMessage($this
->t('Invalid security token.'));
return FALSE;
}
// Let plugins handle the operation.
$return = \Drupal::service('plugin.manager.imce.plugin')
->handleOperation($op, $this);
if ($return === FALSE) {
$this
->setMessage($this
->t('Invalid operation %op.', [
'%op' => $op,
]));
}
return $return;
}
/**
* Adds a folder to the tree.
*/
public function addFolder($path, array $conf = NULL) {
// Existing.
if ($folder = $this
->getFolder($path)) {
if (isset($conf)) {
$folder
->setConf($conf);
}
return $folder;
}
// New. Append to the parent.
if ($parts = Imce::splitPath($path)) {
list($parent_path, $name) = $parts;
if ($parent = $this
->addFolder($parent_path)) {
return $parent
->addSubfolder($name, $conf);
}
}
}
/**
* Get folder.
*
* @param string $path
* The patchs folder.
*
* @return mixed
* Returns a folder from the tree.
*/
public function getFolder($path) {
return isset($this->tree[$path]) ? $this->tree[$path] : NULL;
}
/**
* Checks if the user provided folder path is accessible.
*
* @param string $path
* The patchs folder.
*
* @return object
* Returns the folder object with the path.
*/
public function checkFolder($path) {
if (is_array(Imce::folderInConf($path, $this->conf))) {
return $this
->addFolder($path);
}
}
/**
* Checks if the user provided file path is accessible.
*
* Returns the file object with the path.
*/
public function checkFile($path) {
$item = $this
->checkItem($path);
if ($item && $item->type === 'file') {
return $item;
}
}
/**
* Checks the existence of a user provided item path.
*
* Scans the parent folder and returns the item object if it is accessible.
*/
public function checkItem($path) {
if ($parts = Imce::splitPath($path)) {
if ($folder = $this
->checkFolder($parts[0])) {
return $folder
->checkItem($parts[1]);
}
}
}
/**
* Creates and returns an imce file/folder object by name.
*/
public function createItem($type, $name, $conf = NULL) {
$item = $type === 'folder' ? new ImceFolder($name, $conf) : new ImceFile($name);
$item
->setFm($this);
return $item;
}
/**
* Creates an uri from a relative path.
*/
public function createUri($path) {
return Imce::joinPaths($this
->getConf('root_uri'), $path);
}
/**
* Returns the current operation in the request.
*/
public function getOp() {
return $this
->getPost('jsop');
}
/**
* Returns value of a posted parameter.
*/
public function getPost($key, $default = NULL) {
return $this->request ? $this->request->request
->get($key, $default) : $default;
}
/**
* Returns a configuration option.
*/
public function getConf($key, $default = NULL) {
return isset($this->conf[$key]) ? $this->conf[$key] : $default;
}
/**
* Sets a configuration option.
*/
public function setConf($key, $value) {
$this->conf[$key] = $value;
}
/**
* Checks if a permission exists in any of the predefined folders.
*/
public function hasPermission($permission) {
return Imce::permissionInConf($permission, $this->conf);
}
/**
* Returns the contents of a directory.
*/
public function scanDir($diruri, array $options = []) {
$options += [
'name_filter' => $this
->getNameFilter(),
];
$scanner = $this
->getConf('scanner', 'Drupal\\imce\\Imce::scanDir');
return call_user_func($scanner, $diruri, $options);
}
/**
* Returns name filtering regexp.
*/
public function getNameFilter() {
return Imce::nameFilterInConf($this->conf);
}
/**
* Returns currently selected items.
*/
public function getSelection() {
return $this->selection;
}
/**
* Returns selected items grouped by parent folder path.
*/
public function groupSelection() {
return $this
->groupItems($this->selection);
}
/**
* Groups the items by parent path and type.
*/
public function groupItems(array $items) {
$group = [];
foreach ($items as $item) {
$path = $item->parent
->getPath();
$type = $item->type == 'folder' ? 'subfolders' : 'files';
$group[$path][$type][$item->name] = $item;
}
return $group;
}
/**
* Selects an item.
*/
public function selectItem(ImceItem $item) {
if (!$item->selected && $item->parent) {
$item->selected = TRUE;
$this->selection[] = $item;
}
}
/**
* Deselects an item.
*/
public function deselectItem(ImceItem $item) {
if ($item->selected) {
$item->selected = FALSE;
$index = array_search($item, $this->selection);
if ($index !== FALSE) {
array_splice($this->selection, $index, 1);
}
}
}
/**
* Add an item to the response.
*/
public function addItemToJs(ImceItem $item) {
if ($parent = $item->parent) {
if ($path = $parent
->getPath()) {
$name = $item->name;
$uri = $item
->getUri();
if ($item->type === 'folder') {
$this->response['added'][$path]['subfolders'][$name] = $this
->getFolderProperties($uri);
}
else {
$props = $this
->getFileProperties($uri);
if (isset($item->uuid)) {
$props['uuid'] = $item->uuid;
}
$this->response['added'][$path]['files'][$name] = $props;
}
}
}
}
/**
* Sets an item as removed in the response.
*/
public function removeItemFromJs(ImceItem $item) {
$this
->removePathFromJs($item
->getPath());
}
/**
* Sets a path as removed in the response.
*/
public function removePathFromJs($path) {
if (isset($path)) {
$this->response['removed'][] = $path;
}
}
/**
* Returns js properties of a file.
*/
public function getFileProperties($uri) {
$properties = [
'date' => filemtime($uri),
'size' => filesize($uri),
];
if (preg_match('/\\.(jpe?g|png|gif)$/i', $uri) && ($info = getimagesize($uri))) {
$properties['width'] = $info[0];
$properties['height'] = $info[1];
$style = $this
->getThumbnailStyle();
if ($style && strpos($uri, '/styles/') === FALSE) {
$properties['thumbnail'] = $style
->buildUrl($uri);
}
}
return $properties;
}
/**
* Returns thumbnail style.
*/
public function getThumbnailStyle() {
if (!isset($this->thumbnailStyle)) {
$this->thumbnailStyle = FALSE;
if ($style_name = $this
->getConf('thumbnail_style')) {
$this->thumbnailStyle = \Drupal::entityTypeManager()
->getStorage('image_style')
->load($style_name);
}
}
return $this->thumbnailStyle;
}
/**
* Returns js properties of a folder.
*/
public function getFolderProperties($uri) {
return [
'date' => filemtime($uri),
];
}
/**
* Returns the response data.
*/
public function getResponse() {
$defaults = [
'jsop' => $this
->getOp(),
];
if ($messages = $this
->getMessages()) {
$defaults['messages'] = $messages;
}
if ($folder = $this->activeFolder) {
$defaults['active_path'] = $folder
->getPath();
}
return $this->response + $defaults;
}
/**
* Adds response data.
*/
public function addResponse($key, $value) {
return $this->response[$key] = $value;
}
/**
* Returns the status messages.
*/
public function getMessages() {
// Get drupal messages.
$messenger = \Drupal::messenger();
$messages = $messenger
->all();
$messenger
->deleteAll();
foreach ($messages as &$group) {
foreach ($group as &$message) {
$message = $message instanceof MarkupInterface ? $message . '' : Html::escape($message);
}
}
// Merge with file manager messages.
return array_merge_recursive($messages, $this->messages);
}
/**
* Sets a status message.
*/
public function setMessage($message, $type = 'error') {
$this->messages[$type][] = $message;
}
/**
* Checks parent folder permissions of the given items.
*/
public function validatePermissions(array $items, $file_perm = NULL, $subfolder_perm = NULL) {
foreach ($this
->groupItems($items) as $path => $content) {
$parent = $this
->getFolder($path);
// Parent contains files but does not have the file permission.
if (!empty($content['files'])) {
if (!isset($file_perm) || !$parent
->getPermission($file_perm)) {
return FALSE;
}
}
// Parent contains subfolders but does not have the subfolder permission.
if (!empty($content['subfolders'])) {
if (!isset($subfolder_perm) || !$parent
->getPermission($subfolder_perm)) {
return FALSE;
}
}
}
return TRUE;
}
/**
* Checks the existence of a predefined path.
*/
public function validatePredefinedPath(array $items, $silent = FALSE) {
foreach ($items as $item) {
if ($item->type === 'folder' && ($folder = $item
->hasPredefinedPath())) {
if (!$silent) {
$this
->setMessage($this
->t('%path is a predefined path and can not be modified.', [
'%path' => $folder
->getPath(),
]));
}
return FALSE;
}
}
return TRUE;
}
/**
* Validates a file name.
*/
public function validateFileName($filename, $silent = FALSE) {
// Basic validation.
if ($filename === '.' || $filename === '..' || !($len = strlen($filename)) || $len > 240) {
return FALSE;
}
// Test name filters.
if ($name_filter = $this
->getNameFilter()) {
if (preg_match($name_filter, $filename)) {
if (!$silent) {
$this
->setMessage($this
->t('%filename is not allowed.', [
'%filename' => $filename,
]));
}
return FALSE;
}
}
// Test chars forbidden in various operating systems.
if (preg_match('@^\\s|\\s$|[/\\\\:\\*\\?"<>\\|\\x00-\\x1F]@', $filename)) {
if (!$silent) {
$this
->setMessage($this
->t('%filename contains invalid characters. Use only alphanumeric characters for better portability.', [
'%filename' => $filename,
]));
}
return FALSE;
}
return TRUE;
}
/**
* Validates min/max image dimensions.
*/
public function validateDimensions(array $items, $width, $height, $silent = FALSE) {
// Check min dimensions.
if ($width < 1 || $height < 1) {
return FALSE;
}
// Check max dimensions.
$maxwidth = $this
->getConf('maxwidth');
$maxheight = $this
->getConf('maxheight');
if ($maxwidth && $width > $maxwidth || $maxheight && $height > $maxheight) {
if (!$silent) {
$this
->setMessage($this
->t('Image dimensions must be smaller than %dimensions pixels.', [
'%dimensions' => $maxwidth . 'x' . $maxwidth,
]));
}
return FALSE;
}
return TRUE;
}
/**
* Checks if all the selected items are images.
*/
public function validateImageTypes(array $items, $silent = FALSE) {
$regex = '/\\.(' . preg_replace('/ +/', '|', preg_quote(trim($this
->getConf('image_extensions', 'jpg jpeg png gif')))) . ')$/i';
foreach ($items as $item) {
if ($item->type === 'folder' || !preg_match($regex, $item->name)) {
if (!$silent) {
$this
->setMessage($this
->t('%name is not an image.', [
'%name' => $item->name,
]));
}
return FALSE;
}
}
return TRUE;
}
/**
* Builds file manager page.
*/
public function buildPage() {
$page = [];
$page['#attached']['library'][] = 'imce/drupal.imce';
// Add meta for robots.
$robots = [
'#tag' => 'meta',
'#attributes' => [
'name' => 'robots',
'content' => 'noindex,nofollow',
],
];
$page['#attached']['html_head'][] = [
$robots,
'robots',
];
// Disable cache.
$page['#cache']['max-age'] = 0;
// Run builders of available plugins.
\Drupal::service('plugin.manager.imce.plugin')
->buildPage($page, $this);
// Add active path to the conf.
$conf = $this->conf;
if (!isset($conf['active_path'])) {
if ($folder = $this->activeFolder) {
$conf['active_path'] = $folder
->getPath();
}
elseif ($this->request) {
// Check $_GET['init_path'].
if (($path = $this->request->query
->get('init_path')) && $this
->checkFolder($path)) {
$conf['active_path'] = $path;
}
elseif ($this->user
->isAuthenticated() && ($path = $this->request
->getSession()
->get('imce_active_path'))) {
if ($this
->checkFolder($path)) {
$conf['active_path'] = $path;
}
}
}
}
// Set initial messages.
if ($messages = $this
->getMessages()) {
$conf['messages'] = $messages;
}
$page['#attached']['drupalSettings']['imce'] = $conf;
return $page;
}
/**
* Builds and renders the file manager page.
*/
public function buildRenderPage() {
$page = $this
->buildPage();
return \Drupal::service('bare_html_page_renderer')
->renderBarePage($page, $this
->t('File manager'), 'imce_page', [
'#show_messages' => FALSE,
])
->getContent();
}
/**
* Returns a page response based on the current request.
*/
public function pageResponse() {
if ($request = $this->request) {
// Json request.
if ($request->request
->has('jsop')) {
$this
->run();
$data = $this
->getResponse();
// Return html response if the flag is set.
if ($request->request
->get('return_html')) {
return new Response('<html><body><textarea>' . Json::encode($data) . '</textarea></body></html>');
}
return new JsonResponse($data);
}
// Build and render the main page.
return new Response($this
->buildRenderPage());
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ImceFM:: |
public | property | Active folder. | |
ImceFM:: |
public | property | File manager configuration. | |
ImceFM:: |
public | property | Status messages. | |
ImceFM:: |
public | property | Active request. | |
ImceFM:: |
public | property | Response data. | |
ImceFM:: |
public | property | Currently selected items. | |
ImceFM:: |
private | property | Image style for thumbnails. | |
ImceFM:: |
public | property | Folder tree. | |
ImceFM:: |
public | property | Active user. | |
ImceFM:: |
public | property | Current validation status for the configuration. | |
ImceFM:: |
public | function | Adds a folder to the tree. | |
ImceFM:: |
public | function | Add an item to the response. | |
ImceFM:: |
public | function | Adds response data. | |
ImceFM:: |
public | function | Builds file manager page. | |
ImceFM:: |
public | function | Builds and renders the file manager page. | |
ImceFM:: |
public | function | Checks if the user provided file path is accessible. | |
ImceFM:: |
public | function | Checks if the user provided folder path is accessible. | |
ImceFM:: |
public | function | Checks the existence of a user provided item path. | |
ImceFM:: |
public | function | Creates and returns an imce file/folder object by name. | |
ImceFM:: |
public | function | Creates an uri from a relative path. | |
ImceFM:: |
public | function | Deselects an item. | |
ImceFM:: |
public | function | Returns a configuration option. | |
ImceFM:: |
public | function | Returns js properties of a file. | |
ImceFM:: |
public | function | Get folder. | |
ImceFM:: |
public | function | Returns js properties of a folder. | |
ImceFM:: |
protected | function | Performs the initialization and returns the first error message. | |
ImceFM:: |
public | function | Returns the status messages. | |
ImceFM:: |
public | function | Returns name filtering regexp. | |
ImceFM:: |
public | function | Returns the current operation in the request. | |
ImceFM:: |
public | function | Returns value of a posted parameter. | |
ImceFM:: |
public | function | Returns the response data. | |
ImceFM:: |
public | function | Returns currently selected items. | |
ImceFM:: |
public | function | Returns thumbnail style. | |
ImceFM:: |
public | function | Groups the items by parent path and type. | |
ImceFM:: |
public | function | Returns selected items grouped by parent folder path. | |
ImceFM:: |
public | function | Checks if a permission exists in any of the predefined folders. | |
ImceFM:: |
protected | function | Initializes the file manager. | |
ImceFM:: |
protected | function | Initiates the selection with a list of user provided item paths. | |
ImceFM:: |
public | function | Returns a page response based on the current request. | |
ImceFM:: |
public | function | Sets an item as removed in the response. | |
ImceFM:: |
public | function | Sets a path as removed in the response. | |
ImceFM:: |
public | function | Runs an operation on the file manager. | |
ImceFM:: |
public | function | Returns the contents of a directory. | |
ImceFM:: |
public | function | Selects an item. | |
ImceFM:: |
public | function | Sets a configuration option. | |
ImceFM:: |
public | function | Sets a status message. | |
ImceFM:: |
public | function | Validates min/max image dimensions. | |
ImceFM:: |
public | function | Validates a file name. | |
ImceFM:: |
public | function | Checks if all the selected items are images. | |
ImceFM:: |
public | function | Checks parent folder permissions of the given items. | |
ImceFM:: |
public | function | Checks the existence of a predefined path. | |
ImceFM:: |
public | function | Constructs the file manager. | |
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. |