Kategorien auf ausgewählte Mime-Typen einschränken
Ausgangslage
Im Normalzustand gelten für alle Kategorien im Medienpool die gleichen Regeln bzgl. zulässiger Dateitypen (Mime-Typ).
Die Aufgabe ist einen Weg zu finden, wie man gezielt für einzelne Kategorien des Medienpools andere Regeln für nur dort zulässige Dateitypen implementieren kann.
Als Beispiel dient Kategorie mit der ID "2" für PDFs und eine mit der ID "3" für Bilder (jpg,png).
Wie arbeitet der Medienpool?
Die Liste zulässiger und geblockter Typen ist in der package.yml
des Medienpool zu finden:
blocked_extensions: [php, php3, php4, php5, php6, php7, phar, pht, phtml, hh, pl, asp, aspx, cfm, jsp, jsf, bat, sh, cgi, htaccess, htpasswd]
allowed_doctypes: [bmp, css, doc, docx, eps, gif, gz, jpg, jpeg, mov, mp3, mp4, ogg, pdf, png, ppt, pptx, pps, ppsx, rar, rtf, svg, swf, tar, tif, tiff, txt, webp, wma, xls, xlsx, zip]
Die Steuerung erfolgt also über die Extensions.
Während eines Uploads wird geprüft, dass die Extension
- nicht in der Liste "blocked_extensions" vorkommt
- in der Liste "allowed_doctypes" vorkommt.
Lösungsumfang
Im Medienpool wird nur beim Upload geprüft, ob Dateien den Regeln entsprechen. Da alle Kategorien dieselben Regeln haben, muss danach keine weitere Prüfung erfolgen.
Sobald Kategorien begrenzt sind, sieht die Sache anders aus. Jetzt muss auch geprüft werden, ob Dateien z.B. aus einer unbeschränkten Kategorie in eine beschränkte Kategorie verschoben werden.
Wo einklinken? Lösungsidee!
Eigentlich nutzt man in REDAXO die ExtensionPoints, um in den Ablauf einzugreifen. Der Upload selbst erfolgt
über mediapool/pages/upload.php
. Dort findet sich kein ExtensionPoint.
In den Programmcode einzugreifen, ist auch keine kluge Lösung, da nicht update-sicher.
Ein anderer Ansatz ist der Eingriff in die Liste der "allowed_doctypes". Dabei verbietet sich die
grundlegende Änderung der package.yml
, denn das hätte wieder Auswirkung auf alle Kategorien. Aber man
kann die Liste, nachdem sie geladen wude, kategoriebezogen austauschen.
Dazu muss das System - und zwar bevor der Upload durchgeführt wird - erkennen, dass
- ein Upload in der Medienpool erfolgt und
- das Ablageziel eine beschränkte Kategorie ist.
In dem Fall wird die Liste der "allowed_doctypes" gegen die kategoriebezogene Liste ausgetauscht.
Umsetzung: Upload
Der Code kann in einer beliebigen boot.php
stehen bzw. aus ihr heraus aufgerufen werden (z.B. Projekt-Addon).
Ob ein Upload in eine begrenzte Kategorie vorliegt, kann aus den Request-Parametern abgelesen werden:
- page=mediapool/upload
- rex_file_category=«id_begrenzte_kategorie»
Bereits diesem Punkt die Property 'allowed_doctypes' zu verändern, ist nicht zielführend. Der Medienpool wird evtl. erst danach initialisiert wird und setzt es die Änderungen zurück. Der Eingriff darf erst erfolgen, wenn der Medienpool initialisiert ist. Hierzu klinkt man sich in den ExtensionPoint 'PACKAGES_INCLUDED' ein.
Im EP kommt es letztlich auf zwei Zeilen an:
$mp = rex_package::get('mediapool');
$mp->setProperty('allowed_doctypes',$neueListe);
Alles weitere dient nur der Absicherung:
- verlagere 'allowed_doctypes', die nicht in
$neueListe
stehen, nach 'blocked_extensions' - die neue Liste darf nur ein Teilmenge der originalen 'allowed_doctypes' sein
Der eigentliche Upload mittels page/upload.php
läuft danach ganz normal ab.
Umsetzung: Verschieben
In ähnlicher Weise kann man erkennen, ob eine Datei in eine beschränkte Kategorie verschoben wird.
- page=mediapool/media
- rex_file_category=«id_begrenzte_kategorie»
- btn_update=rex_i18n::msg('pool_file_update')
- file_id=«id_des_bilddatensatzes»
Die 'rex_file_category' ist die ID der Kategorie, in der Mediendatei zukünftig liegen soll. Handlungsbedarf besteht nur, wenn die Datei aktuell in einer anderen Kategorie als 'rex_file_category' liegt. Ergibt die Prüfung, dass der Datei-Suffix nicht in der Liste der für die Zielkategorei zulässigen ist, wird die Änderung unterbunden.
Über den EP 'PAGE_TITLE_SHOWN' wird eine Fehlermeldung eingeschleust. So erfährt der Nutzer von der Beschränkung.
Leider wird immer noch von page/media.php
das Update durchgeführt. Auslöser ist der Request-Parameter 'btn_update'.
Wird 'btn_update' aus '$_POST' entfernt, trickst das media.php
aus und die Medien-Seite wird
normal angezeigt.
Kategoriebeschränkung erfassen
Im Beispielcode im nächsten Kapitel wird ein Array $catRestriction
mit den zulässigen Dateitypen
für ausgewählte Kategorien in der boot.ini
gepflegt. Die Daten werden per USE an die
EP-Funktionen übergeben.
Im praktischen Laben könnten die Daten z.B. in der Systemkonfiguration, in der package.yml
des Projekt-Addons oder in einem Data-Verzeichnis stehen.
Beispiel-Code
Neben der Abfrage auf Backend könnte man auch Benutzerrechte abfragen oder dass der User eingelogged ist.
Der Code ist für eine boot.ini
vorgesehen.
if( rex::isBackend() ) {
$catRestriction = [
2 => ['pdf'], // PDF-Dokumente
3 => ['jpg','jpeg','png'], // Bilder
];
$page = rex_request('page','string','');
$cat = rex_request('rex_file_category','integer',-1);
if( $page == 'mediapool/upload'
&& $_FILES['file_new']['name']
&& array_key_exists( $cat,$catRestriction ) )
{
$catsAllowed = $catRestriction[$cat];
rex_extension::register('PACKAGES_INCLUDED', function ($ep) use($catsAllowed) {
$mp = rex_package::get('mediapool');
$ext = array_diff( $mp->getProperty('allowed_doctypes'),$catsAllowed );
$ext = array_merge($mp->getProperty('blocked_extensions'),$ext);
$mp->setProperty('blocked_extensions', $ext);
$ext = array_intersect( $mp->getProperty('allowed_doctypes'),$catsAllowed );
$mp->setProperty('allowed_doctypes',$ext);
});
}
elseif( $page == 'mediapool/media'
&& rex_post('btn_update','string','') == rex_i18n::msg('pool_file_update')
&& array_key_exists( $cat,$catRestriction )
&& ( $id=rex_request('file_id','integer',-1) ) != -1 )
{
$bild = rex_sql::factory()->getArray('SELECT id,filename FROM '.rex::getTable('media').' WHERE id=:id AND category_id <> :cid',[':id'=>$id,':cid'=>$cat], PDO::FETCH_KEY_PAIR);
if( $bild ) {
$catsAllowed = array_intersect( rex_package::get('mediapool')->getProperty('allowed_doctypes'),$catRestriction[$cat] );
$extension = rex_file::extension($bild[$id]);
if( !in_array($extension,$catsAllowed) ) {
unset( $_POST['btn_update'] );
$mcat = rex_media_category::get($cat);
$result = rex_i18n::msg('pool_file_file') .
" \"<strong>{$bild[$id]}</strong>\" " .
rex_i18n::msg('pool_changecat_selectedmedia_prefix') .
" \"<strong>{$mcat->getName()} [{$mcat->getId()}]</strong>\" " .
rex_i18n::msg('pool_changecat_selectedmedia_suffix') .
' - ' .
rex_i18n::msg('pool_file_mediatype_not_allowed') .
" \"<strong>$extension</strong>\"";
rex_extension::register('PAGE_TITLE_SHOWN', function($ep) use ($result) {
$ep->setSubject(rex_view::error($result) . $ep->getSubject());
});
}
}
}
}