Typo3 4.6.4 Update und Zend Server

Ein kleines Update ist heute veröffentlicht worden. Alle Änderungen sind im Release-Log aufgeführt.

Ich habe seit neustem auf meinem Windows x64 System ein Problem mit dem Zend Server CE (PHP 5.2) 5.6.0 und Typo3 Version 4.6.3. Mit Version 5.5 hat noch alles problemlos funktioniert. Ich weiß nicht, ob es an den “Security Enhancements” in PHP 5.3.9 liegt, aber der Login in den Backend-Bereich von Typo3 ist in dieser Umgebung nicht mehr möglich. Nach Absenden des Login-Formulars erschient eine Meldung ala “Wollen Sie die index.php Datei speichern oder öffnen…”. Darin ist ein 500-HTTP-Status-Code enthalten, jedoch erscheint in den Apache und PHP-Log-Dateien keinerlei Hinweis darauf. In der Ereignisanzeige von Windows sieht das ganz anders aus. Dort scheint die php-cgi.exe einen Fehler zu verursachen.

Ich werde das morgen mit der neuen Typo3-Version testen und auch Bilder und genaue Fehlermeldungen nachliefern.

Update

Eine Aktualisierung auf Typo3 4.6.4 brachte wie vermutet keinen Erfolg. Wie versprochen ein paar Details zu dem Fehler:

Typo3 4.6.3 Login Screen

Typo3 4.6.3 Login Screen

Fehlermeldung nach Login

Fehlermeldung nach Login

 

Inhalt der Datei index.php

Inhalt der Datei index.php
Windows Ereignisanzeige Fehlermeldung

Windows Ereignisanzeige - Fehlermeldung

Nochmal als Text (damit Google das findet):

Name der fehlerhaften Anwendung: php-cgi.exe, Version: 5.3.9.0, Zeitstempel: 0x4ef33bca
Name des fehlerhaften Moduls: php5.dll, Version: 5.3.9.0, Zeitstempel: 0x4ef33bc8
Ausnahmecode: 0xc0000005
Fehleroffset: 0x00092b20
ID des fehlerhaften Prozesses: 0xd1c
Startzeit der fehlerhaften Anwendung: 0x01ccdb33ed105389
Pfad der fehlerhaften Anwendung: C:\Program Files (x86)\Zend\ZendServer\bin\php-cgi.exe
Pfad des fehlerhaften Moduls: C:\Program Files (x86)\Zend\ZendServer\bin\php5.dll
Berichtskennung: f2e4d78f-4728-11e1-bd4d-005056c00008
Noch eine Meldung in der Windows Ereignisanzeige

Noch eine Meldung in der Windows Ereignisanzeige

 

Fehlerbucket , Typ 0
Ereignisname: APPCRASH
Antwort: Nicht verfügbar
CAB-Datei-ID: 0
 
Problemsignatur:
P1: php-cgi.exe
P2: 5.3.9.0
P3: 4ef33bca
P4: php5.dll
P5: 5.3.9.0
P6: 4ef33bc8
P7: c0000005
P8: 00092b20
P9:
P10:

 

Umleitung mit Apache-Rewrite-Modul

Umleitung von einer Domain mit www auf eine Domain ohne www:

RewriteCond %{HTTP_HOST} ^www\.test\.tobias-seckinger\.de [NC]
RewriteRule ^(.*) http://test.tobias-seckinger.de/$1 [R=301,L,QSA]
  • [NC] = No case. Damit spielt die Groß- oder Kleinschreibung keine Rolle
  • [R=XXX] = Redirect mit HTTP-Status-Code XXX. Im Beispiel wird mittels 301 umgeleitet
  • [L] = Last. Letzte Regel, die beachtet werden muß.
  • [QSA] = Query String Append. Hängt neue Parameter an die ursprünglichen Parameter an. Wird für obige Regel nicht zwingend benötigt.
    Beispiel:

    RewriteRule ^source\.php$ /target.php?bar=foo [QSA,L]
    # Eingabe: http://tobias-seckinger.de/source.php?foo=bar
    # Umleitung zu: http://tobias-seckinger.de/target.php?foo=bar&bar=foo

Spam-Kommentare

Na wunderbar. Heute über 50 neue Kommentare mit kurzen schmeichelhaften Sätzen inklusive Rechtschreibfehler. Bei genauem Hinsehen, kommen einige Kommentare von der gleichen IP-Adresse, aber mit komplett anderen Namen und E-Mail-Adressen. Teilweise finden sich bei Google die gleichen Kommentare auch in anderen Blogs…

Mir erschließt sich leider nicht, wozu das gut sein soll. Hier zwei der besagten Kommentare:

  • “That’s the best asewnr of all time! JMHO”
  • “You rlaely saved my skin with this information. Thanks!”

Mehrsprachige Inhalte kennzeichen

Google unterstützt die Kennzeichnung von inhaltlich ähnlichen bzw. gleichen Inhalten, die aber in verschiedenen Sprachen vorliegen mit einem zusätzlichen Attribute.

<link rel="alternate" hreflang="de" href="http://www.example.de/page-de.html" />
<link rel="alternate" hreflang="en" href="http://www.example.de/page-en.html" />

Das Attribute hreflang kennzeichnet die verwendete Sprache. Für Inhalte, die nicht als HTML-Seite zur Verfügung stehen, dann dies über einen HTTP-Header gekennzeichnet werden:

Link: ; rel="alternate"; hreflang="es"

Die möglichen Werte müssen sich an der ISO 6391-1 und optional für Regionen an ISO 3166-1 Alpha 2 orientieren.

Hilfsklassen unter Extbase

Eine Hilfsklasse kann in einer Extbase Extension im Classes Verzeichnis platziert werden. Ich empfehle die Klasse in einem Unterverzeichnis zu platzieren. Der Autoloader ist bei richtiger Bennenung in der Lage die Klasse zu laden.

Beispiel:

myextension/Classes/Helper/MyClass.php (Erster Buchstabe im Dateinamen groß schreiben).

Name der Klasse: Tx_Myextension_Helper_MyClass

Ein Datum mit Javascript

Javascript bietet das Date-Objekt an, um mit einem Datum arbeiten zu können. Wir können leicht ein solches Objekt erstellen:

var myDate1 = new Date(2011, 12, 13, 21, 30, 00);
var myDate2 = new Date(2011, 12, 13);

Das Objekt selbst bietet Funktionen an, um Eigenschaften des Objekts auszulesen oder zu manipulieren:

  • getDate() liefert den Monatstag
  • getDay() liefert den Wochentag
  • getMonth() liefert den Monat
  • getFullYear() liefert das Jahr (vierstellig)
  • getHours() liefert die Stunden der Uhrzeit
  • getMinutes() liefert die Minuten der Uhrzeit

Eine vollständige Liste findet sich z. B. auf der SELFHTML Referenz. Nun möchte man vielleicht mit einem Datum rechnen oder Vergleiche anstellen, eine Benutzereingabe validieren oder ähnliches. Dazu müssen wir in der Regel noch einiges “drumherum” programmieren. Unterstützung kann hier eine Datumsbibiothek bringen.

Datejs

Datejs

Datejs - An Open Source JavaScript Date Library

Das Projekt ist schon älter und das letzte “offizielle” Release wurde 2007 veröffentlicht. Auf der Projektseite wurde die Bibliothek weiter über 1.000.000 mal heruntergeladen. Datejs erweitert das Date-Objekt selbst, d. h. es stehen zusätzliche Funktionen zur Verfügung. Nachfolgend ein kleiner Auszug:

  • Date.today() liefert das aktuelle Datum.
  • Date.today().next().friday() liefert das Datum des nächsten Freitags
  • Date.last().week() liefert das Datum vor einer Woche
  • Date.today().addDays(n) addiert n Tage zu dem aktuellen Datum.

Mehr Beispiele finden sich der Projektseite.

Außerdem kann man das Datumsobjekt auch komfortabel setzen:

var time = {hour:18, minute:15};
Date.today().at(time); // heute um 18:15 Uhr

var mydate = {month: 1, day: 20, hour: 20, minute: 30};
Date.today().set(mydate); // aktuelles Jahr, 20. Januar um 20:30 Uhr

Die Bibliothek bietet noch viel mehr Funktionen z. B. für das Parsen von Strings oder für Datumsvergleiche. Wenn wir beispielsweise ein Anfangs- und Enddatum haben und prüfen wollen, ob ein bestimmtes Datum innerhalb dieser Zeitspanne liegt, so kann das mit folgender Zeile geprüft werden:

Date.today().between(startDate, endDate) // true|false

Eine Lokalisierung von Ausgaben ist möglich. Es gibt bereits fertige Spracherweiterungen

<!-- de-DE (deutsch) -->
<script type="text/javascript" src="date-de-DE.js"></script>

Moment.js

Eine weitere, relative junge “Date Library” ist Moment.js. Anstatt das Date-Objekt zu erweitern, wird hier mit einem Wrapper gearbeitet.

var mydate = moment(new Date(2011, 12, 13));

Mit diesem Objekt kann ähnlich wie unter Datejs gearbeitet werden:

mydate.add('days', 11); // addiert 11 Tage
mydate.subtract('months', 1); // ein Monat zurück
mydate.year(2012); // setzt das Jahr auf 2012

Eine Differenz kann folgendermaßen berechnet werden:

var a = moment([2011, 12, 24]);
var b = moment([2011, 12, 25]);
a.diff(b);

Ab und zu braucht man vielleicht auch wieder das Date-Objekt:

mydate.native();

In der Dokumentation habe ich leider keinen Hinweis gefunden, um zu prüfen, ob ein Datum zwischen zwei Zeiträumen liegt. Vom Umfang her ist diese Bibliothek natürlich schön schlank. Eine Lokalisierung ist auch möglich.

Formular unter Zend validieren

Ich nehme mal an, dass wir den Rumpf eines Formulars vorliegen haben (zf create form…) und eines der Felder validieren wollen:

class Application_Form_MyForm extends Zend_Form
{
  // initialization
  public function init()
  {
    $this->setMethod('post');
 
    $this->addElement(
      'text', 'myelement', array(
        'label' => 'Mein Element*:',
        'required' => true,
        'filters' => array('StringTrim'),
        'validators' => array(array('stringLength', 
                                    false, array(8, 8)), 
                        array('digits'), 
               array(new Application_Form_Validator_MyValidator()))
      )
    );

Dem Element myelement werden unterschiedliche Validatoren hinzugefügt z. B. das nur Zahlen erlaubt sind (digits). Die Validatoren, die das Zend Framework bereits mitbringt, findet man im Verzeichnis Validate. Interessant ist an dieser Stelle der eigene Validator. Damit das ZF den Validator findet muß man zuerst den Autoloader anpassen. Bei mir liegt die Klasse Application_Form_Validator_MyValidator im Verzeichnis application/forms/validators und ist als MyValidator.php abgespeichert. Die Autoloader-Anweisung in der Bootstrap-Klasse lautet wie folgt:

$loader=$this->getResourceLoader();
$loader->addResourceType('validators', 'forms/validators', 
                         'Form_Validator');

Der Validator selbst leitet von der abstrakten Klasse Zend_Validate_Abstract ab und sieht exemplarisch folgendermaßen aus:

class Application_Form_Validator_MyValidator 
                                 extends Zend_Validate_Abstract
{
  // consts
  const INVALID='invalid';
  //----
  
  // properties
  protected $_messageTemplates = array(self::INVALID=>
                               "'%value%' ist kein gültiger Wert");
  //----
  
  // validation
  public function isValid($value, $context = null)
  {
    $this->_setValue($value);
    // validierung
    if(true) // pseudo code
      return true;
 
    $this->_error(self::INVALID);
    return false;
  }
}

Zugriff auf mehrere Datenbanken unter Zend

Wenn man innerhalb einer Zend Anwendung auf verschiedenen Datenbanken (mysql, mssql, etc.) zugreifen möchte, kann die Verbindungen in der application.ini hinterlegen:

resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "xxx"
resources.db.params.password = "yyy"
resources.db.params.dbname = "zzz"
resources.db.isDefaultTableAdapter = true
 
resources.multidb.db1.adapter = "Sqlsrv"
resources.multidb.db1.host = "server-1"
resources.multidb.db1.dbname = "xxx"
resources.multidb.db1.username = "yyy"
resources.multidb.db1.password = "zzz"
resources.multidb.db1.charset = utf8
...

Anschließend kann die Instanz des Adapters geholt werden:

$front=Zend_Controller_Front::getInstance();
$bootstrap=$front->getParam('bootstrap');
$resource=$bootstrap->getPluginResource('multidb');
/**
 * @var Zend_Db_Adapter_Sqlsrv
 */
$db=$resource->getDb('db1');

Super, oder?