Memo an mich selbst #1

Lieber Sascha,

  1. Versuche nicht, eine Zend_Mail ohne addTo zu senden #pfui #böse
  2. setFrom ist bei Zend_Mail wirklich sinnvoll zu setzen #thumbsup
  3. jQuery.post result data auf größer-gleich 1 prüfen, nicht auf größer 0 #uiuiui
  4. Zend_Mail->send schmiert ab, wenn die Adressen ein ( oder ) enthalten #pfuipfui
  5. Lobet den Debugger im Zend Studio #thumbsupupup
  6. Preiset Firebug #findeKeinGeeignetesTag
  7. Lade die geänderte config-Datei auch hoch, du Depp! #facepalm

Ansonsten alles Spaghetti…
Schönen Abend noch…

Achtung: Newsletter-Problem

Quizfrage: Wie speichere ich folgendes, zugegebenermaßen sehr komplexe und nicht grad oft vorkommende Szenario in einer MySQL-Datenbank ab:

Es soll gespeichert werden, ob ein Nutzer zustimmt, einen Newsletter zu bekommen oder nicht

Ja, ich weiß, realitätsfern und Spezialanwendung, akademischer Aspekt und und und. Schon klar, aber als Denksportaufgabe für angehende Doktoren in Theopraktischer-Quanteninformatik bestimmt ein netter Tagesfüller.

Ein möglicher Ansatz – nochmal: wir reden hier über wirklich experimentelle Ansätze, die noch nie ein Mensch zuvor … usw, also weiter – also ein möglich Ansatz wäre folgender:

Man benutze ein Feld vom Typ varchar. Varchar, weil man nie weiß, ob sich evtl. mal die Anforderung ändern könnte. Stichwort hierbei: Skalierbarkeit! Denn wie schnell ändert sich so eine Anforderung und sollte man dann den falschen Datentypen ausgewählt haben (weil man natürlich mal wieder mit primitiven Ansätzen fern jeder akademischen Laufbahn daran gegangen ist und dachte, man könnte als Laie ein derart komplexes System auch nur im Ansatz verstehen), dann, ja dann dampft die Kacke! Also, varchar.

Und auch die Größe des varchar soll und muss disktutiert werden. Ein sicherlich guter Ansatz wäre, das Feld auf 255 Zeichen zu begrenzen – im Spezialfall kann das natürlich noch nach oben korrigiert werden, was aber wieder zu lasten der Konfiguration der Seitlichen Ausrichtung gehen kann und wird und nicht sollte.

Den Verschiedenen Zuständen geben wir die folgenden Namen: ‚active‘ beschreibt den Zustand des „wollenden Empfängers“ (genaue Definition erfolgt in einer Subklasse) und ‚inactive‘ den des dazu konträhren Zustandes. Für alle anderen wählen wir “ als den wohlbekannten Universaloperator auf der Menge der möglichen Zustände über „Ja“ und „Nein“ (präziser wäre ein oder, was aber im allgemeinen Sprachgebrauch eher verwirrt war und nicht mehr an seinen Platz fand. Das und war so nett und sprang kurzfristig ein.).

Wie man nun sieht, kann man selbst komplexe Vorgänge be- und verarbeiten, wenn man nur ruhig und logisch an die Sache heran geht und die Aufgaben in kleinen Abschnitten betrachtet (ist auch viel einfacher, eine Lupe zu benutzen anstelle eines Verkleinerungsglasses.).

Der Vollständigkeit halber sei noch folgender Zwischenruf erwähnt, der einen Eklat innerhalb des Beratungsgremiums hervorrief, als ein hochnäsig-arronanter Programmierer in geistiger Verwirrung den Satz ausrief:

Man benutzt ein (tiny)int-Feld und 0 und 1 zum speichern der Zustände Nein und Ja!

Unvorstellbar, wie dumm doch manche sind…

webEdition kann nicht gestartet werden. session.save_path = “

Aufruf des webEdition Login Fentsers und … *boom* Eine Fehlermeldung, aber was für eine:

WebEdition kann nicht gestartet werden: 0 – Die Variable session.save_path zeigt auf “. Dieses Verzeichnis gibt es nicht auf Ihrem Server!

*puh* Kramwühlsuch, warum, wieso, weshalb, ich hab doch nix verändert…*kopfkratz*

Nach langer Suche kontaktiere ich den Support meines Hosters, der löst das Problem in Sekunden:

In der Datei „/webEdition/we/include/conf/we_conf.inc.php“ muss ein Eintrag geändert werden, von

// Domain or IP address of the database server
define("DB_HOST","localhost");

auf diesen Wert

// Domain or IP address of the database server
define("DB_HOST","127.0.0.1:3306");

Aussage des Support-Mitarbeiters zu meiner Frage „Warum funktioniert das nicht mir localhost?“

Der Zugriff auf localhost ist aus Sicherheitsgründen deaktiviert!

Schön und gut, aber warum sagt die Fehlermeldung was über session.save_path?

Ganz einfach: webEdition versucht auf die Datenbank zuzugreifen, aufgrund der Blockade von localhost scheitert diese Verbindung. Allerdings gibt es dazu keine Rückmeldung, webEdition macht einfach weiter und liest die Konfigurationsdaten aus (zumindest versucht webEdition, dass zu machen). Unter diesen vielen Konf.-Daten ist auch die session.save_path, diese wird mit “ initialisiert. Da nun der Zugriff fehlschlägt, bleibt der Wert “ erhalten und nun prüft webEdition irgendwann, ob das Verzeichnis für die Sessions überhaupt vorhanden ist. Da dies nicht der Fall ist kommt o.a. Fehlermeldung – die natürlich völlig falsch ist.

Also, liebe webEdition-Leute: Bitte das ganze mal überprüfen, denn mit _dieser_ Meldung konnte ich nix anfangen. Ein Hinweis von wegen „Konnte die DB nicht öffnen, Fehlercode xyz“ wäre da um Längen besser gewesen.

jQuery Datepicker in Deutsch

jQuery’s Datepicker ist eine tolle Sache, leider funktioniert das ganze für deutsche Sprache nicht wie in der Doku beschrieben.

Allerdings habe ich in Dennis Blog einen super Eintrag entdeckt, wie es doch geht. Ein paar kleine Umformatierungen, da ich bei mit sowohl jQuery wie auch mootools einsetze und das ganze kann losgehen.


jQuery(function(jQuery)
{
jQuery.datepicker.regional['de'] = {clearText: 'löschen', clearStatus: 'aktuelles Datum löschen',
closeText: 'schließen', closeStatus: 'ohne Änderungen schließen',
prevText: ' nextText: 'Vor>', nextStatus: 'nächsten Monat zeigen',
currentText: 'heute', currentStatus: '',
monthNames: ['Januar','Februar','März','April','Mai','Juni',
'Juli','August','September','Oktober','November','Dezember'],
monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
'Jul','Aug','Sep','Okt','Nov','Dez'],
monthStatus: 'anderen Monat anzeigen', yearStatus: 'anderes Jahr anzeigen',
weekHeader: 'Wo', weekStatus: 'Woche des Monats',
dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayStatus: 'Setze DD als ersten Wochentag', dateStatus: 'Wähle D, M d',
dateFormat: 'dd.mm.yy', firstDay: 1,
initStatus: 'Wähle ein Datum', isRTL: false};
jQuery.datepicker.setDefaults(jQuery.datepicker.regional['de']);
});

Den Code bindet ihr einfach in euer JavaScript ein und ruft euren Datepicker ganz normal nun in Deutsch auf.

Viel Erfolg…

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 😉