Borlabs Cookies zeigt “Ihre Website verwendet keine SSL-Zertifizierung.” an, obwohl SSL aktiviert ist

Wenn Borlabs Cookies “Ihre Website verwendet keine SSL-Zertifizierung.” anzeigt, obwohl SSL aktiviert ist, kann das einen relativen einfachen Grund haben, der – ebenso wie das Problem der WPML typischen Konstante “ICL_LANGUAGE_CODE” – trotzdem mehr als ärgerlich ist.

Borlabs Cookies wertet interessanterweise offensichtlich die Konstante WP_CONTENT_URL aus, um zu bestimmen, ob SSL aktiv ist bzw. die Seite über https ausgeliefert wird. Das Setzen von
define( 'WP_CONTENT_URL', '/wp-content');
ist jedoch alles andere als unüblich; insbesondere wenn eine Seite unter einer Entwicklungsdomain gebaut wird und später umzieht. Mal davon abgesehen, dass die Media-Pfade daduch deutlich kürzer werden.
Es reicht also, die Definition in der wp-config.php auszukommentieren.

Es ist natürlich so, dass eine URL, in diesem Fall die WP_CONTENT_URL, aus Protokoll, Host und Pfad bestehen sollte. Gelebt wird es bzgl. WP_CONTENT_URL jedoch meist anders.

Sollte das Content-Verzeichnis tatsächlich nicht in /wp-content/ liegen, ist WP_CONTENT_URL ggfs. mit Protokoll und Domain zu definieren.

Borlabs Cookie meldet den Fehler “Ihre Sprachkonfiguration ist defekt.”

Sofern man WPML für die Mehrsprachigkeit auf einer WordPress-Instanz im Einsatz hatte und WPML deinstalliert, kann es durchaus sein, dass man im eigenen Code die für WPML typische Konstante “ICL_LANGUAGE_CODE” abfragt und auch selbst setzt, falls sie nicht vorhanden ist, um den eigenen Code unabhängig von WPML lauffähig zu halten.

Sofern man “ICL_LANGUAGE_CODE” im eigenen Code gesetzt hat und WPML nicht mehr im Einsatz ist, stehen die Chancen sehr gut, dass Borlabs Cookie den Dienst – teilweise – verweigert.

Der Grund dafür ist, dass Borlabs Cookie bei Vorhandensein der Konstante “ICL_LANGUAGE_CODE” davon ausgeht, dass WPML installiert ist.

Bei Einsatz bspw. in der functions.php des (Child-)Themes erscheint dann vermutlich im Backend die Fehlermedlung “Ihre Sprachkonfiguration ist defekt. Deaktivieren Sie alle Plugins außer Borlabs Cookie, bis diese Meldung verschwindet. Wenn Sie das Plugin gefunden haben, das diesen Fehler verursacht, überprüfen Sie, ob ein Update verfügbar ist, und installieren Sie es.”.
Darüber hinaus lassen sich vermutlich keine Cookie im Backend anlegen. Stattdessen gibt es die Fehlermeldung “Die ausgewählte Cookie Gruppe existiert nicht.”.

Die Lösung ist realtiv einfach. Statt “ICL_LANGUAGE_CODE” setzt man eine eigene Sprachkonstante und gleicht diese nur bei Vorhandensein mit “ICL_LANGUAGE_CODE” ab.

Sofern man “ICL_LANGUAGE_CODE” in den Template-Files einsetzt, gibt es vermutlich keine Fehlermeldung. Allerdings kann es passieren, dass weder die Cookie-Gruppen in der Cookie Box angezeigt werden, noch dass die optischen Anpassungen der Cookie Box greifen.

Javascript-Debugging unter WordPress mit console.log beim Staging / bei Verwendung einer Testumgebung

Die Javascript-Funktion console.log() ist beim Debugging quasi unumgänglich. Allerdings möchte man in Produktivumgebungen keine Debug-Meldungen sehen.

Man kann natürlich beim Staging aus der Entwicklungs- oder Test-Umgebung jedes mal alle Aufrufe von console.log() auskommentieren oder löschen. Sofern eine Website allerdings einer ständigen Eeiterentwicklung unterliegt, ist das eher mühsam. Außerdem ist jeder manuelle Schritt beim Staging eine potentielle Fehlerquelle.

Eleganter ist es, dabei auf den Debug-Status von WordPress zurückzugreifen.

In Entwicklungs- oder Test-Umgebungen werden sich ziemlich sicher in der wp-config.php die Zeilen

finden.
Während in Live- oder Produktivumgebungen hoffentlich die Zeilen

vorhanden sind.

Man ergänzt jetzt diesen Abschnitt einfach um eine weitere Konstante:

Die Konstante WP_DEBUG_JS lässt sich beim Enqueuing des Javascripts im (Child-)Theme oder Plugin über die Lokalisierung mit übergeben:

In der Javascript-Datei muss dann nur noch console.log() in einer eigenen Funktion gekapselt werden

und einmalig “console.log( … )” durch “stablew_eblog( … )” ersetzt werden.


Exkurs: Relative URLs für Medien für einfacheres Migrieren von der Test- in die Live-Umgebung

Wenn man schon an der wp-config.php dran ist, kann man auch gleich noch dafür Sorge tragen, dass Medien mit relativen URLs verarbeitet werden:

Mozilla Firefox hat Verbindungsprobleme und lastet die CPU aus

In Version 95 und evtl. auch früheren Versionen verbindet sich Mozilla in einigen Konstellationen nicht mehr mit Webservern.

Das Problem ist wohl ein Fehler im HTTP/-Protokollstapel, der vermutlich zeitnah behoben wird. Bis dahin hilft es, HTTP/3 zu deaktivieren:

In der Adresszeile

eingeben.
Die evtl. auftretende Warnmeldung bestätigen und in der eingeblendeten Suchzeile

eingeben und [RETURN] drücken.
Im Suchergebnis (es sollte nur eine Zeile geben) dann auf den Button rechts mit dem Pfeil nach links und rechts klicken, so dass beim Wert in der mitte “false” steht.

Nunmehr sollte Firefox wieder wie gewohnt funktionieren.

Wie kann ich die Standard-PHP-Version auf meinem Synology NAS ändern?

– ggfs. SSH in der Systemsteuerung des NAS aktivieren
– via Putty oder Bitvise oder einen anderen SSH-Client auf dem NAS einloggen
– folgende Befehle abschicken

Auf einem Synology NAS unter DSM lassen sich per Webserver-Script keine Dateien anlegen

Wenn sich bspw. per PHP auf dem Webserver eines Synology NAS keine Dateien anlegen lassen, ist der Grund meist eine mangelnde Rechtezuweisung für die Gruppe “http”.

Meist gibt es dann hübsche Fehlermeldung Warning: fopen(...): failed to open stream: Permission denied in /volume1/web/xyz.php

Um das Problem zu beheben, sind nur wenige Schritte notwendig:

  1. im Backend des NAS die Systemsteuerung öffnen
  2. “Gemeinsamer Ordner” anklicken
  3. in der Liste den betreffenden Ordner anklicken
  4. Button “Bearbeiten” anklicken
  5. im sich öffnenden Fenster den Reiter “Berechtigungen” anklicken
  6. in der Selectbox oben links “Lokale Gruppen” auswählen
  7. für “http” die Checkbox “Lesen/Schreiben” markieren
  8. den Button “OK” anklicken

Nunmehr sollte es keine Probleme mehr geben.

Ein paar wissenswerte Anmerkungen zu IMAP mit PHP

Da ich kürzlich ein Hostingpaket eines Kunden von einem Hoster zum nächsten umziehen sollte, stellte sich das Problem der Postfach-Migration.

Da der Kunde alle E-Mails per IMAP abruft, waren alle Mails auf den Servern des Alt-Hosters gespeichert. Es handelte sich um eine hohe zweistellige Anzahl an Postfächern, von denen viele eine fünfstellige Anzahl an E-Mails beherbergten und Größen im zweistelligen GB-Bereich erreichten.

Früher hätte man das mit IMAPSize relativ einfach erledigen können, aber seit SSL üblich ist, funktioniert IMAPSize halt meist nicht mehr; so auch in diesem Fall. Thunderbird & Co. strecken bei solchen Postfächern ebenfalls meist die Hufe.

Eine Suche nach “IMAP Mail Migration / Umzug” brachte als brauchbare Lösung nur Mailstore Server zu Tage. Allerdings bei dieser Anzahl an Postfächern auch nicht direkt zu einem kleinen Kurs für einen kleineren Gewerbetreibenden.

Nun gut, dann halt per Script. Da gibt es ja bestimmt etwas brauchbares. In Perl gibt es tatsächlich etwas, aber Perl gehört nicht zu meinen üblichen Spielwiesen. Und es gibt auch etwas in PHP. Allerdings war das relativ grob zusammengeschustert und tat nur ansatzweise, was es sollte. Also blieb nur, die Anregungen aus den vorhandenen Scripten aufzunehmen und selbst etwas zu bauen.

Aufgrund der Größe der Postfächer war klar, dass es mit den begrenzten Scriptlaufzeiten auf dem Webserver sicherlich keinen Erfolg geben wird. Also muss man auf die Shell ausweichen.

Ohne zu sehr ins Detail gehen zu wollen, ergaben sich dabei ein paar interessante Probleme:

1. Die Message-IDs innerhalb einer Mailbox (nicht innerhalb des Postfachs) waren nicht eineindeutig, obwohl das so sein sollte.
Warum das wichtig ist, wenn man die Mails doch nur von einem Postfach ins andere Schaufeln möchte? Nun, der Umzug eines Hostingpakets hängt zeitlich von vielen Faktoren ab. Aufgrund der Größe der Postfächer wurden die Postfächer schon im Vorfeld kopiert. Anschließend sollten nur noch inkrementelle Updates gefahren werden.
Um inkrementelle Updates zu realisieren, muss man die E-Mails im alten und neuen Postfach jedoch eindeutig identifizieren können.
Na dann halt eine Kombination aus Message-ID und Zeitstempel im Header der E-Mail. Lustig, denn damit kommen wir zum zweiten Problem:

2. Nicht jede E-Mail hat einen Zeitstempel (Eigenschaft “Date / date” im Header).
Also war eine eindeutige Identifizierung über eine Kombination aus Message-ID und Zeitstempel auch nicht ohne weiteres möglich.
Glücklicherweise verhalten sich die Mail-Server verlässlicher als die absendenden Mail-Clients und -Generatoren. Sie legen tatsächlich im Header jeweils einen “Received”-Eintrag an. Leider geben die PHP-IMAP-Funktionen genau diesen Wert (bzw. diese Werte, da es mehrere Received-Einträge im Header gaben kann) nicht zurück. Es bleibt also nur der Weg, den Header selbst zu zerlegen und den letzten Received-Zeitpunkt zu extrahieren.
Nun kann man anhand der Message-ID und des Zeitstempels alle Mails im Ursprungs- und Ziel-Postfach eindeutig identifizieren und verhindern, dass E-Mails mehrfach übertragen werden.

Zumindest bei E-Mails, die keinen Date-Eintrag im Header haben, sollte man dann beim Aufruf von “imap_append” den Zeitstempel mit übergeben. Interessanter Weise wird im RFC 3501 immer auf RFC 2822 verwiesen. Im Header sind alle Datumswerte auch ganz offensichtlich gemäß der PHP-Konstante DATE_RFC2822 formatiert. Wenn man nun versucht, imap_append mit einem Zeitstempel gemäß RFC 2822 zu füttern, bekommt man die höfliche Notiz, dass diese Angabe ungültig ist. Auch ein reiner Unix-Zeitstempel führt nicht zum Erfolg.
Stattdess muss es ein String gemäß dem Muster date( "d-M-Y H:i:s O", #Unix-Zeitstempel# ); sein. Falls das irgendwo brauchbar dokumentiert ist, war ich jedenfalls nicht in der Lage, es zu finden.

3. Ein weiterer Spaß ist die Kodierung und Struktur der Mailboxnamen (für gewöhnlich als Ordner wahrgenommen). Gemäß RFC 3501 wird eine spezielle Version von UTF-7 für die Kodierung verwendet. Das ist immer dann von Bedeutung, wenn auf dem Quellserver Umlaute für die Mailboxen verwendet werden. Im deutschsprachigen Raum ist das relativ häufig der Fall, da oftmals für die Standard-Mailbox “Drafts” das deutsche “Entwürfe” verwendet wird.
Auch der Delimiter (Hierarchie-Trenner) verdient Beachtung. Während bei der Anlage neuer Mailboxen grundsätzlicher der Slash “/” als Trenner verwendet werden kann, gilt dies auf dem Quellserver für den lesenden Zugriff nicht. Hier heißt es unbedingt mit “imap_getmailboxes” die Mailboxen abzufragen, wobei die Eigenschaft “delimiter” mit übergeben wird, welche man dann zwingend als Trenner auf dem Quellserver verwenden muss.

4. Die Funktion “imap_rfc822_parse_headers” schmiert sehr elegant mit einem “Fatal error” ab, wenn der Header einer E-Mail die Größe von 16 KB übersteigt. Üblicherweise sind Header eher um die 4 KB groß, aber ganz gelegentlich gibt es halt mal Ausreißer. Da hilft nur, den zu übergebenden Header abzuschneiden…

Nachdem alle diese Fallstricke umgangen waren, stand einer erfolgreichen Mail-Migration nichts mehr im Weg. ABER!

Tatsächlich war bei einigen E-Mails der Aufruf von imap_append nicht erfolgreich. Es gab die freundliche Warnung “Can’t save a zero byte message (0.001 + 0.000 secs)”. Zu Analysezwecken habe ich diese Mails dann in EML-Dateien geschrieben und näher angeschaut. Es handelte sich bei diesen E-Mails ausschließlich um Spam-Mails, die nicht wohlgeformt waren.
Damit der Kunde die Diskrepanz zwischen Quell- und Zielpostfach versteht, ließ ich also ein Logfile mitlaufen und exportierte nicht migrierbare in EML-Dateien, um diese zu übergeben.

TinyMCE in WordPress per AJAX aufrufen

TinyMCE lässt sich in Plugins sehr einfach über wp_editor() aufrufen. Allerdings funktioniert das nicht, sobald der Call über AJAX erfolgt, bspw. um in einem Modal TinyMCE zu verwenden.

Abhilfe schafft der Aufruf von

nach dem Schließen des beinhaltenden Formulars.

Anschließend funktionert TinyMCE auch im Modal.

Wichtig ist dabei, das Formular erst mit

zu schließen, da ansonsten das Formular “zerschossen” werden kann.

Die Ausgaben von wp_editor() und do_action lassen sich bei Bedarf übrigens einfach abfangen, wenn bspw. das Ergebnis der AJAX-Calls in einem JSON-encoded-Array zurückgegeben werden soll: