Subversion Repositories cryptochat

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
class DirectoryHashCalculator {
4
        /*
5
 
6
        Directory Hash V3 by Daniel Marschall
7
 
8
        <directoryhash>      ::= SHA1(<directorycontext>)
9
        <directorycontext>   ::= "" | <entry>
10
        <entries>            ::= <entry> ["|" <entry>]
11
                                 IMPORTANT: (MD5) SORTED ASCENDING!
12
        <entry>              ::= <file_md5_hash> <filenames>
13
        <filenames>          ::= "*" <relative_directory> <filename> [<filenames>]
14
                                 IMPORTANT: (RelativeDir+Filename) SORTED ASCENDING!
15
        <file_md5_hash>      ::= MD5(FILECONTENT(<relative_directory> <filename>))
16
        <filename>           ::= given.
17
                                 IMPORTANT: All directories (this automatically
18
                                 excludes "", "." and "..") and non-existing resp.
19
                                 non-readable files are not included.
20
                                 addFile() will return false.
21
        <relative_directory> ::= given.
22
                                 Note: Usually, the directory is in relative diction.
23
                                 IMPORTANT: "./" is always stripped from beginning!
24
                                 IMPORTANT: "\" is made to "/"!
25
 
26
        Example:
27
                "" --> Empty directory
28
                <hash1>*<file1_with_hash1>*<file2_with_hash1>|<hash2>*<file1_with_hash2>
29
 
30
        */
31
 
32
        private $hashes;
33
 
34
        function __construct() {
35
                $this->clear();
36
        }
37
 
38
        private static function makeFilenameConsistently(&$filename) {
39
                // Rule 1: Cut off "./" from beginning
40
                if (substr($filename, 0, 2) == './') {
41
                        $filename = substr($filename, 2, strlen($filename)-2);
42
                }
43
 
44
                // Rule 2: Use "/" instead of "\"
45
                $filename = str_replace('\\', '/', $filename);
46
        }
47
 
48
        /*
49
        @return
50
                MD5-Hash of the file or FALSE is calculation/adding
51
                was not successful.
52
        */
53
        public function addFile($file) {
54
                if (!file_exists($file)) return false;
55
                // if (!is_readable($file)) return false;
56
                // if (basename($file) == '') return false;
57
                // if (basename($file) == '.') return false;
58
                // if (basename($file) == '..') return false;
59
                self::makeFilenameConsistently($file);
60
                $file_md5 = md5_file($file);
61
                if ($file_md5 === false) return false; // Error...
62
                $this->hashes[$file_md5][] = $file;
63
                return $file_md5;
64
        }
65
 
66
        public function clear() {
67
                $this->hashes = array();
68
        }
69
 
70
        private function getDirectoryContext() {
71
                if (count($this->hashes) == 0) return '';
72
                $directory_context = '';
73
                // Sort md5 hashes ascending (so that the result is equal at every machine)
74
                ksort($this->hashes);
75
                foreach ($this->hashes as $hash => $filenames) {
76
                        // Sort filenames ascending (so that the result is equal at every machine)
77
                        sort($filenames);
78
                        $directory_context .= $hash;   
79
                        foreach ($filenames as $filename) {
80
                                $directory_context .= '*'.$filename;
81
                        }
82
                        $directory_context .= '|';
83
                }
84
                $directory_context = substr($directory_context, 0, strlen($directory_context)-1);
85
                return $directory_context;     
86
        }
87
 
88
        public function calculateDirectoryHash() {
89
                $directory_context = $this->getDirectoryContext();
90
                return sha1($directory_context);
91
        }
92
 
93
        function getVersionDescription() {
94
                return 'Marschall V3';
95
        }
96
}
97
 
98
?>