Hi,

I'm trying to fully automate my website, and I'm trying to delete a line from a file that matches the line in a given String.
For example, I have a txt file named toApprove.txt containing a list of names such as:

John
Joe
George
Jake

The file is kept in that format. So, if I have a variable holding "Joe", how do I remove the line that says "Joe" from the text file and keep the rest. here's what I tried ($_GET["file"] represents the line I want to remove):

$file=fopen("toApprove.txt","r+");
$file2=fopen("temp.txt","w+");
while(!feof($file))
{
	$str = fgets($file);
	if($str != $_GET["file"])
	{
		fwrite($file2,$str);
	}
}
fclose($file);
fclose($file2);

$file=fopen("toApprove.txt","w+");
$file2=fopen("temp.txt","r");
while(!feof($file2))
{
	$str = fgets($file2);
	fwrite($file,$str);
}
fclose($file);
fclose($file2);

Thanks so much for your help!

Is there an error you're getting? I don't see any particular problem in the code.

Normally, you'd want to have a database do this job for you. It is much simpler than having to read/write from files.

For example, with a DB it is as simple as:

$result = $Db->Query("DELETE FROM `table` WHERE `column` = '".mysql_real_escape_string($_GET["file"])
."' LIMIT 1";

The database then does basically what you are doing with the files, on the disk or memory depending on the storage type being used. Databases are very efficient at this though by design.

Your code is very good for file updates as it is very memory efficient. If you are working with small files, you could save time by doing something like:

// retrieve file into a string
$txt = file_get_contents('toApprove.txt');
// replace the line with $_GET["file"], assuming line break is \n
$txt = str_replace(trim($_GET["file"])."\n", '', $txt);
// write the string back to the file
file_put_contents('toApprove.txt', $txt);

or

// retrieve the file into an array where each line is a value
$Array = file('toApprove.txt');
// assuming unique values, lets remove the Array key with value $_GET["file"]
unset($Array[array_search(trim($_GET["file"]), $Array)]);
// explode the array into string with line breaks seperation and put everthing back in the file
file_put_contents('toApprove.txt', implode("\n", $Array));

It is much simpler, however, is memory intensive if you have a large file since you will be saving the whole file contents to a variable, $txt (PHP memory).
file_get_contents() should be more efficient than using fopen() and fgets() for smaller files.. it certainly is more convenient.

file_put_contents() is only supported on PHP5, so you can test for it and your system and create the function if it doesn't exist:

if (!file_exists('file_put_contents')) {
// create a simple user function to emulate PHP5's file_put_contents() 
function file_put_contents($file, $contents) {
fwrite($fp = fopen($file), $contents, strlen($contents));
fclose($fp);
}
}

that should work for basic use.

Comments
Nice info..

Thanks for your help! There is no database for me to use (I'm using a free web host).
Also, I'm not getting any error message. Instead, it is just not deleting anything from the file. I will try the file_put_contents function, though. Thanks!

Thanks for your help! There is no database for me to use (I'm using a free web host).
Also, I'm not getting any error message. Instead, it is just not deleting anything from the file. I will try the file_put_contents function, though. Thanks!

Yeah, it's usually easier to just put everything from the file in a string or array, and use the string and array functions to manipulate it. It also allows you to dump the whole string after manipulation just to see if it worked.

You may also be interested in a flat file DB. It reads and writes to disk but has similar functionality as a database. Theres a great one posted here a few weeks ago as part of a new CMS. http://www.daniweb.com/forums/post482294.html

hi

i know this is an old post but i have a question about it.

when using this code the problem i have is that it leaves an empty line in the file where you deleted the line is there any way to do it so it doesnt put an empty line in place of your deleted line?

Nook6

Which code are you using?

Line breaks are represented by "\n" for unix and "\r\n" for windows.

Note that "\n" is only a single character, it is escaped with an \ to show that it is actually a meta character ie: the new line.

If you delete that "\n" together with the line you are deleting there should be no empty line left over.

yes thankyou solved the problem i did take out the \n but then it was adding the next line to the end of the line before.

in the end i used this code:

// retrieve file into a string
$txt = file_get_contents('database.txt');
// replace the line with $_GET["file"], assuming line break is \n
$txt = str_replace(trim($_GET["info"]),'', $txt);
// strip out any empty lines
$txt = preg_replace('/^\n+|^[\t\s]*\n+/m','',$txt);
// write the string back to the file
file_put_contents('database.txt', $txt);

thanks very much.

nook6

There is a fatal flaw to loading the entire file into an array like that. It loads the entire file into memory. If the file only has 30 lines no big deal. If the file as 30000 lines then it will be an issue.

Here is what I recommend instead (PHP 5.1.2 > only):

<?php

/*
 * Create a new SplFileObject representation of the file
 * Open it for reading and writing and place the pointer at the beginning of the file
 * @see fopen for additional modes
 */
$file = new SplFileObject('database.txt', 'a+');

/*
 * Set a bitmask of the flags to apply - Only relates to reading from file
 * In this case SplFileObject::DROP_NEW_LINE to remove new line charachters
 * and SplFileObject::SKIP_EMPTY to remove empty lines
 */
$file->setFlags(7);

/*
 * Lock the file so no other user can interfere with reading and writing while we work with it
 */
$file->flock(LOCK_EX);

/*
 * Create a SplTempFileObject
 * 0 indicates not to use memory to store the temp file.
 * This is probably slower than using memory, but for a large file it will be much more effective
 * than loading the entire file into memory
 * @see http://www.php.net/manual/en/spltempfileobject.construct.php for more details
 */
$temp = new SplTempFileObject(0);

/*
 * Lock the temp file just in case
 */
$temp->flock(LOCK_EX);

/*
 * The line we're hoping to match and remove
 * DO NOT include any line ending charachters these have been stripped already
 */
$delete = 'Some line to match and delete.';

/*
 * Iterate over each line of the file only loading one line into memory at any point in time
 * Use trim() on the line to ensure we don't have excess whitespace anywhere
 */
foreach( $file as $line ){	
	
	if( trim($line) != $delete )
	{
		/*
		 * If this line does NOT match out delete write it to the temp file
		 * Append a line ending to it
		 */
		$temp->fwrite($line.PHP_EOL);
	} 
}

/*
 * Truncate the existing file to 0
 */
$file->ftruncate(0);


/*
 * Write the temp file back to the existing file
 */
foreach( $temp as $line ){
	
	/*
	 * Iterate over temp file and put each line back into original file
	 */
	$file->fwrite($line);
}

/*
 * Release the file locks
 */
$temp->flock(LOCK_UN);
$file->flock(LOCK_UN);

This way we only ever work with 1 line in memory at a time.
You could also port this code to delete a line in the file numerically by changing out the initial foreach loop to something like:

// Delete line 6 (Files start as 0, 1, 2, 3, etc like arrays)
$delete = 5;

/*
 * Iterate over each line and check its key
 */
foreach( $file as $key => $line ){	
	
	if( $key != $delete )
	{
		/*
		 * If this line does NOT match out delete write it to the temp file
		 * Append a line ending to it
		 */
		$temp->fwrite($line.PHP_EOL);
	} 
}
This article has been dead for over six months. Start a new discussion instead.