SELFPHP

SELFPHP-Druckversion
Original Adresse dieser Seite:
http://www.selfphp.de/praxisbuch/praxisbuchseite.php?site=223&group=38
© 2001-2017 E-Mail SELFPHP OHG, info@selfphp.de
© 2005-2017 E-Mail PHP5 Praxisbuch - Matthias Kannengiesser, m.kannengiesser@selfphp.de


Nützliche Dateioperationen


Zum Thema Dateioperationen habe ich noch einige nützliche Codeschnipsel zur Verarbeitung von Dateien für Sie parat.


Zeilen gezielt auslesen

Die Zeilen einer Datei gezielt auszulesen kann leicht umgesetzt werden. Sie können dafür entweder die Funktion file() oder fgets() einsetzen. Die Funktion file() setzt voraus, dass genügend freier Arbeitsspeicher zur Verfügung steht, da in ihrem Fall die Datei vollständig eingelesen wird.

Beispiel – file()

<?php

$daten = file("daten.txt");
// Zweite Zeile ausgeben
echo $daten[1];

?>

Beispiel – fgets()

<?php

$zeilen_zaehler = 0;
$ziel_zeile = 2;

$datei = fopen('daten.txt','r');
while ((! feof($datei)) && ($zeilen_zaehler < $ziel_zeile)) {
  if ($zeile = fgets($datei,1048576)) {
    $zeilen_zaehler++;
  }
}
fclose($datei);

echo $zeile;

?>


Inhalt einer Datei rückwärts einlesen

Wozu das gut sein soll? Beispielsweise könnten Sie in einem Gästebuch neue Beiträge mithilfe von fopen() und dem Anhängmodus »a« (append) ans Dateiende anhängen. Aber wie sieht es mit der Ausgabe aus? Der neueste Eintrag soll schließlich an den Anfang der Ausgabe. Hier eine praktische Lösung.

Beispiel

<?php

$daten = file("daten.txt");
$daten = array_reverse($daten);

foreach ($daten as $eintrag) {
  echo "$eintrag<br>";
}

?>

Natürlich können Sie, anstatt sämtliche Zeilen rückwärtig auszugeben, lediglich eine festgelegte Anzahl von Zeilen ausgeben, etwa die letzten 10 Zeilen.

Beispiel

<?php

$daten = file('daten.txt');
$anzahl = 10;

for ($i = 0, $j = count($daten); $i <= $anzahl; $i++) {
  echo $daten[$j – $i] . "<br>";
}

?>
{PSP}Zeile per Zufall – Spruchgenerator

Wie wäre es mit einem Spruchgenerator, der bei jedem Aufruf zufällig eine Zeile ausliest?

<?php

// Zufallsgenerator
function gen_zahl($max = 1) {
  $faktor = 1000000;
  return ((mt_rand(1,$faktor * $max)-1)/$faktor);
}

// Spruchgenerator
function gen_spruch($dateiname) {
$zeilen_nr = 0;

$datei = fopen($dateiname,'r');
while (! feof($datei)) {
  if ($z = fgets($datei,1048576)) {
    $zeilen_nr++;
    if (gen_zahl($zeilen_nr) < 1) {
      $spruch = $z;
    }
  }
}
fclose($datei);
return $spruch;
}

// Ausgabe
echo gen_spruch("daten.txt");

?>

Wie Sie feststellen werden, habe ich die Zufallszahlen-Funktion gen_zahl() von der Spruchgenerator-Funktion gen_spruch() getrennt, damit Sie die Zufallszahlen-Funktion auch für andere Zwecke nutzen können.

Sie können es natürlich auch einfacher haben, wenn Sie die Funktion file() und anschließend die Funktion shuffle() einsetzen.

Beispiel

<?php

// Spruchgenerator
function gen_spruch($dateiname) {
  $daten = file($dateiname);
  shuffle ($daten);
  return $daten[0];
}

// Ausgabe
echo gen_spruch("daten.txt");

?>


Datei ohne eine temporäre Datei ändern

Stellen Sie sich vor, Sie wollen an einer Datei Änderungen vornehmen, dies jedoch ohne eine temporäre Datei zwischenzuspeichern. In diesem Fall öffnen Sie eine Datei mit dem Modus »r+« und korrigieren nach dem Schreiben der Änderungen die Länge der Datei mithilfe der Funktion ftruncate(). Diese ist in der Lage, eine Datei auf eine angegebene Länge zu kürzen.

Beispiel

<?php

// Datei zum Lesen und Schreiben öffnen
$datei = fopen('daten.txt','r+');

// Gesamte Datei einlesen
$daten = fread($datei,filesize('daten.txt'));

// Konvertiert *Wort* zu <b>Wort</b>
$daten = preg_replace('@\*(.*?)\*@i','<b>$1</b>',$daten);

// Konvertiert /Wort/ zu <u>Wort</u>
$daten = preg_replace('@/(.*?)/@i','<u>$1</u>',$daten);

// Dateizeiger an den Anfang zurücksetzen
rewind($datei);

// Neue Daten in die Datei schreiben
if (-1 == fwrite($datei,$daten)){
  echo "Fehler!";
}

// Dateilänge auf die tatsächliche Datengröße anpassen
ftruncate($datei,ftell($datei));

// Datei schließen
fclose($datei);

?>
{PSP}Ihre daten.txt könnte folgende Daten enthalten:

/Matthias/ ist dort
*Caroline* ist hier

Nach der Änderung stellt sich der Inhalt wie folgt dar:

<u>Matthias</u> ist dort
<b>Caroline</b> ist hier


Schreiben und Lesen von komprimierten Dateien

Um Daten in komprimierter Form als Datei anlegen zu können, steht Ihnen in PHP die zlib-Erweiterung zur Verfügung.

Beispiel – Schreiben

<?php

$datei = gzopen('daten.gz','w');
$daten = "Hier der Text";

if (-1 == gzwrite($datei,$daten)) {
  echo "Fehler!";
} else {
  echo "Datei erzeugt!";
}

gzclose($datei);

?>

Beispiel – Lesen

<?php

$datei = gzopen('daten.gz','r');

while ($zeile = gzgets($datei,1024)) {
  echo $zeile;
}

gzclose($datei);

?>

Die zlib-Erweiterung enthält zahlreiche Dateizugriffsfunktionen wie gzopen(), gzread() und gzwrite(), welche in der Lage sind, Daten beim Schreiben zu komprimieren und beim Lesen zu dekomprimieren. Der von zlib verwendete Kompressions-Algorithmus ist mit den Tools gzip und gunzip kompatibel.


Datei nach einem Muster durchsuchen

Um ein bestimmtes Muster innerhalb einer Datei zu finden und die betreffenden Zeilen auszugeben, sollten Sie sich auf reguläre Ausdrücke und die Funktionen preg_grep(), file() und fgets() stützen.

Entweder Sie lesen die Datei vollständig mithilfe von file() in den Speicher oder Sie gehen zeilenweise vor, indem Sie die Funktion fgets() einsetzen.

Wir verwenden folgende Textdatei:

Inhalt – daten.txt

ActionScript Praxisbuch
ActionScript Profireferenz
MySQL Praxisbuch
PHP 5 Praxisbuch

Beispiel – file()

<?php

// Nur Praxisbücher
$muster = "/\bpraxisbuch\b/i";

// Liste der gefundenen Einträge
$prasix_buecher = preg_grep($muster, file('daten.txt'));

// Ausgabe
foreach ($prasix_buecher as $buch) {
  echo "$buch<br>";
}

?>
{PSP}Ausgabe
ActionScript Praxisbuch
MySQL Praxisbuch
PHP 5 Praxisbuch

Beispiel – fgets()

<?php

// Nur Praxisbücher
$muster = "/\bpraxisbuch\b/i";

// Datei öffnen
@$datei = fopen('daten.txt', 'r') or die("Fehler!");

// Durchsuchen der Datei – zeilenweise
while (!feof($datei)) {
  $zeile = fgets($datei, 4096);
  if (preg_match($muster, $zeile)) {
  $prasix_buecher[] = $zeile;
  }
}

// Ausgabe
foreach ($prasix_buecher as $buch) {
  echo "$buch<br>";
}

// Datei schließen
fclose($datei);

?>

Ausgabe
ActionScript Praxisbuch
MySQL Praxisbuch
PHP 5 Praxisbuch

Die erste Methode ist ungefähr drei- bis viermal schneller als die zweite. Die zweite Methode benötigt für die Suche jedoch weniger Speicher. In diesem Fall müssen Sie als Entwickler entscheiden, was Ihnen wichtiger ist. Und noch etwas: Die zweite Methode ist nicht in der Lage, Zeichenfolgen, die sich über mehrere Zeilen erstrecken, zu finden, da in ihrem Fall der reguläre Ausdruck auf jede Zeile einzeln angewendet wird.


Dateidownload mit PHP

Grundsätzlich können Sie einen Dateidownload auf zwei verschiedene Arten realisieren:

Die Methode per Redirect hat den Nachteil, dass Anwender die Ziel-URL des Redirect mitbekommen und später dann direkt und ungeschützt auf diese Datei zugreifen können.

Will man dies verhindern, muss der Download innerhalb von PHP abgewickelt werden. Die zu ladenden Dateien liegen dann außerhalb der Document Root des Webservers und besitzen somit keine URL. Sie sind lediglich durch PHP abzurufen. In PHP sendet man den passenden MIME-Typ als Header und schickt dann die gewünschte Datei hinterher. Natürlich kann man vorher noch einen Downloadzähler aktualisieren oder überprüfen, ob der Anwender überhaupt für den Download autorisiert ist.

<?php

// $download sei der Bezeichner für die zu ladende Datei
$download = $_GET['download'];

// Dieses Verzeichnis liegt außerhalb des Document Root und
// ist nicht per URL erreichbar.
$basedir = "/home/www/download";

// Übersetzung von Download-Bezeichner in Dateinamen.
$dateiliste = array(
    "file1" => "area1/datei1.zip",
    "file2" => "area1/datei2.zip",
    "file3" => "area2/datei1.zip"
);

// Einbruchsversuch abfangen.
if (!isset($dateiliste[$download])) die("Datei $download nicht vorhanden.");

// Vertrauenswürdigen Dateinamen erzeugen.
$datei = sprintf("%s/%s", $basedir, $dateiliste[$download]);

// Passenden Datentyp erzeugen.
header("Content-Type: application/octet-stream");

// Passenden Dateinamen im Download-Requester vorgeben,
// z. B. den Original-Dateinamen
$speicher_name = basename($dateiliste[$download]);
header("Content-Disposition: attachment; filename=\"$speicher_name\"");

// Datei ausgeben.
readfile($datei);

?>
{PSP}Einsatz von file_get_contents() und file_put_contents()

Die Funktion file_get_contents() wurde in PHP 4.3.0 eingeführt. Nun wurde auch file_put_contents() nachgereicht. Die Funktion file_get_contents() arbeitet ähnlich wie file(), nur mit dem Unterschied, dass der Inhalt einer Datei als Zeichenfolge ausgegeben wird und nicht in Form eines Arrays, wie es bei file() der Fall ist. Der Einsatz dieser neuen Funktion führt übrigens durch Memory Mapping zu einer deutlichen Performanceverbesserung. Sie sollten sie einsetzen, wenn dies Ihr Betriebssystem zulässt.

Syntax

file_get_contents (filename [, path [, context]])

Die Funktion file_put_contents() arbeitet vom Prinzip her wie die Kombination aus den Funktionen fopen(), fwrite() und fclose(). Die Funktion liefert nach einem erfolgreichen Speichervorgang die Datenmenge in Byte zurück.

Syntax

file_put_contents (filename, data [, flags [, context]])

Beide Funktionen sind übrigens binary safe.

Beispiel

<?php

// Auslesen
$inhalt = file_get_contents("info.txt");
echo "Daten: $inhalt<br>";

$inhalt .= "mehr anfügen\n";

// Schreiben
$menge = file_put_contents("info.txt",$inhalt);
echo "Datenmenge: $menge Bytes";

?>

Ausgabe
Daten: Hier ein Text!
Datenmenge: 86 Bytes