File
[ class tree: File ] [ index: File ] [ all elements ]

Source for file SearchReplace.php

Documentation is available at SearchReplace.php

  1. <?php
  2. // +-----------------------------------------------------------------------+
  3. // | Copyright (c) 2002-2005, Richard Heyes                                |
  4. // | All rights reserved.                                                  |
  5. // |                                                                       |
  6. // | Redistribution and use in source and binary forms, with or without    |
  7. // | modification, are permitted provided that the following conditions    |
  8. // | are met:                                                              |
  9. // |                                                                       |
  10. // | o Redistributions of source code must retain the above copyright      |
  11. // |   notice, this list of conditions and the following disclaimer.       |
  12. // | o Redistributions in binary form must reproduce the above copyright   |
  13. // |   notice, this list of conditions and the following disclaimer in the |
  14. // |   documentation and/or other materials provided with the distribution.|
  15. // | o The names of the authors may not be used to endorse or promote      |
  16. // |   products derived from this software without specific prior written  |
  17. // |   permission.                                                         |
  18. // |                                                                       |
  19. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
  20. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
  21. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  22. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
  23. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  24. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
  25. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  26. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  27. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
  28. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  29. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
  30. // |                                                                       |
  31. // +-----------------------------------------------------------------------+
  32. // | Author: Richard Heyes <richard@phpguru.org>                           |
  33. // +-----------------------------------------------------------------------+
  34. //
  35. // $Id: SearchReplace.php,v 1.12 2005/03/11 20:32:40 techtonik Exp $
  36. //
  37. // Search and Replace Utility
  38. //
  39.  
  40. /**
  41.  * Search and Replace Utility
  42.  *
  43.  *
  44.  * @author  Richard Heyes <richard@phpguru.org>
  45.  * @version 1.0
  46.  * @package File
  47.  */
  48. {
  49.     
  50.     // {{{ Properties (All private)
  51.  
  52.     var $find;
  53.     var $replace;
  54.     var $files;
  55.     var $directories;
  56.     var $include_subdir;
  57.     var $ignore_lines;
  58.     var $ignore_sep;
  59.     var $occurences;
  60.     var $search_function;
  61.     var $php5;
  62.     var $last_error;
  63.  
  64.     // }}}
  65.     // {{{ Constructor
  66.  
  67.     /**
  68.      * Sets up the object
  69.      *
  70.      * @access public
  71.      * @param string $find                      The string/regex to find.
  72.      * @param string $replace                   The string/regex to replace $find with.
  73.      * @param array  $files                     The file(s) to perform this operation on.
  74.      * @param array  $directories    (optional) The directories to perform this operation on.
  75.      * @param bool   $include_subdir            If performing on directories, whether to traverse subdirectories.
  76.      * @param array  $ignore_lines              Ignore lines beginning with any of the strings in this array. This
  77.      *                                           feature only works with the "normal" search.
  78.      */
  79.     function File_SearchReplace($find$replace$files$directories ''$include_subdir = TRUE$ignore_lines = array())
  80.     {
  81.  
  82.         $this->find            = $find;
  83.         $this->replace         = $replace;
  84.         $this->files           = $files;
  85.         $this->directories     = $directories;
  86.         $this->include_subdir  = $include_subdir;
  87.         $this->ignore_lines    = (array) $ignore_lines;
  88.  
  89.         $this->occurences      = 0;
  90.         $this->search_function = 'search';
  91.         $this->php5            = (substr(PHP_VERSION01== 5? TRUE : FALSE;
  92.         $this->last_error      = '';
  93.  
  94.     }
  95.  
  96.     // }}}
  97.     // {{{ getNumOccurences()
  98.  
  99.     /**
  100.      * Accessor to return the number of occurences found.
  101.      *
  102.      * @access public
  103.      * @return int Number of occurences found.
  104.      */
  105.     function getNumOccurences()
  106.     {
  107.         return $this->occurences;
  108.     }
  109.  
  110.     // }}}
  111.     // {{{ getLastError()
  112.  
  113.     /**
  114.      * Accessor for retrieving last error.
  115.      *
  116.      * @access public
  117.      * @return string The last error that occurred, if any.
  118.      */
  119.     function getLastError()
  120.     {
  121.         return $this->last_error;
  122.     }
  123.  
  124.     // }}}
  125.     // {{{ setFind()
  126.  
  127.     /**
  128.      * Accessor for setting find variable.
  129.      *
  130.      * @access public
  131.      * @param string $find The string/regex to find.
  132.      */
  133.     function setFind($find)
  134.     {
  135.         $this->find = $find;
  136.     }
  137.  
  138.     // }}}
  139.     // {{{ setReplace()
  140.  
  141.     /**
  142.      * Accessor for setting replace variable.
  143.      *
  144.      * @access public
  145.      * @param string $replace The string/regex to replace the find string/regex with.
  146.      */
  147.     function setReplace($replace)
  148.     {
  149.         $this->replace = $replace;
  150.     }
  151.  
  152.     // }}}
  153.     // {{{ setFiles()
  154.  
  155.     /**
  156.      * Accessor for setting files variable.
  157.      *
  158.      * @access public
  159.      * @param array $files The file(s) to perform this operation on.
  160.      */
  161.     function setFiles($files)
  162.     {
  163.         $this->files = $files;
  164.     }
  165.  
  166.     // }}}
  167.     // {{{ setDirectories()
  168.  
  169.     /**
  170.      * Accessor for setting directories variable.
  171.      *
  172.      * @access public
  173.      * @param array $directories The directories to perform this operation on.
  174.      */
  175.     function setDirectories($directories)
  176.     {
  177.         $this->directories = $directories;
  178.     }
  179.  
  180.     // }}}
  181.     // {{{ setIncludeSubdir
  182.  
  183.     /**
  184.      * Accessor for setting include_subdir variable.
  185.      *
  186.      * @access public
  187.      * @param bool $include_subdir Whether to traverse subdirectories or not.
  188.      */
  189.     function setIncludeSubdir($include_subdir)
  190.     {
  191.         $this->include_subdir = $include_subdir;
  192.     }
  193.  
  194.     // }}}
  195.     // {{{ setIgnoreLines()
  196.  
  197.     /**
  198.      * Accessor for setting ignore_lines variable.
  199.      *
  200.      * @access public
  201.      * @param array $ignore_lines Ignore lines beginning with any of the strings in this array. This
  202.      *                             feature only works with the "normal" search.
  203.      */
  204.     function setIgnoreLines($ignore_lines)
  205.     {
  206.         $this->ignore_lines = $ignore_lines;
  207.     }
  208.  
  209.     // }}}
  210.     // {{{ setSearchFunction()
  211.  
  212.     /**
  213.      * Function to determine which search function is used.
  214.      *
  215.      * @access public
  216.      * @param string The search function that should be used. Can be any one of:
  217.      *                normal - Default search. Goes line by line. Ignore lines feature only works with this type.
  218.      *                quick  - Uses str_replace for straight replacement throughout file. Quickest of the lot.
  219.      *                preg   - Uses preg_replace(), so any regex valid with this function is valid here.
  220.      *                ereg   - Uses ereg_replace(), so any regex valid with this function is valid here.
  221.      */
  222.     function setSearchFunction($search_function)
  223.     {
  224.         switch($search_function{
  225.         case 'normal'$this->search_function = 'search';
  226.             return TRUE;
  227.             break;
  228.  
  229.         case 'quick' $this->search_function = 'quickSearch';
  230.             return TRUE;
  231.             break;
  232.  
  233.         case 'preg'  $this->search_function = 'pregSearch';
  234.             return TRUE;
  235.             break;
  236.  
  237.         case 'ereg'  $this->search_function = 'eregSearch';
  238.             return TRUE;
  239.             break;
  240.  
  241.         default      : $this->last_error      = 'Invalid search function specified';
  242.             return FALSE;
  243.             break;
  244.         }
  245.     }
  246.  
  247.     // }}}
  248.     // {{{ search()
  249.  
  250.     /**
  251.      * Default ("normal") search routine.
  252.      *
  253.      * @access private
  254.      * @param string $filename The filename to search and replace upon.
  255.      * @return array Will return an array containing the new file contents and the number of occurences.
  256.      *                Will return FALSE if there are no occurences.
  257.      */
  258.     function search($filename)
  259.     {
  260.         $occurences = 0;
  261.         $file_array file($filename);
  262.  
  263.         if (empty($this->ignore_lines&& $this->php5// PHP5 acceleration
  264.             $file_array str_replace($this->find$this->replace$file_array$occurences);
  265.  
  266.         else // str_replace() doesn't return number of occurences in PHP4
  267.                  // so we need to count them manually and/or filter strings
  268.             $ignore_lines_num count($this->ignore_lines);
  269.  
  270.             // just for the sake of catching occurences
  271.             $local_find    array_values((array) $this->find);
  272.             $local_replace (is_array($this->replace)) array_values($this->replace$this->replace;
  273.  
  274.             for ($i=0; $i count($file_array)$i++{
  275.  
  276.                 if ($ignore_lines_num > 0{
  277.                     for ($j=0; $j $ignore_lines_num$j++{
  278.                         if (substr($file_array[$i],0,strlen($this->ignore_lines[$j])) == $this->ignore_lines[$j]continue 2;
  279.                     }
  280.                 }
  281.  
  282.                 if ($this->php5{
  283.                     $file_array[$istr_replace($this->find$this->replace$file_array[$i]$counted);
  284.                     $occurences += $counted;
  285.                 else {
  286.                     foreach ($local_find as $fk => $ff{
  287.                         $occurences += substr_count($file_array[$i]$ff);
  288.                         if (!is_array($local_replace)) {
  289.                             $fr $local_replace;
  290.                         else {
  291.                             $fr (isset($local_replace[$fk])) $local_replace[$fk"";
  292.                         }
  293.                         $file_array[$istr_replace($ff$fr$file_array[$i]);
  294.                     }
  295.                 }
  296.             }
  297.  
  298.         }
  299.         if ($occurences > 0$return = array($occurencesimplode(''$file_array)); else $return = FALSE;
  300.         return $return;
  301.  
  302.     }
  303.  
  304.     // }}}
  305.     // {{{ quickSearch()
  306.  
  307.     /**
  308.      * Quick search routine.
  309.      *
  310.      * @access private
  311.      * @param string $filename The filename to search and replace upon.
  312.      * @return array Will return an array containing the new file contents and the number of occurences.
  313.      *                Will return FALSE if there are no occurences.
  314.      */
  315.     function quickSearch($filename)
  316.     {
  317.  
  318.         clearstatcache();
  319.  
  320.         $file          fread($fp fopen($filename'r')filesize($filename))fclose($fp);
  321.         $local_find    array_values((array) $this->find);
  322.         $local_replace (is_array($this->replace)) array_values($this->replace$this->replace;
  323.  
  324.         $occurences    = 0;
  325.  
  326.         // logic is the same as in str_replace function with one exception:
  327.         //   if <search> is a string and <replacement> is an array - substitution
  328.         //   is done from the first element of array. str_replace in this case
  329.         //   usualy fails with notice and returns "ArrayArrayArray..." string
  330.         // (this exclusive logic of SearchReplace will not work for php5, though,
  331.         // because I haven't decided yet whether it is bug or feature)
  332.  
  333.         if ($this->php5{
  334.             $file_array[$istr_replace($this->find$this->replace$file_array[$i]$counted);
  335.             $occurences += $counted;
  336.         else {
  337.             foreach ($local_find as $fk => $ff{
  338.                 $occurences += substr_count($file$ff);
  339.                 if (!is_array($local_replace)) {
  340.                     $fr $local_replace;
  341.                 else {
  342.                     $fr (isset($local_replace[$fk])) $local_replace[$fk"";
  343.                 }
  344.                 $file str_replace($ff$fr$file);
  345.             }
  346.         }
  347.  
  348.         if ($occurences > 0$return = array($occurences$file); else $return = FALSE;
  349.         return $return;
  350.  
  351.     }
  352.  
  353.     // }}}
  354.     // {{{ pregSearch()
  355.  
  356.     /**
  357.      * Preg search routine.
  358.      *
  359.      * @access private
  360.      * @param string $filename The filename to search and replace upon.
  361.      * @return array Will return an array containing the new file contents and the number of occurences.
  362.      *                Will return FALSE if there are no occurences.
  363.      */
  364.     function pregSearch($filename)
  365.     {
  366.  
  367.         clearstatcache();
  368.  
  369.         $file       fread($fp fopen($filename'r')filesize($filename))fclose($fp);
  370.         $local_find    array_values((array) $this->find);
  371.         $local_replace (is_array($this->replace)) array_values($this->replace$this->replace;
  372.  
  373.         $occurences = 0;
  374.  
  375.         foreach($local_find as $fk => $ff{
  376.             $occurences += preg_match_all($ff$file$matches);
  377.             if (!is_array($local_replace)) {
  378.                 $fr $local_replace;
  379.             else {
  380.                 $fr (isset($local_replace[$fk])) $local_replace[$fk"";
  381.             }
  382.             $file preg_replace($ff$fr$file);
  383.         }
  384.  
  385.         if ($occurences > 0$return = array($occurences$file); else $return = FALSE;
  386.         return $return;
  387.  
  388.     }
  389.  
  390.     // }}}
  391.     // {{{ eregSearch()
  392.  
  393.     /**
  394.      * Ereg search routine.
  395.      *
  396.      * @access private
  397.      * @param string $filename The filename to search and replace upon.
  398.      * @return array Will return an array containing the new file contents and the number of occurences.
  399.      *                Will return FALSE if there are no occurences.
  400.      */
  401.     function eregSearch($filename)
  402.     {
  403.  
  404.         clearstatcache();
  405.  
  406.         $file fread($fp fopen($filename'r')filesize($filename))fclose($fp);
  407.         $local_find    array_values((array) $this->find);
  408.         $local_replace (is_array($this->replace)) array_values($this->replace$this->replace;
  409.  
  410.         $occurences = 0;
  411.  
  412.         foreach($local_find as $fk => $ff{
  413.             $occurences += count(split($ff$file)) - 1;
  414.             if (!is_array($local_replace)) {
  415.                 $fr $local_replace;
  416.             else {
  417.                 $fr (isset($local_replace[$fk])) $local_replace[$fk"";
  418.             }
  419.             $file ereg_replace($ff$fr$file);
  420.         }
  421.  
  422.         if ($occurences > 0$return = array($occurences$file); else $return = FALSE;
  423.         return $return;
  424.  
  425.     }
  426.  
  427.     // }}}
  428.     // {{{ writeout()
  429.     
  430.     /**
  431.      * Function to writeout the file contents.
  432.      *
  433.      * @access private
  434.      * @param string $filename The filename of the file to write.
  435.      * @param string $contents The contents to write to the file.
  436.      */
  437.     function writeout($filename$contents)
  438.     {
  439.  
  440.         if ($fp @fopen($filename'w')) {
  441.             flock($fp,2);
  442.             fwrite($fp$contents);
  443.             flock($fp,3);
  444.             fclose($fp);
  445.         else {
  446.             $this->last_error = 'Could not open file: '.$filename;
  447.         }
  448.  
  449.     }
  450.  
  451.     // }}}
  452.     // {{{ doFiles()
  453.  
  454.     /**
  455.      * Function called by doSearch() to go through any files that need searching.
  456.      *
  457.      * @access private
  458.      * @param string $ser_func The search function to use.
  459.      */
  460.     function doFiles($ser_func)
  461.     {
  462.         if (!is_array($this->files)) $this->files = explode(','$this->files);
  463.         for ($i=0; $i<count($this->files)$i++{
  464.             if ($this->files[$i== '.' OR $this->files[$i== '..'continue;
  465.             if (is_dir($this->files[$i]== TRUEcontinue;
  466.             $newfile $this->$ser_func($this->files[$i]);
  467.             if (is_array($newfile== TRUE){
  468.                 $this->writeout($this->files[$i]$newfile[1]);
  469.                 $this->occurences += $newfile[0];
  470.             }
  471.         }
  472.     }
  473.  
  474.     // }}}
  475.     // {{{ doDirectories()
  476.  
  477.     /**
  478.      * Function called by doSearch() to go through any directories that need searching.
  479.      *
  480.      * @access private
  481.      * @param string $ser_func The search function to use.
  482.      */
  483.     function doDirectories($ser_func)
  484.     {
  485.         if (!is_array($this->directories)) $this->directories = explode(','$this->directories);
  486.         for ($i=0; $i<count($this->directories)$i++{
  487.             $dh opendir($this->directories[$i]);
  488.             while ($file readdir($dh)) {
  489.                 if ($file == '.' OR $file == '..'continue;
  490.  
  491.                 if (is_dir($this->directories[$i].$file== TRUE{
  492.                     if ($this->include_subdir == TRUE{
  493.                         $this->directories[$this->directories[$i].$file.'/';
  494.                         continue;
  495.                     else {
  496.                         continue;
  497.                     }
  498.                 }
  499.  
  500.                 $newfile $this->$ser_func($this->directories[$i].$file);
  501.                 if (is_array($newfile== TRUE{
  502.                     $this->writeout($this->directories[$i].$file$newfile[1]);
  503.                     $this->occurences += $newfile[0];
  504.                 }
  505.             }
  506.         }
  507.     }
  508.  
  509.     // }}}
  510.     // {{{ doSearch()
  511.     
  512.     /**
  513.      * This starts the search/replace off. Call this to do the search.
  514.      * First do whatever files are specified, and/or if directories are specified,
  515.      * do those too.
  516.      *
  517.      * @access public
  518.      */
  519.     function doSearch()
  520.     {
  521.         $this->occurences = 0;
  522.         if ($this->find != ''{
  523.             if ((is_array($this->filesAND count($this->files> 0OR $this->files != ''$this->doFiles($this->search_function);
  524.             if ($this->directories != '')                                                   $this->doDirectories($this->search_function);
  525.         }
  526.     }
  527.     
  528.     // }}}
  529.  
  530. }
  531. ?>

Documentation generated on Mon, 11 Mar 2019 14:05:37 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.