Find string and replace multiple values in a large text file using PHP

389 Views Asked by At

I am trying to replace certain values in large text file having approx. 60,000 lines. First time code executes fine and replacing values but in next time it skips line numbers and append new values at end of file.

I am a beginner in coding, so I might need extended guidance.

Lines I need to change :

  1. MaxBytes[192.168.1.1]: 10000. This 1000 may be any number but IP address will be unique here. I need to change it MaxBytes[192.168.1.1]: 20000 (Assigned number);

  2. <TR><TD>Max Speed:</TD> <TD>200</TD></TR> This 200 may be any number. I am tracing <TR><TD>IP Address:</TD><TD>192.168.1.1</TD></TR> line and replacing next line since IP address is unique here.I need to change it to <TR><TD>Max Speed:</TD> <TD>500</TD></TR>

Sample Example.txt:

MaxBytes[192.168.1.1]: 10000
 <TABLE>
   <TR><TD>IP Address:</TD><TD>192.168.1.1</TD></TR>
   <TR><TD>Max Speed:</TD> <TD>300</TD></TR>
 </TABLE>

MaxBytes[192.168.1.2]: 30000
 <TABLE>
   <TR><TD>IP Address:</TD><TD>192.168.1.1</TD></TR>
   <TR><TD>Max Speed:</TD> <TD>300</TD></TR>
 </TABLE>

MaxBytes[192.168.1.3]: 10000
 <TABLE>
   <TR><TD>IP Address:</TD><TD>192.168.1.1</TD></TR>
   <TR><TD>Max Speed:</TD> <TD>200</TD></TR>
 </TABLE>

Here is the codes I am using

<?php
$dir = "Example.txt";
$search = "<TR><TD>IP Address:</TD><TD>192.168.1.1</TD></TR>";
$replacement = "   <TR><TD>Max Speed:</TD> <TD>500</TD></TR>";
$maxbytes = "MaxBytes[192.168.1.1]: ";
$new_line = "MaxBytes[192.168.1.1]: \r";
$newmaxbytes = "MaxBytes[192.168.1.1]: 20000";


///// Change Max Speed
function find_line_number_by_string($dir, $search, $case_sensitive=false ) {
        $line_number = '';
        if ($file_handler = fopen($dir, "r")) {
           $i = 0;
           while ($line = fgets($file_handler)) {
              $i++;
              //case sensitive is false by default
              if($case_sensitive == false) {    
                $search = strtolower($search); 
                $line = strtolower($line);      
              }
              //find the string and store it in an array
              if(strpos($line, $search) !== false){
                $line_number .=  $i.",";
              }
           }
           fclose($file_handler);
        }else{
            return "File not exists, Please check the file path or dir";
        }
        //if no match found
        if(count($line_number)){
            return substr($line_number, 0, -1);
        }else{
            return "No match found";
        }
    }

$line_number = find_line_number_by_string($dir, $search);
echo $line_number;

$lines = file($dir, FILE_IGNORE_NEW_LINES);
$lines[$line_number] = $replacement;
file_put_contents($dir , implode("\n", $lines));

///// Change MaxBytes

$contents = file_get_contents($dir);
$new_contents= "";
if( strpos($contents, $maxbytes) !== false) { // if file contains ID
    $contents_array = preg_split("/\\r\\n|\\r|\\n/", $contents);
    foreach ($contents_array as &$record) {    // for each line
        if (strpos($record, $maxbytes) !== false) { // if we have found the correct line
            $new_contents .= $new_line; // change record to new record
        }else{
            $new_contents .= $record . "\r";
        }
    }

file_put_contents($dir, $new_contents, LOCK_EX);

$fhandle = fopen($dir,"r");
$content = fread($fhandle,filesize($dir));
$content = str_replace($maxbytes, $newmaxbytes, $content);
$fhandle = fopen($dir,"w");
fwrite($fhandle,$content);
fclose($fhandle);

}else{}

?>
2

There are 2 best solutions below

5
Yerke On BEST ANSWER

There is something not fully understandable in your question and code, of course it can be written in more optimal way.
However considering the current code you share, I suppose this changed variant the one you need.

<?php
$dir = "Example.txt";
$search = "<TR><TD>IP Address:</TD><TD>192.168.1.1</TD></TR>";
$replacement = "   <TR><TD>Max Speed:</TD> <TD>10000</TD></TR>";
$maxbytes = "MaxBytes[192.168.1.1]: ";
$new_line = "MaxBytes[192.168.1.1]: \r";
$newmaxbytes = "MaxBytes[192.168.1.1]: 20000";


///// Change Max Speed
function find_line_number_by_string($dir, $search, $case_sensitive=false ) {
    $line_number = [];
    if ($file_handler = fopen($dir, "r")) {
        $i = 0;
        while ($line = fgets($file_handler)) {
            $i++;
            //case sensitive is false by default
            if($case_sensitive == false) {
                $search = strtolower($search);
                $line = strtolower($line);
            }
            //find the string and store it in an array
            if(strpos($line, $search) !== false){
                $line_number[] =  $i;
            }
        }
        fclose($file_handler);
    }else{
        return "File not exists, Please check the file path or dir";
    }

    return $line_number;
}

$line_number = find_line_number_by_string($dir, $search);
var_dump($line_number);


$lines = file($dir, FILE_IGNORE_NEW_LINES);
if(!empty($line_number)) {
    $lines[$line_number[0]] = $replacement;
}

file_put_contents($dir , implode("\n", $lines));

///// Change MaxBytes

$contents = file_get_contents($dir);
$new_contents= "";
if( strpos($contents, $maxbytes) !== false) { // if file contains ID
    $contents_array = preg_split("/\\r\\n|\\r|\\n/", $contents);
    foreach ($contents_array as &$record) {    // for each line
        if (strpos($record, $maxbytes) !== false) { // if we have found the correct line
            $new_contents .= $new_line; // change record to new record
        }else{
            $new_contents .= $record . "\n";
        }
    }

    file_put_contents($dir, $new_contents, LOCK_EX);

    $fhandle = fopen($dir,"r");
    $content = fread($fhandle,filesize($dir));
    $content = str_replace($maxbytes, $newmaxbytes, $content);
    $fhandle = fopen($dir,"w");
    fwrite($fhandle,$content);
    fclose($fhandle);

}else{}

?>

If it does not works the way you need, please contact me, I'll update the answer..

1
Adrian Baginski On

That's because you remove all new lines, but don't add new ones, just carriage returns.

Fix by inserting the following in line 58:

$new_contents .= $record . "\n";

A carriage return (\r) jumps to the next to the next line but doesn't end the current one. You need a line feed for that (\n). After running your code for the second time, PHP thinks the textfile is just one line of text.