phplibrary/core/filesystem.php
2016-07-14 16:29:26 +03:00

583 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once 'core/path.php';
require_once 'core/file.php';
interface IFileSystem
{
// Операции над файлами
public function makeDirectory($name);
public function deleteDirectory($name);
public function deleteFile($name);
public function renameFile($source, $destination);
public function copyFile($source, $destination);
public function moveUploadedFile($source, $destination);
// deleteDirectoryRecursive
public function isDir($name);
public function readFile($source);
public function writeFile($source, $content);
// Содержание директории
public function directoryFiles($name);
public function directoryFilesRecursive($name);
}
interface IFileControl
{
public function commitFile($name, $who, $message);
public function readFileVersion($name, $version = false);
// Информация о файле
public function getFileLog($name);
public function getFileInfo($name);
}
// Реальная файловая система
class FileSystem implements IFileSystem
{
protected $hidden = array('.', '..');
protected $visible = null;
public function __construct()
{
}
public function setVisibleFiles(array $visible)
{
$this->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();
}
}