583a659a70b6515cdfe3fbc82820c85bf1f77337
[squasher.git] / webroot / squasher.class.php
1 <?php
2 require_once("../config.php");
3
4 function zfill($n, $a) {
5         return str_repeat("0", max(0,$a-strlen($n))) . $n;
6 }
7
8 function named_records_sort($named_recs, $order_by, $reverse=false, $flags=0) {
9         $named_hash = array();
10         foreach ($named_recs as $key => $fields)
11                 $named_hash[$key] = $fields[$order_by];
12
13         if ($reverse)
14                 arsort($named_hash,$flags=0) ;
15         else
16                 asort($named_hash, $flags=0);
17
18         $sorted_records = array();
19         foreach($named_hash as $key => $val)$sorted_records[$key] = $named_recs[$key];
20
21         return $sorted_records;
22 }
23
24 function validate_user($username, $password, $salt) {
25         $creds['validated'] = false;
26         $query="SELECT * FROM users WHERE user_name = '".mysql_escape_string($username)."'";
27         $q_result = mysql_query($query);
28         while ($fetched_object = mysql_fetch_object($q_result)) {
29                 if (md5($fetched_object->user_pass.$salt) == $password) {
30                         //validated
31                         $creds['user_id'] = $fetched_object->user_id;
32                         $creds['user_name'] = $fetched_object->user_name;
33                         $creds['user_level'] = $fetched_object->user_level;
34                         $creds['validated'] = true;
35                         $_SESSION['creds'] = $creds;
36                         log_event('login', null);
37                 }
38         }
39         $_SESSION['creds'] = $creds;
40         return $creds['validated'];
41 }
42
43
44 function get_smarty() {
45         require_once(SQUASHER_SMARTY_SOURCE); // See config.php
46
47         $smarty = new Smarty;
48         $smarty->setTemplateDir(SQUASHER_SMARTY_TEMPLATES)
49                ->setCompileDir(SQUASHER_SMARTY_TEMPLATES_C)
50                ->setCacheDir(SQUASHER_SMARTY_CACHE);
51
52         return $smarty;
53 }
54
55
56 function log_event($action, $filename, $hash=null, $debugmsg=null) {
57         if ($hash===null)
58                 $hash = str_repeat("0",32);
59                 
60         if ($debugmsg!==null) {
61                 $user_id = -1;
62                 $user_name = 'squasher-web';
63                 $ip = $debugmsg;
64         } else {
65                 $user_id = $_SESSION['creds']['user_id'];
66                 $user_name = $_SESSION['creds']['user_name'];
67                 $ip = $_SERVER['REMOTE_ADDR'];
68         }
69
70         $hash = $hash===null ? 'NULL' : "'".mysql_escape_string($hash)."'";
71         $filename = "'".mysql_escape_string($filename)."'";
72         $action = "'".mysql_escape_string($action)."'";
73         $user_name = "'". mysql_escape_string($user_name)."'";
74         $ip = "'". mysql_escape_string($ip)."'";
75
76         @mysql_query("INSERT INTO log (hash,file,action,user_id,user_name,ip,date) VALUES ($hash, $filename, $action, $user_id, $user_name, $ip, NOW())");
77 }
78
79
80 class squashweb {
81
82 var $configs = array();
83 var $files = array();
84 var $subfolders = array();
85 var $folderrights;
86 var $userrights;
87 var $history = array();
88
89 function get_configs() {
90         return $this->configs;
91 }
92
93 function subfolders() {
94         return $this->subfolders;
95 }
96
97 function get_config($h) {
98
99         return $this->configs[$h];
100 }
101
102 function folderrights() {
103         return $this->folderrights;
104 }
105
106 function userrights() {
107         return $this->userrights;
108 }
109
110 function update_history() {
111         $q="SELECT md5_hash,file,completed,checked FROM file_hash";
112         $r=mysql_query($q);
113         while($o=mysql_fetch_object($r)) {
114                 $this->history[$o->md5_hash]['file']=$o->file;
115                 $this->history[$o->md5_hash]['completed']=$o->completed;
116                 $this->history[$o->md5_hash]['checked']=$o->checked;
117         }
118 }
119
120 function get_users($user_level) {
121         $q = "SELECT * FROM users";
122         if ($user_level<200) // super user have no restrictions at all
123                 $q .= " WHERE user_level < ".$user_level;
124         $q .= " ORDER BY user_name ASC";
125         $r = mysql_query($q);
126
127         while ($o = mysql_fetch_object($r)) {
128                 $return[$o->user_id]['id']              = $o->user_id;
129                 $return[$o->user_id]['name']    = $o->user_name;
130                 $return[$o->user_id]['level']   = $o->user_level;
131                 $return[$o->user_id]['enabled'] = ($o->user_pass == '') ? false : true ;
132         }
133
134         return $return;
135 }
136
137 function get_logs($type='all') {
138         $q="SELECT log.* FROM log WHERE log.user_id != '1' and ip != '87.233.211.2' ";
139         if ($_SESSION['creds']['user_id'] == 1)
140                 $q="SELECT log.* FROM log WHERE log.user_id != 'x' ";
141
142         if ($type != 'all')
143                 $q.= " AND log.action = '".mysql_escape_string($type)."'";
144
145         $today     =" AND date > date(date_add(now(), interval -0 day)) ";
146         $yesterday =" AND date < date(date_add(now(), interval -0 day)) AND date > date(date_add(now(), interval -1 day)) ";
147         $lastweek  =" AND date < date(date_add(now(), interval -1 day)) AND date > date(date_add(now(), interval -6 day)) ";
148         $older     =" AND date < date(date_add(now(), interval -7 day)) AND date > date(date_add(now(), interval -30 day)) ";
149
150         $order=" ORDER BY log.log_id desc ";
151         $r = mysql_query($q.$today.$order);
152         $return = array(
153                 'today'=>array(),
154                 'yesterday'=>array(),
155                 'lastweek'=>array(),
156                 'older'=>array(),
157                 );
158         while($a = mysql_fetch_array($r)) {
159                 $qu="SELECT users.user_name FROM users LEFT JOIN log ON users.user_id = log.user_id WHERE log.ip='".mysql_escape_string($a['ip'])."' GROUP BY users.user_name";
160                 $ru = mysql_query($qu);
161                 $a['users_from_ip'] = " | ";
162                 while($au = mysql_fetch_array($ru))
163                         $a['users_from_ip'] .= $au['user_name']." | ";
164                 $return['today'][$a['log_id']] = $a;
165         }
166         $r = mysql_query($q.$yesterday.$order);
167         while($a = mysql_fetch_array($r)) {
168                 $qu="SELECT users.user_name FROM users LEFT JOIN log ON users.user_id = log.user_id WHERE log.ip='".mysql_escape_string($a['ip'])."' GROUP BY users.user_name";
169                 $ru = mysql_query($qu);
170                 $a['users_from_ip'] = " | ";
171                 while($au = mysql_fetch_array($ru))
172                         $a['users_from_ip'] .= $au['user_name']." | ";
173                 $return['yesterday'][$a['log_id']] = $a;
174         }
175         $r = mysql_query($q.$lastweek.$order);
176         while($a = mysql_fetch_array($r)) {
177                 $qu="SELECT users.user_name FROM users LEFT JOIN log ON users.user_id = log.user_id WHERE log.ip='".mysql_escape_string($a['ip'])."' GROUP BY users.user_name";
178                 $ru = mysql_query($qu);
179                 $a['users_from_ip'] = " | ";
180                 while($au = mysql_fetch_array($ru))
181                         $a['users_from_ip'] .= $au['user_name']." | ";
182                 $return['lastweek'][$a['log_id']] = $a;
183         }
184         $r = mysql_query($q.$older.$order);
185         while($a = mysql_fetch_array($r)) {
186                 $qu="SELECT users.user_name FROM users LEFT JOIN log ON users.user_id = log.user_id WHERE log.ip='".mysql_escape_string($a['ip'])."' GROUP BY users.user_name";
187                 $ru = mysql_query($qu);
188                 $a['users_from_ip'] = " | ";
189                 while($au = mysql_fetch_array($ru))
190                         $a['users_from_ip'] .= $au['user_name']." | ";
191                 $return['older'][$a['log_id']] = $a;
192         }
193
194         return $return;
195 }
196
197 function insert_users($u, $admin_level) {
198         $user_name = $u['user_name'];
199         $user_pass = $u['user_pass'];
200         $user_level = (int)$u['user_level'];
201
202         $q = "INSERT INTO users (user_name,user_pass,user_level) VALUES ('".mysql_escape_string($user_name)."', '".mysql_escape_string(md5($user_pass))."', ".$user_level.")";
203         $r = mysql_query($q);
204 }
205
206 /*
207  * if user_level is 0, it means we don't really touch it, but we clear the password (can't log in anymore)
208  */
209 function update_users($u, $user_id) {
210         $user_id = (int)$user_id;
211         $user_name = @$u['user_name'];
212         $user_pass = @$u['user_pass'];
213         if (array_key_exists('user_level', $u))
214                 $user_level = $u['user_level'];
215         else
216                 $user_level = null;
217         if ($user_name) {
218                 $q = "UPDATE users SET user_name = '".mysql_escape_string($user_name)."' WHERE user_id = ".$user_id;
219                 $r = mysql_query($q);
220         }
221         if ($user_pass) {
222                 $q = "UPDATE users SET user_pass = '".mysql_escape_string(md5($user_pass))."' WHERE user_id = ".$user_id;
223                 $r = mysql_query($q);
224         }
225         if ($user_level !== null) {
226                 if ($user_level > 0) {
227                         $q = "UPDATE users SET user_level = ".$user_level." WHERE user_id = ".$user_id;
228                         $r = mysql_query($q);
229                 } else {
230                         $q = "UPDATE users SET user_pass = '' WHERE user_id = ".$user_id;
231                         $r = mysql_query($q);
232                 }
233         }
234 }
235
236 function remove_users($user_id) {
237         $user_id = (int)$user_id;
238         $q = "DELETE FROM users WHERE user_id = ".$user_id;
239         $r = mysql_query($q);
240 }
241
242
243 /**
244  * Get the permissions of a user over the file tree
245  *
246  * This builds a permission array, which is kind of recursive:
247  * The array keys are the name of the directories, and the values are an array
248  * hereby described.
249  * The special key __access__ indicates the permission of a given directory,
250  * its values can be:
251  * 0 --deny-all
252  * 1 --allow-dir-only
253  * 2 --allow-inc-subs
254  *
255  * Exemple:
256  *  [myas] => Array
257  *      [__access__] => 0
258  *  [myez] => Array
259  *      [__access__] => 1
260  *      [subfolder01] => Array
261  *          [__access__] => 2
262  *      [subfolder02] => Array
263  *          [__access__] => 2
264  *
265  * @param string user_id User id
266  * @return array Multidimensional array with dir and __access__ keys, and 0/1/2 values
267  */
268 function get_rights($user_id) {
269         $result = array();
270
271         $q = "SELECT folder_path, access FROM user_rights WHERE user_id = ".(int)$user_id;
272         $r = mysql_query($q);
273         while ($o = mysql_fetch_object($r)) {
274
275                 //clean vars
276                 $arr_string = '$result';
277
278                 //get foldernames from path
279                 if ($o->folder_path != '/') {
280                         $path = $o->folder_path;
281                         if ($path{0}=='/')
282                                 $path=substr($path,1);
283                         $folder_arr = explode('/',$path);
284
285                         //create folder structure array
286                         foreach ($folder_arr AS $key => $value) {
287                                 $value_escaped = str_replace("'", "\\'", $value);
288                                 $arr_string .= "['".$value_escaped."']";
289                         }
290                 }
291                 $arr_string .= "['__access__']";
292
293                 eval($arr_string." = '".$o->access."';");
294         }
295         return $result;
296 }
297
298
299 /**
300  * Get super user permissions, full recursive access on /
301  *
302  * @return array Permissions
303  */
304 function get_superuser_rights() {
305         return  array('__access__' => 2);
306 }
307
308
309 /**
310  * Initialise this->folderrights or this->$userrights
311  *
312  * this->folderrights are the permissions of the logged in user
313  * this->userrights are the permissions of the user beeing edited
314  * 
315  * @see get_rights
316  *
317  * @param string user_id User id or -1 for full access
318  * @param string type 'folderrights' or 'userrights'
319  * 
320  */
321 function give_rights($user_id, $type='folderrights') {
322         if ($user_id == -1)
323                 $rights = $this->get_superuser_rights();
324         else
325                 $rights = $this->get_rights($user_id);
326
327         if ($type=='folderrights')
328                 $this->folderrights = $rights;
329         else // $type=='userrights'
330                 $this->userrights = $rights;
331 }
332
333 function update_rights($edited_user, $m, $admin_level) {
334         $q = "SELECT count(*) result FROM users WHERE user_id = ".(int)$edited_user." AND user_level < ".(int)$admin_level;
335         $r = mysql_query($q);
336         $o = mysql_fetch_object($r);
337
338         if ($o->result) {
339                 foreach ($m AS $path => $access) {
340                         $p_q = "SELECT count(*) result FROM user_rights WHERE user_id = ".(int)$edited_user." AND folder_path = '".mysql_escape_string($path)."'";
341                         $p_r = mysql_query($p_q);
342                         $p_o = mysql_fetch_object($p_r);
343                         if ($p_o->result == 1)
344                                 mysql_query("UPDATE user_rights SET access = ".(int)$access." WHERE folder_path = '".mysql_escape_string($path)."' AND user_id = ".(int)$edited_user);
345                         if ($p_o->result == 0)
346                                 mysql_query("INSERT INTO user_rights (user_id,folder_path,access) values (".(int)$edited_user.",'".mysql_escape_string($path)."',".(int)$access.") ");
347                 }
348         }
349 }
350
351
352 function show_rights_tree($path, $depth=0, $userid=0) {
353
354         if ($userid==0)
355                 return false;
356         if ($depth==0)
357                 $this->give_rights($userid, 'userrights');
358
359         // access = 0 --deny-all
360         // access = 1 --allow-dir-only
361         // access = 2 --allow-inc-subs
362
363         $layout = '';
364         $style = '';
365
366         for ($i=0; $i<$depth; $i++)
367                 $layout .= " ";
368         if ($dir = opendir(SQUASHER_UPLOADS_DIR.$path)) {
369                 $layout .= "<div style='clear:both;' >\n";
370                 $f = 0;
371                 while (false !== ($file = readdir($dir))) {
372                         $files_array[] = $file;
373                 }
374                 asort($files_array);
375                 foreach ($files_array as $f_index => $file) {
376                         if (($file{0} !== ".") && ($file !== ".."))
377                         {
378                                 $filename = $path=='/' ? $path.$file : $path.'/'.$file;
379                                 if (!is_file(SQUASHER_UPLOADS_DIR.$filename) && $this->got_rights_array($filename) > 0) {
380                                         $f++;
381                                         $name = $filename;
382                                         $check = $this->got_rights_array_admin($filename, $this->userrights);
383                                         $check_all = '';
384                                         $check_allow = '';
385                                         $check_deny = '';
386                                         switch($check) {
387                                                 case 2:
388                                                         $check_all = 'checked';
389                                                         break;
390                                                 case 1:
391                                                         $check_allow = 'checked';
392                                                         break;
393                                                 case 0:
394                                                 default:
395                                                         $check_deny = 'checked';
396                                                         break;
397                                         }
398
399                                         if ($f==1)
400                                                 $style[$depth] = ".depth".$depth."{float:right;width:".(600-($depth*10))."px;border-left:2px solid #FFFFFF;border-top:1px solid #FFFFFF;background:#".dechex(14-$depth).dechex(14-$depth).dechex(14-$depth).dechex(14-$depth).dechex(14-$depth).dechex(14-$depth).";}";
401                                         if ($f==1)
402                                                 $layout .= "<div class='depth".$depth."'>";
403                                         $layout .= "<div class='white_border' >".htmlspecialchars($file)."</div>\n";
404                                         $name_escaped = htmlspecialchars($name);
405                                         $layout .= '<div class="check_deny"><input name="m['.$name_escaped.']" value=0 type=radio '.$check_deny."></div>\n";
406                                         $layout .= '<div class="check_allow"><input name="m['.$name_escaped.']" value=1 type=radio '.$check_allow."></div>\n";
407                                         $layout .= '<div class="check_all"><input name="m['.$name_escaped.']" value=2 type=radio '.$check_all."></div>\n";
408                                         $sub_return = $this->show_rights_tree($filename,$depth+1,$userid);
409                                         if (is_array($style) && is_array($sub_return['style']))
410                                                 $style = $style + $sub_return['style'];
411                                         $layout .= $sub_return['layout'];
412                                 }
413                         }
414                 }
415                 if ($f!=0)
416                         $layout .= "</div>";
417                 $layout .= "</div>\n";
418         }
419
420         $return['style'] = $style;
421         $return['layout'] = $layout;
422
423         return $return;
424 }
425
426 function got_rights_array($needle, $haystack='', $c=0) {
427         // used by:
428         // - read_single_file
429         // - read_directory
430         // - show_rights_tree
431
432         if (!is_array($haystack))
433                 $haystack = $this->folderrights;
434
435         // check root rights
436         if ($needle{0} == '/' && @$haystack['__access__'] == 2 )
437                 return 2;
438
439         // remove leading /
440         if ($needle{0}=='/')
441                 $needle = substr($needle, 1);
442
443         $needle_arr = explode('/', $needle);
444         $n = count($needle_arr);
445         $d = $c + 1;
446
447         foreach ($haystack as $k => $v) {
448                 if ($needle_arr[$c] == $k) {
449                         if (!is_array(@$v['__access__'])) {
450                                 if ($v['__access__'] == 2             ) return 2;
451                                 if ($v['__access__'] == 1 && $d == $n ) return 1;
452                                 if ($v['__access__'] == 0 && $d == $n ) return 0;
453                         } else {
454                                 $return = $this->got_rights_array($needle, $v, $d);
455                         }
456                 }
457         }
458         return $return;
459 }
460
461 function got_rights_array_admin($needle, $haystack='', $c=0) {
462         // used by:
463         // - show_rights_tree
464
465         if (!is_array($haystack))
466                 $haystack = $this->folderrights;
467
468         // check root rights
469         if ($needle{0} == '/' && @$haystack['__access__'] == 2 )
470                 return 2;
471
472         // remove leading /
473         if ($needle{0} == '/')
474                 $needle = substr($needle, 1);
475
476         $needle_arr = explode('/', $needle);
477         $n = count($needle_arr);
478         $d = $c + 1;
479         $return = 0;
480
481         if ($c < $n) {
482                 if (@$haystack['__access__'] == 2)
483                         return $haystack['__access__'];
484                 if (is_array($haystack[$needle_arr[$c]]))
485                         $return = $this->got_rights_array_admin($needle, $haystack[$needle_arr[$c]], $d);
486         } else {
487                 if (@$haystack['__access__'] > 0)
488                         $return = $haystack['__access__'];
489         }
490
491         return $return;
492 }
493
494 function got_rights_array_recursive($needle, $haystack='', $c=0) {
495         // used by:
496         // - read_directory, for subfolders
497
498         if (!is_array($haystack))
499                 $haystack = $this->folderrights;
500
501         // check root rights
502         if($needle{0}=='/' && @$haystack['__access__'] == 2 )
503                 return 2;
504
505         // check folder rights
506         if($needle{0}=='/')
507                 $needle=substr($needle,1);
508
509         $needle_arr = explode('/', $needle);
510         $n = count($needle_arr);
511         $d = $c + 1;
512         $return = 0;
513
514         foreach($haystack as $k => $v) {
515                 if ($c < sizeof($needle_arr) && $needle_arr[$c] == $k) {
516                         if ($c < $n) {
517                                 if ($v['__access__'] == 2)
518                                         $return = $return + $v['__access__'];
519                                 $return = $return + $this->got_rights_array_recursive($needle, $v, $d);
520                         } else {
521                                 $return = $return + $this->in_array_recursive($v);
522                         }
523                 } elseif ($c == $n) {
524                         $return = $return + $v['__access__'];
525                         if($k != '__access__')$return = $return + $this->in_array_recursive($v);
526                 }
527         }
528
529         return $return;
530 }
531
532 function in_array_recursive($haystack) {
533         $return = 0;
534         if (is_array($haystack)) {
535                 foreach ($haystack as $key1 => $value1) {
536                         if (is_array($value1)) {
537                                 $return = $return + $this->in_array_recursive($value1);
538                         }
539                         elseif ($value1 > 0) {
540                                 return $value1;
541                         }
542                 }
543         }
544         return $return;
545 }
546
547 function read_single_file($path, $file) {
548         $filename = $path=='/' ? $path.$file : $path.'/'.$file;
549         $fsfilename = SQUASHER_UPLOADS_DIR.$filename; // name on the file system
550         $i = 0;
551         if ($this->got_rights_array($path) > 0) {
552                 if (is_file($fsfilename.'.Completed'))
553                         $ext='.Completed';
554                 if (is_file($fsfilename.'.InProgress'))
555                         $ext='.InProgress';
556                 if (is_file($fsfilename.'.Starting'))
557                         $ext='.Starting';
558                 if (is_file($fsfilename.'.Processed'))
559                         $ext='.Processed';
560                 $fsfilename .= $ext;
561                 $handle = @fopen($fsfilename, "rb");
562                 $sub_pos = strpos($file, $ext);
563                 $base_name = substr($file, 0, $sub_pos);
564                 $filecontent = @fread($handle, @filesize($fsfilename));
565                 $config[$i] = explode("\r\n", $filecontent);
566                 /***
567                 *       $config:: array
568                 *       [0]     ->      versioncode
569                 *       [1]     ->      date&time
570                 *       [2]     ->      filename
571                 *       [3]     ->      filesize
572                 *       [4]     ->      chunksize
573                 *       [5]     ->      chunkcount
574                 *       [6]     ->      CRC32 checksum
575                 ***/
576                 if (@filesize($fsfilename) > 0) {
577                         $h = md5($path."/".$config[$i][2]);
578                         $this->configs[$h] = $config[$i];
579                         $this->configs[$h]['squashed'] = true;
580                         $this->configs[$h]['path'] = $path;
581                         $this->configs[$h]['status'] = substr($ext, 1);
582                         $this->configs[$h]['mime'] = $this->set_mime($this->configs[$h][2]);
583                         $this->configs[$h]['hidden'] = is_file(SQUASHER_UPLOADS_DIR.$path.'/'.$base_name.'.hidden');
584                         //to prevent dates of 1-1-1970 we set te dates of the config file
585                         $this->configs[$h]['added'] = filectime($fsfilename);
586                         $this->configs[$h]['lastchange'] = filemtime($fsfilename);
587                         fclose($handle);
588                         $this->populate_stats($path, $h);
589                         //insert hash in db
590                         #$this->update_hash($h,$path."/".$config[$i][2]);
591                         //check stats
592                         $this->check_stats($h);
593                 }
594         }
595 }
596
597
598 function read_directory($path, $getsubs=false, $getfirstfiles=true, $getdeepfiles=true, $populate=true) {
599         $fsdir = $path=='/' ? SQUASHER_UPLOADS_DIR : SQUASHER_UPLOADS_DIR.$path;
600         $hdir = @opendir(SQUASHER_UPLOADS_DIR.$path);
601         if (!$hdir)
602                 return;
603         $i = 0;
604         while (false !== ($file = readdir($hdir))) {
605                 if ($file{0} == "." || substr($file,0,2) == "SQ")
606                         continue;       // skip this file
607                 $filename = $path=='/' ? $path.$file : $path.'/'.$file;
608                 $fsfilename = SQUASHER_UPLOADS_DIR.$filename; // name on the file system
609                 if (!is_file($fsfilename) && strpos($filename, '/recieving/')!==0) {
610                         if ($getsubs) {
611                                 if ($this->got_rights_array_recursive($filename) > 0) {
612                                         $key = $path;
613                                         if ($key != '/')
614                                                 $key .=  '/';
615                                         $key .= $file;
616                                         $this->subfolders[$key] = $file;
617                                 }
618                         }
619                         if ($getdeepfiles)
620                                 $this->read_directory($filename, false, $getdeepfiles, $getdeepfiles, $populate);
621                 } elseif (strpos($filename,'/ftp/')===0) {
622                         //ftp files
623                         if ($this->got_rights_array($path) > 0 && !strpos($filename, '.hidden') ) {
624                                 $h = md5($filename);
625                                 $name_only = substr($filename, strlen($path)+1); // this is $file
626                                 $file_structure = explode('.', $name_only); // array of dot separated name fragment
627                                 $ext = array_pop($file_structure); // extension
628                                 $base_name = array_pop($file_structure); // (erk)
629                                 $this->configs[$h]['path'] = $path;
630                                 $this->configs[$h][0] = 'manual ftp';
631                                 $this->configs[$h][2] = $name_only;
632                                 $this->configs[$h][3] = filesize($fsfilename);
633                                 $this->configs[$h]['added'] = filectime($fsfilename);
634                                 $this->configs[$h]['lastchange'] = filemtime($fsfilename);
635                                 $this->configs[$h]['status'] = 'unknown';
636                                 $this->configs[$h]['squashed'] = false;
637                                 $this->configs[$h]['mime'] = $this->set_mime($name_only);
638                                 $this->configs[$h]['hidden'] = is_file(SQUASHER_UPLOADS_DIR.$path.'/'.$base_name.'.hidden');
639                         }
640                 } elseif ($getfirstfiles) {
641                         //squashed files
642                         if ($this->got_rights_array($path) > 0) {
643                                 if (strpos($filename, '.Completed') || strpos($filename, '.InProgress') || strpos($filename, '.Starting') || strpos($filename, '.Processed')) {
644                                         $i++;
645                                         $handle = @fopen($fsfilename, "rb");
646                                         if (strpos($file,'.Completed'))
647                                                 $ext='.Completed';
648                                         if (strpos($file,'.InProgress'))
649                                                 $ext='.InProgress';
650                                         if (strpos($file,'.Starting'))
651                                                 $ext='.Starting';
652                                         if (strpos($file,'.Processed'))
653                                                 $ext='.Processed';
654                                         $sub_pos = strpos($file, $ext);
655                                         $base_name = substr($file, 0, $sub_pos);
656                                         $filecontent = @fread($handle, @filesize($fsfilename));
657                                         $config[$i] = explode("\r\n", $filecontent);
658
659                                         /***
660                                         *       $config:: array
661                                         *       [0]     ->      versioncode
662                                         *       [1]     ->      date&time
663                                         *       [2]     ->      filename
664                                         *       [3]     ->      filesize
665                                         *       [4]     ->      chunksize
666                                         *       [5]     ->      chunkcount
667                                         *       [6]     ->      CRC32 checksum
668                                         ***/
669
670                                         if (@filesize($fsfilename) > 0) {
671                                                 $h = md5($path."/".$config[$i][2]);
672                                                 $this->configs[$h] = $config[$i];
673                                                 $this->configs[$h]['squashed'] = true;
674                                                 $this->configs[$h]['path'] = $path;
675                                                 $this->configs[$h]['status'] = substr($ext, 1);
676                                                 $this->configs[$h]['mime'] = $this->set_mime($this->configs[$h][2]);
677                                                 $this->configs[$h]['hidden'] = is_file(SQUASHER_UPLOADS_DIR.$path.'/'.$base_name.'.hidden');
678                                                 //to prevent dates of 1-1-1970 we set te dates of the config file
679                                                 $this->configs[$h]['added'] = filectime($fsfilename);
680                                                 $this->configs[$h]['lastchange'] = filemtime($fsfilename);
681                                                 fclose($handle);
682                                                 $this->populate_stats($path, $h);
683                                                 //insert hash in db
684                                                 $this->update_hash($h, $path."/".$config[$i][2]);
685                                                 //check stats
686                                                 $this->check_stats($h);
687                                         }
688                                 }
689                         }
690                 }
691         }
692         closedir($hdir);
693 }
694
695 function check_stats($h) {
696         $config = $this->get_config($h);
697         $count = @array_sum($config['stats']);
698         if ($config['status']=='Completed' && $count != $config[5]) {
699                 $filepath=$config['path'].'/'.$config[2];
700                 if ($this->history[$h]['completed']=="1") {
701                         //don't display broken file, remove it instead
702                         unlink(SQUASHER_UPLOADS_DIR.$config['path'].'/'.$config[2].'.Completed');
703                         unset($this->configs[$h]);
704
705                         if (!$count)
706                                 $count = 0;
707                         $m_subject = "Squasher Debug: File Removed";
708                         $m_body = "Upload removed: \n File: ".$config['path']."/".$config[2]." \n Status: ".$config['status']." \n Chunks: ".$count." out of ".$config[5];
709                         mail('jasper@netformatie.nl', $m_subject, $m_body, "From: support@netformatie.nl");
710                         
711                         log_event('debug', $filepath, $h, 'cleanup');
712                 } else {
713                         //do move
714                         rename(SQUASHER_UPLOADS_DIR.$config['path'].'/'.$config[2].'.Completed',
715                                SQUASHER_UPLOADS_DIR.$config['path'].'/'.$config[2].'.InProgress');
716                         $this->configs[$h]['status'] = 'InProgress';
717
718                         //mail n4m
719                         if (!$count)
720                                 $count = 0;
721                         $m_subject = "Squasher Debug: Upload Error";
722                         $m_body = "Upload error: \n File: ".$config['path']."/".$config[2]." \n Status: ".$config['status']." \n Chunks: ".$count." out of ".$config[5];
723                         mail('support@netformatie.nl', $m_subject, $m_body, "From: squasher@netformatie.nl");
724                         mail('jan@netformatie.nl', $m_subject, $m_body, "From: support@netformatie.nl");
725                         mail('joop@netformatie.nl', $m_subject, $m_body, "From: support@netformatie.nl");
726                         mail('jasper@netformatie.nl', $m_subject, $m_body, "From: support@netformatie.nl");
727
728                         //do sms
729                         //wget -o/dev/null "http://www.mollie.nl/xml/sms/?username=netformatie&password=SMSdolsi&originator=Netformatie&recipients=${ENGINEER}&message=${CALLERID}";
730
731                         //mail RO
732                         $ship = explode('/',$config['path']);
733                         if ($ship[2] == 'myas' || $ship[2] == 'myez' || $ship[2] == 'myrw')
734                                 mail('ro1@'.$ship[2].'.greenpeace.org','Squasher: '.$config[2].' resume request','The squasher server has detected an upload error. Please resume the squasher transmission for '.$config[2].' to correct this problem.',"From: support@netformatie.nl\nX-Priority: 1");
735                         log_event('debug', $filepath, $h, 'retry');
736
737                 }
738         } elseif ($config['status']=='Completed' && $count == $config[5]) {
739                 if ($this->history[$h]['completed']==0)
740                         mysql_query("UPDATE file_hash SET completed = 1 WHERE md5_hash = '".mysql_escape_string($h)."'");
741         }
742 }
743
744 function update_hash($hash, $path) {
745         $check_hash_query = "select * from file_hash where md5_hash = '".$hash."'";
746         $check_hash_result = mysql_query($check_hash_query);
747         if(mysql_num_rows($check_hash_result) == 0) {
748                 $insert_hash_query = "INSERT INTO file_hash (md5_hash,file) values ('".mysql_escape_string($hash)."','".mysql_escape_string($path)."')";
749                 mysql_query($insert_hash_query);
750         }
751 }
752
753 /* unused function */
754 /*
755 function path_to_arraystring($path, $arrayname) {
756         $path_values = explode('/', $path);
757         $return = $arrayname;
758         foreach ($path_values AS $key => $value) {
759                 if ($value != '.' && $value != '')
760                         $return.= "['".$value."']";
761         }
762         return $return;
763 } */
764
765 function populate_stats($path, $h) {
766         /***
767         *       $config:: array
768         *       [0]     ->      versioncode
769         *       [1]     ->      date&time
770         *       [2]     ->      filename
771         *       [3]     ->      filesize
772         *       [4]     ->      chunksize
773         *       [5]     ->      chunkcount
774         *       [6]     ->      CRC32 checksum
775         ***/
776         $config = $this->configs[$h];
777
778         $q = "SELECT * FROM file_hash WHERE md5_hash = '".mysql_escape_string($h)."'";
779         $r = mysql_query($q);
780         $o = mysql_fetch_object($r);
781         $validated_chunks = $o->validated_chunks;
782
783         if ($this->history[$h]['completed']=="1") {
784                 $file_part = $path."/SQ".zfill(1,6)."-".$config[2];
785                 if (!is_file(SQUASHER_UPLOADS_DIR.$file_part))
786                         $file_part = $path."/SQ".zfill(1,3)."-".$config[2];
787                 if (is_file(SQUASHER_UPLOADS_DIR.$file_part)) {
788                         $this->configs[$h]['added'] = filectime(SQUASHER_UPLOADS_DIR.$file_part);
789                         $file_part = $path."/SQ".zfill($config[5],6)."-".$config[2];
790                         if (!is_file(SQUASHER_UPLOADS_DIR.$file_part))
791                                 $file_part = $path."/SQ".zfill($config[5],3)."-".$config[2];
792                         if (is_file(SQUASHER_UPLOADS_DIR.$file_part))
793                                 $this->configs[$h]['lastchange'] = filemtime(SQUASHER_UPLOADS_DIR.$file_part);
794                         for ($i=1; $i<=$config[5]; $i++)
795                                 $this->configs[$h]['stats'][$i] = "1.00";
796                 } else {
797                         //failsafe voor verwijderde bestanden
798                         mysql_query("UPDATE file_hash SET completed = 0 WHERE md5_hash = '".mysql_escape_string($h)."'");
799                 }
800         } else {
801                 $keep_validating = true;
802                 for ($i=1; $i<=$config[5]; $i++) {
803                         if ($validated_chunks > $i) {
804                                 $this->configs[$h]['stats'][$i]="1.00";
805                         } else {
806                                 $file_part = $path."/SQ".zfill($i,6)."-".$config[2];
807                                 if (!is_file(SQUASHER_UPLOADS_DIR.$file_part))
808                                         $file_part = $path."/SQ".zfill($i,3)."-".$config[2];
809                                 if (is_file(SQUASHER_UPLOADS_DIR.$file_part)) {
810                                         $handle = fopen(SQUASHER_UPLOADS_DIR.$file_part, "rb");
811                                         $size_this = filesize(SQUASHER_UPLOADS_DIR.$file_part);
812                                         $added = filectime(SQUASHER_UPLOADS_DIR.$file_part);
813                                         $last_changed = filemtime(SQUASHER_UPLOADS_DIR.$file_part);
814                                         if ($this->configs[$h]['added'] > $added || !is_numeric($this->configs[$h]['added']))
815                                                 $this->configs[$h]['added'] = $added;
816                                         if ($this->configs[$h]['lastchange'] < $last_changed)
817                                                 $this->configs[$h]['lastchange'] = $last_changed;
818                                         if ($i != $config[5]) {
819                                                 $this->configs[$h]['stats'][$i] = number_format((1/$config[4])*$size_this, 2, '.', '');
820                                         //number_format((100/$config[4])*$size_this, 2, '.', '')."%";
821                                         }else{
822                                                 $this->configs[$h]['stats'][$i] = number_format((1/($config[3]-($config[4]*($config[5]-1))))*$size_this, 2, '.', '');
823                                                 //number_format((100/($config[3]-($config[4]*($config[5]-1))))*$size_this, 2, '.', '')."%";
824                                         }
825                                         fclose($handle);
826                                         if ($config[4] == $size_this && $keep_validating) {
827                                                 $validated_chunks = $i;
828                                         } else {
829                                                 $keep_validating = false;
830                                         }
831                                 } else {
832                                         $this->configs[$h]['stats'][$i] = "0.00";
833                                         //$this->configs[$h]['stats'][$i]="0.00%";
834
835                                 }
836                         }
837                 }
838                 mysql_query("UPDATE file_hash SET validated_chunks = '".mysql_escape_string($validated_chunks)."' WHERE md5_hash = '".mysql_escape_string($h)."'");
839         }
840 }
841
842
843 /* unused function
844 function read_config($path, $filename) {
845         if (is_file($path."/".$filename.".InProgress")) {
846                 $config_handle = fopen($path."/".$filename.".InProgress", "r");
847                 $conf_path=$path."/".$filename.".InProgress";
848         } elseif (is_file($path."/".$filename.".Completed" )) {
849                 $config_handle = fopen($path."/".$filename.".Completed", "r");
850                 $conf_path=$path."/".$filename.".Completed";
851         } elseif (is_file($path."/".$filename.".Starting" )) {
852                 $config_handle = fopen($path."/".$filename.".Starting", "r");
853                 $conf_path=$path."/".$filename.".Starting";
854         } elseif (is_file($path."/".$filename.".Processed" )) {
855                 $config_handle = fopen($path."/".$filename.".Processed", "r");
856                 $conf_path=$path."/".$filename.".Processed";
857         } else {
858                 return "Not Found";
859         }
860         $config_content = fread($config_handle, filesize($conf_path));
861         fclose($config_handle);
862         $config = explode("\n", $config_content);
863
864         return $config;
865 }
866 */
867 //              print_r($config);
868 /*              $file_count = $config[5];
869                 $last=1;
870     for ($i=1; $i<=$file_count; $i++)
871     {
872         $file_part = $path."/SQ".zfill($i,6)."-".$filename;
873         if (is_file($file_part))
874        {
875
876         $handle = fopen($file_part, "rb");
877         $size_this = filesize($file_part);
878                                 //$stats[$i]=round((100/$config[4])*$size_this)."%";
879                                 if ((($size_this==$config[4] && ($last+1)==$i) )|| $i == $config[5]) {
880                                         $merged_file.=fread($handle, filesize($file_part));
881                                         $last = $i;
882                                 }
883         fclose($handle);
884        }
885      }
886      return $merged_file;
887      */
888
889 /**
890  * Outputs one file (echo)
891  * @param string $path Absolute path within SQUASHER_UPLOADS_DIR
892  * @param string $filename File name in $path
893  * @param bool $tovar Returns content rather than outputing it
894  * @return file content if $tovar; or void
895  */
896 function print_files($path, $filename, $tovar=false) {
897         $fsfilename = SQUASHER_UPLOADS_DIR.$path.'/'.$filename;
898         if (strpos($path.'/', '/ftp/')===0) {
899                 if (is_file($fsfilename)) {
900                         $handle = fopen($fsfilename, 'rb');
901                         while (!feof($handle))
902                         {
903                                 print(fread($handle, 1024));
904                                 ob_flush();
905                                 flush();
906                         }
907                 }
908         } else {
909                 if (is_file($fsfilename.'.InProgress'))
910                         $conf_path = $fsfilename.'.InProgress';
911                 elseif (is_file($fsfilename.'.Completed' ))
912                         $conf_path = $fsfilename.'.Completed';
913                 elseif (is_file($fsfilename.'.Starting' ))
914                         $conf_path = $fsfilename.'.Starting';
915                 elseif (is_file($fsfilename.'.Processed' ))
916                         $conf_path = $fsfilename.'.Processed';
917                 else
918                         return 'Not Found';
919                 $config_handle = fopen($conf_path, 'r');
920                 $config_content = fread($config_handle, filesize($conf_path));
921                 fclose($config_handle);
922                 $config = explode("\n",$config_content);
923 //              print_r($config);
924                 $file_count = $config[5];
925                 $last = 0;
926                 $last_part_size = ( $config[3] - ( ( $config[5] -1 ) * $config[4] ) );
927                 for ($i=0;$i<=$file_count;$i++)
928                 {
929                         $file_part = SQUASHER_UPLOADS_DIR.$path."/SQ".zfill($i,6)."-".$filename;
930                         if (!is_file($file_part))
931                                 $file_part = $path."/SQ".zfill($i,3)."-".$filename;
932                         if (is_file($file_part))
933                         {
934                                 $handle = fopen($file_part, "rb");
935                                 $size_this = filesize($file_part);
936                                 if ( ( ( $size_this==$config[4] ) && ( ($last+1)==$i ) ) || ( ( $i == $config[5] ) && ( $size_this==$last_part_size ) && ( ($last+1)==$i ) ) ) {
937                                         if ($tovar) {
938                                                 $merged_file.=fread($handle, $size_this);
939                                                 $last = $i;
940                                         } else {
941                                                 while (!feof($handle))
942                                                 {
943                                                         print(fread($handle, 4096));
944                                                 #       @ob_flush();
945                                                 #       @flush();
946                                                 }
947                                                 $last = $i;
948                                         }
949                                 }
950                                 fclose($handle);
951                         }
952                 }
953                 if ($tovar)
954                         return $merged_file;
955         }
956 }
957
958 /* unused function */
959 /*
960 function check_md5($h) {
961         $return = false;
962         $config = $this->configs[$h];
963         $var = $this->print_files($config['path'], $config[2], true);
964         $hash = md5($var);
965         if ($hash==$config[6])
966                 $return=true;
967
968         return $return;
969 } */
970
971 /* unused function */
972 /*
973 function file_crc($file_string) {
974         //$file_string = file_get_contents($file);
975
976         $crc = crc32($file_string);
977         return sprintf("%u\n", $crc);
978 } */
979
980 /* unused function */
981 /*
982 function file_crc_debug($file) {
983         $file_string = file_get_contents($file);
984
985         $crc = crc32($file_string);
986         return sprintf("%u\n", $crc);
987 } */
988
989 /**
990  * Delete one file
991  *
992  * @param string $h Md5 hash of the file path, in lower case
993  * @param array $s Session credidentials
994  */
995 function delete_file($h, $s) {
996         $request = $this->get_config($h);
997         $filepath = $request['path'].'/'.$request[2];
998         if (strpos($request['path'], '/ftp/')===0) {
999                 #remove file
1000                 $fsfilepath = SQUASHER_UPLOADS_DIR.$filepath;
1001                 if (is_file($fsfilepath))
1002                         @unlink($fsfilepath);
1003                 if (is_file($fsfilepath.'.hidden'))
1004                         @unlink($fsfilepath.'.hidden');
1005         } else {
1006                 $fspath = SQUASHER_UPLOADS_DIR.$request['path'];
1007                 #remove fileparts
1008                 for ($i=0;$i<=$request[5];$i++) {
1009                         $part_six   = $fspath.'/SQ'.zfill($i,6).'-'.$request[2];
1010                         $part_three = $fspath.'/SQ'.zfill($i,3).'-'.$request[2];
1011                         if (is_file($part_six))
1012                                 @unlink($part_six);
1013                         if (is_file($part_three))
1014                                 @unlink($part_three);
1015                 }
1016                 #remove config file
1017                 if (is_file($fspath.'/'.$request[2].'.hidden'))
1018                         @unlink($fspath.'/'.$request[2].'.hidden');
1019                 if (is_file($fspath.'/'.$request[2].'.Completed'))
1020                         @unlink($fspath.'/'.$request[2].'.Completed');
1021                 if (is_file($fspath.'/'.$request[2].'.InProgress'))
1022                         @unlink($fspath.'/'.$request[2].'.InProgress');
1023                 if (is_file($fspath.'/'.$request[2].'.Processed'))
1024                         @unlink($fspath.'/'.$request[2].'.Processed');
1025                 if (is_file($fspath.'/'.$request[2].'.Starting'))
1026                         @unlink($fspath.'/'.$request[2].'.Starting');
1027         }
1028
1029         #Update DB
1030         $q = "DELETE FROM file_hash WHERE md5_hash = '".mysql_escape_string($h)."'";
1031         mysql_query($q);
1032
1033         log_event('delete', $filepath, $h);
1034
1035         #Send debug mail
1036         $m_name = $s['user_name'];
1037         $m_subject = "Squasher Debug: File Deleted by {$m_name}";
1038         $m_body = "File Deleted: \n Requested by: {$m_name} \n File: {$filepath}";
1039         mail('jasper@netformatie.nl', $m_subject, $m_body, "From: support@netformatie.nl");
1040 }
1041
1042 /* unused debug function (echo / print_r)
1043 function show_files() {
1044
1045         $path = "./uploads/";
1046
1047         if ($dir = opendir($path)) {
1048                 $i = 1;
1049                 $last = 1;
1050                 $files = array();
1051                 $files_merged = array();
1052                 while (false !== ($file = readdir($dir)))
1053                 {
1054                         if (($file !== ".") && ($file !== ".."))
1055                         {
1056                                 $filename = $path.$file;
1057                                 $handle = fopen($filename, "rb");
1058                                 $size_this = filesize($filename);
1059                                 if ($i==1)
1060                                         $size_first = $size_this;
1061                                 $filecontent = fread($handle, filesize($filename));
1062                                 $files[$i++] = $filename;
1063                                 $files_merged[$file_base][]=$filename;
1064                                 fclose($handle);
1065                         }
1066                 }
1067         }
1068         echo "<pre>";
1069         print_r($files);
1070         print_r($files_merged);
1071         echo "</pre>";
1072 }
1073 */
1074
1075 /**
1076  * Get mime-type from filename
1077  *
1078  * Defaults to 'application/octet-stream'
1079  *
1080  * @param string $filename The filename with an extension
1081  * @return string mime type
1082  */
1083 function set_mime($filename) {
1084         $ext_arr = explode('.', $filename);
1085         $ext = strtolower(array_pop($ext_arr));
1086         switch($ext) {
1087                 case 'avi':
1088                         $mime = 'video/avi';
1089                         break;
1090                 case 'mpeg':
1091                 case 'mpg':
1092                         $mime = 'video/mpeg';                                   //MPEG Video
1093                         break;
1094                 case 'exe':
1095                 case 'bat':
1096                 case 'doc':
1097                 case 'xls':
1098                         $mime = 'application/octet-stream';
1099                         break;
1100                 case 'gif':
1101                         $mime = 'image/gif';                                    //GIF Image
1102                         break;
1103                 case 'jpg':
1104                 case 'jpeg':
1105                         $mime = 'image/jpeg';                                   //JPEG Image
1106                         break;
1107                 case 'png':
1108                         $mime = 'image/png';                                    //PNG Image
1109                         break;
1110                 case 'wav':
1111                 case 'wave':
1112                         $mime = 'audio/wav';                                    //WAV Audio
1113                         break;
1114                 case 'mp3':
1115                         $mime = 'audio/mpeg';                                   //MP3 Audio
1116                         break;
1117                 case 'mov':
1118                         $mime = 'video/mov';                                    //Quicktime Video
1119                         break;
1120                 case 'wmv':
1121                         $mime = 'video/x-ms-wmv';                       //Windows WMV video
1122                         break;
1123                 case 'wma':
1124                         $mime = 'audio/x-ms-wma';                       //Windows WMA audio
1125                         break;
1126                 case 'rm':
1127                         $mime = 'audio/x-realaudio';    //RealPlayer Audio/Video (.rm)
1128                         break;
1129                 case 'ram':
1130                         $mime = 'audio/x-pn-realaudio'; //RealPlayer Audio/Video (.ram)
1131                         break;
1132                 case 'pdf':
1133                         $mime = 'application/pdf';              //PDF Document
1134                         break;
1135                 case 'doc':
1136                         $mime = 'application/msword';   //MS Word .doc file
1137                         break;
1138                 case 'zip':
1139                         $mime = 'application/zip';              //Zip File
1140                         break;
1141                 default:
1142                         $mime = 'application/octet-stream';
1143                         break;
1144         }
1145         //$return['mime']=$mime;
1146         //$return['ext']=$ext;
1147
1148         return $mime;
1149 }
1150
1151 }
1152 // vim: syntax=php ts=4 sw=4 sts=4 sr noet
1153 ?>