Hooks (nein, nicht der mit dem Krokodil...)
Verfasst: Di 24. Mär 2020, 10:26
Bei der Erarbeitung des BotTrap Moduls hatte ich ein Problem... Ich wollte NICHT, dass man - neben dem Aktivieren im Backend - noch was machen muß, egal ob es sich um das Einfügen eines include im Template handelt oder um ein Droplet, was in diesem Fall sowieso zu spät gewesen wäre. Andererseits wollte ich diesen BotTrap auch nicht als Bestandteil des Core haben. Also was tun?
Praktisch wäre es halt, man könnte sich in den normalen Ablauf an passender Stelle einklinken. Und damit sind wir bei Hooks oder Events, was so ein bißchen das selbe und so ein bißchen doch nicht das selbe ist.
Ich habe mich eine Weile umgeschaut, und die einzige verfügbare Klasse, der ich genug zutraue (und die vor allem noch aktiv gepflegt wird), wäre eine Komponente des Symfony-Frameworks gewesen. Da wir von Symfony schon das eine oder andere nutzen, wäre es naheliegend, auch den EventDispatcher zu nutzen. Ich habe mich trotzdem dagegen entschieden, und zwar weil man für jedes Event, welches man verarbeiten will, eine eigene PHP-Klasse schreiben muß. Das erschien mir recht viel Aufwand für eine eigentlich recht geringe Anforderung. Daher habe ich mich dafür entschieden, eine eigene Klasse zu schreiben.
https://symfony.com/doc/current/compone ... tcher.html
Derzeit gibt es genau einen Hook, nämlich den, den ich für meine Anforderung brauchte. Beim Verarbeiten der Anfrage soll möglichst früh erkannt werden, dass es sich bei dem Besucher um einen "bösen Bot" handelt, um diesen aussperren zu können. Das wäre in unserem Fall im Router in der Methode dispatch(). Die einzige Änderung in der Router-Klasse ist diese Zeile:
\CAT\Hook::executeHook('router.before.dispatch');
Wenn es zu diesem Hook keine registrierten externen Funktionen gibt, passiert auch weiter nichts.
Unser BotTrap Admin Tool kann nun diesen Hook "abonnieren". Dazu ist ein Eintrag in der Datenbank notwendig. In diesem steht, welche Funktion in welcher Klasse ausgeführt werden soll, und welche Priorität diese hat. Die Priorität reicht von 0 (niedrigste) bis 100 (höchste). Wenn es nun mehrere Abonnenten gibt, bestimmt die Priorität, in welcher Reihenfolge diese angesprochen werden.
Sofern nun also das BotTrap Admin Tool installiert und aktiviert ist - was das Modul selbst entscheidet, anhand einer Einstellung -, kann die dortige Methode trap() entscheiden, einen Besucher auszuschließen, und das zu ein so frühen Zeitpunkt, dass er weder an Frontend-Seiten noch an den Anmelde-Dialog des Backends rankommt. Dementsprechend hat dieser Abonnent auch die höchste Priorität 100.
Das Abonnieren eines solchen Hooks ist natürlich nicht so ganz ungefährlich; "böse" Module könnten sich in den Ablauf einklinken und "schlimme Dinge" tun. Aber sehen wir es realistisch: Ein scheinbar nützliches Modul vom Typ "page" (z.B. eine Bildergalerie) kann auch im Hintergrund "schlimme Dinge" tun, ohne dass man es merkt.
Die Hook-Klasse selbst ist schon fertig, es fehlen vielleicht noch ein paar Kleinigkeiten, z.B. um ein Abonnement auch wieder aufzuheben, aber der Kern steht schon mal. Die Klasse holt sich die vorhandenen Hooks und Abos aus der Datenbank und führt sie aus, man kann eigene Hooks zur Laufzeit hinzufügen (um sie z.B. in einem eigenen Modul zu benutzen) und existierende abonnieren. Bisher gibt es wie gesagt nur diesen einen Hook an sehr zentraler Stelle, sicherlich werden uns mit der Zeit noch weitere Stellen einfallen, wo sich das sinnvoll nutzen läßt. Schon mit diesem einen Hook ließe sich z.B. bewirken, dass bestimmte Routen (=URLs) kennwortgeschützt sein sollen, auch wenn sie das normalerweise nicht wären.
Praktisch wäre es halt, man könnte sich in den normalen Ablauf an passender Stelle einklinken. Und damit sind wir bei Hooks oder Events, was so ein bißchen das selbe und so ein bißchen doch nicht das selbe ist.
Ich habe mich eine Weile umgeschaut, und die einzige verfügbare Klasse, der ich genug zutraue (und die vor allem noch aktiv gepflegt wird), wäre eine Komponente des Symfony-Frameworks gewesen. Da wir von Symfony schon das eine oder andere nutzen, wäre es naheliegend, auch den EventDispatcher zu nutzen. Ich habe mich trotzdem dagegen entschieden, und zwar weil man für jedes Event, welches man verarbeiten will, eine eigene PHP-Klasse schreiben muß. Das erschien mir recht viel Aufwand für eine eigentlich recht geringe Anforderung. Daher habe ich mich dafür entschieden, eine eigene Klasse zu schreiben.
https://symfony.com/doc/current/compone ... tcher.html
Derzeit gibt es genau einen Hook, nämlich den, den ich für meine Anforderung brauchte. Beim Verarbeiten der Anfrage soll möglichst früh erkannt werden, dass es sich bei dem Besucher um einen "bösen Bot" handelt, um diesen aussperren zu können. Das wäre in unserem Fall im Router in der Methode dispatch(). Die einzige Änderung in der Router-Klasse ist diese Zeile:
\CAT\Hook::executeHook('router.before.dispatch');
Wenn es zu diesem Hook keine registrierten externen Funktionen gibt, passiert auch weiter nichts.
Unser BotTrap Admin Tool kann nun diesen Hook "abonnieren". Dazu ist ein Eintrag in der Datenbank notwendig. In diesem steht, welche Funktion in welcher Klasse ausgeführt werden soll, und welche Priorität diese hat. Die Priorität reicht von 0 (niedrigste) bis 100 (höchste). Wenn es nun mehrere Abonnenten gibt, bestimmt die Priorität, in welcher Reihenfolge diese angesprochen werden.
Sofern nun also das BotTrap Admin Tool installiert und aktiviert ist - was das Modul selbst entscheidet, anhand einer Einstellung -, kann die dortige Methode trap() entscheiden, einen Besucher auszuschließen, und das zu ein so frühen Zeitpunkt, dass er weder an Frontend-Seiten noch an den Anmelde-Dialog des Backends rankommt. Dementsprechend hat dieser Abonnent auch die höchste Priorität 100.
Das Abonnieren eines solchen Hooks ist natürlich nicht so ganz ungefährlich; "böse" Module könnten sich in den Ablauf einklinken und "schlimme Dinge" tun. Aber sehen wir es realistisch: Ein scheinbar nützliches Modul vom Typ "page" (z.B. eine Bildergalerie) kann auch im Hintergrund "schlimme Dinge" tun, ohne dass man es merkt.
Die Hook-Klasse selbst ist schon fertig, es fehlen vielleicht noch ein paar Kleinigkeiten, z.B. um ein Abonnement auch wieder aufzuheben, aber der Kern steht schon mal. Die Klasse holt sich die vorhandenen Hooks und Abos aus der Datenbank und führt sie aus, man kann eigene Hooks zur Laufzeit hinzufügen (um sie z.B. in einem eigenen Modul zu benutzen) und existierende abonnieren. Bisher gibt es wie gesagt nur diesen einen Hook an sehr zentraler Stelle, sicherlich werden uns mit der Zeit noch weitere Stellen einfallen, wo sich das sinnvoll nutzen läßt. Schon mit diesem einen Hook ließe sich z.B. bewirken, dass bestimmte Routen (=URLs) kennwortgeschützt sein sollen, auch wenn sie das normalerweise nicht wären.