PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Archive for Februar, 2010

WordPress Addon SexyBookmarks hinzugefügt

with 3 comments

Da ich mir natürlich wünsche dass meine Artikel auf anderen Seiten weiterverlinkt werden, vereinfache ich nun das Setzen von Bookmarks bei bekannten Diensten sowie das Retweeten mit Hilfe des WordPress-Addons SexyBookmarks. Dadurch sind nun unter jedem Artikel ein paar Symbole von Sozialen Netzwerken und Bookmark-Diensten, mit denen man mit einem Klick den Artikel verlinken kann.

Da ich nicht genau weiß welche Dienste ihr nutzt habe ich erstmal die mir bekannten Dienste dort angezeigt. Falls ihr ein Symbol vermisst (und es in der Liste der unterstützten Features ist) füge ich es natürlich gern hinzu.

Was könnte ich sonst noch tun, um euch zu animieren, meine Artikel zu verlinken? 🙂

Written by Michael Kliewe

Februar 28th, 2010 at 2:54 pm

Posted in Allgemein

Lesepool Nummer 1

with 4 comments

Wer über das Wochenende nicht bereits genug ausgelastet ist, kann hier noch einige interessante Artikel und Webseiten lesen, die ich so in den letzten Tagen gesammelt habe:

PHP:
Month of Bugs in PHP: May 2010
http://www.suspekt.org/2010/02/19/sneak-preview-month-of-php-security-2010/
Symfony 2 soll das schnellste Framework sein? Padraic Brady beschleunigt das Zend Framework
http://blog.astrumfutura.com/archives/421-PHP-Framework-Benchmarks-Entertaining-But-Ultimately-Useless.html
Changelog Zend Framework 1.10.2
http://framework.zend.com/changelog/1.10.2
Man darf doch träumen: Browser Feature Wunschliste
http://www.stevesouders.com/blog/2010/02/15/browser-performance-wishlist/
Das Hacken hat begonnen: HipHop auf GitHub
http://github.com/facebook/hiphop-php

Systeme:
http://www.rootforum.org/wiki/Vergleich_der_Anbindung_von_PHP_als_Apache-Modul_CGI_und_FastCGI_%28de%29

Witziges für Entwickler:
Yeehaa, wir hassen den Internet Explorer!
http://www.chigarden.com/2007/10/tutorial-making-the-ie-voodoo-doll/
Hatte ich ja bereits via Twitter gepostet, aber es ist einfach gut:
http://www.worktobejudged.com/strippause/peca.html

Ich hoffe, dass ich es regelmäßig schaffe, Links zu posten, aber es wird wohl nicht jede Woche sein denke ich, mal sehen.

Written by Michael Kliewe

Februar 26th, 2010 at 11:31 am

Posted in PHP

Tagged with ,

Gratulation an „PHP Hates Me“ für 500 eindrucksvolle Artikel!

without comments

Tja, was soll ich viel sagen, einer meiner fast täglichen Stammblogs über PHP, und mehr oder weniger Inspirator für meinen eigenen Blog feiert heute: „PHP Hates Me“ hat an den letzten 500 Arbeitstagen 500 Artikel veröffentlicht, Gratulation meinerseits!

Auf einige interessante Artikel habe ich ja bereits verwiesen hier im Blog. Immer interessant finde ich auch die wöchentlichen Lesestoff-Links, vielleicht sollte ich das auch mal machen.

Wie dem auch sei, ich wünsche jedenfalls viel Erfolg für die nächsten 500 Artikel!

Written by Michael Kliewe

Februar 22nd, 2010 at 2:21 pm

Posted in PHP

Tagged with ,

Software grafisch darstellen mit Code_Swarm

with 5 comments

Hier erstmal das Video, damit ihr seht worum es geht:

Dies ist das Video, das ich gerade erstellt habe, und zwar vom Zend Framework 1.10 branch. Man sieht, wo welche Programmierer mitgeholfen haben, wer häufig welche Art von Dateien bearbeitet usw. Mit mehr Zeit könnte man da noch andere coole Dinge mit anstellen, wie beispielsweise weitere Dateiendungen farbig markieren etc. etc.

Es gibt natürlich auch aussagekräftigere Tabellen und Statistik-Tools, aber ich finde das eine sehr schöne Darstellung, sollte man mal von seinem Projekt machen wenn mehrere Leute involviert sind (als Motivation).

Code_Swarm kann auf svn, git, hg und wahrscheinlich noch weiteren Repositories losgelassen werden. Wie man es installiert und laufen lässt steht hier:

http://github.com/rictic/code_swarm

ich möchte es nicht kopieren. Ich habe es bereits ohne Probleme unter Mac OS X und Ubuntu ans Laufen bekommen. Unter Ubuntu 9.10 sah das so bei mir aus:

cd
mkdir code_swarm
cd code_swarm
sudo apt-get install git-core subversion mencoder
git clone git://github.com/rictic/code_swarm.git
svn co http://framework.zend.com/svn/framework/standard/branches/release-1.10/
export PATH=$PATH:~/code_swarm/code_swarm/bin
cd release-1.10
code_swarm

Der erste Aufruf von code_swarm generiert eine Folge von Ergebnisbildern, die man auch als Film angezeigt bekommt.. Um viele Tausend png-Bilder auf der Festplatte zu generieren, die wir dann noch in einen Film umwandeln können, muss in der Projektdatei (~/code_swarm/release-1.10/.svn/.code_swarm/project.config) folgendes geändert werden:

ColorAssign3="Source Code"   <-- .php hinzufügen
TakeSnapshots=true
SnapshotLocation=frames/#####.png

Dann nochmal code_swarm im Repository-Verzeichnis aufrufen, anschliessend wird der Aufruf von mencoder daraus ein Video generieren:

cd ../code_swarm/frames/
mencoder mf://*.png -mf fps=24:type=png -ovc lavc -oac copy -o video1.avi

Bei Problemen oder weiteren Einstellungsfragen sollte man dieses HowTo gelesen haben. Hier ist noch ein Posting wo man sehr viele Einstellungsmöglichkeiten sehen kann (Die „Masse“ der Entwickler, Framegröße, Geschwindigkeiten usw)

Weitere interessante Projekte, die sich mit der visuellen Darstellung von Repositores oder Logs beschäftigen, kann man hier sehen:

http://code.google.com/p/gource/

http://code.google.com/p/logstalgia/

Written by Michael Kliewe

Februar 18th, 2010 at 8:52 am

6 Methoden, ein Verzeichnis rekursiv zu scannen

with 6 comments

Wer von euch kennt solchen Code:

if ($handle = opendir('/path/to/files')) {
    while (false !== ($file = readdir($handle))) {
        echo "$file\n";
    }
    closedir($handle);
}

So wird es häufig gemacht, aber hier wird natürlich nur ein Verzeichnis durchsucht und keine Unterordner betrachtet. Und häufig schleichen sich dort auch Fehler ein, beispielsweise wenn man im obigen Beispiel nur

while ($file = readdir($handle)) {

schreibt. Es gibt aber noch eine Menge anderer Möglichkeiten, die ich hier einmal vorstellen und vergleichen möchte. Danach stelle ich noch einige Testergebnisse vor, um die verschiedenen Möglichkeiten zu vergleichen sowie Vor- und Nachteile aufzuzeigen.

Hier erstmal das Script mit den einzelnen Funktionen:

$method = 'dirRead';

echo "mem before:".memory_get_peak_usage(true)."\n";
echo "Starting $method()\n";
clearstatcache();
$startTime = microtime(true);
$allFiles = DirectoryParser::$method('C:/Temp');
echo "Zeit: ".(microtime(true) - $startTime)." sec\n";
echo "mem after:".memory_get_peak_usage(true)."\n";
echo count($allFiles)."\n\n";

class DirectoryParser
{
	public static function createTestFolders($dir) {
		for($i=0; $i<10000; $i++) {
			@mkdir($dir.'/'.$i);
			for ($u=0; $u<10; $u++) {
				touch($dir.'/'.$i.'/'.rand(10000, 999999).'.txt');
			}
		}
	}

	public static function dirRead($dir, &$fileinfo = array()) {
		if ($handle = dir($dir)) {
			while (false !== ($file = $handle->read())) {
				if (!is_dir($dir.'/'.$file)) {
					$fileinfo[] = array($file, filesize($dir.'/'.$file));
				} elseif (is_dir($dir.'/'.$file) && $file != '.' && $file != '..') {
					self::dirRead($dir.'/'.$file, $fileinfo);
				}
			}
			$handle->close();
		}
		return $fileinfo;
	}

	public static function find($dir) {
		if (substr(php_uname(), 0, 7) == "Windows") {
			foreach (explode("\n",` cd "$dir" && dir /S /B /A-D `) as $fullFilename) {
				if ($fullFilename != '') {
					$fileinfo[] = array($fullFilename, filesize($fullFilename));
				}
			}
		} else {
			foreach (explode("\n",` cd $dir && find -maxdepth 3 -type f ! -name ".*" -printf "%f\r%s\n" `) as $fileInfos) {
				if ($fileInfos != '') {
					$fileinfo[] = explode("\r", $fileInfos);
				}
			}
		}
		return $fileinfo;
	}

	public static function glob($dir, &$fileinfo = array()) {
		foreach (glob($dir.'/*') as $file) {
			if (is_dir($file)) {
				self::glob($file, $fileinfo);
			} else {
				$fileinfo[] = array(basename($file), filesize($file));
			}
		}
		return $fileinfo;
	}

	public static function scandir($outerDir){
		$dirs = array_diff(scandir($outerDir), array(".", ".."));
		$fileArray = array();
		foreach ($dirs as $d) {
			if (is_dir($outerDir."/".$d)) {
				$fileArray = array_merge($fileArray, self::scandir($outerDir."/".$d));
			} else {
				$fileArray[] = array($d, filesize($outerDir."/".$d));
			}
		}
		return $fileArray;
	}

	public static function opendir($dir, &$fileinfo = array()) {
		if ($handle = opendir($dir)) {
			while (false !== ($file = readdir($handle))) {
				if (!is_dir($dir.'/'.$file)) {
					$fileinfo[] = array($file, filesize($dir.'/'.$file));
				} elseif (is_dir($dir.'/'.$file) && $file != '.' && $file != '..') {
					self::opendir($dir.'/'.$file, $fileinfo);
				}
			}
			closedir($handle);
		}
		return $fileinfo;
	}

	public static function directoryIterator($dir) {
		$iterator = new RecursiveDirectoryIterator($dir);
		foreach(new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {
			if (false == $file->isDir()) {
				$fileinfo[] = array($file->getFilename(), $file->getSize());
			}
		}
		return $fileinfo;
	}
}

Man wählt also in Zeile 1 eine Methode, stellt in Zeile 7 den Pfad korrekt ein, und lässt das Script laufen. Falls man ein Testverzeichnis erstellen möchte mit 100.000 Dateien, kann man die Methode createTestFolders nutzen.

Bei allen Methoden, die Verzeichnisse durchsuchen und Dateien auslesen (z.B. um die Größe festzustellen) muss man darauf achten, nicht zuviele „offene Filehandles“ zu haben, denn viele Betriebssysteme haben da festgelegte Grenzen, wieviele offene Dateien ein Prozess haben darf.

Unter Linux findet man das beispielsweise heraus mit

$ cat /proc/sys/fs/file-max
184665
$ sysctl fs.file-max
fs.file-max = 184665

Leider weiß ich nicht, wie man die maximale Anzahl an gleichzeitigen FileDescriptors („open files“) eines laufenden Prozesses herausfindet, deshalb habe ich in der unten stehenden Tabelle nur die Gesamtanzahl der Filesystem-Events unter Windows 7 rausgeschrieben (herausgefunden mit dem Process Monitor). Wieviele davon jeweils gleichzeitig geöffnet waren konnte ich nicht herausfinden. Wer weiß Bescheid?

Des weiteren habe ich die Laufzeit protokolliert und auch die Algorithmen einmal einzeln laufen lassen, um den maximalen Speicherverbrauch herauszufinden.

MethodeLaufzeit (s)MemoryPeak (MB)FilesystemEvents Win7Probleme
dir()/read()51331207556
find/dir4639805840
glob()5634900006findet keine Dateien, die mit . beginnen
scandir()312391057467
opendir()/readdir()52331206817
DirectoryIterator87332146331

Die Messungen habe ich mit meiner normalen SATA2 Festplatte gemacht, das untersuchte Verzeichnis hat 90.499 Dateien, die meisten davon 0 Byte groß und insgesamt über 10078 Unterordner verteilt.

Interessanterweise sind die Ergebnisse unter Linux deutlich anders gewesen.

  • Einmal habe ich einen Ubuntu 9.10 Server genommen, mit SSD, aber leider relativ schwacher CPU. PHP 5.2.10
MethodeLaufzeit (s)MemoryPeak (MB)
dir()/read()49993
find/dir135109
glob()51095
scandir()1043113
opendir()/readdir()50794
DirectoryIterator62288
  • Den selben Ubuntu Server, aber mit PHP 5.3.1
MethodeLaufzeit (s)MemoryPeak (MB)
dir()/read()16056
find/dir14676
glob()13158
scandir()291579
opendir()/readdir()14257
DirectoryIterator15657
  • Einmal einen Debian-Server mit QuadCore, Raid1 SATA2 und PHP 5.2.11
MethodeLaufzeit (s)MemoryPeak (MB)
dir()/read()38053
find/dir264
glob()34955
scandir()74464
opendir()/readdir()36654
DirectoryIterator346

Verstehen tue ich einige Ergebnisse noch nicht, zum Beispiel warum die find-Methode auf dem Debian-Server nur 2 Sekunden benötigt, wohingehen sie unter Ubuntu jeweils > 2 Minuten dauert. Das selbe beim DirectoryIterator. Komisch. Außerdem scheint PHP 5.3 ordentlich an Geschwindigkeit zugelegt zu haben gegenüber 5.2.

Falls jemand von euch weiß, wie man die Anzahl der FilesystemEvents (inotify?) unter Linux herausbekommen kann, oder die Anzahl der maximalen gleichzeitigen Filehandles (sowas wie lsof -p PID, nur das Maximum während eines Programmdurchlaufs), bitte in den Kommentaren melden.

Ich überlege auch, ob es sich lohnt, diese Tests mal auf einem NFS-Laufwerk im Netzwerk zu machen, das könnte man evtl. auch mal brauchen.

(Die Tabellen wollte ich übrigens mal ausprobieren, sind mit dem WordPress-Addon WP-Table Reloaded erstellt worden)

Written by Michael Kliewe

Februar 16th, 2010 at 9:29 am