* @license PHP License * @package WB * @subpackage vfs */ WBClass::load('WBVFS'); /** * Virtual File System: Explorer * * * * @version 0.5.1 * @package WB * @subpackage vfs */ class WBVFS_Explorer extends WBVFS { /** * acces to database * @var WBDatasource_Table */ protected $table; /** * acces to tree * @var WBDatasource_Tree */ protected $tree; /** * utility file object * * @var WBVFS_File */ protected $file; /** * direcory parameter * @var unknown_type */ protected $paramDir = array( 'treetable' => 'vfsdir', 'treecolumn' => 'path', 'alphalength' => 4, 'casesensitive' => 0 ); protected $clause = array(); /** * constructor * * Standard constructor * * @param array $parameter */ public function __construct($parameter = array()) { parent::__construct(); // load config and merge with default $config = WBClass::create('WBConfig'); $config->load('vfs'); $this->paramDir = array_merge($this->paramDir, $config->get('dir', array())); if (isset($parameter['chroot']) && !empty($parameter['chroot'])) { $this->paramDir['chroot'] = $parameter['chroot']; } $this->table = WBClass::create('WBDatasource_Table', $this->paramDir); $this->tree = WBClass::create('WBDatasource_Tree', $this->paramDir); $this->file = WBClass::create('WBVFS_File', $parameter); $this->table->switchTranslation(false); $this->tree->switchTranslation(false); $uPrimary = $this->table->getIdentifier('user'); if (isset($parameter['user'])) { $this->clause = array(); $this->clause[] = array( 'field' => $uPrimary, 'value' => $parameter['user'] ); $skel = array( $uPrimary => $parameter['user'] ); $this->tree->setSkeleton($skel); } /* if (isset($parameter['chroot']) && 0 < $parameter['chroot']) { $chroot = $this->tree->get($parameter['chroot']); $this->clause[] = array( 'field' => $this->paramDir['treecolumn'], 'relation' => 'begins', 'value' => $chroot[$this->paramDir['treecolumn']] ); } */ $this->tree->setClause($this->clause); } /** * Actually switch translation * * @param bool $switch */ protected function doSwitchTranslation($switch) { $this->table->switchTranslation($switch); $this->tree->switchTranslation($switch); } /** * trim folder name * * auxillary function to trim name and remove "/" characters. * * @param string $name * @param bool replace slashes * @return string */ public function trim($name, $replace = true) { $name = trim($name, '/ '); if (!$replace) { return $name; } return str_replace('/', '_', $name); } /** * adaptor to get primary key of directories * * Fetch column name of primary key, if any * * @see WBDatasource_Tree::getIdentifier() * @return string */ public function getDirIdentifier() { return $this->tree->getIdentifier(); } /** * adaptor to get primary key of files * * Fetch column name of fake primary key: obscureid * * @see WBDatasource_Table::getIdentifier() * @return string */ public function getFileIdentifier() { return 'obscureid'; } /** * load file by obscure * * @param string $obscureId * @return WBVFS_File|array */ public function getFileByObscureId($obscureId, $object = true) { $res = $this->file->loadByObscureId($obscureId); if ($object) { return $res; } $info = $res->getInfo(); return $info; } /** * load file by obscure * * @param string $obscureId * @return WBVFS_File|array */ public function getFileById($id, $object = true) { $res = $this->file->loadById($id); if ($object) { return $res; } $info = $res->getInfo(); return $info; } /** * find node using path * * Allow access to folders using path like "/foo/bar/blah" * * @param string|array $path * @return string|null */ public function findPath($path) { if (!is_array($path)) { $path = $this->trim($path, false); if (empty($path)) { return null; } $path = explode('/', $path); } if (empty($path)) { return null; } // find first part of path in db $clause = $this->clause; $clause[] = array( 'field' => 'name', 'value' => array_shift($path) ); $inRoot = $this->table->get($this->paramDir['treetable'], null, null, $clause); if (!is_array($inRoot)) { return null; } // get parameter $pCol = $this->paramDir['treecolumn']; $pLen = $this->paramDir['alphalength']; $parent = null; foreach ($inRoot as $parent) { if (strlen($parent[$pCol]) == $pLen) { break; } } if (!$parent) { return null; } unset($inRoot); $primary = $this->tree->getIdentifier(); $id = $parent[$primary]; if (empty($path)) { return $id; } // select all children $children = $this->tree->getChildren($id, 0); // dig down path $ids = array(); foreach ($path as $i => $p) { foreach ($children as $child) { if ($child['name'] == $p && ($i + 2) * $pLen == strlen($child[$pCol])) { $ids[] = $child[$primary]; break; } } } // verify found names all along path if (count($ids) != count($path)) { return null; } return array_pop($ids); } /** * get path to dir * * Fetch all parent nodes to return path * * @param string $dir * @param bool $string tell whether to return string * @return array|string */ public function getPath($dir, $string = false) { if (empty($dir)) { if ($string) { return ''; } return array(); } $current = $this->tree->get($dir); if (empty($current)) { return null; } $path = array(); $list = $this->tree->getParent($dir, 0); if (is_array($list)) { foreach ($list as $l) { $path[] = $l['name']; } } $path[] = $current['name']; if ($string) { $path = implode('/', $path); } return $path; } /** * Make new Folder Or Get ID * * Similar to mkdir * * @param string $parent id of parent not, or null for root * @param string $path folder name or path with slashes * @return string $key of folder */ public function mkDirOrGetId($parent, $path) { $list = $this->lsDir($parent); $path = explode('/', $path); foreach ($path as $name) { $id = null; foreach ($list as $l) { if ($name == $l['name']) { $id = $l['id']; $parent = $id; $list = $this->lsDir($id); break; } } if ($id) { continue; } $id = $this->mkDir($parent, $name); $parent = $id; $list = array(); } return $id; } /** * make new folder * * Similar to mkdir * * @param string|null $parent id of parent not, or null for root * @param string $name folder name * @return string $key of new record */ public function mkDir($parent, $name) { // make sure new name is unique $siblings = $this->tree->getChildren($parent); $name = $this->makeUniqueName($name, $siblings); $new = array( 'name' => $name ); return $this->tree->addChild($parent, $new); } /** * get direcotry node * * Fetch direcotry's node data by id * * @see WBDatasource_Tree::get() * @param string $id * @return array */ public function getDir($id) { $node = $this->tree->get($id); if ($id === null || !isset($node['name'])) { $node['name'] = ''; } return $node; } /** * get all parent folders * * @param string $id * @return array */ public function getParent($id) { return $this->tree->getParent($id, 0); } /** * fetch parent node * * In case the parent is root node, it will return null * * @param string $id * @return array */ public function getParentDir($id) { $list = $this->tree->getParent($id); if (empty($list)) { return null; } if (1 == count($list)) { return $list[0]; } return null; } /** * get id of parent dir * * @see getParentDir() * @param string $id * @return string */ public function getParentDirId($id) { $dir = $this->getParentDir($id); if (is_array($dir)) { return $dir[$this->getDirIdentifier()]; } return null; } /** * directory listing * * @param string $id * @param int $depth * @return array */ public function lsDir($id, $depth = 1) { if ($id == 0) { $id = null; } return $this->tree->getChildren($id, $depth); } /** * remove folder recursively * * @param string $id */ public function rmDir($id) { if ($id == 0) { $id = null; } $node = $this->tree->get($id); $children = $this->tree->getChildren($node, 0); // remove all files $children[] = $node; foreach ($children as $child) { $dir = $child[$this->getDirIdentifier()]; $files = $this->file->listDir($dir); foreach ($files as $f) { $file = $this->getFileById($f['id'], true); $file->delete(); } } // remove all folders and subfolder $this->tree->delete($id); return true; } /** * rename an existing directory * * Allows you to rename dir withoud changing the id, * also duplicate names are avoided * * @see mvDir() * @param string $id * @param string $name * @return string id of changed node */ public function renameDir($id, $name) { $node = $this->tree->get($id); if ($name == $node['name']) { return; } $primary = $this->getDirIdentifier(); $parent = $this->tree->getParent($id); if (empty($parent)) { $parent = array(array($primary => null)); } $parent = array_shift($parent); $siblings = $this->tree->getChildren($parent[$primary]); $name = $this->makeUniqueName($name, $siblings, $id); $save = array( 'name' => $name ); return $this->tree->set($id, $save); } /** * move directory * * Move folder's location. Optionally you may change the * folder's name on the go * * @param string $id node to move * @param string $des destination node's id * @param string $name optional new name * @return string id of moved node */ public function mvDir($id, $des, $name = null) { $node = array(); if (!empty($name)) { $node['name'] = $name; } else { // fetch old name $old = $this->tree->get($id); $node['name'] = $old['name']; } $siblings = $this->tree->getChildren($des); $node['name'] = $this->makeUniqueName($node['name'], $siblings); return $this->tree->moveChild($id, $des, $node); } }