Search code examples
phparrayswordpressfile-get-contentsstr-replace

String replacement within multiple files


I have this function that will search and replace a given term inside a php file. When I pass an array with multiple files, the files are not modified and to avoid this problem I can only pass two files at time. How I can fix or improve this function? I think that the issue is because multiple files will occupy too much memory, but I'm not sure about this. Any help is appreciated. (I'm testing the function using a wordpress installation to find and replace the wp-prefix of some folders and files).

function wp_settings_edit(array $filename, array $patterns, array $replace){
  foreach($filename as $file){
    $wp_file = file_get_contents(__DIR__."/{$file}");
    foreach($patterns as $pattern){
      foreach($replace as $r){
      $wp_file_content = file_put_contents(__DIR__."/{$file}",str_replace("{$pattern}", "{$r}", $wp_file));
      }
    }
  }
}

Usage example:

 $files = array('wp-settings.php', 'wp-load.php');
 $patterns = array('wp-admin', 'wp-includes');
 $replace = array('admin', 'includes');
 wp_settings_edit($files, $patterns, $replace); 

Solution

  • Unless your files are very large – like hundreds of megabytes – you're certainly not running into memory limits. You are, however, doing this quite inefficiently.

    You run a foreach loop on both the search and replace arrays, making an exponential increase in the number of file writes. If str_replace() only accepted string arguments, you could get rid of one of these loops. However, it accepts array arguments, so you can get rid of both.

    function wp_settings_edit(array $filename, array $patterns, array $replace){
        foreach($filename as $file){
            $wp_file = file_get_contents(__DIR__ . "/$file");
            file_put_contents(__DIR__ . "/$file", str_replace($patterns, $replace, $wp_file));
        }
    }
    

    This will improve efficiency and what's more, it will actually do the job you want it to. By doing a nested loop over both arrays, as in the original code, you would end up replacing every item in the search array with only the first element of the replacements array:

    $s = ["foo", "bar", "baz"];
    $r = ["oof", "rab", "zab"];
    $h = "Here is some foo text as well as some bar text and maybe some baz text.";
    foreach ($s as $s1) foreach ($r as $r1) $h = str_replace($s1, $r1, $h);
    echo $h;
    

    Output:

    Here is some oof text as well as some oof text and maybe some oof text.