4

i was wondering if it is posible to delete a single line in a txt file with php.

I am storing emailadresses in a flat txt file named databse-email.txt

I use this code for it:

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
   $email = $_POST['email-subscribe'] . ',' . "\n";
   $store = file_put_contents('database-email.txt', $email, FILE_APPEND | LOCK_EX);
   if($store === false) {
     die('There was an error writing to this file');
   }
   else {
     echo "$email successfully added!";
   }
}

?>

Form:

<form action="" method="POST">
   <input name="email-subscribe" type="text" />
   <input type="submit" name="submit" value="Subscribe">
</form>

The content of the file looks like this:

janny@live.nl,
francis@live.nl,
harry@hotmail.com,
olga@live.nl,
annelore@mail.ru,
igor@gmx.de,
natasha@hotmail.com,
janny.verlinden@gmail.com,

All lines are , seperated

Lets say i want to delete only the emailadres: igor@gmx.de

How can i do that?

What i want to achieve is a unsubscribe form and delete a single line in the .txt file

Jack Maessen
  • 1,780
  • 4
  • 19
  • 51
  • 3
    I would not use a text file for this purpose, but rather a database table. Or you will have concurrent users overwriting each other. Its much easier to prevent this kind of situation with a database table. – Erik Kalkoken Jan 28 '18 at 19:17

5 Answers5

5

You can use str_replace

$content = file_get_contents('database-email.txt');
$content = str_replace('igor@gmx.de,', '', $content);
file_put_contents('database-email.txt', $content);
Mojo Allmighty
  • 793
  • 7
  • 18
3

Because of the way the filesystem works you can't do this in an intuitive way. You have to overwrite the file with all the lines except the one you want to delete, here's an example:

 $emailToRemove = "igor@gmx.de";
 $contents = file('database-email.txt'); //Read all lines
 $contents = array_filter($contents, function ($email) use ($emailToRemove) {
      return trim($email, " \n\r,") != $emailToRemove;
 }); // Filter out the matching email
 file_put_contents('database-email.txt', implode("\n", $contents)); // Write back

Here's a streaming alternative solution in the cases where the file does not fit in memory:

$emailToRemove = "igor@gmx.de";
$fh = fopen('database-email.txt', "r"); //Current file
$fout = fopen('database-email.txt.new', "w"); //New temporary file
while (($line = fgets($fh)) !== null) {
      if (trim($line," \n\r,") != $emailToRemove) {
         fwrite($fout, $line, strlen($line)); //Write to new file if needed
      } 
}
fclose($fh);
fclose($fout);

unlink('database-email.txt');  //Delete old file 
rename('database-email.txt.new', 'database-email.txt'); //New file is old file

There is also a way to do this in-place to minimize extra disk needed but that is trickier.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
  • I've run across this problem before, and it becomes a real nightmare when the file in question is a good 100gb :( – IncredibleHat Jan 28 '18 at 19:13
  • @IncredibleHat in that case you really need to consider using a database which is a lot more optimized for large data storage. However I'll update the question with a way to stream the file. – apokryfos Jan 28 '18 at 19:22
3

You can do it programmatically which will just look over every line and if it not what you want to delete, it gets pushed to an array that will get written back to the file . Like below

 $DELETE = "igor@gmx.de";

 $data = file("database-email.txt");

 $out = array();

 foreach($data as $line) {
     if(trim($line) != $DELETE) {
         $out[] = $line;
     }
 }

 $fp = fopen("database-email.txt", "w+");
 flock($fp, LOCK_EX);
 foreach($out as $line) {
     fwrite($fp, $line);
 }
 flock($fp, LOCK_UN);
 fclose($fp); 
Aftab H.
  • 1,517
  • 4
  • 13
  • 25
1

first read the file using fopen and fget , and make array to list the emails you want to remove , use in_array to check if value exists in array , and then after remove unwanted emails save the file using fwrite and you need to close the file after the read and the write operations using fclose

checkout this code

$data = "";
$emailsToRemove = ["igor@gmx.de" , "janny@live.nl"];

//open to read
$f = fopen('databse-email.txt','r');
while ($line = fgets($f)) {
    $emailWithComma = $line . ",";

    //check if email marked to remove
    if(in_array($emailWithComma , $emailsToRemove))
        continue;

    $data = $data . $line;
}

fclose($f);


//open to write
$f = fopen('databse-email.txt','w');
fwrite($f, $data);
fclose($fh);
Ali Faris
  • 17,754
  • 10
  • 45
  • 70
1

for delete special word and next delete blank line try this:

$file = "file_name.txt";
$search_for = "example_for_remove";
$file_data = file_get_contents($file);
$pattern = "/$search_for/mi";
$file_data_after_remove_word = preg_replace($pattern, '', $file_data);
$file_data_after_remove_blank_line = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $file_data_after_remove_word);
file_put_contents($file,$file_data_after_remove_blank_line);
mamal
  • 1,791
  • 20
  • 14