Zend Server endlich auch für Mac OS X

Endlich gibt es den Zend Server (Version 5.6) auch nativ für Mac OS X.

Wenn man, wie ich, auf einem Mac entwickelt, musste man sich immer mit der doch recht ätzenden Installation des Zend Servers für den Mac herumplagen. Ich glaube, ich habe beim ersten Mal locker drei Versuche benötigt, bis ich eine vernünftige Installation hinter mich gebracht habe.

Hier geht es zum Download: Zend Server

Zend Forms mit Ajax versenden

Im Netz gibt es ja zahlreiche Artikel zu Zend Forms und wie man diese mit Ajax validiert. Eigentlich alle Treffe via Google, die ich gefunden habe, basieren auf die selbe Lösung und exemplarisch dafür möchte ich hier nur auf eine mögliche Seite, die sich diesem Thema annimmt, verweisen: Ajaxify your Zend Form, validation with jquery.

Da eigentlich alle Seiten die gleichen Codefragmente verwendet haben und man hier noch einen ausführlichen Webcast dazu bekommt, hat mir das Tutorial bei Zendcast zu diesem Thema am besten gefallen. Der Vorteil bei dieser Art der Validierung liegt auf der Hand, das Zend Framework nimmt einem jegliche Programmierung bei der eigentlichen Validierung ab und noch wichtiger, die Validierung an sich bleibt Server-Seitig. Leider fand ich nirgends einen Hinweis darauf, wie man die Form, nach erfolgreicher Validierung dann doch abschicken kann. Viele fragten auf einschlägigen Seiten nach, oft gab es aber nur die Antwort darauf, wie man ein automatisches Submit der Form bei erfolgreicher Validierung verhindert.

Als erstes muss man ganz klassisch eine Form mit Hilfe von Zend_Form definieren.

Natürlich sollte hier mindestes ein Pflichtfeld vergeben sein, sonst gibt es nichts zu validieren und das Formular kann immer versendet werden. In diesem Beispiel ist es das E-Mail Feld $email->setRequired(true);. Jetzt benötigt man noch den Controller und die View, schließlich möchte man das Formular ja sehen und falls es valide ist, soll ja irgendwas mit der Eingabe geschehen.

Der Controller sieht vorerst so aus und macht erst einmal nichts weiter als das Formular anzuzeigen:

Die zugehörige View könnte dann zum Beispiel so aussehen:

Oder einfacher (je nachdem, wie flexibel man beim Layout seien muss oder möchte):

Als nächstes kommt dann noch, wie bei ZendCast vorgeführt die eigentliche Validierung via Ajax und dem Serverseitigen Mechanismus, der durch Zend Form zur Verfügung gestellt wird. Hierzu werden einige kurze Javascript Funktionen benötigt, die sich in der entsprechenden View befinden und schnell erstellt sind. Ferner werden die Pflichtfelder bereits bei der Eingabe überprüft (.blur()). Das ganze könnte dann ungefähr so aussehen:

Es gibt, wie man sehen kann, zwei Funktionen für die Validierung. Zum einen, wie bei den ganzen anderen Tutorials die Funktion doValidation(). Hier wird jedes Feld direkt bei der Eingabe überprüft und sofort das entsprechende Feld mit einer Fehlermeldung markiert, bzw. diese Markierung wieder entfernt, sobald das Feld valide ist. Da man aber sicher nicht schon bei der Eingabe eines an sich validen Formulars dieses automatisch absenden möchte, da vielleicht die Felder, die nicht validiert werden, fertig ausgefüllt sind oder man seine Eingabe noch ändern möchte, habe ich eine zweite, angepasste Funktion (doValidationAll()) implementiert, die zum einen das valide Formular absendet und zum anderen alle Felder gleichzeitig beim drücken des Submit Buttons validiert und entsprechende Fehlermeldungen positioniert. Gleichzeitig ist dieser Teil auch dafür zuständig, alle Daten des validen Formulars an den Controller weiter zu reichen, um dann hier die Daten zu verarbeiten.

Man könnte das ganze sicher noch vereinfachen und vor allem bei Erfolg einen leeren JSON-String zurück geben und anschließend auf einen leeren String testen und so ein paar Zeilen sparen. Sicher könnte man auch aus zwei Controllern nur einen machen, aber das sind dann Feinheiten für das Refactoring.

Jedenfalls hat mit genau dieser Teil bei meiner Suche im Netz gefehlt. Vielleicht hilft es ja Jemandem.

IE7,8 Bug mit Problem aus iFrames

Ab und an muss man noch mit iFrames arbeiten, vor allem, wenn man eigene Inhalte auf Facebook Fanseiten zu Verfügung stellen möchte. Mitunter möchte man auch schon mal Daten persistent von einem Tab zum Nächsten beim User speichern, z.B. für eine Sprach- oder Ländereinstellungen. Klar denkt man dann sofort an Cookies.

Wenn man, wie ich, überwiegend mit Chrome oder Firefox testet und den Internet Explorer nur am Schluss zur Überprüfung des Layouts, mit all seinen Tücken, für die letzte Qualitätssicherung hinzu zieht, kann man gerade bei Cookies, die in einem iFrame gesetzt werden, eine Überraschung erleben. Obwohl die Standard-Sicherheitseinstellungen das Speichern des Cookies zulassen müssten, entdeckt man plötzlich ein kleines Warnsymbol in der Statusleiste des IE, mit dem Hinweis, dass der Cookie geblockt wurde. Zuerst dachte ich dann, wird der Cookie in den anderen Browser etwa auch geblockt, aber das kann ja nicht sein, da dort alles einwandfrei funktionierte.

Jedenfalls gibt es beim W3C ein Projekt Namens Platform for Privacy Preferences (P3P). Und dieser quasi Standard des W3C sorgt unter anderem dafür, dass Cookies im IE7 und IE8 nicht wie erwartet funktionieren.

In einem Blog-Eintrag von Adam Young habe ich dann die Lösung (PHP) für das Problem gefunden: http://adamyoung.net/IE-Blocking-iFrame-Cookies

Siehe da, nun klappt es auch im IE.

Double Opt-In ohne Datenbank

Wenn man von Nutzern Daten in irgendeiner Art erhebt, in der Regel via eines Online-Formulars und man Aufgrund des angestossenen Vorgangs reagieren möchte, zum Beispiel dem Versenden von Newslettern, kommt man um ein sogenanntes Double Opt-In nicht drum herum, wenn man sich nicht mit Schadensersatzansprüchen des Nutzers herumschlagen möchte, weil dieser vielleicht unerwünschte E-Mails oder Anrufe erhalten hat.

Wir haben bisher immer alle Benutzerdaten bei diesem Prozess in Datenbanken gesichert, was natürlich bedeutet, dass man den Nutzer zusätzlich auf Datenschutz-Bestimmungen hinweisen muss. Je nach Formulierungen ein weiterer juristischer Knackpunkt. Auf der technischen Seite wird man gezwungen eine Datenbank aufzusetzen, diese Daten zu pflegen und gegebenenfalls per definiertem Regelwerk den Datenbestand wieder zu bereinigen. Wie man sieht, im laufe der Zeit nicht wenig Aufwand, den man sich damit einfängt.

Ich muss zugegeben, es gibt Szenarien, wo man nicht darum herum kommt, die oben genannten Punkte alle zu berücksichtigen, aber wir hatten letztens den Fall, dass Daten via eines Bestellformulars für Probefahrten direkt an ein CRM (Customer-Relationship-Management) weitergeleitet werden sollen und wir die Datenvorhaltung lediglich für das Double Opt-In benötigen. Da kam ein ehemaliger Kollege von mir auf die Idee, doch alles via E-Mail inkl. der Daten per Get-Parameter zu übergeben. Da in diesem Fall sämtliche Daten in dem Link für das Double Opt-In innerhalb der E-Mail sind, benötigen wir hier keine weitere Instanz, um die Daten zu speichern.

Damit nicht jeder sofort erkennt, was da versendet wird, sollte man den Wert des Get-Parameters maskieren, zum Beispiel mit der PHP-Funktion base64_encode. Noch besser wäre es, das ganze zu verschlüsseln, wobei sich hier in PHP die mcrypt-Library eignet. Aus dem ganzen könnte dann folgende Klasse entstehen:

Nun braucht man einen passenden String, den man mit der oben aufgeführten Klasse verschlüsseln möchte. Ich fand einen JSON Formatierten String für diesen Zweck ideal, da man ja am Ende die Daten wieder irgendwie nach Keys und Values auflösen möchte. Hier kann man entweder mit entsprechenden Libraries einen JSON String erstellen (JSON Encode), oder, da das Format recht überschaubar ist, den String selbst erstellen.

Ich habe mich für Letzteres entschieden und am Ende sollte das dann so oder ähnlich aussehen. Das Ergebnis wird dann für das Double Opt-In via E-Mail an den User gesendet. Die Daten kommen aus einem vorher ausgefüllten Formular:

Ich habe den String vor allem selbst erstellt, um die Möglichkeit zu haben, die Key-Namen um einiges zu verkürzen, damit der String bei mehreren Feldern nicht zu lang wird. URLs sollten eine länge von ca. 2000 Zeichen nicht übersteigen und da beim Verschlüsseln, trotz des komprimierens die Länge etwas zunimmt, schadet es nicht, dort zu sparen, wo es geht und Sinn macht.

Der User erhält eine E-Mail, wenn er korrekterweise der richtige Empfänger ist, wird er auf den Link klicken und auf der Zielseite wird der verschlüsselte Wert wieder dekodiert, das JSON Objekt wieder in ein Array umgewandelt und die Daten dann weiter verarbeitet, zum Beispiel an ein externes CRM geschickt.

Wie man sieht, kommt man so um eine eigene Datenhaltung herum und spart sich eine Menge Aufwand.