Archiv der Kategorie: PHP

Benutzereingaben prüfen: Leere Strings

Ich kenne viele Wege, einen String daraufhin zu prüfen, ob der User

a) überhaupt was eingegeben hat und
b) ob der User außer Leerzeichen was eingegeben hat.

In jeder Sprache gibt es dafür viele Wege, einige gut, viele nicht so gut.

Heute mal ein Beispiel aus der Reihe “not so good”:

if

(strlen($tls_description) > 1 && substr_count($tls_description,“ „) >= (strlen($tls_description) – substr_count($tls_description,“ „)))
{
   $err = true;
}

Mein Ansatz, genauso gut, dafür lesbar und ebenso “effektiv”:

if

(strlen(trim($tls_description))<1)
{
   $err = true;
}

Nicht nur schneller, sondern auch lesbarer und nicht so WTF?

return-path bei php mail() erzwingen

Bei machen Webhostern kann es sein, dass die sendmail Konfiguration einen header Eintrag in der Form von

$header .= „Reply-To: test@example.com\n“;

einfach nicht akzeptiert (Nein, es liegt nicht am fehlenden \r, soviel sei gesagt).

Ursache hierfür ist die Einstellung von sendmail, die solche Einträge mit den eigenen Einträgen überschreibt und heraus kommt dann sowas:

Reply-To: meinpc@localhost

Das ist natürlich Müll.

Allerdings kann man diesen Parameter mit der 5ten Option von PHP’s mail() überschreiben. Dazu fügt man am Ende den ‘-f’ Paramater für sendmail an, das Ganze sieht dann so aus:

mail($zieladresse,$subject,$body,$header,” –f test@example.com”);

Somit wird der Mail der gewünschte return-path verpasst.

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 😉

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 …

SQL-Injection sichere MySQL-Query Funktion

Immer wieder ein Thema: SQL-Injections in Webseiten. Nicht zuletzt, seit es immer mehr große Zeitschriften sich zum Thema machen, das Prinzip ‚Wie führe ich eine SQL-Injection durch‘ auch für die ganz … naja, sagen wir mal lernfaulen … auf zu schreiben, wird das Thema doch immer beliebter.

Deshalb stelle ich nun mal – im kleinen Rahmen natürlich – meine Funktion vor, mit deren Hilfe es mir gelang, meine Projekte bis dato SQL-Injection safe laufen zu lassen.

Die Funktion, wie ich sie hier vorstelle, ist nur ein Auszug aus der echten Funktion. Die Funktion selbst liegt bei mir auch innerhalb einer Klasse. Abgerundet mit vielen Features – wie z.B. logging der SQL-Strings, logging der Dauer einzelner und aller Abfragen usw., hat mir diese Klasse über die Jahre sehr gute Dienste geleistet, was eine schnelle, saubere und vor allem sichere Erstellung von Webprojekten angeht.

Okay, genug geschwafelt, hier der Code:

public function myquery()
{
   $args    = func_get_args();
   $query   = array_shift($args);
   $args    = array_map(‚mysql_real_escape_string‘, $args);
   // echo vsprintf($query, $args).“
\n“;
   return mysql_query(vsprintf($query, $args));
}
 

Der Experte sieht gleich, was hier passiert, allen anderen erkläre ich es gern. Die Funktion nimmt sich alle Argumente, benutzt das erste Argument als SQL-Query-String und alle folgenden als Argumente zu diesem String. Alle Argumente werden mit der Funktion mysql_real_escape_string behandelt, welche alle für mySQL gefährlichen Zeichen entsprechend ungefährlich macht (mal salopp ausgedrückt).

Dannach werden die Argumente mittels printf-Funktion in den Query gebracht und dann wird das ganze ausgeführt. Zurück bekommt ihr den Rückgabewert von mysql_query, mit dem ihr dann ganz normal weiterarbeiten könnt.

Ein Beispiel-Aufruf:

$sql = „SELECT userid FROM tblUser WHERE username=’%s‘ AND password=MD5(‚%s‘)“;
$_ressource = mysql_query_safe($sql,$_POST[„username“],$_POST[„password“]);

Hier wird – in einer sonst sehr gefährlichen Umgebung – die UserID nach einem Login anhand von Username und Passwort ermittelt, die der User eingegeben hat.

Die einzelnen Tags, also wann kommt ein %s, wann ein %u usw., das lest ihr am besten direkt bei der Funktion sprintf nach.

Verbesserungsvorschläge nehme ich natürlich gern entgegen.

Dynamischen Content mit jQuery an Events binden

Wow, was für ein komplizierter Titel, was?

Es geht um folgendes: Ich erstelle mit jQuery innerhalb eines Bereiches meiner Seite einen dynamischen Inhalt. Als Beispiel: Ich füge in einem Div ein paar Bilder ein, die ich via AJAX auf Knopfdruck lade.

HTML-Teil:

jQuery-Teil:

$(‚div#meinDiv‘).html(‚‚);

Diese Bilder sollen anschließend noch auf das Ereignis einen Klicks reagieren und dann einen neuen Dialog öffnen, wo es ein paar mehr Infos zu diesem Bild gibt … kann sich jeder was unter diesem Beispiel vorstellen? Okay!

Mein Problem war nun, dass ich mit einem simplen:

$(‚img.meineBilder‘).click(function()
{
console.log(‚*PING*‘);
});

Nicht an das gewünschte Ergebnis kam. Es geschah einfach gar nix 🙁

Nach langem stöbern im Netz nun endlich die Erlösung: Es geht doch, und zwar so (nachdem der dynamische Content eingefügt ist):
$(‚img.meineBilder‘).live(‚click‘, function()

{
console.log(‚*PING*‘);
});

Na also, geht doch …

json_encode wandelt Umlaute in null Werte um

Meine AJAX-Antwort enthält null-Daten. Nun, okay, nicht nur null-Daten, aber so ab und zu schon ein paar. Dumm nur, dass in der Abfrage, die hinter den Daten steht, eigentlich keine null-Reihen auftauchen; zumindest sehe ich an der passenden Stelle im phpMyAdmin sowas nicht. Woran liegt es nun?

Zum Ablauf meines AJAX-Requests:
1. Daten zum POST vorbereiten
2. Daten per jQuery.post zum Server POSTen
3. Daten werden auf dem Server verarbeitet, sprich, eine Abfrage an MySQL wird gestartet
4. Antwort wird per json_encode zurückgeschickt
5. Antwort wird per jQuery ausgewertet und angezeigt

Soweit, so gut. Nur in manchen Zeilen fehlen die Daten.
Okay, Firebug auf und den Request mal näher untersucht.
Meine POST Daten stimmen schon mal, also mal sehen, was der Server antwortet. Aha, in der Antwort liegen schon die null-Felder drin, also stimmt der php-Teil nicht.

Ein schnelles debug-printf auf dem Server kurz vor der Rückgabe zeigt mir an, dass die Abfrage und die Antwort stimmt. Na gut, dann habe ich den Fehler.

Die PHP-Funktion json_encode wandelt alle Strings mit Umlauten in null Daten um. In der Doku zu json_encode steht es ja auch:

Diese Funktion arbeitet nur mit UTF-8-kodierten Daten.

Ich muss also die Eingangsdaten der Funktion json_encode entsprechend UTF-8 konvertieren. Kein Problem, die Funktion utf8_encode hilft mir da weiter und siehe da: Nun funktioniert es wunderbar.

Wieder was gelernt.