Source for file sql_file.php
Documentation is available at sql_file.php
* File value for vfs_type column.
* Folder value for vfs_type column.
* VFS:: implementation using PHP's PEAR database abstraction
* layer and local file system for file storage.
* Required values for $params:<pre>
* 'phptype' The database type (ie. 'pgsql', 'mysql', etc.).
* 'vfsroot' The root directory of where the files should be
* 'table' The name of the vfs table in 'database'. Defaults to
* Required by some database implementations:<pre>
* 'hostspec' The hostname of the database server.
* 'protocol' The communication protocol ('tcp', 'unix', etc.).
* 'database' The name of the database.
* 'username' The username with which to connect to the database.
* 'password' The password associated with 'username'.
* 'options' Additional options to pass to the database.
* 'tty' The TTY on which to connect to the database.
* 'port' The port on which to connect to the database.</pre>
* The table structure for the VFS can be found in
* $Horde: framework/VFS/VFS/sql_file.php,v 1.68 2006/03/30 08:03:09 selsky Exp $
* @author Michael Varghese <mike.varghese@ascellatech.com>
* Handle for the current database connection.
* Retrieve 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)
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
$file = $this->_getNativePath ($path, $name);
$fp = @fopen($file, 'rb');
return PEAR ::raiseError (_("Unable to open VFS file."));
* Store a file in the VFS, with the data copied from a temporary
* @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 be
* @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 )
/* No need to check quota here as we will check it when we call
$dataFP = @fopen($tmpFile, 'rb');
return $this->writeData($path, $name, $data, $autocreate);
* Store 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 )
$res = $this->_checkQuotaWrite ('string', $data);
if (is_a($res, 'PEAR_Error')) {
$fp = @fopen($this->_getNativePath ($path, $name), 'w');
if (is_a($result, 'PEAR_Error')) {
$fp = @fopen($this->_getNativePath ($path, $name), 'w');
return PEAR ::raiseError (_("Unable to open VFS file for writing."));
return PEAR ::raiseError (_("Unable to open VFS file for writing."));
return PEAR ::raiseError (_("Unable to write VFS file data."));
if (is_a($this->_writeSQLData ($path, $name, $autocreate), 'PEAR_Error')) {
@unlink($this->_getNativePath ($path, $name));
return PEAR ::raiseError (_("Unable to write VFS file data."));
* Moves a file in the database and the file system.
* @param string $path The path to store the file in.
* @param string $name The old filename.
* @param string $dest The new filename.
* @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 )
$orig = $this->_getNativePath ($path, $name);
return PEAR ::raiseError (_("Cannot move file(s) - destination is within source."));
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
if (is_a($result, 'PEAR_Error')) {
$fileCheck = $this->listFolder($dest, null , false );
if (is_a($fileCheck, 'PEAR_Error')) {
foreach ($fileCheck as $file) {
if ($file['name'] == $name) {
return PEAR ::raiseError (_("Unable to move VFS file."));
if (strpos($dest, $this->_getSQLNativePath ($path, $name)) !== false ) {
return PEAR ::raiseError (_("Unable to move VFS file."));
return $this->rename($path, $name, $dest, $name);
* Copies a file through the backend.
* @param string $path The path to store the file in.
* @param string $name The filename to use.
* @param string $dest The destination of the file.
* @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 )
$orig = $this->_getNativePath ($path, $name);
return PEAR ::raiseError (_("Cannot copy file(s) - source and destination are the same."));
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
if (is_a($result, 'PEAR_Error')) {
$fileCheck = $this->listFolder($dest, null , false );
if (is_a($fileCheck, 'PEAR_Error')) {
foreach ($fileCheck as $file) {
if ($file['name'] == $name) {
return PEAR ::raiseError (_("Unable to copy VFS file."));
if (strpos($dest, $this->_getSQLNativePath ($path, $name)) !== false ) {
return PEAR ::raiseError (_("Unable to copy VFS file."));
return $this->_recursiveCopy ($path, $name, $dest);
if (!@copy($orig, $this->_getNativePath ($dest, $name))) {
return PEAR ::raiseError (_("Unable to copy VFS file."));
$id = $this->_db->nextId ($this->_params['table']);
$query = sprintf('INSERT INTO %s (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified, vfs_owner) VALUES (?, ?, ?, ?, ?, ?)',
$this->_params['table']);
$values = array ($id, VFS_FILE, $dest, $name, time(), $this->_params['user']);
$result = $this->_db->query ($query, $values);
if (is_a($result, 'PEAR_Error')) {
unlink($this->_getNativePath ($dest, $name));
* Creates a folder on the VFS.
* @param string $path Holds the path of directory to create folder.
* @param string $name Holds the name of the new folder.
* @return mixed True on success or a PEAR_Error object on failure.
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
$id = $this->_db->nextId ($this->_params['table']);
$result = $this->_db->query (sprintf('INSERT INTO %s (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified, vfs_owner)
VALUES (?, ?, ?, ?, ?, ?)',
$this->_params['table']),
array ($id, VFS_FOLDER, $path, $name, time(), $this->_params['user']));
if (is_a($result, 'PEAR_Error')) {
if (!@mkdir($this->_getNativePath ($path, $name))) {
$result = $this->_db->query (sprintf('DELETE FROM %s WHERE vfs_id = ?',
$this->_params['table']),
return PEAR ::raiseError (_("Unable to create VFS directory."));
* Rename a file or folder 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)
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
if (strpos($newpath, '/') === false ) {
list ($parent, $path) = explode('/', $newpath, 2 );
$result = $this->_db->query (sprintf('UPDATE %s SET vfs_path = ?, vfs_name = ?, vfs_modified = ?
WHERE vfs_path = ? AND vfs_name = ?',
$this->_params['table']),
array ($newpath, $newname, time(), $oldpath, $oldname));
if ($this->_db->affectedRows () == 0 ) {
return PEAR ::raiseError (_("Unable to rename VFS file."));
if (is_a($this->_recursiveSQLRename ($oldpath, $oldname, $newpath, $newname), 'PEAR_Error')) {
$result = $this->_db->query (sprintf('UPDATE %s SET vfs_path = ?, vfs_name = ?
WHERE vfs_path = ? AND vfs_name = ?',
$this->_params['table']),
array ($oldpath, $oldname, $newpath, $newname));
return PEAR ::raiseError (_("Unable to rename VFS directory."));
if (!@is_dir($this->_getNativePath ($newpath))) {
if (!@rename($this->_getNativePath ($oldpath, $oldname), $this->_getNativePath ($newpath, $newname))) {
$result = $this->_db->query (sprintf('UPDATE %s SET vfs_path = ?, vfs_name = ?
WHERE vfs_path = ? AND vfs_name = ?',
$this->_params['table']),
array ($oldpath, $oldname, $newpath, $newname));
return PEAR ::raiseError (_("Unable to rename VFS file."));
* Delete a folder from the VFS.
* @param string $path The path to delete the folder from.
* @param string $name The foldername to use.
* @param boolean $recursive Force a recursive delete?
* @return mixed True on success or a PEAR_Error object on failure.
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
if (is_a($result, 'PEAR_Error')) {
if (is_a($list, 'PEAR_Error')) {
return PEAR ::raiseError (sprintf(_("Unable to delete %s, the directory is not empty"),
$result = $this->_db->query (sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ? AND vfs_name = ?',
$this->_params['table']),
if ($this->_db->affectedRows () == 0 || is_a($result, 'PEAR_Error')) {
return PEAR ::raiseError (_("Unable to delete VFS directory."));
if (is_a($this->_recursiveSQLDelete ($path, $name), 'PEAR_Error')) {
return PEAR ::raiseError (_("Unable to delete VFS directory recursively."));
if (is_a($this->_recursiveLFSDelete ($path, $name), 'PEAR_Error')) {
return PEAR ::raiseError (_("Unable to delete VFS directory recursively."));
* Delete a file from the VFS.
* @param string $path The path to store the file in.
* @param string $name The filename to use.
* @return mixed True on success or a PEAR_Error object on failure.
$res = $this->_checkQuotaDelete ($path, $name);
if (is_a($res, 'PEAR_Error')) {
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
$result = $this->_db->query (sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ? AND vfs_name = ?',
$this->_params['table']),
if ($this->_db->affectedRows () == 0 ) {
return PEAR ::raiseError (_("Unable to delete VFS file."));
if (is_a($result, 'PEAR_Error')) {
if (!@unlink($this->_getNativePath ($path, $name))) {
return PEAR ::raiseError (_("Unable to delete VFS file."));
* Return a list of the contents of a folder.
* @param string $path The directory path.
* @param mixed $filter String/hash of items to filter based on
* @param boolean $dotfiles Show dotfiles?
* @param boolean $dironly Show directories only?
* @return mixed File list on success or false on failure.
function _listFolder ($path, $filter = null , $dotfiles = true ,
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
$fileList = $this->_db->getAll (sprintf('SELECT vfs_name, vfs_type, vfs_modified, vfs_owner FROM %s
$this->_params['table']),
if (is_a($fileList, 'PEAR_Error')) {
foreach ($fileList as $line) {
// Filter out dotfiles if they aren't wanted.
if (!$dotfiles && substr($line[0 ], 0 , 1 ) == '.') {
$file['name'] = $line[0 ];
$file['type'] = '**none';
$file['size'] = filesize($this->_getNativePath ($path, $line[0 ]));
$file['date'] = $line[2 ];
$file['owner'] = $line[3 ];
if ($this->_filterMatch ($filter, $file['name'])) {
if ($dironly && $file['type'] !== '**dir') {
$files[$file['name']] = $file;
* Returns a sorted list of folders in specified directory.
* @param string $path The path of the directory to get the
* @param mixed $filter String/hash of items to filter based on
* @param boolean $dotfolders Include dotfolders?
* @return mixed Folder list on success or a PEAR_Error object on failure.
function listFolders($path = '', $filter = array (), $dotfolders = true )
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
$sql = sprintf('SELECT vfs_name, vfs_path FROM %s WHERE vfs_path = ? AND vfs_type = ?',
$this->_params['table']);
$folderList = $this->_db->getAll ($sql, array ($path, $VFS_FOLDER));
if (is_a($folderList, 'PEAR_Error')) {
foreach ($folderList as $line) {
$folder['val'] = $this->_getNativePath ($line[1 ], $line[0 ]);
$folder['abbrev'] .= ' ';
$folder['abbrev'] .= $line[0 ];
$folder['label'] .= $line[0 ];
$folder['abbrev'] = substr($folder['label'], 0 , ($count * 4 ));
$length = (29 - ($count * 4 )) / 2;
$folder['abbrev'] .= substr($folder['label'], ($count * 4 ), $length);
$folder['abbrev'] .= '...';
$folder['abbrev'] .= substr($folder['label'], -1 * $length, $length);
foreach ($filter as $fltr) {
if ($folder['val'] == $fltr) {
$folders[$folder['val']] = $folder;
* Recursively copies the contents of a folder to a destination.
* @param string $path The path to store the directory in.
* @param string $name The name of the directory.
* @param string $dest The destination of the directory.
* @return mixed True on success or a PEAR_Error object on failure.
function _recursiveCopy ($path, $name, $dest)
if (is_a($result, 'PEAR_Error')) {
$file_list = $this->listFolder($this->_getSQLNativePath ($path, $name));
foreach ($file_list as $file) {
$result = $this->copy($this->_getSQLNativePath ($path, $name), $file['name'], $this->_getSQLNativePath ($dest, $name));
if (is_a($result, 'PEAR_Error')) {
* Store a files information within the database.
* @param string $path The path to store the file in.
* @param string $name The filename to use.
* @param boolean $autocreate Automatically create directories?
* @return mixed True on success or a PEAR_Error object on failure.
function _writeSQLData ($path, $name, $autocreate = false )
$conn = $this->_connect ();
if (is_a($conn, 'PEAR_Error')) {
// File already exists in database
if ($this->exists($path, $name)) {
$query = 'UPDATE ' . $this->_params['table'] .
' SET vfs_modified = ?' .
' WHERE vfs_path = ? AND vfs_name = ?';
$values = array (time(), $path, $name);
$id = $this->_db->nextId ($this->_params['table']);
$query = 'INSERT INTO ' . $this->_params['table'] .
' (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified,' .
' vfs_owner) VALUES (?, ?, ?, ?, ?, ?)';
return $this->_db->query ($query, $values);
* Renames all child paths.
* @param string $oldpath The old path of the folder to rename.
* @param string $oldname The old name.
* @param string $newpath The new path of the folder to rename.
* @param string $newname The new name.
* @return mixed True on success or a PEAR_Error object on failure.
function _recursiveSQLRename ($oldpath, $oldname, $newpath, $newname)
$folderList = $this->_db->getCol (sprintf('SELECT vfs_name FROM %s WHERE vfs_type = ? AND vfs_path = ?',
$this->_params['table']),
array (VFS_FOLDER, $this->_getSQLNativePath ($oldpath, $oldname)));
foreach ($folderList as $folder) {
$this->_recursiveSQLRename ($this->_getSQLNativePath ($oldpath, $oldname), $folder, $this->_getSQLNativePath ($newpath, $newname), $folder);
$result = $this->_db->query (sprintf('UPDATE %s SET vfs_path = ? WHERE vfs_path = ?',
$this->_params['table']),
array ($this->_getSQLNativePath ($newpath, $newname),
$this->_getSQLNativePath ($oldpath, $oldname)));
if (is_a($result, 'PEAR_Error')) {
* Delete a folders contents from the VFS in the SQL database,
* @param string $path The path of the folder.
* @param string $name The foldername to use.
* @return mixed True on success or a PEAR_Error object on failure.
function _recursiveSQLDelete ($path, $name)
$result = $this->_db->query (sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ?',
$this->_params['table']),
array (VFS_FILE, $this->_getSQLNativePath ($path, $name)));
if (is_a($result, 'PEAR_Error')) {
$folderList = $this->_db->getCol (sprintf('SELECT vfs_name FROM %s WHERE vfs_type = ? AND vfs_path = ?',
$this->_params['table']),
array (VFS_FOLDER, $this->_getSQLNativePath ($path, $name)));
foreach ($folderList as $folder) {
$this->_recursiveSQLDelete ($this->_getSQLNativePath ($path, $name), $folder);
$result = $this->_db->query (sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_name = ? AND vfs_path = ?',
$this->_params['table']),
* Delete a folders contents from the VFS, recursively.
* @param string $path The path of the folder.
* @param string $name The foldername to use.
* @return mixed True on success or a PEAR_Error object on failure.
function _recursiveLFSDelete ($path, $name)
$dir = $this->_getNativePath ($path, $name);
while (false !== ($file = readdir($dh))) {
if ($file != '.' && $file != '..') {
if (is_dir($dir . '/' . $file)) {
$this->_recursiveLFSDelete (empty ($path) ? $name : $path . '/' . $name, $file);
* Attempts to open a persistent connection to the SQL server.
* @return mixed True on success or a PEAR_Error object on failure.
if ($this->_db === false ) {
return PEAR ::raiseError (_("No configuration information specified for SQL-File VFS."));
$required = array ('phptype', 'vfsroot');
foreach ($required as $val) {
if (!isset ($this->_params[$val])) {
return PEAR ::raiseError (sprintf(_("Required \"%s\" not specified in VFS configuration."), $val));
if (!isset ($this->_params['database'])) {
$this->_params['database'] = '';
if (!isset ($this->_params['username'])) {
$this->_params['username'] = '';
if (!isset ($this->_params['hostspec'])) {
$this->_params['hostspec'] = '';
if (!isset ($this->_params['table'])) {
$this->_params['table'] = 'horde_vfs';
/* Connect to the SQL server using the supplied parameters. */
$this->_db = &DB ::connect ($this->_params,
array ('persistent' => !empty ($this->_params['persistent'])));
if (is_a($this->_db, 'PEAR_Error')) {
// Set DB portability options.
switch ($this->_db->phptype ) {
$this->_db->setOption ('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM );
$this->_db->setOption ('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS );
* Disconnect from the SQL server and clean up the connection.
$this->_db->disconnect ();
* Return a full filename on the native filesystem, from a VFS
* @param string $path The VFS file path.
* @param string $name The VFS filename.
* @return string The full native filename.
function _getNativePath ($path, $name)
if (isset ($this->_params['home']) &&
$path = $this->_params['home'] . '/' . $matches[1 ];
return $this->_params['vfsroot'] . '/' . $path . $name;
return $this->_params['vfsroot'] . $name;
* Return a full SQL filename on the native filesystem, from a VFS
* @param string $path The VFS file path.
* @param string $name The VFS filename.
* @return string The full native filename.
function _getSQLNativePath ($path, $name)
return $path . '/' . $name;
* Returns the size of a file.
* @param string $path The path of the file.
* @param string $name The filename.
* @return integer The size of the file in bytes or PEAR_Error on
if (($size = @filesize($this->_getNativePath ($path, $name))) === false ){
return PEAR ::raiseError (sprintf(_("Unable to check file size of \"%s/%s\".", $path, $name)));
Documentation generated on Mon, 11 Mar 2019 14:39:02 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|