<?php
/**
 * eF_File Class file
 *
 * @package eFront
 * @version 1.0
 */


/**
 *
 */
define("POSTFIX", "efront");           //If POSTFIX is defined, then the name conversion to ids takes place
define("DEFAULT_COMPRESS_METHOD", "zip");



/**
 * EfrontFileSystem class
 *
 * This class is used to provide access to the filesystem. It consists of static methods only
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class EfrontFileSystem
{
    /**
     * An array of mime types
     *
     * @since 3.0
     * @var array
     * @access public
     * @static
     */
    public static $mimeTypes = array (
        'bmp'       =>   'image/bmp',
        'cgm'       =>   'image/cgm',
        'djv'       =>   'image/vnd.djvu',
        'djvu'      =>   'image/vnd.djvu',
        'gif'       =>   'image/gif',
        'ico'       =>   'image/x-icon',
        'ief'       =>   'image/ief',
        'jp2'       =>   'image/jp2',
        'jpe'       =>   'image/jpeg',
        'jpeg'      =>   'image/jpeg',
        'jpg'       =>   'image/jpeg',
        'mac'       =>   'image/x-macpaint',
        'pbm'       =>   'image/x-portable-bitmap',
        'pct'       =>   'image/pict',
        'pgm'       =>   'image/x-portable-graymap',
        'pic'       =>   'image/pict',
        'pict'      =>   'image/pict',
        'png'       =>   'image/png',
        'pnm'       =>   'image/x-portable-anymap',
        'pnt'       =>   'image/x-macpaint',
        'pntg'      =>   'image/x-macpaint',
        'ppm'       =>   'image/x-portable-pixmap',
        'qti'       =>   'image/x-quicktime',
        'qtif'      =>   'image/x-quicktime',
        'ras'       =>   'image/x-cmu-raster',
        'rgb'       =>   'image/x-rgb',
        'svg'       =>   'image/svg+xml',
        'tif'       =>   'image/tiff',
        'tiff'      =>   'image/tiff',
        'wbmp'      =>   'image/vnd.wap.wbmp',
        'xbm'       =>   'image/x-xbitmap',
        'xpm'       =>   'image/x-xpixmap',
        'xwd'       =>   'image/x-xwindowdump',
        'asc'       =>   'text/plain',
        'css'       =>   'text/css',
        'etx'       =>   'text/x-setext',
        'htm'       =>   'text/html',
        'html'      =>   'text/html',
        'ics'       =>   'text/calendar',
        'ifb'       =>   'text/calendar',
        'rtf'       =>   'text/rtf',
        'rtx'       =>   'text/richtext',
        'sgm'       =>   'text/sgml',
        'sgml'      =>   'text/sgml',
        'tsv'       =>   'text/tab-separated-values',
        'txt'       =>   'text/plain',
        'wml'       =>   'text/vnd.wap.wml',
        'wmls'      =>   'text/vnd.wap.wmlscript',
        'kar'       =>   'audio/midi',
        'm3u'       =>   'audio/x-mpegurl',
        'm4a'       =>   'audio/mp4a-latm',
        'm4b'       =>   'audio/mp4a-latm',
        'm4p'       =>   'audio/mp4a-latm',
        'mid'       =>   'audio/midi',
        'midi'      =>   'audio/midi',
        'mp2'       =>   'audio/mpeg',
        'mp3'       =>   'audio/mpeg',
        'mpga'      =>   'audio/mpeg',
        'ra'        =>   'audio/x-pn-realaudio',
        'ram'       =>   'audio/x-pn-realaudio',
        'snd'       =>   'audio/basic',
        'wav'       =>   'audio/x-wav',
        'aif'       =>   'audio/x-aiff',
        'aifc'      =>   'audio/x-aiff',
        'aiff'      =>   'audio/x-aiff',
        'au'        =>   'audio/basic',
        'avi'       =>   'video/x-msvideo',
        'mov'       =>   'video/quicktime',
        'movie'     =>   'video/x-sgi-movie',
        'mp4'       =>   'video/mp4',
        'mpe'       =>   'video/mpeg',
        'mpeg'      =>   'video/mpeg',
        'mpg'       =>   'video/mpeg',
        'm4u'       =>   'video/vnd.mpegurl',
        'm4v'       =>   'video/x-m4v',
        'dif'       =>   'video/x-dv',
        'dv'        =>   'video/x-dv',
        'mxu'       =>   'video/vnd.mpegurl',
        'qt'        =>   'video/quicktime',
        'iges'      =>   'model/iges',
        'igs'       =>   'model/iges',
        'mesh'      =>   'model/mesh',
        'msh'       =>   'model/mesh',
        'silo'      =>   'model/mesh',
        'vrml'      =>   'model/vrml',
        'wrl'       =>   'model/vrml',
        'xyz'       =>   'chemical/x-xyz',
        'pdb'       =>   'chemical/x-pdb',
        'ice'       =>   'x-conference/x-cooltalk',
        'ai'        =>   'application/postscript',
        'atom'      =>   'application/atom+xml',
        'bcpio'     =>   'application/x-bcpio',
        'bin'       =>   'application/octet-stream',
        'cdf'       =>   'application/x-netcdf',
        'class'     =>   'application/octet-stream',
        'cpio'      =>   'application/x-cpio',
        'cpt'       =>   'application/mac-compactpro',
        'csh'       =>   'application/x-csh',
        'dcr'       =>   'application/x-director',
        'dir'       =>   'application/x-director',
        'dll'       =>   'application/octet-stream',
        'dmg'       =>   'application/octet-stream',
        'dms'       =>   'application/octet-stream',
        'doc'       =>   'application/msword',
        'dtd'       =>   'application/xml-dtd',
        'dvi'       =>   'application/x-dvi',
        'dxr'       =>   'application/x-director',
        'eps'       =>   'application/postscript',
        'exe'       =>   'application/octet-stream',
        'ez'        =>   'application/andrew-inset',
        'gram'      =>   'application/srgs',
        'grxml'     =>   'application/srgs+xml',
        'gtar'      =>   'application/x-gtar',
        'hdf'       =>   'application/x-hdf',
        'hqx'       =>   'application/mac-binhex40',
        'jnlp'      =>   'application/x-java-jnlp-file',
        'js'        =>   'application/x-javascript',
        'latex'     =>   'application/x-latex',
        'lha'       =>   'application/octet-stream',
        'lzh'       =>   'application/octet-stream',
        'man'       =>   'application/x-troff-man',
        'mathml'    =>   'application/mathml+xml',
        'me'        =>   'application/x-troff-me',
        'mif'       =>   'application/vnd.mif',
        'ms'        =>   'application/x-troff-ms',
        'nc'        =>   'application/x-netcdf',
        'oda'       =>   'application/oda',
        'ogg'       =>   'application/ogg',
        'pdf'       =>   'application/pdf',
        'pgn'       =>   'application/x-chess-pgn',
        'ppt'       =>   'application/vnd.ms-powerpoint',
        'ps'        =>   'application/postscript',
        'rdf'       =>   'application/rdf+xml',
        'rm'        =>   'application/vnd.rn-realmedia',
        'roff'      =>   'application/x-troff',
        'sh'        =>   'application/x-sh',
        'shar'      =>   'application/x-shar',
        'sit'       =>   'application/x-stuffit',
        'skd'       =>   'application/x-koan',
        'skm'       =>   'application/x-koan',
        'skp'       =>   'application/x-koan',
        'skt'       =>   'application/x-koan',
        'smi'       =>   'application/smil',
        'smil'      =>   'application/smil',
        'so'        =>   'application/octet-stream',
        'spl'       =>   'application/x-futuresplash',
        'src'       =>   'application/x-wais-source',
        'sv4cpio'   =>   'application/x-sv4cpio',
        'sv4crc'    =>   'application/x-sv4crc',
        'swf'       =>   'application/x-shockwave-flash',
        't'         =>   'application/x-troff',
        'tar'       =>   'application/x-tar',
        'tcl'       =>   'application/x-tcl',
        'tex'       =>   'application/x-tex',
        'texi'      =>   'application/x-texinfo',
        'texinfo'   =>   'application/x-texinfo',
        'tr'        =>   'application/x-troff',
        'ustar'     =>   'application/x-ustar',
        'vcd'       =>   'application/x-cdlink',
        'vxml'      =>   'application/voicexml+xml',
        'wbmxl'     =>   'application/vnd.wap.wbxml',
        'wmlc'      =>   'application/vnd.wap.wmlc',
        'wmlsc'     =>   'application/vnd.wap.wmlscriptc',
        'xht'       =>   'application/xhtml+xml',
        'xhtml'     =>   'application/xhtml+xml',
        'xls'       =>   'application/vnd.ms-excel',
        'xml'       =>   'application/xml',
        'xsl'       =>   'application/xml',
        'xslt'      =>   'application/xslt+xml',
        'xul'       =>   'application/vnd.mozilla.xul+xml',
        'zip'       =>   'application/zip');

    /**
     * Get maximum upload size
     *
     * This function is used to calculate the maximum allowed upload
     * file size (in KB). The size is the smallest among the following:
     * - The 'memory_limit' PHP ini setting
     * - The 'upload_max_filesize' PHP ini setting
     * - The 'post_max_size' PHP ini setting
     * - The maximum file size configuration setting
     *
     * @return int The maximum file size, in Kilobytes
     * @see EfrontFileSystem :: uploadFile()
     * @since 3.0
     * @access public
     * @static
     */
    public static function getUploadMaxSize() {
        preg_match('/(\d+)/', ini_get('memory_limit'), $memory_limit);
        preg_match('/(\d+)/', ini_get('upload_max_filesize'), $upload_max_filesize);
        preg_match('/(\d+)/', ini_get('post_max_size'), $post_max_size);
        $memory_limit[1] == 1 ? $memory_limit[1] = $upload_max_filesize[1] : null;        //In case memory_limit is set to -1 (no limit), then equalize this variable with the upload_max_filesize
        $max_upload = min($memory_limit[1] * 1024, $upload_max_filesize[1] * 1024, $post_max_size[1] * 1024, $GLOBALS['configuration']['max_file_size']);

        return $max_upload;
    }

    /**
     * Get specific file types
     *
     * This function can be used to return extensions and mime types of specific file
     * classes, such as images or media.
     *
     * @param mixed $type The file classes: 'image', 'media', 'java'. If none is specified, then all file types available are returned
     * @return array The file types in extension => mime type pairs
     * @see eF_File :: $mimeTypes
     * @since 3.0
     * @access public
     * @static
     */
    public static function getFileTypes($type = false) {
        $fileTypes = array();
        foreach (self :: $mimeTypes as $key => $filetype) {
            switch ($type) {
                case 'image':
                    if (strpos($filetype, 'image/') === 0) {
                        $fileTypes[$key] = $filetype;
                    }
                    break;
                case 'media':
                    if (strpos($filetype, 'audio/') === 0 || strpos($filetype, 'video/') === 0 || $key == 'swf') {
                        $fileTypes[$key] = $filetype;
                    }
                    break;
                case 'java':
                    if ($key == 'class') {
                        $fileTypes[$key] = $filetype;
                    }
                    break;
                default:
                    $fileTypes[$key] = $filetype;
                    break;
            }
        }
        return $fileTypes;
    }

    /**
     * Get directory contents in FileSystem
     *
     * This function is used to retrieve all (physical) files and directories
     * of the directory specified. The result set may be optionally customized depending
     * on the specified parameters
     *
     * @param string $directory The path to the directory to get its contents
     * @param array $filterIn An array of extensions that specifies which file types to return
     * @param boolean $recurseInto Whether to recurse into subfolders
     * @return array The files list
     * @since 3.0
     * @access public
     */
    public static function getContentsFS($directory, $filterIn = false, $recurseInto = true)
    {
        if (!($directory instanceof eF_Directory)) {
            $directory = new eF_Directory($directory);
        }
        return $directory -> getContentsFS($filterIn, $recurseInto);
    }

    /**
     * Delete directory
     *
     * This function deletes the specified directory from the filesystem
     *
     * @param mixed $sourceDirectory Either a string with full path to a directory, or an eF_Directory object
     * @return boolean True if the directory was deleted successfully
     * @see eF_Directory :: delete()
     * @since 3.0
     * @access public
     * @static
     */
    public static function deleteDirectory($sourceDirectory) {
        if (!($sourceDirectory instanceof eF_Directory)) {
            $sourceDirectory = new eF_Directory($sourceDirectory);
        }
        return $sourceDirectory -> delete();
    }

    /**
     * Delete file
     *
     * This function deletes the specified file from the filesystem
     *
     * @param mixed $sourceFile Either a string with full path to a file, or a eF_File object
     * @return boolean True if the file was deleted successfully
     * @see eF_File :: delete()
     * @since 3.0
     * @access public
     * @static
     */
    public static function delete($sourceFile) {
        if (!($sourceFile instanceof eF_File)) {
            $sourceFile = new eF_File($filename);
        }
        return $sourceFile -> delete();
    }

    /**
     * Copy file
     *
     * This function copies the specified file to the designated position
     *
     * @param mixed $sourceFile Either a string with full path to a file, or a eF_File object
     * @param string $destinationDirectory The destination directory
     * @param boolean $overwrite If true, overwrite file with same name in destination.
     * @return eF_File An object representing the copied file
     * @see eF_File :: copy()
     * @since 3.0
     * @access public
     * @static
     */
    public static function copy($sourceFile, $destinationDirectory, $overwrite = false) {
        if (!($sourceFile instanceof eF_File)) {
            $sourceFile = new eF_File($sourceFile);
        }

        return $sourceFile -> copy($destinationDirectory, false, $overwrite);
    }

    /**
     * Move file
     *
     * This function moves the specified file to the designated position
     *
     * @param mixed $sourceFile Either a string with full path to a file, or a eF_File object
     * @param string $destinationDirectory The destination directory
     * @param boolean $overwrite If true, overwrite file with same name in destination.
     * @return eF_File An object representing the moved file
     * @see eF_File :: move()
     * @since 3.0
     * @access public
     * @static
     */
    public static function move($sourceFile, $destinationDirectory, $overwrite = false) {
        if (!($sourceFile instanceof eF_File)) {
            $sourceFile = new eF_File($sourceFile);
        }
        return $sourceFile -> move($destinationDirectory, false, $overwrite);
    }

    /**
     * Rename file
     *
     * This function sets the original name of the specified file to a new name.
     *
     * @param mixed $sourceFile Either a string with full path to a file, or a eF_File object
     * @param string $newName The new file name
     * @param boolean $overwrite If true, overwrite file with same name in destination.
     * @return boolean True if everything is ok
     * @see eF_File :: rename()
     * @since 3.0
     * @access public
     * @static
     */
    public static function rename($sourceFile, $newName) {
        if (!($sourceFile instanceof eF_File)) {
            $sourceFile = new eF_File($sourceFile);
        }
        return $sourceFile -> rename($newName);
    }


    /**
     * Validate path
     *
     * This function is used to check if a path (directory) is valid and exists, and also to standardize
     * its form. It users realpath() to resolve ambiguities and appends trailing /.
     * <br/>Example:
     * <code>
     * $directory = 'c:\www\eFront\';
     * echo EfrontFileSystem :: checkPath($directory); //Displays 'c:/www/eFront/'
     * </code>
     *
     * @param string $directory The directory to check
     * @return mixed The directory name, in a standard format, or false if it is not valid
     * @access public
     * @since 3.0
     * @static
     */
    public static function checkPath($directory) {
        if (!$directory || !is_dir($directory)) {
            return false;
        }
        $directory = realpath($directory.'/');
        if (strpos($directory, realpath(G_ROOTPATH)) !== false) {
            $directory = str_replace("\\", "/", $directory).'/';
            $directory = str_replace("//", "/", $directory);
            return $directory;
        } else {
            return false;
        }
    }

    /**
     * Validate filename
     *
     * This function is used to check if a file name is valid. It checks whether
     * the name has illegal characters, but also against the black and white lists
     * defined in the system. If the file is not valid, an EfrontFileException is thrown
     * <br/>Example:
     * <code>
     * echo EfrontFileSystem :: checkFile('test.txt'); //Displays 'test.txt'
     * echo EfrontFileSystem :: checkFile('test.php'); //php files usually belong to a black list, so this line issues an EfrontFileException
     * </code>
     *
     * @param string $filename The filename to check
     * @return string The valid filename
     * @access public
     * @since 3.0
     * @static
     * @deprecated
     */
    public static function checkFile($filename) {
        $filename = basename($filename);                        //Remove path information from filename
        $GLOBALS['configuration']['file_black_list'] ? $blackList = explode(",", $GLOBALS['configuration']['file_black_list']) : $blackList = array();
        $GLOBALS['configuration']['file_white_list'] ? $whiteList = explode(",", $GLOBALS['configuration']['file_white_list']) : $whiteList = array();

        if (!eF_checkParameter($filename, 'filename')) {
            throw new EfrontFileException(_ILLEGALFILENAME, EfrontFileException :: ILLEGAL_FILE_NAME);
        } else if (in_array(pathinfo($filename, PATHINFO_EXTENSION), $blackList)) {
            throw new EfrontFileException(_NOTALLOWEDEXTENSIONFILEINBLACKLIST, EfrontFileException :: FILE_IN_BLACK_LIST);
        } else if (sizeof($whiteList) > 0 && !in_array(pathinfo($filename, PATHINFO_EXTENSION), $whiteList)) {
            throw new EfrontFileException(_NOTALLOWEDEXTENSIONFILENOTINWHITELIST, EfrontFileException :: FILE_NOT_IN_WHITE_LIST);
        } else {
            return $filename;
        }
    }


    /**
     * Handle uploaded file
     *
     * This function is used to handle an uploaded file. Given the name of the form field
     * that was used to upload the file, as well as the destination directory, the function
     * creates the corresponding database entry and moves the file to the designated position,
     * using the appropriate name.
     * <br/>Example:
     * <code>
     * $directory = new eF_Directory('some_dir');                    //the directory to upload the file to.
     * try {
     *   $uploadedFile = EfrontFileSystem :: uploadFile('file_upload', $directory -> getFullPath());
     * } catch (EfrontFileException $e) {
     *   echo $e -> getMessage();
     * }
     * </code>
     *
     * @param string $fieldName The form file field name
     * @param string $destinationDirectory The destination for the uploaded file
     * @param string $offset If the field name is on the form file[x] (array-like), then specifying specific offset (x) allows for handling of it
     * @return object An object of eF_File class, corresponding to the newly uploaded file.
     * @access public
     * @since 3.0
     * @static
     */
    public static function uploadFile($fieldName, $destinationDirectory, $offset = false) {
        if ($destinationDirectory = EfrontFileSystem :: checkPath($destinationDirectory)) {
            if ($offset !== false) {
                $error    = $_FILES[$fieldName]['error'][$offset];
                $size     = $_FILES[$fieldName]['size'][$offset];
                $name     = $_FILES[$fieldName]['name'][$offset];
                $tmp_name = $_FILES[$fieldName]['tmp_name'][$offset];
            } else {
                $error    = $_FILES[$fieldName]['error'];
                $size     = $_FILES[$fieldName]['size'];
                $name     = $_FILES[$fieldName]['name'];
                $tmp_name = $_FILES[$fieldName]['tmp_name'];
            }

            if ($error) {
                switch ($error) {
                    case UPLOAD_ERR_INI_SIZE :
                        throw new EfrontFileException(_THEFILE." "._MUSTBESMALLERTHAN." ".ini_get('upload_max_filesize'), UPLOAD_ERR_INI_SIZE );
                        break;
                    case UPLOAD_ERR_FORM_SIZE :
                        throw new EfrontFileException(_THEFILE." "._MUSTBESMALLERTHAN." ".sprintf("%.0f", $_POST['MAX_FILE_SIZE']/1024)." "._KILOBYTES, UPLOAD_ERR_FORM_SIZE);
                        break;
                    case UPLOAD_ERR_PARTIAL :
                        throw new EfrontFileException(_FILEWASPARTIALLYUPLOADED, UPLOAD_ERR_PARTIAL);
                        break;
                    case UPLOAD_ERR_NO_FILE :
                        throw new EfrontFileException(_NOFILEUPLOADED, UPLOAD_ERR_NO_FILE);
                        break;
                    case UPLOAD_ERR_NO_TMP_DIR :
                        throw new EfrontFileException(_NOTMPDIR, UPLOAD_ERR_NO_TMP_DIR);
                        break;
                    case UPLOAD_ERR_CANT_WRITE :
                        throw new EfrontFileException(_UPLOADCANTWRITE, UPLOAD_ERR_CANT_WRITE);
                        break;
                    case UPLOAD_ERR_EXTENSION :
                        throw new EfrontFileException(_UPLOADERREXTENSION, UPLOAD_ERR_EXTENSION);
                        break;
                    default:
                        throw new EfrontFileException(_ERRORUPLOADINGFILE, EfrontFileException :: UNKNOWN_ERROR);
                        break;
                }
            } elseif ($size == 0) {
                throw new EfrontFileException(_FILEDOESNOTEXIST, EfrontFileException :: FILE_NOT_EXIST);
            } elseif (!EfrontFileSystem :: checkFile($name)) {
                throw new EfrontFileException(_ILLEGALFILENAME, EfrontFileException :: ILLEGAL_FILE_NAME);
            } else {
                try {
                    $newName = EfrontFileSystem :: createFile($name, $destinationDirectory);
                    move_uploaded_file($tmp_name, $destinationDirectory.$newName);
                    return new eF_File($destinationDirectory.$newName);
                } catch (EfrontFileException $e) {
                    throw $e;
                }
            }

        } else {
            return false;
        }
    }

    /**
     * Create file
     *
     * This function is used to create the database representation of a file.
     * It accepts the original file name and the directory it resides in (or will reside)
     * and creates a database entry for it and a new name to be used in the filesystem
     * It then returns the new name for the file. If a file with the same name already exists
     * in the specified directory, it will be either overwritten or an EfrontFileException will
     * be thrown, depending on the $overwrite parameter
     *
     * @param string $name The original file name
     * @param string $directory The file directory
     * @param boolean $overwrite If true, overwrite existing file with the same original name
     * @return string The new file name
     * @access public
     * @since 3.0
     * @static
     */
    public static function createFile($name, $directory, $overwrite = true) {
        if (($directory = EfrontFileSystem :: checkPath($directory)) && ($name = EfrontFileSystem :: checkFile($name))) {
            $file_exists = eF_getTableData("files", "id, physical_name, type", "original_name = '$name' and directory = '$directory'");
            if (sizeof($file_exists) > 0) {
                if (!$overwrite) {
                    throw new EfrontFileException(_FILEALREADYEXISTS, EfrontFileException :: FILE_ALREADY_EXISTS);
                } elseif ($file_exists[0]['type'] != 'file') {
                    throw new EfrontFileException(_DIRECTORYEXISTSSAMENAME, EfrontFileException :: DIRECTORY_ALREADY_EXISTS);
                } else {
                    return $file_exists[0]['physical_name'];
                }
            } else {
                $fields = array("file"          => $directory.$name,
                                "physical_name" => $name,
                                "original_name" => $name,
                                "users_LOGIN"   => isset($_SESSION['s_login']) ? $_SESSION['s_login'] : '',
                                "timestamp"     => time(),
                                "description"   => $name);
                if ($file_id = eF_insertTableData("files", $fields)) {
                    POSTFIX                             ? $physicalName  = $file_id                                : $physicalName = $name;
                    pathinfo($name, PATHINFO_EXTENSION) ? $physicalName .= '.'.pathinfo($name, PATHINFO_EXTENSION) : null;
                    POSTFIX                             ? $physicalName .= '.'.POSTFIX                             : null;
                    eF_updateTableData("files", array("file" => $directory.$physicalName, "physical_name" => $physicalName), "id=$file_id");
                    return $physicalName;
                } else {
                    throw new EfrontFileException(_COULDNOTCREATEFILEDATABASE, EfrontFileException :: DATABASE_ERROR);
                }
            }
        } else {
            throw new EfrontFileException(_ILLEGALPATH.': '.$directory, EfrontFileException :: ILLEGAL_PATH);
        }
    }

    /**
     * Create directory
     *
     * This function is used to create a new directory in the filesystem, as well as the
     * corresponding database representation for it. It accepts the original directory name
     * and the directory it will reside in and returns the eF_Directory object for the new
     * directory.
     * <br/>Example:
     * <code>
     * $directory = new eF_Directory('some_dir');                    //the directory to create the new directory in.
     * try {
     *   $newDirectory = EfrontFileSystem :: makeDirectory('dir_name', $directory -> getFullPath());
     * } catch (EfrontFileException $e) {
     *   echo $e -> getMessage();
     * }
     * </code>
     *
     * @param string $name The original directory name
     * @param string $parentDirectory The parent directory
     * @return eF_Directory The new directory object
     * @access public
     * @since 3.0
     * @static
     */
    public static function makeDirectory($name, $parentDirectory) {
        if (($parentDirectory = EfrontFileSystem :: checkPath($parentDirectory)) && ($name = EfrontFileSystem :: checkFile($name))) {
            //$directory_exists = eF_getTableData("files", "id, physical_name, type", "original_name = '$name' and directory = '$parentDirectory'");
            try {
                $directory_exists = new eF_Directory($parentDirectory.$name);                           //Check if the directory already exists;
                throw new EfrontFileException(_DIRECTORYALREADYEXISTS, EfrontFileException :: FILE_ALREADY_EXISTS);//If it exists, throw a new exception...
            } catch (EfrontFileException $e) {                                                             //Otherwise, continue
                if ($e -> getCode() == EfrontFileException :: FILE_ALREADY_EXISTS) {                       //If we caught the previously thrown exception, propagate it
                    throw $e;
                }
                $fields = array("file"          => "temp",
                                "physical_name" => "temp",
                                "original_name" => $name.'/',
                                "directory"     => $parentDirectory,
                                "users_LOGIN"   => isset($_SESSION['s_login']) ? $_SESSION['s_login'] : '',
                                "timestamp"     => time(),
                                "type"          => 'directory',
                                "description"   => $name);
                if ($file_id = eF_insertTableData("files", $fields)) {
                    POSTFIX ? $physicalName = $file_id.'/' : $physicalName = $name.'/';
                    eF_updateTableData("files", array("file" => $parentDirectory.$physicalName, "physical_name" => $physicalName), "id=$file_id");
                    if (mkdir($parentDirectory.$physicalName, 0755)) {
                        return new eF_Directory($parentDirectory.$physicalName);
                    } else {
                        eF_deleteTableData("files", "id=".$file_id);
                        throw new EfrontFileException(_COULDNOTCREATEDIRECTORY, EfrontFileException :: GENERAL_ERROR);
                    }
                } else {
                    throw new EfrontFileException(_COULDNOTCREATEDIRECTORYDATABASE, EfrontFileException :: DATABASE_ERROR);
                }
            }
        } else {
            throw new EfrontFileException(_ILLEGALPATH.': '.$parentDirectory, EfrontFileException :: ILLEGAL_PATH);
        }
    }

    /**
     * Filter files
     *
     * This function filters files so that specific entries are not treated.
     * For example, this function may be used to exclude all .php files from a
     * result set, or to narrow a file list to include only files of the designated
     * type, i.e. png, jpg,... By default, '.', '..' and '.svn' are filtered out.
     * The function unsets elements of the array, but does not reindexes it.
     * <br/>Example:
     * <code>
     * $filterInt = array('png');
     * $dirfiles = scandir('/var/www/');                                            //Get all .png files in a directory
     * $dirfiles = array_values(EfrontFileSystem :: filterFiles($dirfiles, $filterIn));
     * </code>
     *
     * @param array $fileList An array of file entries to check, where either values are the file names, or values are sub-arrays with the file name in the 'original_name' key
     * @param array $filterIn An array of file extensions that designate which files should be left in the list
     * @param array $filterOut An array of file extensions that designate which files should be removed from the list
     * @return array The filtered files array
     * @access public
     * @since 3.0
     * @static
     */
    public static function filterFiles($fileList, $filterIn = false, $filterOut = false) {
        is_array($filterOut) && sizeof($filterOut) > 0 ? $filterOut = array_merge($filterOut, array('svn')) : $filterOut = array('svn');        //By default, '.svn' files are excluded. If a $filterOut list was specified, merge it with this

        foreach ($fileList as $key => $file) {
            if (is_array($file)) {
                $file = $file['original_name'];
            }
            function_exists('mb_strtolower') ? $file = mb_strtolower($file) : $file = strtolower($file);    //This is beause this function is used at the installation, before the check that Multibyte support exists

            if ($file == '.' || $file == '..' || in_array(pathinfo($file, PATHINFO_EXTENSION), $filterOut) || (is_array($filterIn) && !in_array(pathinfo($file, PATHINFO_EXTENSION), $filterIn))) {              //Filter array
                unset($fileList[$key]);
            }
        }
        return $fileList;
    }


    /**
     * Import files to filesystem
     *
     * This function imports the specified files (in $list array) to the filesystem,
     * by creating a corresponding database representation. By default, their name
     * is changed to match the id, unless $rename is specified and false. The $list
     * array should contain full paths to the files. The function returns an array
     * of the same size and contents as $list , but this time the file ids being the keys
     * <br/>Example:
     * <code>
     * $list = array('/var/www/text.txt', '/var/www/user.txt');
     * $newList = EfrontFileSystem :: importFiles($list);
     * </code>
     *
     * @param array $list The files list
     * @param boolean $rename whether to rename files
     * @return array An array with the new file ids
     * @access public
     * @since 3.0
     * @static
     */
    public static function importFiles($list, $rename = true) {
        if (!is_array($list)) {
            $list = array($list);
        }

        //$GLOBALS['db']->debug=true;
        $allFiles = eF_getTableDataFlat("files", "file");                       //Get all files, so that if a file already exists, a duplicate entry in the database won't be created
        for ($i = 0; $i < sizeof($list); $i++) {
            if (!in_array($list[$i], $allFiles['file'])) {
                $fields = array('file'          => $list[$i],
                                'physical_name' => basename($list[$i]),
                                'original_name' => basename($list[$i]),
                                'directory'     => eFrontFilesystem :: checkPath(dirname($list[$i])),
                                'type'          => is_dir($list[$i]) ? 'directory' : 'file',
                                'users_LOGIN'   => isset($_SESSION['s_login']) ? $_SESSION['s_login'] : '',
                                'timestamp'     => time(),
                                'description'   => basename($list[$i]));

                $fileId = eF_insertTableData("files", $fields);
                if ($fileId) {
                    $newList[$fileId] = $list[$i];
                    if ($rename) {
                        $newName = $fields['directory'].$fileId.'.'.pathinfo($list[$i], PATHINFO_EXTENSION).'.'.POSTFIX;
                    }
                    if (rename($list[$i], $newName)) {
                        eF_updateTableData("files", array("file" => $newName, "physical_name" => basename($newName)), "id=$fileId");
                    }
                }
            }
        }

        return $newList;
    }

    /**
     * Check if the specified id belongs to a file or directory
     *
     * This function is used to check whether the given id corresponds to
     * a file or a directory entity
     *
     * @param int $id The file or directory id
     * @return string 'file' or 'directory', or false if an entity with the specified id does not exist
     * @access public
     * @since 3.0
     * @static
     *
     */
    public static function checkId($id) {
        if (eF_checkParameter($id, 'id')) {
            $result = eF_getTableData("files", "type", "id=$id");
            if (sizeof($result) > 0) {
                return $result[0]['type'];
            } else {
                return false;
            }
        } else {
            return false;
        }
    }


}

/**
 * eF_File class
 *
 * This class is used to manipulate files
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class eF_File
{
    /**
     * The full physical file, including path
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $file = '';

    /**
     * The physical file name in file system
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $filename = '';

    /**
     * The directory where the real file resides
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $directory = '';

    /**
     * The database stored file data, such as given name, owner, metadata, physical name etc.
     *
     * @since 3.0
     * @var array
     * @access protected
     */
    protected $fileData = array();


    /**
     * Class constructor
     *
     * This function is used to instantiate class. It accepts a file name as initiation parameter
     * The filename may either be a physical file in the file system, or the original file name.
     * In the latter case, the file must have an equivalent database entry. In either case, the
     * directory where the file resides should be specified along with the file name.
     * The filename may also be the file id in the database, in which case there is no need to
     * specify the directory.
     * If the file exists in the database, but not in the filesystem, then it is automatically
     * deleted and an EfrontFileException :: FILE_DELETED exception is thrown
     * If the file exists in the filesystem, but not in the database, then if $createDB is set to
     * true, a database representation will be created, otherwise a FILE_NOT_EXIST exception will
     * be thrown
     * <br/>Example:
     * <code>
     * $file = new eF_File("/var/www/test.txt");                     //Using original file name
     * $file = new eF_File("/var/www/1234.txt.efront");              //Using physical file name
     * $file = new eF_File(3213);                                    //Using file id
     * $file = new eF_File("/var/www/test.txt", true);               //Using original file name, and the database represenation will be created
     * </code>
     *
     * @param string $filename the file name
     * @param boolean $createDB whether to create database representation for the file
     * @since 3.0
     * @access public
     */
    function __construct($filename, $createDB = true) {
        if (eF_checkParameter($filename, 'id')) {
            $result = eF_getTableData("files", "*", "type = 'file' and id=".$filename);
            if (sizeof($result) > 0 && is_file($result[0]['file'])) {
                $dirname = $result[0]['file'];
                $this -> file      = $result[0]['file'];
                $this -> filename  = $result[0]['physical_name'];
                $this -> directory = $result[0]['directory'];
                $this -> fileData  = $result[0];
            } else {
                throw new EfrontFileException(_FILEDOESNOTEXIST, EfrontFileException :: FILE_NOT_EXIST);
            }
        } else {
            $dir = EfrontFileSystem :: checkPath(dirname($filename));                    //Check if the designated file lies within the root directory
            if (!$dir) {
                if (eF_checkParameter($filename, 'path')) {
                    $result = eF_getTableData("files", "*", "file='$filename' and type = 'file'");
                    if (sizeof($result) > 0) {
                        $this -> directory = $result[0]['directory'];
                        $this -> filename  = $result[0]['physical_name'];
                        $this -> file      = $this -> directory.$this -> filename;
                        $this -> fileData  = $result[0];
                    } else {
                        throw new EfrontFileException(_FILEDOESNOTEXIST, EfrontFileException :: FILE_NOT_EXIST);
                    }
                } else {
                    throw new EfrontFileException(_ILLEGALPATH.': '.$filename, EfrontFileException :: ILLEGAL_PATH);
                }
            } else {
                $result = eF_getTableData("files", "*", "type = 'file' and file='".$filename."'");
                if (sizeof($result) > 0) {
                    $this -> directory = $dir;
                    $this -> filename  = basename($filename);
                    $this -> file      = $this -> directory.$this -> filename;
                    $this -> fileData  = $result[0];
                } else {                //A file with the specified filename was not found. Check if the original file name was specified
                    $result = eF_getTableData("files", "*", "type = 'file' and original_name='".basename($filename)."' and directory = '".$dir."'");
                    if (sizeof($result) > 0) {
                        $this -> directory = $result[0]['directory'];
                        $this -> filename  = $result[0]['physical_name'];
                        $this -> file      = $this -> directory.$this -> filename;
                        $this -> fileData  = $result[0];
                    } else {                                                            //The file does not exist, either as physical or as original name
                        if ($createDB && is_file($filename)) {
                            $filename = str_replace("\\", "/", $filename);
                            $fields = array("file"          => $filename,
                                            "physical_name" => basename($filename),
                                            "original_name" => basename($filename),
                                            "directory"     => dirname($filename).'/',
                                            "users_LOGIN"   => isset($_SESSION['s_login']) ? $_SESSION['s_login'] : '',
                                            "timestamp"     => time(),
                                            "type"          => 'file',
                                            "description"   => basename($filename));
                            $file_id = eF_insertTableData("files", $fields);
                            $result = eF_getTableData("files", "*", "id=$file_id");
                            $this -> directory = $result[0]['directory'];
                            $this -> filename  = $result[0]['physical_name'];
                            $this -> file      = $this -> directory.$this -> filename;
                            $this -> fileData  = $result[0];
                        } else {
                            throw new EfrontFileException(_FILEDOESNOTEXIST, EfrontFileException :: FILE_NOT_EXIST);
                        }
                    }
                }
            }
        }

        if (!is_file($this -> file)) {
            $this -> deleteDB();
            throw new EfrontFileException(_FILEDOESNOTEXIST, EfrontFileException :: FILE_DELETED);
        }
    }

    /**
     * Get file full path and name
     *
     * This function returns the full physical file path, including name
     * <br/>Example:
     * <code>
     * echo $file -> getFullPath();     //displays something like "/var/www/321.txt.efront"
     * </code>
     *
     * @return string The full physical path, including name, of the file
     * @since 3.0
     * @access public
     */
    public function getFullPath() {
        return $this -> file;
    }

    /**
     * Get file physical name
     *
     * This function returns the physical file name
     * <br/>Example:
     * <code>
     * echo $file -> getPhysicalName();     //displays something like "321.txt.efront"
     * </code>
     *
     * @return string The physical file name
     * @since 3.0
     * @access public
     */
    public function getPhysicalName() {
        return $this -> filename;
    }

    /**
     * Get file original name
     *
     * This function returns the original file name
     * <br/>Example:
     * <code>
     * echo $file -> getOriginalName();     //displays something like "test.txt"
     * </code>
     *
     * @return string The original file name
     * @since 3.0
     * @access public
     */
    public function getOriginalName() {
        return $this -> fileData['original_name'];
    }

    /**
     * Get file extension
     *
     * This function returns the original file extension
     * <br/>Example:
     * <code>
     * echo $file -> getExtension();     //displays something like "txt"
     * </code>
     *
     * @return string The original file extension
     * @since 3.0
     * @access public
     */
    public function getExtension() {
        return pathinfo($this -> fileData['original_name'], PATHINFO_EXTENSION);
    }

    /**
     * Get file path
     *
     * This function returns the path to the directory where the file resides
     * <br/>Example:
     * <code>
     * echo $file -> getDirectory();     //displays something like "/var/www/"
     * </code>
     *
     * @return string The file directory
     * @since 3.0
     * @access public
     */
    public function getDirectory() {
        return $this -> directory;
    }

    /**
     * Get file id
     *
     * This function returns the file id in the database
     * <br/>Example:
     * <code>
     * echo $file -> getFileId();     //displays something like "322"
     * </code>
     *
     * @return int The file id
     * @since 3.0
     * @access public
     */
    public function getFileId() {
        return $this -> fileData['id'];
    }

    /**
     * Get file information
     *
     * This function returns information about the file
     * <br/>Example:
     * <code>
     * $info = $file -> getInfo();
     * //Returns:
     * Array (
     *   [full_path] => /var/www/321.txt.efront
     *   [physical_name] => 321.txt.efront
     *   [original_name] => test.txt
     *   [extension] => txt
     *   [type]      => file
     *   [mime_type] => text/plain
     *   [timestamp] => 1231231230
     *   [directory] => /var/www/
     *   [size] => 3212
     * )
     * </code>
     *
     * @return array An array with file information
     * @since 3.0
     * @access public
     */
    public function getInfo() {
        $info = array("full_path"     => $this -> getFullPath(),
                      "physical_name" => $this -> getPhysicalName(),
                      "original_name" => $this -> getOriginalName(),
                      "extension"     => $this -> getExtension(),
                      "directory"     => $this -> getDirectory(),
                      "type"          => 'file',
                      "mime_type"     => EfrontFileSystem :: $mimeTypes[strtolower($this -> getExtension())] ? EfrontFileSystem :: $mimeTypes[strtolower($this -> getExtension())] : 'application/'.$this -> getExtension(),
                      "timestamp"     => $this -> fileData['timestamp'],
                      "size"          => round(filesize($this -> getFullPath())/1024, 2),
                      "id"            => $this -> fileData['id'],
                      "users_LOGIN"   => $this -> fileData['users_LOGIN'],
                      "description"   => $this -> fileData['description']);
        return $info;
    }


    /**
     * Delete physical file from file system
     *
     * This function deletes the file from the filesystem. If the file
     * can't be deleted, an EfrontFileException is thrown.
     *
     * @return boolean True if the file was deleted
     * @since 3.0
     * @access public
     */
    public function deleteFS() {
        if (unlink($this -> file)) {
            return true;
        } else {
            throw new EfrontFileException(_CANNOTDELETEFILE, EfrontFileException :: GENERAL_ERROR);
        }
    }

    /**
     * Delete file from data base
     *
     * This function deletes the file from the database only.
     *
     * @return boolean True if the file was deleted
     * @since 3.0
     * @access public
     */
    public function deleteDB() {
        eF_deleteTableData("files", "id=".$this -> fileData['id']);
    }

    /**
     * Delete file
     *
     * This function deletes the file. It uses deleteFS to unlink
     * the physical file, and then deletes its entry from the database
     * and performs any cleanup necessary.
     *
     * @return boolean True if the file was deleted
     * @since 3.0
     * @access public
     * @see function deleteFS()
     */
    public function delete() {
        if (is_file($this -> file)) {                       //This way, even files that their equivalent physical file does not exist, may be deleted
            $this -> deleteFS();
        }
        eF_deleteTableData("files", "id=".$this -> fileData['id']);
        return true;
    }

    /**
     * Rename physical file in file system
     *
     * This function renames a file in the filesystem. It does not alter its database
     * representation. If $overwrite is specified and a file with the same name already exists,
     * It will be replaced.
     *
     * @param string $newName The new physical file name
     * @param boolean $overwrite Whether to overwrite existing file with the same name
     * @return boolean True if the file was renamed
     * @since 3.0
     * @access public
     */
    public function renameFS($newName, $overwrite = false) {
        $newName = EfrontFileSystem :: checkFile($newName);                //Check if the new name specified is valid
        if (is_file($this -> directory.$newName)) {                     //If this file already exists
            if ($overwrite) {                                           //If we are going to repalce the existing file, unlink it first
                unlink($this -> directory.$newName);
            } else {
                throw new EfrontFileException(_CANNOTRENAMEFILE, EfrontFileException :: FILE_ALREADY_EXISTS);
            }
        }
        if (rename($this -> file, $this -> directory.$newName)) {       //Rename file
            return true;
        } else {
            throw new EfrontFileException(_CANNOTRENAMEFILE, EfrontFileException :: GENERAL_ERROR);
        }
    }

    /**
     * Rename file
     *
     * This function renames the file. It does so by changing its original
     * file name that is stored in the database. It does not alter its physical
     * name in the filesystem
     *
     * @param string $newName The new physical file name
     * @return boolean True if the file was renamed
     * @since 3.0
     * @access public
     */
    public function rename($newName) {
        $newName = EfrontFileSystem :: checkFile($newName);                //Check if the new name specified is valid
        $this -> fileData['original_name'] = $newName;                  //Update file information
        $this -> persist();                                             //Store updated file information
        return true;
    }

    /**
     * Copy physical file in file system
     *
     * This function copies a file to the designated directory in the filesystem. It does not alter
     * its database representation. If $newName is specified, then the copied file will be given
     * this name. If $overwrite is specified and a file with the same name already exists,
     * it will be replaced.
     *
     * @param string $destinationDirectory The target directory
     * @param string $newName The copied file name
     * @param boolean $overwrite Whether to overwrite existing file with the same name
     * @return boolean True if the file was copied successfully
     * @since 3.0
     * @access public
     */
    public function copyFS($destinationDirectory, $newName = false, $overwrite = false) {
        if ($destinationDirectory = EfrontFileSystem :: checkPath($destinationDirectory)) {                    //Check if directory is valid
            $newName ? $newName = EfrontFileSystem :: checkFile($newName) : $newName = $this -> filename;      //If $newName is specified, check if it is valid. Otherwise, use the same physical name as the copied file's
            if ((is_file($destinationDirectory.$newName) && !$overwrite) || is_dir($destinationDirectory.$newName)) {       //If a file with the same name already exists and $overwrite is false, throw a FILE_ALREADY_EXISTS Exception
                throw new EfrontFileException(_CANNOTCOPYFILE.': '._FILEALREADYEXISTS, EfrontFileException :: FILE_ALREADY_EXISTS);
            } else {
                if (copy($this -> file, $destinationDirectory.$newName)) {                                  //Copy the file
                    return true;
                } else {
                    throw new EfrontFileException(_CANNOTCOPYFILE, EfrontFileException :: GENERAL_ERROR);         //If the file could not be copied issue a general Exception
                }
            }
        } else {
            throw new EfrontFileException(_ILLEGALPATH.': '.$destinationDirectory, EfrontFileException :: ILLEGAL_PATH);                     //the directory specified is invalid
        }
    }

    /**
     * Copy file
     *
     * This function copies the file to the designated directory. In order to do this, it first
     * creates an empty file entry, using EfrontFileSystem :: createFile(), then copies the file to the new
     * directory and finally renames the copied file using the new name from the empty file
     * If a file with the same original name already exists in the target directory, it may be
     * overwritten depending on $overwrite variable. A file with the same physical name, however,
     * will be definitely overwritten.
     * <br/>Example:
     * <code>
     * $file      = new eF_File(5434);               //Create a file object
     * $directory = new eF_Directory(432);           //Create a directory object
     * $file -> copy($directory);                    //Copy the file to the directory
     * </code>
     *
     * @param mixed $destinationDirectory Either an eF_Directory object or the physical name and path of the directory to copy the file to
     * @param string $overwrite Whether to overwrite existing file with the same name.
     * @return eF_File The copied file
     * @since 3.0
     * @access public
     */
    public function copy($destinationDirectory, $newName = false, $overwrite = false) {
        if ($destinationDirectory instanceof eF_Directory) {
            $destinationDirectory = $destinationDirectory -> getFullPath();
        } else if (!($destinationDirectory = EfrontFileSystem :: checkPath($destinationDirectory))) {  //Check if directory is valid
            throw new EfrontFileException(_ILLEGALPATH.': '.$destinationDirectory, EfrontFileException :: ILLEGAL_PATH);             //the directory specified is invalid
        }
        $newName ? $newName = EfrontFileSystem :: checkFile($newName) : $newName = $this -> fileData['original_name']; //If $newName is specified, check if it is valid. Otherwise, use the same original name as the copied file's
        try {
            $file = new eF_File($destinationDirectory.$newName);                                //Check if a file with the same *original* name already exists. If it does not, execution will jump to Catch block below
            if (!$overwrite) {                                                                  //If we are here, it means the file already exists. If $overwrite is false, then throw a FILE_ALREADY_EXISTS exception
                throw new EfrontFileException(_CANNOTCOPYFILE.': '._FILEALREADYEXISTS, EfrontFileException :: FILE_ALREADY_EXISTS);
            } else {                                                                            //The file with the same already exists, but $overwrite is true.
                $newPhysicalName = $file -> getPhysicalName();                                  //Get the physical name of the existing file
                $this -> copyFS($destinationDirectory, $newPhysicalName, true);                 //Copy the physical file with the same name to replace the old one
                return new eF_File($destinationDirectory.$newName);                             //Database needs not change, since the information is the same. Return the copied file
            }
        } catch (EfrontFileException $e) {                                                         //This means the file does not exist
            $newPhysicalName = EfrontFileSystem :: createFile($newName, $destinationDirectory, $overwrite);     //Create a new file for the copied one, and get the physical name we will use
            $this -> copyFS($destinationDirectory, $newPhysicalName, true);                     //Copy the physical file using the new physical name
            return new eF_File($destinationDirectory.$newName);                                 //Return the new file
        }

    }


    /**
     * Move physical file in file system
     *
     * This function moves a file to the designated directory in the filesystem. It does not alter
     * its database representation. If $newName is specified, then the moved file will be given
     * this name. If $overwrite is specified and a file with the same name already exists,
     * it will be replaced.
     *
     * @param string $destinationDirectory The target directory
     * @param string $newName The moved file name
     * @param boolean $overwrite Whether to overwrite existing file with the same name
     * @return boolean True if the file was moved successfully
     * @since 3.0
     * @access public
     */
    public function moveFS($destinationDirectory, $newName = false, $overwrite = false) {
        $this -> copyFS($destinationDirectory, $newName, $overwrite);                               //Copy the file to the designated position
        $this -> deleteFS();                                                                        //Delete the original file
        return true;
    }

    /**
     * Move file
     *
     * This function moves the file to the designated directory, optionally using
     * $newName as new name. If a file with the same original name already exists
     * in the target directory, it may be overwritten depending on $overwrite variable.
     * A file with the same physical name, however, will be definitely overwritten.
     *
     * @param string $destinationDirectory The directory to move the file to
     * @param string $overwrite Whether to overwrite existing file with the same name.
     * @return boolean True if the file was moved successfully
     * @since 3.0
     * @access public
     */
    public function move($destinationDirectory, $newName = false, $overwrite = false) {
        if ($destinationDirectory = EfrontFileSystem :: checkPath($destinationDirectory)) {            //Check if directory is valid
            $newName ? $newName = EfrontFileSystem :: checkFile($newName) : $newName = $this -> fileData['original_name']; //If $newName is specified, check if it is valid. Otherwise, use the same original name as the moved file's
            try {
                $file = new eF_File($destinationDirectory.$newName);                                //Check if a file with the same *original* name already exists. If it does not, execution will jump to Catch block below
                if (!$overwrite) {                                                                  //If we are here, it means the file already exists. If $overwrite is false, then throw a FILE_ALREADY_EXISTS exception
                    throw new EfrontFileException(_CANNOTMOVEFILE.': '._FILEALREADYEXISTS, EfrontFileException :: FILE_ALREADY_EXISTS);
                } else {
                    $newPhysicalName = $file -> getPhysicalName();                                  //Get the physical name of the existing file
                    $this -> moveFS($destinationDirectory, $newPhysicalName, true);                 //Move the physical file with the same name to replace the old one
                    return new eF_File($destinationDirectory.$newName);                             //Database needs not change, since the information is the same. Return the copied file
                }
            } catch (EfrontFileException $e) {                                                         //This means the file does not exist
                $this -> moveFS($destinationDirectory, false, true);                                //Move the file to the new directory
                $this -> file                      = $destinationDirectory.$this -> filename;       //Update fie information to reflect the change to the path
                $this -> directory                 = $destinationDirectory;
                $this -> fileData['original_name'] = $newName;
                $this -> persist();                                                                 //Store updated information
                return new eF_File($destinationDirectory.$newName);                                 //Return the moved file
            }
        } else {
            throw new EfrontFileException(_ILLEGALPATH.': '.$destinationDirectory, EfrontFileException :: ILLEGAL_PATH);             //the directory specified is invalid
        }
    }

    /**
     * Compress File
     *
     * This function is used to create a compressed version of the file
     * using the designated method. Defaults to 'zip'
     *
     * @param string $method The compression method to use. Can be one of 'zip', 'tar.gz'
     * @return eF_File the compressed version of the file
     * @since 3.0
     * @access public
     */
    public function compress($method = 'gz') {
        switch ($method) {
            case 'gz': case 'tar.gz':
                //require_once("Archive/Tar.php");
                $tarOriginalName = pathinfo($this -> getOriginalName(), PATHINFO_FILENAME).'.tar.gz';
                $tarPhysicalName = EfrontFileSystem :: createFile($tarOriginalName, $this -> getDirectory());
                $tar             = new Archive_Tar($this -> getDirectory().$tarPhysicalName, 'gz');
                $tar -> addString($this -> getOriginalName(), file_get_contents($this -> getFullPath()));
                return new eF_File($this -> getDirectory().$tarPhysicalName);
                break;
            case 'zip': default:
                $zip      = new ZipArchive();
                $zipOriginalName = pathinfo($this -> getOriginalName(), PATHINFO_FILENAME).'.zip';
                $zipPhysicalName = EfrontFileSystem :: createFile($zipOriginalName, $this -> getDirectory());
                if ($zip -> open($this -> getDirectory().$zipPhysicalName, ZIPARCHIVE::CREATE) === TRUE &&
                $zip -> addFile($this -> getFullPath(), $this -> getOriginalName())) {

                    $zip -> close();
                    return new eF_File($this -> getDirectory().$zipPhysicalName);
                } else {
                    throw new EfrontFileException(_CANNOTCREATEZIPFILE, EfrontFileException :: ERROR_CREATE_ZIP);             //the directory specified is invalid
                }
                break;
        }
    }

    /**
     * Uncompress File
     *
     * This function is used to create an uncompressed version of the file
     * using the designated method. If the file already exists it will be
     * overwritten. If $createDirectory is true, then the file will be uncompressed
     * in a folder with the same name.
     *
     * @param string $method The (un)compression method to use. Can be one of 'zip', 'tar.gz'
     * @param boolean $createDirectory Whether a new folder will be created and the files will be uncompressed in it
     * @return boolean true if the operation was successful.
     * @since 3.0
     * @access public
     */
    public function uncompress($method = false, $createDirectory = false) {
        if (!$method) {
            $method = $this -> getExtension();
        }

        switch ($method) {
            case 'gz': case 'tar.gz':
                require_once("Archive/Tar.php");
                $tar         = new Archive_Tar($this -> file, 'gz');
                $tarContents = $tar -> listContent();
                $list       = array();
                foreach ($tarContents as $value) {
                    $list[] = $this -> getDirectory().$value['filename'];
                }

                $tar -> extract($this -> getDirectory());
                $newList = EfrontFileSystem :: importFiles($list, false);
                return $newList;
                break;
            case 'zip': default:
                $zip = new ZipArchive;
                if ($zip -> open($this -> file) === TRUE) {
                    for ($i = 0; $i < $zip -> numFiles; $i++) {
                        //echo $zip -> getNameIndex($i);
                        $newName = EfrontFileSystem :: createFile($zip -> getNameIndex($i), $this -> getDirectory());
                        $zip -> renameIndex($i, $newName);
                        $zip -> extractTo($this -> getDirectory(), $newName);
                    }
                } else {
                    throw new EfrontFileException(_CANNOTOPENCOMPRESSEDFILE, EfrontFileException :: ERROR_OPEN_ZIP);
                }
                break;
        }
    }

    /**
     * Uncompress File only to filesystem
     *
     * This function is used to uncompress the file, without creating database representations
     * for uncompressed files
     *
     * @param string $method The (un)compression method to use. Can be one of 'zip' (default), 'tar.gz'
     * @return boolean true if the operation was successful.
     * @since 3.0
     * @access public
     */
    public function uncompressFS($method = false) {
        if (!$method) {
            $method = $this -> getExtension();
        }
        switch ($method) {
            case 'gz': case 'tar.gz':
                require_once("Archive/Tar.php");
                $tar         = new Archive_Tar($this -> file, 'gz');
                $tar -> extract($this -> getDirectory());
                break;
            case 'zip': default:
                $zip = new ZipArchive;
                if ($zip -> open($this -> file) === TRUE) {
                    $zip -> extractTo($this -> getDirectory());
                } else {
                    throw new EfrontFileException(_CANNOTOPENCOMPRESSEDFILE, EfrontFileException :: ERROR_OPEN_ZIP);
                }
                break;
        }
    }

    /**
     * Persist changed file properties
     *
     * During file operations, internal file attributes, such as name, physical name,
     * directory etc may be changed. Using this function, these values are stored in
     * the database.
     *
     * @return true if everything is ok.
     * @since 3.0
     * @access protected
     */
    protected function persist() {
        $fields = array("file"          => $this -> file,
                        "physical_name" => $this -> filename,
                        "original_name" => $this -> fileData['original_name'],
                        "directory"     => $this -> directory,
                        "description"   => $this -> fileData['description']);
        eF_updateTableData("files", $fields, "id=".$this -> fileData['id']);
        return true;
    }

    /**
     * Set file description
     *
     * This function is used to set the file description
     * <br/>Example:
     * <code>
     * $file = new eF_File(43);
     * $file -> setDescription('the file description');
     * </code>
     *
     * @param string $description The file description
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function setDescription($description) {
        $this -> fileData['description'] = $description;
        $this -> persist();
    }


    /**
     *
     * Create a compatible image from the filename
     *
     * This function is used to create a png image from the
     * given file. It uses the gd library if available, or
     * returns false.
     *
     * <br/>Example:
     * <code>
     * $file = new eF_File(43);
     * $newImage = $file -> createImage();
     * </code>
     *
     * @param $imagesPath: if used then the image exists in the www/images/ folder and the relative path inside that folder will be returned
     * @return the Image filename if everything is ok or False
     * @since 3.5.0
     * @access public
     * @prerequisite: GD Library loaded
     */
    public function createImage($imagesPath = false) {

        // Check if the GD library is loaded
        if (!extension_loaded('gd')) {
            return false;
        }

        // Get the image filename
        if ($imagesPath) {
            $filename = $this-> getPhysicalName();
        } else {
            $filename = $this-> getFullPath();
        }

        // Find the extension of the image file
        $original_name = $this -> fileData['original_name'];
        $fn_length = strlen($original_name);
        $extension = substr($original_name, $fn_length - 4,4);  // 11 = strlen("YXXX.efront") + 4 the extension length
        if ($extension[0] == '.') {                         // if Y == "." then we have a three letter extension
            $extension = substr($extension, 1, 3);
        }

        // Create the path where the image exists - on purpose avoiding use of getDirectory()
        if ($imagesPath) {
            $directory = G_IMAGESPATH . $imagesPath;
        } else {
            $directory = "";
        }


        // Create an image object from the existing file

        // The png, jpg, jpeg and gif files are supported
        $notSupported = 0;
        if ($extension == "png") {
            $imIn = ImageCreatefromPNG($directory.$filename);
        } elseif ($extension == "jpg") {
            $imIn = ImageCreatefromJPEG($directory.$filename);
        } elseif ($extension == "jpeg") {
            $imIn = ImageCreatefromJPEG($directory.$filename);
        } elseif ($extension == "gif") {
            $imIn = ImageCreatefromGIF($directory.$filename);
        } else {
            $notSupported = 1;
        }

        if (!$notSupported) {
             // Output the image to the browser and destroy the stream
            imageinterlace ($imIn, 0);
            ImagePNG($imIn, $directory. $filename.".png",0);

            ImageDestroy($imIn);
            return $directory. $filename.".png";
        } else {
            return false;
        }

    }



}

/**
 * eF_CompressedFile class
 *
 * This class is used to manipulate compressed files
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class eF_CompressedFile extends eF_File
{
    /**
     * The compression method
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $compression = '';

    /**
     *
     */
    function __construct($filename, $compression = false) {
        parent :: __construct($filename);
        if ($compression) {
            $this -> compression = $compression;
        } else if ($this -> getExtension() == 'gz') {
            $this -> compression = 'gz';
            $this -> tar = new Archive_Tar($this -> getFullPath(), 'gz');
        } else if ($this -> getExtension() == 'zip') {
            $this -> compression = 'zip';
        } else {
            throw new EfrontFileException (_UNKNOWNCOMPRESSIONTYPE, EfrontFileException :: UNKNOWN_COMPRESSION);
        }
    }

    /**
     *
     */
    public function addFile() {
        switch ($this -> compression) {
            case 'gz':
                break;
            case 'zip':
                break;
            default:
                throw new EfrontFileException (_UNKNOWNCOMPRESSIONTYPE, EfrontFileException :: UNKNOWN_COMPRESSION);
                break;
        }
    }

    /**
     *
     */
    public function addDirectory($directory) {
        switch ($this -> compression) {
            case 'gz':
                $directory = new eF_Directory($directory);
                $contents  = $directory -> getContentsFS();
                $this -> tar -> addModify($contents, $directory -> getOriginalName(), $directory -> getFullPath());
                return $contents;
                break;
            case 'zip':
                break;
            default:
                throw new EfrontFileException (_UNKNOWNCOMPRESSIONTYPE, EfrontFileException :: UNKNOWN_COMPRESSION);
                break;
        }
    }

    /**
     *
     */
    public function listContents() {
        switch ($this -> compression) {
            case 'gz':
                $contents = $this -> tar -> listContent();
                return $contents;
                break;
            case 'zip':
                break;
            default:
                throw new EfrontFileException (_UNKNOWNCOMPRESSIONTYPE, EfrontFileException :: UNKNOWN_COMPRESSION);
                break;
        }
    }
}


/**
 * eF_Directory class
 *
 * This class is used to manipulate directories
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class eF_Directory
{
    /**
     * The full physical path to the directory, including it
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $fullPath = '';

    /**
     * The physical name of the directory in the file system
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $directoryName = '';

    /**
     * The original name of the directory
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $originalName = '';

    /**
     * The directory where the directory resides
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $parentDirectory = '';

    /**
     * The database stored directory data, such as given name, owner, metadata, physical name etc.
     *
     * @since 3.0
     * @var array
     * @access protected
     */
    protected $directoryData = array();


    /**
     * Class constructor
     *
     * This function is used to instantiate class. It accepts a directory name as initiation parameter
     * The dirname may either be a physical directory in the file system, or the original directory name.
     * In the latter case, the directory must have an equivalent database entry. In either case, the
     * parent directory where the directory resides should be specified along with the directory name.
     * The dirname may also be the directory id in the database, in which case there is no need to
     * specify the parent directory.
     * If the directory exists in the database, but not in the filesystem, then it is automatically
     * deleted and an EfrontFileException :: FILE_DELETED exception is thrown
     * <br/>Example:
     * <code>
     * $directory = new eF_Directory("/var/www/test.txt");                     //Using original directory name
     * $directory = new eF_Directory("/var/www/1234.txt.efront");              //Using physical directory name
     * $directory = new eF_Directory(4325);                                    //Using directory id
     * </code>
     *
     * @param string $dirname the directory name
     * @since 3.0
     * @access public
     */
    function __construct($dirname) {
        if (eF_checkParameter(trim($dirname, '/'), 'id')) {
            $result = eF_getTableData("files", "*", "type = 'directory' and id=".trim($dirname, '/'));
            if (sizeof($result) > 0 && is_dir($result[0]['file'])) {
                $dirname = $result[0]['file'];
                $this -> fullPath        = $dirname;
                $this -> directoryName   = basename($dirname).'/';
                $this -> parentDirectory = dirname($dirname).'/';
                $this -> directoryData   = $result[0];
                $this -> originalName    = $result[0]['original_name'];
            } else {
                throw new EfrontFileException(_DIRECTORYDOESNOTEXIST, EfrontFileException :: FILE_NOT_EXIST);
            }
        } else {
            $parentDirectory = EfrontFileSystem :: checkPath(dirname($dirname));                    //Check if the designated file lies within the root directory
            if (!$parentDirectory) {
                if (eF_checkParameter($dirname, 'path')) {                                      //Try to create an object, even if it is not in an existing path
                    $result = eF_getTableData("files", "*", "file='$dirname' and type = 'directory'");
                    if (sizeof($result) > 0) {
                        $this -> parentDirectory = $result[0]['directory'];
                        $this -> directoryName   = $result[0]['physical_name'];
                        $this -> originalName    = $result[0]['original_name'];
                        $this -> fullPath        = $this -> parentDirectory.$this -> directoryName;
                        $this -> directoryData   = $result[0];
                    } else {
                        throw new EfrontFileException(_DIRECTORYDOESNOTEXIST, EfrontFileException :: FILE_NOT_EXIST);
                    }
                } else {
                    throw new EfrontFileException(_ILLEGALPATH.': '.$dirname, EfrontFileException :: ILLEGAL_PATH);
                }
            } else {
                $dirname = $parentDirectory.basename($dirname).'/';

                $result = eF_getTableData("files", "*", "type = 'directory' and file='".$dirname."'");
                if (sizeof($result) > 0) {
                    $this -> fullPath        = $dirname;
                    $this -> directoryName   = basename($dirname).'/';
                    $this -> parentDirectory = dirname($dirname).'/';
                    $this -> directoryData   = $result[0];
                    $this -> originalName    = $result[0]['original_name'];
                } else {                            //A file with the specified filename was not found in the filesystem. Check if the original file name was specified
                    $this -> originalName  = basename($dirname).'/';
                    $result = eF_getTableData("files", "*", "type = 'directory' and original_name='".basename($dirname).'/'."' and directory = '".$parentDirectory."'");
                    if (sizeof($result) > 0) {
                        $this -> parentDirectory = $result[0]['directory'];
                        $this -> directoryName   = $result[0]['physical_name'];
                        $this -> originalName    = $result[0]['original_name'];
                        $this -> fullPath        = $this -> parentDirectory.$this -> directoryName;
                        $this -> directoryData   = $result[0];
                    } else {                                                            //The file does not exist, either as physical or as original name
                        if (is_dir($dirname)) {
                            $this -> fullPath        = $dirname;
                            $this -> directoryName   = basename($dirname).'/';
                            $this -> parentDirectory = dirname($dirname).'/';
                        } else {
                            throw new EfrontFileException(_DIRECTORYDOESNOTEXIST.': '.$dirname, EfrontFileException :: FILE_NOT_EXIST);
                        }
                    }
                }
            }
        }

        if (!is_dir($this -> fullPath)) {
            $this -> delete();
            throw new EfrontFileException(_DIRECTORYDOESNOTEXIST, EfrontFileException :: FILE_DELETED);
        }
    }

    /**
     * Get directory full path and name
     *
     * This function returns the full physical directory path, including name
     * <br/>Example:
     * <code>
     * echo $directory -> getFullPath();     //displays something like "/var/www/321/"
     * </code>
     *
     * @return string The full physical path, including name, of the directory
     * @since 3.0
     * @access public
     */
    public function getFullPath() {
        return $this -> fullPath;
    }

    /**
     * Get directory physical name
     *
     * This function returns the physical directory name
     * <br/>Example:
     * <code>
     * echo $directory -> getPhysicalName();     //displays something like "321"
     * </code>
     *
     * @return string The physical directory name
     * @since 3.0
     * @access public
     */
    public function getPhysicalName() {
        return $this -> directoryName;
    }

    /**
     * Get directory original name
     *
     * This function returns the original directory name
     * <br/>Example:
     * <code>
     * echo $directory -> getOriginalName();     //displays something like "test"
     * </code>
     *
     * @return string The original directory name
     * @since 3.0
     * @access public
     */
    public function getOriginalName() {
        return $this -> originalName;
    }

    /**
     * Get directory parent path
     *
     * This function returns the path to the parent directory
     * <br/>Example:
     * <code>
     * echo $directory -> getDirectory();     //displays something like "/var/www/"
     * </code>
     *
     * @return string The directory directory
     * @since 3.0
     * @access public
     */
    public function getDirectory() {
        return $this -> parentDirectory;
    }

    /**
     * Get directory information
     *
     * This function returns information about the directory
     * <br/>Example:
     * <code>
     * $info = $directory -> getInfo();
     * //Returns:
     * Array (
     *   [full_path] => /var/www/321/
     *   [physical_name] => 321
     *   [original_name] => mydir
     *   [directory] => /var/www/
     * )
     * </code>
     *
     * @return array An array with directory information
     * @since 3.0
     * @access public
     */
    public function getInfo() {
        $info = array("full_path"     => $this -> getFullPath(),
                      "physical_name" => $this -> getPhysicalName(),
                      "original_name" => $this -> getOriginalName(),
                      "directory"     => $this -> getDirectory(),
                      "type"          => 'directory',
                      "id"            => $this -> directoryData['id'],
                      "timestamp"     => $this -> directoryData['timestamp']);
        return $info;
    }

    /**
     * Get directory id
     *
     * This function returns the directory id in the database
     * <br/>Example:
     * <code>
     * echo $directory -> getDirectoryId();     //displays something like "322"
     * </code>
     *
     * @return int The directory id
     * @since 3.0
     * @access public
     */
    public function getDirectoryId() {
        return $this -> directoryData['id'];
    }

    /**
     * Get directory contents in FileSystem
     *
     * This function is used to retrieve all (physical) files and directories
     * of the directory. The result set may be optionally customized depending
     * on the specified parameters
     *
     * @param array $filterIn An array of extensions that specifies which file types to return
     * @param boolean $recurseInto Whether to recurse into subfolders
     * @return array The files list
     * @since 3.0
     * @access public
     */
    public function getContentsFS($filterIn = false, $recurseInto = true)
    {
        $directories = array($this -> fullPath);                                //The current directory is the first element in the $directories entry
        $filelist    = array();                                                 //The array that will hold the files
        for ($i = 0; isset($directories[$i]) && $i < 1000; $i++) {              //While there are directories, get their content. $i is put here to prevent infinite loops
            $dirfiles = scandir($directories[$i]);                              //Get all the contents of the directory
            $dirfiles = array_values(EfrontFileSystem :: filterFiles($dirfiles, $filterIn));       //Filter contents
            foreach ($dirfiles as &$file) {                                     //Loop through directory contents to harvest new directory entries. These will be put at the bottom of the $directories list, to be examined in consecutive loops
                $file = $directories[$i].$file;
                if (is_dir($file) && $recurseInto) {
                    $directories[] = $file.'/';
                }
            }
            unset($file);
            $filelist = array_merge($filelist, $dirfiles);                      //Augment $filelist array with new entries
        }
        return $filelist;
    }

    /**
     * Get directory contents based on DB information
     *
     * This function returns all directory contents, based on the database information
     * If a file does not have an equivalent physical representation, it will be removed from
     * the database.  The result set may be optionally customized depending
     * on the specified parameters
     *
     * @param boolean $recurseInto Whether to recurse into subfolders
     * @param boolean $fullInfo Whether the result set contains only paths/name pairs, or extra information
     * @param mixed $filterIn An array of extensions that specifies which file types to return. Alternatively, if $filterIn equals 'directory', only directories will be returned and if $filterIn equals 'file', only files will be returned
     * @param mixed $filterOut An array of extensions that specifies which file types will be excluded from results.
     * @return array The files list, in full path => original name pairs, or, if $fullInfo is set, as an array with extra fields for each entry
     * @since 3.0
     * @access public
     */
    public function getContents($recurseInto = false, $fullInfo = true, $filterIn = false, $filterOut = false) {
        if ($filterIn == 'directory' || $filterIn == 'file') {
            $allFiles = eF_getTableData("files", "file, original_name, directory, type", "type = '$filterIn'"); //Get all files in all directories
            $filterIn = false;
        } else {
            $allFiles = eF_getTableData("files", "file, original_name, directory, type");                     //Get all files in all directories
        }

        $filelist      = array();
        $directorylist = array();
        $dirFiles      = array();

        for ($i = 0; $i < sizeof($allFiles); $i++) {                                                        //Loop through all files
            if (!$recurseInto && trim($allFiles[$i]['directory'], '/') == trim($this -> fullPath, '/')) {                       //Get only files in the current directory
                $dirFiles[] = $allFiles[$i];
            } else if ($recurseInto && strpos($allFiles[$i]['directory'], $this -> fullPath) !== false) {   //Get only files below the current directory
                $dirFiles[] = $allFiles[$i];
            }
        }

        for ($i = 0; $i < sizeof($dirFiles); $i++) {                                                    //Loop through directory files
            if (!$fullInfo) {
                $filelist[$dirFiles[$i]['file']] = $dirFiles[$i]['original_name'];                      //Create the full path => original name pairs
            } else {                                                                                    //$fullInfo is set, so create objects
                try {
                    if ($dirFiles[$i]['type'] == 'file' && is_file($dirFiles[$i]['file'])) {                                                  //Create file object
                        $obj        = new eF_File($dirFiles[$i]['file']);
                        $filelist[] = $obj -> getInfo();                                                //Get the extra information
                    } else if ($dirFiles[$i]['type'] == 'directory' && is_dir($dirFiles[$i]['file'])) {
                        $obj             = new eF_Directory($dirFiles[$i]['file']);
                        $directorylist[] = $obj -> getInfo();
                    }
                } catch (EfrontFileException $e) {                                                     //The file/directory object was not created; some error occured
                    if ($e -> getCode() != EfrontFileException :: FILE_DELETED) {
                        throw ($e);
                    }
                }
            }
        }

        sizeof($directorylist) > 0 ? $filelist = array_merge($directorylist, $filelist) : null;

        if (sizeof($filterIn) > 0 || sizeof($filterOut) > 0) {
            $filelist = EfrontFileSystem :: filterFiles($filelist, $filterIn, $filterOut);
        }

        return ($filelist);
    }


    /**
     * Delete directory from Filesystem
     *
     * This function erases a directory with all its contents, including
     * subdirectories, from the filesystem. If, for some reason, a file/folder
     * was not deleted, its path is put in an array which is returned at the end
     *
     * @return array An array with paths of files/folders that could not be deleted
     * @since 3.0
     * @access public
     */
    public function deleteFS() {
        $notDeletedFiles = array();                         //The failed deletions array
        $contents        = $this -> getContentsFS();        //Get the physical contents of the directory
        foreach ($contents as $dirEntry) {
            if (is_dir($dirEntry)) {
                $directories[] = $dirEntry;                 //If the entry is a directory, keep it seprately
            } else {
                if (!unlink($dirEntry)) {
                    $notDeletedFiles[] = $dirEntry;         //If a file could not be deleted, put it in this array
                }
            }
        }

        //The directories are now emptied from files... we may delete them with rmdir
        $directories[] = $this -> fullPath;                 //Append the current directory to the directories list
        rsort($directories);                                //Sort in reverse order, so that subdirectories are deleted first

        foreach ($directories as $directory) {
            if (!rmdir($directory)) {
                $notDeletedFiles[] = $directory;            //If a directory could not be deleted, put it in this array
            }
        }

        return $notDeletedFiles;
    }

    /**
     * Delete directory
     *
     * This function deleted the current directory, both from the filesystem
     * and from the database.
     *
     * @return array An array with paths of files/folders that could not be deleted, as returned from deleteFS()
     * @since 3.0
     * @access public
     * @see deleteFS()
     */
    public function delete() {
        $allFiles = eF_getTableData("files", "*");                                      //Get all files (this way eliminating the need for consecutive db queries
        foreach ($allFiles as $file) {
            if (strpos($file['file'], $this -> getFullPath()) !== false) {              //Check if this file lies within the current directory
                if ($file['type'] == 'file') {
                    try {
                        $fileObj = new eF_File($file['file']);
                        $fileObj -> delete();
                    } catch (EfrontFileException $e) {
                        if ($e -> getCode() != EfrontFileException :: FILE_DELETED) {      //FILE_DELETED exception is issued when a database entry does not have a corresponding physical equivalent. Since the file/directory contructor deleted this file from the database, we don't have to do anything else
                            throw ($e);
                        }
                    }
                } else {
                    $directories[] = $file['file'];                                     //This is a directory, so append it to the directories list
                }
            }
        }

        $directories[] = $this -> fullPath;                                             //Put the current directory to the directories list
        foreach ($directories as $directory) {
            eF_deleteTableData("files", "file='$directory'");                           //Remove directories from the database
        }

        $notDeletedFiles = $this -> deleteFS();                                         //Finally, remove physical equivlent of directory
        return $notDeletedFiles;
    }

    /**
     * Copy physical directory in file system
     *
     * This function copies a directory to the designated dstination in the filesystem. It does not alter
     * its database representation. If $newName is specified, then the copied directory will be given
     * this name.
     *
     * @param string $destinationDirectory The target directory
     * @param string $newName The copied directory name
     * @param string $overwrite Whether to overwrite existing data
     * @return array An array with files / directories that could not be copied
     * @since 3.0
     * @access public
     */
    public function copyFS($destinationDirectory, $newName = false, $overwrite = false) {
        if ($destinationDirectory = EfrontFileSystem :: checkPath($destinationDirectory)) {                        //Check if directory is valid
            $newName ? $newName = EfrontFileSystem :: checkFile($newName) : $newName = $this -> directoryName;     //If $newName is specified, check if it is valid. Otherwise, use the same physical name as the copied directory's
            if (!$overwrite && (is_file($destinationDirectory.$newName) || is_dir($destinationDirectory.$newName))) {            //If an entity with the same name already exists and $overwrite is false, throw a DIRECTORY_ALREADY_EXISTS Exception
                throw new EfrontFileException(_CANNOTCOPYDIRECTORY.', '.$destinationDirectory.$newName.' : '._DIRECTORYALREADYEXISTS, EfrontFileException :: DIRECTORY_ALREADY_EXISTS);
            } else {
                $dirContents = $this -> getContentsFS();
                $directories = array($destinationDirectory.$newName);
                $files       = array();
                $failedFiles = array();
                foreach ($dirContents as $entry) {
                    if (is_dir($entry)) {
                        $directories[] = str_replace($this -> fullPath, $destinationDirectory.$newName, $entry);
                    } else {
                        $files[$entry] = str_replace($this -> fullPath, $destinationDirectory.$newName, $entry);
                    }
                }

                foreach ($directories as $directory) {
                    if (!mkdir($directory, 0755)) {
                        $failedFiles[] = $directory;
                    }
                }
                foreach ($files as $oldPath => $newPath) {
                    if (!copy($oldPath, $newPath)) {                                  //Copy the file
                        $failedFiles[] = $file;
                    }
                }

                return $failedFiles;
            }
        } else {
            throw new EfrontFileException(_ILLEGALPATH.': '.$destinationDirectory, EfrontFileException :: ILLEGAL_PATH);                     //the directory specified is invalid
        }
    }

    /**
     * Empty directory contents
     *
     * This function is used to clear all the directory contents
     * <br/>Example:
     * <code>
     * $directory = new eF_Directory(432);              //432 is the directory id
     * $directory -> emptyContents();                   //Now the directory contains nothing
     * </code>
     *
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function emptyContents() {
        $dirContents = $this -> getContents();
        foreach ($dirContents as $entry) {
            if ($entry['type'] == 'directory') {
                $dir = new eF_Directory($entry['id']);
                $dir -> delete();
            }
        }
        $dirContents = $this -> getContents();
        foreach ($dirContents as $entry) {
            if ($entry['type'] == 'file') {
                $dir = new eF_File($entry['id']);
                $dir -> delete();
            }
        }

        return true;
    }

    /**
     * Copy directory
     *
     * This function copies the directory to the designated directory. In order to do this, it first
     * creates an empty directory entry, using EfrontFileSystem :: makeDirectory(), then copies the directory to the new
     * directory and finally renames the copied directory using the new name from the empty directory
     * If a directory with the same original name already exists in the target directory, an exception will be issued.
     * <br/>Example:
     * <code>
     * $src  = new eF_Directory(5434);          //The source directory
     * $dest = new eF_Directory(432);           //The destination directory
     * $src -> copy($dest);                     //Copy src to dest
     * </code>
     *
     * @param mixed $destinationDirectory Either an eF_Directory object or the physical name and path of the directory to copy the file to
     * @return boolean True if the file was copied
     * @since 3.0
     * @access public
     */
    public function copy($destinationDirectory, $newName = false) {
        if ($destinationDirectory instanceof eF_Directory) {
            $destinationDirectory = $destinationDirectory -> getFullPath();
        } else if (!($destinationDirectory = EfrontFileSystem :: checkPath($destinationDirectory))) {  //Check if directory is valid
            throw new EfrontFileException(_ILLEGALPATH.': '.$destinationDirectory, EfrontFileException :: ILLEGAL_PATH);             //the directory specified is invalid
        }

        $newName ? $newName = EfrontFileSystem :: checkFile($newName) : $newName = $this -> originalName; //If $newName is specified, check if it is valid. Otherwise, use the same original name as the copied directory's
        try {
            $dir = new eF_Directory($destinationDirectory.$newName);                           //Check if a directory with the same *original* name already exists. If it does not, execution will jump to Catch block below
            throw new EfrontFileException(_CANNOTCOPYDIRECTORY.': '._DIRECTORYALREADYEXISTS, EfrontFileException :: DIRECTORY_ALREADY_EXISTS);//If we are here, it means the directory already exists.
        } catch (EfrontFileException $e) {                                                         //This means the directory does not exist
            $dirContents  = $this -> getContents();
            $newDirectory = EfrontFileSystem :: makeDirectory($newName, $destinationDirectory);
            foreach ($dirContents as $entry) {
                if ($entry['type'] == 'directory') {
                    $dir = new eF_Directory($entry['full_path']);
                    $dir -> copy($newDirectory);
                } else {
                    $file = new eF_File($entry['full_path']);
                    $file -> copy($newDirectory);
                }
            }
        }

    }

    /**
     * Move physical directory in file system
     *
     * This function moves a directory to the designated dstination in the filesystem. It does not alter
     * its database representation. If $newName is specified, then the moved directory will be given
     * this name.
     *
     * @param string $destinationDirectory The target directory
     * @param string $newName The moved directory name
     * @return array An array with files / directories that could not be moved
     * @since 3.0
     * @access public
     */
    public function moveFS($destinationDirectory, $newName = false) {
        $this -> copyFS($destinationDirectory, $newName);
        $this -> deleteFS();
    }

    /**
     * Move directory
     *
     * This function moves the directory to the designated directory. It does so
     * be first calling copy() method and then delete().
     *
     * @param mixed $destinationDirectory Either an eF_Directory object or the physical name and path of the directory to move the file to
     * @return boolean True if the file was moved
     * @since 3.0
     * @access public
     * @see copy()
     */
    public function move ($destinationDirectory, $newName = false) {
        $this -> copy($destinationDirectory, $newName);
        $this -> delete();
    }

    /**
     * Rename physical directory in file system
     *
     * This function renames a directory in the filesystem. It does not alter its database
     * representation.
     *
     * @param string $newName The new physical directory name
     * @return boolean True if the directory was renamed
     * @since 3.0
     * @access public
     */
    public function renameFS($newName) {
        $newName = EfrontFileSystem :: checkFile(trim($newName, "/"));    //Check if the new name specified is valid
        if (is_dir($this -> parentDirectory.$newName) || is_file($this -> parentDirectory.$newName)) {                     //If this directory already exists
            throw new EfrontFileException(_CANNOTRENAMEDIRECTORY, EfrontFileException :: FILE_ALREADY_EXISTS);
        }
        if (rename($this -> fullPath, $this -> parentDirectory.$newName)) {       //Rename directory
            return true;
        } else {
            throw new EfrontFileException(_CANNOTRENAMEDIRECTORY, EfrontFileException :: GENERAL_ERROR);
        }
    }

    /**
     * Rename directory
     *
     * This function renames the directory. It does so by changing its original
     * directory name that is stored in the database. It does not alter its physical
     * name in the filesystem
     *
     * @param string $newName The new physical directory name
     * @return boolean True if the directory was renamed
     * @since 3.0
     * @access public
     */
    public function rename($newName) {
        $newName = EfrontFileSystem :: checkFile(trim($newName, "/"));                //Check if the new name specified is valid
        $this -> originalName = $newName.'/';                  //Update file information
        $this -> persist();                                             //Store updated file information
        return true;
    }

    /**
     * Compress Directory
     *
     * This function is used to create a compressed version of the directory
     * using the designated method. Defaults to 'zip'
     *
     * @param string $method The compression method to use. Can be one of 'zip', 'tar.gz'
     * @return eF_Directory the compressed version of the directory
     * @since 3.0
     * @access public
     */
    public function compress($method = 'tar.gz') {
        switch ($method) {
            case 'gz': case 'tar.gz':
                //require_once("Archive/Tar.php");
                $tarOriginalName = basename($this -> getOriginalName()).'.tar.gz';
                $tarPhysicalName = EfrontFileSystem :: createFile($tarOriginalName, $this -> getDirectory());
                $tar             = new Archive_Tar($this -> getDirectory().$tarPhysicalName, 'gz');

                $tar -> createModify($this -> getContentsFS(), $this -> getOriginalName(), $this -> getFullPath());

                return new eF_CompressedFile($this -> getDirectory().$tarPhysicalName);
                break;
            case 'zip': default:
                break;
        }
    }

    /**
     * Persist changed directory properties
     *
     * During directory operations, internal directory attributes, such as name, physical name,
     * parent directory etc may be changed. Using this function, these values are stored in
     * the database.
     *
     * @return true if everything is ok.
     * @since 3.0
     * @access protected
     */
    protected function persist() {
        $fields = array("file"          => $this -> fullPath,
                        "physical_name" => $this -> physicaName,
                        "original_name" => $this -> originalName,
                        "directory"     => $this -> parentDirectory,
                        "description"   => $this -> directoryData['description']);

        eF_updateTableData("files", $fields, "id=".$this -> directoryData['id']);
        return true;
    }

    /**
     * Set directory description
     *
     * This function is used to set the directory description
     * <br/>Example:
     * <code>
     * $file = new eF_Directory(43);
     * $file -> setDescription('the directory description');
     * </code>
     *
     * @param string $description The directory description
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function setDescription($description) {
        $this -> directoryData['description'] = $description;
        $this -> persist();
    }
}




/**
 * eF_miniFM class
 *
 * This class is used to create and display a mini File manager
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class eF_MiniFM
{
    /**
     * The root directory of the file manager
     *
     * @since 3.0
     * @var object
     * @access protected
     */
    protected $rootDir;

    /**
     * The current directory of the file manager
     *
     * @since 3.0
     * @var object
     * @access protected
     */
    protected $currentDir;

    /**
     * The root directory's contents
     *
     * @since 3.0
     * @var array
     * @access protected
     */
    protected $dirContents = array();

    /**
     * The upload form object
     *
     * @since 3.0
     * @var object
     * @access protected
     */
    protected $uploadForm;

    /**
     * The create directory form object
     *
     * @since 3.0
     * @var object
     * @access protected
     */
    protected $createDirectoryForm;


    /**
     * The default URI for the file manager
     *
     * @since 3.0
     * @var string
     * @access protected
     */
    protected $defaultUri = '';

    public $parentId = '';

    /**
     *
     */
    function __construct($rootDir) {
        if ($rootDir instanceof eF_Directory) {
            $this -> rootDir = $rootDir;
        } else if (is_dir($rootDir)) {
            $this -> rootDir = new eF_Directory($rootDir);
        } else {
            throw new EfrontFileException(_THEDIRECTORYDOESNOTEXIST.': '.$rootDir, EfrontFileException :: DIRECTORY_NOT_EXIST);
        }

        if (isset($_GET['dir'])) {
            $subdir = new eF_Directory($_GET['dir']);
            if (strpos($subdir -> getDirectory(), $rootDir -> getFullPath()) != 0) {
                throw new EfrontFileException(_ILLEGALPATH.': '.$subdir -> getOriginalName(), EfrontFileException :: ILLEGAL_PATH);
            } else {
                $this -> currentDir = $subdir;
                if ($subdir -> getDirectory() != $rootDir -> getFullPath()) {
                    $parentDir = new eF_Directory($subdir -> getDirectory());
                    $this -> parentId = $parentDir -> getDirectoryId();
                }
            }
        } else {
            $this -> currentDir = $this -> rootDir;
        }

        foreach ($this -> currentDir -> getContents() as $value) {
            $this -> dirContents[$value['id']] = $value;
        }
        //$this -> dirContents = $this -> currentDir -> getContents();
    }

    /**
     *
     */
    function setDefaultURI($uri) {
        $uri ? $this -> defaultUri = $uri.'&' : $this -> defaultUri = $uri.'?';
    }

    /**
     *
     */
    public function getUploadForm() {
        isset($_GET['dir']) ? $postTarget = $this -> defaultUri.'dir='.$_GET['dir'] : $postTarget = $this -> defaultUri;

        $this -> uploadForm = new HTML_QuickForm("upload_file_form", "post", $postTarget, "", null, true);
        $this -> uploadForm -> registerRule('checkParameter', 'callback', 'eF_checkParameter');                   //Register this rule for checking user input with our function, eF_checkParameter
        $this -> uploadForm -> addElement('file', 'file_upload', null, 'class = "inputText"');
        $this -> uploadForm -> addElement('submit', 'submit_upload_file', _UPLOAD, 'class = "flatButton"');
        $this -> uploadForm -> setMaxFileSize(EfrontFileSystem :: getUploadMaxSize() * 1024);

        if ($this -> uploadForm -> isSubmitted() && $this -> uploadForm -> validate()) {
            $uploadedFile = EfrontFileSystem :: uploadFile('file_upload', $this -> currentDir -> getFullPath());
            header("location:$postTarget&message=".urlencode(_FILEUPLOADEDSUCCESSFULLY)."&message_type=success");
        }

        return $this -> uploadForm;
    }

    /**
     *
     */
    public function getCreateDirectoryForm($postTarget = '', $refreshTarget = '') {
        isset($_GET['dir']) ? $postTarget = $this -> defaultUri.'dir='.$_GET['dir'] : $postTarget = $this -> defaultUri;

        $this -> createDirectoryForm = new HTML_QuickForm("create_directory_form", "post", $postTarget, "", null, true);
        $this -> createDirectoryForm -> registerRule('checkParameter', 'callback', 'eF_checkParameter');                   //Register this rule for checking user input with our function, eF_checkParameter
        $this -> createDirectoryForm -> addElement('text', 'directory_name', null, 'class = "inputText"');
        $this -> createDirectoryForm -> addRule('directory_name', _THEFIELD.' '._NAME.' '._ISMANDATORY, 'required', null, 'client');
        $this -> createDirectoryForm -> addRule('directory_name', _INVALIDFIELDDATA, 'checkParameter', 'filename');
        $this -> createDirectoryForm -> addElement('submit', 'submit_create_directory', _CREATE, 'class = "flatButton"');

        if ($this -> createDirectoryForm -> isSubmitted() && $this -> createDirectoryForm -> validate()) {
            try {
                $newDirectory = EfrontFileSystem :: makeDirectory($this -> createDirectoryForm -> exportValue('directory_name'), $this -> currentDir -> getFullPath());
                header("location:".$_SERVER['PHP_SELF'].$postTarget."&message=".urlencode(_SUCCESFULLYCREATEDFOLDER)."&message_type=success");
            } catch (Exception $e) {
                $message      = $e -> getMessage();
                $message_type = 'failure';
            }
        }

        return $this -> createDirectoryForm;
    }

    /**
     * Return directory contents
     */
    public function getFiles() {
        return $this -> dirContents;
    }

}

/**BETA don't use!!!*/
class EfrontFileManager
{
    /**
     * The root directory where the file manager exposes files from
     *
     * @var string
     * @since 3.5.0
     * @access public
     */
    public $rootDirectory = G_ROOTPATH;

    /**
     * The default URI for the file manager. This is a string that will be prepended
     * to all file manager links
     *
     * @var string
     * @since 3.5.0
     * @access public
     */
    public $defaultUri = '';

    /**
     * The current directory that the file manager is at
     *
     * @var string
     * @since 3.5.0
     * @access public
     */
    public $currentDirectory = '';

    /**
     * The directory's contents, as returned by eF_Directory :: getContents()
     *
     * @var array
     * @since 3.5.0
     * @access public
     * @see eF_Directory :: getContents()
     */
    public $dirContents = array();

    /**
     * Class Constructor
     *
     * This function initializes the file manager,
     * using the designated root directory. The root directory can not be outside
     * eFront's root directory, defined by the G_ROOTPATH constant.
     * <br/>Example:
     * <code>
     * $fileManager = new EfrontFileManager('/var/www/efront/');        //Instantiate file manager using a directory path
     * $directory   = new eF_Directory('/var/www/efront/');
     * $fileManager = new EfrontFileManager($directory);                //Instantiate file manager using an eF_Directory instance
     * $fileManager = new EfrontFileManager('/var/');                   //This will throw an exception
     * </code>
     *
     * @param mixed $rootDirectory The root directory of the file manager, either as a string or as an eF_Directory object
     * @since 3.5.0
     * @access public
     */
    function __construct($rootDirectory) {
        if ($rootDirectory instanceof eF_Directory) {
            $this -> rootDirectory = $rootDirectory;
        } else if (is_dir($rootDirectory)) {
            $this -> rootDirectory = new eF_Directory($rootDirectory);
        } else {
            throw new EfrontFileException(_THEDIRECTORYDOESNOTEXIST.': '.$rootDirectory, EfrontFileException :: DIRECTORY_NOT_EXIST);
        }

        $this -> setCurrectDirectory($rootDirectory);
    }

    /**
     * Set the current directory.
     *
     * If this is different than root directory, then we are
     * in a subdirectory, so an "up" link will be made available
     * <br/>Example:
     * <code>
     * $directory   = new eF_Directory('/var/www/efront/');
     * $fileManager = new EfrontFileManager($directory);                //Instantiate file manager using an eF_Directory instance
     * $currentDirectory = new eF_Directory('/var/www/efront/www/content/lessons/3');
     * $fileManager -> setCurrectDirectory($currentDirectory);
     * </code>
     *
     * @param mixed $directory The current directory, either as a string or as an eF_Directory object
     * @return array The directory contents;
     * @since 3.5.0
     * @access public
     */
    public function setCurrectDirectory($directory) {
        if ($directory instanceof eF_Directory) {
            $this -> currentDirectory = $directory;
        } else if (is_dir($directory)) {
            $this -> currentDirectory = new eF_Directory($directory);
        } else {
            throw new EfrontFileException(_THEDIRECTORYDOESNOTEXIST.': '.$directory, EfrontFileException :: DIRECTORY_NOT_EXIST);
        }

        return $this -> getContents();
    }

    /**
     * Get directory contents
     *
     * This function returns the list of files for the current directory
     * <br/>Example:
     * <code>
     * $directory   = new eF_Directory('/var/www/efront/');
     * $fileManager = new EfrontFileManager($directory);                //Instantiate file manager using an eF_Directory instance
     * $currentDirectory = new eF_Directory('/var/www/efront/www/content/lessons/3');
     * $fileManager -> setCurrectDirectory($currentDirectory);
     * $files = $fileManager -> getContents();
     * </code>
     *
     * @return array the list of files in the current directory
     * @since 3.5.0
     * @access public
     */
    public function getContents() {
        if (sizeof($this -> dirContents) == 0) {
            foreach ($this -> currentDirectory -> getContents() as $value) {        //Assign file ids as keys
                $this -> dirContents[$value['id']] = $value;
            }

            foreach ($this -> dirContents as &$dirFile) {
                if (is_file(G_IMAGESPATH.'file_types/'.$dirFile['extension'].'.png')) {
                    $dirFile['image'] = $dirFile['extension'].'.png';
                } else {
                    $dirFile['image'] = 'unknown.png';
                }
            }
            unset($dirFile);
        }

        return $this -> dirContents;
    }

    /**
     * Get upload form
     *
     * This function is used to get the upload form for the
     * file manager.
     * <br/>Example:
     * <code>
     * $directory    = new eF_Directory('/var/www/efront/');
     * $fileManager  = new EfrontFileManager($directory);               //Instantiate file manager using an eF_Directory instance
     * $uploadedForm = $fileManager -> getUploadForm();
     * </code>
     *
     * @return HTML_Quickform The upload form
     * @since 3.5.0
     * @access public
     */
    public function getUploadForm() {
        $uploadForm  = new HTML_QuickForm("upload_file_form", "post", null, null, null, true);
        $uploadForm -> registerRule('checkParameter', 'callback', 'eF_checkParameter');                   //Register this rule for checking user input with our function, eF_checkParameter
        $uploadForm -> addElement('file', 'file_upload', null, 'class = "inputText"');
        $uploadForm -> addElement('submit', 'submit_upload_file', _UPLOAD, 'class = "flatButton"');

        if ($uploadForm -> isSubmitted() && $uploadForm -> validate()) {
            try {
                $uploadedFile = EfrontFileSystem :: uploadFile('file_upload', $this -> currentDirectory -> getFullPath());
            } catch (Exception $e) {
                $message      = $e -> getMessage();
                $message_type = 'failure';
            }
        }

        return $uploadForm;
    }

    /**
     * Get create directory form
     *
     * Thsi function builds the form that is used to create a new directory
     * at the file manager
     * <br/>Example:
     * <code>
     * $directory    = new eF_Directory('/var/www/efront/');
     * $fileManager  = new EfrontFileManager($directory);               //Instantiate file manager using an eF_Directory instance
     * $$createDirectoryForm = $fileManager -> getCreateDirectoryForm();
     * </code>
     *
     * @return HTML_QuickForm The create directory form
     * @since 3.5.0
     * @access public
     */
    public function getCreateDirectoryForm() {
        $createDirectoryForm  = new HTML_QuickForm("create_directory_form", "post", null, null, null, true);
        $createDirectoryForm -> registerRule('checkParameter', 'callback', 'eF_checkParameter');                   //Register this rule for checking user input with our function, eF_checkParameter
        $createDirectoryForm -> addElement('text', 'directory_name', null, 'class = "inputText"');
        $createDirectoryForm -> addRule('directory_name', _THEFIELD.' '._NAME.' '._ISMANDATORY, 'required', null, 'client');
        $createDirectoryForm -> addRule('directory_name', _INVALIDFIELDDATA, 'checkParameter', 'filename');
        $createDirectoryForm -> addElement('submit', 'submit_create_directory', _CREATE, 'class = "flatButton"');

        if ($createDirectoryForm -> isSubmitted() && $createDirectoryForm -> validate()) {
            try {
                $newDirectory = EfrontFileSystem :: makeDirectory($createDirectoryForm -> exportValue('directory_name'), $this -> currentDirectory -> getFullPath());
            } catch (Exception $e) {
                $message      = $e -> getMessage();
                $message_type = 'failure';
            }
        }

        return $createDirectoryForm;
    }

    /**
     *
     */
    public function toHTML() {
        $count = 0;
        $files = $this -> getContents();
        $str = '
            <table style = "width:100%" class = "sortedTable">
                <tr class = "defaultRowHeight">
                    <td class = "topTitle">'._TYPE.'</td>
                    <td class = "topTitle">'._FILENAME.'</td>
                    <td class = "topTitle">'._SIZE.'</td>
                    <td class = "topTitle">'._LASTMODIFIED.'</td>
                    <td class = "topTitle centerAlign noSort">'._FUNCTIONS.'</td>
                    <td class = "topTitle centerAlign">'._SELECT.'</td>
                </td></tr>';
        foreach ($files as $id => $file) {
            if ($file['type'] == 'directory') {
                $str .= '
                    <tr class = "'.($count++ % 2 ? 'oddRowColor' : 'evenRowColor').'">
                        <td><img src = "images/16x16/folder.png" alt = "'._FOLDER.'" title = "'._FOLDER.'"/></td>
                        <td><a href = "">'.$file['original_name'].'</a></td>
                        <td></td>
                        <td>#filter:timestamp_time-'.$file['timestamp'].'#</td>
                        <td style = "text-align:center;white-space:nowrap">
                            <a href = ""><img src = "images/16x16/import1.png" title = "'._COMPRESSDOWNLOAD.'" alt = "'._COMPRESSDOWNLOAD.'" border = "0"/></a>
                            <a href = ""><img src = "images/16x16/copy.png" title = "'._COPY.'" alt = "'._COPY.'" border = "0"/></a>
                            <a href = ""><img src = "images/16x16/edit.png" title = "'._EDIT.'" alt = "'._EDIT.'" border = "0"/></a>
                            <a href = "" onclick = "return confirm(\''._IRREVERSIBLEACTIONAREYOUSURE.'\')"><img src = "images/16x16/delete.png" title = "'._DELETE.'" alt = "'._DELETE.'" border = "0"/></a>
                        </td>
                        <td></td>
                    </tr>';
            } else {
                $str .= '
                    <tr class = "'.($count++ % 2 ? 'oddRowColor' : 'evenRowColor').'">
                        <td><img src = "images/file_types/'.$file['image'].'" alt = "'.$file['mime_type'].'" title = "'.$file['mime_type'].'"/><span style = "display:none">'.$file['extension'].'</span></td>
                        <td><a href = "view_file.php?file='.$file['id'].'" title = "'._PREVIEW.'" target = "PREVIEW_FRAME" onclick = "eF_js_showDivPopup(\''._PREVIEW.'\', 2, \'preview_table\');">'.$file['original_name'].'</a></td>
                        <td>'.$file['size'].' '._KB.'</td>
                        <td>#filter:timestamp_time-'.$file['timestamp'].'#</td>
                        <td style = "text-align:center;white-space:nowrap">
                            <a href = ""><img src = "images/16x16/import2.png" title = "'._DOWNLOADFILE.'" alt = "'._DOWNLOADFILE.'" border = "0"/></a>
                            <a href = ""><img src = "images/16x16/copy.png" title = "'._COPY.'" alt = "'._COPY.'" border = "0"/></a>
                            <a href = ""><img src = "images/16x16/edit.png" title = "'._EDIT.'" alt = "'._EDIT.'" border = "0"/></a>
                            <a href = "" onclick = "return confirm(\''._IRREVERSIBLEACTIONAREYOUSURE.'\')"><img src = "images/16x16/delete.png" title = "'._DELETE.'" alt = "'._DELETE.'" border = "0"/></a>
                        </td>
                        <td class = "centerAlign"><input type = "checkbox" name = "files['.$file['id'].']" class = "inputCheckbox" /></td>
                    </tr>';
            }
        }
        $str .= '
            </table>';


/*
        $str .= '
            <div id = "edit_table" style = "display:none;">
                    '.$uploadFormArray['javascript'].'
                    <form '.$uploadFormArray['attributes'].'>
                        '.$uploadFormArray['hidden'].'
                        <table style = "margin: 2em 2em 2em 2em" class = "formElements">
                            <tr><td class = "labelCell">'._NAME.':&nbsp;</td>
                                <td>'.$uploadFormArray['name']['html'].'</td></tr>
                            '.($uploadFormArray['name']['error'] ? '<tr><td></td><td class = "formError">'.$uploadFormArray['name']['error'].'</td></tr>' : '').'
                            <tr><td></td><td>&nbsp;</td></tr>
                            <tr><td></td><td class = "submitCell">'.$uploadFormArray['submit_edit']['html'].'</td></tr>
                        </table>
                    </form>
                </div>';

        $renderer                =& new HTML_QuickForm_Renderer_ArraySmarty($foo);                //Get a smarty renderer, only because it reforms the form in a very convenient way for printing html
        $uploadForm               = $this -> getUploadForm();
        $uploadForm               -> accept($renderer);
        $uploadFormArray          = $renderer -> toArray();

        //$createDirectoryForm      = $this -> getCreateDirectoryForm();
        //$renderer                -> accept($createDirectoryForm);
        //$createDirectoryFormArray = $renderer -> toArray();

        $str .= '
            <div id = "upload_table" style = "display:none;">
                <form '.$uploadFormArray['attributes'].'>
                <table>
                    <tr><td class = "labelCell>'._FILE.'</td>
                        <td class = "elementCell">'.$uploadFormArray['file_upload']['html'].'</td></tr>
                    <tr><td class = "labelCell>'._FILE.'</td>
                        <td class = "elementCell">'.$uploadFormArray['submit_upload_file']['html'].'</td></tr>
                    </table>
                </form>
            </div>';
*/
        return $str;
    }




}












?>