Convert VFS to PHP 5.
authorMichael M Slusarz <slusarz@curecanti.org>
Sun, 7 Mar 2010 08:06:17 +0000 (01:06 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 10 Mar 2010 01:33:36 +0000 (18:33 -0700)
I realize there is a H4-Vfs stub lying around, but it looks like zero
work has been done on it for awhile.  So, in the meanwhile, update VFS -
mostly to eliminate the boatload of PEAR_Error usage.

17 files changed:
framework/VFS/lib/VFS.php
framework/VFS/lib/VFS/Browser.php
framework/VFS/lib/VFS/Exception.php [new file with mode: 0644]
framework/VFS/lib/VFS/GC.php
framework/VFS/lib/VFS/ListItem.php
framework/VFS/lib/VFS/Object.php
framework/VFS/lib/VFS/file.php
framework/VFS/lib/VFS/ftp.php
framework/VFS/lib/VFS/horde.php
framework/VFS/lib/VFS/kolab.php
framework/VFS/lib/VFS/musql.php
framework/VFS/lib/VFS/smb.php
framework/VFS/lib/VFS/sql.php
framework/VFS/lib/VFS/sql_file.php
framework/VFS/lib/VFS/ssh2.php
framework/VFS/package.xml
framework/VFS/scripts/VFS/vfs.php

index 45fa4ff..a04b993 100644 (file)
@@ -1,11 +1,7 @@
 <?php
 
 require_once 'Log.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);
+require_once dirname(__FILE__) . '/VFS/Exception.php';
 
 /**
  * VFS API for abstracted file storage and access.
@@ -18,14 +14,27 @@ define('VFS_QUOTA_METRIC_GB', 4);
  * @author  Chuck Hagenbuch <chuck@horde.org>
  * @package VFS
  */
-class VFS {
+class VFS
+{
+    /* Quota constants. */
+    const QUOTA_METRIC_BYTE = 1;
+    const QUOTA_METRIC_KB = 2;
+    const QUOTA_METRIC_MB = 3;
+    const QUOTA_METRIC_GB = 4;
+
+    /**
+     * Singleton instances.
+     *
+     * @var array
+     */
+    static protected $_instances = array();
 
     /**
      * Hash containing connection parameters.
      *
      * @var array
      */
-    var $_params = array();
+    protected $_params = array();
 
     /**
      * List of additional credentials required for this VFS backend (example:
@@ -33,17 +42,30 @@ class VFS {
      *
      * @var array
      */
-    var $_credentials = array();
+    protected $_credentials = array();
 
     /**
      * List of permissions and if they can be changed in this VFS backend.
      *
      * @var array
      */
-    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));
+    protected $_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
@@ -51,7 +73,7 @@ class VFS {
      *
      * @var Log
      */
-    var $_logger = null;
+    protected $_logger = null;
 
     /**
      * The log level to use - messages with a higher log level than configured
@@ -59,56 +81,115 @@ class VFS {
      *
      * @var integer
      */
-    var $_logLevel = PEAR_LOG_ERR;
+    protected $_logLevel = PEAR_LOG_ERR;
 
     /**
      * The current size, in bytes, of the VFS item.
      *
      * @var integer
      */
-    var $_vfsSize = null;
+    protected $_vfsSize = null;
 
     /**
-     * Constructor.
+     * Attempts to return a reference to a concrete instance based on
+     * $driver. It will only create a new instance if no instance with the
+     * same parameters currently exists.
      *
-     * @param array $params  A hash containing connection parameters.
+     * 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 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.
+     * @throws VFS_Exception
      */
-    function VFS($params = array())
+    static public function singleton($driver, $params = array())
     {
-        if (empty($params['user'])) {
-            $params['user'] = '';
-        }
-        if (empty($params['vfs_quotalimit'])) {
-            $params['vfs_quotalimit'] = -1;
+        ksort($params);
+        $signature = serialize(array($driver, $params));
+        if (!isset(self::$_instances[$signature])) {
+            self::$_instances[$signature] = self::factory($driver, $params);
         }
-        if (empty($params['vfs_quotaroot'])) {
-            $params['vfs_quotaroot'] = '/';
+
+        return self::$_instances[$signature];
+    }
+
+    /**
+     * Attempts to return a concrete instance based on $driver.
+     *
+     * @param mixed $driver  The type of concrete 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.
+     * @throws VFS_Exception
+     */
+    static public function factory($driver, $params = array())
+    {
+        $driver = basename($driver);
+        $class = __CLASS__ . '_' . $driver;
+        if (!class_exists($class)) {
+            include_once 'VFS/' . $driver . '.php';
+            if (!class_exists($class)) {
+                throw new VFS_Exception('Class definition of ' . $class . ' not found.');
+            }
         }
-        $this->_params = $params;
+
+        return new $class($params);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param array $params  A hash containing connection parameters.
+     */
+    public function __construct($params = array())
+    {
+        $this->setParams(array(
+            'user' => '',
+            'vfs_quotalimit' => -1,
+            'vfs_quotaroot' => '/'
+        ));
+        $this->setParams($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.
+     * @throws VFS_Exception
      */
-    function checkCredentials()
+    public function checkCredentials()
+    {
+        $this->_connect();
+    }
+
+    /**
+     * TODO
+     *
+     * @throws VFS_Exception
+     */
+    protected function _connect()
     {
-        return $this->_connect();
     }
 
     /**
      * Sets configuration parameters.
      *
-     * @param array $params  An associative array with parameter names as keys.
+     * @param array $params  An associative array with parameter names as
+     *                       keys.
      */
-    function setParams($params = array())
+    public function setParams($params = array())
     {
-        foreach ($params as $name => $value) {
-            $this->_params[$name] = $value;
-        }
+        $this->_params = array_merge($this->_params, $params);
     }
 
     /**
@@ -118,9 +199,11 @@ class VFS {
      *
      * @return mixed  The parameter value or null if it doesn't exist.
      */
-    function getParam($name)
+    public function getParam($name)
     {
-        return isset($this->_params[$name]) ? $this->_params[$name] : null;
+        return isset($this->_params[$name])
+            ? $this->_params[$name]
+            : null;
     }
 
     /**
@@ -130,13 +213,13 @@ class VFS {
      * @param mixed   $message   The message to be logged.
      * @param integer $priority  The message's priority.
      */
-    function log($message, $priority = PEAR_LOG_ERR)
+    public function log($message, $priority = PEAR_LOG_ERR)
     {
-        if (!isset($this->_logger) || $priority > $this->_logLevel) {
+        if (!isset($this->_logger) || ($priority > $this->_logLevel)) {
             return;
         }
 
-        if (is_a($message, 'PEAR_Error')) {
+        if ($message instanceof PEAR_Error) {
             $userinfo = $message->getUserInfo();
             $message = $message->getMessage();
             if ($userinfo) {
@@ -160,17 +243,15 @@ class VFS {
     /**
      * Sets the PEAR Log object used to log informational or error messages.
      *
-     * @param Log &$logger  The Log object to use.
+     * @param Log $logger  The Log object to use.
      */
-    function setLogger(&$logger, $logLevel = null)
+    public function setLogger($logger, $logLevel = null)
     {
-        if (!is_callable(array($logger, 'log'))) {
-            return false;
-        }
-
-        $this->_logger = &$logger;
-        if (!is_null($logLevel)) {
-            $this->_logLevel = $logLevel;
+        if (is_callable(array($logger, 'log'))) {
+            $this->_logger = $logger;
+            if (!is_null($logLevel)) {
+                $this->_logLevel = $logLevel;
+            }
         }
     }
 
@@ -182,11 +263,12 @@ class VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return integer The file size.
+     * @return integer  The file size.
+     * @throws VFS_Exception
      */
-    function size($path, $name)
+    public function size($path, $name)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -195,24 +277,19 @@ class VFS {
      * @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
-     *                  failure.
+     * @return integer  The size of the folder, in bytes.
+     * @throws VFS_Exception
      */
-    function getFolderSize($path = null, $name = null)
+    public function getFolderSize($path = null, $name = null)
     {
         $size = 0;
-        $root = ((!is_null($path)) ? $path . '/' : '') . $name;
+        $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'])) {
-                $size += $this->getFolderSize($root, $key);
-            } else {
-                $filesize = $this->size($root, $key);
-                if (is_a($filesize, 'PEAR_Error')) {
-                    return $filesize;
-                }
-                $size += $filesize;
-            }
+            $size += isset($val['subdirs'])
+                ? $this->getFolderSize($root, $key)
+                : $this->size($root, $key);
         }
 
         return $size;
@@ -226,11 +303,12 @@ class VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return string The file data.
+     * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -243,15 +321,15 @@ class VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return string A local filename.
+     * @return string  A local filename.
+     * @throws VFS_Exception
      */
-    function readFile($path, $name)
+    public function readFile($path, $name)
     {
         // Create a temporary file and register it for deletion at the
         // end of this request.
-        $localFile = $this->_getTempFile();
-        if (!$localFile) {
-            return PEAR::raiseError(_("Unable to create temporary file."));
+        if (!($localFile = tempnam(null, 'vfs'))) {
+            throw new VFS_Exception('Unable to create temporary file.');
         }
         register_shutdown_function(create_function('', 'unlink(\'' . addslashes($localFile) . '\');'));
 
@@ -259,48 +337,16 @@ class VFS {
             // Use a stream from the VFS if possible, to avoid reading all data
             // into memory.
             $stream = $this->readStream($path, $name);
-            if (is_a($stream, 'PEAR_Error')) {
-                return $stream;
-            }
-
-            $localStream = fopen($localFile, 'w');
-            if (!$localStream) {
-                return PEAR::raiseError(_("Unable to open temporary file."));
-            }
 
-            if (is_callable('stream_copy_to_stream')) {
-                // If we have stream_copy_to_stream, it can do the data transfer
-                // in one go.
-                stream_copy_to_stream($stream, $localStream);
-            } else {
-                // Otherwise loop through in chunks.
-                while ($buffer = fread($stream, 8192)) {
-                    fwrite($localStream, $buffer);
-                }
+            if (!($localStream = fopen($localFile, 'w'))) {
+                throw new VFS_Exception('Unable to open temporary file.');
             }
-
+            stream_copy_to_stream($stream, $localStream);
             fclose($localStream);
         } else {
             // We have to read all of the data in one shot.
             $data = $this->read($path, $name);
-            if (is_a($data, 'PEAR_Error')) {
-                return $data;
-            }
-
-            if (is_callable('file_put_contents')) {
-                // file_put_contents is more efficient if we have it.
-                file_put_contents($localFile, $data);
-            } else {
-                // Open the local file and write to it.
-                $localStream = fopen($localFile, 'w');
-                if (!$localStream) {
-                    return PEAR::raiseError(_("Unable to open temporary file."));
-                }
-                if (!fwrite($localStream, $data)) {
-                    return PEAR::raiseError(_("Unable to write temporary file."));
-                }
-                fclose($localStream);
-            }
+            file_put_contents($localFile, $data);
         }
 
         // $localFile now has $path/$name's data in it.
@@ -326,11 +372,13 @@ class VFS {
      * @param integer $remaining  The bytes that are left, after the part that
      *                            is retrieved.
      *
-     * @return string The file data.
+     * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function readByteRange($path, $name, &$offset, $length = -1, &$remaining)
+    public function readByteRange($path, $name, &$offset, $length = -1,
+                                  &$remaining)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -344,11 +392,11 @@ class VFS {
      *                             be stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -361,11 +409,11 @@ class VFS {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -376,14 +424,12 @@ class VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function move($path, $name, $dest, $autocreate = false)
+    public function move($path, $name, $dest, $autocreate = false)
     {
-        if (is_a($result = $this->copy($path, $name, $dest, $autocreate), 'PEAR_Error')) {
-            return $result;
-        }
-        return $this->deleteFile($path, $name);
+        $this->copy($path, $name, $dest, $autocreate);
+        $this->deleteFile($path, $name);
     }
 
     /**
@@ -394,68 +440,49 @@ class VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function copy($path, $name, $dest, $autocreate = false)
+    public function copy($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
+            throw new VFS_Exception('Cannot copy file(s) - source and destination are the same.');
         }
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
+
         if ($this->isFolder($path, $name)) {
-            if (is_a($result = $this->_copyRecursive($path, $name, $dest), 'PEAR_Error')) {
-                return $result;
-            }
+            $this->_copyRecursive($path, $name, $dest);
         } else {
-            $data = $this->read($path, $name);
-            if (is_a($data, 'PEAR_Error')) {
-                return $data;
-            }
-            return $this->writeData($dest, $name, $data, $autocreate);
+            return $this->writeData($dest, $name, $this->read($path, $name), $autocreate);
         }
-        return true;
     }
 
     /**
      * Recursively copies a directory through the backend.
      *
-     * @access protected
+     * @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 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.
+     * @throws VFS_Exception
      */
-    function _copyRecursive($path, $name, $dest)
+    protected function _copyRecursive($path, $name, $dest)
     {
-        if (is_a($result = $this->createFolder($dest, $name), 'PEAR_Error')) {
-            return $result;
-        }
-
-        if (is_a($file_list = $this->listFolder($this->_getPath($path, $name)), 'PEAR_Error')) {
-            return $file_list;
-        }
+        $this->createFolder($dest, $name);
 
+        $file_list = $this->listFolder($this->_getPath($path, $name));
         foreach ($file_list as $file) {
-            $result = $this->copy($this->_getPath($path, $name),
-                                  $file['name'],
-                                  $this->_getPath($dest, $name));
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->copy($this->_getPath($path, $name), $file['name'], $this->_getPath($dest, $name));
         }
     }
 
     /**
      * Alias to deleteFile()
      */
-    function delete($path, $name)
+    public function delete($path, $name)
     {
         return $this->deleteFile($path, $name);
     }
@@ -468,11 +495,11 @@ class 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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -485,11 +512,11 @@ class VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -500,13 +527,13 @@ class VFS {
      *
      * @return boolean  True if it exists, false otherwise.
      */
-    function exists($path, $name)
+    public function exists($path, $name)
     {
-        $list = $this->listFolder($path);
-        if (is_a($list, 'PEAR_Error')) {
-            return false;
-        } else {
+        try {
+            $list = $this->listFolder($path);
             return isset($list[$name]);
+        } catch (VFS_Exception $e) {
+            return false;
         }
     }
 
@@ -518,11 +545,11 @@ class 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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -530,8 +557,10 @@ class VFS {
      * $path.
      *
      * @param string $path  The VFS path to autocreate.
+     *
+     * @throws VFS_Exception
      */
-    function autocreatePath($path)
+    public function autocreatePath($path)
     {
         $dirs = explode('/', $path);
         if (is_array($dirs)) {
@@ -542,9 +571,6 @@ class VFS {
                 }
                 if (!$this->isFolder($cur, $dir)) {
                     $result = $this->createFolder($cur, $dir);
-                    if (is_a($result, 'PEAR_Error')) {
-                        return $result;
-                    }
                 }
                 if ($cur != '/') {
                     $cur .= '/';
@@ -552,8 +578,6 @@ class VFS {
                 $cur .= $dir;
             }
         }
-
-        return true;
     }
 
     /**
@@ -564,10 +588,14 @@ class VFS {
      *
      * @return boolean  True if it is a folder, false otherwise.
      */
-    function isFolder($path, $name)
+    public function isFolder($path, $name)
     {
-        $folderList = $this->listFolder($path, null, true, true);
-        return isset($folderList[$name]);
+        try {
+            $folderList = $this->listFolder($path, null, true, true);
+            return isset($folderList[$name]);
+        } catch (VFS_Exception $e) {
+            return false;
+        }
     }
 
     /**
@@ -579,11 +607,11 @@ class VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -592,34 +620,19 @@ class VFS {
      *
      * @param string $path  The path of the folder to empty.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function emptyFolder($path)
+    public function emptyFolder($path)
     {
         // Get and delete the subfolders.
-        $list = $this->listFolder($path, null, true, true);
-        if (is_a($list, 'PEAR_Error')) {
-            return $list;
-        }
-        foreach ($list as $folder) {
-            $result = $this->deleteFolder($path, $folder['name'], true);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+        foreach ($this->listFolder($path, null, true, true) as $folder) {
+            $this->deleteFolder($path, $folder['name'], true);
         }
+
         // Only files are left, get and delete them.
-        $list = $this->listFolder($path);
-        if (is_a($list, 'PEAR_Error')) {
-            return $list;
+        foreach ($this->listFolder($path) as $file) {
+            $this->deleteFile($path, $file['name']);
         }
-        foreach ($list as $file) {
-            $result = $this->deleteFile($path, $file['name']);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
-        }
-
-        return true;
     }
 
     /**
@@ -631,13 +644,14 @@ class VFS {
      * @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.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function listFolder($path, $filter = null, $dotfiles = true,
-                        $dironly = false, $recursive = false)
+    public 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')) {
+        if (!$recursive) {
             return $list;
         }
 
@@ -660,12 +674,13 @@ class VFS {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show only directories?
      *
-     * @return array  File list on success or PEAR_Error on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path, $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path, $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -673,7 +688,7 @@ class VFS {
      *
      * @return string  The current working directory.
      */
-    function getCurrentDirectory()
+    public function getCurrentDirectory()
     {
         return '';
     }
@@ -681,31 +696,28 @@ class VFS {
     /**
      * Returns whether or not a filename matches any filter element.
      *
-     * @access private
-     *
      * @param mixed $filter     String/hash to build the regular expression
      *                          from.
      * @param string $filename  String containing the filename to match.
      *
      * @return boolean  True on match, false on no match.
      */
-    function _filterMatch($filter, $filename)
+    protected function _filterMatch($filter, $filename)
     {
         $namefilter = null;
 
         // Build a regexp based on $filter.
-        if ($filter !== null) {
+        if (!is_null($filter)) {
             $namefilter = '/';
             if (is_array($filter)) {
                 $once = false;
                 foreach ($filter as $item) {
                     if ($once !== true) {
-                        $namefilter .= '(';
                         $once = true;
                     } else {
-                        $namefilter .= '|(';
+                        $namefilter .= '|';
                     }
-                    $namefilter .= $item . ')';
+                    $namefilter .= '(' . $item . ')';
                 }
             } else {
                 $namefilter .= '(' . $filter . ')';
@@ -714,7 +726,7 @@ class VFS {
         }
 
         $match = false;
-        if ($namefilter !== null) {
+        if (!is_null($namefilter)) {
             $match = preg_match($namefilter, $filename);
         }
 
@@ -730,11 +742,11 @@ class VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function changePermissions($path, $name, $permission)
+    public function changePermissions($path, $name, $permission)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -747,11 +759,12 @@ class VFS {
      * @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.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = null, $dotfolders = true)
+    public function listFolders($path = '', $filter = null, $dotfolders = true)
     {
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -759,7 +772,7 @@ class VFS {
      *
      * @return array  Credential list.
      */
-    function getRequiredCredentials()
+    public function getRequiredCredentials()
     {
         return array_diff($this->_credentials, array_keys($this->_params));
     }
@@ -770,57 +783,17 @@ class VFS {
      *
      * @return array  Changeable permisions.
      */
-    function getModifiablePermissions()
+    public function getModifiablePermissions()
     {
         return $this->_permissions;
     }
 
     /**
-     * Converts a string to all lowercase characters ignoring the current
-     * locale.
-     *
-     * @param string $string  The string to be lowercased
-     *
-     * @return string  The string with lowercase characters
-     */
-    function strtolower($string)
-    {
-        $language = setlocale(LC_CTYPE, 0);
-        setlocale(LC_CTYPE, 'C');
-        $string = strtolower($string);
-        setlocale(LC_CTYPE, $language);
-        return $string;
-    }
-
-    /**
-     * 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
-     *                         string's length.
-     *
-     * @return string  The string's length.
-     */
-    function strlen($string, $charset = null)
-    {
-        if (extension_loaded('mbstring')) {
-            if (is_null($charset)) {
-                $charset = 'ISO-8859-1';
-            }
-            $result = @mb_strlen($string, $charset);
-            if (!empty($result)) {
-                return $result;
-            }
-        }
-        return strlen($string);
-    }
-
-    /**
      * Returns the size of the VFS item.
      *
      * @return integer  The size, in bytes, of the VFS item.
      */
-    function getVFSSize()
+    public function getVFSSize()
     {
         if (is_null($this->_vfsSize)) {
             $this->_vfsSize = $this->getFolderSize($this->_params['vfs_quotaroot']);
@@ -834,18 +807,18 @@ class VFS {
      * @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)
+    public function setQuota($quota, $metric = self::QUOTA_METRIC_BYTE)
     {
         switch ($metric) {
-        case VFS_QUOTA_METRIC_KB:
+        case self::QUOTA_METRIC_KB:
             $quota *= pow(2, 10);
             break;
 
-        case VFS_QUOTA_METRIC_MB:
+        case self::QUOTA_METRIC_MB:
             $quota *= pow(2, 20);
             break;
 
-        case VFS_QUOTA_METRIC_GB:
+        case self::QUOTA_METRIC_GB:
             $quota *= pow(2, 30);
             break;
         }
@@ -858,7 +831,7 @@ class VFS {
      *
      * @param string $dir  The root directory for the quota determination.
      */
-    function setQuotaRoot($dir)
+    public function setQuotaRoot($dir)
     {
         $this->_params['vfs_quotaroot'] = $dir;
     }
@@ -867,154 +840,82 @@ class VFS {
      * 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.
+     * <pre>
+     * 'limit' = Maximum quota allowed
+     * 'usage' = Currently used portion of quota (in bytes)
+     * </pre>
+     * @throws VFS_Exception
      */
-    function getQuota()
+    public function getQuota()
     {
         if (empty($this->_params['vfs_quotalimit'])) {
-            return PEAR::raiseError(_("No quota set."));
-        }
-
-        $usage = $this->getVFSSize();
-        if (is_a($usage, 'PEAR_Error')) {
-            return $usage;
-        } else {
-            return array('usage' => $usage, 'limit' => $this->_params['vfs_quotalimit']);
+            throw new VFS_Exception('No quota set.');
         }
-    }
-
-    /**
-     * Determines the location of the system temporary directory.
-     *
-     * @access protected
-     *
-     * @return string  A directory name which can be used for temp files.
-     *                 Returns false if one could not be found.
-     */
-    function _getTempDir()
-    {
-        $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
-                               'c:\windows\temp', 'c:\winnt\temp');
-
-        /* Try PHP's upload_tmp_dir directive. */
-        $tmp = ini_get('upload_tmp_dir');
-
-        /* Otherwise, try to determine the TMPDIR environment variable. */
-        if (!strlen($tmp)) {
-            $tmp = getenv('TMPDIR');
-        }
-
-        /* If we still cannot determine a value, then cycle through a list of
-         * preset possibilities. */
-        while (!strlen($tmp) && count($tmp_locations)) {
-            $tmp_check = array_shift($tmp_locations);
-            if (@is_dir($tmp_check)) {
-                $tmp = $tmp_check;
-            }
-        }
-
-        /* 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.
-     *
-     * @access protected
-     *
-     * @return string   Returns the full path-name to the temporary file or
-     *                  false if a temporary file could not be created.
-     */
-    function _getTempFile()
-    {
-        $tmp_dir = $this->_getTempDir();
-        if (!strlen($tmp_dir)) {
-            return false;
-        }
-
-        $tmp_file = tempnam($tmp_dir, 'vfs');
-        if (!strlen($tmp_file)) {
-            return false;
-        } else {
-            return $tmp_file;
-        }
+        return array(
+            'limit' => $this->_params['vfs_quotalimit'],
+            'usage' => $this->getVFSSize()
+        );
     }
 
     /**
      * Checks the quota when preparing to write data.
      *
-     * @access private
-     *
      * @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.
+     * @throws VFS_Exception
      */
-    function _checkQuotaWrite($mode, $data)
+    protected function _checkQuotaWrite($mode, $data)
     {
-        if ($this->_params['vfs_quotalimit'] != -1) {
-            if ($mode == 'file') {
-                $filesize = filesize($data);
-                if ($filesize === false) {
-                    return PEAR::raiseError(_("Unable to read VFS file (filesize() failed)."));
-               }
-            } else {
-                $filesize = strlen($data);
-            }
-            $vfssize = $this->getVFSSize();
-            if (is_a($vfssize, 'PEAR_Error')) {
-                return $vfssize;
-            }
-            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;
+        if ($this->_params['vfs_quotalimit'] == -1) {
+            return;
+        }
+
+        if ($mode == 'file') {
+            $filesize = filesize($data);
+            if ($filesize === false) {
+                throw new VFS_Exception('Unable to read VFS file (filesize() failed).');
             }
+        } else {
+            $filesize = strlen($data);
         }
 
-        return true;
+        $vfssize = $this->getVFSSize();
+        if (($vfssize + $filesize) > $this->_params['vfs_quotalimit']) {
+            throw new VFS_Exception('Unable to write VFS file, quota will be exceeded.');
+        } elseif ($this->_vfsSize !== 0) {
+            $this->_vfsSize += $filesize;
+        }
     }
 
     /**
      * Checks the quota when preparing to delete data.
      *
-     * @access private
-     *
      * @param string $path  The path the file is located in.
      * @param string $name  The filename.
      *
-     * @return mixed  PEAR_Error on error, true on success.
+     * @throws VFS_Exception
      */
-    function _checkQuotaDelete($path, $name)
+    protected 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;
+            $this->_vfsSize -= $this->size($path, $name);
         }
-
-        return true;
     }
 
     /**
      * Returns the full path of an item.
      *
-     * @access protected
-     *
      * @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.
      */
-    function _getPath($path, $name)
+    protected function _getPath($path, $name)
     {
         if (strlen($path) > 0) {
             if (substr($path, -1) == '/') {
@@ -1022,68 +923,50 @@ class VFS {
             } else {
                 return $path . '/' . $name;
             }
-        } else {
-            return $name;
         }
+
+        return $name;
     }
 
     /**
-     * Attempts to return a concrete VFS instance based on $driver.
+     * Converts a string to all lowercase characters ignoring the current
+     * locale.
      *
-     * @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.
+     * @param string $string  The string to be lowercased
      *
-     * @return VFS  The newly created concrete VFS instance, or a PEAR_Error
-     *              on failure.
+     * @return string  The string with lowercase characters
      */
-    function &factory($driver, $params = array())
+    public function strtolower($string)
     {
-        $driver = basename($driver);
-        $class = 'VFS_' . $driver;
-        if (!class_exists($class)) {
-            include_once 'VFS/' . $driver . '.php';
-        }
-
-        if (class_exists($class)) {
-            $vfs = new $class($params);
-        } else {
-            $vfs = PEAR::raiseError(sprintf(_("Class definition of %s not found."), $class));
-        }
-
-        return $vfs;
+        $language = setlocale(LC_CTYPE, 0);
+        setlocale(LC_CTYPE, 'C');
+        $string = strtolower($string);
+        setlocale(LC_CTYPE, $language);
+        return $string;
     }
 
     /**
-     * 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()
+     * Returns the character (not byte) length of a string.
      *
-     * @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.
+     * @param string $string   The string to return the length of.
+     * @param string $charset  The charset to use when calculating the
+     *                         string's length.
      *
-     * @return VFS  The concrete VFS reference, or a PEAR_Error on failure.
+     * @return string  The string's length.
      */
-    function &singleton($driver, $params = array())
+    public function strlen($string, $charset = null)
     {
-        static $instances = array();
-
-        $signature = serialize(array($driver, $params));
-        if (!isset($instances[$signature])) {
-            $instances[$signature] = &VFS::factory($driver, $params);
+        if (extension_loaded('mbstring')) {
+            if (is_null($charset)) {
+                $charset = 'ISO-8859-1';
+            }
+            $result = @mb_strlen($string, $charset);
+            if (!empty($result)) {
+                return $result;
+            }
         }
-
-        return $instances[$signature];
+        return strlen($string);
     }
 
+
 }
index 019353d..d2fa003 100644 (file)
  * @author  Chuck Hagenbuch <chuck@horde.org>
  * @package VFS
  */
-class VFS_Browser {
-
+class VFS_Browser
+{
     /**
      * The VFS instance that we are browsing.
      *
      * @var VFS
      */
-    var $_vfs;
+    protected $_vfs;
 
     /**
      * The directory where the templates to use are.
      *
      * @var string
      */
-    var $_templates;
+    protected $_templates;
 
     /**
      * Constructor
      *
-     * @param VFS &$vfs          A VFS object.
-     * @param string $templates  TODO
+     * @param VFS $vfs           A VFS object.
+     * @param string $templates  Template directory.
      */
-    function VFS_Browser(&$vfs, $templates)
+    public function __construct($vfs, $templates)
     {
-        if (isset($vfs)) {
-            $this->_vfs = $vfs;
-        }
+        $this->setVFSObject($vfs);
         $this->_templates = $templates;
     }
 
     /**
      * Set the VFS object in the local object.
      *
-     * @param VFS &$vfs  A VFS object.
+     * @param VFS $vfs  A VFS object.
      */
-    function setVFSObject(&$vfs)
+    public function setVFSObject($vfs)
     {
-        $this->_vfs = &$vfs;
+        $this->_vfs = $vfs;
     }
 
     /**
@@ -56,8 +54,10 @@ class VFS_Browser {
      * @param string $path       TODO
      * @param boolean $dotfiles  TODO
      * @param boolean $dironly   TODO
+     *
+     * @throws VFS_Exception
      */
-    function getUI($path, $dotfiles = false, $dironly = false)
+    public function getUI($path, $dotfiles = false, $dironly = false)
     {
         $this->_vfs->listFolder($path, $dotfiles, $dironly);
     }
diff --git a/framework/VFS/lib/VFS/Exception.php b/framework/VFS/lib/VFS/Exception.php
new file mode 100644 (file)
index 0000000..62edcc9
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Exception class for the VFS package.
+ *
+ * Copyright 2010 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  Michael Slusarz <slusarz@horde.org>
+ * @package VFS
+ */
+class VFS_Exception extends Exception {}
index 20449d2..5733a7e 100644 (file)
  * @author  Michael Slusarz <slusarz@horde.org>
  * @package VFS
  */
-class VFS_GC {
-
+class VFS_GC
+{
     /**
      * Garbage collect files in the VFS storage system.
      *
-     * @param VFS &$vfs      The VFS object to perform garbage collection on.
+     * @param VFS $vfs       The VFS object to perform garbage collection on.
      * @param string $path   The VFS path to clean.
      * @param integer $secs  The minimum amount of time (in seconds) required
      *                       before a file is removed.
      */
-    function gc(&$vfs, $path, $secs = 345600)
+    public function gc($vfs, $path, $secs = 345600)
     {
         /* A 1% chance we will run garbage collection during a call. */
         if (rand(0, 99) != 0) {
@@ -33,15 +33,14 @@ class VFS_GC {
         }
 
         /* Make sure cleaning is done recursively. */
-        $files = $vfs->listFolder($path, null, true, false, true);
-        if (!is_a($files, 'PEAR_Error') && is_array($files)) {
+        try {
             $modtime = time() - $secs;
-            foreach ($files as $val) {
+            foreach ($vfs->listFolder($path, null, true, false, true) as $val) {
                 if ($val['date'] < $modtime) {
                     $vfs->deleteFile($path, $val['name']);
                 }
             }
-        }
+        } catch (VFS_Exception $e) {}
     }
 
 }
index 4ecb070..628acf9 100644 (file)
  * @author  Jon Wood <jon@jellybob.co.uk>
  * @package VFS
  */
-class VFS_ListItem {
-
+class VFS_ListItem
+{
     /**
-     * VFS path
+     * VFS path.
      *
      * @var string
      */
-    var $_path;
+    protected $_path;
 
     /**
-     * Filename
+     * Filename.
      *
      * @var string
      */
-    var $_name;
+    protected $_name;
 
     /**
-     * File permissions (*nix format: drwxrwxrwx)
+     * File permissions (*nix format: drwxrwxrwx).
      *
      * @var string
      */
-    var $_perms;
+    protected $_perms;
 
     /**
-     * Owner user
+     * Owner user.
      *
      * @var string
      */
-    var $_owner;
+    protected $_owner;
 
     /**
-     * Owner group
+     * Owner group.
      *
      * @var string
      */
-    var $_group;
+    protected $_group;
 
     /**
      * Size.
      *
      * @var string
      */
-    var $_size;
+    protected. $_size;
 
     /**
      * Last modified date.
      *
      * @var string
      */
-    var $_date;
+    protected $_date;
 
     /**
-     * Type
-     *   .*      --  File extension
-     *   **none  --  Unrecognized type
-     *   **sym   --  Symlink
-     *   **dir   --  Directory
+     * Type.
+     * <pre>
+     * .*     - File extension
+     * **none - Unrecognized type
+     * **sym  - Symlink
+     * **dir  - Directory
+     * </pre>
      *
      * @var string
      */
-    var $_type;
+    protected $_type;
 
     /**
      * Type of target if type is '**sym'.
      * NB. Not all backends are capable of distinguishing all of these.
-     *   .*        --  File extension
-     *   **none    --  Unrecognized type
-     *   **sym     --  Symlink to a symlink
-     *   **dir     --  Directory
-     *   **broken  --  Target not found - broken link
+     * <pre>
+     * .*       - File extension
+     * **none   - Unrecognized type
+     * **sym    - Symlink to a symlink
+     * **dir    - Directory
+     * **broken - Target not found - broken link
+     * </pre>
      *
      * @var string
      */
-    var $_linktype;
+    protected $_linktype;
 
     /**
      * Constructor
@@ -94,7 +98,7 @@ class VFS_ListItem {
      * @param string $path      The path to the file.
      * @param array $fileArray  An array of file properties.
      */
-    function VFS_ListItem($path, $fileArray)
+    public function _-construct($path, $fileArray)
     {
         $this->_path = $path . '/' . $fileArray['name'];
         $this->_name = $fileArray['name'];
index e5d3b94..da25ffc 100644 (file)
@@ -1,7 +1,4 @@
 <?php
-
-require_once dirname(__FILE__) . '/../VFS.php';
-
 /**
  * A wrapper for the VFS class to return objects, instead of arrays.
  *
@@ -13,102 +10,93 @@ require_once dirname(__FILE__) . '/../VFS.php';
  * @author  Jon Wood <jon@jellybob.co.uk>
  * @package VFS
  */
-class VFS_Object {
-
+class VFS_Object
+{
     /**
-     * The actual vfs that does the work
+     * The actual vfs object that does the work.
      *
      * @var VFS
      */
-    var $_vfs;
+    protected $_vfs;
 
     /**
-     * The current path that has been passed to listFolder, if this
+     * The current path that has been passed to listFolder(), if this
      * changes, the list will be rebuilt.
      *
      * @var string
      */
-    var $_currentPath;
+    protected $_currentPath;
 
     /**
-     * The return value from a standard VFS listFolder call, to
-     * be read with the Object listFolder.
+     * The return value from a standard VFS listFolder() call, to
+     * be read with the Object listFolder().
      *
      * @var array
      */
-    var $_folderList;
+    protected $_folderList;
 
     /**
-     * Constructor.
+     * Attempts to return a reference to a concrete instance
+     * based on $driver. It will only create a new instance if no
+     * VFS instance with the same parameters currently exists.
      *
-     * If you pass in an existing VFS object, it will be used as the VFS
-     * object for this object.
+     * 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_Object::singleton();
+     *
+     * @param mixed $driver  The type of concrete subclass to return.
+     * @param array $params  A hash containing any additional configuration or
+     *                       connection parameters a subclass might need.
      *
-     * @param VFS &$vfs  The VFS object to wrap.
+     * @return VFS_Object  The concrete VFS_Object reference.
+     * @throws VFS_Exception
      */
-    function VFS_Object(&$vfs)
+    static public function singleton($driver, $params = array())
     {
-        if (isset($vfs)) {
-            $this->_vfs = $vfs;
-        }
+        require_once dirname(__FILE__) . '/../VFS.php';
+        $classname = __CLASS__;
+        return new $classname(VFS::singleton($driver, $params = array()));
     }
 
     /**
-     * Attempts to return a concrete VFS_Object instance based on $driver.
+     * Attempts to return a concrete instance based on $driver.
      *
-     * @param mixed $driver  The type of concrete VFS subclass to return. If
-     *                       $driver is an array then we will look in
-     *                       $driver[0]/lib/VFS/ for the subclass
-     *                       implementation named $driver[1].php.
+     * @param mixed $driver  The type of concrete subclass to return.
      * @param array $params  A hash containing any additional configuration or
      *                       connection parameters a subclass might need.
      *
-     * @return VFS_Object  The newly created concrete VFS_Object instance, or
-     *                     false on an error.
+     * @return VFS_Object  The newly created concrete VFS_Object instance.
+     * @throws VFS_Exception
      */
-    function &factory($driver, $params = array())
+    static public function factory($driver, $params = array())
     {
-        $vfs = &VFS::factory($driver, $params = array());
-        $vfsobject = new VFS_Object($vfs);
-        return $vfsobject;
+        return self::singleton($driver, $params);
     }
 
     /**
-     * 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()
+     * Constructor.
      *
-     * @param mixed $driver  The type of concrete VFS subclass to return. If
-     *                       $driver is an array then we will look in
-     *                       $driver[0]/lib/VFS/ for the subclass
-     *                       implementation named $driver[1].php.
-     * @param array $params  A hash containing any additional configuration or
-     *                       connection parameters a subclass might need.
+     * If you pass in an existing VFS object, it will be used as the VFS
+     * object for this object.
      *
-     * @return VFS_Object  The concrete VFS_Object reference, or false on
-     *                     error.
+     * @param VFS $vfs  The VFS object to wrap.
      */
-    function &singleton($driver, $params = array())
+    public function __construct($vfs)
     {
-        $vfs = &VFS::singleton($driver, $params = array());
-        $vfsobject = new VFS_Object($vfs);
-        return $vfsobject;
+        if (isset($vfs)) {
+            $this->_vfs = $vfs;
+        }
     }
 
     /**
      * Check the credentials that we have to see if there is a valid login.
      *
-     * @return mixed  True on success, PEAR_Error describing the problem
-     *                if the credentials are invalid.
+     * @throws VFS_Exception;
      */
-    function checkCredentials()
+    public function checkCredentials()
     {
-        return $this->_vfs->checkCredentials();
+        $this->_vfs->checkCredentials();
     }
 
     /**
@@ -117,7 +105,7 @@ class VFS_Object {
      * @param array $params  An associative array of parameter name/value
      *                       pairs.
      */
-    function setParams($params = array())
+    public function setParams($params = array())
     {
         $this->_vfs->setParams($params);
     }
@@ -128,8 +116,9 @@ class VFS_Object {
      * @param string $path  The pathname to the file.
      *
      * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function read($path)
+    public function read($path)
     {
         return $this->_vfs->read(dirname($path), basename($path));
     }
@@ -142,11 +131,11 @@ class VFS_Object {
      *                             stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $tmpFile, $autocreate = false)
+    public function write($path, $tmpFile, $autocreate = false)
     {
-        return $this->_vfs->write(dirname($path), basename($path), $tmpFile, $autocreate = false);
+        $this->_vfs->write(dirname($path), basename($path), $tmpFile, $autocreate);
     }
 
     /**
@@ -156,11 +145,11 @@ class VFS_Object {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $data, $autocreate = false)
+    public function writeData($path, $data, $autocreate = false)
     {
-        return $this->_vfs->writeData(dirname($path), basename($path), $data, $autocreate = false);
+        $this->_vfs->writeData(dirname($path), basename($path), $data, $autocreate);
     }
 
     /**
@@ -169,11 +158,11 @@ class VFS_Object {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path)
+    public function deleteFile($path)
     {
-        return $this->_vfs->deleteFile(dirname($path), basename($path));
+        $this->_vfs->deleteFile(dirname($path), basename($path));
     }
 
     /**
@@ -184,9 +173,9 @@ class VFS_Object {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $newpath)
+    public function rename($oldpath, $newpath)
     {
         return $this->_vfs->rename(dirname($oldpath), basename($oldpath), dirname($newpath), basename($newpath));
     }
@@ -196,11 +185,11 @@ class VFS_Object {
      *
      * @param string $path  The path to the folder.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function createFolder($path)
+    public function createFolder($path)
     {
-        return $this->_vfs->createFolder(dirname($path));
+        $this->_vfs->createFolder(dirname($path));
     }
 
     /**
@@ -208,11 +197,11 @@ class VFS_Object {
      *
      * @param string $path The path of the folder to delete.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path)
+    public function deleteFolder($path)
     {
-        return $this->_vfs->deleteFolder(dirname($path));
+        $this->_vfs->deleteFolder(dirname($path));
     }
 
     /**
@@ -222,11 +211,11 @@ class VFS_Object {
      *
      * @param string $path  The path of the diretory.
      *
-     * @return mixed  File list (array) on success, a PEAR_Error
-     *                object on failure, or false if the folder is
+     * @return mixed  File list (array) on success or false if the folder is
      *                completely read.
+     * @throws VFS_Exception
      */
-    function listFolder($path)
+    public function listFolder($path)
     {
         if (!($path === $this->_currentPath)) {
             $folderList = $this->_vfs->listFolder($path);
@@ -234,17 +223,15 @@ class VFS_Object {
                 $this->_folderList = $folderList;
                 $this->_currentPath = $path;
             } else {
-                return PEAR::raiseError(sprintf(_("Could not read %s."), $path));
+                require_once dirname(__FILE__) . '/Exception.php';
+                throw new VFS_Exception('Could not read ' . $path . '.');
             }
         }
 
         require_once dirname(__FILE__) . '/ListItem.php';
-        if ($file = array_shift($this->_folderList)) {
-            $file = new VFS_ListItem($path, $file);
-            return $file;
-        } else {
-            return false;
-        }
+        return ($file = array_shift($this->_folderList))
+            ? new VFS_ListItem($path, $file)
+            : false;
     }
 
     /**
@@ -253,11 +240,11 @@ class VFS_Object {
      * @param string $path        Holds the path of directory of the Item.
      * @param string $permission  TODO
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function changePermissions($path, $permission)
+    public function changePermissions($path, $permission)
     {
-        return $this->_vfs->changePermissions(dirname($path), basename($path), $permission);
+        $this->_vfs->changePermissions(dirname($path), basename($path), $permission);
     }
 
     /**
@@ -265,7 +252,7 @@ class VFS_Object {
      *
      * @return array  Credential list.
      */
-    function getRequiredCredentials()
+    public function getRequiredCredentials()
     {
         return $this->_vfs->getRequiredCredentials();
     }
@@ -276,7 +263,7 @@ class VFS_Object {
      *
      * @return array  Changeable permisions.
      */
-    function getModifiablePermissions()
+    public function getModifiablePermissions()
     {
         return $this->_vfs->getModifiablePermissions();
     }
index 76d1af2..5367b97 100644 (file)
@@ -2,8 +2,10 @@
 /**
  * VFS implementation for a standard filesystem.
  *
- * Required parameters:<pre>
- *   'vfsroot'  The root path</pre>
+ * Required parameters:
+ * <pre>
+ * 'vfsroot' - (string) The root path.
+ * </pre>
  *
  * Note: The user that your webserver runs as (commonly 'nobody',
  * 'apache', or 'www-data') MUST have read/write permission to the
  * @author  Chuck Hagenbuch
  * @package VFS
  */
-class VFS_file extends VFS {
-
+class VFS_file extends VFS
+{
     /**
-     * List of permissions and if they can be changed in this VFS
-     * backend.
+     * List of permissions and if they can be changed in this VFS backend.
      *
      * @var array
      */
-    var $_permissions = array(
-        'owner' => array('read' => true, 'write' => true, 'execute' => true),
-        'group' => array('read' => true, 'write' => true, 'execute' => true),
-        'all'   => array('read' => true, 'write' => true, 'execute' => true)
+    protected $_permissions = array(
+        'owner' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        ),
+        'group' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        ),
+        'all' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        )
     );
 
     /**
@@ -36,15 +49,14 @@ class VFS_file extends VFS {
      *
      * @param array $params  A hash containing connection parameters.
      */
-    function VFS_file($params = array())
+    public function __construct($params = array())
     {
-        parent::VFS($params);
+        parent::__construct($params);
 
-        if (!empty($this->_params['vfsroot'])) {
-            if (substr($this->_params['vfsroot'], -1) == '/' ||
-                substr($this->_params['vfsroot'], -1) == '\\') {
-                $this->_params['vfsroot'] = substr($this->_params['vfsroot'], 0, strlen($this->_params['vfsroot']) - 1);
-            }
+        if (!empty($this->_params['vfsroot']) &&
+            ((substr($this->_params['vfsroot'], -1) == '/') ||
+             (substr($this->_params['vfsroot'], -1) == '\\'))) {
+            $this->_params['vfsroot'] = substr($this->_params['vfsroot'], 0, strlen($this->_params['vfsroot']) - 1);
         }
     }
 
@@ -54,14 +66,15 @@ class VFS_file extends VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return integer The file size.
+     * @return integer  The file size.
+     * @throws VFS_Exception
      */
-    function size($path, $name)
+    public function size($path, $name)
     {
-        $size = @filesize($this->_getNativePath($path, $name));
-        if ($size === false) {
-            return PEAR::raiseError(sprintf(_("Unable to check file size of \"%s/%s\"."), $path, $name));
+        if (($size = @filesize($this->_getNativePath($path, $name))) === false) {
+            throw new VFS_Exception(sprintf('Unable to check file size of "%s/%s".'), $path, $name);
         }
+
         return $size;
     }
 
@@ -72,12 +85,12 @@ class VFS_file extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
-        $data = @file_get_contents($this->_getNativePath($path, $name));
-        if ($data === false) {
-            return PEAR::raiseError(_("Unable to open VFS file."));
+        if (($data = @file_get_contents($this->_getNativePath($path, $name))) === false) {
+            throw new VFS_Exception('Unable to open VFS file.');
         }
 
         return $data;
@@ -95,7 +108,7 @@ class VFS_file extends VFS {
      *
      * @return string A local filename.
      */
-    function readFile($path, $name)
+    public function readFile($path, $name)
     {
         return $this->_getNativePath($path, $name);
     }
@@ -107,13 +120,14 @@ class VFS_file extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return resource  The stream.
+     * @throws VFS_Exception
      */
-    function readStream($path, $name)
+    public function readStream($path, $name)
     {
         $mode = OS_WINDOWS ? 'rb' : 'r';
         $stream = @fopen($this->_getNativePath($path, $name), $mode);
         if (!is_resource($stream)) {
-            return PEAR::raiseError(_("Unable to open VFS file."));
+            throw new VFS_Exception('Unable to open VFS file.');
         }
 
         return $stream;
@@ -124,8 +138,6 @@ class VFS_file extends VFS {
      * reading large files which would exceed the PHP memory limits if they
      * were stored in a string.
      *
-     * @abstract
-     *
      * @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
@@ -138,19 +150,21 @@ class VFS_file extends VFS {
      * @param integer $remaining  The bytes that are left, after the part that
      *                            is retrieved.
      *
-     * @return string The file data.
+     * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function readByteRange($path, $name, &$offset, $length = -1, &$remaining)
+    public function readByteRange($path, $name, &$offset, $length = -1,
+                                  &$remaining)
     {
         if ($offset < 0) {
-            return PEAR::raiseError(sprintf(_("Wrong offset %d while reading a VFS file."), $offset));
+            throw new VFS_Exception(sprintf('Wrong offset %d while reading a VFS file.', $offset));
         }
 
         // Calculate how many bytes MUST be read, so the remainging
         // bytes and the new offset can be calculated correctly.
         $file = $this->_getNativePath($path, $name);
         $size = filesize ($file);
-        if ($length == -1 || (($length + $offset) > $size)) {
+        if (($length == -1) || (($length + $offset) > $size)) {
             $length = $size - $offset;
         }
         if ($remaining < 0) {
@@ -159,7 +173,7 @@ class VFS_file extends VFS {
 
         $fp = @fopen($file, 'rb');
         if (!$fp) {
-            return PEAR::raiseError(_("Unable to open VFS file."));
+            throw new VFS_Exception('Unable to open VFS file.');
         }
         fseek($fp, $offset);
         $data = fread($fp, $length);
@@ -181,34 +195,26 @@ class VFS_file extends VFS {
      *                             stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = true)
+    public function write($path, $name, $tmpFile, $autocreate = true)
     {
         if (!@is_dir($this->_getNativePath($path))) {
             if ($autocreate) {
-                $res = $this->autocreatePath($path);
-                if (is_a($res, 'PEAR_Error')) {
-                    return $res;
-                }
+                $this->autocreatePath($path);
             } else {
-                return PEAR::raiseError(_("VFS directory does not exist."));
+                throw new VFS_Exception('VFS directory does not exist.');
             }
         }
 
-        $res = $this->_checkQuotaWrite('file', $tmpFile);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaWrite('file', $tmpFile);
 
         // Since we already have the data in a file, don't read it
         // into PHP's memory at all - just copy() it to the new
         // location. We leave it to the caller to clean up the
         // temporary file, so we don't use rename().
-        if (@copy($tmpFile, $this->_getNativePath($path, $name))) {
-            return true;
-        } else {
-            return PEAR::raiseError(_("Unable to write VFS file (copy() failed)."));
+        if (!@copy($tmpFile, $this->_getNativePath($path, $name))) {
+            throw new VFS_Exception('Unable to write VFS file (copy() failed).');
         }
     }
 
@@ -220,37 +226,28 @@ class VFS_file extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function move($path, $name, $dest, $autocreate = false)
+    public function move($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getNativePath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
+            throw new VFS_Exception('Cannot move file(s) - destination is within source.');
         }
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, false);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, false) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(_("Unable to move VFS file."));
+                throw new VFS_Exception('Unable to move VFS file.');
             }
         }
 
         if (!@rename($orig, $this->_getNativePath($dest, $name))) {
-            return PEAR::raiseError(_("Unable to move VFS file."));
+            throw new VFS_Exception('Unable to move VFS file.');
         }
-
-        return true;
     }
 
     /**
@@ -261,42 +258,30 @@ class VFS_file extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function copy($path, $name, $dest, $autocreate = false)
+    public function copy($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getNativePath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
+            throw new VFS_Exception('Cannot copy file(s) - source and destination are the same.');
         }
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, false);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, false) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(_("Unable to copy VFS file."));
+                throw new VFS_Exception('Unable to copy VFS file.');
             }
         }
 
-        $res = $this->_checkQuotaWrite('file', $orig);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaWrite('file', $orig);
 
         if (!@copy($orig, $this->_getNativePath($dest, $name))) {
-            return PEAR::raiseError(_("Unable to copy VFS file."));
+            throw new VFS_Exception('Unable to copy VFS file.');
         }
-
-        return true;
     }
 
     /**
@@ -307,18 +292,15 @@ class VFS_file extends VFS {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = true)
+    public function writeData($path, $name, $data, $autocreate = true)
     {
         if (!@is_dir($this->_getNativePath($path))) {
             if ($autocreate) {
-                $res = $this->autocreatePath($path);
-                if (is_a($res, 'PEAR_Error')) {
-                    return $res;
-                }
+                $this->autocreatePath($path);
             } else {
-                return PEAR::raiseError(_("VFS directory does not exist."));
+                throw new VFS_Exception('VFS directory does not exist.');
             }
         }
 
@@ -326,34 +308,17 @@ class VFS_file extends VFS {
         // since otherwise the file will not be created at all.
         if (!strlen($data)) {
             if (@touch($this->_getNativePath($path, $name))) {
-                return true;
-            } else {
-                return PEAR::raiseError(_("Unable to create empty VFS file."));
+                return;
             }
+            throw new VFS_Exception('Unable to create empty VFS file.');
         }
 
-        $res = $this->_checkQuotaWrite('string', $data);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaWrite('string', $data);
 
         // Otherwise we go ahead and try to write out the file.
-        if (function_exists('file_put_contents')) {
-            if (!@file_put_contents($this->_getNativePath($path, $name), $data)) {
-                return PEAR::raiseError(_("Unable to write VFS file data."));
-            }
-        } else {
-            $fp = @fopen($this->_getNativePath($path, $name), 'w');
-            if (!$fp) {
-                return PEAR::raiseError(_("Unable to open VFS file for writing."));
-            }
-
-            if (!@fwrite($fp, $data)) {
-                return PEAR::raiseError(_("Unable to write VFS file data."));
-            }
+        if (!@file_put_contents($this->_getNativePath($path, $name), $data)) {
+            throw new VFS_Exception('Unable to write VFS file data.');
         }
-
-        return true;
     }
 
     /**
@@ -362,20 +327,15 @@ class VFS_file extends 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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        $res = $this->_checkQuotaDelete($path, $name);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaDelete($path, $name);
 
         if (!@unlink($this->_getNativePath($path, $name))) {
-            return PEAR::raiseError(_("Unable to delete VFS file."));
+            throw new VFS_Exception('Unable to delete VFS file.');
         }
-
-        return true;
     }
 
     /**
@@ -385,31 +345,22 @@ class VFS_file extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
         if ($recursive) {
-            $result = $this->emptyFolder($path . '/' . $name);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->emptyFolder($path . '/' . $name);
         } else {
             $list = $this->listFolder($path . '/' . $name);
-            if (is_a($list, 'PEAR_Error')) {
-                return $list;
-            }
             if (count($list)) {
-                return PEAR::raiseError(sprintf(_("Unable to delete %s, the directory is not empty"),
-                                                $path . '/' . $name));
+                throw new VFS_Exception(sprintf('Unable to delete %s, the directory is not empty', $path . '/' . $name));
             }
         }
 
         if (!@rmdir($this->_getNativePath($path, $name))) {
-            return PEAR::raiseError(_("Unable to delete VFS directory."));
+            throw new VFS_Exception('Unable to delete VFS directory.');
         }
-
-        return true;
     }
 
     /**
@@ -418,15 +369,13 @@ class VFS_file extends VFS {
      * @param string $path  The path to create the folder in.
      * @param string $name  The foldername to use.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
         if (!@mkdir($this->_getNativePath($path, $name))) {
-            return PEAR::raiseError(_("Unable to create VFS directory."));
+            throw new VFS_Exception('Unable to create VFS directory.');
         }
-
-        return true;
     }
 
     /**
@@ -437,7 +386,7 @@ class VFS_file extends VFS {
      *
      * @return boolean  True if it is a folder, false otherwise.
      */
-    function isFolder($path, $name)
+    public function isFolder($path, $name)
     {
         return @is_dir($this->_getNativePath($path, $name));
     }
@@ -449,15 +398,13 @@ class VFS_file extends VFS {
      * @param string $name         The name of the item.
      * @param integer $permission  The octal value of the new permission.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function changePermissions($path, $name, $permission)
+    public function changePermissions($path, $name, $permission)
     {
         if (!@chmod($this->_getNativePath($path, $name), $permission)) {
-            return PEAR::raiseError(sprintf(_("Unable to change permission for VFS file %s/%s."), $path, $name));
+            throw new VFS_Exception(sprintf('Unable to change permission for VFS file %s/%s.', $path, $name));
         }
-
-        return true;
     }
 
     /**
@@ -468,24 +415,25 @@ class VFS_file extends VFS {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show only directories?
      *
-     * @return array  File list on success, PEAR_Error on error.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path, $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path, $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
         $files = array();
-        $path = isset($path) ? $this->_getNativePath($path) : $this->_getNativePath();
+        $path = $this->_getNativePath(isset($path) ? $path : '');
 
         if (!@is_dir($path)) {
-            return PEAR::raiseError(_("Not a directory"));
+            throw new VFS_Exception('Not a directory');
         }
 
         if (!@chdir($path)) {
-            return PEAR::raiseError(_("Unable to access VFS directory."));
+            throw new VFS_Exception('Unable to access VFS directory.');
         }
 
-        $handle = opendir($path);
-        while (($entry = readdir($handle)) !== false) {
+        $d = dir($path);
+        while (($entry = $d->read()) !== false) {
             // Filter out '.' and '..' entries.
             if ($entry == '.' || $entry == '..') {
                 continue;
@@ -511,11 +459,9 @@ class VFS_file extends VFS {
 
             // Group
             $file['group'] = filegroup($entry);
-            if (function_exists('posix_getgrgid')) {
-                if (PHP_VERSION != '5.2.1') {
-                    $group = posix_getgrgid($file['group']);
-                    $file['group'] = $group['name'];
-                }
+            if (function_exists('posix_getgrgid') && (PHP_VERSION != '5.2.1')) {
+                $group = posix_getgrgid($file['group']);
+                $file['group'] = $group['name'];
             }
 
             // Size
@@ -542,7 +488,7 @@ class VFS_file extends VFS {
                     } elseif (is_file($file['link'])) {
                         $ext = explode('.', $file['link']);
                         if (!(count($ext) == 1 || ($ext[0] === '' && count($ext) == 2))) {
-                            $file['linktype'] = VFS::strtolower($ext[count($ext) - 1]);
+                            $file['linktype'] = self::strtolower($ext[count($ext) - 1]);
                         }
                     }
                 } else {
@@ -555,7 +501,7 @@ class VFS_file extends VFS {
                 if (count($ext) == 1 || (substr($file['name'], 0, 1) === '.' && count($ext) == 2)) {
                     $file['type'] = '**none';
                 } else {
-                    $file['type'] = VFS::strtolower($ext[count($ext) - 1]);
+                    $file['type'] = self::strtolower($ext[count($ext) - 1]);
                 }
             } else {
                 $file['type'] = '**none';
@@ -586,6 +532,8 @@ class VFS_file extends VFS {
             unset($file);
         }
 
+        $d->close();
+
         return $files;
     }
 
@@ -597,29 +545,27 @@ class VFS_file extends VFS {
      * @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.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
     function listFolders($path = '', $filter = null, $dotfolders = true)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $folders = array();
-        $folders[dirname($path)] = array('val' => dirname($path),
-                                         'abbrev' => '..',
-                                         'label' => '..');
+        $folders[dirname($path)] = array(
+            'val' => dirname($path),
+            'abbrev' => '..',
+            'label' => '..'
+        );
 
         $folderList = $this->listFolder($path, null, $dotfolders, true);
-        if (is_a($folderList, 'PEAR_Error')) {
-            return $folderList;
-        }
-
         foreach ($folderList as $name => $files) {
-            $folders[$name] = array('val' => $path . '/' . $files['name'],
-                                    'abbrev' => $files['name'],
-                                    'label' => $path . '/' . $files['name']);
+            $folders[$name] = array(
+                'val' => $path . '/' . $files['name'],
+                'abbrev' => $files['name'],
+                'label' => $path . '/' . $files['name']
+            );
         }
 
         ksort($folders);
@@ -630,13 +576,11 @@ class VFS_file extends VFS {
     /**
      * Return Unix style perms.
      *
-     * @access private
-     *
      * @param integer $perms  The permissions to set.
      *
      * @return string  Unix style perms.
      */
-    function _getUnixPerms($perms)
+    protected function _getUnixPerms($perms)
     {
         // Determine permissions
         $owner['read']    = ($perms & 00400) ? 'r' : '-';
@@ -660,11 +604,9 @@ class VFS_file extends VFS {
             $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
         }
 
-        $unixPerms = $owner['read'] . $owner['write'] . $owner['execute'] .
-                     $group['read'] . $group['write'] . $group['execute'] .
-                     $world['read'] . $world['write'] . $world['execute'];
-
-        return $unixPerms;
+        return $owner['read'] . $owner['write'] . $owner['execute'] .
+               $group['read'] . $group['write'] . $group['execute'] .
+               $world['read'] . $world['write'] . $world['execute'];
     }
 
     /**
@@ -675,22 +617,18 @@ class VFS_file extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
         if (!@is_dir($this->_getNativePath($newpath))) {
-            if (is_a($res = $this->autocreatePath($newpath), 'PEAR_Error')) {
-                return $res;
-            }
+            $this->autocreatePath($newpath);
         }
 
         if (!@rename($this->_getNativePath($oldpath, $oldname),
                      $this->_getNativePath($newpath, $newname))) {
-            return PEAR::raiseError(sprintf(_("Unable to rename VFS file %s/%s."), $oldpath, $oldname));
+            throw new VFS_Exception(sprintf('Unable to rename VFS file %s/%s.', $oldpath, $oldname));
         }
-
-        return true;
     }
 
     /**
@@ -701,7 +639,7 @@ class VFS_file extends VFS {
      *
      * @return boolean  True if it exists, false otherwise.
      */
-    function exists($path, $name)
+    public function exists($path, $name)
     {
         return file_exists($this->_getNativePath($path, $name));
     }
@@ -710,14 +648,12 @@ class VFS_file extends VFS {
      * Return a full filename on the native filesystem, from a VFS
      * path and name.
      *
-     * @access private
-     *
      * @param string $path  The VFS file path.
      * @param string $name  The VFS filename.
      *
      * @return string  The full native filename.
      */
-    function _getNativePath($path = '', $name = '')
+    protected function _getNativePath($path = '', $name = '')
     {
         $name = basename($name);
         if (strlen($name)) {
@@ -739,27 +675,23 @@ class VFS_file extends VFS {
             } else {
                 return $this->_params['vfsroot'] . '/' . $path . $name;
             }
-        } else {
-            return $this->_params['vfsroot'] . $name;
         }
+
+        return $this->_params['vfsroot'] . $name;
     }
 
     /**
      * Stub to check if we have a valid connection. Makes sure that
      * the vfsroot is readable.
      *
-     * @access private
-     *
-     * @return mixed  True if vfsroot is readable, PEAR_Error if it isn't.
+     * @throws VFS_Exception
      */
-    function _connect()
+    protected function _connect()
     {
-        if ((@is_dir($this->_params['vfsroot']) &&
-             is_readable($this->_params['vfsroot'])) ||
-            @mkdir($this->_params['vfsroot'])) {
-            return true;
-        } else {
-            return PEAR::raiseError(_("Unable to read the vfsroot directory."));
+        if (!(@is_dir($this->_params['vfsroot']) &&
+              is_readable($this->_params['vfsroot'])) ||
+            !@mkdir($this->_params['vfsroot'])) {
+            throw new VFS_Exception('Unable to read the vfsroot directory.');
         }
     }
 
index 0173572..bfdca4b 100644 (file)
@@ -3,30 +3,28 @@
  * VFS implementation for an FTP server.
  *
  * Required values for $params:<pre>
- *      'username'       The username with which to connect to the ftp server.
- *      'password'       The password with which to connect to the ftp server.
- *      'hostspec'       The ftp server to connect to.</pre>
+ * username - (string) The username with which to connect to the ftp server.
+ * password - (string) The password with which to connect to the ftp server.
+ * hostspec - (string) The ftp server to connect to.</pre>
  *
  * Optional values for $params:<pre>
- *      'lsformat'       The return formatting from the 'ls' command).
+ * lsformat - (string) The return formatting from the 'ls' command).
  *                       Values: 'aix', 'standard' (default)
- *      'maplocalids'    If true and the POSIX extension is available, the
- *                       driver will map the user and group IDs returned from
- *                       the FTP server with the local IDs from the local
- *                       password file.  This is useful only if the FTP server
- *                       is running on localhost or if the local user/group
- *                       IDs are identical to the remote FTP server.
- *      'pasv'           If true, connection will be set to passive mode.
- *      'port'           The port used to connect to the ftp server if other
- *                       than 21.
- *      'ssl'            If true, and PHP had been compiled with OpenSSL
- *                       support, TLS transport-level encryption will be
- *                       negotiated with the server.
- *      'timeout'        If defined, use this value as the timeout for the
- *                       server.
- *      'type'           The type of the remote FTP server.
- *                       Possible values: 'unix', 'win', 'netware'
- *                       By default, we attempt to auto-detect type.</pre>
+ * maplocalids - (boolean) If true and the POSIX extension is available, the
+ *               driver will map the user and group IDs returned from the FTP
+ *               server with the local IDs from the local password file.  This
+ *               is useful only if the FTP server is running on localhost or
+ *               if the local user/group IDs are identical to the remote FTP
+ *               server.
+ * pasv - (boolean) If true, connection will be set to passive mode.
+ * port - (integer) The port used to connect to the ftp server if other than
+ *        21 (FTP default).
+ * ssl - (boolean) If true, and PHP had been compiled with OpenSSL support,
+ *        TLS transport-level encryption will be negotiated with the server.
+ * timeout -(integer) The timeout for the server.
+ * type - (string) The type of the remote FTP server.
+ *        Possible values: 'unix', 'win', 'netware'
+ *        By default, we attempt to auto-detect type.</pre>
  *
  * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
  * Copyright 2002-2007 Michael Varghese <mike.varghese@ascellatech.com>
  * @author  Michael Varghese <mike.varghese@ascellatech.com>
  * @package VFS
  */
-class VFS_ftp extends VFS {
-
+class VFS_ftp extends VFS
+{
     /**
      * List of additional credentials required for this VFS backend.
      *
      * @var array
      */
-    var $_credentials = array('username', 'password');
+    protected $_credentials = array('username', 'password');
 
     /**
      * List of permissions and if they can be changed in this VFS backend.
      *
      * @var array
      */
-    var $_permissions = array(
-        'owner' => array('read' => true, 'write' => true, 'execute' => true),
-        'group' => array('read' => true, 'write' => true, 'execute' => true),
-        'all'   => array('read' => true, 'write' => true, 'execute' => true));
+    protected $_permissions = array(
+        'owner' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        ),
+        'group' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        ),
+        'all' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        )
+    );
 
     /**
      * Variable holding the connection to the ftp server.
      *
      * @var resource
      */
-    var $_stream = false;
+    protected $_stream = false;
 
     /**
      * Local cache array for user IDs.
      *
      * @var array
      */
-    var $_uids = array();
+    protected $_uids = array();
 
     /**
      * Local cache array for group IDs.
      *
      * @var array
      */
-    var $_gids = array();
+    protected $_gids = array();
 
     /**
+     * The FTP server type.
+     *
+     * @var string
      */
-    var $_type;
+    protected $_type;
 
     /**
      * Returns the size of a file.
      *
-     * @access public
-     *
      * @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
-     *                  failure.
+     * @return integer  The size of the file in bytes.
+     * @throws VFS_Exception
      */
-    function size($path, $name)
+    public function size($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if (($size = @ftp_size($this->_stream, $this->_getPath($path, $name))) === false) {
-            return PEAR::raiseError(sprintf(_("Unable to check file size of \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to check file size of "%s".', $this->_getPath($path, $name)));
         }
 
         return $size;
@@ -115,19 +124,14 @@ class VFS_ftp extends VFS {
      *
      * @return string  The file data.
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
         $file = $this->readFile($path, $name);
-        if (is_a($file, 'PEAR_Error')) {
-            return $file;
-        }
-
         $size = filesize($file);
-        if ($size === 0) {
-            return '';
-        }
 
-        return file_get_contents($file);
+        return ($size === 0)
+            ? ''
+            : file_get_contents($file);
     }
 
     /**
@@ -140,20 +144,17 @@ class VFS_ftp extends VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return string A local filename.
+     * @return string  A local filename.
+     * @throws VFS_Exception
      */
-    function readFile($path, $name)
+    public function readFile($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         // Create a temporary file and register it for deletion at the
         // end of this request.
-        $localFile = $this->_getTempFile();
-        if (!$localFile) {
-            return PEAR::raiseError(_("Unable to create temporary file."));
+        if (!($localFile = tempnam(null, 'vfs'))) {
+            throw new VFS_Exception('Unable to create temporary file.');
         }
         register_shutdown_function(create_function('', '@unlink(\'' . addslashes($localFile) . '\');'));
 
@@ -162,8 +163,9 @@ class VFS_ftp extends VFS {
             $localFile,
             $this->_getPath($path, $name),
             FTP_BINARY);
+
         if ($result === false) {
-            return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to open VFS file "%s".', $this->_getPath($path, $name)));
         }
 
         return $localFile;
@@ -176,16 +178,11 @@ class VFS_ftp extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return resource  The stream.
+     * @throws VFS_Exception
      */
-    function readStream($path, $name)
+    public function readStream($path, $name)
     {
-        $file = $this->readFile($path, $name);
-        if (is_a($file, 'PEAR_Error')) {
-            return $file;
-        }
-
-        $mode = OS_WINDOWS ? 'rb' : 'r';
-        return fopen($file, $mode);
+        return fopen($this->readFile($path, $name), OS_WINDOWS ? 'rb' : 'r');
     }
 
     /**
@@ -197,35 +194,23 @@ class VFS_ftp extends VFS {
      *                             be stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
-        $res = $this->_checkQuotaWrite('file', $tmpFile);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_connect();
+        $this->_checkQuotaWrite('file', $tmpFile);
 
         if (!@ftp_put($this->_stream, $this->_getPath($path, $name), $tmpFile, FTP_BINARY)) {
             if ($autocreate) {
-                $result = $this->autocreatePath($path);
-                if (is_a($result, 'PEAR_Error')) {
-                    return $result;
+                $this->autocreatePath($path);
+                if (@ftp_put($this->_stream, $this->_getPath($path, $name), $tmpFile, FTP_BINARY)) {
+                    return;
                 }
-                if (!@ftp_put($this->_stream, $this->_getPath($path, $name), $tmpFile, FTP_BINARY)) {
-                    return PEAR::raiseError(sprintf(_("Unable to write VFS file \"%s\"."), $this->_getPath($path, $name)));
-                }
-            } else {
-                return PEAR::raiseError(sprintf(_("Unable to write VFS file \"%s\"."), $this->_getPath($path, $name)));
             }
-        }
 
-        return true;
+            throw new VFS_Exception(sprintf('Unable to write VFS file "%s".', $this->_getPath($path, $name)));
+        }
     }
 
     /**
@@ -236,23 +221,19 @@ class VFS_ftp extends VFS {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        $res = $this->_checkQuotaWrite('string', $data);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
+        $this->_checkQuotaWrite('string', $data);
+        file_put_contents(tempnam('null', 'vfs'), $data);
+        try {
+            $this->write($path, $name, $tmpFile, $autocreate);
+            unlink($tmpFile);
+        } catch (VFS_Exception $e) {
+            unlink($tmpFile);
+            throw $e;
         }
-
-        $tmpFile = $this->_getTempFile();
-        $fp = fopen($tmpFile, 'wb');
-        fwrite($fp, $data);
-        fclose($fp);
-
-        $result = $this->write($path, $name, $tmpFile, $autocreate);
-        unlink($tmpFile);
-        return $result;
     }
 
     /**
@@ -261,25 +242,16 @@ class VFS_ftp extends 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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        $res = $this->_checkQuotaDelete($path, $name);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
-
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
+        $this->_checkQuotaDelete($path, $name);
 
         if (!@ftp_delete($this->_stream, $this->_getPath($path, $name))) {
-            return PEAR::raiseError(sprintf(_("Unable to delete VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to delete VFS file "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -290,22 +262,20 @@ class VFS_ftp extends VFS {
      *
      * @return boolean  True if it is a folder, false otherwise.
      */
-    function isFolder($path, $name)
+    public function isFolder($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
         $result = false;
-        $olddir = $this->getCurrentDirectory();
 
-        /* See if we can change to the given path. */
-        if (@ftp_chdir($this->_stream, $this->_getPath($path, $name))) {
-            $result = true;
-        }
+        try {
+            $this->_connect();
 
-        $this->_setPath($olddir);
+            $olddir = $this->getCurrentDirectory();
+
+            /* See if we can change to the given path. */
+            $result = @ftp_chdir($this->_stream, $this->_getPath($path, $name));
+
+            $this->_setPath($olddir);
+        } catch (VFS_Exception $e) {}
 
         return $result;
     }
@@ -317,18 +287,14 @@ class VFS_ftp extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $isDir = false;
-        $dirCheck = $this->listFolder($path);
-        foreach ($dirCheck as $file) {
+        foreach ($this->listFolder($path) as $file) {
             if ($file['name'] == $name && $file['type'] == '**dir') {
                 $isDir = true;
                 break;
@@ -337,36 +303,24 @@ class VFS_ftp extends VFS {
 
         if ($isDir) {
             $file_list = $this->listFolder($this->_getPath($path, $name));
-            if (is_a($file_list, 'PEAR_Error')) {
-                return $file_list;
-            }
-
             if (count($file_list) && !$recursive) {
-                return PEAR::raiseError(sprintf(_("Unable to delete \"%s\", the directory is not empty."),
-                                                $this->_getPath($path, $name)));
+                throw new VFS_Exception(sprintf('Unable to delete "%s", as the directory is not empty.', $this->_getPath($path, $name)));
             }
 
             foreach ($file_list as $file) {
                 if ($file['type'] == '**dir') {
-                    $result = $this->deleteFolder($this->_getPath($path, $name), $file['name'], $recursive);
+                    $this->deleteFolder($this->_getPath($path, $name), $file['name'], $recursive);
                 } else {
-                    $result = $this->deleteFile($this->_getPath($path, $name), $file['name']);
-                }
-                if (is_a($result, 'PEAR_Error')) {
-                    return $result;
+                    $this->deleteFile($this->_getPath($path, $name), $file['name']);
                 }
             }
 
             if (!@ftp_rmdir($this->_stream, $this->_getPath($path, $name))) {
-                return PEAR::raiseError(sprintf(_("Cannot remove directory \"%s\"."), $this->_getPath($path, $name)));
-            }
-        } else {
-            if (!@ftp_delete($this->_stream, $this->_getPath($path, $name))) {
-                return PEAR::raiseError(sprintf(_("Cannot delete file \"%s\"."), $this->_getPath($path, $name)));
+                throw new VFS_Exception(sprintf('Cannot remove directory "%s".', $this->_getPath($path, $name)));
             }
+        } elseif (!@ftp_delete($this->_stream, $this->_getPath($path, $name))) {
+            throw new VFS_Exception(sprintf('Cannot delete file "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -377,23 +331,16 @@ class VFS_ftp extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        if (is_a($conn = $this->_connect(), 'PEAR_Error')) {
-            return $conn;
-        }
-
-        if (is_a($result = $this->autocreatePath($newpath), 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
+        $this->autocreatePath($newpath);
 
         if (!@ftp_rename($this->_stream, $this->_getPath($oldpath, $oldname), $this->_getPath($newpath, $newname))) {
-            return PEAR::raiseError(sprintf(_("Unable to rename VFS file \"%s\"."), $this->_getPath($oldpath, $oldname)));
+            throw new VFS_Exception(sprintf('Unable to rename VFS file "%s".', $this->_getPath($oldpath, $oldname)));
         }
-
-        return true;
     }
 
     /**
@@ -402,20 +349,15 @@ class VFS_ftp extends 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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if (!@ftp_mkdir($this->_stream, $this->_getPath($path, $name))) {
-            return PEAR::raiseError(sprintf(_("Unable to create VFS directory \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to create VFS directory "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -425,20 +367,15 @@ class VFS_ftp extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function changePermissions($path, $name, $permission)
+    public function changePermissions($path, $name, $permission)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if (!@ftp_site($this->_stream, 'CHMOD ' . $permission . ' ' . $this->_getPath($path, $name))) {
-            return PEAR::raiseError(sprintf(_("Unable to change permission for VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to change permission for VFS file "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -449,23 +386,19 @@ class VFS_ftp extends VFS {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show only directories?
      *
-     * @return array  File list on success or PEAR_Error on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path = '', $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path = '', $filter = null,
+                                   $dotfiles = true, $dironly = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
-        $files = array();
+        $this->_connect();
 
         if (empty($this->_type)) {
             if (!empty($this->_params['type'])) {
                 $this->_type = $this->_params['type'];
             } else {
-                $type = VFS::strtolower(@ftp_systype($this->_stream));
+                $type = self::strtolower(@ftp_systype($this->_stream));
                 if ($type == 'unknown') {
                     // Go with unix-style listings by default.
                     $type = 'unix';
@@ -481,10 +414,7 @@ class VFS_ftp extends VFS {
 
         $olddir = $this->getCurrentDirectory();
         if (strlen($path)) {
-            $res = $this->_setPath($path);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
+            $this->_setPath($path);
         }
 
         if ($this->_type == 'unix') {
@@ -503,25 +433,20 @@ class VFS_ftp extends VFS {
 
         if (!is_array($list)) {
             if (isset($olddir)) {
-                $res = $this->_setPath($olddir);
-                if (is_a($res, 'PEAR_Error')) {
-                    return $res;
-                }
+                $this->_setPath($olddir);
             }
             return array();
         }
 
         /* If 'maplocalids' is set, check for the POSIX extension. */
-        $mapids = false;
-        if (!empty($this->_params['maplocalids']) &&
-            extension_loaded('posix')) {
-            $mapids = true;
-        }
+        $mapids = (!empty($this->_params['maplocalids']) && extension_loaded('posix'));
 
         $currtime = time();
+        $files = array();
 
         foreach ($list as $line) {
             $file = array();
+
             $item = preg_split('/\s+/', $line);
             if (($this->_type == 'unix') ||
                 (($this->_type == 'win') && !preg_match('|\d\d-\d\d-\d\d|', $item[0]))) {
@@ -570,16 +495,16 @@ class VFS_ftp extends VFS {
                     $file['type'] = '**sym';
 
                    if ($this->isFolder('', $file['link'])) {
-                              $file['linktype'] = '**dir';
-                                                    } else {
-                                                    $parts = explode('/', $file['link']);
-                                                    $name = explode('.', array_pop($parts));
-                                                    if (count($name) == 1 || ($name[0] === '' && count($name) == 2)) {
-                                                        $file['linktype'] = '**none';
-                                                        } else {
-                                                            $file['linktype'] = VFS::strtolower(array_pop($name));
-                                                            }
-                                                                   }
+                       $file['linktype'] = '**dir';
+                   } else {
+                       $parts = explode('/', $file['link']);
+                       $name = explode('.', array_pop($parts));
+                       if (count($name) == 1 || ($name[0] === '' && count($name) == 2)) {
+                           $file['linktype'] = '**none';
+                       } else {
+                           $file['linktype'] = VFS::strtolower(array_pop($name));
+                       }
+                   }
                 } elseif ($p1 === 'd') {
                     $file['type'] = '**dir';
                 } else {
@@ -587,7 +512,7 @@ class VFS_ftp extends VFS {
                     if (count($name) == 1 || (substr($file['name'], 0, 1) === '.' && count($name) == 2)) {
                         $file['type'] = '**none';
                     } else {
-                        $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                        $file['type'] = self::strtolower($name[count($name) - 1]);
                     }
                 }
                 if ($file['type'] == '**dir') {
@@ -659,7 +584,7 @@ class VFS_ftp extends VFS {
                     if (count($name) == 1 || (substr($file['name'], 0, 1) === '.' && count($name) == 2)) {
                         $file['type'] = '**none';
                     } else {
-                        $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                        $file['type'] = self::strtolower($name[count($name) - 1]);
                     }
                 }
             }
@@ -679,11 +604,9 @@ class VFS_ftp extends VFS {
         }
 
         if (isset($olddir)) {
-            $res = $this->_setPath($olddir);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
+            $this->_setPath($olddir);
         }
+
         return $files;
     }
 
@@ -695,38 +618,31 @@ class VFS_ftp extends VFS {
      * @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.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = null, $dotfolders = true)
+    public function listFolders($path = '', $filter = null, $dotfolders = true)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
-        $folders = array();
-        $folder = array();
+        $folder = array(
+            'abbrev' => '..',
+            'label' => '..',
+            'val' => $this->_parentDir($path)
+        );
+        $folders = array($folder['val'] => $folder);
 
         $folderList = $this->listFolder($path, null, $dotfolders, true);
-        if (is_a($folderList, 'PEAR_Error')) {
-            return $folderList;
-        }
-
-        $folder['val'] = $this->_parentDir($path);
-        $folder['abbrev'] = '..';
-        $folder['label'] = '..';
-
-        $folders[$folder['val']] = $folder;
-
         foreach ($folderList as $files) {
-            $folder['val'] = $this->_getPath($path, $files['name']);
-            $folder['abbrev'] = $files['name'];
-            $folder['label'] = $folder['val'];
-
-            $folders[$folder['val']] = $folder;
+            $folders[$folder['val']] = array(
+                'abbrev' => $files['name'],
+                'label' => $folder['val'],
+                'val' => $this->_getPath($path, $files['name'])
+            );
         }
 
         ksort($folders);
+
         return $folders;
     }
 
@@ -738,63 +654,46 @@ class VFS_ftp extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function copy($path, $name, $dest, $autocreate = false)
+    public function copy($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
+            throw new VFS_Exception('Cannot copy file(s) - source and destination are the same.');
         }
 
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, true);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, true) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(sprintf(_("%s already exists."), $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('%s already exists.'), $this->_getPath($dest, $name));
             }
         }
 
         if ($this->isFolder($path, $name)) {
-            if (is_a($result = $this->_copyRecursive($path, $name, $dest), 'PEAR_Error')) {
-                return $result;
-            }
+            $this->_copyRecursive($path, $name, $dest);
         } else {
-            $tmpFile = $this->_getTempFile();
+            $tmpFile = tempnam(null, 'vfs');
             $fetch = @ftp_get($this->_stream, $tmpFile, $orig, FTP_BINARY);
             if (!$fetch) {
                 unlink($tmpFile);
-                return PEAR::raiseError(sprintf(_("Failed to copy from \"%s\"."), $orig));
+                throw new VFS_Exception(sprintf('Failed to copy from "%s".', $orig));
             }
 
-            $res = $this->_checkQuotaWrite('file', $tmpFile);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
+            $this->_checkQuotaWrite('file', $tmpFile);
 
             if (!@ftp_put($this->_stream, $this->_getPath($dest, $name), $tmpFile, FTP_BINARY)) {
                 unlink($tmpFile);
-                return PEAR::raiseError(sprintf(_("Failed to copy to \"%s\"."), $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('Failed to copy to "%s".', $this->_getPath($dest, $name)));
             }
 
             unlink($tmpFile);
         }
-
-        return true;
     }
 
     /**
@@ -805,90 +704,69 @@ class VFS_ftp extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function move($path, $name, $dest, $autocreate = false)
+    public function move($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
+            throw new VFS_Exception('Cannot move file(s) - destination is within source.');
         }
 
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, true);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, true) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(sprintf(_("%s already exists."), $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('%s already exists.', $this->_getPath($dest, $name)));
             }
         }
 
         if (!@ftp_rename($this->_stream, $orig, $this->_getPath($dest, $name))) {
-            return PEAR::raiseError(sprintf(_("Failed to move to \"%s\"."), $this->_getPath($dest, $name)));
+            throw new VFS_Exception(sprintf('Failed to move to "%s".', $this->_getPath($dest, $name)));
         }
-
-        return true;
     }
 
     /**
      * Returns the current working directory on the FTP server.
      *
      * @return string  The current working directory.
+     * @throws VFS_Exception
      */
-    function getCurrentDirectory()
+    public function getCurrentDirectory()
     {
-        if (is_a($connected = $this->_connect(), 'PEAR_Error')) {
-            return $connected;
-        }
+        $this->_connect();
         return @ftp_pwd($this->_stream);
     }
 
     /**
      * Changes the current directory on the server.
      *
-     * @access private
-     *
      * @param string $path  The path to change to.
      *
-     * @return mixed  True on success, or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function _setPath($path)
+    protected function _setPath($path)
     {
         if (!@ftp_chdir($this->_stream, $path)) {
-            return PEAR::raiseError(sprintf(_("Unable to change to %s."), $path));
+            throw new VFS_Exception(sprintf('Unable to change to %s.', $path));
         }
-        return true;
     }
 
     /**
      * Returns the parent directory of the specified path.
      *
-     * @access private
-     *
      * @param string $path  The path to get the parent of.
      *
-     * @return string  The parent directory (string) on success or a PEAR_Error
-     *                 object on failure.
+     * @return string  The parent directory.
+     * @throws VFS_Exception
      */
-    function _parentDir($path)
+    protected function _parentDir($path)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $olddir = $this->getCurrentDirectory();
         @ftp_cdup($this->_stream);
@@ -897,7 +775,7 @@ class VFS_ftp extends VFS {
         $this->_setPath($olddir);
 
         if (!$parent) {
-            return PEAR::raiseError(_("Unable to determine current directory."));
+            throw new VFS_Exception('Unable to determine current directory.');
         }
 
         return $parent;
@@ -906,59 +784,57 @@ class VFS_ftp extends VFS {
     /**
      * Attempts to open a connection to the FTP server.
      *
-     * @access private
-     *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function _connect()
+    protected function _connect()
     {
-        if ($this->_stream === false) {
-            if (!extension_loaded('ftp')) {
-                return PEAR::raiseError(_("The FTP extension is not available."));
-            }
+        if ($this->_stream !== false) {
+            return;
+        }
 
-            if (!is_array($this->_params)) {
-                return PEAR::raiseError(_("No configuration information specified for FTP VFS."));
-            }
+        if (!extension_loaded('ftp')) {
+            throw new VFS_Exception('The FTP extension is not available.');
+        }
 
-            $required = array('hostspec', 'username', 'password');
-            foreach ($required as $val) {
-                if (!isset($this->_params[$val])) {
-                    return PEAR::raiseError(sprintf(_("Required \"%s\" not specified in VFS configuration."), $val));
-                }
+        if (!is_array($this->_params)) {
+            throw new VFS_Exception('No configuration information specified for FTP VFS.');
+        }
+
+        $required = array('hostspec', 'username', 'password');
+        foreach ($required as $val) {
+            if (!isset($this->_params[$val])) {
+                throw new VFS_Exception(sprintf('Required "%s" not specified in VFS configuration.', $val));
             }
+        }
 
-            /* Connect to the ftp server using the supplied parameters. */
-            if (!empty($this->_params['ssl'])) {
-                if (function_exists('ftp_ssl_connect')) {
-                    $this->_stream = @ftp_ssl_connect($this->_params['hostspec'], $this->_params['port']);
-                } else {
-                    return PEAR::raiseError(_("Unable to connect with SSL."));
-                }
+        /* Connect to the ftp server using the supplied parameters. */
+        if (!empty($this->_params['ssl'])) {
+            if (function_exists('ftp_ssl_connect')) {
+                $this->_stream = @ftp_ssl_connect($this->_params['hostspec'], $this->_params['port']);
             } else {
-                $this->_stream = @ftp_connect($this->_params['hostspec'], $this->_params['port']);
-            }
-            if (!$this->_stream) {
-                return PEAR::raiseError(_("Connection to FTP server failed."));
+                throw new VFS_Exception('Unable to connect with SSL.');
             }
+        } else {
+            $this->_stream = @ftp_connect($this->_params['hostspec'], $this->_params['port']);
+        }
 
-            $connected = @ftp_login($this->_stream, $this->_params['username'], $this->_params['password']);
-            if (!$connected) {
-                @ftp_quit($this->_stream);
-                $this->_stream = false;
-                return PEAR::raiseError(_("Authentication to FTP server failed."));
-            }
+        if (!$this->_stream) {
+            throw new VFS_Exception('Connection to FTP server failed.');
+        }
 
-            if (!empty($this->_params['pasv'])) {
-                @ftp_pasv($this->_stream, true);
-            }
+        if (!@ftp_login($this->_stream, $this->_params['username'], $this->_params['password'])) {
+            @ftp_quit($this->_stream);
+            $this->_stream = false;
+            throw new VFS_Exception('Authentication to FTP server failed.');
+        }
 
-            if (!empty($this->_params['timeout'])) {
-                ftp_set_option($this->_stream, FTP_TIMEOUT_SEC, $this->_params['timeout']);
-            }
+        if (!empty($this->_params['pasv'])) {
+            @ftp_pasv($this->_stream, true);
         }
 
-        return true;
+        if (!empty($this->_params['timeout'])) {
+            ftp_set_option($this->_stream, FTP_TIMEOUT_SEC, $this->_params['timeout']);
+        }
     }
 
 }
index 487d081..afef889 100644 (file)
  * @author  Jan Schneider <jan@horde.org>
  * @package VFS
  */
-class VFS_horde extends VFS {
-
+class VFS_horde extends VFS
+{
     /**
      * Reference to a Horde Registry instance.
      *
-     * @var Registry
+     * @var Horde_Registry
      */
-    var $_registry;
+    protected $_registry;
 
     /**
      * Constructor.
      *
      * @param array $params  A hash containing connection parameters.
+     * @throws VFS_Exception
      */
-    function VFS_horde($params = array())
+    public function __construct($params = array())
     {
-        parent::VFS($params);
+        parent::__construct($params);
+
         if (!isset($this->_params['horde_base'])) {
-            $this->_registry = PEAR::raiseError(sprintf(_("Required \"%s\" not specified in VFS configuration."), 'horde_base'));
-            return;
+            throw new VFS_Exception('Required "horde_base" not specified in VFS configuration.');
         }
 
         require_once $this->_params['horde_base'] . '/lib/Application.php';
@@ -46,41 +47,25 @@ class VFS_horde extends VFS {
         $this->_registry = $GLOBALS['registry'];
     }
 
-    function _connect()
+    /**
+     */
+    protected function _connect()
     {
         if (!empty($this->_params['user']) &&
             !empty($this->_params['password'])) {
-            Horde_Auth::setAuth($this->_params['user'],
-                           array('password' => $this->_params['password']));
+            Horde_Auth::setAuth($this->_params['user'], array('password' => $this->_params['password']));
         }
     }
 
     /**
-     * Retrieves the size of a file from the VFS.
-     *
-     * @abstract
-     *
-     * @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."));
-    }
-
-    /**
      * Retrieves a file from the VFS.
      *
-     * @abstract
-     *
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return string The file data.
+     * @return string  The file data.
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
         if (substr($path, 0, 1) == '/') {
             $path = substr($path, 1);
@@ -97,125 +82,27 @@ class VFS_horde extends VFS {
     }
 
     /**
-     * Stores a file in the VFS.
-     *
-     * @abstract
-     *
-     * @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 stored.
-     * @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.
-     *
-     * @abstract
-     *
-     * @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.
-     *
-     * @abstract
-     *
-     * @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.
-     *
-     * @return mixed  True on success or a PEAR_Error object on failure.
-     */
-    function move($path, $name, $dest)
-    {
-        return PEAR::raiseError(_("Not supported."));
-    }
-
-    /**
-     * Copies a file through the backend.
-     *
-     * @abstract
-     *
-     * @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.
-     *
-     * @return mixed  True on success or a PEAR_Error object on failure.
-     */
-    function copy($path, $name, $dest)
-    {
-        return PEAR::raiseError(_("Not supported."));
-    }
-
-    /**
-     * Deletes a file from the VFS.
-     *
-     * @abstract
-     *
-     * @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.
-     */
-    function deleteFile($path, $name)
-    {
-        return PEAR::raiseError(_("Not supported."));
-    }
-
-    /**
-     * Renames a file in the VFS.
-     *
-     * @abstract
-     *
-     * @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 an an unsorted file list of the specified directory.
      *
-     * @abstract
-     *
      * @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.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path, $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path, $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
         $list = array();
         if ($path == '/') {
-            $apps = $this->_registry->listApps(null, false, Horde_Perms::READ);
-            if (is_a($apps, 'PEAR_Error')) {
-                return $apps;
+            try {
+                $apps = $this->_registry->listApps(null, false, Horde_Perms::READ);
+            } catch (Horde_Exception $e) {
+                throw new VFS_Exception($e->getMessage());
             }
+
             foreach ($apps as $app) {
                 if ($this->_registry->hasMethod('browse', $app)) {
                     $file = array(
@@ -239,15 +126,16 @@ class VFS_horde extends VFS {
         try {
             $items = $this->_registry->callByPackage($pieces[0], 'browse', array('path' => $path, 'properties' => array('name', 'browseable', 'contenttype', 'contentlength', 'modified')));
         } catch (Horde_Exception $e) {
-            return PEAR::raiserError($e->getMessage(), $e->getCode());
+            throw new VFS_Exception($e->getMessage());
         }
 
         if (!is_array(reset($items))) {
             /* We return an object's content. */
-            return PEAR::raiseError(_("unknown error"));
+            throw new VFS_Exception('Unknown error');
         }
 
-        include_once 'Horde/MIME/Magic.php';
+        @include_once 'Horde/Mime/Magic.php';
+
         foreach ($items as $sub_path => $i) {
             if ($dironly && !$i['browseable']) {
                 continue;
@@ -258,12 +146,9 @@ class VFS_horde extends VFS {
                 continue;
             }
 
-            if (class_exists('MIME_Magic')) {
-                $type = empty($i['contenttype']) ? 'application/octet-stream' : $i['contenttype'];
-                $type = MIME_Magic::MIMEToExt($type);
-            } else {
-                $type = '**none';
-            }
+            $type = class_exists('Horde_Mime_Magic')
+                ? Horde_Mime_Magic::mimeToExt(empty($i['contenttype']) ? 'application/octet-stream' : $i['contenttype'])
+                : '**none';
 
             $file = array(
                 //'name' => $i['name'],
@@ -278,21 +163,4 @@ class VFS_horde extends VFS {
         return $list;
     }
 
-    /**
-     * Returns a sorted list of folders in the specified directory.
-     *
-     * @abstract
-     *
-     * @param string $path         The path of the directory to get the
-     *                             directory list for.
-     * @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."));
-    }
-
 }
index 7df4840..ad3d995 100644 (file)
@@ -14,21 +14,21 @@ require_once 'Horde/Kolab/Storage/List.php';
  * @author  Gunnar Wrobel <wrobel@pardus.de>
  * @package VFS
  */
-class VFS_kolab extends VFS {
-
+class VFS_kolab extends VFS
+{
     /**
      * Variable holding the connection to the Kolab storage system.
      *
      * @var Horde_Kolab_IMAP
      */
-    var $_imap = false;
+    protected $_imap = false;
 
     /**
      * Cache for the list of folders.
      *
      * @var array
      */
-    var $_folders;
+    protected $_folders;
 
     /**
      * Retrieves a file from the VFS.
@@ -37,15 +37,13 @@ class VFS_kolab extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
         list($app, $uid) = $this->_getAppUid($path);
         if ($app && $uid) {
-            $handler = &$this->_getAppHandler($app, $uid);
-            if (is_a($handler, 'PEAR_Error')) {
-                return $handler;
-            }
+            $handler = $this->_getAppHandler($app, $uid);
             $object = $handler->getObject($uid);
 
             if (isset($object['_attachments'][$name])) {
@@ -55,18 +53,19 @@ class VFS_kolab extends VFS {
 
         //FIXME
         if ($this->isFolder(dirname($path), basename($path))) {
-            $session = &Horde_Kolab_Session::singleton();
-            $imap = &$session->getImap();
+            $session = Horde_Kolab_Session::singleton();
+            $imap = $session->getImap();
 
             $result = $imap->select(substr($path,1));
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
+            if ($result instanceof PEAR_Error) {
+                throw new VFS_Exception($result->getMessage());
             }
 
             $file = explode('/', $name);
 
             return $this->_getFile($imap, $file[0], $file[1]);
         }
+
         return '';
     }
 
@@ -79,16 +78,13 @@ class VFS_kolab extends VFS {
      *                             be stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
         list($app, $uid) = $this->_getAppUid($path);
         if ($app) {
-            $handler = &$this->_getAppHandler($app, $uid);
-            if (is_a($handler, 'PEAR_Error')) {
-                return $handler;
-            }
+            $handler = $this->_getAppHandler($app, $uid);
             $object = $handler->getObject($uid);
             $object['_attachments'][$name]['path'] = $tmpFile;
             if (empty($object['link-attachment'])) {
@@ -101,37 +97,29 @@ class VFS_kolab extends VFS {
         }
 
         if ($autocreate && !$this->isFolder(dirname($path), basename($path))) {
-            $result = $this->autocreatePath($path);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($path);
         }
 
         //FIXME
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
      * Deletes a file from the VFS.
      *
-     * @abstract
-     *
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
         list($app, $uid) = $this->_getAppUid($path);
         if ($app) {
-            $handler = &$this->_getAppHandler($app, $uid);
-            if (is_a($handler, 'PEAR_Error')) {
-                return $handler;
-            }
+            $handler = $this->_getAppHandler($app, $uid);
             $object = $handler->getObject($uid);
             if (!isset($object['_attachments'][$name])) {
-                return PEAR::raiseError(_("Unable to delete VFS file."));
+                throw new VFS_Exception('Unable to delete VFS file.');
             }
             unset($object['_attachments'][$name]);
             $object['link-attachment'] = array_values(array_diff($object['link-attachment'], array($name)));
@@ -140,7 +128,7 @@ class VFS_kolab extends VFS {
         }
 
         //FIXME
-        return PEAR::raiseError(_("Not supported."));
+        throw new VFS_Exception('Not supported.');
     }
 
     /**
@@ -149,9 +137,9 @@ class VFS_kolab extends 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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
         $list = Kolab_List::singleton();
         $folder = $this->_getFolder($path, $name);
@@ -159,9 +147,9 @@ class VFS_kolab extends VFS {
         $object = $list->getNewFolder();
         $object->setName($folder);
 
-        $result = $object->save(array('type' => 'h-file'));
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        $object->save(array('type' => 'h-file'));
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
 
         $this->_folders = null;
@@ -174,23 +162,16 @@ class VFS_kolab extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
         if ($recursive) {
-            $result = $this->emptyFolder($path . '/' . $name);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->emptyFolder($path . '/' . $name);
         } else {
             $list = $this->listFolder($path . '/' . $name, null, false);
-            if (is_a($list, 'PEAR_Error')) {
-                return $list;
-            }
             if (count($list)) {
-                return PEAR::raiseError(sprintf(_("Unable to delete %s, the directory is not empty"),
-                                                $path . '/' . $name));
+                throw new VFS_Exception(sprintf('Unable to delete %s, the directory is not empty', $path . '/' . $name));
             }
         }
 
@@ -199,26 +180,19 @@ class VFS_kolab extends VFS {
             /**
              * Objects provide no real folders and we don't delete them.
              */
-            return true;
+            return;
         }
 
         $folders = $this->_getFolders();
-        if (is_a($folders, 'PEAR_Error')) {
-            return $folders;
-        }
         $folder = $this->_getFolder($path, $name);
 
         if (!empty($folders['/' . $folder])) {
-            $result = $folders['/' . $folder]->delete();
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
-
+            $folders['/' . $folder]->delete();
             $this->_folders = null;
-
-            return true;
+            return;
         }
-        return PEAR::raiseError(sprintf('No such folder %s!', '/' . $folder));
+
+        throw new VFS_Exception(sprintf('No such folder %s!', '/' . $folder));
     }
 
     /**
@@ -227,34 +201,21 @@ class VFS_kolab extends VFS {
      *
      * @param string $path  The path of the folder to empty.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function emptyFolder($path)
+    public function emptyFolder($path)
     {
         // Get and delete the subfolders.
         $list = $this->listFolder($path, null, false, true);
-        if (is_a($list, 'PEAR_Error')) {
-            return $list;
-        }
         foreach ($list as $folder) {
-            $result = $this->deleteFolder($path, $folder['name'], true);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->deleteFolder($path, $folder['name'], true);
         }
+
         // Only files are left, get and delete them.
         $list = $this->listFolder($path, null, false);
-        if (is_a($list, 'PEAR_Error')) {
-            return $list;
-        }
         foreach ($list as $file) {
-            $result = $this->deleteFile($path, $file['name']);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->deleteFile($path, $file['name']);
         }
-
-        return true;
     }
 
     /**
@@ -265,45 +226,44 @@ class VFS_kolab extends VFS {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show only directories?
      *
-     * @return array  File list on success or PEAR_Error on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path = '', $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path = '', $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
         list($app, $uid) = $this->_getAppUid($path);
         if ($app) {
             if ($dironly) {
-                /** 
+                /**
                  * Objects dont support directories.
                  */
                 return array();
             }
             if ($uid) {
-                $handler = &$this->_getAppHandler($app, $uid);
-                if (is_a($handler, 'PEAR_Error')) {
-                    return $handler;
-                }
+                $handler = $this->_getAppHandler($app, $uid);
                 $object = $handler->getObject($uid);
-                if (is_a($object, 'PEAR_Error')) {
-                    return $object;
+                if ($object instanceof PEAR_Error) {
+                    throw new VFS_Exception($object->getMessage());
                 }
 
-                $filenames = isset($object['_attachments']) ? array_keys($object['_attachments']) : array();
+                $filenames = isset($object['_attachments'])
+                    ? array_keys($object['_attachments'])
+                    : array();
             } else {
                 $filenames = $this->_getAppUids($app);
             }
 
             $owner = Horde_Auth::getAuth();
 
-            $files = array();
-            $file = array();
-            foreach($filenames as $filename) {
+            $file = $files = array();
+            foreach ($filenames as $filename) {
                 $name = explode('.', $filename);
 
                 if (count($name) == 1) {
                     $file['type'] = '**none';
                 } else {
-                    $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                    $file['type'] = self::strtolower($name[count($name) - 1]);
                 }
 
                 $file['size'] = '-1';
@@ -315,21 +275,17 @@ class VFS_kolab extends VFS {
 
                 $files[$file['name']] = $file;
             }
+
             return $files;
         }
 
         $owner = Horde_Auth::getAuth();
 
-        $files = array();
+        $file = $files = array();
 
         $folders = $this->listFolders($path, $filter, $dotfiles);
-        if (is_a($folders, 'PEAR_Error')) {
-            return $folders;
-        }
-
         $list = $this->_getFolders();
 
-        $file = array();
         foreach ($folders as $folder) {
             $file['type'] = '**dir';
             $file['size'] = -1;
@@ -346,29 +302,24 @@ class VFS_kolab extends VFS {
             $files[$file['name']] = $file;
         }
 
-        if (!$dironly
-            && $this->isFolder(basename($path), basename($path))
-            && !empty($list[$path])) {
-
-            $session = &Horde_Kolab_Session::singleton();
-            $imap = &$session->getImap();
+        if (!$dironly &&
+            $this->isFolder(basename($path), basename($path)) &&
+            !empty($list[$path])) {
+            $session = Horde_Kolab_Session::singleton();
+            $imap = $session->getImap();
 
             $result = $imap->select(substr($path, 1));
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
+            if ($result instanceof PEAR_Error) {
+                throw new VFS_Exception($result->getMessage());
             }
 
             $uids = $imap->getUids();
-            if (is_a($uids, 'PEAR_Error')) {
-                return $uids;
+            if ($uids instanceof PEAR_Error) {
+                throw new VFS_Exception($uids->getMessage());
             }
 
             foreach ($uids as $uid) {
-                $mFiles = $this->_parseMessage($imap, $uid);
-                if (is_a($mFiles, 'PEAR_Error')) {
-                    return $mFiles;
-                }
-                $result = array_merge($files, $mFiles);
+                $result = array_merge($files, $this->_parseMessage($imap, $uid));
                 $files = $result;
             }
         }
@@ -376,29 +327,30 @@ class VFS_kolab extends VFS {
         return $files;
     }
 
-    function _parseMessage($imap, $uid)
+    /**
+     */
+    protected function _parseMessage($imap, $uid)
     {
         $result = $imap->getMessageHeader($uid);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
 
         $raw_headers = $result;
 
         $body = $imap->getMessageBody($uid);
-        if (is_a($body, 'PEAR_Error')) {
-            return $body;
+        if ($body instanceof PEAR_Error) {
+            throw new VFS_Exception($body->getMessage());
         }
 
         $raw_message = $raw_headers . $body;
 
-        $mime_message = &MIME_Structure::parseTextMIMEMessage($raw_message);
+        $mime_message = Horde_Mime_Part::parseMessage($raw_message);
         $parts = $mime_message->contentTypeMap();
 
         $owner = Horde_Auth::getAuth();
 
-        $files = array();
-        $file = array();
+        $file = $files = array();
 
         foreach ($parts as $part_id => $disposition) {
             $part = $mime_message->getPart($part_id);
@@ -426,44 +378,41 @@ class VFS_kolab extends VFS {
         return $files;
     }
 
-
-    function _getFile($imap, $uid, $filename)
+    /**
+     */
+    protected function _getFile($imap, $uid, $filename)
     {
         $result = $imap->getMessageHeader($uid);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
 
         $raw_headers = $result;
 
         $body = $imap->getMessageBody($uid);
-        if (is_a($body, 'PEAR_Error')) {
-            return $body;
+        if ($body instanceof PEAR_Error) {
+            throw new VFS_Exception($body->getMessage());
         }
 
         $raw_message = $raw_headers . $body;
 
-        $mime_message = &MIME_Structure::parseTextMIMEMessage($raw_message);
+        $mime_message = Horde_Mime_Part::parseMessage($raw_message);
         $parts = $mime_message->contentTypeMap();
 
         $owner = Horde_Auth::getAuth();
 
-        $files = array();
-        $file = array();
-
         foreach ($parts as $part_id => $disposition) {
             $part = $mime_message->getPart($part_id);
 
-            $f= $part->getDispositionParameter('filename');
-
-            if ($f && $f == $filename ) {
+            $f = $part->getDispositionParameter('filename');
+            if ($f && $f == $filename) {
                 return $part->transferDecode();
             }
         }
+
         return '';
     }
 
-
     /**
      * Returns a sorted list of folders in the specified directory.
      *
@@ -472,16 +421,16 @@ class VFS_kolab extends VFS {
      * @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.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = null, $dotfolders = true)
+    public function listFolders($path = '', $filter = null, $dotfolders = true)
     {
         if (substr($path, -1) != '/') {
             $path .= '/';
         }
 
-        $aFolders = array();
-        $aFolder = array();
+        $aFolder = $aFolders = array();
 
         if ($dotfolders && $path != '/') {
             $aFolder['val'] = dirname($path);
@@ -510,7 +459,9 @@ class VFS_kolab extends VFS {
         return $aFolders;
     }
 
-    function _getFolder($path, $name)
+    /**
+     */
+    protected function _getFolder($path, $name)
     {
         $folder = $path . '/' . $name;
 
@@ -525,11 +476,11 @@ class VFS_kolab extends VFS {
         return $folder;
     }
 
-
-    function _getFolders()
+    /**
+     */
+    protected function _getFolders()
     {
         if (!isset($this->_folders)) {
-
             $vfs_folders = array();
 
             $list = Kolab_List::singleton();
@@ -540,8 +491,8 @@ class VFS_kolab extends VFS {
                 $folders = $list->getByType('h-file');
             }
 
-            if (is_a($folders, 'PEAR_Error')) {
-                return $folders;
+            if ($folders instanceof PEAR_Error) {
+                throw new VFS_Exception($folders->getMessage());
             }
 
             foreach ($folders as $folder) {
@@ -559,19 +510,25 @@ class VFS_kolab extends VFS {
             }
             $this->_folders = $vfs_folders;
         }
+
         return $this->_folders;
     }
 
-    function _getAppUid($path)
+    /**
+     */
+    protected function _getAppUid($path)
     {
-        if (defined('TURBA_VFS_PATH')
-            && substr($path, 0, strlen(TURBA_VFS_PATH)) == TURBA_VFS_PATH) {
+        if (defined('TURBA_VFS_PATH') &&
+            substr($path, 0, strlen(TURBA_VFS_PATH)) == TURBA_VFS_PATH) {
             return array('turba', substr($path, strlen(TURBA_VFS_PATH) + 1));
         }
+
         return array(false, false);
     }
 
-    function &_getAppHandler($app, $uid)
+    /**
+     */
+    protected function _getAppHandler($app, $uid)
     {
         global $registry;
 
@@ -588,18 +545,20 @@ class VFS_kolab extends VFS {
                                             'sources' => array_keys($sources),
                                             'fields' => $fields));
             if (!isset($result[$uid])) {
-                return PEAR::raiseError('No such contact!');
+                throw new VFS_Exception('No such contact!');
             }
             $list = Kolab_List::singleton();
-            $share = &$list->getByShare($result[$uid][0]['source'], 'contact');
-            if (is_a($share, 'PEAR_Error')) {
-                return $share;
+            $share = $list->getByShare($result[$uid][0]['source'], 'contact');
+            if ($share instanceof PEAR_Error) {
+                throw new VFS_Exception($share->getMessage());
             }
             return $share->getData();
         }
     }
 
-    function _getAppUids($app)
+    /**
+     */
+    protected function _getAppUids($app)
     {
         global $registry;
 
@@ -621,14 +580,4 @@ class VFS_kolab extends VFS {
         }
     }
 
-    /**
-     * Connecting is not required for this driver.
-     *
-     * @access private
-     *
-     * @return NULL
-     */
-    function _connect()
-    {
-    }
 }
index efa59ea..8df5d26 100644 (file)
@@ -3,16 +3,6 @@
 require_once dirname(__FILE__) . '/sql.php';
 
 /**
- * Permission for read access.
- */
-define('VFS_FLAG_READ', 1);
-
-/**
- * Permission for read access.
- */
-define('VFS_FLAG_WRITE', 2);
-
-/**
  * Multi User VFS implementation for PHP's PEAR database
  * abstraction layer.
  *
@@ -64,17 +54,35 @@ define('VFS_FLAG_WRITE', 2);
  * @author  Mike Cochrane <mike@graftonhall.co.nz>
  * @package VFS
  */
-class VFS_musql extends VFS_sql {
+class VFS_musql extends VFS_sql
+{
+    /* Permission for read access. */
+    const FLAG_READ = 1;
+
+    /* Permission for read access. */
+    const FLAG_WRITE = 2;
 
     /**
      * List of permissions and if they can be changed in this VFS
      *
      * @var array
      */
-    var $_permissions = array(
-        'owner' => array('read' => false, 'write' => false, 'execute' => false),
-        'group' => array('read' => false, 'write' => false, 'execute' => false),
-        'all'   => array('read' => true,  'write' => true,  'execute' => false)
+    protected $_permissions = array(
+        'owner' => array(
+            'read' => false,
+            'write' => false,
+            'execute' => false
+        ),
+        'group' => array(
+            'read' => false,
+            'write' => false,
+            'execute' => false
+        ),
+        'all' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => false
+        )
     );
 
     /**
@@ -85,14 +93,11 @@ class VFS_musql extends VFS_sql {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        $conn = $this->_connect();
-        if (PEAR::isError($conn)) {
-            return $conn;
-        }
+        $this->_connect();
 
         /* Make sure we have write access to this and all parent paths. */
         if ($path != '') {
@@ -100,14 +105,9 @@ class VFS_musql extends VFS_sql {
             $path_name = array_pop($paths);
             if (!$this->isFolder(implode('/', $paths), $path_name)) {
                 if (!$autocreate) {
-                    return PEAR::raiseError(
-                        sprintf(_("Folder \"%s\" does not exist"), $path),
-                        'horde.error');
+                    throw new VFS_Exception(sprintf('Folder "%s" does not exist'), $path);
                 } else {
-                    $result = $this->autocreatePath($path);
-                    if (is_a($result, 'PEAR_Error')) {
-                        return $result;
-                    }
+                    $this->autocreatePath($path);
                 }
             }
             $paths[] = $path_name;
@@ -119,25 +119,25 @@ class VFS_musql extends VFS_sql {
                                $this->_params['table']);
                 $this->log($sql, PEAR_LOG_DEBUG);
                 $results = $this->_db->getAll($sql, array($previous, $thispath));
-                if (is_a($results, 'PEAR_Error')) {
+                if ($results instanceof PEAR_Error) {
                     $this->log($results, PEAR_LOG_ERR);
-                    return $results;
+                    throw new VFS_Exception($results->getMessage());
                 }
                 if (!is_array($results) || count($results) < 1) {
-                    return PEAR::raiseError(_("Unable to create VFS file."));
+                    throw new VFS_Exception('Unable to create VFS file.');
                 }
 
                 $allowed = false;
                 foreach ($results as $result) {
                     if ($result[0] == $this->_params['user'] ||
-                        $result[1] & VFS_FLAG_WRITE) {
+                        $result[1] & self::FLAG_WRITE) {
                         $allowed = true;
                         break;
                     }
                 }
 
                 if (!$allowed) {
-                    return PEAR::raiseError(_("Access denied creating VFS file."));
+                    throw new VFS_Exception('Access denied creating VFS file.');
                 }
 
                 $previous = $thispath;
@@ -153,27 +153,24 @@ class VFS_musql extends VFS_sql {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        $conn = $this->_connect();
-        if (PEAR::isError($conn)) {
-            return $conn;
-        }
+        $this->_connect();
 
         $sql = sprintf('SELECT vfs_id, vfs_owner, vfs_perms FROM %s
                         WHERE vfs_path = ? AND vfs_name= ? AND vfs_type = ?',
                        $this->_params['table']);
         $this->log($sql, PEAR_LOG_DEBUG);
-        $fileList = $this->_db->getAll($sql, array($path, $name, VFS_FILE));
+        $fileList = $this->_db->getAll($sql, array($path, $name, self::FILE));
 
-        if (is_a($fileList, 'PEAR_Error')) {
+        if ($fileList instanceof PEAR_Error) {
             $this->log($fileList, PEAR_LOG_ERR);
-            return $fileList;
+            throw new VFS_Exception($fileList->getMessage());
         }
         if (!is_array($fileList) || count($fileList) < 1) {
-            return PEAR::raiseError(_("Unable to delete VFS file."));
+            throw new VFS_Exception('Unable to delete VFS file.');
         }
 
         /* There may be one or more files with the same name but the user may
@@ -181,25 +178,25 @@ class VFS_musql extends VFS_sql {
          * delete the one they have access to. */
         foreach ($fileList as $file) {
             if ($file[1] == $this->_params['user'] ||
-                $file[2] & VFS_FLAG_WRITE) {
+                $file[2] & self::FLAG_WRITE) {
                 $sql = sprintf('DELETE FROM %s WHERE vfs_id = ?',
                                $this->_params['table']);
                 $this->log($sql, PEAR_LOG_DEBUG);
                 $result = $this->_db->query($sql, array($file[0]));
 
-                if (is_a($result, 'PEAR_Error')) {
+                if ($result instanceof PEAR_Error) {
                     $this->log($result, PEAR_LOG_ERR);
-                    return $result;
+                    throw new VFS_Exception($result->getMessage());
                 }
                 if ($this->_db->affectedRows() == 0) {
-                    return PEAR::raiseError(_("Unable to delete VFS file."));
+                    throw new VFS_Exception('Unable to delete VFS file.');
                 }
                 return $result;
             }
         }
 
         // FIXME: 'Access Denied deleting file %s/%s'
-        return PEAR::raiseError(_("Unable to delete VFS file."));
+        throw new VFS_Exception('Unable to delete VFS file.');
     }
 
     /**
@@ -210,14 +207,11 @@ class VFS_musql extends VFS_sql {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        $conn = $this->_connect();
-        if (PEAR::isError($conn)) {
-            return $conn;
-        }
+        $this->_connect();
 
         $sql = sprintf('SELECT vfs_id, vfs_owner, vfs_perms FROM %s
                         WHERE vfs_path = ? AND vfs_name= ?',
@@ -225,12 +219,12 @@ class VFS_musql extends VFS_sql {
         $this->log($sql, PEAR_LOG_DEBUG);
         $fileList = $this->_db->getAll($sql, array($oldpath, $oldname));
 
-        if (is_a($fileList, 'PEAR_Error')) {
+        if ($fileList instanceof PEAR_Error) {
             $this->log($fileList, PEAR_LOG_ERR);
-            return $fileList;
+            throw new VFS_Exception($fileList);
         }
         if (!is_array($fileList) || count($fileList) < 1) {
-            return PEAR::raiseError(_("Unable to rename VFS file."));
+            throw new VFS_Exception('Unable to rename VFS file.');
         }
 
         if (strpos($newpath, '/') === false) {
@@ -240,9 +234,7 @@ class VFS_musql extends VFS_sql {
             list($parent, $path) = explode('/', $newpath, 2);
         }
         if (!$this->isFolder($parent, $path)) {
-            if (is_a($result = $this->autocreatePath($newpath), 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($newpath);
         }
 
         /* There may be one or more files with the same name but the user may
@@ -250,7 +242,7 @@ class VFS_musql extends VFS_sql {
          * rename the one they have access to. */
         foreach ($fileList as $file) {
             if ($file[1] == $this->_params['user'] ||
-                $file[2] & VFS_FLAG_WRITE) {
+                $file[2] & self::FLAG_WRITE) {
                 $sql = sprintf('UPDATE %s SET vfs_path = ?, vfs_name = ?, vfs_modified = ?
                                 WHERE vfs_id = ?',
                                $this->_params['table']);
@@ -258,16 +250,15 @@ class VFS_musql extends VFS_sql {
                 $result = $this->_db->query(
                     $sql,
                     array($newpath, $newname, time(), $file[0]));
-                if (is_a($result, 'PEAR_Error')) {
+                if ($result instanceof PEAR_Error) {
                     $this->log($result, PEAR_LOG_ERR);
-                    return $result;
+                    throw new VFS_Exception($result->getMessage());
                 }
                 return $result;
             }
         }
 
-        return PEAR::raiseError(sprintf(_("Unable to rename VFS file %s/%s."),
-                                        $oldpath, $oldname));
+        throw new VFS_Exception(sprintf('Unable to rename VFS file %s/%s.', $oldpath, $oldname));
     }
 
     /**
@@ -276,14 +267,11 @@ class VFS_musql extends VFS_sql {
      * @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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
-        $conn = $this->_connect();
-        if (PEAR::isError($conn)) {
-            return $conn;
-        }
+        $this->_connect();
 
         /* Make sure we have write access to this and all parent paths. */
         if (strlen($path)) {
@@ -296,25 +284,25 @@ class VFS_musql extends VFS_sql {
                                $this->_params['table']);
                 $this->log($sql, PEAR_LOG_DEBUG);
                 $results = $this->_db->getAll($sql, array($previous, $thispath));
-                if (is_a($results, 'PEAR_Error')) {
+                if ($results instanceof PEAR_Error) {
                     $this->log($results, PEAR_LOG_ERR);
-                    return $results;
+                    throw new VFS_Exception($results->getMessage());
                 }
                 if (!is_array($results) || count($results) < 1) {
-                    return PEAR::raiseError(_("Unable to create VFS directory."));
+                    throw new VFS_Exception('Unable to create VFS directory.');
                 }
 
                 $allowed = false;
                 foreach ($results as $result) {
                     if ($result[0] == $this->_params['user'] ||
-                        $result[1] & VFS_FLAG_WRITE) {
+                        $result[1] & self::FLAG_WRITE) {
                         $allowed = true;
                         break;
                     }
                 }
 
                 if (!$allowed) {
-                    return PEAR::raiseError(_("Access denied creating VFS directory."));
+                    throw new VFS_Exception('Access denied creating VFS directory.');
                 }
 
                 $previous = $thispath;
@@ -330,9 +318,9 @@ class VFS_musql extends VFS_sql {
         $result = $this->_db->query(
             $sql,
             array($id, VFS_FOLDER, $path, $name, time(), $this->_params['user'], 0));
-        var_dump($this->_db->last_query);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             $this->log($result, PEAR_LOG_ERR);
+            throw new VFS_Exception($result->getMessage());
         }
 
         return $result;
@@ -345,29 +333,18 @@ class VFS_musql extends VFS_sql {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
-        $conn = $this->_connect();
-        if (PEAR::isError($conn)) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($recursive) {
-            $result = $this->emptyFolder($path . '/' . $name);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->emptyFolder($path . '/' . $name);
         } else {
             $list = $this->listFolder($path . '/' . $name);
-            if (is_a($list, 'PEAR_Error')) {
-                return $list;
-            }
             if (count($list)) {
-                return PEAR::raiseError(
-                    sprintf(_("Unable to delete %s, the directory is not empty"),
-                            $path . '/' . $name));
+                throw new VFS_Exception(sprintf('Unable to delete %s, the directory is not empty', $path . '/' . $name));
             }
         }
 
@@ -377,12 +354,12 @@ class VFS_musql extends VFS_sql {
         $this->log($sql, PEAR_LOG_DEBUG);
         $fileList = $this->_db->getAll($sql, array($path, $name, VFS_FOLDER));
 
-        if (is_a($fileList, 'PEAR_Error')) {
+        if ($fileList instanceof PEAR_Error) {
             $this->log($fileList, PEAR_LOG_ERR);
-            return $fileList;
+            throw new VFS_Exception($fileList->getMessage());
         }
         if (!is_array($fileList) || count($fileList) < 1) {
-            return PEAR::raiseError(_("Unable to delete VFS directory."));
+            throw new VFS_Exception('Unable to delete VFS directory.');
         }
 
         /* There may be one or more folders with the same name but as the user
@@ -390,18 +367,18 @@ class VFS_musql extends VFS_sql {
          * to delete the one they have access to */
         foreach ($fileList as $file) {
             if ($file[1] == $this->_params['user'] ||
-                $file[2] & VFS_FLAG_WRITE) {
+                $file[2] & self::FLAG_WRITE) {
                 $sql = sprintf('DELETE FROM %s WHERE vfs_id = ?',
                                $this->_params['table']);
                 $this->log($sql, PEAR_LOG_DEBUG);
                 $result = $this->_db->query($sql, array($file[0]));
 
-                if (is_a($result, 'PEAR_Error')) {
+                if ($result instanceof PEAR_Error) {
                     $this->log($result, PEAR_LOG_ERR);
-                    return $result;
+                    throw new VFS_Exception($result->getMessage());
                 }
                 if ($this->_db->affectedRows() == 0) {
-                    return PEAR::raiseError(_("Unable to delete VFS directory."));
+                    throw new VFS_Exception('Unable to delete VFS directory.');
                 }
 
                 return $result;
@@ -409,7 +386,7 @@ class VFS_musql extends VFS_sql {
         }
 
         // FIXME: 'Access Denied deleting folder %s/%s'
-        return PEAR::raiseError(_("Unable to delete VFS directory."));
+        throw new VFS_Exception('Unable to delete VFS directory.');
     }
 
     /**
@@ -420,15 +397,13 @@ class VFS_musql extends VFS_sql {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show only directories?
      *
-     * @return mixed  File list on success or false on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path, $filter = null, $dotfiles = true,
-                        $dironly = false)
+    protected function _listFolder($path, $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $length_op = $this->_getFileSizeOp();
         $sql = sprintf('SELECT vfs_name, vfs_type, vfs_modified, vfs_owner, vfs_perms, %s(vfs_data) FROM %s
@@ -437,10 +412,10 @@ class VFS_musql extends VFS_sql {
         $this->log($sql, PEAR_LOG_DEBUG);
         $fileList = $this->_db->getAll(
             $sql,
-            array($path, $this->_params['user'], VFS_FLAG_READ));
-        if (is_a($fileList, 'PEAR_Error')) {
+            array($path, $this->_params['user'], self::FLAG_READ));
+        if ($fileList instanceof PEAR_Error) {
             $this->log($fileList, PEAR_LOG_ERR);
-            return $fileList;
+            throw new VFS_Exception($fileList->getMessage());
         }
 
         $files = array();
@@ -452,17 +427,17 @@ class VFS_musql extends VFS_sql {
 
             $file['name'] = stripslashes($line[0]);
 
-            if ($line[1] == VFS_FILE) {
+            if ($line[1] == self::FILE) {
                 $name = explode('.', $line[0]);
 
                 if (count($name) == 1) {
                     $file['type'] = '**none';
                 } else {
-                    $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                    $file['type'] = self::strtolower($name[count($name) - 1]);
                 }
 
                 $file['size'] = $line[5];
-            } elseif ($line[1] == VFS_FOLDER) {
+            } elseif ($line[1] == self::FOLDER) {
                 $file['type'] = '**dir';
                 $file['size'] = -1;
             }
@@ -471,10 +446,10 @@ class VFS_musql extends VFS_sql {
             $file['owner'] = $line[3];
 
             $line[4] = intval($line[4]);
-            $file['perms']  = ($line[1] == VFS_FOLDER) ? 'd' : '-';
+            $file['perms']  = ($line[1] == self::FOLDER) ? 'd' : '-';
             $file['perms'] .= 'rw-';
-            $file['perms'] .= ($line[4] & VFS_FLAG_READ) ? 'r' : '-';
-            $file['perms'] .= ($line[4] & VFS_FLAG_WRITE) ? 'w' : '-';
+            $file['perms'] .= ($line[4] & self::FLAG_READ) ? 'r' : '-';
+            $file['perms'] .= ($line[4] & self::FLAG_WRITE) ? 'w' : '-';
             $file['perms'] .= '-';
             $file['group'] = '';
 
@@ -501,19 +476,16 @@ class VFS_musql extends VFS_sql {
      * @param string $path  Holds the path of directory of the Item.
      * @param string $name  Holds the name of the Item.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function changePermissions($path, $name, $permission)
+    public function changePermissions($path, $name, $permission)
     {
-        $conn = $this->_connect();
-        if (PEAR::isError($conn)) {
-            return $conn;
-        }
+        $this->_connect();
 
         $val = intval(substr($permission, -1));
         $perm = 0;
-        $perm |= ($val & 4) ? VFS_FLAG_READ : 0;
-        $perm |= ($val & 2) ? VFS_FLAG_WRITE : 0;
+        $perm |= ($val & 4) ? self::FLAG_READ : 0;
+        $perm |= ($val & 2) ? self::FLAG_WRITE : 0;
 
         $sql = sprintf('SELECT vfs_id, vfs_owner, vfs_perms FROM %s
                         WHERE vfs_path = ? AND vfs_name= ?',
@@ -521,12 +493,12 @@ class VFS_musql extends VFS_sql {
         $this->log($sql, PEAR_LOG_DEBUG);
         $fileList = $this->_db->getAll($sql, array($path, $name));
 
-        if (is_a($fileList, 'PEAR_Error')) {
+        if ($fileList instanceof PEAR_Error) {
             $this->log($fileList, PEAR_LOG_ERR);
-            return $fileList;
+            throw new VFS_Exception($fileList->getMessage());
         }
         if (!is_array($fileList) || count($fileList) < 1) {
-            return PEAR::raiseError(_("Unable to rename VFS file."));
+            throw new VFS_Exception('Unable to rename VFS file.');
         }
 
         /* There may be one or more files with the same name but the user may
@@ -534,19 +506,20 @@ class VFS_musql extends VFS_sql {
          * chmod the one they have access to. */
         foreach ($fileList as $file) {
             if ($file[1] == $this->_params['user'] ||
-                $file[2] & VFS_FLAG_WRITE) {
+                $file[2] & self::FLAG_WRITE) {
                 $sql = sprintf('UPDATE %s SET vfs_perms = ?
                                 WHERE vfs_id = ?',
                                $this->_params['table']);
                 $this->log($sql, PEAR_LOG_DEBUG);
                 $result = $this->_db->query($sql, array($perm, $file[0]));
+                if ($result instanceof PEAR_Error) {
+                    throw new VFS_Exception($result->getMessage());
+                }
                 return $result;
             }
         }
 
-        return PEAR::raiseError(
-            sprintf(_("Unable to change permission for VFS file %s/%s."),
-                    $path, $name));
+        throw new VFS_Exception(sprintf('Unable to change permission for VFS file %s/%s.', $path, $name));
     }
 
 }
index af2c11e..f326c29 100644 (file)
@@ -4,22 +4,22 @@
  *
  * Required values for $params:
  * <pre>
- *   'username'  - The username with which to connect to the SMB server.
- *   'password'  - The password with which to connect to the SMB server.
- *   'hostspec'  - The SMB server to connect to.
- *   'port'      - The SMB port number to connect to.
- *   'share'     - The share to access on the SMB server.
- *   'smbclient' - The path to the 'smbclient' executable.
+ * username - (string)The username with which to connect to the SMB server.
+ * password - (string) The password with which to connect to the SMB server.
+ * hostspec - (string) The SMB server to connect to.
+ * port' - (integer) The SMB port number to connect to.
+ * share - (string) The share to access on the SMB server.
+ * smbclient - (string) The path to the 'smbclient' executable.
  * </pre>
  *
  * Optional values for $params:
  * <pre>
- *   'ipaddress' - The address of the server to connect to.
+ * ipaddress - (string) The address of the server to connect to.
  * </pre>
  *
  * Functions not implemented:
- *   - changePermissions(): The SMB permission style does not fit with the
- *                          module.
+ * - changePermissions(): The SMB permission style does not fit with the
+ *                        module.
  *
  * Codebase copyright 2002 Paul Gareau <paul@xhawk.net>.  Adapted with
  * permission by Patrice Levesque <wayne@ptaff.ca> from phpsmb-0.8 code, and
  * @author  Patrice Levesque <wayne@ptaff.ca>
  * @package VFS
  */
-class VFS_smb extends VFS {
-
+class VFS_smb extends VFS
+{
     /**
      * List of additional credentials required for this VFS backend.
      *
      * @var array
      */
-    var $_credentials = array('username', 'password');
-
-    /**
-     * List of permissions and if they can be changed in this VFS backend.
-     *
-     * @var array
-     */
-    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));
+    protected $_credentials = array('username', 'password');
 
     /**
      * Authenticates a user on the SMB server and share.
      *
-     * @access private
-     *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function _connect()
+    protected function _connect()
     {
-        $cmd = array('quit');
-        $err = $this->_command('', $cmd);
-        if (is_a($err, 'PEAR_Error')) {
-            return PEAR::raiseError(_("Authentication to the SMB server failed."));
+        try {
+            $this->_command('', array('quit'));
+        } catch (VFS_Exception $e) {
+            throw new VFS_Exception('Authentication to the SMB server failed.');
         }
-        return true;
     }
 
     /**
@@ -77,19 +64,13 @@ class VFS_smb extends VFS {
      *
      * @return string  The file data.
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
         $file = $this->readFile($path, $name);
-        if (is_a($file, 'PEAR_Error')) {
-            return $file;
-        }
-
         $size = filesize($file);
-        if ($size === 0) {
-            return '';
-        }
-
-        return file_get_contents($file);
+        return ($size === 0)
+            ? ''
+            : file_get_contents($file);
     }
 
     /**
@@ -102,26 +83,22 @@ class VFS_smb extends VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return string A local filename.
+     * @return string  A local filename.
      */
-    function readFile($path, $name)
+    public function readFile($path, $name)
     {
         // Create a temporary file and register it for deletion at the
         // end of this request.
-        $localFile = $this->_getTempFile();
-        if (!$localFile) {
-            return PEAR::raiseError(_("Unable to create temporary file."));
+        if (!($localFile = tempnam(null, 'vfs'))) {
+            throw new VFS_Exception('Unable to create temporary file.');
         }
-        register_shutdown_function(create_function('', 'unlink(\'' . addslashes($localFile) . '\');'));
+        register_shutdown_function(create_function('', '@unlink(\'' . addslashes($localFile) . '\');'));
 
         list($path, $name) = $this->_escapeShellCommand($path, $name);
         $cmd = array('get \"' . $name . '\" ' . $localFile);
-        $result = $this->_command($path, $cmd);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_command($path, $cmd);
         if (!file_exists($localFile)) {
-            return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to open VFS file "%s".', $this->_getPath($path, $name)));
         }
 
         return $localFile;
@@ -135,15 +112,9 @@ class VFS_smb extends VFS {
      *
      * @return resource  The stream.
      */
-    function readStream($path, $name)
+    public function readStream($path, $name)
     {
-        $file = $this->readFile($path, $name);
-        if (is_a($file, 'PEAR_Error')) {
-            return $file;
-        }
-
-        $mode = OS_WINDOWS ? 'rb' : 'r';
-        return fopen($file, $mode);
+        return fopen($this->readFile($path, $name),OS_WINDOWS ? 'rb' : 'r');
     }
 
     /**
@@ -155,9 +126,9 @@ class VFS_smb extends VFS {
      *                             stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
         // Double quotes not allowed in SMB filename.
         $name = str_replace('"', "'", $name);
@@ -166,16 +137,10 @@ class VFS_smb extends VFS {
         $cmd = array('put \"' . $tmpFile . '\" \"' . $name . '\"');
         // do we need to first autocreate the directory?
         if ($autocreate) {
-            $result = $this->autocreatePath($path);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
-        }
-        $err = $this->_command($path, $cmd);
-        if (is_a($err, 'PEAR_Error')) {
-            return $err;
+            $this->autocreatePath($path);
         }
-        return true;
+
+        $this->_command($path, $cmd);
     }
 
     /**
@@ -186,17 +151,19 @@ class VFS_smb extends VFS {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        $tmpFile = $this->_getTempFile();
-        $fp = fopen($tmpFile, 'wb');
-        fwrite($fp, $data);
-        fclose($fp);
-        $result = $this->write($path, $name, $tmpFile, $autocreate);
-        unlink($tmpFile);
-        return $result;
+        $tmpFile = tempnam(null, 'vfs');
+        file_put_contents($tmpFile, $data);
+        try {
+            $this->write($path, $name, $tmpFile, $autocreate);
+            unlink($tmpFile);
+        } catch (VFS_Exception $e) {
+            unlink($tmpFile);
+            throw $e;
+        }
     }
 
     /**
@@ -205,9 +172,9 @@ class VFS_smb extends VFS {
      * @param string $path  The path to delete the file from.
      * @param string $name  The filename to use.
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
         // In some samba versions after samba-3.0.25-pre2, $path must
         // end in a trailing slash.
@@ -217,11 +184,7 @@ class VFS_smb extends VFS {
 
         list($path, $name) = $this->_escapeShellCommand($path, $name);
         $cmd = array('del \"' . $name . '\"');
-        $err = $this->_command($path, $cmd);
-        if (is_a($err, 'PEAR_Error')) {
-            return $err;
-        }
-        return true;
+        $this->_command($path, $cmd);
     }
 
     /**
@@ -232,15 +195,16 @@ class VFS_smb extends VFS {
      *
      * @return boolean  True if it is a folder, false otherwise.
      */
-    function isFolder($path, $name)
+    public function isFolder($path, $name)
     {
         list($path, $name) = $this->_escapeShellCommand($path, $name);
         $cmd = array('quit');
-        $err = $this->_command($this->_getPath($path, $name), $cmd);
-        if (is_a($err, 'PEAR_Error')) {
+        try {
+            $this->_command($this->_getPath($path, $name), array('quit'));
+            return true;
+        } catch (VFS_Exception $e) {
             return false;
         }
-        return true;
     }
 
     /**
@@ -250,9 +214,9 @@ class VFS_smb extends VFS {
      * @param string $name        The name of the folder to delete.
      * @param boolean $recursive  Force a recursive delete?
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
         // In some samba versions after samba-3.0.25-pre2, $path must
         // end in a trailing slash.
@@ -261,38 +225,31 @@ class VFS_smb extends VFS {
         }
 
         if (!$this->isFolder($path, $name)) {
-            return PEAR::raiseError(sprintf(_("\"%s\" is not a directory."), $path . '/' . $name));
+            throw new VFS_Exception(sprintf('"%s" is not a directory.', $path . '/' . $name));
         }
 
         $file_list = $this->listFolder($this->_getPath($path, $name));
-        if (is_a($file_list, 'PEAR_Error')) {
-            return $file_list;
-        }
 
         if ($file_list && !$recursive) {
-            return PEAR::raiseError(sprintf(_("Unable to delete \"%s\", the directory is not empty."),
-                                            $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to delete "%s", the directory is not empty.', $this->_getPath($path, $name)));
         }
 
         foreach ($file_list as $file) {
             if ($file['type'] == '**dir') {
-                $result = $this->deleteFolder($this->_getPath($path, $name), $file['name'], $recursive);
+                $this->deleteFolder($this->_getPath($path, $name), $file['name'], $recursive);
             } else {
-                $result = $this->deleteFile($this->_getPath($path, $name), $file['name']);
-            }
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
+                $this->deleteFile($this->_getPath($path, $name), $file['name']);
             }
         }
 
         // Really delete the folder.
         list($path, $name) = $this->_escapeShellCommand($path, $name);
         $cmd = array('rmdir \"' . $name . '\"');
-        $err = $this->_command($path, $cmd);
-        if (is_a($err, 'PEAR_Error')) {
-            return PEAR::raiseError(sprintf(_("Unable to delete VFS folder \"%s\"."), $this->_getPath($path, $name)));
-        } else {
-            return true;
+
+        try {
+            $this->_command($path, $cmd);
+        } catch (VFS_Exception $e) {
+            throw new VFS_Exception(sprintf('Unable to delete VFS folder "%s".', $this->_getPath($path, $name)));
         }
     }
 
@@ -304,13 +261,11 @@ class VFS_smb extends VFS {
      * @param string $newpath  The new path of the file.
      * @param string $newname  The new filename.
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        if (is_a($result = $this->autocreatePath($newpath), 'PEAR_Error')) {
-            return $result;
-        }
+        $this->autocreatePath($newpath);
 
         // Double quotes not allowed in SMB filename. The '/' character should
         // also be removed from the beginning/end of the names.
@@ -318,7 +273,7 @@ class VFS_smb extends VFS {
         $newname = str_replace('"', "'", trim($newname, '/'));
 
         if (empty($oldname)) {
-            return PEAR::raiseError(_("Unable to rename VFS file to same name."));
+            throw new VFS_Exception('Unable to rename VFS file to same name.');
         }
 
         /* If the path was not empty (i.e. the path is not the root path),
@@ -333,11 +288,12 @@ class VFS_smb extends VFS {
         list($file, $name) = $this->_escapeShellCommand($oldname, $newname);
         $cmd = array('rename \"' .  str_replace('/', '\\\\', $oldpath) . $file . '\" \"' .
                                     str_replace('/', '\\\\', $newpath) . $name . '\"');
-        if (is_a($err = $this->_command('', $cmd), 'PEAR_Error')) {
-            return PEAR::raiseError(sprintf(_("Unable to rename VFS file \"%s\"."), $this->_getPath($path, $name)));
-        }
 
-        return true;
+        try {
+            $this->_command('', $cmd);
+        } catch (VFS_Exception $e) {
+            throw new VFS_Exception(sprintf('Unable to rename VFS file "%s".', $this->_getPath($path, $name)));
+        }
     }
 
     /**
@@ -346,9 +302,9 @@ class VFS_smb extends VFS {
      * @param string $path  The path of directory to create folder.
      * @param string $name  The name of the new folder.
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
         // In some samba versions after samba-3.0.25-pre2, $path must
         // end in a trailing slash.
@@ -361,11 +317,12 @@ class VFS_smb extends VFS {
 
         list($dir, $mkdir) = $this->_escapeShellCommand($path, $name);
         $cmd = array('mkdir \"' . $mkdir . '\"');
-        $err = $this->_command($dir, $cmd);
-        if (is_a($err, 'PEAR_Error')) {
-            return PEAR::raiseError(sprintf(_("Unable to create VFS folder \"%s\"."), $this->_getPath($path, $name)));
+
+        try {
+            $this->_command($dir, $cmd);
+        } catch (VFS_Exception $e) {
+            throw new VFS_Exception(sprintf('Unable to create VFS folder "%s".', $this->_getPath($path, $name)));
         }
-        return true;
     }
 
     /**
@@ -378,21 +335,19 @@ class VFS_smb extends VFS {
      *                           smbclient.
      * @param boolean $dironly   Show directories only?
      *
-     * @return boolean|PEAR_Error  File list on success or a PEAR_Error on
-     *                             failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function listFolder($path = '', $filter = null, $dotfiles = true, $dironly = false)
+    public function listFolder($path = '', $filter = null, $dotfiles = true,
+                               $dironly = false)
     {
         list($path) = $this->_escapeShellCommand($path);
-        $cmd = array('ls');
-        $res = $this->_command($path, $cmd);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
-        return $this->parseListing($res, $filter, $dotfiles, $dironly);
+        return $this->parseListing($this->_command($path, array('ls'), $filter, $dotfiles, $dironly);
     }
 
-    function parseListing($res, $filter, $dotfiles, $dironly)
+    /**
+     */
+    public function parseListing($res, $filter, $dotfiles, $dironly)
     {
         $num_lines = count($res);
         $files = array();
@@ -434,7 +389,7 @@ class VFS_smb extends VFS {
                 $my_type = '**dir';
                 $my_size = -1;
             } else {
-                $my_type = VFS::strtolower($ext_name[count($ext_name) - 1]);
+                $my_type = self::strtolower($ext_name[count($ext_name) - 1]);
             }
             $my_date = strtotime($split2[4] . ' ' . $split2[3] . ' ' .
                                  $split2[6] . ' ' . $split2[5]);
@@ -457,6 +412,7 @@ class VFS_smb extends VFS {
 
             $files[$filedata['name']] = $filedata;
         }
+
         return $files;
     }
 
@@ -468,32 +424,26 @@ class VFS_smb extends VFS {
      * @param mixed $filter        Hash of items to filter based on folderlist.
      * @param boolean $dotfolders  Include dotfolders? Irrelevant for SMB.
      *
-     * @return boolean|PEAR_Error  Folder list on success or a PEAR_Error on
-     *                             failure.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = null, $dotfolders = true)
+    public function listFolders($path = '', $filter = null, $dotfolders = true)
     {
-        $folders = array();
-        $folder = array();
-
-        $folderList = $this->listFolder($path, null, $dotfolders, true);
-        if (is_a($folderList, 'PEAR_Error')) {
-            return $folderList;
-        }
-
         // dirname will strip last component from path, even on a directory
-        $folder['val'] = dirname($path);
-        $folder['abbrev'] = '..';
-        $folder['label'] = '..';
-
-        $folders[$folder['val']] = $folder;
+        $folder = array(
+            ['val'] = dirname($path),
+            $folder['abbrev'] = '..',
+            $folder['label'] = '..'
+        );
+        $folders = array($folder['val'] => $folder);
 
+        $folderList = $this->listFolder($path, null, $dotfolders, true);
         foreach ($folderList as $files) {
-            $folder['val'] = $this->_getPath($path, $files['name']);
-            $folder['abbrev'] = $files['name'];
-            $folder['label'] = $folder['val'];
-
-            $folders[$folder['val']] = $folder;
+            $folders[$folder['val']] = array(
+                'val' => $this->_getPath($path, $files['name']),
+                'abbrev' => $files['name'],
+                'label' => $folder['val']
+            );
         }
 
         ksort($folders);
@@ -508,51 +458,34 @@ class VFS_smb extends VFS {
      * @param string $dest         The destination of the file.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function copy($path, $name, $dest, $autocreate = false)
+    public function copy($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
+            throw new VFS_Exception('Cannot copy file(s) - source and destination are the same.');
         }
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, true);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, true) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(sprintf(_("%s already exists."),
-                                                $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('%s already exists.', $this->_getPath($dest, $name)));
             }
         }
 
         if ($this->isFolder($path, $name)) {
-            if (is_a($result = $this->_copyRecursive($path, $name, $dest), 'PEAR_Error')) {
-                return $result;
-            }
+            $this->_copyRecursive($path, $name, $dest);
         } else {
-            $tmpFile = $this->readFile($path, $name);
-            if (is_a($tmpFile, 'PEAR_Error')) {
-                return PEAR::raiseError(sprintf(_("Failed to retrieve: %s"), $orig));
-            }
-
-            $result = $this->write($dest, $name, $tmpFile);
-            if (is_a($result, 'PEAR_Error')) {
-                return PEAR::raiseError(sprintf(_("Copy failed: %s"),
-                                                $this->_getPath($dest, $name)));
+            try {
+                $this->write($dest, $name, $this->readFile($path, $name));
+            } catch (VFS_Exception $e) {
+                throw new VFS_Exception(sprintf('Copy failed: %s', $this->_getPath($dest, $name)));
             }
         }
-
-        return true;
     }
 
     /**
@@ -563,52 +496,41 @@ class VFS_smb extends VFS {
      * @param string $dest         The destination of the file.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return boolean|PEAR_Error  True on success or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function move($path, $name, $dest, $autocreate = false)
+    public function move($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
+            throw new VFS_Exception('Cannot copy file(s) - destination is within source.');
         }
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, true);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, true) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(sprintf(_("%s already exists."),
-                                                $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('%s already exists.', $this->_getPath($dest, $name)));
             }
         }
 
-        $err = $this->rename($path, $name, $dest, $name);
-        if (is_a($err, 'PEAR_Error')) {
-            return PEAR::raiseError(sprintf(_("Failed to move to \"%s\"."),
-                                            $this->_getPath($dest, $name)));
+        try {
+            $this->rename($path, $name, $dest, $name);
+        } catch (VFS_Exception $e) {
+            throw new VFS_Exception(sprintf('Failed to move to "%s".', $this->_getPath($dest, $name)));
         }
-        return true;
     }
 
     /**
      * Replacement for escapeshellcmd(), variable length args, as we only want
      * certain characters escaped.
      *
-     * @access private
-     *
      * @param array $array  Strings to escape.
      *
-     * @return array
+     * @return array  TODO
      */
-    function _escapeShellCommand()
+    protected function _escapeShellCommand()
     {
         $ret = array();
         $args = func_get_args();
@@ -621,13 +543,12 @@ class VFS_smb extends VFS {
     /**
      * Executes a command and returns output lines in array.
      *
-     * @access private
-     *
-     * @param string $cmd  Command to be executed
+     * @param string $cmd  Command to be executed.
      *
-     * @return mixed  Array on success, false on failure.
+     * @return array  Array on success.
+     * @throws VFS_Exception
      */
-    function _execute($cmd)
+    protected function _execute($cmd)
     {
         $cmd = str_replace('"-U%"', '-N', $cmd);
         exec($cmd, $out, $ret);
@@ -654,7 +575,8 @@ class VFS_smb extends VFS {
             if (!$err) {
                 $err = $out ? $out[count($out) - 1] : $ret;
             }
-            return PEAR::raiseError($err);
+
+            throw new VFS_Exception($err);
         }
 
         // Check for errors even on success.
@@ -671,7 +593,7 @@ class VFS_smb extends VFS {
         }
 
         if ($err) {
-            return PEAR::raiseError($err);
+            throw new VFS_Exception($err);
         }
 
         return $out;
@@ -681,14 +603,13 @@ class VFS_smb extends VFS {
      * Executes SMB commands - without authentication - and returns output
      * lines in array.
      *
-     * @access private
-     *
      * @param array $path  Base path for command.
      * @param array $cmd   Commands to be executed.
      *
-     * @return mixed  Array on success, false on failure.
+     * @return array  Array on success.
+     * @throws VFS_Exception
      */
-    function _command($path, $cmd)
+    protected function _command($path, $cmd)
     {
         list($share) = $this->_escapeShellCommand($this->_params['share']);
         putenv('PASSWD=' . $this->_params['password']);
@@ -704,6 +625,7 @@ class VFS_smb extends VFS {
             $fullcmd .= $c . ";";
         }
         $fullcmd .= '"';
+
         return $this->_execute($fullcmd);
     }
 
index 395c5e0..fdb374f 100644 (file)
@@ -1,41 +1,30 @@
 <?php
-
-/**
- * File value for vfs_type column.
- */
-define('VFS_FILE', 1);
-
-/**
- * Folder value for vfs_type column.
- */
-define('VFS_FOLDER', 2);
-
 /**
  * VFS implementation for PHP's PEAR database abstraction layer.
  *
  * Required values for $params:<pre>
- *   'phptype'      The database type (ie. 'pgsql', 'mysql', etc.).</pre>
+ * phptype - (string) The database type (ie. 'pgsql', 'mysql', etc.).</pre>
  *
  * Optional values:<pre>
- *   'table'          The name of the vfs table in 'database'. Defaults to
- *                    'horde_vfs'.</pre>
+ * table - (string) The name of the vfs table in 'database'. Defaults to
+ *         'horde_vfs'.</pre>
  *
  * 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>
+ * hostspec - (string) The hostname of the database server.
+ * protocol - (string) The communication protocol ('tcp', 'unix', etc.).
+ * database - (string) The name of the database.
+ * username - (string) The username with which to connect to the database.
+ * password - (string) The password associated with 'username'.
+ * options - (array) Additional options to pass to the database.
+ * tty - (string) The TTY on which to connect to the database.
+ * port - (integer) The port on which to connect to the database.</pre>
  *
  * Optional values when using separate reading and writing servers, for example
  * in replication settings:<pre>
- *   'splitread'   Boolean, whether to implement the separation or not.
- *   'read'        Array containing the parameters which are different for
- *                 the read database connection, currently supported
- *                 only 'hostspec' and 'port' parameters.</pre>
+ * splitread - (boolean) Whether to implement the separation or not.
+ * read - (array) Parameters which are different for the read database
+ *                connection, currently supported only 'hostspec' and 'port'
+ *                parameters.</pre>
  *
  * The table structure for the VFS can be found in data/vfs.sql.
  *
@@ -60,14 +49,20 @@ define('VFS_FOLDER', 2);
  * @author  Chuck Hagenbuch <chuck@horde.org>
  * @package VFS
  */
-class VFS_sql extends VFS {
+class VFS_sql extends VFS
+{
+    /* File value for vfs_type column. */
+    const FILE = 1;
+
+    /* Folder value for vfs_type column. */
+    const FOLDER = 2;
 
     /**
      * Handle for the current database connection.
      *
      * @var DB
      */
-    var $_db = false;
+    protected $_db = false;
 
     /**
      * Handle for the current database connection, used for writing. Defaults
@@ -75,7 +70,7 @@ class VFS_sql extends VFS {
      *
      * @var DB
      */
-    var $_write_db;
+    protected $_write_db;
 
     /**
      * Boolean indicating whether or not we're connected to the SQL
@@ -83,7 +78,7 @@ class VFS_sql extends VFS {
      *
      * @var boolean
      */
-    var $_connected = false;
+    protected $_connected = false;
 
     /**
      * Retrieves the filesize from the VFS.
@@ -91,14 +86,12 @@ class VFS_sql extends VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return int The file size.
+     * @return integer  The file size.
+     * @throws VFS_Exception
      */
-    function size($path, $name)
+    public function size($path, $name)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         $length_op = $this->_getFileSizeOp();
         $sql = sprintf(
@@ -111,7 +104,7 @@ class VFS_sql extends VFS {
         $size = $this->_db->getOne($sql, $values);
 
         if (is_null($size)) {
-            return PEAR::raiseError(sprintf(_("Unable to check file size of \"%s/%s\"."), $path, $name));
+            throw new VFS_Exception(sprintf('Unable to check file size of "%s/%s".', $path, $name));
         }
 
         return $size;
@@ -120,22 +113,19 @@ class VFS_sql extends VFS {
     /**
      * Returns the size of a file.
      *
-     * @access public
-     *
      * @param string $path  The path of the file.
      * @param string $name  The filename.
      *
-     * @return integer  The size of the folder in bytes or PEAR_Error on
-     *                  failure.
+     * @return integer  The size of the folder in bytes.
+     * @throws VFS_Exception
      */
-    function getFolderSize($path = null, $name = null)
+    public function getFolderSize($path = null, $name = null)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
-        $where = (is_null($path)) ? null : sprintf('WHERE vfs_path LIKE %s', ((!strlen($path)) ? '""' : $this->_db->quote($this->_convertPath($path) . '%')));
+        $where = is_null($path)
+            ? null
+            : sprintf('WHERE vfs_path LIKE %s', ((!strlen($path)) ? '""' : $this->_db->quote($this->_convertPath($path) . '%')));
         $length_op = $this->_getFileSizeOp();
         $sql = sprintf(
             'SELECT SUM(%s(vfs_data)) FROM %s %s',
@@ -146,7 +136,7 @@ class VFS_sql extends VFS {
         $this->log($sql, PEAR_LOG_DEBUG);
         $size = $this->_db->getOne($sql);
 
-        return $size !== null ? $size : 0;
+        return is_null($size) ? $size : 0;
     }
 
     /**
@@ -156,17 +146,15 @@ class VFS_sql extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
-
-        return $this->_readBlob($this->_params['table'], 'vfs_data',
-                                array('vfs_path' => $this->_convertPath($path),
-                                      'vfs_name' => $name));
+        $this->_connect();
+        return $this->_readBlob($this->_params['table'], 'vfs_data', array(
+            'vfs_path' => $this->_convertPath($path),
+            'vfs_name' => $name
+        ));
     }
 
     /**
@@ -176,27 +164,28 @@ class VFS_sql extends VFS {
      *
      * @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 be
-     *                            stored in here).
-     * @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 read.
-     * @param integer $remaining  The bytes that are left, after the part that is
-     *                            retrieved.
+     * @param integer $offset     The offset of the part. (The new offset will
+     *                            be stored in here).
+     * @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 read.
+     * @param integer $remaining  The bytes that are left, after the part that
+     *                            is retrieved.
      *
-     * @return string The file data.
+     * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function readByteRange($path, $name, &$offset, $length = -1, &$remaining)
+    public function readByteRange($path, $name, &$offset, $length = -1,
+                                  &$remaining)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
-        $data = $this->_readBlob($this->_params['table'], 'vfs_data',
-                                 array('vfs_path' => $this->_convertPath($path),
-                                       'vfs_name' => $name));
+        $data = $this->_readBlob($this->_params['table'], 'vfs_data', array(
+            'vfs_path' => $this->_convertPath($path),
+            'vfs_name' => $name
+        ));
 
         // Calculate how many bytes MUST be read, so the remainging
         // bytes and the new offset can be calculated correctly.
@@ -224,9 +213,9 @@ class VFS_sql extends VFS {
      *                             be stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
         /* Don't need to check quota here since it will be checked when
          * writeData() is called. */
@@ -244,19 +233,12 @@ class VFS_sql extends VFS {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        $result = $this->_checkQuotaWrite('string', $data);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
-
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_checkQuotaWrite('string', $data);
+        $this->_connect();
 
         $path = $this->_convertPath($path);
 
@@ -268,9 +250,9 @@ class VFS_sql extends VFS {
         $this->log($sql, PEAR_LOG_DEBUG);
         $id = $this->_db->getOne($sql, $values);
 
-        if (is_a($id, 'PEAR_Error')) {
+        if ($id instanceof PEAR_Error) {
             $this->log($id, PEAR_LOG_ERR);
-            return $id;
+            throw new VFS_Exception($id->getMessage());
         }
 
         if (!is_null($id)) {
@@ -284,28 +266,26 @@ class VFS_sql extends VFS {
             $parent = implode('/', $dirs);
             if (!$this->isFolder($parent, $path_name)) {
                 if (!$autocreate) {
-                    return PEAR::raiseError(sprintf(_("Folder \"%s\" does not exist"), $path), 'horde.error');
-                } else {
-                    $result = $this->autocreatePath($path);
-                    if (is_a($result, 'PEAR_Error')) {
-                        return $result;
-                    }
+                    throw new VFS_Exception(sprintf('Folder "%s" does not exist', $path));
                 }
+
+                $this->autocreatePath($path);
             }
 
             $id = $this->_write_db->nextId($this->_params['table']);
-            if (is_a($id, 'PEAR_Error')) {
+            if ($id instanceof PEAR_Error) {
                 $this->log($id, PEAR_LOG_ERR);
-                return $id;
+                throw new VFS_Exception($id->getMessage());
             }
 
-            return $this->_insertBlob($this->_params['table'], 'vfs_data',
-                                      $data, array('vfs_id' => $id,
-                                                   'vfs_type' => VFS_FILE,
-                                                   'vfs_path' => $path,
-                                                   'vfs_name' => $name,
-                                                   'vfs_modified' => time(),
-                                                   'vfs_owner' => $this->_params['user']));
+            return $this->_insertBlob($this->_params['table'], 'vfs_data', $data, array(
+                'vfs_id' => $id,
+                'vfs_type' => self::FILE,
+                'vfs_path' => $path,
+                'vfs_name' => $name,
+                'vfs_modified' => time(),
+                'vfs_owner' => $this->_params['user']
+            ));
         }
     }
 
@@ -315,31 +295,24 @@ class VFS_sql extends 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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        $result = $this->_checkQuotaDelete($path, $name);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
-
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_checkQuotaDelete($path, $name);
+        $this->_connect();
 
         $path = $this->_convertPath($path);
 
         $sql = sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path %s AND vfs_name = ?',
                        $this->_params['table'],
                        (!strlen($path) && $this->_db->dbsyntax == 'oci8') ? ' IS NULL' : ' = ' . $this->_db->quote($path));
-        $values = array(VFS_FILE, $name);
+        $values = array(self::FILE, $name);
         $this->log($sql, PEAR_LOG_DEBUG);
         $result = $this->_db->query($sql, $values);
 
         if ($this->_db->affectedRows() == 0) {
-            return PEAR::raiseError(_("Unable to delete VFS file."));
+            throw new VFS_Exception('Unable to delete VFS file.');
         }
 
         return $result;
@@ -353,14 +326,11 @@ class VFS_sql extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         if (strpos($newpath, '/') === false) {
             $parent = '';
@@ -368,10 +338,9 @@ class VFS_sql extends VFS {
         } else {
             list($parent, $path) = explode('/', $newpath, 2);
         }
+
         if (!$this->isFolder($parent, $path)) {
-            if (is_a($result = $this->autocreatePath($newpath), 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($newpath);
         }
 
         $oldpath = $this->_convertPath($oldpath);
@@ -386,13 +355,13 @@ class VFS_sql extends VFS {
         $result = $this->_write_db->query($sql, $values);
 
         if ($this->_write_db->affectedRows() == 0) {
-            return PEAR::raiseError(_("Unable to rename VFS file."));
+            throw new VFS_Exception('Unable to rename VFS file.');
         }
 
         $rename = $this->_recursiveRename($oldpath, $oldname, $newpath, $newname);
-        if (is_a($rename, 'PEAR_Error')) {
+        if ($rename instanceof PEAR_Error) {
             $this->log($rename, PEAR_LOG_ERR);
-            return PEAR::raiseError(sprintf(_("Unable to rename VFS directory: %s."), $rename->getMessage()));
+            throw new VFS_Exception(sprintf('Unable to rename VFS directory: %s.', $rename->getMessage()));
         }
 
         return $result;
@@ -404,26 +373,23 @@ class VFS_sql extends 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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         $id = $this->_write_db->nextId($this->_params['table']);
-        if (is_a($id, 'PEAR_Error')) {
+        if ($id instanceof PEAR_Error) {
             $this->log($id, PEAR_LOG_ERR);
-            return $id;
+            throw new VFS_Exception($id->getMessage());
         }
 
-        $sql  = 'INSERT INTO ' . $this->_params['table'];
-        $sql .= ' (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified, vfs_owner) VALUES (?, ?, ?, ?, ?, ?)';
+        $sql = 'INSERT INTO ' . $this->_params['table'] .
+               ' (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified, vfs_owner) VALUES (?, ?, ?, ?, ?, ?)';
         $this->log($sql, PEAR_LOG_DEBUG);
 
-        $values = array($id, VFS_FOLDER, $this->_convertPath($path), $name, time(), $this->_params['user']);
+        $values = array($id, self::FOLDER, $this->_convertPath($path), $name, time(), $this->_params['user']);
 
         return $this->_db->query($sql, $values);
     }
@@ -435,28 +401,20 @@ class VFS_sql extends VFS {
      * @param string $name        The folder name to use.
      * @param boolean $recursive  Force a recursive delete?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         $path = $this->_convertPath($path);
-
         $folderPath = $this->_getNativePath($path, $name);
 
         /* Check if not recursive and fail if directory not empty */
         if (!$recursive) {
             $folderList = $this->listFolder($folderPath, null, true);
-            if (is_a($folderList, 'PEAR_Error')) {
-                $this->log($folderList, PEAR_LOG_ERR);
-                return $folderList;
-            } elseif (!empty($folderList)) {
-                return PEAR::raiseError(sprintf(_("Unable to delete %s, the directory is not empty"),
-                                                $path . '/' . $name));
+            if (!empty($folderList)) {
+                throw new VFS_Exception(sprintf('Unable to delete %s, the directory is not empty', $path . '/' . $name));
             }
         }
 
@@ -467,9 +425,9 @@ class VFS_sql extends VFS {
                        (!strlen($folderPath) && $this->_write_db->dbsyntax == 'oci8') ? ' IS NULL' : ' LIKE ' . $this->_write_db->quote($this->_getNativePath($folderPath, '%')));
         $this->log($sql, PEAR_LOG_DEBUG);
         $deleteContents = $this->_write_db->query($sql);
-        if (is_a($deleteContents, 'PEAR_Error')) {
+        if ($deleteContents instanceof PEAR_Error) {
             $this->log($deleteContents, PEAR_LOG_ERR);
-            return PEAR::raiseError(sprintf(_("Unable to delete VFS recursively: %s."), $deleteContents->getMessage()));
+            throw new VFS_Exception(sprintf('Unable to delete VFS recursively: %s.', $deleteContents->getMessage()));
         }
 
         /* Now delete everything inside the folder. */
@@ -478,9 +436,9 @@ class VFS_sql extends VFS {
                        (!strlen($path) && $this->_write_db->dbsyntax == 'oci8') ? ' IS NULL' : ' = ' . $this->_write_db->quote($folderPath));
         $this->log($sql, PEAR_LOG_DEBUG);
         $delete = $this->_write_db->query($sql);
-        if (is_a($delete, 'PEAR_Error')) {
+        if ($delete instanceof PEAR_Error) {
             $this->log($delete, PEAR_LOG_ERR);
-            return PEAR::raiseError(sprintf(_("Unable to delete VFS directory: %s."), $delete->getMessage()));
+            throw new VFS_Exception(sprintf('Unable to delete VFS directory: %s.', $delete->getMessage()));
         }
 
         /* All ok now delete the actual folder */
@@ -490,12 +448,10 @@ class VFS_sql extends VFS {
         $values = array($name);
         $this->log($sql, PEAR_LOG_DEBUG);
         $delete = $this->_write_db->query($sql, $values);
-        if (is_a($delete, 'PEAR_Error')) {
+        if ($delete instanceof PEAR_Error) {
             $this->log($delete, PEAR_LOG_ERR);
-            return PEAR::raiseError(sprintf(_("Unable to delete VFS directory: %s."), $delete->getMessage()));
+            throw new VFS_Exception(sprintf('Unable to delete VFS directory: %s.', $delete->getMessage()));
         }
-
-        return $delete;
     }
 
     /**
@@ -507,15 +463,13 @@ class VFS_sql extends VFS {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show directories only?
      *
-     * @return mixed  File list on success or false on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path, $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path, $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         $path = $this->_convertPath($path);
 
@@ -533,8 +487,8 @@ class VFS_sql extends VFS {
                        $where);
         $this->log($sql, PEAR_LOG_DEBUG);
         $fileList = $this->_db->getAll($sql);
-        if (is_a($fileList, 'PEAR_Error')) {
-            return $fileList;
+        if ($fileList instanceof PEAR_Error) {
+            throw new VFS_Exception($fileList->getMessage());
         }
 
         $files = array();
@@ -546,17 +500,17 @@ class VFS_sql extends VFS {
 
             $file['name'] = $line[0];
 
-            if ($line[1] == VFS_FILE) {
+            if ($line[1] == self::FILE) {
                 $name = explode('.', $line[0]);
 
                 if (count($name) == 1) {
                     $file['type'] = '**none';
                 } else {
-                    $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                    $file['type'] = self::strtolower($name[count($name) - 1]);
                 }
 
                 $file['size'] = $line[2];
-            } elseif ($line[1] == VFS_FOLDER) {
+            } elseif ($line[1] == self::FOLDER) {
                 $file['type'] = '**dir';
                 $file['size'] = -1;
             }
@@ -592,14 +546,13 @@ class VFS_sql extends VFS {
      *                             folderlist.
      * @param boolean $dotfolders  Include dotfolders?
      *
-     * @return mixed  Folder list on success or PEAR_Error object on failure.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = array(), $dotfolders = true)
+    public function listFolders($path = '', $filter = array(),
+                                $dotfolders = true)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         $path = $this->_convertPath($path);
 
@@ -607,11 +560,11 @@ class VFS_sql extends VFS {
         $sql .= ' WHERE vfs_path = ? AND vfs_type = ?';
         $this->log($sql, PEAR_LOG_DEBUG);
 
-        $values = array($path, VFS_FOLDER);
+        $values = array($path, self::FOLDER);
 
         $folderList = $this->_db->getAll($sql, $values);
-        if (is_a($folderList, 'PEAR_Error')) {
-            return $folderList;
+        if ($folderList instanceof PEAR_Error) {
+            throw new VFS_Exception($folderList->getMessage());
         }
 
         $folders = array();
@@ -663,37 +616,36 @@ class VFS_sql extends VFS {
      * @param string $path   The VFS path to clean.
      * @param integer $secs  The minimum amount of time (in seconds) required
      *                       before a file is removed.
+     *
+     * @throws VFS_Exception
      */
-    function gc($path, $secs = 345600)
+    public function gc($path, $secs = 345600)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         $sql = 'DELETE FROM ' . $this->_params['table']
             . ' WHERE vfs_type = ? AND vfs_modified < ? AND (vfs_path = ? OR vfs_path LIKE ?)';
         $this->log($sql, PEAR_LOG_DEBUG);
 
-        $values = array(VFS_FILE,
-                        time() - $secs,
-                        $this->_convertPath($path),
-                        $this->_convertPath($path) . '/%');
+        $values = array(
+            self::FILE,
+            time() - $secs,
+            $this->_convertPath($path),
+            $this->_convertPath($path) . '/%'
+        );
 
-        return $this->_write_db->query($sql, $values);
+        $this->_write_db->query($sql, $values);
     }
 
     /**
      * Renames all child paths.
      *
-     * @access private
-     *
      * @param string $path  The path of the folder to rename.
      * @param string $name  The foldername to use.
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function _recursiveRename($oldpath, $oldname, $newpath, $newname)
+    protected function _recursiveRename($oldpath, $oldname, $newpath, $newname)
     {
         $oldpath = $this->_convertPath($oldpath);
         $newpath = $this->_convertPath($newpath);
@@ -702,7 +654,7 @@ class VFS_sql extends VFS {
         $sql .= ' WHERE vfs_type = ? AND vfs_path = ?';
         $this->log($sql, PEAR_LOG_DEBUG);
 
-        $values = array(VFS_FOLDER, $this->_getNativePath($oldpath, $oldname));
+        $values = array(self::FOLDER, $this->_getNativePath($oldpath, $oldname));
 
         $folderList = $this->_db->getCol($sql, 0, $values);
 
@@ -715,21 +667,19 @@ class VFS_sql extends VFS {
 
         $values = array($this->_getNativePath($newpath, $newname), $this->_getNativePath($oldpath, $oldname));
 
-        return $this->_write_db->query($sql, $values);
+        $this->_write_db->query($sql, $values);
     }
 
     /**
      * Return a full filename on the native filesystem, from a VFS
      * path and name.
      *
-     * @access private
-     *
      * @param string $path  The VFS file path.
      * @param string $name  The VFS filename.
      *
      * @return string  The full native filename.
      */
-    function _getNativePath($path, $name)
+    protected function _getNativePath($path, $name)
     {
         if (!strlen($path)) {
             return $name;
@@ -746,50 +696,47 @@ class VFS_sql extends VFS {
     /**
      * Attempts to open a persistent connection to the SQL server.
      *
-     * @access private
-     *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function _connect()
+    protected function _connect()
     {
         if ($this->_connected) {
             return true;
         }
 
         if (!is_array($this->_params)) {
-            return PEAR::raiseError(_("No configuration information specified for SQL VFS."));
+            throw new VFS_Exception('No configuration information specified for SQL VFS.');
         }
 
         $required = array('phptype');
         foreach ($required as $val) {
             if (!isset($this->_params[$val])) {
-                return PEAR::raiseError(sprintf(_("Required \"%s\" not specified in VFS configuration."), $val));
+                throw new VFS_Exception(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';
-        }
+        $this->_params = array_merge(array(
+            'database' => '',
+            'hostspec' => '',
+            'table' => 'horde_vfs',
+            'username' => ''
+        ), $this->_params);
 
         /* Connect to the SQL server using the supplied parameters. */
         require_once 'DB.php';
-        $this->_write_db = &DB::connect($this->_params,
-                                        array('persistent' => !empty($this->_params['persistent']),
-                                              'ssl' => !empty($this->_params['ssl'])));
-        if (is_a($this->_write_db, 'PEAR_Error')) {
+        $this->_write_db = DB::connect(
+            $this->_params,
+            array(
+                'persistent' => !empty($this->_params['persistent']),
+                'ssl' => !empty($this->_params['ssl']
+            )
+        ));
+
+        if ($this->_write_db instanceof PEAR_Error) {
             $this->log($this->_write_db, PEAR_LOG_ERR);
-            $error = $this->_write_db;
+            $error = new VFS_Exception($this->_write_db->getMessage());
             $this->_write_db = false;
-            return $error;
+            throw $error;
         }
 
         // Set DB portability options.
@@ -805,11 +752,16 @@ class VFS_sql extends VFS {
          * seperately. */
         if (!empty($this->_params['splitread'])) {
             $params = array_merge($this->_params, $this->_params['read']);
-            $this->_db = &DB::connect($params,
-                                      array('persistent' => !empty($params['persistent']),
-                                            'ssl' => !empty($params['ssl'])));
-            if (is_a($this->_db, 'PEAR_Error')) {
-                return $this->_db;
+            $this->_db = DB::connect(
+                $params,
+                array(
+                    'persistent' => !empty($params['persistent']),
+                    'ssl' => !empty($params['ssl']
+                )
+            ));
+
+            if ($this->_db instanceof PEAR_Error) {
+                throw new VFS_Exception($this->_db->getMessage());
             }
 
             // Set DB portability options.
@@ -827,24 +779,22 @@ class VFS_sql extends VFS {
         }
 
         $this->_connected = true;
-        return true;
     }
 
     /**
      * Read file data from the SQL VFS backend.
      *
-     * @access private
-     *
      * @param string $table    The VFS table name.
      * @param string $field    TODO
      * @param array $criteria  TODO
      *
      * @return mixed  TODO
+     * @throws VFS_Exception
      */
-    function _readBlob($table, $field, $criteria)
+    protected function _readBlob($table, $field, $criteria)
     {
         if (!count($criteria)) {
-            return PEAR::raiseError('You must specify the fetch criteria');
+            throw new VFS_Exception('You must specify the fetch criteria');
         }
 
         $where = '';
@@ -869,10 +819,11 @@ class VFS_sql extends VFS {
             if (OCIFetchInto($statement, $lob)) {
                 $result = $lob[0]->load();
                 if (is_null($result)) {
-                    $result = PEAR::raiseError('Unable to load SQL data.');
+                    throw new VFS_Exception('Unable to load SQL data.');
                 }
             } else {
-                $result = PEAR::raiseError('Unable to load SQL data.');
+                OCIFreeStatement($statement);
+                throw new VFS_Exception('Unable to load SQL data.');
             }
             OCIFreeStatement($statement);
             break;
@@ -891,7 +842,7 @@ class VFS_sql extends VFS {
             $result = $this->_db->getOne($sql);
 
             if (is_null($result)) {
-                $result = PEAR::raiseError('Unable to load SQL data.');
+                throw new VFS_Exception('Unable to load SQL data.');
             } else {
                 switch ($this->_db->dbsyntax) {
                 case 'pgsql':
@@ -907,19 +858,17 @@ class VFS_sql extends VFS {
     /**
      * TODO
      *
-     * @access private
-     *
      * @param string $table       TODO
      * @param string $field       TODO
      * @param string $data        TODO
      * @param string $attributes  TODO
      *
      * @return mixed  TODO
+     * @throws VFS_Exception
      */
-    function _insertBlob($table, $field, $data, $attributes)
+    protected function _insertBlob($table, $field, $data, $attributes)
     {
-        $fields = array();
-        $values = array();
+        $fields = $values = array();
 
         switch ($this->_write_db->dbsyntax) {
         case 'oci8':
@@ -944,7 +893,10 @@ class VFS_sql extends VFS {
             $result = OCICommit($this->_write_db->connection);
             $lob->free();
             OCIFreeStatement($statement);
-            return $result ? true : PEAR::raiseError('Unknown Error');
+            if ($result) {
+                return true;
+            }
+            throw new VFS_Exception('Unknown Error');
 
         default:
             foreach ($attributes as $key => $value) {
@@ -978,8 +930,6 @@ class VFS_sql extends VFS {
     /**
      * TODO
      *
-     * @access private
-     *
      * @param string $table      TODO
      * @param string $field      TODO
      * @param string $data       TODO
@@ -987,11 +937,11 @@ class VFS_sql extends VFS {
      * @param array $alsoupdate  TODO
      *
      * @return mixed  TODO
+     * @throws VFS_Exception
      */
-    function _updateBlob($table, $field, $data, $where, $alsoupdate)
+    protected function _updateBlob($table, $field, $data, $where, $alsoupdate)
     {
-        $fields = array();
-        $values = array();
+        $fields = $values = array();
 
         switch ($this->_write_db->dbsyntax) {
         case 'oci8':
@@ -1015,7 +965,10 @@ class VFS_sql extends VFS {
             $result = OCICommit($this->_write_db->connection);
             $lob[0]->free();
             OCIFreeStatement($statement);
-            return $result ? true : PEAR::raiseError('Unknown Error');
+            if ($result) {
+                return true;
+            }
+            throw new VFS_Exception('Unknown Error');
 
         default:
             $updatestring = '';
@@ -1063,21 +1016,21 @@ class VFS_sql extends VFS {
      * Namely, we will treat '/' as a base directory as this is pretty much
      * the standard way to access base directories over most filesystems.
      *
-     * @access private
-     *
      * @param string $path  A VFS path.
      *
      * @return string  The path with any surrouding slashes stripped off.
      */
-    function _convertPath($path)
+    protected function _convertPath($path)
     {
         return trim($path, '/');
     }
 
     /**
      * TODO
+     *
+     * @return string  TODO
      */
-    function _getFileSizeOp()
+    protected function _getFileSizeOp()
     {
         switch ($this->_db->dbsyntax) {
         case 'mysql':
@@ -1102,15 +1055,14 @@ class VFS_sql extends VFS {
      * @param string $path  Path to possible folder
      * @param string $name  Name of possible folder
      *
-     * @return boolean        True if $path/$name is a folder
+     * @return boolean  True if $path/$name is a folder
      */
-    function isFolder($path, $name)
+    public function isFolder($path, $name)
     {
-        if ($path == '' && $name == '') {
+        return (($path == '') && ($name == ''))
             // The root of VFS is always a folder.
-            return true;
-        }
-        return parent::isFolder($path, $name);
+            ? true
+            : parent::isFolder($path, $name);
     }
 
 }
index 0325b56..8143a01 100644 (file)
@@ -4,16 +4,6 @@
  */
 
 /**
- * File value for vfs_type column.
- */
-define('VFS_FILE', 1);
-
-/**
- * Folder value for vfs_type column.
- */
-define('VFS_FOLDER', 2);
-
-/**
  * VFS_file parent class.
  */
 include_once 'VFS/file.php';
@@ -23,23 +13,23 @@ include_once 'VFS/file.php';
  * 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
- *                      actually stored.</pre>
+ * phptype - (string) The database type (ie. 'pgsql', 'mysql', etc.).
+ * vfsroot - (string) The root directory of where the files should be
+ *           actually stored.</pre>
  *
  * Optional values:<pre>
- *      'table'         The name of the vfs table in 'database'. Defaults to
- *                      'horde_vfs'.</pre>
+ * table - (string) The name of the vfs table in 'database'. Defaults to
+ *         'horde_vfs'.</pre>
  *
  * 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>
+ * hostspec - (string) The hostname of the database server.
+ * protocol - (string) The communication protocol ('tcp', 'unix', etc.).
+ * database - (string) The name of the database.
+ * username - (string) The username with which to connect to the database.
+ * password - (string) The password associated with 'username'.
+ * options - (array) Additional options to pass to the database.
+ * tty - (string) The TTY on which to connect to the database.
+ * port - (integer) The port on which to connect to the database.</pre>
  *
  * The table structure for the VFS can be found in
  * data/vfs.sql.
@@ -47,14 +37,20 @@ include_once 'VFS/file.php';
  * @author  Michael Varghese <mike.varghese@ascellatech.com>
  * @package VFS
  */
-class VFS_sql_file extends VFS_file {
+class VFS_sql_file extends VFS_file
+{
+    /* File value for vfs_type column. */
+    const FILE = 1;
+
+    /* Folder value for vfs_type column. */
+    const FOLDER = 2;
 
     /**
      * Handle for the current database connection.
      *
      * @var DB
      */
-    var $_db = false;
+    protected $_db = false;
 
     /**
      * Store a file in the VFS, with the data copied from a temporary
@@ -66,9 +62,9 @@ class VFS_sql_file extends VFS_file {
      *                             stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
         /* No need to check quota here as we will check it when we call
          * writeData(). */
@@ -84,38 +80,32 @@ class VFS_sql_file extends VFS_file {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        $res = $this->_checkQuotaWrite('string', $data);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaWrite('string', $data);
 
         $fp = @fopen($this->_getNativePath($path, $name), 'w');
         if (!$fp) {
             if ($autocreate) {
-                $result = $this->autocreatePath($path);
-                if (is_a($result, 'PEAR_Error')) {
-                    return $result;
-                }
+                $this->autocreatePath($path);
                 $fp = @fopen($this->_getNativePath($path, $name), 'w');
                 if (!$fp) {
-                    return PEAR::raiseError(_("Unable to open VFS file for writing."));
+                    throw new VFS_Exception('Unable to open VFS file for writing.');
                 }
             } else {
-                return PEAR::raiseError(_("Unable to open VFS file for writing."));
+                throw new VFS_Exception('Unable to open VFS file for writing.');
             }
         }
 
         if (!@fwrite($fp, $data)) {
-            return PEAR::raiseError(_("Unable to write VFS file data."));
+            throw new VFS_Exception('Unable to write VFS file data.');
         }
 
-        if (is_a($this->_writeSQLData($path, $name, $autocreate), 'PEAR_Error')) {
+        if ($this->_writeSQLData($path, $name, $autocreate) instanceof PEAR_Error) {
             @unlink($this->_getNativePath($path, $name));
-            return PEAR::raiseError(_("Unable to write VFS file data."));
+            throw new VFS_Exception('Unable to write VFS file data.');
         }
     }
 
@@ -127,37 +117,30 @@ class VFS_sql_file extends VFS_file {
      * @param string $dest         The new filename.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function move($path, $name, $dest, $autocreate = false)
+    public function move($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getNativePath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
+            throw new VFS_Exception('Cannot move file(s) - destination is within source.');
         }
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, false);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, false) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(_("Unable to move VFS file."));
+                throw new VFS_Exception('Unable to move VFS file.');
             }
         }
 
         if (strpos($dest, $this->_getSQLNativePath($path, $name)) !== false) {
-            return PEAR::raiseError(_("Unable to move VFS file."));
+            throw new VFS_Exception('Unable to move VFS file.');
         }
 
-        return $this->rename($path, $name, $dest, $name);
+        $this->rename($path, $name, $dest, $name);
     }
 
     /**
@@ -168,68 +151,53 @@ class VFS_sql_file extends VFS_file {
      * @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.
+     * @throws VFS_Exception
      */
-    function copy($path, $name, $dest, $autocreate = false)
+    public function copy($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getNativePath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
+            throw new VFS_Exception('Cannot copy file(s) - source and destination are the same.');
         }
 
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($autocreate) {
-            $result = $this->autocreatePath($dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, false);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, false) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(_("Unable to copy VFS file."));
+                throw new VFS_Exception('Unable to copy VFS file.');
             }
         }
 
         if (strpos($dest, $this->_getSQLNativePath($path, $name)) !== false) {
-            return PEAR::raiseError(_("Unable to copy VFS file."));
+            throw new VFS_Exception('Unable to copy VFS file.');
         }
 
         if (is_dir($orig)) {
             return $this->_recursiveCopy($path, $name, $dest);
         }
 
-        $res = $this->_checkQuotaWrite('file', $orig);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaWrite('file', $orig);
 
         if (!@copy($orig, $this->_getNativePath($dest, $name))) {
-            return PEAR::raiseError(_("Unable to copy VFS file."));
+            throw new VFS_Exception('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']);
+        $values = array($id, self::FILE, $dest, $name, time(), $this->_params['user']);
 
         $result = $this->_db->query($query, $values);
 
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             unlink($this->_getNativePath($dest, $name));
-            return $result;
+            throw new VFS_Exception($result->getMessage());
         }
-
-        return true;
     }
 
     /**
@@ -238,32 +206,27 @@ class VFS_sql_file extends VFS_file {
      * @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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $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')) {
-            return $result;
+                                    array($id, self::FOLDER, $path, $name, time(), $this->_params['user']));
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
 
         if (!@mkdir($this->_getNativePath($path, $name))) {
             $result = $this->_db->query(sprintf('DELETE FROM %s WHERE vfs_id = ?',
                                                 $this->_params['table']),
                                         array($id));
-            return PEAR::raiseError(_("Unable to create VFS directory."));
+            throw new VFS_Exception('Unable to create VFS directory.');
         }
-
-        return true;
     }
 
     /**
@@ -274,14 +237,11 @@ class VFS_sql_file extends VFS_file {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if (strpos($newpath, '/') === false) {
             $parent = '';
@@ -289,44 +249,30 @@ class VFS_sql_file extends VFS_file {
         } else {
             list($parent, $path) = explode('/', $newpath, 2);
         }
+
         if (!$this->isFolder($parent, $path)) {
-            if (is_a($result = $this->autocreatePath($newpath), 'PEAR_Error')) {
-                return $result;
-            }
+            $this->autocreatePath($newpath);
         }
 
-        $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));
+        $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."));
+            throw new VFS_Exception('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."));
+            $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));
+            throw new VFS_Exception('Unable to rename VFS directory.');
         }
 
         if (!@is_dir($this->_getNativePath($newpath))) {
-            if (is_a($res = $this->autocreatePath($newpath), 'PEAR_Error')) {
-                return $res;
-            }
+            $this->autocreatePath($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));
+            $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."));
         }
-
-        return true;
     }
 
     /**
@@ -336,48 +282,31 @@ class VFS_sql_file extends VFS_file {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($recursive) {
-            $result = $this->emptyFolder($path . '/' . $name);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->emptyFolder($path . '/' . $name);
         } else {
             $list = $this->listFolder($path . '/' . $name);
-            if (is_a($list, 'PEAR_Error')) {
-                return $list;
-            }
             if (count($list)) {
-                return PEAR::raiseError(sprintf(_("Unable to delete %s, the directory is not empty"),
-                                                $path . '/' . $name));
+                throw new VFS_Exception(sprintf('Unable to delete %s, the directory is not empty', $path . '/' . $name));
             }
         }
 
-        $result = $this->_db->query(sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ? AND vfs_name = ?',
-                                            $this->_params['table']),
-                                    array(VFS_FOLDER, $path, $name));
+        $result = $this->_db->query(sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ? AND vfs_name = ?', $this->_params['table']), array(self::FOLDER, $path, $name));
 
-        if ($this->_db->affectedRows() == 0 || is_a($result, 'PEAR_Error')) {
-            return PEAR::raiseError(_("Unable to delete VFS directory."));
+        if ($this->_db->affectedRows() == 0 || ($result instanceof PEAR_Error)) {
+            throw new VFS_Exception('Unable to delete VFS directory.');
         }
 
-        if (is_a($this->_recursiveSQLDelete($path, $name), 'PEAR_Error')) {
-            return PEAR::raiseError(_("Unable to delete VFS directory recursively."));
+        if ($this->_recursiveSQLDelete($path, $name) instanceof PEAR_Error ||
+            $this->_recursiveLFSDelete($path, $name) instanceof PEAR_Error) {
+            throw new VFS_Exception('Unable to delete VFS directory recursively.');
         }
-
-        if (is_a($this->_recursiveLFSDelete($path, $name), 'PEAR_Error')) {
-            return PEAR::raiseError(_("Unable to delete VFS directory recursively."));
-        }
-
-        return $result;
     }
 
     /**
@@ -386,37 +315,28 @@ class VFS_sql_file extends VFS_file {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        $res = $this->_checkQuotaDelete($path, $name);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
-
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_checkQuotaDelete($path, $name);
+        $this->_connect();
 
         $result = $this->_db->query(sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ? AND vfs_name = ?',
                                             $this->_params['table']),
-                                    array(VFS_FILE, $path, $name));
+                                    array(self::FILE, $path, $name));
 
         if ($this->_db->affectedRows() == 0) {
-            return PEAR::raiseError(_("Unable to delete VFS file."));
+            throw new VFS_Exception('Unable to delete VFS file.');
         }
 
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
 
         if (!@unlink($this->_getNativePath($path, $name))) {
-            return PEAR::raiseError(_("Unable to delete VFS file."));
+            throw new VFS_Exception('Unable to delete VFS file.');
         }
-
-        return true;
     }
 
     /**
@@ -428,25 +348,22 @@ class VFS_sql_file extends VFS_file {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show directories only?
      *
-     * @return mixed  File list on success or false on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path, $filter = null, $dotfiles = true,
-                        $dironly = false)
+    protected function _listFolder($path, $filter = null, $dotfiles = true,
+                                   $dironly = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $files = array();
-        $fileList = array();
 
         $fileList = $this->_db->getAll(sprintf('SELECT vfs_name, vfs_type, vfs_modified, vfs_owner FROM %s
                                                WHERE vfs_path = ?',
                                                $this->_params['table']),
                                        array($path));
-        if (is_a($fileList, 'PEAR_Error')) {
-            return $fileList;
+        if ($fileList instanceof PEAR_Error) {
+            throw new VFS_Exception($fileList->getMessage());
         }
 
         foreach ($fileList as $line) {
@@ -457,17 +374,17 @@ class VFS_sql_file extends VFS_file {
 
             $file['name'] = $line[0];
 
-            if ($line[1] == VFS_FILE) {
+            if ($line[1] == self::FILE) {
                 $name = explode('.', $line[0]);
 
                 if (count($name) == 1) {
                     $file['type'] = '**none';
                 } else {
-                    $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                    $file['type'] = self::strtolower($name[count($name) - 1]);
                 }
 
                 $file['size'] = filesize($this->_getNativePath($path, $line[0]));
-            } elseif ($line[1] == VFS_FOLDER) {
+            } elseif ($line[1] == self::FOLDER) {
                 $file['type'] = '**dir';
                 $file['size'] = -1;
             }
@@ -503,21 +420,20 @@ class VFS_sql_file extends VFS_file {
      *                             folderlist.
      * @param boolean $dotfolders  Include dotfolders?
      *
-     * @return mixed  Folder list on success or a PEAR_Error object on failure.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = array(), $dotfolders = true)
+    public function listFolders($path = '', $filter = array(),
+                                $dotfolders = true)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $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')) {
-            return $folderList;
+        $folderList = $this->_db->getAll($sql, array($path, self::FOLDER));
+        if ($folderList instanceof PEAR_Error) {
+            throw new VFS_Exception($folderList->getMessage());
         }
 
         $folders = array();
@@ -538,7 +454,7 @@ class VFS_sql_file extends VFS_file {
             $folder['abbrev'] .= $line[0];
             $folder['label'] .= $line[0];
 
-            $strlen = VFS::strlen($folder['label']);
+            $strlen = self::strlen($folder['label']);
             if ($strlen > 26) {
                 $folder['abbrev'] = substr($folder['label'], 0, ($count * 4));
                 $length = (29 - ($count * 4)) / 2;
@@ -566,49 +482,34 @@ class VFS_sql_file extends VFS_file {
     /**
      * Recursively copies the contents of a folder to a destination.
      *
-     * @access private
-     *
      * @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.
+     * @throws VFS_Exception
      */
     function _recursiveCopy($path, $name, $dest)
     {
-        $result = $this->createFolder($dest, $name);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->createFolder($dest, $name);
 
         $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')) {
-                return $result;
-            }
+            $this->copy($this->_getSQLNativePath($path, $name), $file['name'], $this->_getSQLNativePath($dest, $name));
         }
-        return true;
      }
 
     /**
      * Store a files information within the database.
      *
-     * @access private
-     *
      * @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.
+     * @throws VFS_Exception
      */
-    function _writeSQLData($path, $name, $autocreate = false)
+    protected function _writeSQLData($path, $name, $autocreate = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         // File already exists in database
         if ($this->exists($path, $name)) {
@@ -622,7 +523,7 @@ class VFS_sql_file extends VFS_file {
             $query = 'INSERT INTO ' . $this->_params['table'] .
                      ' (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified,' .
                      ' vfs_owner) VALUES (?, ?, ?, ?, ?, ?)';
-            $values = array($id, VFS_FILE, $path, $name, time(),
+            $values = array($id, self::FILE, $path, $name, time(),
                             $this->_params['user']);
         }
         return $this->_db->query($query, $values);
@@ -631,21 +532,20 @@ class VFS_sql_file extends VFS_file {
     /**
      * Renames all child paths.
      *
-     * @access private
-     *
      * @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.
+     * @throws VFS_Exception
      */
-    function _recursiveSQLRename($oldpath, $oldname, $newpath, $newname)
+    protected 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']),
                                          0,
-                                         array(VFS_FOLDER, $this->_getSQLNativePath($oldpath, $oldname)));
+                                         array(self::FOLDER, $this->_getSQLNativePath($oldpath, $oldname)));
 
         foreach ($folderList as $folder) {
             $this->_recursiveSQLRename($this->_getSQLNativePath($oldpath, $oldname), $folder, $this->_getSQLNativePath($newpath, $newname), $folder);
@@ -656,8 +556,8 @@ class VFS_sql_file extends VFS_file {
                                     array($this->_getSQLNativePath($newpath, $newname),
                                           $this->_getSQLNativePath($oldpath, $oldname)));
 
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
     }
 
@@ -665,49 +565,36 @@ class VFS_sql_file extends VFS_file {
      * Delete a folders contents from the VFS in the SQL database,
      * recursively.
      *
-     * @access private
-     *
      * @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.
+     * @throws VFS_Exception
      */
-    function _recursiveSQLDelete($path, $name)
+    protected 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')) {
-            return $result;
+        $result = $this->_db->query(sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path = ?', $this->_params['table']), array(self::FILE, $this->_getSQLNativePath($path, $name)));
+        if ($result instanceof PEAR_Error) {
+            throw new VFS_Exception($result->getMessage());
         }
 
-        $folderList = $this->_db->getCol(sprintf('SELECT vfs_name FROM %s WHERE vfs_type = ? AND vfs_path = ?',
-                                                 $this->_params['table']),
-                                         0,
-                                         array(VFS_FOLDER, $this->_getSQLNativePath($path, $name)));
+        $folderList = $this->_db->getCol(sprintf('SELECT vfs_name FROM %s WHERE vfs_type = ? AND vfs_path = ?', $this->_params['table']), 0, array(self::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']),
-                                    array(VFS_FOLDER, $name, $path));
-
-        return $result;
+        $this->_db->query(sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_name = ? AND vfs_path = ?', $this->_params['table']), array(self::FOLDER, $name, $path));
     }
 
     /**
      * Delete a folders contents from the VFS, recursively.
      *
-     * @access private
-     *
      * @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.
+     * @throws VFS_Exception
      */
-    function _recursiveLFSDelete($path, $name)
+    protected function _recursiveLFSDelete($path, $name)
     {
         $dir = $this->_getNativePath($path, $name);
         $dh = @opendir($dir);
@@ -723,58 +610,51 @@ class VFS_sql_file extends VFS_file {
         }
         @closedir($dh);
 
-        return rmdir($dir);
+        rmdir($dir);
     }
 
     /**
      * Attempts to open a persistent connection to the SQL server.
      *
-     * @access private
-     *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function _connect()
+    protected function _connect()
     {
         if ($this->_db !== false) {
-            return true;
+            return;
         }
 
         if (!is_array($this->_params)) {
-            return PEAR::raiseError(_("No configuration information specified for SQL-File VFS."));
+            throw new VFS_Exception('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));
+                throw new VFS_Exception(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';
-        }
+        $this->_params = array_merge(array(
+            'database' => '',
+            'hostspec' => '',
+            'table' => 'horde_vfs',
+            'username' => ''
+        ), $this->_params);
 
         /* Connect to the SQL server using the supplied parameters. */
         require_once 'DB.php';
-        $this->_db = &DB::connect($this->_params,
-                                  array('persistent' => !empty($this->_params['persistent']),
-                                        'ssl' => !empty($this->_params['ssl'])));
-        if (is_a($this->_db, 'PEAR_Error')) {
-            $error = $this->_db;
+        $this->_db = DB::connect(
+            $this->_params,
+            array(
+                'persistent' => !empty($this->_params['persistent']),
+                'ssl' => !empty($this->_params['ssl']
+            )
+        ));
+        if ($this->_db instanceof PEAR_Error) {
+            $error = new VFS_Exception($this->_db->getMessage());
             $this->_db = false;
-            return $error;
+            throw $error;
         }
 
         // Set DB portability options.
@@ -786,26 +666,23 @@ class VFS_sql_file extends VFS_file {
         default:
             $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
         }
-
-        return true;
     }
 
     /**
      * Return a full filename on the native filesystem, from a VFS
      * path and name.
      *
-     * @access private
-     *
      * @param string $path  The VFS file path.
      * @param string $name  The VFS filename.
      *
      * @return string  The full native filename.
      */
-    function _getNativePath($path, $name)
+    protected function _getNativePath($path, $name)
     {
         if (strlen($name)) {
             $name = '/' . $name;
         }
+
         if (strlen($path)) {
             if (isset($this->_params['home']) &&
                 preg_match('|^~/?(.*)$|', $path, $matches)) {
@@ -813,29 +690,25 @@ class VFS_sql_file extends VFS_file {
             }
 
             return $this->_params['vfsroot'] . '/' . $path . $name;
-        } else {
-            return $this->_params['vfsroot'] . $name;
         }
+
+        return $this->_params['vfsroot'] . $name;
     }
 
     /**
      * Return a full SQL filename on the native filesystem, from a VFS
      * path and name.
      *
-     * @access private
-     *
      * @param string $path  The VFS file path.
      * @param string $name  The VFS filename.
      *
      * @return string  The full native filename.
      */
-    function _getSQLNativePath($path, $name)
+    protected function _getSQLNativePath($path, $name)
     {
-        if (!strlen($path)) {
-            return $name;
-        }
-
-        return $path . '/' . $name;
+        return strlen($path)
+            ? $path . '/' . $name
+            : $name;
     }
 
 }
index 3c3beda..00e5129 100644 (file)
@@ -4,13 +4,13 @@
  * This module requires the SSH2 (version 0.10+) PECL package.
  *
  * Required values for $params:<pre>
- *      'username'       The username with which to connect to the ssh2 server.
- *      'password'       The password with which to connect to the ssh2 server.
- *      'hostspec'       The ssh2 server to connect to.</pre>
+ * username - (string) The username with which to connect to the ssh2 server.
+ * password - (string) The password with which to connect to the ssh2 server.
+ * hostspec - (string) The ssh2 server to connect to.</pre>
  *
  * Optional values for $params:<pre>
- *      'port'           The port used to connect to the ssh2 server if other
- *                       than 22.</pre>
+ * port - (integer) The port used to connect to the ssh2 server if other than
+ *        22.</pre>
  *
  * Copyright 2006-2010 The Horde Project (http://www.horde.org/)
  *
  * @editor  Cliff Green <green@umdnj.edu>
  * @package VFS
  */
-class VFS_ssh2 extends VFS {
-
+class VFS_ssh2 extends VFS
+{
     /**
      * List of additional credentials required for this VFS backend.
      *
      * @var array
      */
-    var $_credentials = array('username', 'password');
+    protected $_credentials = array('username', 'password');
 
     /**
      * List of permissions and if they can be changed in this VFS backend.
@@ -35,66 +35,74 @@ class VFS_ssh2 extends VFS {
      * @var array
      */
     var $_permissions = array(
-        'owner' => array('read' => true, 'write' => true, 'execute' => true),
-        'group' => array('read' => true, 'write' => true, 'execute' => true),
-        'all'   => array('read' => true, 'write' => true, 'execute' => true));
+        'owner' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        ),
+        'group' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        ),
+        'all' => array(
+            'read' => true,
+            'write' => true,
+            'execute' => true
+        )
+    );
 
     /**
      * Variable holding the connection to the ssh2 server.
      *
      * @var resource
      */
-    var $_stream = false;
+    protected $_stream = false;
 
     /**
      * The SFTP resource stream.
      *
      * @var resource
      */
-    var $_sftp;
+    protected $_sftp;
 
     /**
      * The current working directory.
      *
      * @var string
      */
-    var $_cwd;
+    protected $_cwd;
 
     /**
      * Local cache array for user IDs.
      *
      * @var array
      */
-    var $_uids = array();
+    protected $_uids = array();
 
     /**
      * Local cache array for group IDs.
      *
      * @var array
      */
-    var $_gids = array();
+    protected $_gids = array();
 
     /**
      * Returns the size of a file.
      *
-     * @access public
-     *
      * @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
-     *                  failure.
+     * @return integer  The size of the file in bytes.
+     * @throws VFS_Exception
      */
-    function size($path, $name)
+    public function size($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $statinfo = @ssh2_sftp_stat($this->_sftp, $this->_getPath($path, $name));
         if (($size = $statinfo['size']) === false) {
-            return PEAR::raiseError(sprintf(_("Unable to check file size of \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to check file size of "%s".', $this->_getPath($path, $name)));
         }
 
         return $size;
@@ -107,21 +115,16 @@ class VFS_ssh2 extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return string  The file data.
+     * @throws VFS_Exception
      */
-    function read($path, $name)
+    public function read($path, $name)
     {
         $file = $this->readFile($path, $name);
-        if (is_a($file, 'PEAR_Error')) {
-            return $file;
-        }
-
         clearstatcache();
-        $size = filesize($file);
-        if ($size === 0) {
-            return '';
-        }
 
-        return file_get_contents($file);
+        return (filesize($file) === 0)
+            ? ''
+            : file_get_contents($file);
     }
 
     /**
@@ -134,25 +137,22 @@ class VFS_ssh2 extends VFS {
      * @param string $path  The pathname to the file.
      * @param string $name  The filename to retrieve.
      *
-     * @return string A local filename.
+     * @return string  A local filename.
+     * @throws VFS_Exception
      */
-    function readFile($path, $name)
+    public function readFile($path, $name)
     {
-        $result = $this->_connect();
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
-        }
+        $this->_connect();
 
         // Create a temporary file and register it for deletion at the
         // end of this request.
-        $localFile = $this->_getTempFile();
-        if (!$localFile) {
-            return PEAR::raiseError(_("Unable to create temporary file."));
+        if (!($localFile = tempnam(null, 'vfs'))) {
+            throw new VFS_Exception('Unable to create temporary file.');
         }
-        register_shutdown_function(create_function('', 'unlink(\'' . addslashes($localFile) . '\');'));
+        register_shutdown_function(create_function('', '@unlink(\'' . addslashes($localFile) . '\');'));
 
         if (!$this->_recv($this->_getPath($path, $name), $localFile)) {
-            return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to open VFS file "%s".', $this->_getPath($path, $name)));
         }
 
         return $localFile;
@@ -165,16 +165,11 @@ class VFS_ssh2 extends VFS {
      * @param string $name  The filename to retrieve.
      *
      * @return resource  The stream.
+     * @throws VFS_Exception
      */
-    function readStream($path, $name)
+    public function readStream($path, $name)
     {
-        $file = $this->readFile($path, $name);
-        if (is_a($file, 'PEAR_Error')) {
-            return $file;
-        }
-
-        $mode = OS_WINDOWS ? 'rb' : 'r';
-        return fopen($file, $mode);
+        return fopen($this->readFile($path, $name), OS_WINDOWS ? 'rb' : 'r');
     }
 
     /**
@@ -186,35 +181,23 @@ class VFS_ssh2 extends VFS {
      *                             be stored.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function write($path, $name, $tmpFile, $autocreate = false)
+    public function write($path, $name, $tmpFile, $autocreate = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
-        $res = $this->_checkQuotaWrite('file', $tmpFile);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_connect();
+        $this->_checkQuotaWrite('file', $tmpFile);
 
         if (!$this->_send($tmpFile, $this->_getPath($path, $name)))  {
             if ($autocreate) {
-                $result = $this->autocreatePath($path);
-                if (is_a($result, 'PEAR_Error')) {
-                    return $result;
-                }
-                if (!$this->_send($tmpFile, $this->_getPath($path, $name))) {
-                    return PEAR::raiseError(sprintf(_("Unable to write VFS file \"%s\"."), $this->_getPath($path, $name)));
+                $this->autocreatePath($path);
+                if ($this->_send($tmpFile, $this->_getPath($path, $name))) {
+                    return;
                 }
-            } else {
-                return PEAR::raiseError(sprintf(_("Unable to write VFS file \"%s\"."), $this->_getPath($path, $name)));
             }
-        }
 
-        return true;
+            throw new VFS_Exception(sprintf('Unable to write VFS file "%s".', $this->_getPath($path, $name)));
+        }
     }
 
     /**
@@ -225,27 +208,22 @@ class VFS_ssh2 extends VFS {
      * @param string $data         The file data.
      * @param boolean $autocreate  Automatically create directories?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function writeData($path, $name, $data, $autocreate = false)
+    public function writeData($path, $name, $data, $autocreate = false)
     {
-        $res = $this->_checkQuotaWrite('string', $data);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_checkQuotaWrite('string', $data);
 
-        $tmpFile = $this->_getTempFile();
-        if (function_exists('file_put_contents')) {
-            file_put_contents($tmpFile, $data);
-        } else {
-            $fp = fopen($tmpFile, 'wb');
-            fwrite($fp, $data);
-            fclose($fp);
-        }
+        $tmpFile = tempnam(null, 'vfs');
+        file_put_contents($tmpFile, $data);
 
-        $result = $this->write($path, $name, $tmpFile, $autocreate);
-        unlink($tmpFile);
-        return $result;
+        try {
+            $this->write($path, $name, $tmpFile, $autocreate);
+            unlink($tmpFile);
+        } catch (VFS_Exception $e) {
+            unlink($tmpFile);
+            throw $e;
+        }
     }
 
     /**
@@ -254,25 +232,16 @@ class VFS_ssh2 extends 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.
+     * @throws VFS_Exception
      */
-    function deleteFile($path, $name)
+    public function deleteFile($path, $name)
     {
-        $res = $this->_checkQuotaDelete($path, $name);
-        if (is_a($res, 'PEAR_Error')) {
-            return $res;
-        }
-
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_checkQuotaDelete($path, $name);
+        $this->_connect();
 
         if (!@ssh2_sftp_unlink($this->_sftp, $this->_getPath($path, $name))) {
-            return PEAR::raiseError(sprintf(_("Unable to delete VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to delete VFS file "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -283,11 +252,12 @@ class VFS_ssh2 extends VFS {
      *
      * @return boolean  True if it is a folder, false otherwise.
      */
-    function isFolder($path, $name)
+    public function isFolder($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
+        try {
+            $this->_connect();
+        } catch (VFS_Exception $e) {
+            return false;
         }
 
         /* See if we can stat the remote filename. ANDed with 040000 is true
@@ -303,18 +273,14 @@ class VFS_ssh2 extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function deleteFolder($path, $name, $recursive = false)
+    public function deleteFolder($path, $name, $recursive = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $isDir = false;
-        $dirCheck = $this->listFolder($path);
-        foreach ($dirCheck as $file) {
+        foreach ($this->listFolder($path) as $file) {
             if ($file['name'] == $name && $file['type'] == '**dir') {
                 $isDir = true;
                 break;
@@ -323,35 +289,25 @@ class VFS_ssh2 extends VFS {
 
         if ($isDir) {
             $file_list = $this->listFolder($this->_getPath($path, $name));
-            if (is_a($file_list, 'PEAR_Error')) {
-                return $file_list;
-            }
-
             if (count($file_list) && !$recursive) {
-                return PEAR::raiseError(sprintf(_("Unable to delete \"%s\", the directory is not empty."),
-                                                $this->_getPath($path, $name)));
+                throw new VFS_Exception(sprintf('Unable to delete "%s", the directory is not empty.', $this->_getPath($path, $name)));
             }
             foreach ($file_list as $file) {
                 if ($file['type'] == '**dir') {
-                    $result = $this->deleteFolder($this->_getPath($path, $name), $file['name'], $recursive);
+                    $this->deleteFolder($this->_getPath($path, $name), $file['name'], $recursive);
                 } else {
-                    $result = $this->deleteFile($this->_getPath($path, $name), $file['name']);
-                }
-                if (is_a($result, 'PEAR_Error')) {
-                    return $result;
+                    $this->deleteFile($this->_getPath($path, $name), $file['name']);
                 }
             }
 
             if (!@ssh2_sftp_rmdir($this->_sftp, $this->_getPath($path, $name))) {
-                return PEAR::raiseError(sprintf(_("Cannot remove directory \"%s\"."), $this->_getPath($path, $name)));
+                throw new VFS_Exception(sprintf('Cannot remove directory "%s".', $this->_getPath($path, $name)));
             }
         } else {
             if (!@ssh2_sftp_unlink($this->_sftp, $this->_getPath($path, $name))) {
-                return PEAR::raiseError(sprintf(_("Cannot delete file \"%s\"."), $this->_getPath($path, $name)));
+                throw new VFS_Exception(sprintf('Cannot delete file "%s".', $this->_getPath($path, $name)));
             }
         }
-
-        return true;
     }
 
     /**
@@ -362,24 +318,16 @@ class VFS_ssh2 extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function rename($oldpath, $oldname, $newpath, $newname)
+    public function rename($oldpath, $oldname, $newpath, $newname)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
-        if (is_a($res = $this->autocreatePath($newpath), 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_connect();
+        $this->autocreatePath($newpath);
 
         if (!@ssh2_sftp_rename($this->_sftp, $this->_getPath($oldpath, $oldname), $this->_getPath($newpath, $newname))) {
-            return PEAR::raiseError(sprintf(_("Unable to rename VFS file \"%s\"."), $this->_getPath($oldpath, $oldname)));
+            throw new VFS_Exception(sprintf('Unable to rename VFS file "%s".', $this->_getPath($oldpath, $oldname)));
         }
-
-        return true;
     }
 
     /**
@@ -388,20 +336,15 @@ class VFS_ssh2 extends 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.
+     * @throws VFS_Exception
      */
-    function createFolder($path, $name)
+    public function createFolder($path, $name)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if (!@ssh2_sftp_mkdir($this->_sftp, $this->_getPath($path, $name))) {
-            return PEAR::raiseError(sprintf(_("Unable to create VFS directory \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to create VFS directory "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -411,20 +354,15 @@ class VFS_ssh2 extends VFS {
      * @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.
+     * @throws VFS_Exception
      */
-    function changePermissions($path, $name, $permission)
+    public function changePermissions($path, $name, $permission)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if (!@ssh2_exec($this->_stream, 'chmod ' . escapeshellarg($permission) . ' ' . escapeshellarg($this->_getPath($path, $name)))) {
-            return PEAR::raiseError(sprintf(_("Unable to change permission for VFS file \"%s\"."), $this->_getPath($path, $name)));
+            throw new VFS_Exception(sprintf('Unable to change permission for VFS file "%s".', $this->_getPath($path, $name)));
         }
-
-        return true;
     }
 
     /**
@@ -435,24 +373,18 @@ class VFS_ssh2 extends VFS {
      * @param boolean $dotfiles  Show dotfiles?
      * @param boolean $dironly   Show only directories?
      *
-     * @return array  File list on success or PEAR_Error on failure.
+     * @return array  File list.
+     * @throws VFS_Exception
      */
-    function _listFolder($path = '', $filter = null, $dotfiles = true,
-                         $dironly = false)
+    protected function _listFolder($path = '', $filter = null,
+                                   $dotfiles = true, $dironly = false)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         $files = array();
 
         /* If 'maplocalids' is set, check for the POSIX extension. */
-        $mapids = false;
-        if (!empty($this->_params['maplocalids']) &&
-            extension_loaded('posix')) {
-            $mapids = true;
-        }
+        $mapids = (!empty($this->_params['maplocalids']) && extension_loaded('posix'));
 
         // THIS IS A PROBLEM....  there is no builtin systype() fn for SSH2.
         // Go with unix-style listings for now...
@@ -460,10 +392,7 @@ class VFS_ssh2 extends VFS {
 
         $olddir = $this->getCurrentDirectory();
         if (strlen($path)) {
-            $res = $this->_setPath($path);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
+            $this->_setPath($path);
         }
 
         if ($type == 'unix') {
@@ -501,10 +430,7 @@ class VFS_ssh2 extends VFS {
 
         if (!is_array($list)) {
             if (isset($olddir)) {
-                $res = $this->_setPath($olddir);
-                if (is_a($res, 'PEAR_Error')) {
-                    return $res;
-                }
+                $this->_setPath($olddir);
             }
             return array();
         }
@@ -564,7 +490,7 @@ class VFS_ssh2 extends VFS {
                            (($name[0] === '') && (count($name) == 2))) {
                            $file['linktype'] = '**none';
                        } else {
-                           $file['linktype'] = VFS::strtolower(array_pop($name));
+                           $file['linktype'] = self::strtolower(array_pop($name));
                        }
                    }
                 } elseif ($p1 === 'd') {
@@ -576,7 +502,7 @@ class VFS_ssh2 extends VFS {
                          (count($name) == 2))) {
                         $file['type'] = '**none';
                     } else {
-                        $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                        $file['type'] = self::strtolower($name[count($name) - 1]);
                     }
                 }
                 if ($file['type'] == '**dir') {
@@ -638,7 +564,7 @@ class VFS_ssh2 extends VFS {
                          (count($name) == 2))) {
                         $file['type'] = '**none';
                     } else {
-                        $file['type'] = VFS::strtolower($name[count($name) - 1]);
+                        $file['type'] = self::strtolower($name[count($name) - 1]);
                     }
                 }
             }
@@ -675,34 +601,27 @@ class VFS_ssh2 extends VFS {
      * @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.
+     * @return array  Folder list.
+     * @throws VFS_Exception
      */
-    function listFolders($path = '', $filter = null, $dotfolders = true)
+    public function listFolders($path = '', $filter = null, $dotfolders = true)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
-        $folders = array();
-        $folder = array();
-
-        $folderList = $this->listFolder($path, null, $dotfolders, true);
-        if (is_a($folderList, 'PEAR_Error')) {
-            return $folderList;
-        }
-
-        $folder['val'] = $this->_parentDir($path);
-        $folder['abbrev'] = $folder['label'] = '..';
+        $this->_connect();
 
+        $folder = array(
+            'abbrev' => '..',
+            'val' => $this->_parentDir($path),
+            'label' => '..'
+        );
         $folders[$folder['val']] = $folder;
 
+        $folderList = $this->listFolder($path, null, $dotfolders, true);
         foreach ($folderList as $files) {
-            $folder['val'] = $this->_getPath($path, $files['name']);
-            $folder['abbrev'] = $files['name'];
-            $folder['label'] = $folder['val'];
-
-            $folders[$folder['val']] = $folder;
+            $folders[$folder['val']] = array(
+                'val' => $this->_getPath($path, $files['name']),
+                'abbrev' => $files['name'],
+                'label' => $folder['val']
+            );
         }
 
         ksort($folders);
@@ -718,64 +637,45 @@ class VFS_ssh2 extends VFS {
      * @param boolean $autocreate  Auto-create the directory if it doesn't
      *                             exist?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function copy($path, $name, $dest, $autocreate = false)
+    public function copy($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
+            throw new VFS_Exception('Cannot copy file(s) - source and destination are the same.');
         }
 
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($autocreate) {
-            $res = $this->autocreatePath($dest);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
-        }
-        $fileCheck = $this->listFolder($dest, null, true);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
+            $this->autocreatePath($dest);
         }
 
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, true) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(sprintf(_("%s already exists."), $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('%s already exists.', $this->_getPath($dest, $name)));
             }
         }
 
         if ($this->isFolder($path, $name)) {
-            $result = $this->_copyRecursive($path, $name, $dest);
-            if (is_a($result, 'PEAR_Error')) {
-                return $result;
-            }
+            $this->_copyRecursive($path, $name, $dest);
         } else {
-            $tmpFile = $this->_getTempFile();
-            $fetch = $this->_recv($orig, $tmpFile);
-            if (!$fetch) {
+            $tmpFile = tempnam(null, 'vfs');
+            if (!$this->_recv($orig, $tmpFile)) {
                 unlink($tmpFile);
-                return PEAR::raiseError(sprintf(_("Failed to copy from \"%s\"."), $orig));
+                throw new VFS_Exception(sprintf('Failed to copy from "%s".', $orig));
             }
 
-            $res = $this->_checkQuotaWrite('file', $tmpFile);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
+            $this->_checkQuotaWrite('file', $tmpFile);
 
             if (!$this->_send($tmpFile, $this->_getPath($dest, $name))) {
                 unlink($tmpFile);
-                return PEAR::raiseError(sprintf(_("Failed to copy to \"%s\"."), $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('Failed to copy to "%s".', $this->_getPath($dest, $name)));
             }
 
             unlink($tmpFile);
         }
-
-        return true;
     }
 
     /**
@@ -787,200 +687,174 @@ class VFS_ssh2 extends VFS {
      * @param boolean $autocreate  Auto-create the directory if it doesn't
      *                             exist?
      *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function move($path, $name, $dest, $autocreate = false)
+    public function move($path, $name, $dest, $autocreate = false)
     {
         $orig = $this->_getPath($path, $name);
         if (preg_match('|^' . preg_quote($orig) . '/?$|', $dest)) {
-            return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
+            throw new VFS_Exception('Cannot move file(s) - destination is within source.');
         }
 
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
+        $this->_connect();
 
         if ($autocreate) {
-            $res = $this->autocreatePath($dest);
-            if (is_a($res, 'PEAR_Error')) {
-                return $res;
-            }
+            $this->autocreatePath($dest);
         }
 
-        $fileCheck = $this->listFolder($dest, null, true);
-        if (is_a($fileCheck, 'PEAR_Error')) {
-            return $fileCheck;
-        }
-
-        foreach ($fileCheck as $file) {
+        foreach ($this->listFolder($dest, null, true) as $file) {
             if ($file['name'] == $name) {
-                return PEAR::raiseError(sprintf(_("%s already exists."), $this->_getPath($dest, $name)));
+                throw new VFS_Exception(sprintf('%s already exists.', $this->_getPath($dest, $name)));
             }
         }
 
         if (!@ssh2_sftp_rename($this->_sftp, $orig, $this->_getPath($dest, $name))) {
-            return PEAR::raiseError(sprintf(_("Failed to move to \"%s\"."), $this->_getPath($dest, $name)));
+            throw new VFS_Exception(sprintf('Failed to move to "%s".', $this->_getPath($dest, $name)));
         }
-
-        return true;
     }
 
     /**
      * Returns the current working directory on the SSH2 server.
      *
      * @return string  The current working directory.
+     * @throws VFS_Exception
      */
-    function getCurrentDirectory()
+    public function getCurrentDirectory()
     {
-        if (is_a($res = $this->_connect(), 'PEAR_Error')) {
-            return $res;
-        }
+        $this->_connect();
+
         if (!strlen($this->_cwd)) {
             $stream = @ssh2_exec($this->_stream, 'pwd');
             stream_set_blocking($stream, true);
             $this->_cwd = trim(fgets($stream));
         }
+
         return $this->_cwd;
     }
 
     /**
      * Changes the current directory on the server.
      *
-     * @access private
-     *
      * @param string $path  The path to change to.
      *
-     * @return boolean  True on success, or a PEAR_Error on failure.
+     * @throws VFS_Exception
      */
-    function _setPath($path)
+    protected function _setPath($path)
     {
-        if ($stream = @ssh2_exec($this->_stream, 'cd ' . escapeshellarg($path) . '; pwd')) {
-            stream_set_blocking($stream, true);
-            $this->_cwd = trim(fgets($stream));
-            fclose($stream);
-            return true;
-        } else {
-            return PEAR::raiseError(sprintf(_("Unable to change to %s."), $path));
+        if (!($stream = @ssh2_exec($this->_stream, 'cd ' . escapeshellarg($path) . '; pwd'))) {
+            throw new VFS_Exception(sprintf('Unable to change to %s.', $path));
         }
+
+        stream_set_blocking($stream, true);
+        $this->_cwd = trim(fgets($stream));
+        fclose($stream);
     }
 
     /**
      * Returns the full path of an item.
      *
-     * @access private
-     *
      * @param string $path  The directory of the item.
      * @param string $name  The name of the item.
      *
      * @return mixed  Full path to the file when $path is not empty and just
      *                $name when not set.
      */
-    function _getPath($path, $name)
+    protected function _getPath($path, $name)
     {
-        if ($path !== '') {
-            return ($path . '/' . $name);
-        }
-        return $name;
+        return ($path !== '')
+            ? ($path . '/' . $name)
+            : $name;
     }
 
     /**
      * Returns the parent directory of the specified path.
      *
-     * @access private
-     *
      * @param string $path  The path to get the parent of.
      *
-     * @return string  The parent directory (string) on success or a PEAR_Error
-     *                 object on failure.
+     * @return string  The parent directory.
+     * @throws VFS_Exception
      */
-    function _parentDir($path)
+    protected function _parentDir($path)
     {
-        $conn = $this->_connect();
-        if (is_a($conn, 'PEAR_Error')) {
-            return $conn;
-        }
-
+        $this->_connect();
         $this->_setPath('cd ' . $path . '/..');
+
         return $this->getCurrentDirectory();
     }
 
     /**
      * Attempts to open a connection to the SSH2 server.
      *
-     * @access private
-     *
-     * @return mixed  True on success or a PEAR_Error object on failure.
+     * @throws VFS_Exception
      */
-    function _connect()
+    protected function _connect()
     {
-        if ($this->_stream === false) {
-            if (!extension_loaded('ssh2')) {
-                return PEAR::raiseError(_("The SSH2 PECL extension is not available."));
-            }
+        if ($this->_stream !== false) {
+            return;
+        }
 
-            if (!is_array($this->_params)) {
-                return PEAR::raiseError(_("No configuration information specified for SSH2 VFS."));
-            }
+        if (!extension_loaded('ssh2')) {
+            throw new VFS_Exception('The SSH2 PECL extension is not available.');
+        }
 
-            $required = array('hostspec', 'username', 'password');
-            foreach ($required as $val) {
-                if (!isset($this->_params[$val])) {
-                    return PEAR::raiseError(sprintf(_("Required \"%s\" not specified in VFS configuration."), $val));
-                }
-            }
+        if (!is_array($this->_params)) {
+            throw new VFS_Exception('No configuration information specified for SSH2 VFS.');
+        }
 
-            /* Connect to the ssh2 server using the supplied parameters. */
-            if (empty($this->_params['port'])) {
-                $this->_stream = @ssh2_connect($this->_params['hostspec']);
-            } else {
-                $this->_stream = @ssh2_connect($this->_params['hostspec'], $this->_params['port']);
-            }
-            if (!$this->_stream) {
-                return PEAR::raiseError(_("Connection to SSH2 server failed."));
+        $required = array('hostspec', 'username', 'password');
+        foreach ($required as $val) {
+            if (!isset($this->_params[$val])) {
+                throw new VFS_Exception(sprintf('Required "%s" not specified in VFS configuration.', $val));
             }
+        }
 
-            $connected = @ssh2_auth_password($this->_stream, $this->_params['username'], $this->_params['password']);
-            if (!$connected) {
-                $this->_stream = false;
-                return PEAR::raiseError(_("Authentication to SSH2 server failed."));
-            }
+        /* Connect to the ssh2 server using the supplied parameters. */
+        if (empty($this->_params['port'])) {
+            $this->_stream = @ssh2_connect($this->_params['hostspec']);
+        } else {
+            $this->_stream = @ssh2_connect($this->_params['hostspec'], $this->_params['port']);
+        }
 
-            /* Create sftp resource. */
-            $this->_sftp = @ssh2_sftp($this->_stream);
+        if (!$this->_stream) {
+            $this->_stream = false;
+            throw new VFS_Exception('Connection to SSH2 server failed.');
         }
 
-        return true;
+        if (!@ssh2_auth_password($this->_stream, $this->_params['username'], $this->_params['password'])) {
+            $this->_stream = false;
+            throw new VFS_Exception('Authentication to SSH2 server failed.');
+        }
+
+        /* Create sftp resource. */
+        $this->_sftp = @ssh2_sftp($this->_stream);
     }
 
     /**
      * Sends local file to remote host.
-     * This function exists because the php_scp_* functions doesn't seem to work on some hosts.
-     *
-     * @access private
+     * This function exists because the php_scp_* functions doesn't seem to
+     * work on some hosts.
      *
      * @param string $local   Full path to the local file.
      * @param string $remote  Full path to the remote location.
      *
-     * @return boolean TRUE on success, FALSE on failure.
+     * @return boolean  Success.
      */
-    function _send($local, $remote)
+    protected function _send($local, $remote)
     {
         return @copy($local, $this->_wrap($remote));
     }
 
     /**
      * Receives file from remote host.
-     * This function exists because the php_scp_* functions doesn't seem to work on some hosts.
-     *
-     * @access private
+     * This function exists because the php_scp_* functions doesn't seem to
+     * work on some hosts.
      *
-     * @param string $local  Full path to the local file.
-     * @param string $remote Full path to the remote location.
+     * @param string $local   Full path to the local file.
+     * @param string $remote  Full path to the remote location.
      *
-     * @return boolean TRUE on success, FALSE on failure.
+     * @return boolean  Success.
      */
-    function _recv($remote, $local)
+    protected function _recv($remote, $local)
     {
         return @copy($this->_wrap($remote), $local);
     }
@@ -988,16 +862,15 @@ class VFS_ssh2 extends VFS {
     /**
      * Generate a stream wrapper file spec for a remote file path
      *
-     * @access private
-     *
      * @param string $remote  Full path to the remote location
      *
      * @return string  A full stream wrapper path to the remote location
      */
-    function _wrap($remote)
+    protected function _wrap($remote)
     {
-        return 'ssh2.sftp://' . $this->_params['username'] . ':' . $this->_params['password']
-            . '@' . $this->_params['hostspec'] . ':' . $this->_params['port'] . $remote;
+        return 'ssh2.sftp://' . $this->_params['username'] . ':' .
+            $this->_params['password'] . '@' . $this->_params['hostspec'] .
+            ':' . $this->_params['port'] . $remote;
     }
 
 }
index 2501cdd..1d75c95 100644 (file)
@@ -34,14 +34,14 @@ Reading, writing and listing of files are all supported, and there are both obje
  <date>2009-12-31</date>
  <version>
   <release>0.4.0</release>
-  <api>0.3.0</api>
+  <api>0.4.0</api>
  </version>
  <stability>
   <release>beta</release>
   <api>beta</api>
  </stability>
  <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* TODO</notes>
+ <notes>* Now throws exceptions instead of returning PEAR_Errors. Package now requires PHP 5.</notes>
  <contents>
   <dir name="/">
    <dir name="data">
@@ -62,6 +62,7 @@ Reading, writing and listing of files are all supported, and there are both obje
    <dir name="lib">
     <dir name="VFS">
      <file name="Browser.php" role="php" />
+     <file name="Exception.php" role="php" />
      <file name="file.php" role="php" />
      <file name="ftp.php" role="php" />
      <file name="GC.php" role="php" />
@@ -82,7 +83,7 @@ Reading, writing and listing of files are all supported, and there are both obje
  <dependencies>
   <required>
    <php>
-    <min>4.3.0</min>
+    <min>5.0.0</min>
    </php>
    <pearinstaller>
     <min>1.4.0b1</min>
@@ -100,6 +101,7 @@ Reading, writing and listing of files are all supported, and there are both obje
   <filelist>
    <install name="scripts/VFS/vfs.php" as="vfs" />
    <install name="lib/VFS/Browser.php" as="VFS/Browser.php" />
+   <install name="lib/VFS/Exception.php" as="VFS/Exception.php" />
    <install name="lib/VFS/file.php" as="VFS/file.php" />
    <install name="lib/VFS/ftp.php" as="VFS/ftp.php" />
    <install name="lib/VFS/GC.php" as="VFS/GC.php" />
@@ -185,7 +187,6 @@ Reading, writing and listing of files are all supported, and there are both obje
 * Add SSH2/SFTP driver (Cliff Green &lt;green@umdnj.edu&gt;).
 * Let rename() automatically create the destination path.
 * Make sure copy/move doesn&apos;t result in infinite recursion (Horde Bug #3680).
-      
    </notes>
   </release>
   <release>
index a2069c9..87ad04c 100644 (file)
@@ -86,12 +86,13 @@ function ls($url, $argv, $filter)
     $params = url2params($url);
     $recursive = in_array('R', $argv);
 
-    $vfs = &vfs($params);
-    $list = $vfs->listFolder($params['path'],
-                             count($filter) ? $filter[0] : null,
-                             in_array('a', $argv));
-    if (is_a($list, 'PEAR_Error')) {
-        usage($list);
+    $vfs = vfs($params);
+    try {
+        $list = $vfs->listFolder($params['path'],
+                                 count($filter) ? $filter[0] : null,
+                                 in_array('a', $argv));
+    } catch (VFS_Exception $e) {
+        usage($e);
     }
     if (in_array('a', $argv)) {
         $list = array_merge(array('.' => array('name' => '.'),
@@ -208,9 +209,10 @@ function _cp(&$source_vfs, &$target_vfs, $source_path, $target_path, $argv,
         return;
     }
 
-    $data = &$source_vfs->read($source_parent_path, $source_object);
-    if (is_a($data, 'PEAR_Error')) {
-        usage($data);
+    try {
+        $data = &$source_vfs->read($source_parent_path, $source_object);
+    } catch (VFS_Exception $e) {
+        usage($e);
     }
 
     if ($target_vfs->isFolder($target_parent_path, $target_object)) {
@@ -218,24 +220,25 @@ function _cp(&$source_vfs, &$target_vfs, $source_path, $target_path, $argv,
             echo '`' . $source_path . '\' -> `' . $target_path . '/' .
                 $source_object . "'\n";
         }
-        $result = $target_vfs->writeData($target_path, $source_object,
-                                         $data, true);
-        if (is_a($result, 'PEAR_Error')) {
-            usage($result);
+
+        try {
+            $target_vfs->writeData($target_path, $source_object, $data, true);
+        } catch (VFS_Exception $e) {
+            usage($e);
         }
     } elseif ($target_vfs->isFolder(dirname($target_parent_path),
                                     basename($target_parent_path))) {
         if (in_array('v', $argv)) {
             echo '`' . $source_path . '\' -> `' . $target_path . "'\n";
         }
-        $result = $target_vfs->writeData($target_parent_path, $target_object,
-                                         $data, true);
-        if (is_a($result, 'PEAR_Error')) {
-            usage($result);
+
+        try {
+            $target_vfs->writeData($target_parent_path, $target_object, $data, true);
+        } catch (VFS_Exception $e) {
+            usage($e);
         }
     } else {
-        usage(PEAR::raiseError('"' . $target_parent_path .
-                               '" does not exist or is not a folder.'));
+        usage(new VFS_Exception('"' . $target_parent_path . '" does not exist or is not a folder.'));
     }
 }
 
@@ -246,9 +249,8 @@ function _cp(&$source_vfs, &$target_vfs, $source_path, $target_path, $argv,
  */
 function usage($error = null)
 {
-    if (is_a($error, 'PEAR_Error')) {
+    if ($error instanceof VFS_Exception) {
         echo $error->getMessage() . "\n";
-        echo $error->getUserinfo() . "\n\n";
     } else {
         switch ($error) {
         case 'ls':
@@ -290,7 +292,7 @@ USAGE;
  *
  * @return VFS  An instance of the requested VFS backend.
  */
-function &vfs($params)
+function vfs($params)
 {
     return VFS::singleton($params['driver'], $params);
 }