Tuesday, March 15, 2011

Recursive find and replace with Regex SubPattern in PHP

SkyHi @ Tuesday, March 15, 2011
<?php

### Requirements  ###
/*
 * Replace 
 * <a style="font-size: 13px;" href="url">
 * with
 * <a onclick="location.href='url';">
*/

### The following are test samples ###
#$string = '<a href="featuredwines.php">';
#$string = '<a style="font-size: 13px;" href="bookmarks.php?id=0000000113&add=0000000113&main=1&varietal=&chi=&vhi="';
#$string = '<a href="wine.php?id=0000000234&main=1&varietal=&chi=&vhi=&whi="';
#$string = "<a href='main.php?main=2&pricelist=1&sml='";
$string = '<a href="wine.php?id=0000000196&main=1&varietal=&chi=&vhi=&whi=&pri="';

#$pattern = '/(\<a href=")(.*?)(")/i';
##same
#$pattern = "/(\<a)(.*?)(href=\")(.*?)(\"|')/i";
##good one
#$pattern = '/(\<a)(.*?)(href="|\')(.*?)["|\']/i';
#$pattern = '/(<a)(.*?)(href=\'|")(.*?)("|\')/i';
$pattern = '/(<a)(.*?)(href=[\'"])(.*?)([\'"])/i';

#$replacement = '<a onclick="location.href=\'$2\';"';
$replacement = '<a$2onclick="location.href=\'$4\';"';

echo preg_replace($pattern, $replacement, $string);
?>


PHP CLI: Recursive Search and Replace
<?php
//=== Recursive File Search and replace  ==========================================
// Inputs:  $start_dir   Absolute or relative path to starting folder. Do not
//                       include a forward slash at the end. c:/test ./test
//          $file_type   A regex patern containg file types to be searched
//                       e.g.  $file_type = '/(\.txt|\.cnf|\.conf)/'
//          $search_str  A regex patern e.g $search_str  = '/\nListen\s\d+/'
//          $replace_str A plain text string e.g. $replace_str = "\nListen 8080"
//
// Output:  Returns true --- Need to add error checking
//
// Notes :  Searches for files of the specified type starting at $start_dir and
//          incluse all sub-folders. Each file found a search and replace is
//          performed.
//
// -----------------------------------------------------------------------------------

function file_sr_global($start_dir,$file_type,$search_str,$replace_str){

  $dirlist = opendir($start_dir);                // Open start directory

  while ($file = readdir($dirlist)){             // Iterate through list
    if ($file != '.' && $file != '..'){          // Skip if . or ..
      $newpath = $start_dir.'/'.$file;           // Create path. Either dir or file

      if (is_dir($newpath)){                     // Is it a folder
                                                 // yes: Repeat this function
        file_sr_global($newpath,$file_type,$search_str,$replace_str);
      }                                          // for that new folder
      else{                                      // no: Its a file
       if (preg_match($file_type, $newpath)){    // Filter by file extension.

         $fh = fopen($newpath, 'r');             // Open file for read
         $Data = fread($fh, filesize($newpath)); // Read all data into variable
         fclose($fh);                            // Close file handle

         $Data = preg_replace($search_str, $replace_str, $Data,-1,$count);// S & R
         if($count){                             // Was a replacement made
           $fh = fopen($newpath, 'w');           // yes: Open file for write
           fwrite($fh, $Data);                   // Write new $Data to file
           fclose($fh);                          // Close file handle
           echo $newpath." Replaced ".$count."\n"; //***** Delete this line *******
         }
       }
      }//eof else
    }
  }//eof while

  closedir($dirlist);                          // Close handle
  return true;                                 // Return
}
//=================================== END Recursive File Search and replace  ======

$start_dir = '/home/searchandreplace/mark';             // Start folder
$file_type = '/(\.txt|\.php|\.conf)/';  // Filter, required files


#$search_str = '/(\<a)(.*?)(href=")(.*?)("|')/i';
#$search_str = '/(\<a)(.*?)(href="|\')(.*?)("|\')/i';
#$search_str = '/(<a)(.*?)(href=[\'"])(.*?)("|\')/i';
/*
 * Each (parameter) is a subpattern, each pattern will be replaced by the
 * $replacement counterpart($1,$2...etc).
 * Leave $2 and $4 intact
 *  #[\'"] present the OR, couldn't get (\'|") to work???
 */
$search_str = '/(<a)(.*?)(href=[\'"])(.*?)([\'"])/i';
$replace_str = '<a$2onclick="location.href=\'$4\';"';

if(file_sr_global($start_dir,$file_type,$search_str,$replace_str)){
        echo "\n Search and replace complete\n";
}

exit(0);

?>

REFERENCES
http://ca3.php.net/manual/en/function.preg-replace.php
http://ca3.php.net/manual/en/reference.pcre.pattern.modifiers.php
http://wiki.uniformserver.com/index.php/PHP_CLI:_Recursive_Search_and_Replace
http://hubpages.com/hub/Regex-SubPattern-in-PHP
http://beaver6813.com/2010/04/php-search-and-replace-directory-recursively/
http://darcyclarke.me/development/php-recursive-find-and-replace/