File Operation Again

From: Date: Mon, 30 Jul 2001 10:43:37 +0000
Subject: File Operation Again
Groups: php.pear.dev 
Request: Send a blank email to pear-dev+get-1145@lists.php.net to get a copy of this message
I hope this one comes through, I've renamed it to .txt. I also had an error in the example Valid criteria's right now are FILE_CRITERIA_BIGGER FILE_CRITERIA_SMALLER FILE_CRITERIA_EQUAL ( the above take parameters as 100 for bytes, 100KB for kilobytes, 100MB 100GB) FILE_CRITERIA_OLDER FILE_CRITERIA_OLDER_MINUTES FILE_CRITERIA_OLDER_DAYS FILE_CRITERIA_OLDER_HOURS FILE_CRITERIA_NEWER FILE_CRITERIA_NEWER_* (file name matching is not complete) <?php include("File/Operation.php"); include("File/Find.php"); function errorFunc($err){ print($err->getMessage()); die(); } PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'errorFunc'); $filefind = new File_Find(); $files = $filefind->maptree("c:/temp/"); $op = new File_Operation(); $op->debug = true; $op->run(&$files[1], FILE_CRITERIA_BIGGER, "10MB" , FILE_OPERATION_MOVE, "c:/big_files/"); print_r($op->failed_reasons); ?> I also managed to squeeze in a new feature, if you use the runHtml() method it will display an html form that will give access to most of the features. ex <?php include("PEAR.php"); include("File/Find.php"); include("File/Operation.php"); PEAR::setErrorHandling(PEAR_ERROR_PRINT); $op = new File_Operation(); $op->runHtml(); ?> The difference between a good man and a bad one is the choice of cause - William James

<?php // +----------------------------------------------------------------------+ // | PHP version 4.0 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Yavor Shahpasov <yavo@itenasolutions.com> | // +----------------------------------------------------------------------+ // // $Id: Config.php,v 1.5 2001/07/27 11:53:35 alexmerz Exp $ require_once("PEAR.php"); /** * A class to apply operations on number of files * * Usefull when you need to apply some operations on a number of files * XXX Todo Make multiple criterias. i.e. * XXX Add more actions (i.e. Output to screen, encode, encrypt, compress) * XXX Fix error handling add error codes, make an error class etc * ex: * include("File/Operation.php"); * include("File/Find.php"); * * $filefind = new File_Find(); * $files = $filefind->maptree("c:/temp/"); * $op = new File_Operation(); * $op->debug = true; * $op->run(&$files[1], FILE_CRITERIA_OLDER_DAYS, "10" , FILE_OPERATION_MOVE, "c:/trash/"); * print_r($op->failed_reasons); * * @author Yavor Shahpasov <yavo@itenasolutions.com> * @access public * @version $Revision$ * @package File */ /** Note, this could be implemented with bitmasks to support multiple Criterias */ /** The size of the file is bigger than some value */ define(FILE_CRITERIA_BIGGER_THAN, 0); /** The size of the file is bigger than some value */ define(FILE_CRITERIA_BIGGER, 0); /** The size of the file is smaller than some value */ define(FILE_CRITERIA_SMALLER_THAN, 1); /** The size of the file is smaller than some value */ define(FILE_CRITERIA_SMALLER, 1); /** The size of the file is equal to some value */ define(FILE_CRITERIA_EQUAL, 2); /** The file creation date is older than some value */ define(FILE_CRITERIA_OLDER_THAN, 3); define(FILE_CRITERIA_OLDER, 3); define(FILE_CRITERIA_OLDER_THAN_SECONDS, 3); define(FILE_CRITERIA_OLDER_SECONDS, 3); define(FILE_CRITERIA_OLDER_THAN_MINUTES, 4); define(FILE_CRITERIA_OLDER_MINUTES, 4); define(FILE_CRITERIA_OLDER_THAN_HOURS, 5); define(FILE_CRITERIA_OLDER_HOURS, 5); define(FILE_CRITERIA_OLDER_THAN_DAYS, 6); define(FILE_CRITERIA_OLDER_DAYS, 6); /** The file creation date is newer than some value */ define(FILE_CRITERIA_NEWER_THAN, 7); define(FILE_CRITERIA_NEWER, 7); define(FILE_CRITERIA_NEWER_THAN_SECONDS, 7); define(FILE_CRITERIA_NEWER_SECONDS, 7); define(FILE_CRITERIA_NEWER_THAN_MINUTES, 8); define(FILE_CRITERIA_NEWER_MINUTES, 8); define(FILE_CRITERIA_NEWER_THAN_HOURS, 9); define(FILE_CRITERIA_NEWER_HOURS, 9); define(FILE_CRITERIA_NEWER_THAN_DAYS, 10); define(FILE_CRITERIA_NEWER_DAYS, 10); /** File name matches some string */ define(FILE_CRITERIA_NAME_LIKE, 11); define(FILE_CRITERIA_LIKE, 11); /** File name does not match some string */ define(FILE_CRITERIA_NAME_NOT_LIKE, 12); define(FILE_CRITERIA_NOT_LIKE, 12); /** File name matches some ereg expression */ define(FILE_CRITERIA_NAME_EREG, 13); define(FILE_CRITERIA_EREG, 13); /** File name does not match some string */ define(FILE_CRITERIA_NAME_NOT_EREG, 14); define(FILE_CRITERIA_NOT_EREG, 14); /** Use the touch function */ define(FILE_OPERATION_TOUCH, 0); /** User the rename() function */ define(FILE_OPERATION_MOVE, 1); /** Practically the same as above */ define(FILE_OPERATION_RENAME, 1); /** Uses the unlink fuinction */ define(FILE_OPERATION_DELETE, 2); define(FILE_OPERATION_UNLINK, 2); // These would not work in windows /** Changes file permissions */ define(FILE_OPERATION_UNMASK, 3); define(FILE_OPERATION_CHANGEPERMISSION, 3); /** Make a symbolic link */ define(FILE_OPERATION_LINK, 4); /** Used for debugging */ define(FILE_OPERATION_PRINT, -1); /** Do nothing, used when you just want to get a report */ define(FILE_OPERATION_NOTHING, -2); $dir = "c:\temp"; $action = "filePrint"; class File_Operation { /** Parameters */ var $params; /** Files */ var $files; /** Matched files */ var $matched = array(); /** Criteria Selected */ var $criteria; /** Criteria value */ var $criteriaval; /** Action, what to do with the files that match criteria */ var $action; /** Action value ex: if the action is move, this would be the target dir */ var $actionval; /** * Constructor * * @param mixed $files expects and array of filename complete with path or just one filename as a string * @param int $criteria This is the criteria, use the defined constants to remain compatiple with future versions * @param mixed $criteriaval This is a value to check against the criteria, ex if you use OPERATION_CRITERIA_BIGGER criteria the value would be the size * @param int $action What to do with the matched files, use defined constants to remain compatiple * @param mixed $actionval Some actions might require a parameter, for example the MOVE action would require a destination directory, the TOUCH action would need a timestamp * */ function File_Operation($files=null, $criteria=null, $criteriaval=null, $action=null, $actionval=null){ // If file is given as an argument check for other parameters, otherwise ignore // criteria etc and assume they are set if(isset($files)){ $this->files = &$files; if(isset($criteria)){ $this->setCriteria($criteria); } if(isset($criteriaval)){ $this->setCriteriaValue($criteriaval); } if(isset($action)){ $this->setAction($action); } if(isset($actionval)){ $this->setActionValue($actionval); } } } /** * Calculates the byte value for the BIGGER|SMALLER|EQUAL operations * * Expects the either an integer to be set as the criterialval or a string with the two trailing chars * defining the size. Valid options are case insensitive KB, MB and GB. * @return int The bytesize in bytes. ex 100KB would become 100*1024 * */ function _getByteValue(){ if(!is_numeric($this->criteriaval)){ $bytetype = substr($this->criteriaval, -2); $bytes = substr($this->criteriaval, 0, -2); if(!is_numeric($bytes)){ return(PEAR::raiseError("Invallid byte size. Valid values 100, 100KB 100MB ")); } switch(strtoupper($bytetype)){ case "KB": $this->criteriaval = $this->criteriaval * 1024; break; case "MB": $this->criteriaval = $this->criteriaval * 1048576; break; case "GB": $this->criteriaval = $this->criteriaval * 1073741824; break; default: return(PEAR::raseError("Invallid byte type. Valid options are KB, MB and GB. Use {bytesize}{bytetype}, ex 100MB")); } } return($this->criteriaval); } /** * Applies matching rules against the crteria specified. * * Given the selected criteria a match is performed for each individual member of the files array. * Future features would be applying multiple criteria either sequentialy or or simultaneusly. * * @return array All the matched files, also saved in the matched array. */ function &_getMatched(){ if(!isset($this->files)){ return(PEAR::raiseError("No files to operate on. Use setFiles first.")); } if(!isset($this->files)){ return(PEAR::raiseError("Criteria not set. Use setCriteria first.")); } // If files is not an array assume only one file if(!is_array($this->files)){ $this->files = array($this->files); } ///print("Criteria ".$this->criteria."\n"); reset($this->files); switch($this->criteria){ case FILE_CRITERIA_BIGGER_THAN: // Adjust the byte to KB MB etc $this->_getByteValue(); while(list(, $val) = each($this->files)){ if(filesize($val) > $this->criteriaval){ $this->matched[] = $val; } } break; case FILE_CRITERIA_SMALLER_THAN: // Adjust the byte to KB MB etc $this->_getByteValue(); while(list(, $val) = each($this->files)){ if(filesize($val) < $this->criteriaval){ $this->matched[] = $val; } } break; case FILE_CRITERIA_EQUAL: // Adjust the byte to KB MB etc $this->_getByteValue(); while(list(, $val) = each($this->files)){ if(filesize($val) == $this->criteriaval){ $this->matched[] = $val; } } break; case FILE_CRITERIA_NEWER_THAN_MINUTES: case FILE_CRITERIA_NEWER_THAN_HOURS: case FILE_CRITERIA_NEWER_THAN_DAYS: case FILE_CRITERIA_NEWER_THAN: if(!is_numeric($this->criteriaval)){ return(PEAR::raiseError("Value for time shoud be a number.")); } $this->criteria == FILE_CRITERIA_NEWER_THAN_MINUTES ? $this->criteriaval = $this->criteriaval * 60 : null ; $this->criteria == FILE_CRITERIA_NEWER_THAN_HOURS ? $this->criteriaval = $this->criteriaval * 3600 : null; $this->criteria == FILE_CRITERIA_NEWER_THAN_DAYS ? $this->criteriaval = $this->criteriaval * 86400 : null ; reset($this->files); while(list(, $val) = each($this->files)){ if( (filemtime($val)) > (time() - $this->criteriaval) ){ $this->matched[] = $val; } } break; case FILE_CRITERIA_OLDER_THAN_MINUTES: case FILE_CRITERIA_OLDER_THAN_HOURS: case FILE_CRITERIA_OLDER_THAN_DAYS: case FILE_CRITERIA_OLDER_THAN: $this->criteria == FILE_CRITERIA_OLDER_THAN_MINUTES ? $this->criteriaval = $this->criteriaval * 60 : null ; $this->criteria == FILE_CRITERIA_OLDER_THAN_HOURS ? $this->criteriaval = $this->criteriaval * 3600 : null; $this->criteria == FILE_CRITERIA_OLDER_THAN_DAYS ? $this->criteriaval = $this->criteriaval * 86400 : null ; reset($this->files); while(list(, $val) = each($this->files)){ if( (filemtime($val)) < (time() - $this->criteriaval) ){ /* Debug output print("File date :". date("d/m/Y", filemtime($val)). " Condition date:". date("d/m/Y",time() - $this->criteriaval)."\n"); */ $this->matched[] = $val; } } break; case FILE_CRITERIA_LIKE: if(!isset($this->criteriaval)){ return(PEAR::raiseError("File name to match agains is not set. PLease use setCrteriaValue")); } while(list(, $val) = each($this->files)){ if(strstr($this->criteriaval, $val)){ $this->matched[] = $val; } } break; default: return(PEAR::raiseError("Not implemented")); break; } return($this->matched); } /** * Executes the operation. * * Executes the operation calls _getMatched and _runOperation * * @param mixed $files expects and array of filename complete with path or just one filename as a string * @param int $criteria This is the criteria, use the defined constants to remain compatiple with future versions * @param mixed $criteriaval This is a value to check against the criteria, ex if you use OPERATION_CRITERIA_BIGGER criteria the value would be the size * @param int $action What to do with the matched files, use defined constants to remain compatiple * @param mixed $actionval Some actions might require a parameter, for example the MOVE action would require a destination directory, the TOUCH action would need a timestamp * @return bool Operation status, note that if not all mached files fail the result will be true * * @see _getMatched * @see _runOperation * @see File_Operation */ function run($files=null, $criteria=null, $criteriaval=null, $action=null, $actionval=null){ $this->File_Operation(&$files, $criteria, $criteriaval, $action, $actionval); $this->_getMatched(); $res = $this->_runOperation(); return($res); } /** * Does the actual work of processing the matched files * * Checks the action and actionval parameters and executes the appropriate actions. * If debug is set will print a brief summary of the operation. All failed files have a * error registered with them in the failed_reasons array, implemented using ob_* functions * * @return bool False if all matched files fail, true otherwise * @see getSummaryBrief */ function _runOperation(){ if(isset($this->matched)){ // Try to detect the path delimiter, if not given put it there to avoid // problems with dir/file concatenation if( (substr ($this->actionval, -1) != "/") || (substr ($this->actionval, -1) != "\\") ){ // The / char works as path for win and unix so I'll not bother to // detect OS here, if I'm wrong let someone tell me please $this->actionval .= "/"; } switch($this->action){ case FILE_OPERATION_NOTHING: break; case FILE_OPERATION_PRINT: while(list(,$val) = each($this->matched)){ print("File:".$val." Date:".date("d/m/Y", filemtime($val))." Size:".(round(filesize($val)/1024, 2))."Kb\n"); } break; case FILE_OPERATION_MOVE: case FILE_OPERATION_RENAME: // Try to detect the path delimiter, if not given put it there to avoid // problems with dir/file concatenation if(!isset($this->actionval)){ return(PEAR::raiseError("Target directory is not set. Please set it with setActionValue.")); } if(!is_dir($this->actionval)){ if(!mkdir($this->actionval, 0755)){ return(PEAR::raiseError("Target directory [".$this->actionval."] does not exist and could not be created.")); } } reset($this->matched); while(list(, $val) = each($this->matched)){ ob_start(); $res = rename($val, $this->actionval.basename($val)); if($res){ $this->processed[] = $val; } else{ $this->failed[] = $val; $this->failed_reasons = ob_get_contents(); ob_end_clean(); } } break; case FILE_OPERATION_DELETE: case FILE_OPERATION_UNLINK: reset($this->matched); while(list(, $val) = each($this->matched)){ ob_start(); $res = unlink($val); if($res){ $this->processed[] = $val; } else{ $this->failed[] = $val; $this->failed_reasons = ob_get_contents(); ob_end_clean(); } } break; } } if($this->debug){ print $this->getSummaryBrief()."\n"; } } /** * Gets a short summary of the operation * @return string A string describing how many files were passed, how many matched, proceesed and failed */ function getSummaryBrief(){ return("Total files:".count($this->files)." matched:".count($this->matched)." processed:".count($this->processed)." failed:".count($this->failed)); } /** * Gets a full summary of what happened. * * Will display all files info, all matched files info * all processed files info and all failed files info together this the reason why they failed. * XXX not implemented * * @return string a full description of the operation */ function getSummaryFull(){ return("Total files:".count($this->files)." matched:".count($this->matched)." failed:".count($this->failed)); } /** * Same ass getSummaryFull but this will display a nicely formatted HTML report * * */ function getSummaryHTML(){ return("Total files:".count($this->files)." matched:".count($this->matched)." failed:".count($this->failed)); } /** * Sets the files to prosess * * @param mixed $files Thiles to process can be an array of files with full path of just one file */ function setFiles($files){ $this->files = $files; } /** * Sets the criteria * * @param int $criteria The criteria to use, can be any of the defined OPERATION_CRITERIA_* constants */ function setCriteria($criteria){ $this->criteria = $criteria; } /** * Sets the criteria value * * Described in File_Operation * @param int $criteriaval The criteria value, for BIGGER this would be the file size to check agains */ function setCriteriaValue($criteriaval){ $this->criteriaval = $criteriaval; } /** * What to do with the matched files. * * Valid options for this would FILE_OPEARATION_MOVE, FILE_OPEARATION_DELETE, * FILE_OPEARATION_TOUCH etc. * @param int $action Use the defined constants */ function setAction($action){ $this->action = $action; } /** * The parameted for the action * * Sets an optional parameter for the action, not all actions requre one but some do * for exmple the MOVE would require a targed directory. */ function setActionValue($actionval){ $this->actionval = $actionval; } function htmlHeader(){ print " <html> <head> <title></title> </head> <body> "; } function htmlFooter(){ print " </body> </html> "; } /** * Provides a web interface * * Uses run and creates a web form to retrieve parameters. * */ function runHTML($fileroot=null){ global $HTTP_POST_VARS, $PHP_SELF; if(isset($HTTP_POST_VARS["File_Opearation"])){ print_r($HTTP_POST_VARS); require_once("File/Find.php"); $find = new File_Find(); $files = $find->maptree($HTTP_POST_VARS["sourcedir"]); $this->run($files[1], $HTTP_POST_VARS["criteria"], $HTTP_POST_VARS["criteriaval"], $HTTP_POST_VARS["action"], $HTTP_POST_VARS["actionval"]); $this->htmlHeader(); print($this->getSummaryHtml()); $this->htmlFooter(); return(0); } $this->htmlHeader(); print " <form name=\"run\" method=\"post\" action=\"".$PHP_SELF."\"> <input type=\"hidden\" name=\"File_Opearation\"> <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\"> <tr> <td>Source directory</td> <td> <input type=\"text\" name=\"sourcedir\"> </td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <td>Criteria</td> <td> <select name=\"criteria\"> <option value=\"0\" selected>Bigger</option> <option value=\"1\">Smaller</option> <option value=\"2\">Equal</option> <option value=\"3\">Older than (seconds)</option> <option value=\"4\">Older than (minutes)</option> <option value=\"5\">Older than (hours)</option> <option value=\"6\">Older than (days)</option> <option value=\"7\">Newer than (seconds)</option> <option value=\"8\">Newer than (minutes)</option> <option value=\"9\">Newer than (hours)</option> <option value=\"10\">Newer than (days)</option> <option value=\"11\">Name like</option> <option value=\"12\">Name not like</option> <option value=\"13\">Name ereg</option> <option value=\"14\">Name not ereg</option> </select> </td> <td>=&gt; </td> <td> <input type=\"text\" name=\"criteriaval\" size=\"20\" maxlength=\"50\"> </td> <td>&nbsp;</td> </tr> <tr> <td>Operation</td> <td> <select name=\"action\"> <option value=\"-1\" selected>Print</option> <option value=\"0\">Touch</option> <option value=\"1\">Move</option> <option value=\"2\">Delete</option> <option value=\"3\">Change permissions</option> <option value=\"-2\">Nothing</option> </select> </td> <td>=&gt; </td> <td> <input type=\"text\" name=\"actionval\" size=\"20\" maxlength=\"50\"> </td> <td>&nbsp;</td> </tr> <tr> <td>&nbsp;</td> <td><input type=\"submit\" name=\"run\" value=\"run\"></td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> </table> </form> "; $this->htmlFooter(); } } ?>
« previous php.pear.dev (#1145) next »