View source
<?php
namespace Drupal\imce;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
class ImceFM {
use StringTranslationTrait;
public $conf;
public $user;
public $request;
public $validated;
public $selection = [];
public $tree = [];
public $activeFolder;
public $response = [];
public $messages = [];
private $thumbnailStyle;
public function __construct(array $conf, AccountProxyInterface $user = NULL, Request $request = NULL) {
$this->conf = $conf;
$this->user = $user ?: \Drupal::currentUser();
$this->request = $request;
$this
->init();
}
protected function init() {
if (!isset($this->validated)) {
$root = $this
->createItem('folder', '.');
$root
->setPath('.');
if ($error = $this
->getInitError()) {
$this
->setMessage($error);
}
else {
$this
->initSelection();
}
$this->validated = $error === FALSE;
}
}
protected function getInitError() {
$conf =& $this->conf;
$keys = [
'folders',
'root_uri',
];
foreach ($keys as $key) {
if (empty($conf[$key])) {
return $this
->t('Missing configuration %key.', [
'%key' => $key,
]);
}
}
$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.');
}
}
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.');
}
$path = $this
->getPost('active_path');
if (isset($path) && $path !== '') {
if ($folder = $this
->checkFolder($path)) {
$this->activeFolder = $folder;
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;
}
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);
}
}
}
}
public function run($op = NULL) {
if (!$this->validated) {
return FALSE;
}
if (!isset($op)) {
$op = $this
->getOp();
}
if (!$op || !is_string($op)) {
return FALSE;
}
$token = $this
->getPost('token');
if (!$token || $token !== $this
->getConf('token')) {
$this
->setMessage($this
->t('Invalid security token.'));
return FALSE;
}
$return = \Drupal::service('plugin.manager.imce.plugin')
->handleOperation($op, $this);
if ($return === FALSE) {
$this
->setMessage($this
->t('Invalid operation %op.', [
'%op' => $op,
]));
}
return $return;
}
public function addFolder($path, array $conf = NULL) {
if ($folder = $this
->getFolder($path)) {
if (isset($conf)) {
$folder
->setConf($conf);
}
return $folder;
}
if ($parts = Imce::splitPath($path)) {
list($parent_path, $name) = $parts;
if ($parent = $this
->addFolder($parent_path)) {
return $parent
->addSubfolder($name, $conf);
}
}
}
public function getFolder($path) {
return isset($this->tree[$path]) ? $this->tree[$path] : NULL;
}
public function checkFolder($path) {
if (is_array(Imce::folderInConf($path, $this->conf))) {
return $this
->addFolder($path);
}
}
public function checkFile($path) {
$item = $this
->checkItem($path);
if ($item && $item->type === 'file') {
return $item;
}
}
public function checkItem($path) {
if ($parts = Imce::splitPath($path)) {
if ($folder = $this
->checkFolder($parts[0])) {
return $folder
->checkItem($parts[1]);
}
}
}
public function createItem($type, $name, $conf = NULL) {
$item = $type === 'folder' ? new ImceFolder($name, $conf) : new ImceFile($name);
$item
->setFm($this);
return $item;
}
public function createUri($path) {
return Imce::joinPaths($this
->getConf('root_uri'), $path);
}
public function getOp() {
return $this
->getPost('jsop');
}
public function getPost($key, $default = NULL) {
return $this->request ? $this->request->request
->get($key, $default) : $default;
}
public function getConf($key, $default = NULL) {
return isset($this->conf[$key]) ? $this->conf[$key] : $default;
}
public function setConf($key, $value) {
$this->conf[$key] = $value;
}
public function hasPermission($permission) {
return Imce::permissionInConf($permission, $this->conf);
}
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);
}
public function getNameFilter() {
return Imce::nameFilterInConf($this->conf);
}
public function getSelection() {
return $this->selection;
}
public function groupSelection() {
return $this
->groupItems($this->selection);
}
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;
}
public function selectItem(ImceItem $item) {
if (!$item->selected && $item->parent) {
$item->selected = TRUE;
$this->selection[] = $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);
}
}
}
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;
}
}
}
}
public function removeItemFromJs(ImceItem $item) {
$this
->removePathFromJs($item
->getPath());
}
public function removePathFromJs($path) {
if (isset($path)) {
$this->response['removed'][] = $path;
}
}
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;
}
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;
}
public function getFolderProperties($uri) {
return [
'date' => filemtime($uri),
];
}
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;
}
public function addResponse($key, $value) {
return $this->response[$key] = $value;
}
public function getMessages() {
$messenger = \Drupal::messenger();
$messages = $messenger
->all();
$messenger
->deleteAll();
foreach ($messages as &$group) {
foreach ($group as &$message) {
$message = $message instanceof MarkupInterface ? $message . '' : Html::escape($message);
}
}
return array_merge_recursive($messages, $this->messages);
}
public function setMessage($message, $type = 'error') {
$this->messages[$type][] = $message;
}
public function validatePermissions(array $items, $file_perm = NULL, $subfolder_perm = NULL) {
foreach ($this
->groupItems($items) as $path => $content) {
$parent = $this
->getFolder($path);
if (!empty($content['files'])) {
if (!isset($file_perm) || !$parent
->getPermission($file_perm)) {
return FALSE;
}
}
if (!empty($content['subfolders'])) {
if (!isset($subfolder_perm) || !$parent
->getPermission($subfolder_perm)) {
return FALSE;
}
}
}
return TRUE;
}
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;
}
public function validateFileName($filename, $silent = FALSE) {
if ($filename === '.' || $filename === '..' || !($len = strlen($filename)) || $len > 240) {
return FALSE;
}
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;
}
}
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;
}
public function validateDimensions(array $items, $width, $height, $silent = FALSE) {
if ($width < 1 || $height < 1) {
return FALSE;
}
$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;
}
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;
}
public function buildPage() {
$page = [];
$page['#attached']['library'][] = 'imce/drupal.imce';
$robots = [
'#tag' => 'meta',
'#attributes' => [
'name' => 'robots',
'content' => 'noindex,nofollow',
],
];
$page['#attached']['html_head'][] = [
$robots,
'robots',
];
$page['#cache']['max-age'] = 0;
\Drupal::service('plugin.manager.imce.plugin')
->buildPage($page, $this);
$conf = $this->conf;
if (!isset($conf['active_path'])) {
if ($folder = $this->activeFolder) {
$conf['active_path'] = $folder
->getPath();
}
elseif ($this->request) {
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;
}
}
}
}
if ($messages = $this
->getMessages()) {
$conf['messages'] = $messages;
}
$page['#attached']['drupalSettings']['imce'] = $conf;
return $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();
}
public function pageResponse() {
if ($request = $this->request) {
if ($request->request
->has('jsop')) {
$this
->run();
$data = $this
->getResponse();
if ($request->request
->get('return_html')) {
return new Response('<html><body><textarea>' . Json::encode($data) . '</textarea></body></html>');
}
return new JsonResponse($data);
}
return new Response($this
->buildRenderPage());
}
}
}