Pedda: Zeile in Textdatei löschen (Problem)

Hallo zusammen,

ich versuche mich seit einiger Zeit in PHP und habe mich nun an ein etwas "komplexeres" Thema gewagt ...
... und schon tauchen die Probleme auf *g*

Situation:
Ich schreibe Kontaktdaten in ein Textfile.
Jeder Datensatz steht in einer Reihe.
Die einzelnen Felder sind durch "#" getrennt.
Das erste Feld enthält eine durchlaufende Nummer.

Von einer Auflistung der Kontaktdaten aus möchte ich per Klick den gewählten Datensatz (also die entsprechende Zeile im txt-file) löschen.
Dazu rufe ich mein "delete.php" auf und übergebe die durchlaufende Nummer der Zeile (delid).

Hier erstmal der code der delete.php
(das Problem beschreibe ich danach !)

<?PHP
    $delid = $_GET['delid'];
    $dir = opendir('../data');
    $filename = '../data/kontakte.txt';
    $filename2 = '../data/tempkontakte.txt';
    $fp = fopen($filename, "r");
    $fp2 = fopen($filename2, "a");
    $contents = file($filename);
    $anzahl = count($contents);
    $setid = 1;

for ($a=0;$a<$anzahl;$a++) {
 list $id,$name,$vorname,$strasse,$plz,$ort,$telg,$telp,$mobg,$mobp,$mail1,$mail2,$nick,$burtzel) = explode("#", $contents[$a]);

if ($fp2) {
          flock($fp2,2);
          if ($id == $delid) {
     $setid = $setid;
   }
   else {
     fputs ($fp2, "$setid#$name#$vorname#$strasse#$plz#$ort#$telg#$telp#$mobg#$mobp#$mail1#$mail2#$nick#$burtzel ");
     $setid = $setid+1;
   }
   flock($fp2,3);
    }
    else {
      echo "Fehlaaaa!";
     }
 }
 // close file
 fclose($fp);
 fclose($fp2);
 unlink('../data/kontakte.txt');
 if (rename("../data/tempkontakte.txt", "../data/kontakte.txt")) {
echo "ok";}

closedir($dir);
?>

Soviel dazu... ich denke mal, es geht auch wesentlich einfacher !?
Nun zum Problem:
Lösche ich (bei z.B.10 Datensätzen gesamt) einen aus der Mitte (also z.B. den fünften) funktioniert alles wunderbar - ich habe im Anschluss 9 Zeilen mit den durchlaufenden Nummern 1 bis 9...
Lösche ich aber den letzten Datensatz, habe ich AUCH 9 Zeilen (wieder 1 bis 9), allerdings hat das txt-file eine Leerzeile am Schluss, was dazu führt, dass ein leerer Datensatz ohne Nummer (müsste dann ja 10 sein) angezeigt wird...

Frage:
(1.) Wieso taucht da die Leerzeile auf ?
Ich sehe keinen Grund, warum das passiert !?
(2.) Hat jemand eine Idee, wie ich diese Leerzeile verhindern kann ?

Thnx 4 support !

Pedda

  1. echo $begrüßung;

    (1.) Wieso taucht da die Leerzeile auf ?
    Ich sehe keinen Grund, warum das passiert !?

    Dann lass dir mit Hilfe von Kontrollausgaben anzeigen, wie dein Script arbeitet, welche Stellen es in welcher Reihenfolge abarbeitet. Der Inhalt der Variablen ist sicher auch von Interesse. Verwende dazu var_dump(), dann wird dir auch der Typ der Variable(n) angezeigt und du erkennst beispielsweise Leerstrings besser als mit einem einfachen echo.

    (2.) Hat jemand eine Idee, wie ich diese Leerzeile verhindern kann ?

    Dir wird dazu schon was einfallen, wenn du herausgefunden hast, warum sie eingefügt wird.

    echo "$verabschiedung $name";

    1. Hallo dedlfix

      Besten Dank für den Tip mit var_dump()....
      Hab's mal recht intensiv (wie ich glaube) eingesetzt.

      Dir wird dazu schon was einfallen, wenn du herausgefunden hast, warum sie eingefügt wird.

      Naja... *verschämtzuBodenguck* ...
      nö...
      Mir ist nix eingefallen (was daran liegen mag, dass ich nicht gefunden habe WARUM die Leerzeile eingefügt wird) :(

      Falls du die Lösung weisst, wäre es nett, wenn du "etwas" konkreter werden könntest ;-)

      Gruss
      Pedda

      1. echo $begrüßung;

        Mir ist nix eingefallen (was daran liegen mag, dass ich nicht gefunden habe WARUM die Leerzeile eingefügt wird) :(

        Mein Tipp ging lautete nicht nach_denken_ sondern nach_schauen_. Da du anscheinend fehlerhaften Gedankengängen nachhängst, solltest du mittels der Kontrollausgaben prüfen, welche davon nicht richtig sind.

        Falls du die Lösung weisst, wäre es nett, wenn du "etwas" konkreter werden könntest ;-)

        Nein, ich weiß die Lösung nicht, weil ich beispielsweise den Inhalt der Datei ../data/kontakte.txt nicht kenne. Notfalls musst du halt noch einen Hexeditor zu Rate ziehen oder die Zeichen / Bytes, die du in die Datei schreibst, einzeln überprüfen (naja, nicht alle, nur die relevanten Stellen).

        Mit chunk_split(bin2hex($teststring), 2, ' '); bekommst du übrigens eine Hexdarstellung von $teststring.

        echo "$verabschiedung $name";

        1. Hallo Dedlfix,

          Mit chunk_split(bin2hex($teststring), 2, ' '); bekommst du übrigens eine Hexdarstellung von $teststring.

          ...und die scheint mir hier auch angemessen zu sein. Daher der Tipp mit einer 'echten' CSV-Datei, also mit Feldtrennern _und_ Feldbegrenzern. Und vor dem Zusammenbau der Felder zu einer Zeile erstmal die Feldbegrenzer doppeln, die in den Daten enthalten sind...

          Ab PHP 5 gibts dafür sogar eine fertige Funktion:
          http://de2.php.net/manual/de/function.fputcsv.php

          Ich habe sie allerdings noch nicht selbst getestet.

          LG
          Chris

  2. Hallo Du Einer,

    <?PHP
        $delid = $_GET['delid'];
        $dir = opendir('../data');
        $filename = '../data/kontakte.txt';
        $filename2 = '../data/tempkontakte.txt';
        $fp = fopen($filename, "r");
        $fp2 = fopen($filename2, "a");
        $contents = file($filename);

    Warum deklarierst Du $filename, wenn Du es dann nicht benutzt?

    file() ist so nicht geeignet für konkurrierende Operationen

    Die Veränderung der Daten bedarf der exclusiven Sperre

    von VOR dem Lesen bis NACH dem Schreiben!

    $anzahl = count($contents);
        $setid = 1;

    ##     Warum for() und nicht foreach() ?

    for ($a=0;$a<$anzahl;$a++)

    {

    list $id,$name,$vorname,$strasse,$plz,$ort,$telg,$telp,$mobg,$mobp,$mail1,$mail2,$nick,$burtzel) = explode("#", $contents[$a]);

    if ($fp2) {
              flock($fp2,2);

    ##  Das Sperren ist hier schon zu spät.
    ##  Die Quelldatei könnte zwischenzeitlich trotzdem nochmal
    ##  gelesen werden

    if ($id == $delid) {
         $setid = $setid;
       }
       else {
         fputs ($fp2, "$setid#$name#$vorname#$strasse#$plz#$ort#$telg#$telp#$mobg#$mobp#$mail1#$mail2#$nick#$burtzel ");
         $setid = $setid+1;
       }
       flock($fp2,3);
        }
        else {
          echo "Fehlaaaa!";
         }
    }
    // close file
    fclose($fp);
    fclose($fp2);
    unlink('../data/kontakte.txt');
    if (rename("../data/tempkontakte.txt", "../data/kontakte.txt")) {
    echo "ok";}

    closedir($dir);
    ?>

    Es würde sich lohnen, sich mit fgetcsv() auseinanderzusetzen und außerdem die Datei auch als 'echte' CSV-Datei abzuspeichern.

    Das erspart einem eine Menge Arbeit oder Kummer, wenn in den Feldern Sonderzeichen enthalten sind.

    LG

    Chris

    1. Tach Chris,

      vielen Dank für deine Antwort...
      ...ich guck mal, ob ich bei fgetcsv() irgendwas finde ;-)

      Gruss
      Pedda

  3. Hallo Pedda,

    ich glaube das Problem zu sehen( bin aber nicht sicher)

    • in jedem Durchgang deiner Schleife setzt du den Zeiger mit flock($fp2,2); ans Ende deiner Datei mit flock($fp2,3); gibt du sie wieder frei.
    • ich denke du hast jetzt eine leere Zeile ans Ende gesetzt
    • hast du noch eine Zeile zu schreiben wird die leere Zeile aufgefüllt
    • schreibst du jedoch keine weitere bleibt die leere Zeile am Ende leer stehen

    Lösung, wie ich denke: die Flocks müssen ausserhalb deiner for-Schleife stehen.

    bydey

    --
    -- noch immer ein erfolgloser <DIV> Jünger --