PHP Template System
Hier mal ein Anfang für ein eigenes Template-System für PHP:
Ein Beispiel für die index.tpl:
[head.tpl]
<div id="content">
<p>your content here</p>
</div>
[footer.tpl]Die Dateien head.tpl und footer.tpl können weitere Template-Dateien enthalten. Es wird rekursiv geparst.
Der Aufruf:
echo new Template('index.tpl');
Die Klasse:
class Template { private $template; public function __construct($templateFile) { if (is_file($templateFile)) { $this->template = file_get_contents($templateFile); } else { die('Template File "'.$templateFile.'" not found.'); } } private function getModules($s) { preg_match_all( "/\[(.+?)\]/is", $s, $matches); return $matches[1]; } private function parse($tpl) { $modules = $this->getModules($tpl); if (count($modules)) { foreach ($modules as $mod) { if (is_file($mod)) { $tpl = str_replace('['.$mod.']',file_get_contents($mod), $tpl); $tpl = $this->parse($tpl); } } } return $tpl; } public function __toString() { return $this->parse($this->template); } }
Nach langem Suchen hier die korrekte Schreibweise für die Datei /config/database.yml :
all:
doctrine:
class: sfDoctrineDatabase
param:
dsn: 'mysql:dbname=hierDerDbName;host=localhost;unix_socket=/tmp/mysql5.sock;'
username: hierDerBenutzername
password: hierDasPasswortDie Kurzschreibweise “localhost:/tmp/mysql5.sock” wie bei 1&1 angegeben funktioniert an dieser Stelle nicht! Diese Schreibweise wird von den PHP Data Objects (PDO) nicht akzeptiert und erzeugt folgende Fehlermeldung:
PDO Connection Error: SQLSTATE[HY000] [2005] Unknown MySQL server host 'localhost:/tmp/mysql5.sock'
jScrollPane print-Stylesheet
JScrollPane ist ein jQuery Plugin von Kevin Luck:
http://www.kelvinluck.com/assets/jquery/jScrollPane/jScrollPane.html.
Folgenden Codeschnipsel für eine korrekte Druck-Ausgabe habe ich hier gefunden:
http://stackoverflow.com/questions/2570906/how-to-print-a-full-content-of-jscrollpane
div.jScrollPaneContainer { position: static !important; height: auto !important; overflow: visible !important; } div.jScrollPaneContainer > * { display: none !important; } div.scroll-pane { position: static !important; display: block !important; float: none !important; }
OpenDocument Dateien mit PHP ändern
Das erste was man wissen muss, wenn man OpenDocument Dateien bearbeiten will, ist dass es sich dabei um ein offenes Format handelt, welches aus einem ZIP Archiv mit vielen einzelnen Dateien besteht. Wie dieses Archiv aufgebaut ist, kann man hier nachlesen: http://de.wikipedia.org/wiki/OpenDocument
Nachdem man das Archiv also mit einem Programm seiner Wahl entpackt hat (z.B. mit 7-Zip: http://www.7-zip.org/), kann man die einzelnen Dateien ganz einfach mit PHP bearbeiten. Zur Unterstützung habe ich dafür eine kleine PHP-Klasse geschrieben (siehe weiter unten). Als Beispiel bearbeite ich hier mal eine odt-Datei aus OpenOffice Writer.
Der Platzhalter ###BEISPIEL###, den ich vorher mit OpenOffice an die entsprechende Stelle gesetzt habe soll hier durch den String “Hat geklappt” ersetzt werden:
<? include 'opendocument.class.php'; // klasse einbinden // Als erstes erstelle ich ein neues Odf - Objekt. Im Ordner 'beispiel' befinden sie die // unkomprimierten Dateien meiner OpenDocument-Text Datei $Odf = new opendocument('/www/beispiel/'); // Inhalt von content.xml einlesen: // (Hier steht der eigentliche Inhalt des Dokuments drin --> siehe wikipedia) $content = $Odf -> get_file('content.xml'); // Platzhalter ###beispiel### durch String 'Hat geklappt' ersetzen: $content = str_replace('###BEISPIEL###','Hat geklappt',$content); // Neuen Content "setzen": $Odf -> set_file($content,'content.xml'); // Header senden ($Odf->get_mime gibt den mime-Typ zurück): header("Content-type: ".$Odf->get_mime); header("Content-Disposition: attachment; filename=beispiel.odt"); // Manipuliertes Dokument ausgeben: echo $Odf -> output(); ?>
und hier die dazu benötigte Klasse:
<? class opendocument { /* * opendocument class * written by D.Lehmann (www.quirks-modus.de) * * zip file support based on 'zip.lib.php' of the phpMyAdmin project * official zip file format: http://www.pkware.com/documents/casestudies/APPNOTE.TXT * */ private $source; // dir of the unzipped opendocument file private $files = array(); // array to store changed files private $datasec = array(); // array to store compressed data private $ctrl_dir = array(); // central directory (zip-file) private $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; // end of central directory record (zip file) private $old_offset = 0; //last offset position (zip-file) private function unix2DosTime($unixtime = 0) { // converts an unix timestamp to a four byte DOS date and time format (date // in high two bytes, time in low two bytes allowing magnitude comparison). $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime); if ($timearray['year'] < 1980) { $timearray['year'] = 1980; $timearray['mon'] = 1; $timearray['mday'] = 1; $timearray['hours'] = 0; $timearray['minutes'] = 0; $timearray['seconds'] = 0; } return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); } private function zipAddFile($data, $name, $time = 0) { // adds "file" to archive $name = str_replace('\\', '/', $name); $dtime = dechex($this->unix2DosTime($time)); $hexdtime = '\x' . $dtime[6] . $dtime[7] . '\x' . $dtime[4] . $dtime[5] . '\x' . $dtime[2] . $dtime[3] . '\x' . $dtime[0] . $dtime[1]; eval('$hexdtime = "' . $hexdtime . '";'); $fr = "\x50\x4b\x03\x04"; $fr .= "\x14\x00"; // ver needed to extract $fr .= "\x00\x00"; // gen purpose bit flag $fr .= "\x08\x00"; // compression method $fr .= $hexdtime; // last mod time and date // "local file header" segment $unc_len = strlen($data); $crc = crc32($data); $zdata = gzcompress($data); $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug $c_len = strlen($zdata); $fr .= pack('V', $crc); // crc32 $fr .= pack('V', $c_len); // compressed filesize $fr .= pack('V', $unc_len); // uncompressed filesize $fr .= pack('v', strlen($name)); // length of filename $fr .= pack('v', 0); // extra field length $fr .= $name; // "file data" segment $fr .= $zdata; // add this entry to array $this -> datasec[] = $fr; // now add to central directory record $cdrec = "\x50\x4b\x01\x02"; $cdrec .= "\x00\x00"; // version made by $cdrec .= "\x14\x00"; // version needed to extract $cdrec .= "\x00\x00"; // gen purpose bit flag $cdrec .= "\x08\x00"; // compression method $cdrec .= $hexdtime; // last mod time & date $cdrec .= pack('V', $crc); // crc32 $cdrec .= pack('V', $c_len); // compressed filesize $cdrec .= pack('V', $unc_len); // uncompressed filesize $cdrec .= pack('v', strlen($name)); // length of filename $cdrec .= pack('v', 0); // extra field length $cdrec .= pack('v', 0); // file comment length $cdrec .= pack('v', 0); // disk number start $cdrec .= pack('v', 0); // internal file attributes $cdrec .= pack('V', 32); // external file attributes - 'archive' bit set $cdrec .= pack('V', $this -> old_offset); // relative offset of local header $this -> old_offset += strlen($fr); $cdrec .= $name; // optional extra field, file comment goes here // save to central directory $this -> ctrl_dir[] = $cdrec; } private function zipDumpFile() { // dumps out zipfile $data = implode('', $this -> datasec); $ctrldir = implode('', $this -> ctrl_dir); return $data . $ctrldir . $this -> eof_ctrl_dir . pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk" pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall pack('V', strlen($ctrldir)) . // size of central dir pack('V', strlen($data)) . // offset to start of central dir "\x00\x00"; // .zip file comment length } private function zipAddDir($verzeichnis, $excludedFiles) { // adds a directory to zip file $handle = opendir($verzeichnis); while ($datei = readdir($handle)) { if ($datei != "." && $datei != ".." && !in_array($datei, $excludedFiles)) { if (is_dir($verzeichnis.$datei)) { // ... if you want you can create empty directories here ... $this->zipAddDir($verzeichnis.$datei.'/', $excludedFiles); } else { // is file: $this->zipAddFile(file_get_contents($verzeichnis.$datei), substr($verzeichnis.$datei,strlen($this->source))); } } } closedir($handle); } public function opendocument($source) { if ($source=='') throw new Exception('no source defined'); if (!is_dir($source)) throw new Exception('source must be a directory with uncompressed opendocument files'); if (!is_file($source.'mimetype')) throw new Exception('no mimetype file found in '.$source); $this -> source = $source; $this->files['mimetype'] = file_get_contents($this->source.'mimetype'); } public function get_file($filename, $overwrite = false) { $file = $this->source.$filename; if (is_file($file)) { if (!array_key_exists($filename,$this->files) || $overwrite) { $this->files[$filename] = file_get_contents($file); return $this->files[$filename]; } } else { if (!array_key_exists($filename,$this->files)) { throw new Exception('File "'.$file.'" not found'); } else { return $this->files[$filename]; } } } public function set_file($content, $file) { $this->files[$file] = $content; } public function get_mime() { return $this->files['mimetype']; } public function output() { $this->zipAddFile($this->files['mimetype'], 'mimetype'); // set mimetyp first $keys = array_keys($this->files); for ($i=0; $i<count($this->files); $i++) { if ($keys[$i] != 'mimetype') { $this -> zipAddFile($this->files[$keys[$i]],$keys[$i]); } } $this->zipAddDir($this->source, $keys); return $this->zipDumpFile(); } } ?>
Gepunkteter Rahmen um Links
… tauchen u.a. im Firefox auf wenn ein Link aktiv ist bzw. angeklickt wurde. So kann man den Rahmen entfernen:
a:active, a:focus { outline: none; }
dabei gilt zu beachten, dass dies als optischer Hinweis gedacht ist, wenn ein User per TAB-Taste o.ä. durch die Seite navigiert. Dieser Hinweis entfällt in diesem Fall.
Petition: Datenschutz – Aufhebung des elektronischen Entgeltnachweises (ELENA) vom 20.12.2009
Zum 1. Januar 2010 wurde der Elektronische Entgeltnachweis (ELENA) eingeführt. Der Chaos Computer Club (CCC) fordert ein Ende der Datenanhäufung auf Vorrat und ruft zur Unterzeichnung einer Petition an den Deutschen Bundestag auf.
Typografie im Internet
Hier mal eine kleine Übersicht über wichtige Sonderzeichen, Normen etc…
Wichtige Zeichen:
| Zeichen | DEC | HTML | Bemerkung |
|---|---|---|---|
| „ | 0132 | „ | |
| “ | 0147 | “ | |
| » | 0187 | » | |
| « | 0171 | « | |
| … | 0133 | … | |
| • | 7 | • | |
| – | 0150 | – | Halbgeviertstrich (Gedankenstrich) |
| × | 0215 | × | Typografisches Malzeichen |
| − | 8722 | − | Typografisches Minuszeichen |
| ÷ | 0247 | ÷ | Divisionszeichen nach Johann Rahn |
| © | 0169 | © | |
| ® | 0174 | ® | |
| < | 060 | < | |
| > | 062 | > | |
| & | 038 | & | |
| € | 0128 | € | |
| ’ | 0146 | ’ | Typografischer Apostroph |
Auszeichnungen
Korrekte Auszeichnung: („ / 0132)„text“(“ / 0147)
alternativ: (» / 0187)»text«(« / 0171)
Apostroph
Typografisch korrekt: ’ (’ / 0146)
Ersatzzeichen: ' (' / 039)
Anwendung: Der Apostroph ersetzt den Buchstaben „e“ und in seltenen Fällen den Buchstaben „i“.
Geldbeträge
Mit Halbgeviertstrich: 15,–(– / 0150) €
Telefonnummern
Beispiel nach DIN 5008: 0123 456789
MySQL-Gründer Michael Widenius hat eine Kampagne gegen die Übernahme von MySQL durch Oracle gestartet. Die Übergabe der Unterschriften soll am 4. Januar 2010 erfolgen. Weitere Informationen und Unterschriftensammlung hier:
PHP: Array rekursiv durchlaufen
Um zum Beispiel die Funktion htmlentities auf ein Array rekursiv anzuwenden kann man wie folgt vorgehen:
1. Eine neue (rekursive) Funktion arr_htmlentities erstellen:
function arr_htmlentities($arr) { foreach ($arr as $key=>$value) { if (!is_array($arr[$key])) { $arr[$key] = htmlentities($arr[$key]); } else { $arr[$key] = arr_htmlentities($arr[$key]); } } return $arr; }
2. Die neue Funktion für das array $_POST (z.B. Eingaben aus einem Kontaktformular) aufrufen:
$userInput = arr_htmlentities($_POST); // ausgabe: print_r($userInput);
Lange gesucht und am Ende hier gefunden:
http://de2.php.net/manual/de/function.date-diff.php#93915
Die Funktion berechnet die Differenz zwischen 2 Timestamps und gibt als Rückgabewert ein Array mit den Jahren, Monaten, Tagen, Stunden, Minuten und Sekunden:
function date_diff($d1, $d2){ /* This is correctly working time differentiating function. It's resistant to problems with leap year and different days of month. Inputs are two timestamps and function returns array with differences in year, month, day, hour, minute a nd second. Compares two timestamps and returns array with differencies (year, month, day, hour, minute, second) More infos at http://de2.php.net/manual/de/function.date-diff.php#93915 */ //check higher timestamp and switch if neccessary if ($d1 < $d2) { $temp = $d2; $d2 = $d1; $d1 = $temp; } else { $temp = $d1; //temp can be used for day count if required } $d1 = date_parse(date("Y-m-d H:i:s",$d1)); $d2 = date_parse(date("Y-m-d H:i:s",$d2)); //seconds if ($d1['second'] >= $d2['second']){ $diff['second'] = $d1['second'] - $d2['second']; } else { $d1['minute']--; $diff['second'] = 60-$d2['second']+$d1['second']; } //minutes if ($d1['minute'] >= $d2['minute']){ $diff['minute'] = $d1['minute'] - $d2['minute']; } else { $d1['hour']--; $diff['minute'] = 60-$d2['minute']+$d1['minute']; } //hours if ($d1['hour'] >= $d2['hour']){ $diff['hour'] = $d1['hour'] - $d2['hour']; } else { $d1['day']--; $diff['hour'] = 24-$d2['hour']+$d1['hour']; } //days if ($d1['day'] >= $d2['day']){ $diff['day'] = $d1['day'] - $d2['day']; } else { $d1['month']--; $diff['day'] = date("t",$temp)-$d2['day']+$d1['day']; } //months if ($d1['month'] >= $d2['month']){ $diff['month'] = $d1['month'] - $d2['month']; } else { $d1['year']--; $diff['month'] = 12-$d2['month']+$d1['month']; } //years $diff['year'] = $d1['year'] - $d2['year']; return $diff; }
Hier mal ein paar kleine Berechnungen zu Geburtsdaten:
define(BIRTHDAY, strtotime('1980-08-26 15:25:00')); // geburtsdatum $now = time(); // aktuelles datum // geburtsdatum dieses jahr: $birthdayThisYear = mktime(date('H',BIRTHDAY),date('i',BIRTHDAY),date('s',BIRTHDAY),date('n',BIRTHDAY),date('j',BIRTHDAY),date('Y',$now)); // geburtsdatum nächstes jahr: $birthdayNextYear = mktime(date('H',BIRTHDAY),date('i',BIRTHDAY),date('s',BIRTHDAY),date('n',BIRTHDAY),date('j',BIRTHDAY),date('Y',$now)+1); // geburtsdatum letztes jahr: $birthdayLastYear = mktime(date('H',BIRTHDAY),date('i',BIRTHDAY),date('s',BIRTHDAY),date('n',BIRTHDAY),date('j',BIRTHDAY),date('Y',$now)-1); // der nächste geburtstag: $nextBirthday = ($now<$birthdayThisYear)?$birthdayThisYear:$birthdayNextYear; // der letzte geburtstag: $lastBirthday = ($now<=$birthdayThisYear)?$birthdayLastYear:$birthdayThisYear; // wie viel prozent des jahres bis zum nächsten geburtstag sind schon um? $percent = ($now-$lastBirthday) / ($nextBirthday-$lastBirthday) * 100; // wie viele tage sind es noch bis zum nächsten geburtstag? $days2Birthday = floor(($nextBirthday - $now) / 86400); // alter als array (jahre, monate, tage, stunden, minuten, sekunden - schaltjahre werde berücksichtigt!) $age = date_diff(BIRTHDAY, $now);