<?php
class files{
protected $_config_file_name = '.!config.dir.ini'; // название конфиг-файла
protected $_data = array(); // параметры директории
protected $_need_save = false; // необходимость сохранения параметров директории
protected $_screens = array(); // список скриншотов
protected $_keys = array(); // ключи, доступные для сортировки
var $sort = 'runame:asc'; // сортировка по-умолчанию

function __construct($path_abs)
{
$path_abs = realpath($path_abs);

$this -> _data['type'] = 'folder'; // тип содержимого 
$this -> _data['runame'] = convert::to_utf8(basename($path_abs)); // отображаемое название папки
$this -> _data['group_show'] = 2; // группа пользователей, которой разрешен просмотр папки
$this -> _data['group_write'] = 3; // группа пользователей, которой разрешено создание вложенных файлов и папок
$this -> _data['group_edit'] = groups::max(); // группа пользователей, которой разрешено изменение параметров данной папки
$this -> _data['position'] = 1; // позиция. Учитывается при сортировке
$this -> _data['id_user'] = 0; // создатель папки (группы)
$this -> _data['description'] = '';
$this -> _data['time_last'] = 0; // время последних действий

if ($cfg_ini = ini::read($path_abs.'/'.$this -> _config_file_name, true)){
// загружаем конфиг
$this -> _data = array_merge($this->_data, (array)@$cfg_ini['CONFIG']);
$this -> _screens = array_merge($this -> _screens, (array)@$cfg_ini['SCREENS']);
$this -> _keys = array_merge($this -> _keys, (array)@$cfg_ini['ADDKEYS']);
}
else
{


$this -> _data['time_create'] = TIME; // время создания
$this -> _need_save = true;
}


// настоящее имя папки
$this -> _data['name'] = basename($path_abs);



$this -> _setPathes($path_abs);
}

public function filesAdd($files)
{
$ok = array();
$files = (array)$files;
foreach ($files as $path => $runame) {
$name = text::for_filename($runame); 

if (move_uploaded_file($path, $this -> _data['path_abs'].'/'.$name))
{
$ok[$path] = $f_obj = new files_file($this -> _data['path_abs'], $name);
$f_obj -> runame = $runame;
$f_obj -> time_add = TIME;

}

}


$this -> cacheClear();
return $ok;
}


// очистка кэша директории (а также проверка соответствия записей в базе реальным файлам)
public function cacheClear()
{
$path_rel_ru = convert::to_utf8($this -> _data['path_rel']);
$q = mysql_query("SELECT * FROM `files_cache` WHERE `path_file_rel` LIKE '".my_esc($path_rel_ru)."/%'");
while ($files = mysql_fetch_assoc($q)) {
	$abs_path = FILES.convert::of_utf8($files['path_file_rel']);
	if (is_file($abs_path))continue; // если файл существует, то все ОК, пропускаем
	
//	НО!!! Если файла нет, то это лишняя запись в базе, которую необходимо "похерить"

// удаление файла из кэша базы
mysql_query("DELETE FROM `files_cache` WHERE `id` = '".intval($files['id'])."' LIMIT 1");
// удаление комментов к файлу
mysql_query("DELETE FROM `files_comments` WHERE `id_file` = '".intval($files['id'])."'");
}


// а так же очистка кэша содержимого папки
global $cache;
$cache -> set('files.'.$this -> _data['path_rel'],false,1);
$this -> _need_save = true;
}

// создание папки
public function mkdir($runame, $name = false)
{

if ($name)
$name = text::for_filename($name);
else
$name = text::for_filename($runame);

if (!filesystem::mkdir($this -> _data['path_abs'].'/'.$name))return false;



$new_dir = new files($this -> _data['path_abs'].'/'.$name);
$new_dir -> runame = $runame;
$new_dir -> group_show = $this -> _data['group_show'];
$new_dir -> group_write = $this -> _data['group_write'];
$new_dir -> group_edit = $this -> _data['group_edit'];
$new_dir -> time_create = TIME;

$this -> cacheClear();

return $new_dir;
}


// удаление папки со всем содержимым
public function delete()
{
// если папки не существует, то и удалять ее не можем.
if (!is_dir($this -> _data['path_abs']))return false;
// папки и файлы с точкой являются системными и их случайное удаление крайне нежелательно
if ($this -> _data['name']{0} === '.')return false;



$od = opendir($this -> _data['path_abs']);

while ($rd = readdir($od)) {
	if ($rd{0} == '.')continue;

	if(is_dir($this -> _data['path_abs'].'/'.$rd))
	{
		if (function_exists('set_time_limit'))set_time_limit(30);
	$dir = new files($this -> _data['path_abs'].'/'.$rd);
	$dir -> delete(); // "Правильное" рекурсивное удаление папки
  }
  elseif(is_file($this -> _data['path_abs'].'/'.$rd))
	{
	$file = new files_file($this -> _data['path_abs'], $rd);
	$file -> delete(); // "Правильное" удаление файла
  }

}

closedir($od);

	if (function_exists('set_time_limit'))set_time_limit(30);
if (filesystem::rmdir($this -> _data['path_abs']))
{

$ld = pathinfo($this -> _data['path_abs']);
$last_dir = new files($ld['dirname']);
$last_dir -> cacheClear();

$this -> __destruct();
return true;
}

}



// получение новых файлов
public function getNewFiles($time = 0)
{
$time = (int)$time;
global $user;
$content = array('dirs' => array(), 'files' => array());
$path_rel_ru = convert::to_utf8($this -> _data['path_rel']);
$q = mysql_query("SELECT * FROM `files_cache` WHERE `group_show` <= '".intval($user -> group)."' AND `path_file_rel` LIKE '".my_esc($path_rel_ru)."/%' AND `path_file_rel` NOT LIKE '".my_esc($path_rel_ru)."/.%' AND `time_add` > '$time' ORDER BY `time_add` DESC");

while ($files = mysql_fetch_assoc($q)) {
	$abs_path = FILES.convert::of_utf8($files['path_file_rel']);
	if (!is_file($abs_path))continue;
	$pathinfo = pathinfo($abs_path);
	$content['files'][] = new files_file($pathinfo['dirname'],$pathinfo['basename']);
}

return $content;
}


// поиск файлов в папке и во всех вложенных папках
protected function _search($search)
{
global $user;
$content = array('dirs' => array(), 'files' => array());
$path_rel_ru = convert::to_utf8($this -> _data['path_rel']);
$q = mysql_query("SELECT * FROM `files_cache` WHERE `group_show` <= '".intval($user -> group)."' AND `path_file_rel` LIKE '".my_esc($path_rel_ru)."/%' AND `path_file_rel` NOT LIKE '".my_esc($path_rel_ru)."/.%' AND `runame` LIKE '%".my_esc($search)."%'");

while ($files = mysql_fetch_assoc($q)) {
	$abs_path = FILES.convert::of_utf8($files['path_file_rel']);
	if (!is_file($abs_path))continue;
	$pathinfo = pathinfo($abs_path);
	$content['files'][] = new files_file($pathinfo['dirname'],$pathinfo['basename']);
}

return $content;
}


// количество файлов с времени $time
public function count($time = 0)
{
global $user,$cache;

if ($count = $cache -> get('files.count.'.$this -> _data['path_rel'].'.'.$time))
return $count;


$path_rel_ru = convert::to_utf8($this -> _data['path_rel']);
$count = mysql_result(mysql_query("SELECT COUNT(*) FROM `files_cache` WHERE `group_show` <= '".intval($user -> group)."' AND `time_add` > '".intval($time)."' AND `path_file_rel` LIKE '".my_esc($path_rel_ru)."/%' AND `path_file_rel` NOT LIKE '".my_esc($path_rel_ru)."/.%'"),0);

$cache -> set('files.count.'.$this -> _data['path_rel'].'.'.$time, $count, 600);
return $count;
}

public function getKeys()
{
$keys = array();
$keys['runame:asc'] = 'Название';
$keys['size:desc'] = 'Размер';
$keys['time_add:desc'] = 'Время добавления';

return array_merge($keys, $this -> _keys);
}


// получаем содержимое директории (без использования кэширования)
protected function _getListFull()
{
global $cache;
if ($content = $cache -> get('files.'.$this -> _data['path_rel']))return $content;


$this -> _keys = array();
$content = array('dirs' => array(), 'files' => array());
$od = opendir($this -> _data['path_abs']);


while ($rd = readdir($od)) {
	if ($rd{0}=='.')continue; // все файлы и папки начинающиеся с точки пропускаем

	if(is_dir($this -> _data['path_abs'].'/'.$rd))
	{
	$content['dirs'][] = new files($this -> _data['path_abs'].'/'.$rd);
  }
  elseif(is_file($this -> _data['path_abs'].'/'.$rd))
	{
	$content['files'][] = $file = new files_file($this -> _data['path_abs'],$rd);
	$this -> _keys = array_merge($this -> _keys, $file -> getKeys());
  }

}

//if (count($content['dirs']) + count($content['files']) > 30)
$cache -> set('files.'.$this -> _data['path_rel'],$content,60);


$this -> _need_save = true;
closedir($od);
return $content;
}






protected function _sort_cmp($f1,$f2)
{
$sn = $this -> sort; // сортировка пользователя
if ($f1 -> $sn == $f2 -> $sn) {
return 0;
}
return ($f1 -> $sn < $f2 -> $sn) ? -1 : 1;
}

protected function _listSort($list,$sort)
{

$this -> sort = 'position';
usort($list['dirs'], array($this,'_sort_cmp'));
usort($list['files'], array($this,'_sort_cmp'));

if (!empty($sort)){
@list($this -> sort,$order) = @explode(':', $sort);
usort($list['dirs'], array($this,'_sort_cmp'));
usort($list['files'], array($this,'_sort_cmp'));

if ($order=='desc')$list['files']=array_reverse($list['files']);
}

return $list;
}

protected function _listFilter($list)
{
global $user;
$list2= array();
$c = count($list);
for ($i=0;$i<$c;$i++)
{
if ($list[$i] -> group_show <= $user -> group)$list2[]=$list[$i];
}
return $list2;
}


// получаем список содержимого директории (группы)
public function getList($sort=false,$search=false)
{

if ($search)
$list = $this -> _search($search); // получение списка файлов по запросу
else
$list = $this -> _getListFull(); // получение списка содержимого


$list['dirs'] = $this -> _listFilter($list['dirs']); // отсеиваем недоступные папки 
$list['files'] = $this -> _listFilter($list['files']); // отсеиваем недоступные файлы
$list = $this -> _listSort($list,$sort); // сортируем
return $list;
}

// получение пути на русском языке
public function getPathRu()
{
$return = array();
$all_path = array();
if ($this -> _data['path_rel']){
$path_rel = preg_split('#/+#', $this -> _data['path_rel']);
if ($path_rel){
//$all_path[]='/';
foreach ($path_rel as $key=>$value) {
$path = '';
	for ($i=0;$i<$key;$i++){
  $path .= $path_rel[$i].'/';
  }
  if ($path)$all_path[]=$path;	
}
}


if ($all_path){
for ($i=0;$i<count($all_path);$i++)
{
$cnf = new files(FILES.'/'.$all_path[$i]);
$return[] = $cnf -> runame;
}
}
}

return ($return?implode('/',$return).'/':'').$this -> _data['runame'];
}

// получение пути к папке для ссылки
public function getPath()
{
$path_rel = preg_split('#/+#', $this -> _data['path_rel']);
foreach ($path_rel as $key=>$value) {
	$path_rel[$key] = urlencode($value);
}
return implode('/',$path_rel).'/';
}


public function getScreens()
{
$screens = array();
foreach ($this -> _screens as $key=>$value) {
	if(is_file($this -> _data['path_abs'].'/'.$value))
	$screens[] = $this -> _data['path_rel'].'/'.$value;
}
return $screens;
}



// вывод массива путей для возврата
public function ret($k=5)
{
$return = array();
$all_path = array();
if ($this -> _data['path_rel']){
$path_rel = preg_split('#/+#', $this -> _data['path_rel']);
if ($path_rel){
//$all_path[]='/';
foreach ($path_rel as $key=>$value) {
$path = '';
	for ($i=0;$i<$key;$i++){
  $path .= $path_rel[$i].'/';
  }
  if ($path)$all_path[]=$path;	
}
}


if ($all_path){
$all_path = array_reverse($all_path);
for ($i=0;$i<$k && $i<count($all_path);$i++)
{
$cnf = new files(FILES.'/'.$all_path[$i]);
$return[] = array('path'=> $cnf -> getPath(),'runame'=>$cnf -> runame);
}
}
}
return $return;
}



public function icon()
{
return array('size' =>'small', 'src' => '/sys/images/icons_files/' . $this -> _data['type'] . '.png');
}


// перемещение папки
public function move($new_path_abs)
{
$new_path_abs = filesystem::unixpath($new_path_abs);

// если новое расположение выходит за рамки Папки загрузок
if (strpos($new_path_abs, filesystem::unixpath(FILES))!==0)return false;

// новое расположение не может находиться внутри текущего
if (strpos($new_path_abs, $this -> _data['path_abs']) === 0)return false;

// если нихрена не прокатило
if (!rename($this -> _data['path_abs'], $new_path_abs))return false;

$path_rel_ru_old = convert::to_utf8($this -> _data['path_rel']);
$this -> _setPathes($new_path_abs);
$path_rel_ru_new = convert::to_utf8($this -> _data['path_rel']);

// не забываем и в базе изменить путь вложенных файлов
mysql_query("UPDATE `files_cache` SET `path_file_rel` = REPLACE(`path_file_rel`, '".my_esc($path_rel_ru_old)."', '".my_esc($path_rel_ru_new)."') WHERE `path_file_rel` LIKE '".my_esc($path_rel_ru_old)."/%'");

$np = pathinfo($new_path_abs);
$to_dir = new files($np['dirname']);
$to_dir -> cacheClear();

$this -> _need_save = true;
return true;
}

// установка путей
protected function _setPathes($path_dir_abs)
{
// полный путь к папке
$this -> _data['path_abs'] = filesystem::unixpath($path_dir_abs);

// относительный путь к папке
$this -> _data['path_rel'] = str_replace(filesystem::unixpath(FILES), '', $this ->_data['path_abs']);

}

// переименование папки
public function rename($runame,$realname)
{
if ($this -> _data['path_rel'] && $this->_data['name']{0}!=='.')
{
$path_new = preg_replace('#[^\/\\\]+$#u', $realname, $this -> _data['path_rel']);

if (!@rename($this -> _data['path_abs'], FILES.$path_new))return false;
else
{
$this -> _data['name'] = basename($path_new);
}


$path_rel_ru_old = convert::to_utf8($this -> _data['path_rel']);
$this -> _setPathes(FILES.$path_new);
$path_rel_ru_new = convert::to_utf8($this -> _data['path_rel']);

// не забываем и в базе изменить путь вложенных файлов
mysql_query("UPDATE `files_cache` SET `path_file_rel` = REPLACE(`path_file_rel`, '".my_esc($path_rel_ru_old)."', '".my_esc($path_rel_ru_new)."') WHERE `path_file_rel` LIKE '".my_esc($path_rel_ru_old)."/%'");

}

$np = pathinfo($this -> _data['path_abs']);
$to_dir = new files($np['dirname']);
$to_dir -> cacheClear();

$this -> _data['runame'] = $runame;
$this -> _need_save = true;
return true;
}

// получение всех объектов папок (рекурсивно)
public function getPathesRecurse($exclude = false)
{
$dirs = array();
$od = opendir($this -> _data['path_abs']);

while ($rd = readdir($od)) {
	if ($rd == '.' || $rd == '..')continue;

	if(is_dir($this -> _data['path_abs'].'/'.$rd))
	{
	if (function_exists('set_time_limit'))set_time_limit(30);
 $dir = new files($this -> _data['path_abs'].'/'.$rd);
 
//if ($dir -> name{0}!=='.')
$dirs[] = $dir;
 // обработка исключений
 if ($exclude && strpos($dir -> path_abs, $exclude -> path_abs)===0) continue;
 	
	$dirs = array_merge($dirs, $dir -> getPathesRecurse($exclude));
  }

}

closedir($od);

return $dirs;
}

// установка группы пользователей, которым разрешено просматривать директорию
// данный параметр будет рекурсивно применен ко всем вложенным объектам
public function setGroupShowRecurse($group_show)
{
$od = opendir($this -> _data['path_abs']);

while ($rd = readdir($od)) {
	if ($rd{0} == '.')continue;

	if(is_dir($this -> _data['path_abs'].'/'.$rd))
	{
	if (function_exists('set_time_limit'))set_time_limit(30);
	$dir = new files($this -> _data['path_abs'].'/'.$rd);
	$dir -> setGroupShowRecurse($group_show);
  }
  elseif(is_file($this -> _data['path_abs'].'/'.$rd))
	{
	$file = new files_file($this -> _data['path_abs'], $rd);
	$file -> group_show = $group_show;
  }

}

closedir($od);

$this -> cacheClear();
$this -> _data['group_show'] = $group_show;
$this -> _need_save = true;

}


function __get($n)
{
if (isset($this -> _data[$n]))return $this -> _data[$n];else return false;
}

function __set($n,$v)
{
if (!isset($this -> _data[$n]))return false;

$this -> _data[$n] = $v;
$this -> _need_save = true;
}


function __destruct()
{
if ($this -> _need_save)
{
$this -> _data['time_last'] = TIME; // время последних действий

ini::save($this -> _data['path_abs'].'/'.$this -> _config_file_name, 
array('CONFIG' => $this -> _data, 'SCREENS' => $this -> _screens, 'ADDKEYS' => $this -> _keys), true);
}
}



}
?>
