• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

Zeile aus einer Datei löschen [PHP]

Al-Pi

New member
Hallo zusammen,

ich möchte anhand einer ID, eine Zeile aus einer Datei löschen. Die inhalt der Datei sieht wie folgt aus

Code:
149|Hans|Müller|47158
148|Muster|Mustermann|52068
135|Helga|Hof|41061
112|Klaus|Haus|37089

folgende php code soll z.B mit $_POST['delid'] = 148 die komplette Zeile
148|Muster|Mustermann|52068
löschen.

PHP:
//daten sammeln
	$datei = '../data/names.dat'; //Speicherort für die Daten
	$array = file($datei);
	$delName = $_POST['delid']; // ID der zulöschenden Person
	
//prüfen ob id im datei vorhanden ist und gegebenfalls löschen 
	foreach ($array as $element){
		list($nameID, $vorname, $name, $plz) = explode("|", $element); //einzelne daten trennen
			if ($nameID == $delName) {  
				unset ($array[$nameID]);
				echo 'person wird gelöscht';
				//restliche daten wieder speichern
				$rest = fopen ($datei, 'w');
				fwrite ( $rest, $array );
				fclose ( $rest );
			}
			else{
				echo ' ID dieser Person ist nicht vorhanden';
			}
	}

Leider funktioniert das nicht , ich erhalte nur die echo ID dieser Person ist nicht vorhanden zurück.
wäre für hilfreiche antworten sehr dankbar
 
Wird denn die Datei korrekt geöffnet?
Wird $array korrekt erstellt?
Wird $delName korrekt via POST empfangen und gesetzt?
Ist $nameID auch wirklich das was du vergleichen willst?
 
hallo miniA4kuser,
bis zu zeile "list($nameID, $vorname, $name, $plz) = explode("|", $element);" wird alles korrekt ausgegeben, testweise habe ich direkt dahinter mit echo die daten ausgelesen (alles in ordnung).

ich vermute mal das ich mit if ($nameID == $delName) nicht die richtige zeile finde um es zu löschen.
 
Prüfe mal was in $_POST['delid'] überhaupt ankommt, vermute da dein erstes Problem. Dann ist in deiner Schleife noch ein logischer Fehler.
Wenn du die Id gefunden hast, solltest du die Schleife abbrechen und erst am Schleifenende ausgeben das nichts gefunden wurde, wenn dieser Fall eingetreten ist und nicht für jede ID.

Edit: $array[$nameID] existiert nicht, kann also auch nicht gelöscht werden.
 
Zuletzt bearbeitet:
hallo danke für eure Antworten, ich habe so gut wie keine Ahnung von PHP, daher sagen mir einige Begriffe nichts aus :confused:

um unnötige Fehlerquellen zu vermeiden habe ich den Script leicht verändert, bin jetzt auch ein schritt weitergekommen, erhalte schon mal die Ausgabe ob ID vorhanden oder nicht vorhanden ist.

PHP:
<?php
//daten sammeln
	$datei = '../data/names.dat'; //Speicherort für die Daten
	$array = file($datei);
	$delName = '148'; // ID der zulöschenden Person
	$check = true;
	
	
//prüfen ob id im datei vorhanden ist und gegebenfalls löschen 
	foreach ($array as $element)
	{
		list($nameID, $vorname, $name, $plz) = explode("|", $element); //einzelne daten trennen
		if (trim($nameID) == $delName) 
		{ 
			$check = false;
			break;
		} 
	}
	
	if ($check)
	{
		echo ' nummer nicht vorhanden';
	}
	else
	{
		echo ' nummer vorhanden'; //ab hier komme ich nicht weiter
		/*
				unset ($array[$nameID]);
				echo 'person wird gelöscht';
				//restliche daten wieder speichern
				$rest = fopen ($datei, 'w');
				fwrite ( $rest, $array );
				fclose ( $rest );
		*/
	}
?>

doch mit dem löschen der Zeile fehlt mir der jegliche Ansatzt.
 
Hi,
gib mal dein $array mit var_dump($array) aus, um zu sehen, wie es aufgebaut ist. Diesen Schlüssel brauchst du, um ein array-Element zu löschen.
Mit $nameID kann $array nichts anfangen.
PHP:
foreach ($array as $key => $element)
Damit hast du auch den Schlüssel für $array verfügbar. Diesen mußt du dir für den Fall trim($nameID) == $delName merken, um bei deinen Ansatz zu bleiben. Nach den Löschen des array-elementes mußt du es aber die Zeilen wieder so wie deine Ausgangsdatei zusammenbauen und zurückschreiben.
Das ist für dich noch ein Stück Arbeit. Dein fwrite ( $rest, $array ); funktioniert so nicht.

Es gibt weit effektivere Lösungen. Da ich aber vermute, du willst in erster Linie lernen, verkneife ich mir hier diese Ansätze.

LG jspit
 
soo viel Arbeit ist das gar nicht... ein Befehl mehr und den key brauch er auch nicht:
Code:
<?php
  //daten sammeln 
  $datei = '../data/names.dat'; //Speicherort für die Daten 
  $array = file($datei); // Sollst du aber u.U nur für kleine Dateien verwenden. sobald die Datei größer wird, kannst du an der Stelle probleme bekommen, weil die ganze Datei eingelesen wird.
  $delName = '148'; // ID der zulöschenden Person 

// Funktion zum prüfen ob die ID in einem bestimmten Record vorhanden ist (dabei ist Record hier noch ein String... und wird erst in der funktion zu einem richtigen Record :D)
function checkDataRecordForId($record, $idToDelete) {
  list($nameID, $vorname, $name, $plz) = explode("|", $element); //einzelne daten trennen 
  if (trim($nameID) == $idToDelete) {  
    return true;
  }
  return false;
}

//prüfen ob id im datei vorhanden ist und gegebenfalls löschen.
// ANMERKUNG: Deine Variante geht auch. aber an der Stelle geht es einfach viel schöner mit array_walk :) Daher verwende ich das jetzt auch:
array_walk($array, function(&item, $key) {
  // Wenn die ID in Item vorhanden ist, dann...
  if(checkDataRecordForId($item, $delName)) {
    // ... löschen:
    unset($item);
  }
});
// Das Schreiben geht viel einfacherer:
file_put_contents($datei, implode("\n", $array));
?>

ungetestet aber sollte gehen denke ich.

Lg Kasalop

EDIT: und noch was zu dem Punkt von jspit, dass du evtl deinen code beibehalten willst: Dann kannste natürlich seine Anmerkungen beherzigen. Allerdings würde ich dir trotzdem zu meinem Wegschreiben raten ;) oder du musst bei dir das $array, einfach durch ein implode("\n", $array) ersetzten.
 
Zuletzt bearbeitet:
@Kasalop:
1. du hast einen Syntaxfehler (&item --> &$item)
2. dein Code kann erst ab PHP 5.3.0 funktionieren - anonyme Funktionen...
3. kann man array_walk nicht verwenden um Elemente zu löschen: PHP: array_walk - Manual -> unter funcname
 
@Kasalop:
kkapsner hat ja schon auf einiges hingewiesen, ist aber noch nicht alles:
- seine Daten sind in der Zeile durch ein '|' getrennt, das sollte man dann auch bei implode benutzen
- Es ist bei der Ausgabe auch zu berücksichtigen, wie und ob ich die Zeilen abschließe (\n, \r\n,..) in abhängigkeit davon,
wie das Orginal vorliegt. Es sollen ja nicht bei jeden Löschvorgang eine neue Dateistruktur entstehen.

Noch wesentlich kürzer und einfacher (wer's versteht) als mit arrays geht das mit file_get_contents, preg_replace und file_put_contents.

Für sehr große Dateien sollte man zeilenweise lesen, die zu löschende Zeilen verwerfen und wieder schreiben.

LG jspit
 
Zuletzt bearbeitet:
hallo,
nochmals danke an alle

Es gibt weit effektivere Lösungen. Da ich aber vermute, du willst in erster Linie lernen, verkneife ich mir hier diese Ansätze.
LG jspit

An erster stelle möchte ich es verstehen was ich da mache , damit ich gegeben falls ändern, anpassen und vielleicht anderweitig nutzen kann.
In der Datei sind im durchschnitt 100-150 Zeilen, die Löschfunktion wird eher selten benutzt. Wenn man es einfacher und effektiver lösen kann würde ich natürlich dies vorziehen.

So nach langem probieren habe ich es fast gelöst.

PHP:
<?php
//daten sammeln
	$datei = '../data/names.dat'; //Speicherort für die Daten
	$array = file($datei);
	$delName = '148'; // ID der zulöschenden Person
	$check = true;
	//var_dump($array);
	
//prüfen ob id im datei vorhanden ist und gegebenfalls löschen 
	foreach ($array as $element)
	{	
		list($nameID, $vorname, $name, $plz) = explode("|", $element); //einzelne daten trennen
		if (trim($nameID) == $delName) 
		{ 
			$delelement = $element; //löschende zeile in variable übergeben
			$check = false;
			break;			
		} 
	}
	
	if ($check)
	{
		echo ' nummer nicht vorhanden';
	}
	else
	{
		echo ' nummer vorhanden <br />'.$delelement;  // ausgabe: 148|Muster|Mustermann|52068
		$handle = fopen($datei,"w");
		unset($array[1]) ; // statt array numer [1] die ich eigentlich nicht kenne müsste hier die lösch variable rein
		foreach($array as $zeile) {
		   fwrite ($handle,$zeile);
		}
		fclose($handle);
	}
?>

einziges problem, entweder
a) ich muss von der löschenden Zeile die array Nummer ermitteln und ins unset übergeben unset($array[ARRAYNUMMER])

b)ich muss die lösch Variable ins unset integrieren unset($array[$delelement])

Edit://
ups jspit hatte mir schon die Lösung geschrieben

PHP:
foreach ($array as $key => $element)
......
unset($array[$key])
 
Zuletzt bearbeitet:
@Kasalop:
1. du hast einen Syntaxfehler (&item --> &$item)
2. dein Code kann erst ab PHP 5.3.0 funktionieren - anonyme Funktionen...
3. kann man array_walk nicht verwenden um Elemente zu löschen: PHP: array_walk - Manual -> unter funcname
1. okay ja vertippselt ;)
2. closures. ja ich gehe halt von aktuellen Server Einstellungen aus. und da ist 5.3 schon wieder veraltet. Dann lagere eben diese funktion auch nochmal aus, aber wie gesagt. Ist nen Hinweis, aber sollte eigentlich nicht relevant sein.
3. klar kann man das. Dann ist das Manual unvollständig. Aber schau in die Kommentare, dann siehste das es geht: PHP: array_walk - Manual

@Kasalop:
kkapsner hat ja schon auf einiges hingewiesen, ist aber noch nicht alles:
- seine Daten sind in der Zeile durch ein '|' getrennt, das sollte man dann auch bei implode benutzen
- Es ist bei der Ausgabe auch zu berücksichtigen, wie und ob ich die Zeilen abschließe (\n, \r\n,..) in abhängigkeit davon,
wie das Orginal vorliegt. Es sollen ja nicht bei jeden Löschvorgang eine neue Dateistruktur entstehen.

Noch wesentlich kürzer und einfacher (wer's versteht) als mit arrays geht das mit file_get_contents, preg_replace und file_put_contents.

Für sehr große Dateien sollte man zeilenweise lesen, die zu löschende Zeilen verwerfen und wieder schreiben.

LG jspit

zu 1) nein, weil ich ja nicht die record-splits wieder zusammenführe, sondern die arrayzeilen und diese sind durch einen zeilenumbruch getrennt... sonst wären es ja keine Zeilen. Einlesen tut er ja auch mittels file() ;)
zu 2) Das muss er aber auch bei der funktion file() sowieso beachten, wobei meiner Meinung nach auch hier das Manual unvollständig / falsch ist. Der TE sollte aber eh die Flags verwenden, da er leere zeilen skippen will und damit umgeht er auch frech die \r\n problematik.

preg_replace geht natürlich auch, aber nur wenn man mit RegEx umgehen kann. Obs schneller ist und um wie viel müsste man mal nen Benchmark machen. Deinen zweiten Punkt hatte ich oben ja auch schon geschrieben.

Lg Kasalop
 
@Kasalop:
zu 1. Hast Recht. Das Zusammensetzen der Zeile ist überflüssig, diese liegt ja noch im Orginal vor.
zu 2. Das Zeilenende ist ohne Flags ja genau noch so in der Zeile, wie es gebraucht wird.
Ein implode('',$array); dürfte reichen.

Je nach dem, in welchen Kontext die Datei erzeugt wurde, sind auch unterschiedliche Zeilenumbrüche anzutreffen.
Diese zu erfassen, ist auch ein kleines Teilproblem für die Lösung per regulären Ausdruck.
Dafür gibt es jedoch die weniger bekannte Escape Sequence \R . Häufige Alternativen sind (\r\n|\r|\n) und (?:\r?\n|\r).
Wer Lust hat mal einen Benchmark zu machen, hier meine Variante:
PHP:
$datei = '../data/names.dat'; //Speicherort für die Daten 
$file_content = file_get_contents($datei);
$delName = '148'; // ID der zulöschenden Person 
$regEx = '/'.preg_quote($delName,'/').'\|[^\r\n]+\R/';
$file_content = preg_replace($regEx,'',$file_content);
file_put_contents($datei,$file_content);

LG jspit
 
@Kasalop: ich würde mich ja nicht auf
php Manual schrieb:
nicht definiert[es] und auch nicht vorhersagbar[es]
Verhalten verlassen - auch wenn es das tut, was ich will. Bei jeder neuen Version kann es passieren, dass sich das Verhalten ändert...
 
Zurück
Oben