Problem mit UTF-8 in CakePHP mit MySQL

CakePHP kann zwar mit UTF-8 umgehen, allerdings werden die Daten nicht als UTF-8 in der MySQL-Datenbank gespeichert. Datensätze sehen dann beispielsweise so aus: „Bündnis 90 Die Grünen“.

Im Konstruktor des AppModel („/app/app_model.php“) kann man dieses Problem aber beheben, indem man „SET NAMES ‚UTF8′“ ausführen lässt, bevor andere Abfragen an die Datenbank gestellt werden.

class AppModel extends Model
{
    function __construct($id=false, $table=null, $ds=null)
    {
        parent::__construct($id, $table, $ds);
        if(!defined('SET_NAMES_UTF8'))
        {
            $this->query("SET NAMES 'UTF8'");
            define('SET_NAMES_UTF8', true);
        }
    }
}

CakePHP-Entwicklung im Allgemeinen und speziell unter OS-X

cake2000_medGrob gesagt ist CakePHP ein MVC-Framework in PHP. Es unterstützt Validierung, Internationalisierung und bietet eine automatischer Objektserialisierung in die Datenbank. Mit CakePHP kann man Model, Controller und Views generieren backen. Besonders praktisch ist, dass man mit CakePHP die notwendigen Objekte und Seiten für ein voll funktionstüchtiges CRUD (Change Read Update Delete) inklusive Admin-Interface erstellen kann. 

Seit ich es vor einem Jahr entdeckt habe, möchte ich keine PHP-Anwendung mehr ohne CakePHP machen. CakePHP ist Open-Source, klein, klar, gut programmiert, anständig dokumentiert und relativ leicht verständlich. Es beschleunigt nicht nur die Entwicklung ungemein, sondern sorgt auch mit einem klaren Benennungs-Schema dafür, dass der Code sauber und übersichtlich bleibt. 

Installation

Zur Installation wird CakePHP lediglich entpackt und dann in den htdocs-Ordner des Webservers kopiert. In dem entpackten Ordner befindet sich eine im Finder unsichtbare .htaccess-Datei, die unbedingt mit kopiert werden muss. Falls die Startseite nach der Installation so aussieht, als hätte sie kein CSS, wurde das wahrscheinlich vergessen.

CakePHP läuft sowohl mit MAMP, als auch mit XAMMP. Alle weiteren, für die Installation notwendigen Dinge, wie Datenbank-Konfiguration und Verzeichnisberechtigungen, werden nach Aufruf der Startseite in der Installations-URL im Browser angezeigt. 

Nach der Installation sollte die Startseite so grün, wie im folgenden Screenshot aussehen.

cakephp-installation

Backen

Mit CakePHP lassen sich Model-Objekte, Controller und die CRUD-GUI-Seiten automatisch aus in der Datenbank angelegten Entities generieren. Dazu geht man mit dem Terminal in den Ordner /cake/console und kann nun die gewünschten PHP-Klassen mit

/Applications/xampp/xamppfiles/bin/php cake.php bake 

wenn man XAMPP benutzt oder 

/Applications/MAMP/bin/php5/bin/php cake.php bake

mit MAMP, generieren.

Datenbank

Datenbanktabellen sollten für CakePHP immer in der Mehrzahl benannt werden, also „users“ oder „locations“. CakePHP kann einen von der Datenbank generierten Primärschlüssel nutzen. Unter MySQL beispielsweise legt man einen auto_increment key mit

`id` int(11) NOT NULL auto_increment,

an. Wenn man dem Primärschlüssel den typ CHAR(36) gibt, generiert CakePHP beim Speichern der Objekte automatisch eine UUID als Primärschlüssel. 

Die Felder „created“ und „modified“ werden von CakePHP automatisch  mit dem Datum der Erstellung und der letzten Änderung des Datensatzes befüllt. 

`created` datetime NOT NULL,
`modified` datetime NOT NULL,

Folgende Datentypen können für das CakePHP-Model im Fall von MySQL genutzt werden:

CakePHP Datentyp MySQL Datentyp
primary_key NOT NULL auto_increment
string varchar(255)
text text
integer int(11)
float float
datetime datetime
timestamp datetime
time time
date date
binary blob
boolean tinyint(1)

Die Datentypen für weitere Datenbanken, wie PostgreSQL, DB2 oder Oracle findet man hier im Cookbook

Dokumentation

Weitere Informationen über CakePHP

Ich wünsche frohes backen!

Mit Python schnell mal einen HTTP- oder SMTP-Server starten

In Python ist so einiges nützliches eingebaut. Wir finden in Python beispielsweise einen kleinen HTTP-Server und auch einen SMTP-Server. Auf Systemen mit installiertem Python lassen sich so Dateien schnell und unproblematisch zum Download durch andere Computer freigeben oder man kann mal eben einen Mail-Server zum Testen der selbst programmierten E-Mail-Versende-Funktion starten.

Mit dem HTTP-Server Verzeichnisse freigeben

Um Dateien per HTTP freizugeben, einfach mit dem Terminal in den Ordner wechseln, den man freigeben möchte und dann den Python-HTTP-Server mit

python -m SimpleHTTPServer

starten.

Der Server ist danach auf Port 8000 erreichbar, also unter http://MEIN_COMPUTER:8000/.

Mit dem Python-SMTP-Server E-Mail-Versendung testen

Sehr nützlich für die Software-Entwicklung ist der Python-SMTP-Debug-Server, der alle empfangenen E-Mails lediglich direkt auf der Kommandozeile ausgibt. Einen solchen SMTP-Server kann man auf Port 1025 mit dem Befehl

python -m smtpd -n -c DebuggingServer localhost:1025

starten.

Weitere Informationen:

Leerzeichen und leere Zeilen automatisch aus Tomcat-JSPs entfernen

Bei der Erstellung von JSPs entstehen im generierten HTML oft viele sinnlose Leerzeichen und leere Zeilen. Ab Tomcat 5.5 kann man diesen überflüssigen Whitespace automatisch per Konfiguration heraus filtern.

Dazu kann, wie in folgendem Code-Ausschnitt gezeigt, in der $CATALINA_HOME/conf/web.xml dem „jsp“-Servlet der init-param „trimSpaces“, hinzugefügt werden.

<init-param>
    <param-name>trimSpaces</param-name>
    <param-value>true</param-value>
</init-param>

Das Resultat ist kompakteres HTML. Etwas Vorsicht ist allerdings geboten, da sich durch das Trimmen der Leerzeichen, vor allem in älteren Browsern, auch das Erscheinungsbild der Seite ändern kann.

PHP-Seiten bei Auslieferung zippen

Mit zwei einfachen Zeilen in der .htaccess lässt sich der Inhalt von PHP-Seiten bei der Auslieferung automatisch gzippen, was zu einer Reduzierung der Seitengröße um bis zu 90% führen kann.

php_value output_buffering On
php_value output_handler ob_gzhandler

Diese Konfiguration lässt sich auch mit folgenden Zeilen in der php.ini durchführen.

output_buffering = On;
output_handler = ob_gzhandler;

…oder direkt im PHP-Sourcecode, durch Hinzufügen von

<?php
ob_start("ob_gzhandler");
?>

Notwendig für die Funktionsfähigkeit dieser Komprimierung ist die zlib-Erweiterung von PHP. Diese Erweiterung ist aber allgemeiner Standard bei PHP-Hosting-Anbietern.

Dokumentation zu ob_gzhandler auf php.net

Problem mit Boolean in Hibernate mit MySQL

Wenn Hibernate mit MySQL und MySQLDialect oder MySQL5Dialect genutzt wird, kann es sein, dass der Datentyp Boolean nicht richtig funktioniert. Und zwar legt Hibernate ein Boolean-Feld in MySQL als BIT(1) an, womit scheinbar der JDBC-Treiber nicht klarkommt.

Damit Boolean-Felder mit Hibernate/MySQL richtig funktionieren, kann und sollte man den Datentyp des Feldes auf TINYINT(1) setzen. Mit Annotations geht das beispielsweise so:

@Column(columnDefinition="TINYINT(1)")
private boolean disabled;

Zum Nachlesen: Der Bugreport HH-468 von Hibernate über diesen Fehler.

jQuery 1.3.x ist wesentlich schneller als 1.2.x

Die 1.3er Version von jQuery ist, zumindest unter OS-X mit Firefox, wesentlich schneller als die Vorgänger-Version 1.2. Kurz nach dem Laden einer HTML-Seite entsteht nun nicht mehr diese ärgerliche Rechenpause bei der der Browser kurz hing. Ein Upgrade lohnt sich.

Doppeltes Formular-Absenden in Spring-MVC verhindern

Jeder, der Web-Anwendungen erstellt oder betreibt, kennt es. Wenn ein Web-Formular nach 2 Sekunden noch nicht verarbeitet ist, klickt der Benutzer gerne ein weiteres mal auf den „Senden“-Button und erzeugt so einen weiteren Request. Da HTTP asynchron und verbindungslos ist, ist es gar nicht so einfach eine solche doppelte Formularversendung zu erkennen.

Session synchronisieren und Session-Form aktivieren

Im Spring-MVC lassen sich Formular-Requests bezüglich der Session synchronisieren. Dazu setzen wir das Controller-Attribut „synchronizeOnSession“ auf true. Es wird so verhindert, dass ein Formular nebenläufig verarbeitet wird.

setSynchronizeOnSession(true);

Ausserdem wird ein weiteres Controller-Attribut, und zwar „sessionForm“ auf true gesetzt, was Spring MVC dazu veranlasst, die Formulardaten in der Session zu speichern und, falls ein Formular doppelt abgesendet wurde, die Methode „handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response)“ aufzurufen.

setSessionForm(true);

Falls jetzt ein Formular doppelt versendet wird, oder falls ein Benutzer ein Formular mit dem „zurück“-Button erneut anzeigen und absenden möchte, wird also nun „handleInvalidSubmit“ aufgerufen. Diese Methode lässt sich in unserem Controller überschreiben, um so zu bestimmen, wie sich der Controller im Falle einer doppelten Datensendung verhalten soll.

@Override
protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception
{
    return new ModelAndView(getSuccessView()); // einfach weiter, da das Formular ja schon abgeschickt wurde
} 

Es muss übrigens nicht immer richtig sein, doppelte Formularversendungen zu verbieten. Wenn wir beispielsweise ein Suchformular erstellen, kann es sinnvoll sein, dem Nutzer zu erlauben, mit der Browser-Navigation zurück zum Formular zu gehen und eine Suche erneut abzuschicken.

Siehe hierzu auch: Doppeltes Formular-Absenden mit jQuery verhindern

Doppeltes Formular-Absenden mit jQuery verhindern

Mit Javascript kann man verhindern, dass der „Senden“ Button in Web-Formularen doppelt geklickt wird. Wir setzen ihn dazu automatisch auf „disabled“, wenn das Formular gesendet wurde. In jQuery sieht das etwas so aus:

$("#myForm").submit( function(){ $("#submitButton").attr("disabled", "true"); } );

Zur jQuery-Dokumentation von Events/submit

Der Befehl „cp -r *“ kopiert keine versteckten Dateien

Wenn man mit beispielsweise

cp -r * /zu/diesem/verzeichnis/

den Inhalt eines Verzeichnisses in ein anderes kopieren will, so werden keine versteckten Dateien kopiert. Der bash-Wildcard ‚*‘ gilt nämlich nicht für versteckte Dateien, also Dateien, die mit einem Punkt anfangen, wie z.B. „.htaccess“. Mit

cp -r * .[!.]* /zu/diesem/verzeichnis/

kopiert man auch die versteckten Dateien.

  • * kopiert „normale“ Dateien
  • .[!.]* kopiert Dateien, die mit einem ‚.‘ beginnen, ohne das übergeordnete Verzeichnis ‚..‘ zu kopieren

Siehe hierzu auch: Bash Wildcards