CoolCMS API

EditorUploadTrait

File manager for TinyMCE (admin `rich-editor.js`, full editor) over its own folder `uploads/editorUploads/`: listing, subfolders, upload, rename, delete.

Deliberately separate from assets: images inserted into page or article text have no database record and no variants; it is a plain folder that receives whatever the editor picks. Management of the whole uploads/ (including other modules) stays in the admin under System, Files (FileSystemPresenter), which uses the same Api layer.

The editor root is EDITOR_UPLOAD_FOLDER. The client works with paths relative to it and the prefix is added only here (editorPath()), so the editor cannot reach outside its own folder even with a hand-made request.

All reads and writes go through FileSystemManager (Api layer); admin never touches the file system directly and gets path traversal protection and name sanitization for free.

Signals (handle*) are chosen on purpose: Nette 3.2+ gives them #[Requires(sameOrigin: true)] automatically, so the endpoints have CSRF protection without an own token. They live on the admin BasePresenter side because the editor can be on any admin page and the link {link editorUpload!} must point to the presenter currently running (a signal of another presenter cannot be linked).

Table of Contents

Constants

BLOCKED_EXTENSIONS  : mixed = ['php', 'php3', 'php4', 'php5', 'php7', 'php8',...
Extensions that must not be uploaded into the web-served folder; otherwise an editor upload would mean running foreign code on the server. It is no content whitelist (the editor uploads what is needed), only a safeguard against executable files.
EDITOR_UPLOAD_FOLDER  : mixed = 'editorUploads'
Editor root (relative to the `uploads/` root). Changing it to `''` would open the whole `uploads/` tree to the manager; the editor user could then reach (and delete) files of other modules such as products and avatars.
IMAGE_EXTENSIONS  : mixed = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', '...
Extensions the file manager shows as a preview instead of a document icon.

Properties

$editorUploadManager  : FileSystemManager
NOTE: own property name, not `$fileSystemManager`.

Methods

handleEditorCreateFolder()  : void
Creates a subfolder in `folder` (path relative to the editor root).
handleEditorDelete()  : void
Deletes a file or (recursively) a folder. An empty path would point to the editor root, which cannot be deleted.
handleEditorFiles()  : void
Sends the folder listing for the editor file manager. The `folder` parameter is a path relative to the editor root (empty means the root).
handleEditorRename()  : void
Renames a file or folder (`path` relative to the editor root).
handleEditorUpload()  : void
Accepts a file from the editor (field `file`, multipart POST; optional `folder` = subfolder of the editor root) and sends JSON `{"location": "/www/uploads/editorUploads/..."}`, the format TinyMCE expects from `images_upload_handler`.
editorBreadcrumb()  : array<int, array{label: string, path: string}>
Builds the breadcrumb navigation: cumulative segment paths.
editorParentFolder()  : string|null
Returns the parent folder (null in the editor root).
editorPath()  : string|null
Converts a client path (relative to the editor root) to an Api path (relative to the `uploads/` root).
editorUploadName()  : string|null
Builds a safe and unique file name. Sanitization copies the Api layer rules (webalize of the base and of the extension), so the name returned in the URL is exactly the name the file is stored under. The random suffix prevents collisions: `writeFile()` overwrites the same name without asking, so two different `obrazek.jpg` files would overwrite each other.
editorUploadUrl()  : string
Returns the public URL of a file. `$path` is relative to the `uploads/` root (so it includes `editorUploads/`), the same shape as other uploads in the system.
ensureEditorRoot()  : void
Creates the editor root folder; when it already exists the Api returns false and nothing happens.
storeEditorUpload()  : bool
Stores a file; the target folder may not exist (first upload into the root), so after a failure the root is created once and the write is retried. Deeper subfolders are created by the editor user through `editorCreateFolder`.

Constants

BLOCKED_EXTENSIONS

Extensions that must not be uploaded into the web-served folder; otherwise an editor upload would mean running foreign code on the server. It is no content whitelist (the editor uploads what is needed), only a safeguard against executable files.

private mixed BLOCKED_EXTENSIONS = ['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phps', 'phtml', 'phar', 'cgi', 'pl', 'py', 'sh', 'bash', 'htaccess', 'htpasswd']

EDITOR_UPLOAD_FOLDER

Editor root (relative to the `uploads/` root). Changing it to `''` would open the whole `uploads/` tree to the manager; the editor user could then reach (and delete) files of other modules such as products and avatars.

private mixed EDITOR_UPLOAD_FOLDER = 'editorUploads'

IMAGE_EXTENSIONS

Extensions the file manager shows as a preview instead of a document icon.

private mixed IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'bmp']

Properties

$editorUploadManager

NOTE: own property name, not `$fileSystemManager`.

public FileSystemManager $editorUploadManager

FileSystemPresenter takes the same manager as private readonly in its constructor, and PHP cannot redeclare a property of the same name between public and private.

Attributes
#[Inject]

Methods

handleEditorCreateFolder()

Creates a subfolder in `folder` (path relative to the editor root).

public handleEditorCreateFolder([string $folder = '' ][, string $name = '' ]) : void
Parameters
$folder : string = ''
$name : string = ''
Attributes
#[Requires]
$methods: 'POST'

handleEditorDelete()

Deletes a file or (recursively) a folder. An empty path would point to the editor root, which cannot be deleted.

public handleEditorDelete([string $path = '' ]) : void
Parameters
$path : string = ''
Attributes
#[Requires]
$methods: 'POST'

handleEditorFiles()

Sends the folder listing for the editor file manager. The `folder` parameter is a path relative to the editor root (empty means the root).

public handleEditorFiles([string $folder = '' ]) : void

Sends JSON {folder, parent, breadcrumb[], folders[], files[]}; paths in the response are again relative to the editor root, and a public URL is given for files only. The server path never leaves the server.

A non-existent folder gives an empty listing, not an error (until something is uploaded the root does not exist physically and the manager just shows the empty state).

Parameters
$folder : string = ''

handleEditorRename()

Renames a file or folder (`path` relative to the editor root).

public handleEditorRename([string $path = '' ][, string $name = '' ]) : void
Parameters
$path : string = ''
$name : string = ''
Attributes
#[Requires]
$methods: 'POST'

handleEditorUpload()

Accepts a file from the editor (field `file`, multipart POST; optional `folder` = subfolder of the editor root) and sends JSON `{"location": "/www/uploads/editorUploads/..."}`, the format TinyMCE expects from `images_upload_handler`.

public handleEditorUpload() : void
Attributes
#[Requires]
$methods: 'POST'

editorBreadcrumb()

Builds the breadcrumb navigation: cumulative segment paths.

private editorBreadcrumb(string $relative) : array<int, array{label: string, path: string}>
Parameters
$relative : string
Return values
array<int, array{label: string, path: string}>

editorParentFolder()

Returns the parent folder (null in the editor root).

private editorParentFolder(string $relative) : string|null
Parameters
$relative : string
Return values
string|null

editorPath()

Converts a client path (relative to the editor root) to an Api path (relative to the `uploads/` root).

private editorPath(string $relative) : string|null

This is the only place where the prefix is added, so the segment check lives here too. The Api rejects .. as well, but without this check a ../ from the request would not escape uploads/ yet would escape editorUploads/ into neighboring folders of other modules.

Parameters
$relative : string
Return values
string|null —

null when the path contains a forbidden segment

editorUploadName()

Builds a safe and unique file name. Sanitization copies the Api layer rules (webalize of the base and of the extension), so the name returned in the URL is exactly the name the file is stored under. The random suffix prevents collisions: `writeFile()` overwrites the same name without asking, so two different `obrazek.jpg` files would overwrite each other.

private editorUploadName(string $untrustedName) : string|null
Parameters
$untrustedName : string
Return values
string|null —

null for a forbidden extension or an unusable name

editorUploadUrl()

Returns the public URL of a file. `$path` is relative to the `uploads/` root (so it includes `editorUploads/`), the same shape as other uploads in the system.

private editorUploadUrl(string $path) : string
Parameters
$path : string
Return values
string

ensureEditorRoot()

Creates the editor root folder; when it already exists the Api returns false and nothing happens.

private ensureEditorRoot() : void

storeEditorUpload()

Stores a file; the target folder may not exist (first upload into the root), so after a failure the root is created once and the write is retried. Deeper subfolders are created by the editor user through `editorCreateFolder`.

private storeEditorUpload(string $folder, string $name, string $base64) : bool
Parameters
$folder : string
$name : string
$base64 : string
Return values
bool
On this page

Search results