Archiv der Kategorie: PHP

Achtung: boolean filtern mit filter_var()

Wer seine Eingaben prüfen will, kommt um Filter nicht mehr rum. Ganz rudimentär und ohne „externe“ Frameworks kommt man aus, wenn man filter_var() benutzt.
Doch Achtung: Eine Validierung auf boolean in diesem Stil geht schief, denn:

filter_var('1', FILTER_VALIDATE_BOOLEAN);
filter_var('0', FILTER_VALIDATE_BOOLEAN);
filter_var('abc', FILTER_VALIDATE_BOOLEAN);

Folgende Ergebnisse:

1 -> true
2 -> false
3 -> false

Die ersten beiden Fälle sind richtig – obwohl man bei Zeile 2 auch ein true erwarten dürfte, denn die 0 ist ein boolean-Wert und damit könnte die Prüfung auch true sein, wenn man mit der Absicht prüft, ob es denn überhaupt ein boolean-Wert ist oder nicht, nicht welcher boolean-Wert vorliegt. Das klärt sich aber gleich – , der dritte Fall ist nicht gewollt oder nach der o.a. Logik ist diese Zeile richtig und Zeile 2 falsch, je nach Ansicht.

Klar ist aber jedem, dass man damit nicht arbeiten kann. Für ein Ergebnis, mit dem man arbeiten kann, muss man eine Option in filter_var() mit dem dritten Parameter setzen.

filter_var('1', FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE);
filter_var('0', FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE);
filter_var('abc', FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE);

Ergebnisse nun:

1 -> true
2 -> false
3 -> null

Und damit kann man nun sehr gut arbeiten…

funktionen vs konstanten ; echo vs printf

Gleich zwei Sachen in einem. Ich muss oft an alten Code. Mal muss ich dort eine neue Funktion implementieren, mal ein Bugfix durchführen, usw. usw. Kennen viele von euch. Derzeit muss ich an alten Code, um ein altes Projekt mit vielen neuen Features auszustatten.

„Dabei könnte ich doch gleich mal an der Performace-Schraube drehen…“

…denke ich mir so und nachdem ich viele offensichtliche Bremsen entfernt habe wende ich mich dem Profiling-Report aus dem Zend Studio zu. Nach einiger Zeit kommt in mir eine interessante Frage auf. Da im Code an vielen Stellen solche Konstrukte verwendet werden:

Datei1.php


function getDBName() { return 'meinDBName'; }

Datei2.php


$dbName = getDBName();

Ich denke mir intuitiv: Konstanten wären schneller, aber solch eine Vermutung ist schnell geäußert – Beweise müssen her. Und da ich schon dabei bin und das Projekt noch eins von den echo-HTML Projekten ist (habe ich erwähnt, dass es schon älter ist?), kommt gleich die nächste Frage: echo oder printf?

Meine Vermutung: Aufrufe von Konstanten und die Verwendung von printf ist die schnellste Variante!

Hier also mein Test-Code:


$rounds=999;
function getStringOne() { return 'Hallo'; }
function getStringTwo() { return 'Welt'; }
define("StringONE", 'Hallo');
define("StringTWO", 'Welt');

$start=microtime(1);
for ($i=0;$i<$rounds;$i++)
echo getStringOne() . ' ' . getStringTwo() . " - ";
$endFunction1=microtime(1);

for ($i=0;$i<$rounds;$i++)
printf('%s %s - ',getStringOne(),getStringTwo());
$endFunction2=microtime(1);

for ($i=0;$i<$rounds;$i++)
echo StringONE . ' ' . StringTWO . " - ";
$endConstant1=microtime(1);

for ($i=0;$i<$rounds;$i++)
printf('%s %s - ',StringONE,StringTWO);
$endConstant2=microtime(1);

printf("Rounds: %u\n",$rounds);
printf("Funktion echo: %f\n",($endFunction1-$start));
printf("Funktion printf: %f\n",($endFunction2-$endFunction1));
printf("Konstanten echo: %f\n",($endConstant1-$endFunction2));
printf("Konstanten printf: %f\n",($endConstant2-$endConstant1));
exit;

Und das Ergebnis:


Funktion echo: 0.025293
Funktion printf: 0.024530
Konstanten echo: 0.017224
Konstanten printf: 0.017751

Meine erste Vermutung – Konstanten sind schneller als Funktionen – hat sich bewahrheitet; meine zweite Vermutung – printf ist schneller als echo – nur zum Teil. Ich bekomme da zum Teil Ergebnisse nach dem Motto "e;Mal so, mal so"e; und kann das nun an diesem Code nicht eindeutig beantworten. In einer Variante habe ich die Rundenzahl auf 99.999 erhöht und in diesem Test waren alle Aufrufe mit printf langsamer als die echo-Varianten, allerdings nicht wirklich signifikant.

Die Frage echo oder printf ist wohl eher eine Geschmacksfrage; für mich im aktuellen Projekt heißt das: Die echo’s können bleiben, es bringt mehr, meine Zeit auf die „Entfunktionalisierung“ zu verwenden.

Füllen von array-Werten in Reihenfolge: for vs range

Will man ein Array mit Werten füllen, die in einer Reihenfolge stehen (a-x, 1-20, usw.), dann gibt es dazu die Funktion “range”, aufruf mit

$reihenfolge = range(1,20);

Dabei erhält man ein Array mit Werten von 1 – 20.
Die alternative ist, das ganze “manuell” zu erledigen, sprich in unserem Beispiel 1-20 wäre das:

$reihenfolge=array();
for ($i=1;$i<=20;$i++)
array_push($reihenfolge,$i);

Meine ursprüngliche Fassung war Nummer 2 bis ich auf die Funktion “range” stieß. Und die muss ich natürlich gleich ausprobieren und Performance-Tests machen. “Muss doch mit einer PHP-Funktion schneller sein wie mein kindlich-naiver Ansatz!”, denke ich mir so, denn eine Zeile gegen 3 Zeilen, dazu noch von PHP-Spezialisten verfasst und – wahrscheinlich – optimiert bis zum maximal Möglichen, dass _muss_ doch schneller gehen!
Aber was ist nun schneller, range oder for?
Meine Tests habe ich mit dem Zend Studio vorgenommen, hier das Durchschnittliche Ergebnis von vielen Messungen:

range
for
1-20
0.047ms
0,006ms

Hätte ich persönlich nicht vermutet, aber meine Kindlicher Ansatz ist wirklich schneller und zwar im Durchschnitt 7x schneller.

[UPDATE 28.06.2010]

Danke an Daniel und seine „Nachuntersuchung“ meines Artikels, dabei habe ich noch einen Fehler in meiner Auswertung gefunden, der mich wirklich zu meinem gezeigten Ergebnis bringt.

Zur Überprüfung habe ich nochmal einen eigenen Code geschrieben, der range, array_push und [] überprüft und aufzeit: range ist wirklich um ein vielfaches schneller wie die beiden anderen Methoden! Daniel, du hast ja recht 😉

Hier mal der Testcode:


$anzahl_der_werte = 99999;

$start1=microtime(1);
$stack1=array();
for ($i=1;$i<=$anzahl_der_werte;$i++)
array_push($stack1,$i);
$ende1=microtime(1);

$stack2=range(1,$anzahl_der_werte,1);
$ende2=microtime(1);

$stack3=array();
for ($i=1;$i<=$anzahl_der_werte;$i++)
$stack3[]=$i;
$ende3=microtime(1);

echo "Anzahl der Durchgaenge: " . $anzahl_der_werte . "\n";
echo "Zeit array_push: " . ($ende1-$start1) . "\n";
echo "Zeit range: " . ($ende2-$ende1) . "\n";
echo "Zeit []: " . ($ende3-$ende2) . "\n";
exit;

Und das Ergebnis:


Anzahl der Durchgaenge: 99999
Zeit array_push: 0.36060690879822
Zeit range: 0.013633966445923
Zeit []: 0.33861804008484

Man sieht also sehr gut, dass range wirklich schneller ist, das ganze hält sich auch bei kleinen und großen Werten, man muss sich also nur merken, dass man bei sowas range nimmt.

Algorithmus Wettbewerb: Meine Lösung

Eine super Idee hat Michael in seinem Blog: Eine Programmier-Aufgabe, die es wirklich in sich hat.

Die Aufgabe findet ihr unter dem Link, hier findet sich meine Lösung.

28.06.2010
Das ganze muss auch eine mathematische Lösbarkeit haben, hier mal meine bisherigen Überlegungen:
x = Anzahl der Spieler
p1 = Anzahl der möglichen Platzierungen ohne Partiedopplung (also ohne das ein Spieler mehrfach gegen einen anderen antritt), Brettdopplung nicht berücksichtigt:
p1 = (x²-x)/2 = Summe 1 bis (x-1)

Memo an mich: Mehrfach-Matrix mit Substitution erstellen, Speicherbedarf testen!

24.06.2010

Erste Lösung, nicht hochperformant, aber funktioniert.
Die echo „.“ Angaben und die variable $neustarts sind nur für mich und könnten in einer finalen Fassung entfernt werden

$startzeit = microtime(1);
if ($_SERVER['argv'][1]%2!=0)
die("Nur gerade Eingaben!\n");
$spieler = $_SERVER['argv'][1];
//$spieler = 8;
$bretter = $spieler/2;
$spielplan = array();
$neustarts=0;
$abbruch = $spieler ^ 3;
for ($runde=1; $runde<=$bretter; $runde++)
{
$rundensatz = -1;
$count = 0;
while ($rundensatz == -1)
{
$count++;
if ($count > $abbruch)
{
$count=0;
for ($x=1;$x<=($spieler/2);$x++)
$spielplan[$x] = null;
$runde=0;
$neustarts++;
echo "."; flush();
break;
}
$spielerstack = generiereSpielerStack($spieler);
$rundensatz = besetzeRunde($spielplan,$runde,$spielerstack);
}
if ($rundensatz==-1) continue;
$spielplan[$runde] = $rundensatz;
}

print_r($spielplan);

$endzeit=microtime(1);
printf("Spieler: %u\n",$spieler);
printf("Bretter/Runden: %u\n",$bretter);
echo 'Benoetigte Zeit: '.($endzeit-$startzeit).'s'."\n";
printf('Benoetigte Neustarts: %s',$neustarts);

exit;

function generiereSpielerStack($spieler)
{
$stack=array();
for ($i=1;$i<=$spieler;$i++)
array_push($stack,$i);
shuffle($stack);
return $stack;
}

function besetzeRunde($spielplan,$runde,$spielerstack)
{
$bretter = count($spielerstack)/2;
$aktuellerSpieler = array_shift($spielerstack);
while (count($spielerstack)>0 && is_numeric($aktuellerSpieler))
{
if ($brett>$bretter)
{
return -1;
}
for ($brett=1;$brett<=$bretter;$brett++)
{
$opp=0;
if (brettBesetzt($brett,$runde,$spielplan))
continue;

if (hatGespieltAufBrett($aktuellerSpieler,$brett,$spielplan))
continue;

if (is_numeric($spielplan[$runde][$brett][0])
&&
hatGespieltGegen($aktuellerSpieler,$spielplan[$runde][$brett][0],$spielplan))
continue;

if (is_numeric($spielplan[$runde][$brett][0]))
$opp=1;

$spielplan[$runde][$brett][$opp]=$aktuellerSpieler;
$aktuellerSpieler = array_shift($spielerstack);
if (is_null($aktuellerSpieler))
{
return $spielplan[$runde];
}
$brett=0;
}
}
if (is_numeric($aktuellerSpieler))
return -1;
else
return $spielplan[$runde];
}

function brettBesetzt($brett,$runde,$spielplan)
{
return (is_numeric($spielplan[$runde][$brett][0]) && is_numeric($spielplan[$runde][$brett][1]));
}

function hatGespieltGegen($spieler1, $spieler2, $spielplan)
{
for ($i=1;$i<=count($spielplan);$i++)
{
if ($spielplan[$i] == null)
return false;

for ($j=1;$j<=count($spielplan[$i]);$j++)
{
if ( ($spielplan[$i][$j][0] == $spieler1 && $spielplan[$i][$j][1] == $spieler2 )
||
($spielplan[$i][$j][0] == $spieler2 && $spielplan[$i][$j][1] == $spieler1 )
)
return true;
}
}
return false;
}

function hatGespieltAufBrett($spieler, $brett, $spielplan)
{
for ($i=1;$i<=count($spielplan);$i++)
{
if ($spielplan[$i] == null)
return false;

if ($spielplan[$i][$brett][0] == $spieler || $spielplan[$i][$brett][1] == $spieler )
return true;
}
return false;
}

Verbesserungsvorschläge überaus erwünscht 😉

RewriteRule nur für nicht vorhandene Dateien

… oder wie stelle dynamische Inhalte in statischen webEdition Seiten dar?

Die Apache RewriteRule kennt wohl jeder, der etwas mehr mit Webseiten macht. RewriteCond sollte auch bekannt sein, allerdings hatte ich bisher diese beiden Direktiven nicht in dieser Form miteinander verbunden.

Das Problem:

Ursächlich war, dass ich in webEdition Seiten dynamische Inhalte anzeigen wollte. Die Inhalte kommen von extern und somit wollte ich a) die Seite nur einmal bauen und b) einen Teil der Inhalte von ausßen dynamisch füllen (z.B. die neuesten Twitter-Feeds oder oder oder).

Nun merke ich schnell: Ist eine webEdition Seite einmal als “statisch” definiert, dann ist diese auch genau das: statisch. Es ist HTML, webEdition zieht alle Informationen die es braucht in dem Moment aus alles Quellen und schreibt eine .html-Seite. Mehr nicht. Aber genau das soll webEdition ja auch machen. Also kein Grund zum meckern … oder? Bedingt.

Ja, webEdition macht rein technisch alles richtig, nur will ich doch in einer Sidebar dynamische Inhalte haben 🙁

Okay, Seite auf “dynamisch” umstellen und dann: Lasse ich die Dateiendung auf .html, dann sehe ich nur PHP-Code.

Sicher, ich könnte nun die Dateiendung umstellen – auf .php funktioniert das ganze wie gewünscht – aber das ist weder Sinn der Übung, noch ist das gewünscht; Stichwort Kundenwunsch!

Lösungsvorschläge:

Also, hier der andere Weg: mod_rewrite.

Der einfachste Weg: Alles, was .php heißt in .html umleiten, aber Halt! Der erfahrende Mensch sieht: Das geht schief, denn es können durchaus .php Dateien auf dem Server liegen, die auch ausgeführt werden wollen.

Lösungsvorschlag 1:

AddHandler-Direktive nutzen.
Man könnte die AddHandler Direktive nutzen und allen .html-Code als PHP ausführen lassen. Bei statischen Seiten würde dies nur sehr geringen Zeitverlust bedeuten und es würden die .html-Seiten auch korrekt ausgeführt, die PHP-Code beinhalten (also unsere dynamischen webEdition Seiten).

Lösungsvorschlag 2:

Bedingtes Umleiten!
Funktioniert Lösung 1 nicht (warum auch immer) oder ist dieser Weg nicht gewünscht (der Kunde ist doch König), dann sollte man es so versuchen – und kommen damit wieder zur Überschrift zurück (was für ein Handlungsbogen).
Man leitet alle Anfragen auf .html-Seiten, die nicht existieren, auf .php-Seiten um, die exakt so heißen, wie die .php Version.

Schritt 1: Zuerst werden die webEdition-Seiten geparkt, als dynamisch markiert und dann als xyz.php gespeichert.

Schritt 2: In der .htaccess wird folgende neue RewriteCond mit folgender RewriteRule ergänzt … ich habe diese ganz ans Ende gepackt, kommt aber immer auf den individuellen Fall an:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\.html $1.php [L]

So werden nun nur die .html-Aufrufe an .php-Scripte übergeben, deren .html-Datei nicht real auf dem Dateisystem des Servers existiert.

Viel Erfolg…

webEdition kann PHP nur eingeschränkt

Das webEdition – CMS ist bekannt dafür, dass es einiges kann und viel Arbeit erzeugen kann. Dafür ist es u.a. möglich, beliebigen PHP Code in die Templates zu schreiben.

Dachte ich …

Allerdings kann webEdition PHP nur eingeschränkt, was ich am Beispiel eines Quellcodes verdeutlichen will. Ebenfalls soll hier eine Liste entstehen, was ich wann entdecke und wann es ggf. behoben wird.

  1. [28.05.2010] && und AND
    Die Verkettungsoperatoren && und AND sind ja für die “normale” Programmausführung relativ gleich (es wird eine UND-Verknüpfung erstellt), lediglich der Rang der Operator-Rangfolge ist anders (&& ist “(ge)wichtiger”).
    webEdition kennt AND überhaupt nicht, obwohl beide zum PHP-Sprachkern gehören.
    Bringt man nun in einem webEdition Template z.B. eine if-Abfrage mittels AND ein, so gibt webEdition für alles nach (!) dem ersten Ausdruck true zurück. Wählt man den ersten Ausdruck also etwas unglücklich, kommt im betreffenden if immer true zurück und somit wird Code ausgeführt, den man eigentlich erst unter bestimmten Bedingungen ausführen wollte.

Mal schauen, wann das webEdition Team das ganze behebt. Eine Rückmeldung an mich wäre toll, da ich das ganze nicht jeden Tag gegenprüfe.

POST Parameter in JavaScript benutzen

Nachdem der letzte Beitrag wohl etwas irreführend war, hier mal ein Bericht mit dem Ziel, POST Parameter in JavaScript zu benutzen.

Nachdem man ja GET-Parameter relativ leicht auslesen kann, will ich hier nur auf die POST-Parameter eingehen.

Zunächst einmal muss man beschreiben, was denn nun bei einem POST-Request passiert und warum man nicht einfach per JavaScript darauf zugreifen kann.

Ganz kurz: Per POST werden Daten vom Browser (Client) an den Webserver (Server) gesendet, wo diese dann ausgewertet werden können. Der Client “wartet” solange auf Antwort, bis der Server diese sendet. In der ganzen Zeit kann man mit “normalem” JavaScript nix anfangen, da der Client-Code ja noch gar nicht im Browser ist. Sendet der Server nun eine Antwort, so erhält der Browser einfach neue Parameter, ähnlich wie beim GET, nur sind die POST-Paramater nicht zugänglich, weil diese in dem Moment nirgendwo mehr gesetzt sind.
Soviel zur Basis.

“Und wie komme ich nun an die Parameter ran?”
Gute Frage und ebenso leicht zu beantworten. Den POST muss Serverseitig ja irgendeine Serverseitige Scriptsprache entgegennehmen (nehmen wir mal rein zufällig … ähm … PHP) und diese kann dann auf die Eingabe reagieren und eine neue Seite bauen.

Damit ich nun Clientseitig wieder die POST-Daten habe, muss ich mir von PHP aus die POST-Daten irgendwohin in die Antwort an den Browser schreiben, wo JavaScript auch was damit anfangen kann.

Beispiel, ein Kontaktformular (ganz simpel):

<form action="formular.php" method="POST">
<input name="meinname" type="text" />
<input name="senden" type="submit" value="absenden!" />
</form>

Wir möchten nun, nachdem das Formular abgesendet wurde, auf der Antwortseite eine alert-Box aufpoppen lassen, die “Danke, xyz” sagt (ist wirklich ein sehr einfaches Beispiel, oder?)

Okay, der Code für formular.php

<?php if (isset($_POST['meinname'])) { ?>
<script>
var derNameLautet = <?=$_POST['meinname']?>;
alert('Danke, ' + derNameLauetet);
</script>
<?php } ?>

So, nun wird, wenn ein POST vorliegt, der POST-Wert in eine JavaScript Variable geschrieben. Diese kann ich dann für vieles Benutzen, ich hoffe, das Prinzip ist klar.

Aber ich habe einen AJAX-POST, wie mache ich das denn da?
Noch einfacher, der AJAX-POST verlässt ja die Seite nicht, d.h. die Werte, die per POST gesendet wurden, liegen ja noch immer vor und können recht einfach weiterbenutzt werden.

So, diesmal sollte das ganze Prinzip klarer sein, warum ein Auslesen der POST-Variablen in JavaScript mittels

<script>
var meinePOSTVariable = POST[‘postVariable’];
</script>

schlicht nicht möglich ist.

Führungsnull in Excel aus CSV anzeigen

Viele kennen das Problem. Man hat eine CSV Datei, in dieser steht eine Postleitzahl oder eine Telefonnummer, die als erste Stelle eine 0 (Null) hat.

Öffnet man das nun in Excel, ist die Null weg.

Beispiel: Ein Kunde kommt aus Dresden, gibt als PLZ “01307” ein. Exportiert man das ganze dann als “kunden.csv” und doppelklickt es in Excel auf, so erscheint “1307”, was ja nicht ganz richtig ist. Excel ist einfach zu schlau…

Da wir aber klein, trotzig und unwürdig sind, möchten wir trotzdem die führende Null sehen; der Kunde übrigens auch. Da der Kunde König und Excel eh nur eingekauft ist, ist der Weg klar: Die Null muss her!

Wer lange sucht, der findet auch die tollsten Lösungswege. Nicht Excel muss sich an uns, vielmehr müssen wir uns an Excel anpassen; sprich: Nicht einfach per doppelklick öffnen, o nein, gefälligst per Import die Daten einholen und dann als Text formatieren.

Das kann es nicht sein, hier also der Weg des Programmierers!

Unser Vorteil ist, das Excel die Daten pro Spalte nicht nur importiert, sondern auch interpretiert, d.h. wir benutzen eine Funktion aus Excel, die dafür sorgt, dass die Daten korrekt dargestellt werden.

Diese heißt für unseren Zweck: VERKETTEN

Will man also diese Zeile richtig importieren:

“Max”;”01307”;”Dresden”

Dann muss man sowas schreiben:

“Max”;”=VERKETTEN(0;1;3;0;7)”;”Dresden”

Und da Programmierer erwiesenermaßen faul sind, werfe ich gleich mal eine PHP-Funktion dafür in die Runde. Die kann sicherlich noch optimiert werden, aber für’s erste genügt diese den Anforderungen:

function formatForExcel($text) 
{
   $excelText = '=VERKETTEN(';
   for($i=0; $i<strlen($text);$i++)
   {
     if ($i>0) {
       $excelText .= ';';
     }
     $excelText .= $text[$i];
   }   
   $excelText .= ')';
   return $excelText; 
}

Wird nun formatForExcel aufgerufen, dann werden die Daten entsprechend per “Verketten” abgelegt und dann in Excel richtig aufgerufen.

Mathematische Strings mit PHP auswerten

Wer immer einen mathematischen Ausdruck in einem String auswerten bzw. ausrechnen möchte, muss ein wenig in die Trickkiste von PHP greifen.

Aber mal langsam, wir beginnen mit der Aufgabe:

$mystring = „123*1.1“;

Der String selbst kommt von irgendwo z.B. aus einem Formular und soll einen Wert + 10% berechnen. Wie machen wir das in PHP? Ein einfaches

echo $mystring;

reicht da nicht aus.

Nach ein bischen suchen im Handbuch kam ich auf diese Lösung, nicht schön, aber es geht:

eval(‚$ergebnis = ‚.$mystring.‘;‘);
echo $ergebnis;

Auf das Ergebnis kann man nun bequem zurückgreifen.

Okay, hier fehlen noch ein paar Sicherheitsmechanismen (eval is evil), aber der Grundsatz sollte klar sein und solche Funktionen sind schnell nachgerüstet (siehe die Filter-Sektion im Handbuch).

Generell sollte man eval natürlich vermeiden, aber in speziellen Anwendungen – wie in diesem – kann es durchaus Sinn machen, die “böse” Funktion zu nutzen.

Ich bin schon mal froh, diese Funktion zu haben und will diese euch nicht vor enthalten.