visible = $visible; } public function setHiddenFiles(array $hidden) { $this->hidden = array_merge($this->hidden, $hidden); } /** * */ public function makeDirectory($name) { if (file_exists($name) === false) { mkdir($name); } } /** * */ public function makeFile($name) { if (file_exists($name) === false) { file_put_contents($name, ''); } } /** * */ public function deleteDirectory($name) { rmdir($name); } /** * */ public function deleteDirectoryRecursive($name) { if ($handle = opendir($name)) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $sf = $name . DIRECTORY_SEPARATOR . $file; if (is_dir($sf) && !is_link($sf)) { self::deleteDirectoryRecursive($sf); } else { unlink($sf); } } } closedir($handle); @rmdir($name); } } /** * */ public function deleteFile($name) { if (file_exists($name)) { unlink($name); } } // При перемещении или все файлы если есть совпадения переписываются /** * */ public function renameFile($source, $destination) { rename($source, $destination); } /** * */ public function copyFile($source, $destination) { copy($source, $destination); } /** * */ public function copyDirectory($source, $destination) { if (is_dir($source)) { if (! file_exists($destination)) mkdir($destination); $handle = opendir($source); while (false !== ($file = readdir($handle))) { $entry = $source . DIRECTORY_SEPARATOR . $file; if (is_dir($entry)) { self::copyDirectory($entry, $destination . DIRECTORY_SEPARATOR . $file); } else { copy($entry, $destination . DIRECTORY_SEPARATOR . $file); } } } } /** * */ public function moveUploadedFile($source, $destination) { move_uploaded_file($source, $destination); } /** * */ public function isVisible($file) { if (in_array(basename($file), $this->hidden) === true) { return false; } return ($this->isDir($file) || $this->visible == null) || in_array(pathinfo($file, PATHINFO_EXTENSION), $this->visible); } /** * */ public function directoryFiles($name) { $result = array(); $files = scandir($name); foreach ($files as $file) { $fullname = $name . DIRECTORY_SEPARATOR . $file; if ($this->isVisible($fullname)) { $result [$file] = new FileRecord(array(), $fullname); } } return $result; } /** * */ public function readFile($name) { return file_get_contents($name); } /** * */ public function writeFile($name, $content) { file_put_contents($name, $content); } /** * */ public function directoryFilesRecursive($name) { } function isDir($name) { return is_dir($name); } } // То что хранится в базе данных class EFileSystem implements IFileSystem, IFileControl { protected $basepath; protected $db; public function __construct($basepath, $db, $fs) { $this->basepath = $basepath; $this->db = $db; $this->fs = $fs; } /*function createExtendRecord($index) { static $fileSQL = "INSERT INTO file (id_record) VALUES (?)"; $query = $this->db->prepareStatement($fileSQL); $query->setString(1, $index); $query->executeQuery(); }*/ private function createRecord($name, $type, $path) { static $recordSQL = "INSERT INTO files (filename, idfile, lastrevdate, filepath, filetype) VALUES (?, ?, ?, ?, ?)"; $last = $this->db->getIdGenerator(); $index = $last->getId('files_idfile_seq'); $query = $this->db->prepareStatement($recordSQL); $query->setString(1, $name); $query->setInt(2, $index); $query->setInt(3, 0); $query->setString(4, $path); $query->setString(5, $type); $query->executeQuery(); /*if ($type == 0) { $this->createExtendRecord($index); }*/ return $index; } function setVisibleFiles(array $visible) { $this->fs->setVisibleFiles($visible); } function setHiddenFiles(array $hidden) { $this->fs->setHiddenFiles($hidden); } public function getFullPath($name) { return Path::join($this->basepath, $name); } private function getRecordId($name, $path) { static $recordSQL = "SELECT idfile FROM files WHERE filename = ? AND filepath = ?"; $query = $this->db->prepareStatement($recordSQL); $query->setString(1, $name); $query->setString(2, $path); $result = $query->executeQuery(); if ($result->next()) { $index = $result->getInt('idfile'); return $index; } return false; // Может лучше кидать исключение ?? } function getIdFromPath($name) { return $this->getRecordId(basename($name), self::getPathName($name)); } // Создание новой директории public function makeDirectory($name) { $path = new Path($name); $fullpath = $this->basepath; $temp_path = ''; foreach ($path->getParts() as $subpath) { $index = $this->getRecordId($subpath, $temp_path); if ($index === false) { $index = $this->createRecord($subpath, 1, $temp_path); } $temp_path = Path::join($temp_path, $subpath); } $this->fs->makeDirectory($this->getFullPath($name)); } public function isDir($name) { return $this->fs->isDir($this->getFullPath($name)); } // Переименование файла или директории все изменения должны записываться в базу чтобы можно было сделать отмену !!! public function renameFile($source, $destination) { // При перемещении файлы могут совпадать $stmt = $this->db->prepareStatement('UPDATE files SET filepath = ?, filename = ? WHERE filepath = ? AND filename = ?'); $stmt->setString(1, self::getPathName($destination)); $stmt->setString(2, basename($destination)); $stmt->setString(3, self::getPathName($source)); $stmt->setString(4, basename($source)); $stmt->executeQuery(); if ($this->isDir($source)) { $length = strlen($from) + 1; $stmt = $this->db->prepareStatement("UPDATE file SET filepath = '?' || substr(filepath, ?) WHERE filepath LIKE (?) OR filepath LIKE (? || '/%')"); $stmt->setString(1, $destination); $stmt->setInt(2, $length); $stmt->setString(3, $source); $stmt->setString(4, $source); } $this->fs->renameFile($this->getFullPath($source), $this->getFullPath($destination)); } // Копирование файла или директории public function copyFile($source, $destination) { // При копировании файлы могут совпадать $stmt = $this->db->prepareStatement('INSERT INTO files (filepath, filename, lastrevdate) VALUES (?, ?, ?)'); $stmt->setString(1, self::getPathName($destination)); $stmt->setString(2, basename($destination)); $stmt->setString(3, time()); $stmt->executeQuery(); if ($this->isDir($source)) { $stmt = $this->db->prepareStatement("INSERT INTO files (filepath, filename, lastrevdate) SELECT '?' || substr(filepath, ?) AS filepath, filename, lastrevdate WHERE WHERE filepath LIKE (?) OR filepath LIKE (? || '/%')"); $stmt->setString(1, $destination); $stmt->setInt(2, $length); $stmt->setString(3, $source); $stmt->setString(4, $source); } $this->fs->copyFile($this->getFullPath($source), $this->getFullPath($destination)); } private function getPathName($name) { $path = dirname($name); return ($path == '.') ? '' : $path; } public function makeFile($name) { $base = self::getPathName($name); $this->makeDirectory($base); $filename = basename($name); $index = $this->getRecordId($filename, $base); if ($index === false) { $index = $this->createRecord($filename, 0, $base); } $this->fs->makeFile($this->getFullPath($name)); } public function readFile($name) { return $this->fs->readFile($this->getFullPath($name)); } public function readFileVersion($name, $revision = false) { if ($revision === false) { return $this->readFile($name); } else { $id_file = $this->getIdFromPath($name); $query = $this->db->prepareStatement("SELECT * FROM history WHERE revision = ? AND idfile = ?"); $query->setInt(1, $revision); $query->setInt(2, $id_file); $file = $query->executeQuery(); if ($file->next()) { return gzuncompress($file->getBlob('content')); } } return null; } public function writeFile($name, $content) { $this->makeFile($name); $this->fs->writeFile($this->getFullPath($name), $content); } public function getLastRevision($name) { $id_file = $this->getIdFromPath($name); $stmt = $this->db->prepareStatement("SELECT * FROM history WHERE revision IN (SELECT MAX(revision) AS lastrev FROM history WHERE idfile = ?)"); $stmt->setInt(1, $id_file); $rev = $stmt->executeQuery(); if ($rev->next()) { return $rev; } return false; } /** * */ public function commitFile($name, $owner, $message) { $id_file = $this->getIdFromPath($name); $content = $this->readFile($name); $stmt = $this->db->prepareStatement("SELECT MAX(revision) AS lastrev FROM history WHERE idfile = ?"); $stmt->setInt(1, $id_file); $rev = $stmt->executeQuery(); $revision = ($rev->next()) ? $rev->getInt('lastrev') + 1 : 1; $query = $this->db->prepareStatement("INSERT INTO history (content, owner, revsummary, revdate, revision, idfile) VALUES (?, ?, ?, ?, ?, ?)"); $query->setBlob(1, gzcompress($content)); $query->setString(2, $owner); $query->setString(3, $message); $query->setInt(4, time()); $query->setInt(5, $revision); $query->setInt(6, $id_file); $query->executeQuery(); } /** * */ public function getFileDifference($name, $revision1, $revision2 = false) { $first = $this->readFileVersion($name, $revision1); $second = $this->readFileVersion($name, $revision2); } /** * */ public function getFileLog($name) { $id_file = $this->getIdFromPath($name); $query = $this->db->prepareStatement("SELECT revision,revsummary,owner,revdate FROM history WHERE idfile = ? ORDER BY revision"); $query->setInt(1, $id_file); $list = $query->executeQuery(); return iterator_to_array($list->getIterator()); } public function directoryFiles($name) { $result = $this->fs->directoryFiles($this->getFullPath($name)); /* Список файлов из базы данных */ $query = $this->db->prepareStatement("SELECT * FROM files WHERE filepath = ?"); $query->setString(1, $name); $list = $query->executeQuery(); foreach ($list as $file) { $fullpath = $this->getFullPath($name . DIRECTORY_SEPARATOR . $file['filename']); if ($this->fs->isVisible($fullpath)) { $file['state'] = ((isset($result[$file['filename']])) ? (($file['lastrevdate'] > $file['change']) ? 'exclamation' : 'unchanged') : 'expected'); $record = new FileRecord($file, $fullpath); $result [$file['filename']] = $record; } } return $result; } public function getFileInfo($name) { $index = $this->getIdFromPath($name); $fullpath = $this->basepath . DIRECTORY_SEPARATOR . $name; if ($index !== false) { $query = $this->db->prepareStatement("SELECT * FROM files AS r LEFT JOIN filemeta AS f ON r.idfile = f.id_record WHERE r.idfile = ?"); $query->setInt(1, $index); $list = $query->executeQuery(); $list->next(); $file = $list->getRow(); $file['state'] = (file_exists($fullpath) ? 'unchanged' : 'expected'); $result = new FileRecord($file, $fullpath); } else { $result = new FileRecord(array(), $fullpath); } return $result; } public function setFileInfo($name, Collection $list) { $index = $this->getIdFromPath($name); if ($index !== false) { $stmt = $this->db->prepareStatement("UPDATE files SET title = ? WHERE idfile = ?"); $stmt->setString(1, $list->get('title')); $stmt->setInt(2, $index); $stmt->executeQuery(); /*if (some($list, array('keywords', 'author', 'description'))) { $hasfile = $this->db->executeQuery("SELECT * FROM file WHERE id_record = $index"); if(!$hasfile->next()) { static $fileSQL = "INSERT INTO file (id_record) VALUES (?)"; $query = $this->db->prepareStatement($fileSQL); $query->setString(1, $index); $query->executeQuery(); } $query = $this->db->prepareStatement("UPDATE file SET keywords = ?, author = ?, description = ? WHERE id_record = ?"); $query->setString(1, $list->get('keywords')); $query->setString(2, $list->get('author')); $query->setString(3, $list->get('description')); $query->setInt(4, $index); $query->executeQuery(); }*/ } } /** * Удаляем директорию если она не пустая */ function deleteDirectory($name) { $index = $this->getIdFromPath($name); $query = $this->db->prepareStatement("SELECT COUNT(*) AS col FROM files WHERE filepath = (?) OR filepath LIKE(? || '/%')"); $query->setString(1, $name); $query->setString(2, $name); $result = $query->executeQuery(); $result->next(); if ($index && $result->getInt('col') == 0) { $query = $this->db->prepareStatement("DELETE FROM files WHERE idfile = ?"); $query->setInt(1, $index); $query->executeQuery(); } $this->fs->deleteDirectory($this->getFullPath($name)); } function deleteFile($name) { $index = $this->getIdFromPath($name); if ($index) { $query = $this->db->prepareStatement("DELETE FROM history WHERE idfile = ?; DELETE FROM filemeta WHERE id_record = ?;DELETE FROM files WHERE idfile = ?"); $query->setInt(1, $index); $query->setInt(2, $index); $query->setInt(3, $index); $query->executeQuery(); } $this->fs->deleteFile($this->getFullPath($name)); } function moveUploadedFile($source, $destination) { $this->fs->moveUploadedFile($source, $this->getFullPath($destination)); $this->makeFile($destination); } function directoryFilesRecursive($name) { $files = $this->fs->directoryFilesRecursive($this->getFullPath($name)); $query = $this->db->prepareStatement("DELETE FROM files WHERE filepath = (?) OR filepath LIKE (? || '/%')"); $query->setString(1, $name); $query->setString(2, $name); $query->executeQuery(); } }