Filesystem Tools

MakeDir

Behaves like unix mkdir -p. Will create intermediate dirs in the path if they don't exist. Can optionally specify permissions (default is 0755). New dirs will be created with the specified permissions but exisiting dirs in the path will not be changed.

<?php    

new MakeDir('path/to/new/dir'); // default permissions 0755
new MakeDir('path/to/new/dir'0711); // optionally specify permissions

DeleteBranch

Delete a dir and all of its contents.

<?php    

new DeleteBranch('path/to/deletable/');

// keep the branch root dir but delete all contents
new DeleteBranch('path/to/deletable/'false); 

Filesystem Traversal

If filesystem traversal is split off from the actual processing, it's easy to implement operations such as backups, searches, or etc.

Nowadays there are iterators in php5 which can handle filesystem traversal if you want to use them instead. They look unnecessarily complicated to me. A good filesystem traversal class should be a pared down traversal algorithm, nothing more.

BranchReader

Extend BranchReader and implement _dir(), _file() or _link() as required. Found items will be passed to these methods.

<?php    

class MyClass extends BranchReader {
    
    function 
_dir($parent_dir$name) {
        
// do something with the dir
    
}
    function 
_file($parent_dir$name) {
        
// do something with the file
    
}
    function 
_link($parent_dir$name) {
        
// do something with the symlink
    
}
}

A rather naive example which would display file encodings:

<?php    

class ShowFileEncodings extends BranchReader {

    function 
_file($parent_dir$item) {
        echo 
$item "\t" ;
        echo 
mb_detect_encoding(file_get_contents($parent_dir $item));
        echo 
"\n";
    }
}

To read through a branch:

<?php    

$branch 
= new ShowFileEncodings($branch_root_dir);
$branch->read();

The read() method will return boolean true if the branch root exists and is readable. False if not.

Sometimes you may want to stop mid-read. For example, a search application doesn't need to continue searching after it has found the item you're looking for. Throw a StopNow exception:

<?php    

class MyClass extends BranchReader {
    
    function 
_file($parent_dir$name) {
        if(
$something) {
            throw new 
StopNow;
        }
    }

SelectiveBranchReader

SelectiveBranchReader is a subclass of BranchReader which allows the user to define policies for followable dirs and processable files. Policies should implement an "isValid" method which returns boolean true/false — see policies & predicates.

Processing is handed over to an aggregated processor object rather than a subclass.make both same?<--> All processor classes should implement:

<?php    

interface BranchProcessor {
    function 
processDir($parent_dir$item);
    function 
processFile($parent_dir$item);
    function 
processLink($parent_dir$item);
}
<?php    

$branch 
= new SelectiveBranchReader(
    
$branch_root_dir
    
$followable_dirs_policy
    
$processable_files_policy);

$branch->setProcessor(new YourProcessor);
$branch->read();

Alternatively, you can pass the processor at instantiation:

<?php    

$branch 
= new SelectiveBranchReader(
    
$branch_root_dir
    
$followable_dirs_policy
    
$processable_files_policy
    new 
YourProcessor);

$branch->read();

As you might expect, if a policy returns true the item will be passed on to the processor. Dirs are checked with the followable dirs policy and files are checked with the wanted files policy.

Note that the full path is passed to the followable dirs policy but only the file name is passed to the wanted files policy (all the dirs in the full path have already been checked against the followable dirs policy).

For example, to ignore the contents of working copy .svn dirs and to process all other files:

<?php    
require_once('aperiplus/lib/filesystem/filesystem-tools.php');
require_once(
'aperiplus/lib/predicates/predicates.php');

$branch = new SelectiveBranchReader(
    
$branch_root_dir
    new 
Negation(new MatchesPattern('/\.svn/')), 
    new 
Allow
    new 
YourProcessor);

$branch->read();

When a new dir is found, a decision has to be made if its contents should be examined (ie the dir is "followable") and also if the dir itself should be passed to the aggregated processor. Note that "followable" and "processable" are held to mean the same thing. If they don't, add further path filters in the processor.

FindInFiles

A BranchProcessor for SelectiveBranchReader. Returns path of first file whose contents match the specified regex pattern. To search all files in all dirs of $branch_root_dir:

<?php    
require_once('aperiplus/lib/filesystem/filesystem-tools.php');
require_once(
'aperiplus/lib/predicates/predicates.php');

$finder = new SelectiveBranchReader(
    
$branch_root_dir
    new 
Allow
    new 
Allow
    new 
FindInFiles('/perl regex/'));
$finder->read();
$finder->getFound();

CopyBranch

Subclass of BranchReader. Very simple to use:

<?php    
require_once('aperiplus/lib/filesystem/filesystem-tools.php');
new 
CopyBranch($from$to);

DirectoryContents

BranchReader Subclass. Note recursive traversal is turned off so you only get the contents of the named dir.

<?php    
require_once('aperiplus/lib/filesystem/filesystem-tools.php');

$folder = new DirectoryContents($dir);

// getters return an array
$folder->getDirs();
$folder->getFiles();
$folder->getLinks();

FileEditor

A BranchProcessor used to apply an edit to all files in a branch (see SelectiveBranchReader).

First you need to define the edit to be applied. FileEditor accepts an Editor object which implements (in the loose sense) either:

<?php    

interface Editor {
    function 
edit($string); // returns the edited string
}
interface 
ResettableEditor {
    function 
edit($string);
    function 
reset($current_path);
}

You might need a reset() method if there are any "bullets left in the barrel" issues. The current path (the file being edited) is passed to reset().

A simple example:

<?php    

class FindReplace // implements Editor

    
function __construct($from$to) {
        
$this->_from $from;
        
$this->_to $to;
    }
    function 
edit($string) {
        return 
str_replace(
            
$this->_from
            
$this->_to
            
$string);
    }
}

If you want to apply several edits, use the composite Editors class:

<?php    

$editors 
= new Editors;
$editors->add(new MyEditor);
$editors->add(new AnotherEditor);

Putting it all together:

<?php    
require_once('aperiplus/lib/filesystem/filesystem-tools.php');
require_once(
'aperiplus/lib/predicates/predicates.php');

$editors = ... your choice ... ;
$branch = new SelectiveBranchReader(
    
$branch_root_dir
    new 
Allow// or etc
    
new Allow
    new 
FileEditor($editors));
$branch->read();

SourceForge.net Logo