Archiv für den Monat: September 2010

phpinfo mit Parameter

Was mir persönlich bisher ziemlich unbekannt war, ist die Tatsache, dass man phpinfo auch mit Parametern aufrufen kann.

Ruft man einfach

phpinfo();

auf, dann erscheint ganz normal die Übersicht über alle Features des Webservers. Allerdings ist es ja oft so, dass man aus diesem ganzen Wust von Informationen nur einen ganz kleinen Teil benötigt, zum Beispiel die Servervariablen. Dazu benutzt man den (optionalen) Parameter $what (der heißt wirklich so).

Um nur die Servervariablen zu bekommen, ruft man die Funktion einfach mit der richtigen benannten Konstante auf:

phpinfo(INFO_VARIABLES);

Hier mal eine Übersicht über alle Konstanten mit eigenen Erklärungen, die „Originaltexte“ könnt ihr unten beim Quellenlink nachlesen:

  • INFO_GENERAL
    Informationen über das System, build-config, stream-filter, usw.
  • INFO_CREDITS
    Die Danksagungen. In meinem Zend Community Server ist der bereich bis auf die Überschrift leer.
  • INFO_CONFIGURATION
    Die Konfiguration des aktuellen Systems. safe_mode on oder off, error_log Verzeichnis usw. findet sich hier.
  • INFO_MODULES
    Die aktivierten Module des Servers. bz2 an? curl enabled? gd Unterstützung mit dabei? Alles hier.
  • INFO_ENVIRONMENT
    Die Umgebungsvariablen des Servers; userprofile, os, path, usw.
  • INFO_VARIABLES
    Quasi das ganze $_Server-Array nochmal im phpinfo-theme.
  • INFO_LICENSE
    Die PHP Lizenz.
  • INFO_ALL
    Zeigt alle oben angegebenen Parameter an, die gleiche Ausgabe, wie ohne Parameter.

sehr gut ist auch, dass man diese Parameter miteinander verknüpfen kann, um mehr, aber doch noch nicht alle Informationen zu bekommen:

phpinfo(INFO_MODULES + INFO_VARIABLES);

Somit erhält man nur 2 Bereiche, in denen man die Informationen heraussuchen kann, die man benötigt.

Quelle: http://de2.php.net/manual/de/function.phpinfo.php

PHP Filter vs. Zend Framework am Fall einer Mailadressprüfung

Eine Mailadresse prüfen, dass muss jeder Entwickler mal in seinem Code machen. Dass dabei eine Menge schief gehen kann, davon kann sicherlich jeder PHP-Programmierer ein Lied singen. Gemacht werden muss es aber, nur wie? Ich stelle die PHP eigene Funktion filter_var() gegen die Filterfunktion des Zend Frameworks und schaue mal, welche der beiden Lösungen denn „Praxistaugliche“ Antworten erzeugt.

Für die PHP eigenen Funktionen lasse ich filter_var mit Filteroption FILTER_VALIDATE_EMAIL antreten. Zur einfachen Übersicht baue ich eine Funktion „isEMailValid“. Diese soll bei korrekter Mailadresse true zurückliefern, ansonsten false; also eher trivial.


function isEMailValid($mail)
{
return (filter_var($mail, FILTER_VALIDATE_EMAIL) !== FALSE);
}

Für die Frameworks tritt das Zend Framework an und speziell dessen Zend_Validate_EmailAddress Klasse. Diese besitzt eine Funktion isValid, die das gleiche Verhalten zeigt wie unsere eigene „isEMailValid“ Funktion.

Als Beispiel gebe ich 4 ähnliche Mailadressen an, nur die erste ist eine „echte“ Mailadresse, bei allen anderen fehlt was bzw. ist ein Teil unvollständig. Sicherlich prüft das ganze nicht alle möglichen Fälle von Mailadressen ab, aber es zeigt einen (sinngemäßen) Fall, der mir Probleme bereitete und mich nun zum Wechsel von meiner „filter_var plus regex“-Methode zum ZendFramework bewegen konnte.


function isEMailValid($mail)
{
return (filter_var($mail, FILTER_VALIDATE_EMAIL) !== FALSE);
}

$mail1 = 'max.muster-mann@eine.beispieldomain.com';
$mail2 = 'max.muster-mann@com';
$mail3 = 'max.muster-mann eine.beispieldomain.com';
$mail4 = 'max.muster-manneine.beispieldomain.com';

printf('php-filter:'."\n");
var_dump(isEMailValid($mail1));
var_dump(isEMailValid($mail2));
var_dump(isEMailValid($mail3));
var_dump(isEMailValid($mail4));

printf('zend:'."\n");
require_once 'Zend/Validate.php';
require_once 'Zend/Validate/EmailAddress.php';
$mailvalidator = new Zend_Validate_EmailAddress();
var_dump($mailvalidator->isValid($mail1));
var_dump($mailvalidator->isValid($mail2));
var_dump($mailvalidator->isValid($mail3));
var_dump($mailvalidator->isValid($mail4));

Die Ausgabe:


php-filter:
bool(true)
bool(true)
bool(false)
bool(false)
zend:
bool(true)
bool(false)
bool(false)
bool(false)

Wie man sieht, die „normale“ filter_var() Funktion von PHP schlägt fehl und meldet die zweite Mailadresse als korrekt, was nicht richtig ist.

Allein das zeigt mir nun, dass ich mich auf die Ergebnisse der PHP eigenen Prüfung nicht verlassen kann. Ich werde das ganze weiterhin beobachten, allerdings wird das nächste Projekt dann Funktionen aus dem Zend Framework benutzen. Das schöne ist, dass ich nur einmal in meiner Prüfungsmethode meiner Validatorklasse die Prüfung ändern muss, damit Projektweit die „richtige“ Prüfung benutzt wird. OOP ist toll 😉

PHP-Version: 5.2.13

Nachtrag vom 24.09.2010

Die ersten 5 Kommentare brachten mich auf andere Wege und zu mehr „Erkentnis“ des ganzen. Danke an IchBinIch und SkaveRat für die Hinweise!

Nimmt man noch ein paar andere Abwandlungen der Mailadressen zeigt sich ein Bild, dass man erklären sollte, denn filter_var und Zend arbeiten anscheinend völlig unterschiedlich. Oder doch nicht?

Was soll man nun benutzen? filter_var oder doch die Zend-Funktionen?

Die Antwortet lautet: Es kommt drauf an!
Je nachdem, was man mit der Prüfung erreichen will, benötigt man entweder das eine oder das andere. Hier die beiden Möglichkeiten:

  • 1. Prüfung für den Mailversand!
    Der wohl häufigste Fall. Man möchte wissen, ob eine Mailadresse dazu taugt, etwas per SMTP dort auch hinsenden zu können (Zugangsdaten, Newsletter, …). Hier lautet die Antwort: Zend-Framework, denn das prüft, ob ein String eine versendbare Mailadresse nach RFC 5321 beinhaltet (siehe auch Kommentar 3 von SkaveRat).
  • 2. Prüfung, ob es ganz generell eine Mailadresse sein könnte!
    Hier ist die Antwort: filter_var, denn diese Funktion prüft die generelle Syntax des Strings, nicht dessen Nutzbarkeit. Dabei können auch Global-Parts wie ‚localhost‘ eingesetzt werden, allerdings werden auch Mailadressen wie ‚a@com‘ durchgelassen, da diese ja theoretisch auch Mailadressen sind.

Man sieht, dass es durchaus auf den Anwendungsfall ankommt, will man sich für eine Filterklasse entscheiden. Ich werde das auf jeden Fall bei der nächsten Prüfung berücksichtigen.

Relative URL’s im tinyMCE

Das Problem: Jedesmal wenn ich im tinyMCE-Editor eine URL angebe, wird diese in eine „bessere“ Form gebracht.

Beispiel: Eine URL der Art „/bilder/meinBild.png“ wird zu „../bilder/meinBild.png“.

Die Browserengines sind zwar so schlau, dass ganze auch wirklich Problem- und Warnungslos anzuzeigen, aber Suchmaschinen sind da schon pingeliger.

Die Lösung lautet, die Option „convert_urls“ in der Konfiguration des Editor auf „false“ zu setzen.

tinyMCE.init({
...
convert_urls : false,
...
});

Damit bleibt dann der Eintrag so, wie dieser in den Editor geschrieben wird.

2 Jahre Blogjubiläum

Heute ist Jubiläum: Mein Blog – dieses Blog – gibt es nun genau 2 Jahre. Zumindest ist das erste Posting so alt. Es handelt vom Suchfeld des Firefox und wie man damit direkt bei php.net nach Funktionen usw. suchen kann. Seitdem kamen zuerst nur sporadisch neue Beiträge und ich musste mich auch erstmal an das „neue“ Medium Blog gewöhnen.

Mittlerweile habe ich das ganze besser im Griff, poste auch ab und zu mal was interessantes und ich hoffe, das ein oder andere Posting konnte euch auch mal helfen.

Zukünftig möchte ich natürlich noch mehr posten, vor allen Dingen natürlich mehr Code-Sachen. Schauen wir mal, wer mich ein wenig kennt, der weiß, dass ich wirklich nicht viel Zeit habe. Aber ich versuche, nicht ungeduldig werden 😉

So, jetzt habe ich euch genug von eurem Zeug abgehalten; los, los, wieder zurück an die Arbeit 😉

Memo an mich selbst #2

@Sascha: Alter siehst du gestresst aus!
Pass auf, ich schreib es dir nochmal hin:

  • Klassenmethoden und -attribute sind die mit dem static!
  • foreach in Java ist das hier: for (String item: stringList) {…}
  • Nicht vergessen: Erst den Datentyp bestimmen, dort die speziellste Methode finden und erst dann (!) überschreiben!
  • Vergiss die Sache mit den Threads, dafür ist die Zeit zu eng.
  • Die Sache mit den Objektatributen bei generischen Klassen wird noch geklärt!
  • Und noch ganz wichtig: Die Klausur ist am Samstag von 10-13 Uhr in Bochum!

Danke an mich selbst 😉

Mehrere MySQL-Tabellen mit ähnlichen Inhalten in einer Abfrage

Mehrere MySQL-Tabellen mit ähnlichen Inhalten in einer Abfrage abhandeln und das ganze dann auch noch am besten mit dem gleichen Code durchlaufen, obwohl in den Tabellen zwar ähnliche, aber nicht gleiche Daten stehen? Dazu noch eine Art „Flag“, dass man weiß, in welcher Zeile ein Ergebnis aus Tabelle1 und in welcher es aus Tabelle2 kommt? Kein Problem…

Sicherlich, man könnte nun die Tabellen einzeln abfragen und ebenso einzeln abhandeln, aber, hej, das kann jeder, wir, WIR, können das besser. WIR benutzen dazu nicht 2 oder x Abfragen, nur um hinterher zu sehen, dass wir alle Felder gleich behandeln, bis auf eins. WIR machen dann sowas wie hier 😉

Die Vorrausetzungen nochmal:

  • Ich brauche x Felder aus der Datenbank aus Y Tabellen.
  • Von diesen x Feldern sind x-1 Felder gleich, auch im späteren Code werden x-1 Felder völlig gleich abgearbeitet.
  • Die Spaltennamen in der Datenbank sind für diese X Felder nicht gleich, die Inhalte bzw. deren Signatur bzw. deren Datentypen aber schon.
  • Ich normalisiere die x Spalten aus den y Tabellen
  • Ich verkette diese y Tabellen miteinander nacheinander.

Zauberwort hierbei heißt „normalisieren“ und „verketten“. Zuerst funktioniert das ganze nur dann, wenn man zum einen die gleiche Anzahl Spalten hat und zum anderen die Spalten selbst auch den gleichen Typ und den gleichen Namen besitzen.

Gleiche Anzahl und (Daten)Typ, dass müsst _ihr_ sicherstellen; beim Namen kann man ja mit dem Zauberwort AS etwas „tricksen“ 😉

Trickreich wird es allerdings beim Punkt „wissen, aus welcher Tabelle das ganze kommt“, denn evtl. möchte oder muss man ja doch in der späteren Verarbeitung das eine oder andere Feld entsprechend unterschiedlich behandeln. Dazu gibt es diesen kleinen „Trick“. Man legt einen Spaltennamen für die Spalte fest, in der die Unterscheidung stattfinden soll und schreibt dann in Klammern und Hochkommata einen Bezeichner davor. Der Bezeichner gibt an, was in der Zeile steht.

Beispiel: tabelle1 enthält Produktdaten, tabelle2 die Kategorien, wir wollen u.a. die Produktnamen und die Kategorienamen auslesen und auch wissen, was wir nun haben. Als verkettung benutzen wir UNION bzw. UNION ALL. Die Unterscheidungsspalte nenne ich „herkunft“:

SELECT produkt_name AS name, ("tabelle1")herkunft, ...
FROM tabelle1
UNION ALL
SELECT kategorie_name AS name, ("tabelle2")herkunft, ...
FROM tabelle2
ORDER BY irgendwas

Das Ergebnis sieht dann in etwa so aus:

name herkunft
produkt 1 tabelle1
kategorie 1 tabelle2
kategorie 2 tabelle2
produkt 2 tabelle1
produkt 3 tabelle1
usw. usw.

Nun sehe ich sehr schön, woher die Daten stammen und kann somit die kleinen Unterschiede mittels einer Kondition in die richtigen Bahnen lenken.

Ich hoffe, ich konnte dem ein oder anderen helfen…