Forum Moderators: coopster
public function uncompress($addDB = true) {
if ($this['extension'] == 'zip') {
$zip = new ZipArchive;
if ($zip -> open($this['path']) === true && $zip -> extractTo($this['directory'])) {
for ($i = 0; $i < $zip -> numFiles; $i++) {
$file = $this['directory'].'/'.$zip -> getNameIndex($i);
try { //If the file is not allowed, then append to its extension '.ext'
FileSystemTree::checkFile($file);
} catch (EfrontFileException $e) {
$fileObj = new EfrontFile($file);
$fileObj -> rename($this['directory'].'/'.$zip -> getNameIndex($i).'.ext', true);
$file = $fileObj['path'];
}
$zipFiles[] = $file;
}
if ($this['id'] != -1 && $addDB) {
$importedFiles = FileSystemTree :: importFiles($zipFiles, $options);
return $importedFiles;
} else {
return $zipFiles;
}
} else {
throw new EfrontFileException(_CANNOTOPENCOMPRESSEDFILE.': '.$this['path'], EfrontFileException :: ERROR_OPEN_ZIP);
}
} else {
require_once("Archive/Tar.php");
$tar = new Archive_Tar($this['path'], 'gz');
$tarContents = $tar -> listContent();
$list = array();
foreach ($tarContents as $value) {
if ($value['typeflag'] != 5) { //5 is a directory
$file = $this['directory'].'/'.ltrim($value['filename'], "/"); //ltrim here due to a possible bug in previous versions
try { //If the file is not allowed, then append to its extension '.ext'
FileSystemTree::checkFile($file);
} catch (EfrontFileException $e) {
$fileObj = new EfrontFile($file);
$fileObj -> rename($this['directory'].'/'.$zip -> getNameIndex($i).'.ext', true);
$file = $fileObj['path'];
}
$list[] = $file;
}
}
$tar -> extract($this['directory']);
if ($this['id'] != -1 && $addDB) {
$importedFiles = FileSystemTree :: importFiles($list, $options);
return $importedFiles;
} else {
return $list;
}
}
}
/**
* Get the image for the file type
*
* This function returns the url to an image representing the current
* file type.
* <br/>Example:
* <code>
* echo $file -> getTypeImage();//Returns something like 'images/16x16/zip.png' if it's a zip file
* </code>
*
* @return string The url to the image representing the file type
* @since 3.5.0
* @access public
*/
public function getTypeImage() {
if (is_file(G_IMAGESPATH.'file_types/'.$this['extension'].'.png')) {
$image = 'images/file_types/'.$this['extension'].'.png';
} else {
$image = 'images/file_types/unknown.png';
}
return $image;
}
/**
* Share file
*
* This function is used to make the current file available to the lesson's
* students. A file can be made available to a single lesson only.
* <br/>Example:
* <code>
* $file = new EfrontFile(43);
* $file -> share();//The file is now visible to the shared files list
* $file -> unshare();//The file was made hidden again
* </code>
*
* @param int $lessonId A specific lesson to share this file for
* @since 3.5.0
* @access public
*/
public function share($lessonId = false) {
if (!$lessonId) {
$lessonId = $_SESSION['s_lessons_ID'];
}
if ($lessonId) {
if ($this['id'] == -1) { //If the file does not have a database representation, create one for it
$newList = FileSystemTree :: importFiles($this['path']);
$this['id'] = key($newList);
$this -> refresh();
}
$this['shared'] = $lessonId;
$this -> persist();
} else {
throw new EfrontFileException(_CANNOTSHAREFILE.': '.$this['path'], EfrontFileException :: NOT_LESSON_FILE);
}
}
/**
* Unshare file
*
* This function is used to make the current file unavailable to the lesson's
* students. It must belong to a lesson (that is, it must have a lesson id)
* in order to do so.
* <br/>Example:
* <code>
* $file = new EfrontFile(43);
* $file -> share();//The file is now visible to the shared files list
* $file -> unshare();//The file was made hidden again
* </code>
*
* @since 3.5.0
* @access public
*/
public function unshare() {
$this['shared'] = 0;
$this -> persist();
}
/**
* Print a link with tooltip
*
* This function is used to print a file link with a popup tooltip
* containing information on this file. The link must be provided
* and optionally the information.
* <br/>Example:
* <code>
* $link = 'view_file.php?file=23';
* echo $file -> toHTMLTooltipLink($link);
* </code>
*
* @param string $link The link to print
* @param boolean $preview Whether to display link in a preview panel
* @since 3.5.0
* @access public
*/
public function toHTMLTooltipLink($link, $preview = true) {
$classes[] = 'info'; //This array holds the link css classes
if (!$link) {
$link = 'javascript:void(0)';
$classes[] = 'inactiveLink';
}
$tooltipString = '
<a href = "'.$link.'" class = "'.implode(" ", $classes).'" style = "vertical-align:middle;" '.($preview ? 'onclick = "eF_js_showDivPopup(\''._PREVIEW.'\', 2, \'preview_table_'.$tableId.'\')" target = "PREVIEW_FRAME"' : '').'>
'.$this -> offsetGet('name').'
<img class = "tooltip" border = "0" src="images/others/tooltip_arrow.gif"/><span class = "tooltipSpan">';
foreach ($this as $key => $value) {
if ($value) {
switch ($key) {
//case 'path' : $tooltipString .= '<div style = "white-space:nowrap"><strong>'._PHYSICALNAME."</strong>: ".basename($value)."<br/></div>"; break;
case 'users_LOGIN' : $tooltipString .= '<strong>'._USER."</strong>: $value<br/>"; break;
case 'timestamp' : $tooltipString .= '<strong>'._LASTMODIFIED."</strong>: ".formatTimestamp($value, 'time_nosec')."<br/>"; break;
//case 'shared' : $tooltipString .= '<strong>'._SHARED."</strong>: $value<br/>"; break;
case 'mime_type' : $tooltipString .= '<strong>'._MIMETYPE."</strong>: $value<br/>"; break;
default: break;
}
}
}
$tooltipString .= '</span></a>';
return $tooltipString;
}
/**
* Encode file name
*
* This function is used to encode the given name, based on the current
* configuration options.
* <br/>Example:
* <code>
* $name = 'some name';//The name to encode
* $newName = EfrontFile :: encode($name);//Encodeded version of name
* </code>
* A little word about the need of encoding:
* Throughut eFront UTF-8 is used as encoding. When uploading a file, for example, its name is encoded
* in UTF-8, and with this name is stored in the filesystem. This does not cause any problems, when the
* OS is UTF8-aware, for example in most Linux distributions. However, for Windows installations, this
* causes major side-effects: The file name is messed up. On the other hand, when trying to access the file,
* the encoding is still in UTF8, so that many browsers, for example FireFox, have no problem in accessing
* the file, using its initial, UTF8-encoded, correct name. Unfortunately, Internet Explorer (6,7) cannot access
* the file at all.
* So when using a windows server, we must encode non-latin characters in order to be able to access any
* uploaded files with international characters. The most (if not the only) convenient encoding is UTF7-IMAP, which is a
* version of UTF-7 without the filesystem incompatible characters (see [tools.ietf.org...]
* If we are sure that only the native windows language will be used for file names, there is a somewhat better solution
* than using UTF7-IMAP (which scrambles the file names in the file system). We could use the native windows encoding.
* For example, for greek, the native windows encoding is windows-1253 (ISO-8859-7 is also supported). So, instead of
* UTF7-IMAP, we select this encoding and everything works like a charm. Except for filenames with characters other
* than latin and greek, of course.
*
* @param string $name The filename to encode
* @return string The encoded file name
* @since 3.5.0
* @access public
* @static
*/
public static function encode($name) {
$newName = $name;
if ($GLOBALS['configuration']['file_encoding']) {
if (in_array($GLOBALS['configuration']['file_encoding'], mb_list_encodings())) {
$newName = mb_convert_encoding($name, $GLOBALS['configuration']['file_encoding'], "UTF-8");
} else {
$newName = mb_convert_encoding($name, "UTF7-IMAP", "UTF-8");
}
}
return $newName;
}
/**
* Decode filename
*
* This function is the opposite of encode() and is used to convert a file name
* back to UTF8
* <br/>Example:
* <code>
* $name = EfrontFile :: decode($encodedName);
* </code>
*
* @param string $name The encoded name
* @return string The decoded name
* @since 3.5.0
* @access public
* @static
* @see EfrontFile :: encode()
*/
public static function decode($name) {
$newName = $name;
if ($GLOBALS['configuration']['file_encoding']) {
if (in_array($GLOBALS['configuration']['file_encoding'], mb_list_encodings())) {
$newName = mb_convert_encoding($name, "UTF-8", $GLOBALS['configuration']['file_encoding']);
} else {
$newName = mb_convert_encoding($name, "UTF-8", "UTF7-IMAP");
}
}
return $newName;
}
}
/**
* Class for directories in Efront file system
*
* @since 3.5.0
* @package eFront
*/
class EfrontDirectory extends ArrayObject
{
/**
* Class constructor
*
* The class constructor instantiates the object based on the $directory parameter.
* $directory may be either:
* - an array with directory attributes
* - a directory id
* - the full path to a physical directory
* - the full path to a directory using its original directory name
* <br/>Example:
* <code>
* $result = eF_getTableData("files", "*", "id=43");
* $file = new EfrontDirectory($result[0]); //Instantiate object using array of values
* $file = new EfrontDirectory(43); //Instantiate object using id
* $file = new EfrontDirectory('/var/www/32/'); //Instantiate object using path
* </code>
*
* @param mixed $directory The directory information, either an array, an id or a path string
* @since 3.5.0
* @access public
*/
function __construct($directory) {
$directory = EfrontDirectory :: normalize($directory);
if (is_dir($directory) && strpos($directory, rtrim(G_ROOTPATH, "/")) !== false) { //Create object without database information
$directoryArray = array('path' => $directory,
'name' => EfrontFile :: decode(basename($directory)),
'directory' => dirname($directory),
'timestamp' => filemtime($directory),
'type' => 'directory',
'physical_name' => basename($directory));
foreach ($pathParts = explode("/", $directoryArray['path']) as $key => $value) {
$pathParts[$key] = urlencode($value);
}
$directoryArray['url_path'] = implode("/", $pathParts);
} else if (strpos($directory, rtrim(G_ROOTPATH, "/")) === false) {
throw new EfrontFileException(_ILLEGALPATH.': '.$directory, EfrontFileException :: ILLEGAL_PATH);
} else {
throw new EfrontFileException(_DIRECTORYDOESNOTEXIST.': '.$directory, EfrontFileException :: DIRECTORY_NOT_EXIST);
}
parent :: __construct($directoryArray); //Create an ArrayObject from the given array
}
/**
* Normalize path
*
* This function is used to normalize a path string. It applies
* realpath() to translate relevant paths, converts \ to / and trims
* trailing /
* <br/>Example:
* <code>
* $path = '..\..\..\test.php\';
* echo EfrontDirectory :: normalize($path);//Outputs c:/test.php
* </code>
*
* @param string $path The path to normalize
* @return string The normalized path
* @since 3.5.0
* @access public
*/
public static function normalize($path) {
$realPath = realpath($path);
if ($realPath && file_exists($realPath)) {
return rtrim(str_replace("\\", "/", $realPath), "/");
} else {
return rtrim(str_replace("\\", "/", $path), "/");
}
}
/**
* Rcursively delete directory
*
* This function recursively deletes the directory.
* <br/>Example:
* <code>
* $directory = new EfrontDirectory(34); //Instantiate directory
* $directory -> delete(); //Delete directory
* </code>
*
* @since 3.5.0
* @access public
*/
public function delete() {
$it = new EfrontREFilterIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this['path']), RecursiveIteratorIterator :: SELF_FIRST), array('/.svn/'), false);
$files = array();
$result = eF_getTableData("files", "*", "path like '".str_replace(G_ROOTPATH, '', $this['path'])."%'");
foreach ($result as $file) {
$files[G_ROOTPATH.$file['path']] = $file;
}
foreach ($it as $node => $value) {
if ($value -> isFile()) {
$current = str_replace("\\", "/", $node);
if (isset($files[$current])) {
$current = new EfrontFile($files[$current]);
} else {
$fileArray = array('id' => -1, //Set 'id' to -1, meaning this file has not a database representation
'path' => $value -> getPathName());
$current = new EfrontFile($fileArray);
}
$current -> delete();
}
}
$directories[] = $this['path']; //Append current directory to the beginning of the array
foreach ($it as $node => $value) {
if ($value -> isDir()) {
$directories[] = str_replace("\\", "/", $node);
}
}
unset($it); //The iterator keeps an open handle to the directory, so it must be unset beore we delete the current directory
$directories = array_reverse($directories); //Reverse directories order, so that they are deleted from the innermost to the outermost
foreach ($directories as $key => $value) {
rmdir($value);
}
}
/**
* Copy directory
*
* This function is used to recursively copy the current directory to a new destination.
* <br/>Example:
* <code>
* $directory = new EfrontDirectory(43); //Instantiate directory object
* $directory -> copy('/var/www/'); //Copy directory to /var/www/
* </code>
*
* @param string $destinationPath The destination directory
* @param boolean $overwrite Whether to overwrite existing files/directories in the destination
* @return EfrontDirectory The copied directory
* @since 3.5.0
* @access public
*/
public function copy($destinationPath, $overwrite = false) {
$destinationPath = EfrontDirectory :: normalize($destinationPath);
$parentDirectory = new EfrontDirectory(dirname($destinationPath)); //This way we check integrity of destination
if (!is_dir($destinationPath)) {
mkdir($destinationPath, 0755);
} elseif (!$overwrite) {
throw new EfrontFileException(_CANNOTCOPYDIRECTORY.': '.$destinationPath.', '._FILEALREADYEXISTS, EfrontFileException :: DIRECTORY_ALREADY_EXISTS);
}
$it = new EfrontREFilterIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this['path']), RecursiveIteratorIterator :: SELF_FIRST), array('/.svn/'), false);
foreach ($it as $node => $value) {
if ($value -> isDir()) {
$current = str_replace("\\", "/", $node);
$newDir = str_replace($this['path'], $destinationPath, $current);
mkdir($newDir, 0755);
}
}
foreach ($it as $node => $value) {
if ($value -> isFile()) {
$current = str_replace("\\", "/", $node);
$newPath = str_replace($this['path'], $destinationPath, $current);
$file = new EfrontFile($node);
$file -> copy($newPath, $overwrite);
}
}
$newDirectory = new EfrontDirectory($destinationPath);
return $newDirectory;
}
/**
* Rename / Move directory
*
* This function is used to rename and/or move the directory. The destinationPath must contain the same name
* if it is going to be moved only, or a new name if it is going to be renamed also
* directory after copying it.
* <br/>Example:
* <code>
* $directory = new EfrontDirectory(43); //Instantiate directory object
* $directory -> rename('/var/www/'); //Move directory to /var/www/
* </code>
*
* @param mixed $destinationPath The destination directory
* @return EfrontDirectory The renamed/moved directory
* @since 3.5.0
* @access public
* @see copy()
*/
public function rename($destinationPath, $overwrite = false) {
$destinationPath = EfrontDirectory :: normalize($destinationPath);
$parentDirectory = new EfrontDirectory(dirname($destinationPath)); //This way we check integrity of destination
if (!is_dir($destinationPath)) {
mkdir($destinationPath, 0755);
} elseif (!$overwrite) {
throw new EfrontFileException(_CANNOTCOPYDIRECTORY.': '.$destinationPath.', '._FILEALREADYEXISTS, EfrontFileException :: DIRECTORY_ALREADY_EXISTS);
}
$it = new EfrontREFilterIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this['path']), RecursiveIteratorIterator :: SELF_FIRST), array('/.svn/'), false);
foreach ($it as $node => $value) {
if ($value -> isDir()) {
$current = str_replace("\\", "/", $node);
$newDir = str_replace($this['path'], $destinationPath, $current);
mkdir($newDir, 0755);
}
}
foreach ($it as $node => $value) {
if ($value -> isFile()) {
$current = str_replace("\\", "/", $node);
$newPath = str_replace($this['path'], $destinationPath, $current);
$file = new EfrontFile($node);
$file -> rename($newPath, $overwrite);
}
}
unset($it);
rmdir($this['path']);
$directory = new EfrontDirectory($destinationPath);
$this['name'] = $directory['name'];
$this['path'] = $directory['path'];
$this['directory'] = $directory['directory'];
$this['timestamp'] = $directory['timestamp'];
$this['physical_name'] = $directory['physical_name'];
}
/**
* Compress directory
*
* This function is used to compress (to zip format) the current directory.
* It creates a zip file with the specified name, or the same
* name as the directory iteself, if the parameter $zipName is
* ommited
* <br/>Example:
* <code>
* $directory = new EfrontDirectory('/var/www/efront/www/content/lessons/32/test_folder');
* $file = $directory -> compress();//This will create a file named 'test_folder.zip' inside the directory
* </code>
*
* @param string $zipName The name if the compressed file
* @param boolean $includeSelf Whether to include itself to the zip file
* @param boolean $decode Whether the file name should be decoded
* @return EfrontFile The compressed file
* @since 3.5.0
* @access public
*/
public function compress($zipName = false, $includeSelf = true, $decode = false) {
if (!$zipName) {
$zipName = $this['path'].'.zip';
} else {
$zipName = $this['directory'].'/'.(EfrontFile :: encode(basename($zipName)));
}
try { //This way we delete the file, if it already exists
$file = new EfrontFile($zipName);
$file -> delete();
} catch (Exception $e) {}
$zip = new ZipArchive;
if ($zip -> open($zipName, ZIPARCHIVE::CREATE ) === true) {
$count = 0;
$it = new EfrontREFilterIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this['path']), RecursiveIteratorIterator :: SELF_FIRST), array('/.svn/'), false);
foreach ($it as $node => $value) {
if ($value -> isFile()) {
$current = str_replace("\\", "/", $node);
if ($includeSelf) {
$nameInZip = ltrim(str_replace(dirname($this['path']), '', $current), '/');
} else {
$nameInZip = ltrim(str_replace($this['path'], '', $current), '/');
}
//pr($current);pr($nameInZip);
if ($decode) {
$zip -> addFile($node, EfrontFile :: decode($nameInZip));
} else {
$zip -> addFile($node, $nameInZip);
}
if ($count++ > 500) { //See bug [pecl.php.net...]
$zip -> close();
$zip -> open($zipName, ZIPARCHIVE::CREATE);
$count = 0;
}
}
}