All pastes #709490 Raw Edit

Someone

public text v1 · immutable
#709490 ·published 2007-09-24 18:43 UTC
rendered paste body
<?php

require 'Console/ProgressBar.php';

ob_implicit_flush(true);

class DupeFinder {

    private $path;
    private $pattern;

    public function __construct($path, $pattern = null) {
        $this->path    = realpath($path);
        $this->pattern = $pattern;
    }
    
    public function find() {
        echo "Finding files...\n";
        $filelist  = $this->_findFiles($this->path, $this->pattern);
        $same_filesizes = $this->_checkFilesizes($filelist);
        
        // Check the first 16 bytes of the file
        echo "Checking contents...\n";
        $bar = new Console_ProgressBar('%current%/%max% [%bar%] %percent%', '=>', ' ', 80, sizeof($same_filesizes));
        $same_contents = Array();
        for($i = 0; $i < sizeof($same_filesizes); $i++) {
            $out = $this->_checkContents($same_filesizes[$i]);
            if(sizeof($out) > 0) {
                $same_contents[] = $out[0];
            }
            $bar->update($i + 1);
        }
        echo "\n";
          
        // Find the ones with matching checksums
        $bar = new Console_ProgressBar('%current%/%max% [%bar%] %percent%', '=>', ' ', 80, sizeof($same_contents));
        $same_checksums = Array();
        for($i = 0; $i < sizeof($same_contents); $i++) {
            $out = $this->_checkChecksums($same_contents[$i]);
            if(sizeof($out) > 0) {
                $same_checksums[] = $out[0];
            }
            $bar->update($i + 1);
        }
        echo "\n";
        
        return $same_checksums;
    }
    
    private function _findFiles($path, $pattern = null) {
    
        $filelist = Array();
        $handle   = dir($path);
        
        while( ($file = $handle->read()) !== false) {
            $name = $path . '/' . $file;
                 
            if(!is_readable($name))
                continue; // Don't even bother trying
            if($file[0] == '.')
                continue;
            if(is_link($name))
                continue;
            
            if(is_dir($name)) {
                $filelist = array_merge($filelist, $this->_findFiles($name, $pattern));
            } else if(is_file($name)) {
                if($pattern != null) {
                    if(preg_match($pattern, $file)) {
                        $filelist[] = $name;
                    }
                } else {
                    $filelist[] = $name;
                }
            }
        }
        
        return $filelist;
    }
    
    // Make arrays of files with the same size
    private function _checkFilesizes($filelist) {
        $filesizes = Array();
        
        foreach($filelist as $file) {
            $size = filesize($file);
            if($size < 1)
                continue; // wtf?
            if(!isset($filesizes[$size]))
                $filesizes[$size] = Array();
            $filesizes[$size][] = $file;
        }
        
        $output = Array();
        foreach($filesizes as $size => $files) {
            if(sizeof($files) > 1)
                $output[] = $files;
        }
        
        return $output;
    }
    
    private function _checkContents($filelist) {
        $signatures = Array();
        
        foreach($filelist as $file) {
            $fp = fopen($file, "r");
            if(!$fp)
                throw new Exception("Couldn't open file: $file");
            $signature = fread($fp, 16);
            fclose($fp);
            if(!isset($signatures[$signature]))
                $signatures[$signature] = Array();
            $signatures[$signature][] = $file;
        }
        
        $output = Array();
        foreach($signatures as $signature => $files) {
            if(sizeof($files) > 1) {
                $output[] = $files;
            }
        }
        
        return $output;
    }
    
    private function _checkChecksums($filelist) {
        $sums = Array();
        
        foreach($filelist as $file) {
            $sum = md5_file($file);
            
            if(!isset($sums[$sum]))
                $sums[$sum] = Array();
            $sums[$sum][] = $file;
        }
        
        $output = Array();
        foreach($sums as $sum => $files) {
            if(sizeof($files) > 1) {
                $output[] = $files;
            }
        }
        
        return $output;
    }

}

$finder = new DupeFinder(".");
$dupes = $finder->find();

?>