Search file for word and delete line - php

This is a second request on the same subject. I wasn't clear
I needed the line to be deleted.
I searched here and found part of a script that is suppose search for
a word and delete the line. There seems to be a slight error with what
I'm trying to do.
I have an option list in a pull down. I would like for it to
remove the line selected. The file choice.php that is called
from the pull down page seems to be released when the php below
is called called because there is no access denied, or violation
errors.
These are the errors I'm getting after adding the 3 last lines I
was told I need.
fopen() expects at least 2 parameters, 1 given
implode(): Invalid arguments passed
fwrite() expects parameter 1 to be resource, boolean given
fclose() expects parameter 1 to be resource, boolean given
Thanks in advance
<?php
// Separate choice.php has the following pull down
// Select item to delete from list
// <option value="item1.php">Item 1</option>
// <option value="item2.php">Item 2</option>
// ...... many items.
$workitem = $_POST["itemtodelete"];
$file = file("option.list.php");
foreach( $file as $key=>$line ) {
if( false !== strpos($line, $workitem) ) {
unset ($file[$key]);
}
}
// Removed "\n"
$file = implode("", $file);
// Told to add this.
$fp = fopen ("option.list.php");
fwrite($fp,implode("",$file);
fclose ($fp);
?>

fopen requires a $mode as the second parameter, so that fails and everything that needs $fp.
Just use file_put_contents. It will even implode the array for you:
$workitem = $_POST["itemtodelete"];
$file = file("option.list.php");
foreach( $file as $key=>$line ) {
if( false !== strpos($line, $workitem) ) {
unset ($file[$key]);
}
}
file_put_contents('option.list.php', $file);

Ok. You are missing some closing parenthesis, as well as other things.
$replaceItem = $_POST['itemtodelete']; // You should filter this data
$newContents = "";
$path = PATH_TO_FILE; // This could be hard coded, but not recommended
$filename = "option.list.php";
// Check to see if the file exists
if ( file_exists($path."/".$filename) ) {
// Wrap our IO stuff so we catch any exceptions
try {
// Open the file for reading
$fp = fopen($path."/".$filename, "r");
if ($fp) {
// Loop line-by-line through the file
while($line = fgets($fp, 4096) !== false) {
// Only add the line if it doesn't contain $replaceItem
// This is case insensitive. I.E. 'item' == 'ITEM'
// For case sensitive, use strstr()
if ( stristr($line, $replaceItem) == false ) {
$newContents .= $line;
}
}
}
// Close our file
fclose($fp);
// Replace the contents of the file with the new contents
file_put_contents($path."/".$filename, $newContents);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
Edit: Try this. I modified it somewhat.

Related

Creating new files from an old one

while (($line = fgets($handle)) !== false) {
//look for the first payor block
if(strpos($line, 'N1*PR*') !== false || $block_start) {
$header_end = true; $block_start = true;
//see if the block finished
if(strpos($line, 'CAS*CO*45*20.43**253*1.27~') !== false) {
$block_start = false;
$payor_blocks[$count] .= $line;
$count++;
}
$payor_blocks[$count] .= $line;
} else {
//append to the header
if($header_end) {
$footer .= $line."\n";
} else {
$header .= $line."\n";
}
}
}
//get payor blocks and create a file foreach payor
$new_files = array();
foreach($payor_blocks as $block) {
$filename = $file . "_" . $count;
$count++;
$new_files[] = array(
'name' => $filename,
'content' => $header."\n".$block."\n".$footer
);
//loop through new files and create them
foreach($new_files as $new_file) {
$myfile = fopen($file, "x");
fwrite($myfile, $new_file['content']);
//close the file
fclose($myfile);
I have the code above, it's suppose to be able to open an original file called "$file" and create a new file then close it, However its not creating and when I run it, i get this warning error:
Warning: fopen(362931550.1a): failed to open stream:
File exists in /script2.php on line 90 Warning:
fwrite() expects parameter 1 to be resource,
boolean given in /script2.php on line 94 Warning:
fclose() expects parameter 1 to be resource, boolean
given in /script2.php on line 96
Any help is kindly appreciated.
I have one file named: 362931550.1a
I did a code that splits them at certain areas, (its pretty long to post), when i run the script I see it on my browser but it doesn't create 2 new files in the folder.
Your file open mode is incorrect.
From php.net documentation:
'x' Create and open for writing only; place the file pointer at the beginning of the file. If the file already exists, the fopen() call will fail by returning FALSE and generating an error of level E_WARNING [...]
You should probably use 'w' mode:
'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
The script failed to open a stream with the fopen() function and return a boolean. The function fwrite() become the boolean value but need a resource.
The reason is that you only create files with the x-modifier in the stream.
Create and open for writing only; place the file pointer at the beginning of the file. If the file already exists, the fopen() call will fail by returning FALSE and generating an error of level E_WARNING. If the file does not exist, attempt to create it.
You see in the PHP manual more informations about the stream-modes (PHP manual).
To prevent this message check if the value isn't false.
$stream = fopen("file.txt", "x");
if($stream === false) {
echo "Error while open stream";
}
//here your code

Push file to array in loop

EDIT after all the answers, i updated the function, and it works
I read out a importfolder. In this folder are many different files available.
Step: I read the folder and add the files to a array
Step: I open every file and try to import
When i cant import a file, then this happens, when another file in this row have to be imported first.
Example: If I open a file "message to a address", this could not be imported, when the address are not added into the database. But in some other file of this filelist is the "create address"-file. When this is created, then it is good, when the "message to a address" will be added to the filelistarray on the end.
My Code give me an offset problem:
function importData( $path, $db, $mail )
{
//Get available Importfiles
$filelist = getFilelist( $path );
for ($i = 0; $i < count($filelist); $i++)
{
$filename = $path . "/" . $filelist[$i];
$file = fopen( $filename,"r" );
while(!feof( $file )) {
$items = explode( ";", fgets( $file ) );
//Get messagetyp
if( strtolower(trim($items[0])) == "nachrichtentyp" )
{
$messagetyp = $items[1];
break;
}
}
fclose($file);
if ( $messagetyp )
{
$f = "import" . $messagetyp;
if( !$f($filename, $db, $mail) )
{
array_push($filelist, $filelist[$i]);
}
}
}
}
This my error, when I push the element to the the filelist-array
PHP Warning: feof() expects parameter 1 to be resource, boolean given in /var/www/symfony/importscript/import.php on line 37
PHP Warning: fgets() expects parameter 1 to be resource, boolean given in /var/www/symfony/importscript/import.php on line 38
According to your errors, problem lies not in array_push but in fopen():
$file = fopen( $filename,"r" );
If php fails to open that file, variable $file will be set to false and because of that feof() and fgets() will give you errors.
You definitely should check if fopen returns another value than FALSE, maybe one of the files does not exist or you are restricted.

I want to fetch contents of a file.txt and print it only up to a certain keyword php

Let's consider that there is a text file called 1.txt which has the following content.
wow<br>wow<br>wow<!--Read More--><br>wow<br>wow<br>wow<br>wow<br>wow<br>wow<br>
I want to display its contents only upto the <!--Read More-->
Presently am using fopen command to read and display whole text file.
$file_handle = fopen("posts/1.txt", "r");
while (!feof($file_handle)) {
$line_of_text = fgets($file_handle);
print $line_of_text;
}
Kindly someone help me with this...
$file_handle = fopen("posts/1.txt", "r");
while ((!feof($file_handle) && (($line_of_text = fgets($file_handle)) != "<!--Read More-->"))
{
print $line_of_text;
}
Warning: This works only if your "stop text" is always on the same line
You can use strstr() function to check if the line you read contains the string on which to stop.
Calling it with your line as the first parameter, the string searched as the second and true as the third parameter will return false if the string searched is not in the line or it will return the part of the line before the string searched.
$file_handle = fopen("posts/1.txt", "r");
while (!feof($file_handle)) {
/* Retrieve a line */
$line_of_text = fgets($file_handle);
/* Check if the stop text is in the line. If no returns false
else return the part of the string before the stop text */
$ret = strstr($line_of_text, "<!--Read More-->", true);
/* If stop text not found, print the line else print only the beginning */
if (false === $ret) {
print $line_of_text;
} else {
print $ret;
break;
}
}

Define array of file locations, parse and replace. Where's my error?

I'm trying to define an array with a list of file urls, and then have each file parsed and if a predefined string is found, for that string to be replaced. For some reason what I have isn't working, I'm not sure what's incorrect:
<?php
$htF = array('/home/folder/file.extension', '/home/folder/file.extension', '/home/folder/file.extension', '/home/folder/file.extension', '/home/folder/file.extension');
function update() {
global $htF;
$handle = fopen($htF, "r");
if ($handle) {
$previous_line = $content = '';
while (!feof($handle)) {
$current_line = fgets($handle);
if(stripos($previous_line,'PREDEFINED SENTENCE') !== FALSE)
{
$output = shell_exec('URL.COM');
if(preg_match('#([0-9]{1,3}\.){3}[0-9]{1,3}#',$output,$matches))
{
$content .= 'PREDEFINED SENTENCE '.$matches[0]."\n";
}
}else{
$content .= $current_line;
}
$previous_line = $current_line;
}
fclose($handle);
$tempFile = tempnam('/tmp','allow_');
$fp = fopen($tempFile, 'w');
fwrite($fp, $content);
fclose($fp);
rename($tempFile,$htF);
chown($htF,'admin');
chmod($htF,'0644');
}
}
array_walk($htF, 'update');
?>
Any help would be massively appreciated!
Do you have permissions to open the file?
Do you have permissions to write to /tmp ?
Do you have permissions to write to the destination file or folder?
Do you have permissions to chown?
Have you checked your regex? Try something like http://regexpal.com/ to see if it's valid.
Try adding error messages or throw Exceptions for all of the fail conditions for these.
there's this line:
if(stripos($previous_line,'PREDEFINED SENTENCE') !== FALSE)
and I think you just want a != in there. Yes?
You're using $htF within the update function as global, which means you're trying to fopen() an array.
$fh = fopen($htF, 'r');
is going to get parsed as
$fh = fopen('Array', 'r');
and return false, unless you happen to have a file named 'Array'.
You've also not specified any parameters for your function, so array_walk cannot pass in the array element it's dealing with at the time.

How to delete a line from the file with php?

I have a file named $dir and a string named $line, I know that this string is a complete line of that file but I don't know its line number and I want to remove it from file, what should I do?
Is it possible to use awk?
$contents = file_get_contents($dir);
$contents = str_replace($line, '', $contents);
file_put_contents($dir, $contents);
Read the lines one by one, and write all but the matching line to another file. Then replace the original file.
this 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. see this
$DELETE = "the_line_you_want_to_delete";
$data = file("./foo.txt");
$out = array();
foreach($data as $line) {
if(trim($line) != $DELETE) {
$out[] = $line;
}
}
$fp = fopen("./foo.txt", "w+");
flock($fp, LOCK_EX);
foreach($out as $line) {
fwrite($fp, $line);
}
flock($fp, LOCK_UN);
fclose($fp);
It can be solved without the use of awk:
function remove_line($file, $remove) {
$lines = file($file, FILE_IGNORE_NEW_LINES);
foreach($lines as $key => $line) {
if($line === $remove) unset($lines[$key]);
}
$data = implode(PHP_EOL, $lines);
file_put_contents($file, $data);
}
Another approach is to read the file line by line until you find a match, then truncate the file to that point, and then append the rest of the lines.
This is also good if you're looking for a substring (ID) in a line and want to replace the old line with the a new line.
Code:
$contents = file_get_contents($dir);
$new_contents = "";
if (strpos($contents, $id) !== false) { // if file contains ID
$contents_array = explode(PHP_EOL, $contents);
foreach ($contents_array as &$record) { // for each line
if (strpos($record, $id) !== false) { // if we have found the correct line
continue; // we've found the line to delete - so don't add it to the new contents.
} else {
$new_contents .= $record . "\r"; // not the correct line, so we keep it
}
}
file_put_contents($dir, $new_contents); // save the records to the file
echo json_encode("Successfully updated record!");
}
else {
echo json_encode("failed - user ID ". $id ." doesn't exist!");
}
Example:
input: "123,student"
Old file:
ID,occupation
123,student
124,brick layer
Running the code will change file to:
New file:
ID,occupation
124,brick layer
All answeres here have in common, that they load the complete file into the memory. Here is an implementation of removing one (or more) line(s) without coyping the files content into a variable.
The idea is to iterate over the files lines. If a line should be removed, the lines length is added to the $byte_offset. The next line is then moved $byte_offset bytes "upwards". This is done with all following lines. If all lines are processed, the files last $byte_offset bytes are removed.
I guess that this is faster for bigger files because nothing is copied. And I guess that at some file size the other answers do not work at all while this one should. But I didn't test it.
Usage:
$file = fopen("path/to/file", "a+");
// remove lines 1 and 2 and the line containing only "line"
fremove_line($file, 1, 2, "line");
fclose($file);
The code of the fremove_line() function:
/**
* Remove the `$lines` by either their line number (as an int) or their content
* (without trailing new-lines).
*
* Example:
* ```php
* $file = fopen("path/to/file", "a+"); // must be opened writable
* // remove lines 1 and 2 and the line containing only "line"
* fremove_line($file, 1, 2, "line");
* fclose($file);
* ```
*
* #param resource $file The file resource opened by `fopen()`
* #param int|string ...$lines The one-based line number(s) or the full line
* string(s) to remove, if the line does not exist, it is ignored
*
* #return boolean True on success, false on failure
*/
function fremove_line($file, ..$lines): bool{
// set the pointer to the start of the file
if(!rewind($file)){
return false;
}
// get the stat for the full size to truncate the file later on
$stat = fstat($file);
if(!$stat){
return false;
}
$current_line = 1; // change to 0 for zero-based $lines
$byte_offset = 0;
while(($line = fgets($file)) !== false){
// the bytes of the lines ("number of ASCII chars")
$line_bytes = strlen($line);
if($byte_offset > 0){
// move lines upwards
// go back the `$byte_offset`
fseek($file, -1 * ($byte_offset + $line_bytes), SEEK_CUR);
// move the line upwards, until the `$byte_offset` is reached
if(!fwrite($file, $line)){
return false;
}
// set the file pointer to the current line again, `fwrite()` added `$line_bytes`
// already
fseek($file, $byte_offset, SEEK_CUR);
}
// remove trailing line endings for comparing
$line_content = preg_replace("~[\n\r]+$~", "", $line);
if(in_array($current_line, $lines, true) || in_array($line_content, $lines, true)){
// the `$current_line` should be removed so save to skip the number of bytes
$byte_offset += $line_bytes;
}
// keep track of the current line
$current_line++;
}
// remove the end of the file
return ftruncate($file, $stat["size"] - $byte_offset);
}
Convert text to array, remove first line and reconvert to text
$line=explode("\r\n",$text);
unset($line[0]);
$text=implode("\r\n",$line);
I think the best way to work with files is to act them like strings:
/**
* Removes the first found line inside the given file.
*
* #param string $line The line content to be searched.
* #param string $filePath Path of the file to be edited.
* #param bool $removeOnlyFirstMatch Whether to remove only the first match or
* the whole matches.
* #return bool If any matches found (and removed) or not.
*
* #throw \RuntimeException If the file is empty.
* #throw \RuntimeException When the file cannot be updated.
*/
function removeLineFromFile(
string $line,
string $filePath,
bool $removeOnlyFirstMatch = true
): bool {
// You can wrap it inside a try-catch block
$file = new \SplFileObject($filePath, "r");
// Checks whether the file size is not zero
$fileSize = $file->getSize();
if ($fileSize !== 0) {
// Read the whole file
$fileContent = $file->fread($fileSize);
} else {
// File is empty
throw new \RuntimeException("File '$filePath' is empty");
}
// Free file resources
$file = null;
// Divide file content into its lines
$fileLineByLine = explode(PHP_EOL, $fileContent);
$found = false;
foreach ($fileLineByLine as $lineNumber => $thisLine) {
if ($thisLine === $line) {
$found = true;
unset($fileLineByLine[$lineNumber]);
if ($removeOnlyFirstMatch) {
break;
}
}
}
// We don't need to update file either if the line not found
if (!$found) {
return false;
}
// Join lines together
$newFileContent = implode(PHP_EOL, $fileLineByLine);
// Finally, update the file
$file = new \SplFileObject($filePath, "w");
if ($file->fwrite($newFileContent) !== strlen($newFileContent)) {
throw new \RuntimeException("Could not update the file '$filePath'");
}
return true;
}
Here is a brief description of what is being done: Get the whole file content, split the content into its lines (i.e. as an array), find the match(es) and remove them, join all lines together, and save the result back to the file (only if any changes happened).
Let's now use it:
// $dir is your filename, as you mentioned
removeLineFromFile($line, $dir);
Notes:
You can use fopen() family functions instead of SplFileObject, but I do recommend the object form, as it's exception-based, more robust and more efficient (in this case at least).
It's safe to unset() an element of an array being iterated using foreach (There's a comment here showing it can lead unexpected results, but it's totally wrong: As you can see in the example code, $value is copied (i.e. it's not a reference), and removing an array element does not affect it).
$line should not have new line characters like \n, otherwise, you may perform lots of redundant searches.
Don't use
$fileLineByLine[$lineNumber] = "";
// Or even
$fileLineByLine[$lineNumber] = null;
instead of
unset($fileLineByLine[$key]);
The reason is, the first case doesn't remove the line, it just clears the line (and an unwanted empty line will remain).
Hope it helps.
Like this:
file_put_contents($filename, str_replace($line . "\r\n", "", file_get_contents($filename)));

Categories