Refactoring – Alter Code im neuen Kleid … nicht nur für PHP

Grade in einem Code gefunden, der Aufruf der Funktion ‘getSession()’. Und nun mal die Preisfrage an alle PHP-Pro’s: Wieviel Code davon muss wirklich sein?
Aber erstmal der Originalcode:

function getSession(){
  $akt_timestamp = getTimestamp();
  $ses_timestamp = $_SESSION[getSession_Timeout()];
  if($akt_timestamp > $ses_timestamp){
    return false;
  }
else{
    if($akt_timestamp < $ses_timestamp){
      return true;
    }
  }
}
function getTimestamp() {
  return time();
}
function getSession_Timeout(){ return „usrTimeout“; }

*wow* Das sind 3 Funktionen, die ineinandergreifen, was?
Und nun – nochmal – die Preisfrage: Wieviel Code davon muss sein?
Ich behaupte: Nicht so viel, wie oben steht.
Beweis? Ich refaktorisiere den Code oder neudenglisch: Ich mache refactoring! (Ich red’ da lieber deutsch, aber jeder wie er/sie will).
Betrachten wir die Anforderungen:

  • beim Aufruf der Funktion getSession() wird eine Rückgabe vom Typ Boolean erwartet, dies sollten wir beachten.
  • Vereinfacht wird das refactoring (hier finde ich das passend) dadurch, dass es keine Übergabeparameter an die Funktion gibt.

So, die Hülle der Funktion steht, nun zum Inhalt.
Was macht die Funktion eigentlich?

  • Sie legt eine lokale Variable an, in der die aktuelle Zeit gespeichert wird.
  • Sie legt eine lokale Variable an, in der ein Wert aus der aktuellen Session gespeichert wird.
  • Wenn die aktuelle Zeit größer ist als der Wert der Session, gibt die Funktion false zurück.
  • Ist die aktuelle Zeit kleiner als der Wert der Session, dann gibt die Funktion true zurück.
  • Hier schon der erste Fehler: Was ist, wenn beide Werte gleich sind? Dieser Fall wird nicht berücksichtigt.

Nun das refactoring:

  1. Die Funktion getTimestamp() wird in der Funktion getSession() durch den Aufruf von time() ersetzt, somit fällt diese Funktion weg.
  2. Die Funktion getSession_Timeout() wird in der Funktion getSession() durch die Rückgabe von getSession_Timeout() ersetzt, somit fällt auch diese Funktion weg.
  3. Ziel der Funktion ist es, ein true oder false bei o.a. Bedingungen zurückzugeben.

Während unseres Refactorings verbessern wir auch gleich die Funktion der Funktion (*g*) und legen auch gleich fest, was passieren soll:

  • Ist die aktuelle Zeit größer wie der Wert in der Session, dann gibt die Funktion true zurück, sonst false.

Klingt einfach? Ist es auch.
Verkürzt man nun sukzessive die if…else Schleife und bedenkt, dass man die beiden lokalen Variablen nicht braucht und ersetzt diese mit ihren Entsprechungen (time() und Session-Wert),  so erhält man folgende Funktion:

function getSession()
{
  return (time() < $_SESSION[‚usrTimeout‘]);
}

Kurz, knackig und präzise. Diese Funktion erfüllt alle Anforderungen (und übererfüllt sogar diese, in dem es die alte Funktion um den Bereich “Zeit ist gleich Sessionwert” erweitert).

Für meine Behauptung oben auf die Frage “Wieviel Code davon ist nötig” würde ich nun sagen: q.e.d.

So, das war ein kleiner Ausflug in die Welt des Refactoring.
Ich hoffe, ihr habt alle was gelernt …

HEREDOC in PHP – Kleine Einführung …

Muss man oft fremden Code in eine Seite einbinden und dies auch noch per JavaScript, so kommt es nicht selten vor, dass mensch den entsprechenden Code per E-Mail bekommt.

Ich rede hier von Fremdcode in der länge 6-60 Zeilen, so wie in etwa für Analyse-Javascripte oder sonstige, kleinere Sachen. Diese sollen dann meist über PHP in den HTML-Code eingebettet werden und meist auch exakt so, wie der Code vorgegeben wird (Stichwort Zeilenumbrüche).

Nun folgt der nächste Schritt, man öffnet das PHP-File und bereitet den Einbau vor. Oft sehe ich es bei Kollegen und Bekannten so:

  1. PHP-Datei öffnen.
  2. Fremdcode per Copy & Paste in den heimischen Editor bringen.
  3. Ein “echo” vorbereiten.
  4. Es folgt ein wildes getippe, damit alle Anführungszeichen entsprechend escaped werden.
  5. Hochladen
  6. zu 80%: Frust!

Frust! Der entsteht zu 80% am Ende der oft langen Phase des “coden” und “escapen”, weil am Ende vergessen wurde, den ganzen “echo’s” auch Zeilenumbrüche wie \n mitzugeben, damit nicht der ganze Code auf einer Zeile im Quelltext steht. Manche Analyse-Codes nehmen einem das mit falschem oder – schlimmstenfalls – keinem Tracking übel.

Nur, was tun? Das Stichwort dazu heißt: HEREDOC

Mit HEREDOC kann ich Fremdcode so in eine Variable oder an eine Ausgabe übergeben, dass der exakt so ausgegeben wird und das ist so einfach, dass ich auf jeden Fall schneller bin wie meine Kollegen – und dabei kann ich mich auch auf die Zeilenumbrüche verlassen.

HEREDOC funktioniert so:

$meinFremderInhalt = <<< MEINHEREDOC

Inhalt, Inhalt

Mehr Inhalt, kann auch Code sein

usw. , usf.

MEINHEREDOC;

Man nehme eine Variable und weise ihr mit Hilfe von <<< den Inhalt dessen zu, was der folgende HEREDOC-Delimiter enthält. Alles ab der Zeile unter MEINHEREDOC wird übernommen, Zeilenumbrüche, Einschübe usw.

Ein HEREDOC Bereich endet dann wieder mit dem exakten (!) HEREDOC Delimiter, den mensch auch oben benutzt plus einem abschließenden ; (nicht vergessen!).

Dannach kann mensch ganz einfach den Inhalt per

printf(‘%s’.”\n”,$meinFremderInhalt);

zum Beispiel in die Webseite ausgeben – inklusive Zeilenumbrüche.

Wie oft kommt string1 in string 2 vor? Kleine Hilfe …

Weil ich es nun schon oft gesehen habe, hier mal die kleine Anleitung zum Thema: „Wie zähle ich, wie oft string1 in string 2 vorhanden ist?“

Ich sehe fast täglich neue implementationen dazu, wobei sich die entsprechenden Programmierer des öfteres mal „einen abbrechen“, eine aufwändige Funktion zu erstellen, die dann aber doch an Kleinigkeiten scheitert (z.B. keine UFT-8 Unterstützung, nicht binary-safe, usw.).

Aber warum machen es sich die Leute so schwer?
Weil diese Leute die PHP-Funktion substr_count nicht kennen.

Ein Beispiel: Ihr wollt zählen, ob eine Zeichenkette in einem String vorkommt, dann geht das hiermit am schnellsten:

$string = "Hallo Welt, ich bin da, dein liebster elton!";
$suchstring = "elt";
if (substr_count($string,$suchstring) > 1)
{   
  // suchstring in string mindestens einmal vorhanden, macht was
}
else
{  
  // suchstring NICHT vorhanden
}

Gar nicht schwer, oder?

Darüberhinaus kann man auch einen offset angeben, sozusagen die Startposition, in unserem Beispiel oben ergibt das:

echo substr_count($string,$suchstring);
echo substr_count($string,$suchstring,12);

Ergebnis:
2
1

Der optionale vierte Parameter gibt die Suchlänge an, d.h.:

echo substr_count($string,$suchstring);
echo substr_count($string,$suchstring,12,3);

Ergebnis nun:
2
0

Die Funktion ist sehr schnell – in meinen Tests sogar schneller wie strpos – und läßt sich auch sehr einfach einsetzen; darüberhinaus ist substr_count binary-safe, d.h. es arbeitet auch mit UTF-8 usw.

Mein Tipp: spart euch Zeit und nerven, benutzt die Funktionen die schon da sind, erfindet nicht das Rad neu und werdet schneller produktiv…

strtolower auch für UTF-Sonderzeichen

Das Problem: Ein beliebiger String soll kleingeschrieben werden.

Unsere Funktion dazu:

$sMyString = strtolower(trim($sMyString));

Das funktionierte aber plötzlich für einen String nicht mehr, das große Ö blieb ein großes Ö, also debuggen und siehe da, im Zend Debugger stellt sich das Ö als Viereck dar –> Hinweis auf ein Somderzeichen. Es war auch wirklich kein ASCII-Ö, sondern ein UTF8-Ö (komm da erstmal drauf).

Die Lösung: Es wird die Multibyte-Variante von strtolower benutzt:

$sMyString = mb_strtolower(trim($sMyString));

Vorher allerdings drauf achten, dass euer Projekt auch wirklich UTF-8 geeignet ist.

Dazu

  • Datei als UTF-8 speichern
  • Charset UTF-8 einstellen
  • Die mysql-connect’s auf UFT-8 einstellen, dies geht so

// mysql_connect

mysql_query("SET character_set_results = 'utf8', character_set_client = 'utf8', character_set_connection = 'utf8', character_set_database = 'utf8', character_set_server = 'utf8'");

// query ausführen

Diesen Code nach dem mysql_connect und der ersten Abfrage ausführen, dann hat man alle Daten als UTF-8.

Ach ja, und natürlich auch die Datenbank-Tabellen in einem geeigneten Charset speichern 😉

Immatrikuliert

Es geht weiter, grade kam per Post meine Imatrikulationsbescheinigung. Ab April geht es dann mit 3 Modulen los.

Natürlich war dem ganzen auch gleich der Gebührenbescheid angehängt, was dann die Freude wieder etwas trübt.

Naja, ab April kann ich meine Gedanken dann auf “Mathematische Grundlagen”, “Einführung in die objektorientiere Programmierung” und “Datenstrukturen I” lenken.

Mit Putty per Doppelklick direkt zum Zielserver

Tja, wer kennt das nicht. Putty auf, richtige Verbindung raussuchen, Username eintippen, an das richtige Passwort erinnern und so weiter und so fort.

Wenn man, wie ich, mit vielen verschiedenen Servern arbeiten muss, wäre man ja über jede Erleichterung dankbar. Für Putty habe ich so eine Arbeitserleichterung nun gefunden.

Also, zunächst stellt man sich in Putty alles für den Server so ein, wie gewohnt, sprich, Serveradresse eingeben, Farben und Größe des Fenstern bestimmen und so weiter.

Nun gibt man dem ganzen einen netten Namen (in diesem Beispiel nennen wir den Rechner “Hades”).

Nun erstellt man sich (zum Beispiel auf dem Desktop) eine Verknüpfung Putty. Diese Verknüpfung editiert man nun und stellt (bei Windows) unter “Ziel” das ganze so ein.

C:\Programme\PUTTY\putty.exe -load „Hades“

Nun wird beim doppelklick schonmal der entsprechende Server ausgewählt und man kann direkt mit dem eintippen von Username und Passwort weitermachen.

Aber da Entwickler bekanntermnaßen ein recht faules optimierfreudiges Volk sind, kann man diesen Arbeitsaufwand auch noch minimieren.

Wir ergänzen das “Ziel” also noch um mindestens 2, maximal 3 Einträge, diese sind

  • ssh
  • l
  • pw

“ssh” gibt den Verbindungstypen vor, “l” den Usernamen und “pw” das Passwort. Die Optionen “l” und “pw” setzen einander voraus (“pw” allein geht nicht) und beide setzen die Option “ssh” vorraus (ohne die geht nix).

Also, wer sich mit Putty zu einem bestimmen Zielserver (zum Beispiel dem SVN oder CVS Server) verbinden will und dabei _nur_ das Passwort eintippen möchte, der schreibt sowas:

C:\Programme\PUTTY\putty.exe -load „Hades“ –ssh –l USERNAME

Den Usernamen müsst ihr schon richtig reinschreiben.

Soll die Verbindung sofort und komplett und ohne weitere Angaben aufgebaut werden, dann macht ihr das so:

C:\Programme\PUTTY\putty.exe -load „Colin (SVN)“ -ssh -l USERNAME -pw PASSWORD

Auch hier: Passwort und Username noch eintragen, dann kann es ganz leicht per Doppelklick losgehen.

Erleichtert einem wirklich etwas die Arbeit, auch wenn es sich empfiehlt, die “pw” Option nicht zu nutzen. Man spart sich das (r)aussuchen des richtigen Servers und den Usernamen, braucht also nur noch das Passwort.

Viel Spaß …

Java MySQL Tutorial

In Sachen Java und Datenbank bin ich ein totaler Neuling. Allerdings hält man sich ja gern fit in solchen Sachen und da wir hier firmenintern ein neues Desktop-Tool brauchen, bot sich Java an. Für mich die einzige Schwierigkeit: Die Verbindung von Java zur MySQL-Datenbank.

Lange habe ich gesucht, lange herumprobiert und getippt und gelesen und wieder getippt. Am Ende habe ich es dann geschafft, mit ganz einfachen Mitteln eine Verbindung herzustellen.

Die Anforderungen waren:

  • Connect zur MySQL Datenbank
  • Ausführen eines SELECT´s
  • Auswerten der Antwort
  • Schließen der Datenbank

Das ganze aber ohne Frameworks wie Hibernate oder sowas, sondern nur mit Bordmitteln, die Java mitliefert. Betrachtet man das Ergebnis, ist es doch sehr einfach, aber man muss es ja auch erstmal wissen. Ich will es euch nicht vorenthalten. Dazu habe ich mal eine Beispiel – Konsolen Anwendung mit NetBeans erstellt, der Code läßt sich aber problemlos in große Projekte übernehmen.

Schritt 0: Benötigte imports

Folgendes import wird benötigt

import java.sql.*;

Vor den ganzen Code setzt man noch folgende Merker:

Statement stmt;       
ResultSet rs;

Die Funktion von ResultSet und Statement erkläre ich später.

Schritt 1: Treiber einbinden

(Alles ab hier sollte in einen try…catch Block)
Den Treiber für MySQL muss man mit 2 Schritten einbinden, in Netbeans geht das ziemlich einfach.
a) Rechtsklick auf das Projekt, Properties, dann Libraries, dann bei „Compile“ und „Run“ die „MySQL JDBC Driver“ mit „Add Library“ auswählen und bestätigen.
b) Den Code

Class.forName("com.mysql.jdbc.Driver");

hinzufügen.

Schritt 2: Verbindung zur MySQL-Datenbank herstellen

Die Verbindung zur Datenbank wird wie folgt hergestellt


String url     = "jdbc:mysql://localhost:3306/meinDatenbankSchema";
Connection con = DriverManager.getConnection(url,"benutzername", "benutzerpasswort");
stmt = con.createStatement();

Zeile 1 definiert das Datenbankziel, Zeile 2 stellt die eigentliche Verbindung her. Nicht vergessen, die Daten für „meinDatenbankSchema„, „benutzername“ und „benutzerpasswort“ anzupassen.
Zeile 3 erzeugt ein sogenanntes „Statement“ Objekt, mit welchem wir Anfragen an die Datenbank stellen können (Querys).

Schritt 3: Querys zur Datenbank senden

SQL-Querys sendet man mit Hilfe des Statement-Objektes zur Datenbank und wertet das ganze mit dem ResultSet-Objekt wieder aus.
SELECT-Beispiel, absenden des SQL, return-typ ist ResultSet:

rs = stmt.executeQuery("SELECT vorname, nachname FROM users");

UPDATE-Beipiel, absenden des SQL, return-typ ist integer:

int anzahlZeilen = stmt.executeQuery("UPDATE users SET vorname = 'Harry' WHERE vorname='Larry' ");
Schritt 4: Auswerten eines SELECT Ergebnisses

Bei einer SELECT Anfrage bekommt man ein ResultSet Objekt zurück, dieses kann man wie folgt auswerten:

while (rs.next())       
{
    String  vorname = rs.getString("vorname");
    String  nachname = rs.getString("nachname");
    System.out.println("Vorname: "+vorname+" | Nachname: "+nachname);
}
Schritt 5: Auswerten eines UPDATE Ergebnisses

Einfach den integer auswerten, er gibt die Anzahl der sogenannten „betroffenen Zeilen“ an.

Schritt 6: Verbindung zur MySQL-Datenbank schließen

Geht ganz einfach und sollte in jedem Fall gemacht werden (im Gegensatz zu PHP, wo das leider noch ein kann ist, ist es bei Java ein muss).

con.close();

So, ich hoffe, ihr könnt damit was anfangen – im wahrsten Sinne des Wortes. Mir jedenfalls wird es sehr helfen, meine ersten Datenbankabhängigen Servlets, JSP’s oder Java-Anwendungen zu schreiben.

Offener Brief an das PHP-Journal

Hallo PHP-Journal Redaktion,

Gestern kam sie, die neue Ausgabe des PHP-Journal, das wir hier in unserer Firma abonniert haben. Ausgabe 6/2009, um genau zu sein.

Obwohl das PHP-Journal schon immer eine lustige Zeitung war, verschlug es uns gestern wirklich die Sprache.
Besonders die Kategorie “Know-how für PHP-Profis” hat es uns diesmal angetan und ist Auslöser dafür, dass die PHP-Journal von uns demnächst nicht mehr abonniert wird.

Kleines Beispiel? Okay, Seite 74 aufschlagen und den Blick mittig schweifen lassen, direkt über das Bild. Was steht da als Überschrift? Genau: “Javascript”. Drunter ein kleiner “Profi-Tipp”, wie man es denn schafft, mit Javascript ein Pop-Fenster “on-top” zu halten.

1. Kam bestimmt noch keiner drauf, das ganze im body Tag via “onBlur=self.focus();” zu machen.

2. Was hat so ein Tipp in einem PHP-Journal in der Rubrik “PHP-Profi-Tipps” zu suchen?

Kleinigkeit? Kann ja mal passieren?
Es kommt noch besser. Eine Seite weiter, die Tipps mit Namen “Verschlüsselung” und “Formulare”. Coole Namen, besonders der Punkt “Verschlüsselung” “Passwörter verschlüsseln” fiel uns in Auge.

Mal schnell rein lesen, was die da wohl für einen tollen, neuen, uns unbekannten Tipp haben, auf den wahrscheinlich bisher nur absolute PHP-Götter kamen und … *sprachlos*

*meeP* Was wir dann lasen, brachte zuerst Verwirrung (meinen die das ernst?), dann nochmal Verwirrung (hieß die Rubrik wirklich “PHP-Tipps für Profis”?), dann doch ein kleines Schmunzeln (evtl. verwechseln die das mit einem April-Scherz) bis hin zu kleiner Traurigkeit (ne, scheint so, als meinen die das ernst).

Es wäre ein “Profi-Tipp”, wenn man doch bitte unsichere Inhalte mit solchen Strukturen absichert:

    $pass= ‘abcde’;
    $sicher = md5($pass);
    echo $sicher;
?>

Mal abgesehen davon, dass dies garantiert kein “Profi”-Tipp ist (jeder halbwegs begabte Anfänger kennt MD5), ist MD5 bestimmt keine Methode mehr, die man als “sicher” kennzeichnen könnte. Liebes “Profi”-Team der PHP-Journal, sucht mal nach “MD5 Cracken” und lernt.

Okay, nächster “Profi”-Tipp: “Formulare” “Arrays betrachten”.

Cool, (lacht noch über die Sache mit dem md5), mal sehen, ob das auch wieder so lustig wird.

Und: Wider aller Erwartung wurden wir wieder fündig: Um Daten aus einem Array ansehen zu können, könnte man doch die Funktion

print_r($_POST);

benutzen (hier stellt diese alle POST Daten dar).

Auch hier der Hinweis: Was hat das bitteschön in der Profi-Ecke zu tun? Dies sollte jeder End-Anfänger schon wissen.Und wenn ich – als Autor – schon so einen Tipp in die “Profi”-Ecke stelle, dann sollte ich das ganze wenigstens auch in

 – Tags setzen, damit solch ein Profi – der solche Tipps noch nötig hat – das ganze auch noch auf im Browser lesen kann (weil solche “Profis” sicherlich noch nichts für die Konsole programmiert haben, wo diese Ausgabe dann wieder klar strukturiert und lesbar ist).

Versteht mich nicht falsch, die Tipps sind sicherlich ganz toll … für Newbies, Anfänger und Leute, die PHP grade erst kennengelernt oder noch nicht viel professionelles damit gemacht haben.

Mit “Know-how für PHP-Profis” hat das nichts mehr zu tun, denn Profis sollten das alles schon lange wissen und täglich umsetzen.

Liebe Redaktion der PHP-Journal: Uns reicht es nun und wir bestellen eure Zeitung ab. Wenn ihr irgendwann mal wirklich einen Profi-Tipp zustande bekommt, meldet euch doch bitte bei mir.

Auf Nimmerwiederlesen …