I am trying to do a string replace for entire file in PHP. My file is over 100MB so I have to go line by line and can not use file_get_contents()
. Is there a good solution to this?
-
2Is it necessary to use PHP? If you have access to the command line, you could use the `sed` command to perform this same function, probably with a much less of a headache. If it needs to be automated, you can make a shell script that runs on cron. – Dominic Barnes Jan 29 '10 at 01:05
-
1Agreed, this is something for the command line, not PHP. – Mike Jan 29 '10 at 01:20
6 Answers
If you aren't required to use PHP, I would highly recommend performing stuff like this from the command line. It's by far the best tool for the job, and much easier to use.
In any case, the sed
(Stream Editor) command is what you are looking for:
sed s/search/replace oldfilename > newfilename
If you need case-insensitivity:
sed s/search/replace/i oldfilename > newfilename
If you need this to perform dynamically within PHP, you can use passthru()
:
$output = passthru("sed s/$search/$replace $oldfilename > $newfilename");

- 2,363
- 2
- 26
- 51

- 28,083
- 8
- 65
- 90
-
1
-
4Either would work, but using passthru, you can get the entire output. exec only returns the last line of the output. – Dominic Barnes Jan 29 '10 at 04:29
-
it's not that easy to use passthru to call sed, see my answer for details. – Riccardo Galli Jun 26 '13 at 10:24
-
For case-insensitivity: ```sed s/search/replace/i old_file > new_file``` [man sed](https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command) – Stack Underflow Apr 07 '20 at 16:56
-
I know this is too old.. but haw can I try to use sed to replace Ø to Ø ```"sed 's/Ø/Ø' {$this->xml->path} > {$this->xml->path}"``` but I get this error sh: 1: Oslash: not found sed: -e expression #1, char 2: unterminated `s' command sh: 1: /Ø: not found – Sean Reyes May 01 '20 at 08:56
Here you go:
function replace_file($path, $string, $replace)
{
set_time_limit(0);
if (is_file($path) === true)
{
$file = fopen($path, 'r');
$temp = tempnam('./', 'tmp');
if (is_resource($file) === true)
{
while (feof($file) === false)
{
file_put_contents($temp, str_replace($string, $replace, fgets($file)), FILE_APPEND);
}
fclose($file);
}
unlink($path);
}
return rename($temp, $path);
}
Call it like this:
replace_file('/path/to/fruits.txt', 'apples', 'oranges');
-
6It was kind of a joke. I don't know why it would have been funny. I'm going to give it to our JDT (Joke Development Team) and get back to you in 6 to 8 weeks. – Tyler Carter Jan 29 '10 at 02:51
If you can't use directly sed from command line because it's a dynamic task and you need to call it from php it's difficult to get the syntax right: you must escape in different ways in the search and replacement strings these characters
' / $ . * [ ] \ ^ &
The following function search and replace a string in a file without interpreting the searched string as a regular expression. So if you wanted you could search for the string ".*" and replace it with "$".
/**
* str_replace_with_sed($search, $replace, $file_in, $file_out=null)
*
* Search for the fixed string `$search` inside the file `$file_in`
* and replace it with `$replace`. The replace occurs in-place unless
* `$file_out` is defined: in that case the resulting file is written
* into `$file_out`
*
* Return: sed return status (0 means success, any other integer failure)
*/
function str_replace_with_sed($search, $replace, $file_in, $file_out=null)
{
$cmd_opts = '';
if (! $file_out)
{
// replace inline in $file_in
$cmd_opts .= ' -i';
}
// We will use Basic Regular Expressions (BRE). This means that in the
// search pattern we must escape
// $.*[\]^
//
// The replacement string must have these characters escaped
// \ &
//
// In both cases we must escape the separator character too ( usually / )
//
// Since we run the command trough the shell we We must escape the string
// too (yai!). We're delimiting the string with single quotes (') and we'll
// escape them with '\'' (close string, write a single quote, reopen string)
// Replace all the backslashes as first thing. If we do it in the following
// batch replace we would end up with bogus results
$search_pattern = str_replace('\\', '\\\\', $search);
$search_pattern = str_replace(array('$', '.', '*', '[', ']', '^'),
array('\\$', '\\.', '\\*', '\\[', '\\]', '\\^'),
$search_pattern);
$replace_string = str_replace(array('\\', '&'),
array('\\\\', '\\&'),
$replace);
$output_suffix = $file_out ? " > '$file_out' " : '';
$cmd = sprintf("sed ".$cmd_opts." -e 's/%s/%s/g' \"%s\" ".$output_suffix,
str_replace('/','\\/', # escape the regexp separator
str_replace("'", "'\''", $search_pattern) // sh string escape
),
str_replace('/','\\/', # escape the regexp separator
str_replace("'", "'\''", $replace_string) // sh string escape
),
$file_in
);
passthru($cmd, $status);
return $status;
}

- 12,419
- 6
- 64
- 62
I would have used 'sed' in a more explicit way, so you are less dependent of your system.
$output = passthru("sed -e 's/$search/$replace/g' $oldfilename > $newfilename");

- 8,676
- 7
- 43
- 56

- 609
- 1
- 5
- 18
Get it a few lines at a time, dump the variable, get the next few lines.
$fh = fopen("bigfile.txt", "flags");
$num = 0;
$length = 300;
$filesize = filesize("bigfile.txt");
while($num < $filesize)
{
$contents = fread($fh, $length);
// .. do stuff ...
$num = $num+$length;
fseek($fh, $num);
}
fclose($fh);
You are going to want to make sure that is correct (haven't tested). See the library on PHP Documentation.
The tricky part is going to be writing back to the file. The first idea that pops into my mind is do the string replace, write the new content to another file, and then at the end, delete the old file and replace it with the new one.

- 60,743
- 20
- 130
- 150
-
1yea that's right... a poor man's streaming. That effectively how it would work if you did it on the command line: cat file | sed 's/replace/something/g' > output.file – mlathe Jan 29 '10 at 00:27
-
1I would run a php script that called the command line function -- then printed out the output file :) – Dirk Jan 29 '10 at 00:32
-
3This method has a problem if the string you're looking to replace is longer than a single character. It's quite possible that the string could span multiple chunks of data, causing you to skip the replacement. – bish Jan 29 '10 at 04:36
something like this?
$infile="file";
$outfile="temp";
$f = fopen($infile,"r");
$o = fopen($outfile,"a");
$pattern="pattern";
$replace="replace";
if($f){
while( !feof($f) ){
$line = fgets($f,4096);
if ( strpos($pattern,"$line") !==FALSE ){
$line=str_replace($pattern,$replace,$line);
}
fwrite($o,$line);
}
}
fclose($f);
fclose($o);
rename($outfile,$infile);

- 327,991
- 56
- 259
- 343
-
1Typically I like solutions with pure php but I think in this case 'my case' `sed` will work better. I can't guarantee my mysql dump file won't have lines > 4096 chars and that a string won't exist in that break point. – Richard Tyler Miles Feb 28 '22 at 21:34