Mit PHP Ordner über Netzwerklaufwerke auslesen

Heute geht es darum, wie man erfolgreich mit einem PHP-Skript Ordner, Unterordner und Dateien über ein Netzwerklaufwerk ausliest und auflistet.

Ein solches Skript könnte z.B. so aussehen:

<?php

clearstatcache();

$sourcepath = "Laufwerksbuchstabe:";

// Replace \ by / and remove the final / if any
$root = ereg_replace( "/$", "", ereg_replace( "[\\]", "/", $sourcepath ));

// Search for text files
$results = m_find_in_dir( $root, ".*\.*" );
if( false === $results ) {
	echo "'{$sourcepath}' ist kein gültiges Laufwerk\n";
} elseif($results!=false) {
	print_r( $results );
} else {
	echo "Keine Strings länger als 255 Zeichen gefunden.";
}

/**
* Search for a file maching a regular expression
*
* @param string $root Root path
* @param string $pattern POSIX regular expression pattern
* @param boolean $recursive Set to true to walk the subdirectories recursively
* @param boolean $case_sensitive Set to true for case sensitive search
* @return array An array of string representing the path of the matching files,
* or false in case of error
*/
function m_find_in_dir( $root, $pattern, $recursive = true, $case_sensitive = false ) {
$result = array();
if( $case_sensitive ) {
	if( false === m_find_in_dir__( $root, $pattern, $recursive, $result )) {
		return false;
	}
} else {
	if( false === m_find_in_dir_i__( $root, $pattern, $recursive, $result )) {
		return false;
	}
}

return $result;
}

/**
* @access private
*/
function m_find_in_dir__( $root, $pattern, $recursive, &$result ) {
	$dh = @opendir( $root );
	if( false === $dh ) {
		return false;
	}
	while( $file = readdir( $dh )) {
		if( "." == $file || ".." == $file ){
			continue;
		}
		if( false !== @ereg( $pattern, "{$root}/{$file}" ) && strlen("{$root}/{$file}") >= 255 ) {
			$result[] = "{$root}/{$file}<br />";
		}
		if( false !== $recursive && is_dir( "{$root}/{$file}" )) {
			m_find_in_dir__( "{$root}/{$file}", $pattern, $recursive, $result );
		}
	}
	closedir( $dh );
	return true;
}

/**
* @access private
*/
function m_find_in_dir_i__( $root, $pattern, $recursive, &$result ) {
	$dh = @opendir( $root );
	if( false === $dh ) {
		return false;
	}
	while( $file = readdir( $dh )) {
		if( "." == $file || ".." == $file ){
			continue;
		}
		if( false !== @eregi( $pattern, "{$root}/{$file}" ) && strlen("{$root}/{$file}") >= 255 ) {
			$result[] = "{$root}/{$file}<br />";
		}
		if( false !== $recursive && is_dir( "{$root}/{$file}" )) {
			m_find_in_dir__( "{$root}/{$file}", $pattern, $recursive, $result );
		}
	}
	closedir( $dh );
	return true;
}

>

Dieses Skript durchsucht nach dem Aufruf das in der 5. Zeile unter $sourcepath angegebene Laufwerk nach Dateien und Ordnern.
In Zeile 11 kann man zusätzlich noch einen Suchausdruck eintragen. ".*\.*" sucht nach allen Dateien, ".*\.txt" sucht nur nach Dateien mit der Endung .txt.
In Zeile 17 taucht die Zahl 255 auf. Diese steht auch in Zeile 56 und 79. Hier lasse ich mir quasi nur die Dateien anzeigen, deren String (z.B. C:\foo\foobar.txt) länger oder genauso lang sind wie eben 255 Zeichen. Warum? Weil es immer mal wieder zu Problemen unter Windows kommt, so lange Strings von einer Platte oder Partition auf eine andere zu kopieren. Warum erläutere ich gerne ein anderes mal. Auf jeden Fall kann man && strlen("{$root}/{$file}") >= 255 auch weg lassen. Dann werden eben alle Dateien und Ordner x-beliebiger Länge angezeigt.

Problem der Sache bestand darin, dass ich ein Netzlaufwerk “scannen” wollte und der Webserver-Dienst auf meinem Client läuft und nicht auf dem eigentlichen Server. PHP erlangt über den normal laufenden Apache-Dienst (ich nutze XAMPP) keinen Zugriff auf die verbunden Netzlaufwerke. Dieses Problem kann man jedoch umgehen, indem man in der Windows-Verwaltung auf dem Client unter “Dienste” den Apache-Dienst anklickt und im Reiter “Anmelden” nicht das Lokale Systemkonto nutzt, sondern “Dieses Konto” auswählt. Hier trägt man als Domain-Admin einfach seinen Benutzernamen (z.B. Benutzer@domain) und sein Kennwort ein. Nach einem Klick auf OK folgt ein Neustart des Apache-Dienstes. Rechter Mausklick auf Apache und “Neu starten” ermöglicht auf die schnelle auch dies.

Jetzt sollte das Skript auch auf alle Netzlaufwerke zugreifen können. Elegant ist das nur leider nicht. Am besten wäre es, man erstellt sich einen neuen Benutzer und vergibt diesem gezielte Zugriffsrechte auf diverse Laufwerke.

Ein weiteres Problem, das gerne bei solchen überdimensionalen und zeitaufwendigen Skripten auftritt ist, dass wenn man sie im Browser startet, sie normalerweise nach 60 Sekunden abbrechen. Je nach Einstellung in der php.ini. Hier findet sich der Eintrag default_socket_timeout mit dem Standard-Wert von 60 Sekunden. Diesen kann man zwar erhöhen, ist allerdings wieder nicht wirklich elegant. Für solche Aufgaben eignet sich hervorragend die Konsole. Man öffnet die Kommandokonsole von Windows und wechselt in das Verzeichnis, in dem sich die php.exe befindet. Bei XAMPP wäre das im Ordner c:\xampp\php. Jetzt folgt der Befehl “php pfad\zum\skript.php” und schon geht’s los. Hier in der Konsole gelten keine Timeouts. Außerdem muss man nicht die php.ini verändern.

Als Ausgabe erhält man die einzelnen Array-Werte. Für mich eine schöne und schnelle Möglichkeit, nach bestimmten Dateien zu suchen, die man über die Windows-Suche nicht finden würde. Bzw. wo bei Windows einfach die Auswahl der entsprechenden Suchkriterien fehlt. Schade ist leider, dass man mit diesem Skript nicht mehrere Laufwerke gleichzeitig durchsuchen kann. Sprich, man mehrere Laufwerksbuchstaben angibt, die nacheinander durchsucht werden. Wenn allerdings jemand eine Lösung kennt, immer her damit.

Tags: , , , , , , , ,

Hinterlasse eine Antwort