Source for file VFS.php
Documentation is available at VFS.php
define('VFS_QUOTA_METRIC_BYTE', 1 );
define('VFS_QUOTA_METRIC_KB', 2 );
define('VFS_QUOTA_METRIC_MB', 3 );
define('VFS_QUOTA_METRIC_GB', 4 );
* VFS API for abstracted file storage and access.
* $Horde: framework/VFS/lib/VFS.php,v 1.1.2.8 2009/01/06 15:23:46 jan Exp $
* Copyright 2002-2009 The Horde Project (http://www.horde.org/)
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
* @author Chuck Hagenbuch <chuck@horde.org>
* Hash containing connection parameters.
* List of additional credentials required for this VFS backend (example:
* For FTP, we need a username and password to log in to the server with).
var $_credentials = array ();
* List of permissions and if they can be changed in this VFS backend.
var $_permissions = array (
'owner' => array ('read' => false , 'write' => false , 'execute' => false ),
'group' => array ('read' => false , 'write' => false , 'execute' => false ),
'all' => array ('read' => false , 'write' => false , 'execute' => false ));
* A PEAR Log object. If present, will be used to log errors and
* informational messages about VFS activity.
* The log level to use - messages with a higher log level than configured
* here will not be logged. Defaults to only logging errors or higher.
var $_logLevel = PEAR_LOG_ERR;
* The current size, in bytes, of the VFS item.
* @param array $params A hash containing connection parameters.
function VFS($params = array ())
if (empty ($params['user'])) {
if (empty ($params['vfs_quotalimit'])) {
$params['vfs_quotalimit'] = -1;
if (empty ($params['vfs_quotaroot'])) {
$params['vfs_quotaroot'] = '/';
$this->_params = $params;
* Checks the credentials that we have by calling _connect(), to see if
* there is a valid login.
* @return mixed True on success, PEAR_Error describing the problem if the
* credentials are invalid.
return $this->_connect ();
* Sets configuration parameters.
* @param array $params An associative array with parameter names as keys.
foreach ($params as $name => $value) {
$this->_params[$name] = $value;
* Returns configuration parameters.
* @param string $name The parameter to return.
* @return mixed The parameter value or null if it doesn't exist.
return isset ($this->_params[$name]) ? $this->_params[$name] : null;
* Logs a message if a PEAR Log object is available, and the message's
* priority is lower than or equal to the configured log level.
* @param mixed $message The message to be logged.
* @param integer $priority The message's priority.
function log($message, $priority = PEAR_LOG_ERR )
if (!isset ($this->_logger) || $priority > $this->_logLevel) {
if (is_a($message, 'PEAR_Error')) {
$userinfo = $message->getUserInfo ();
$message = $message->getMessage ();
$userinfo = implode(', ', $userinfo);
$message .= ': ' . $userinfo;
/* Make sure to log in the system's locale. */
$this->_logger->log ($message, $priority);
/* Restore original locale. */
* Sets the PEAR Log object used to log informational or error messages.
* @param Log &$logger The Log object to use.
function setLogger(&$logger, $logLevel = null )
$this->_logger = &$logger;
$this->_logLevel = $logLevel;
* Retrieves the size of a file from the VFS.
* @param string $path The pathname to the file.
* @param string $name The filename to retrieve.
* @return integer The file size.
function size($path, $name)
return PEAR ::raiseError (_("Not supported."));
* Returns the size of a folder
* @param string $path The path to the folder.
* @param string $name The name of the folder.
* @return integer The size of the folder, in bytes, or PEAR_Error on
$root = ((!is_null($path)) ? $path . '/' : '') . $name;
$object_list = $this->listFolder($root, null , true , false , true );
foreach ($object_list as $key => $val) {
if (isset ($val['subdirs'])) {
$filesize = $this->size($root, $key);
if (is_a($filesize, 'PEAR_Error')) {
* Retrieves a file from the VFS.
* @param string $path The pathname to the file.
* @param string $name The filename to retrieve.
* @return string The file data.
function read($path, $name)
return PEAR ::raiseError (_("Not supported."));
* Retrieves a file from the VFS as an on-disk local file.
* This function provides a file on local disk with the data of a VFS file
* in it. This file <em>cannot</em> be modified! The behavior if you do
* modify it is undefined. It will be removed at the end of the request.
* @param string $path The pathname to the file.
* @param string $name The filename to retrieve.
* @return string A local filename.
// Create a temporary file and register it for deletion at the
return PEAR ::raiseError (_("Unable to create temporary file."));
// Use a stream from the VFS if possible, to avoid reading all data
$stream = $this->readStream ($path, $name);
if (is_a($stream, 'PEAR_Error')) {
$localStream = fopen($localFile, 'w');
return PEAR ::raiseError (_("Unable to open temporary file."));
// If we have stream_copy_to_stream, it can do the data transfer
// Otherwise loop through in chunks.
while ($buffer = fread($stream, 8192 )) {
fwrite($localStream, $buffer);
// We have to read all of the data in one shot.
$data = $this->read($path, $name);
if (is_a($data, 'PEAR_Error')) {
// file_put_contents is more efficient if we have it.
// Open the local file and write to it.
$localStream = fopen($localFile, 'w');
return PEAR ::raiseError (_("Unable to open temporary file."));
if (!fwrite($localStream, $data)) {
return PEAR ::raiseError (_("Unable to write temporary file."));
// $localFile now has $path/$name's data in it.
* Retrieves a part of a file from the VFS. Particularly useful when
* reading large files which would exceed the PHP memory limits if they
* were stored in a string.
* @param string $path The pathname to the file.
* @param string $name The filename to retrieve.
* @param integer $offset The offset of the part. (The new offset will
* @param integer $length The length of the part. If the length = -1,
* the whole part after the offset is retrieved.
* If more bytes are given as exists after the
* given offset. Only the available bytes are
* @param integer $remaining The bytes that are left, after the part that
* @return string The file data.
function readByteRange($path, $name, &$offset, $length = -1 , &$remaining)
return PEAR ::raiseError (_("Not supported."));
* Stores a file in the VFS.
* @param string $path The path to store the file in.
* @param string $name The filename to use.
* @param string $tmpFile The temporary file containing the data to
* @param boolean $autocreate Automatically create directories?
* @return mixed True on success or a PEAR_Error object on failure.
function write($path, $name, $tmpFile, $autocreate = false )
return PEAR ::raiseError (_("Not supported."));
* Stores a file in the VFS from raw data.
* @param string $path The path to store the file in.
* @param string $name The filename to use.
* @param string $data The file data.
* @param boolean $autocreate Automatically create directories?
* @return mixed True on success or a PEAR_Error object on failure.
function writeData($path, $name, $data, $autocreate = false )
return PEAR ::raiseError (_("Not supported."));
* Moves a file through the backend.
* @param string $path The path of the original file.
* @param string $name The name of the original file.
* @param string $dest The destination file name.
* @param boolean $autocreate Automatically create directories?
* @return mixed True on success or a PEAR_Error object on failure.
function move($path, $name, $dest, $autocreate = false )
if (is_a($result = $this->copy($path, $name, $dest, $autocreate), 'PEAR_Error')) {
* Copies a file through the backend.
* @param string $path The path of the original file.
* @param string $name The name of the original file.
* @param string $dest The name of the destination directory.
* @param boolean $autocreate Automatically create directories?
* @return mixed True on success or a PEAR_Error object on failure.
function copy($path, $name, $dest, $autocreate = false )
return PEAR ::raiseError (_("Cannot copy file(s) - source and destination are the same."));
if (is_a($result, 'PEAR_Error')) {
$data = $this->read($path, $name);
if (is_a($data, 'PEAR_Error')) {
return $this->writeData($dest, $name, $data, $autocreate);
* Recursively copies a directory through the backend.
* @param string $path The path of the original file.
* @param string $name The name of the original file.
* @param string $dest The name of the destination directory.
foreach ($file_list as $file) {
if (is_a($result, 'PEAR_Error')) {
* Deletes a file from the VFS.
* @param string $path The path to delete the file from.
* @param string $name The filename to delete.
* @return mixed True on success or a PEAR_Error object on failure.
return PEAR ::raiseError (_("Not supported."));
* Renames a file in the VFS.
* @param string $oldpath The old path to the file.
* @param string $oldname The old filename.
* @param string $newpath The new path of the file.
* @param string $newname The new filename.
* @return mixed True on success or a PEAR_Error object on failure.
function rename($oldpath, $oldname, $newpath, $newname)
return PEAR ::raiseError (_("Not supported."));
* Returns if a given file or folder exists in a folder.
* @param string $path The path to the folder.
* @param string $name The file or folder name.
* @return boolean True if it exists, false otherwise.
if (is_a($list, 'PEAR_Error')) {
return isset ($list[$name]);
* Creates a folder in the VFS.
* @param string $path The parent folder.
* @param string $name The name of the new folder.
* @return mixed True on success or a PEAR_Error object on failure.
return PEAR ::raiseError (_("Not supported."));
* Automatically creates any necessary parent directories in the specified
* @param string $path The VFS path to autocreate.
foreach ($dirs as $dir) {
if (is_a($result, 'PEAR_Error')) {
* Checks if a given item is a folder.
* @param string $path The parent folder.
* @param string $name The item name.
* @return boolean True if it is a folder, false otherwise.
$folderList = $this->listFolder($path, null , true , true );
return isset ($folderList[$name]);
* Deletes a folder from the VFS.
* @param string $path The parent folder.
* @param string $name The name of the folder to delete.
* @param boolean $recursive Force a recursive delete?
* @return mixed True on success or a PEAR_Error object on failure.
return PEAR ::raiseError (_("Not supported."));
* Recursively remove all files and subfolders from the given
* @param string $path The path of the folder to empty.
* @return mixed True on success or a PEAR_Error object on failure.
// Get and delete the subfolders.
$list = $this->listFolder($path, null , true , true );
if (is_a($list, 'PEAR_Error')) {
foreach ($list as $folder) {
$result = $this->deleteFolder($path, $folder['name'], true );
if (is_a($result, 'PEAR_Error')) {
// Only files are left, get and delete them.
if (is_a($list, 'PEAR_Error')) {
foreach ($list as $file) {
$result = $this->deleteFile($path, $file['name']);
if (is_a($result, 'PEAR_Error')) {
* Returns a file list of the directory passed in.
* @param string $path The path of the directory.
* @param mixed $filter String/hash to filter file/dirname on.
* @param boolean $dotfiles Show dotfiles?
* @param boolean $dironly Show only directories?
* @param boolean $recursive Return all directory levels recursively?
* @return array File list on success or PEAR_Error on failure.
function listFolder($path, $filter = null , $dotfiles = true ,
$dironly = false , $recursive = false )
$list = $this->_listFolder ($path, $filter, $dotfiles, $dironly);
if (!$recursive || is_a($list, 'PEAR_Error')) {
foreach ($list as $name => $values) {
if ($values['type'] == '**dir') {
$list[$name]['subdirs'] = $this->listFolder($path . '/' . $name, $filter, $dotfiles, $dironly, $recursive);
* Returns an an unsorted file list of the specified directory.
* @param string $path The path of the directory.
* @param mixed $filter String/hash to filter file/dirname on.
* @param boolean $dotfiles Show dotfiles?
* @param boolean $dironly Show only directories?
* @return array File list on success or PEAR_Error on failure.
function _listFolder ($path, $filter = null , $dotfiles = true ,
return PEAR ::raiseError (_("Not supported."));
* Returns the current working directory of the VFS backend.
* @return string The current working directory.
* Returns whether or not a filename matches any filter element.
* @param mixed $filter String/hash to build the regular expression
* @param string $filename String containing the filename to match.
* @return boolean True on match, false on no match.
function _filterMatch ($filter, $filename)
// Build a regexp based on $filter.
foreach ($filter as $item) {
$namefilter .= $item . ')';
$namefilter .= '(' . $filter . ')';
if ($namefilter !== null ) {
* Changes permissions for an item on the VFS.
* @param string $path The parent folder of the item.
* @param string $name The name of the item.
* @param string $permission The permission to set.
* @return mixed True on success or a PEAR_Error object on failure.
return PEAR ::raiseError (_("Not supported."));
* Returns a sorted list of folders in the specified directory.
* @param string $path The path of the directory to get the
* @param mixed $filter Hash of items to filter based on folderlist.
* @param boolean $dotfolders Include dotfolders?
* @return mixed Folder list on success or a PEAR_Error object on failure.
function listFolders($path = '', $filter = null , $dotfolders = true )
return PEAR ::raiseError (_("Not supported."));
* Returns the list of additional credentials required, if any.
* @return array Credential list.
* Returns an array specifying what permissions are changeable for this
* @return array Changeable permisions.
return $this->_permissions;
* Converts a string to all lowercase characters ignoring the current
* @param string $string The string to be lowercased
* @return string The string with lowercase characters
* Returns the character (not byte) length of a string.
* @param string $string The string to return the length of.
* @param string $charset The charset to use when calculating the
* @return string The string's length.
function strlen($string, $charset = null )
* Returns the size of the VFS item.
* @return integer The size, in bytes, of the VFS item.
$this->_vfsSize = $this->getFolderSize($this->_params['vfs_quotaroot']);
* Sets the VFS quota limit.
* @param integer $quota The limit to apply.
* @param integer $metric The metric to multiply the quota into.
function setQuota($quota, $metric = VFS_QUOTA_METRIC_BYTE )
$this->_params['vfs_quotalimit'] = $quota;
* Sets the VFS quota root.
* @param string $dir The root directory for the quota determination.
$this->_params['vfs_quotaroot'] = $dir;
* Get quota information (used/allocated), in bytes.
* @return mixed An associative array.
* 'limit' = Maximum quota allowed
* 'usage' = Currently used portion of quota (in bytes)
* Returns PEAR_Error on failure.
if (empty ($this->_params['vfs_quotalimit'])) {
return PEAR ::raiseError (_("No quota set."));
if (is_a($usage, 'PEAR_Error')) {
return array ('usage' => $usage, 'limit' => $this->_params['vfs_quotalimit']);
* Determines the location of the system temporary directory.
* @return string A directory name which can be used for temp files.
* Returns false if one could not be found.
$tmp_locations = array ('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
'c:\windows\temp', 'c:\winnt\temp');
/* Try PHP's upload_tmp_dir directive. */
/* Otherwise, try to determine the TMPDIR environment variable. */
/* If we still cannot determine a value, then cycle through a list of
* preset possibilities. */
/* If it is still empty, we have failed, so return false; otherwise
* return the directory determined. */
return strlen($tmp) ? $tmp : false;
* Creates a temporary file.
* @return string Returns the full path-name to the temporary file or
* false if a temporary file could not be created.
$tmp_file = tempnam($tmp_dir, 'vfs');
* Checks the quota when preparing to write data.
* @param string $mode Either 'string' or 'file'. If 'string', $data is
* the data to be written. If 'file', $data is the
* filename containing the data to be written.
* @param string $data Either the data or the filename to the data.
* @return mixed PEAR_Error on error, true on success.
function _checkQuotaWrite ($mode, $data)
if ($this->_params['vfs_quotalimit'] != -1 ) {
if ($filesize === false ) {
return PEAR ::raiseError (_("Unable to read VFS file (filesize() failed)."));
if (is_a($vfssize, 'PEAR_Error')) {
if (($vfssize + $filesize) > $this->_params['vfs_quotalimit']) {
return PEAR ::raiseError (_("Unable to write VFS file, quota will be exceeded."));
} elseif ($this->_vfsSize !== 0 ) {
$this->_vfsSize += $filesize;
* Checks the quota when preparing to delete data.
* @param string $path The path the file is located in.
* @param string $name The filename.
* @return mixed PEAR_Error on error, true on success.
function _checkQuotaDelete ($path, $name)
if (($this->_params['vfs_quotalimit'] != -1 ) &&
!empty ($this->_vfsSize)) {
$filesize = $this->size($path, $name);
if (is_a($filesize, 'PEAR_Error')) {
return PEAR ::raiseError (_("Unable to read VFS file (size() failed)."));
$this->_vfsSize -= $filesize;
* Returns the full path of an item.
* @param string $path The path of directory of the item.
* @param string $name The name of the item.
* @return mixed Full path when $path isset and just $name when not set.
if (substr($path, -1 ) == '/') {
return $path . '/' . $name;
* Attempts to return a concrete VFS instance based on $driver.
* @param mixed $driver The type of concrete VFS subclass to return. This
* is based on the storage driver ($driver). The
* code is dynamically included.
* @param array $params A hash containing any additional configuration or
* connection parameters a subclass might need.
* @return VFS The newly created concrete VFS instance, or a PEAR_Error
function &factory($driver, $params = array ())
$class = 'VFS_' . $driver;
include_once 'VFS/' . $driver . '.php';
$vfs = new $class($params);
$vfs = PEAR ::raiseError (sprintf(_("Class definition of %s not found."), $class));
* Attempts to return a reference to a concrete VFS instance based on
* $driver. It will only create a new instance if no VFS instance with the
* same parameters currently exists.
* This should be used if multiple types of file backends (and, thus,
* multiple VFS instances) are required.
* This method must be invoked as: $var = &VFS::singleton()
* @param mixed $driver The type of concrete VFS subclass to return. This
* is based on the storage driver ($driver). The
* code is dynamically included.
* @param array $params A hash containing any additional configuration or
* connection parameters a subclass might need.
* @return VFS The concrete VFS reference, or a PEAR_Error on failure.
function &singleton($driver, $params = array ())
static $instances = array ();
$signature = serialize (array ($driver, $params));
if (!isset ($instances[$signature])) {
$instances[$signature] = &VFS ::factory ($driver, $params);
return $instances[$signature];
Documentation generated on Mon, 11 Mar 2019 15:34:57 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|