VFS
[ class tree: VFS ] [ index: VFS ] [ all elements ]

Source for file sql.php

Documentation is available at sql.php

  1. <?php
  2.  
  3. /**
  4.  * File value for vfs_type column.
  5.  */
  6. define('VFS_FILE'1);
  7.  
  8. /**
  9.  * Folder value for vfs_type column.
  10.  */
  11. define('VFS_FOLDER'2);
  12.  
  13. /**
  14.  * VFS implementation for PHP's PEAR database abstraction layer.
  15.  *
  16.  * Required values for $params:<pre>
  17.  *   'phptype'      The database type (ie. 'pgsql', 'mysql', etc.).</pre>
  18.  *
  19.  * Optional values:<pre>
  20.  *   'table'          The name of the vfs table in 'database'. Defaults to
  21.  *                    'horde_vfs'.</pre>
  22.  *
  23.  * Required by some database implementations:<pre>
  24.  *   'hostspec'     The hostname of the database server.
  25.  *   'protocol'     The communication protocol ('tcp', 'unix', etc.).
  26.  *   'database'     The name of the database.
  27.  *   'username'     The username with which to connect to the database.
  28.  *   'password'     The password associated with 'username'.
  29.  *   'options'      Additional options to pass to the database.
  30.  *   'tty'          The TTY on which to connect to the database.
  31.  *   'port'         The port on which to connect to the database.</pre>
  32.  *
  33.  * Optional values when using separate reading and writing servers, for example
  34.  * in replication settings:<pre>
  35.  *   'splitread'   Boolean, whether to implement the separation or not.
  36.  *   'read'        Array containing the parameters which are different for
  37.  *                 the read database connection, currently supported
  38.  *                 only 'hostspec' and 'port' parameters.</pre>
  39.  *
  40.  * The table structure for the VFS can be found in data/vfs.sql.
  41.  *
  42.  * Database specific notes:
  43.  *
  44.  * MSSQL:
  45.  * <pre>
  46.  * - The vfs_data field must be of type IMAGE.
  47.  * - You need the following php.ini settings:
  48.  *    ; Valid range 0 - 2147483647. Default = 4096.
  49.  *    mssql.textlimit = 0 ; zero to pass through
  50.  *
  51.  *    ; Valid range 0 - 2147483647. Default = 4096.
  52.  *    mssql.textsize = 0 ; zero to pass through
  53.  * </pre>
  54.  *
  55.  * $Horde: framework/VFS/lib/VFS/sql.php,v 1.1.2.6 2009/02/13 05:45:19 chuck Exp $
  56.  *
  57.  * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
  58.  *
  59.  * See the enclosed file COPYING for license information (LGPL). If you
  60.  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  61.  *
  62.  * @author  Chuck Hagenbuch <chuck@horde.org>
  63.  * @package VFS
  64.  */
  65. class VFS_sql extends VFS {
  66.  
  67.     /**
  68.      * Handle for the current database connection.
  69.      *
  70.      * @var DB 
  71.      */
  72.     var $_db = false;
  73.  
  74.     /**
  75.      * Handle for the current database connection, used for writing. Defaults
  76.      * to the same handle as $_db if a separate write database is not required.
  77.      *
  78.      * @var DB 
  79.      */
  80.     var $_write_db;
  81.  
  82.     /**
  83.      * Boolean indicating whether or not we're connected to the SQL
  84.      * server.
  85.      *
  86.      * @var boolean 
  87.      */
  88.     var $_connected = false;
  89.  
  90.     /**
  91.      * Retrieves the filesize from the VFS.
  92.      *
  93.      * @param string $path  The pathname to the file.
  94.      * @param string $name  The filename to retrieve.
  95.      *
  96.      * @return int The file size.
  97.      */
  98.     function size($path$name)
  99.     {
  100.         $result $this->_connect();
  101.         if (is_a($result'PEAR_Error')) {
  102.             return $result;
  103.         }
  104.  
  105.         $length_op $this->_getFileSizeOp();
  106.         $sql sprintf(
  107.             'SELECT %s(vfs_data) FROM %s WHERE vfs_path = ? AND vfs_name = ?',
  108.             $length_op,
  109.             $this->_params['table']
  110.         );
  111.         $values = array($this->_convertPath($path)$name);
  112.         $this->log($sqlPEAR_LOG_DEBUG);
  113.         $size $this->_db->getOne($sql$values);
  114.  
  115.         if (is_null($size)) {
  116.             return PEAR::raiseError(sprintf(_("Unable to check file size of \"%s/%s\".")$path$name));
  117.         }
  118.  
  119.         return $size;
  120.     }
  121.  
  122.     /**
  123.      * Returns the size of a file.
  124.      *
  125.      * @access public
  126.      *
  127.      * @param string $path  The path of the file.
  128.      * @param string $name  The filename.
  129.      *
  130.      * @return integer  The size of the folder in bytes or PEAR_Error on
  131.      *                   failure.
  132.      */
  133.     function getFolderSize($path = null$name = null)
  134.     {
  135.         $result $this->_connect();
  136.         if (is_a($result'PEAR_Error')) {
  137.             return $result;
  138.         }
  139.  
  140.         $where (is_null($path)) ? null : sprintf('WHERE vfs_path LIKE %s'((!strlen($path)) '""' $this->_db->quote($this->_convertPath($path'%')));
  141.         $length_op $this->_getFileSizeOp();
  142.         $sql sprintf(
  143.             'SELECT SUM(%s(vfs_data)) FROM %s %s',
  144.             $length_op,
  145.             $this->_params['table'],
  146.             $where
  147.         );
  148.         $this->log($sqlPEAR_LOG_DEBUG);
  149.         $size $this->_db->getOne($sql);
  150.  
  151.         return $size !== null ? $size : 0;
  152.     }
  153.  
  154.     /**
  155.      * Retrieve a file from the VFS.
  156.      *
  157.      * @param string $path  The pathname to the file.
  158.      * @param string $name  The filename to retrieve.
  159.      *
  160.      * @return string  The file data.
  161.      */
  162.     function read($path$name)
  163.     {
  164.         $result $this->_connect();
  165.         if (is_a($result'PEAR_Error')) {
  166.             return $result;
  167.         }
  168.  
  169.         return $this->_readBlob($this->_params['table']'vfs_data',
  170.                                 array('vfs_path' => $this->_convertPath($path),
  171.                                       'vfs_name' => $name));
  172.     }
  173.  
  174.     /**
  175.      * Retrieves a part of a file from the VFS. Particularly useful
  176.      * when reading large files which would exceed the PHP memory
  177.      * limits if they were stored in a string.
  178.      *
  179.      * @param string  $path       The pathname to the file.
  180.      * @param string  $name       The filename to retrieve.
  181.      * @param integer $offset     The offset of the part. (The new offset will be
  182.      *                             stored in here).
  183.      * @param integer $length     The length of the part. If the length = -1, the
  184.      *                             whole part after the offset is retrieved. If
  185.      *                             more bytes are given as exists after the given
  186.      *                             offset. Only the available bytes are read.
  187.      * @param integer $remaining  The bytes that are left, after the part that is
  188.      *                             retrieved.
  189.      *
  190.      * @return string The file data.
  191.      */
  192.     function readByteRange($path$name&$offset$length = -1&$remaining)
  193.     {
  194.         $result $this->_connect();
  195.         if (is_a($result'PEAR_Error')) {
  196.             return $result;
  197.         }
  198.  
  199.         $data $this->_readBlob($this->_params['table']'vfs_data',
  200.                                  array('vfs_path' => $this->_convertPath($path),
  201.                                        'vfs_name' => $name));
  202.  
  203.         // Calculate how many bytes MUST be read, so the remainging
  204.         // bytes and the new offset can be calculated correctly.
  205.         $size strlen ($data);
  206.         if ($length == -1 || (($length $offset$size)) {
  207.             $length $size $offset;
  208.         }
  209.         if ($remaining < 0{
  210.             $remaining = 0;
  211.         }
  212.  
  213.         $data substr($data$offset$length);
  214.         $offset $offset $length;
  215.         $remaining $size $offset;
  216.  
  217.         return $data;
  218.     }
  219.  
  220.     /**
  221.      * Stores a file in the VFS.
  222.      *
  223.      * @param string $path         The path to store the file in.
  224.      * @param string $name         The filename to use.
  225.      * @param string $tmpFile      The temporary file containing the data to
  226.      *                              be stored.
  227.      * @param boolean $autocreate  Automatically create directories?
  228.      *
  229.      * @return mixed  True on success or a PEAR_Error object on failure.
  230.      */
  231.     function write($path$name$tmpFile$autocreate = false)
  232.     {
  233.         /* Don't need to check quota here since it will be checked when
  234.          * writeData() is called. */
  235.         return $this->writeData($path,
  236.                                 $name,
  237.                                 file_get_contents($tmpFile),
  238.                                 $autocreate);
  239.     }
  240.  
  241.     /**
  242.      * Store a file in the VFS from raw data.
  243.      *
  244.      * @param string $path         The path to store the file in.
  245.      * @param string $name         The filename to use.
  246.      * @param string $data         The file data.
  247.      * @param boolean $autocreate  Automatically create directories?
  248.      *
  249.      * @return mixed  True on success or a PEAR_Error object on failure.
  250.      */
  251.     function writeData($path$name$data$autocreate = false)
  252.     {
  253.         $result $this->_checkQuotaWrite('string'$data);
  254.         if (is_a($result'PEAR_Error')) {
  255.             return $result;
  256.         }
  257.  
  258.         $result $this->_connect();
  259.         if (is_a($result'PEAR_Error')) {
  260.             return $result;
  261.         }
  262.  
  263.         $path $this->_convertPath($path);
  264.  
  265.         /* Check to see if the data already exists. */
  266.         $sql sprintf('SELECT vfs_id FROM %s WHERE vfs_path %s AND vfs_name = ?',
  267.                        $this->_params['table'],
  268.                        (!strlen($path&& $this->_db->dbsyntax == 'oci8'' IS NULL' ' = ' $this->_db->quote($path));
  269.         $values = array($name);
  270.         $this->log($sqlPEAR_LOG_DEBUG);
  271.         $id $this->_db->getOne($sql$values);
  272.  
  273.         if (is_a($id'PEAR_Error')) {
  274.             $this->log($idPEAR_LOG_ERR);
  275.             return $id;
  276.         }
  277.  
  278.         if (!is_null($id)) {
  279.             return $this->_updateBlob($this->_params['table']'vfs_data',
  280.                                       $dataarray('vfs_id' => $id),
  281.                                       array('vfs_modified' => time()));
  282.         else {
  283.             /* Check to see if the folder already exists. */
  284.             $dirs explode('/'$path);
  285.             $path_name array_pop($dirs);
  286.             $parent implode('/'$dirs);
  287.             if (!$this->isFolder($parent$path_name)) {
  288.                 if (!$autocreate{
  289.                     return PEAR::raiseError(sprintf(_("Folder \"%s\" does not exist")$path)'horde.error');
  290.                 else {
  291.                     $result $this->autocreatePath($path);
  292.                     if (is_a($result'PEAR_Error')) {
  293.                         return $result;
  294.                     }
  295.                 }
  296.             }
  297.  
  298.             $id $this->_write_db->nextId($this->_params['table']);
  299.             if (is_a($id'PEAR_Error')) {
  300.                 $this->log($idPEAR_LOG_ERR);
  301.                 return $id;
  302.             }
  303.  
  304.             return $this->_insertBlob($this->_params['table']'vfs_data',
  305.                                       $dataarray('vfs_id' => $id,
  306.                                                    'vfs_type' => VFS_FILE,
  307.                                                    'vfs_path' => $path,
  308.                                                    'vfs_name' => $name,
  309.                                                    'vfs_modified' => time(),
  310.                                                    'vfs_owner' => $this->_params['user']));
  311.         }
  312.     }
  313.  
  314.     /**
  315.      * Delete a file from the VFS.
  316.      *
  317.      * @param string $path  The path to store the file in.
  318.      * @param string $name  The filename to use.
  319.      *
  320.      * @return mixed  True on success or a PEAR_Error object on failure.
  321.      */
  322.     function deleteFile($path$name)
  323.     {
  324.         $result $this->_checkQuotaDelete($path$name);
  325.         if (is_a($result'PEAR_Error')) {
  326.             return $result;
  327.         }
  328.  
  329.         $result $this->_connect();
  330.         if (is_a($result'PEAR_Error')) {
  331.             return $result;
  332.         }
  333.  
  334.         $path $this->_convertPath($path);
  335.  
  336.         $sql sprintf('DELETE FROM %s WHERE vfs_type = ? AND vfs_path %s AND vfs_name = ?',
  337.                        $this->_params['table'],
  338.                        (!strlen($path&& $this->_db->dbsyntax == 'oci8'' IS NULL' ' = ' $this->_db->quote($path));
  339.         $values = array(VFS_FILE$name);
  340.         $this->log($sqlPEAR_LOG_DEBUG);
  341.         $result $this->_db->query($sql$values);
  342.  
  343.         if ($this->_db->affectedRows(== 0{
  344.             return PEAR::raiseError(_("Unable to delete VFS file."));
  345.         }
  346.  
  347.         return $result;
  348.     }
  349.  
  350.     /**
  351.      * Rename a file or folder in the VFS.
  352.      *
  353.      * @param string $oldpath  The old path to the file.
  354.      * @param string $oldname  The old filename.
  355.      * @param string $newpath  The new path of the file.
  356.      * @param string $newname  The new filename.
  357.      *
  358.      * @return mixed  True on success or a PEAR_Error object on failure.
  359.      */
  360.     function rename($oldpath$oldname$newpath$newname)
  361.     {
  362.         $result $this->_connect();
  363.         if (is_a($result'PEAR_Error')) {
  364.             return $result;
  365.         }
  366.  
  367.         if (strpos($newpath'/'=== false{
  368.             $parent '';
  369.             $path $newpath;
  370.         else {
  371.             list($parent$pathexplode('/'$newpath2);
  372.         }
  373.         if (!$this->isFolder($parent$path)) {
  374.             if (is_a($result $this->autocreatePath($newpath)'PEAR_Error')) {
  375.                 return $result;
  376.             }
  377.         }
  378.  
  379.         $oldpath $this->_convertPath($oldpath);
  380.         $newpath $this->_convertPath($newpath);
  381.  
  382.         $sql  'UPDATE ' $this->_params['table'];
  383.         $sql .= ' SET vfs_path = ?, vfs_name = ?, vfs_modified = ? WHERE vfs_path = ? AND vfs_name = ?';
  384.         $this->log($sqlPEAR_LOG_DEBUG);
  385.  
  386.         $values = array($newpath$newnametime()$oldpath$oldname);
  387.  
  388.         $result $this->_write_db->query($sql$values);
  389.  
  390.         if ($this->_write_db->affectedRows(== 0{
  391.             return PEAR::raiseError(_("Unable to rename VFS file."));
  392.         }
  393.  
  394.         $rename $this->_recursiveRename($oldpath$oldname$newpath$newname);
  395.         if (is_a($rename'PEAR_Error')) {
  396.             $this->log($renamePEAR_LOG_ERR);
  397.             return PEAR::raiseError(sprintf(_("Unable to rename VFS directory: %s.")$rename->getMessage()));
  398.         }
  399.  
  400.         return $result;
  401.     }
  402.  
  403.     /**
  404.      * Creates a folder on the VFS.
  405.      *
  406.      * @param string $path  Holds the path of directory to create folder.
  407.      * @param string $name  Holds the name of the new folder.
  408.      *
  409.      * @return mixed  True on success or a PEAR_Error object on failure.
  410.      */
  411.     function createFolder($path$name)
  412.     {
  413.         $result $this->_connect();
  414.         if (is_a($result'PEAR_Error')) {
  415.             return $result;
  416.         }
  417.  
  418.         $id $this->_write_db->nextId($this->_params['table']);
  419.         if (is_a($id'PEAR_Error')) {
  420.             $this->log($idPEAR_LOG_ERR);
  421.             return $id;
  422.         }
  423.  
  424.         $sql  'INSERT INTO ' $this->_params['table'];
  425.         $sql .= ' (vfs_id, vfs_type, vfs_path, vfs_name, vfs_modified, vfs_owner) VALUES (?, ?, ?, ?, ?, ?)';
  426.         $this->log($sqlPEAR_LOG_DEBUG);
  427.  
  428.         $values = array($idVFS_FOLDER$this->_convertPath($path)$nametime()$this->_params['user']);
  429.  
  430.         return $this->_db->query($sql$values);
  431.     }
  432.  
  433.     /**
  434.      * Delete a folder from the VFS.
  435.      *
  436.      * @param string $path        The path of the folder.
  437.      * @param string $name        The folder name to use.
  438.      * @param boolean $recursive  Force a recursive delete?
  439.      *
  440.      * @return mixed  True on success or a PEAR_Error object on failure.
  441.      */
  442.     function deleteFolder($path$name$recursive = false)
  443.     {
  444.         $result $this->_connect();
  445.         if (is_a($result'PEAR_Error')) {
  446.             return $result;
  447.         }
  448.  
  449.         $path $this->_convertPath($path);
  450.  
  451.         $folderPath $this->_getNativePath($path$name);
  452.  
  453.         /* Check if not recursive and fail if directory not empty */
  454.         if (!$recursive{
  455.             $folderList $this->listFolder($folderPathnulltrue);
  456.             if (is_a($folderList'PEAR_Error')) {
  457.                 $this->log($folderListPEAR_LOG_ERR);
  458.                 return $folderList;
  459.             elseif (!empty($folderList)) {
  460.                 return PEAR::raiseError(sprintf(_("Unable to delete %s, the directory is not empty"),
  461.                                                 $path '/' $name));
  462.             }
  463.         }
  464.  
  465.         /* First delete everything below the folder, so if error we
  466.          * get no orphans */
  467.         $sql sprintf('DELETE FROM %s WHERE vfs_path %s',
  468.                        $this->_params['table'],
  469.                        (!strlen($folderPath&& $this->_write_db->dbsyntax == 'oci8'' IS NULL' ' LIKE ' $this->_write_db->quote($this->_getNativePath($folderPath'%')));
  470.         $this->log($sqlPEAR_LOG_DEBUG);
  471.         $deleteContents $this->_write_db->query($sql);
  472.         if (is_a($deleteContents'PEAR_Error')) {
  473.             $this->log($deleteContentsPEAR_LOG_ERR);
  474.             return PEAR::raiseError(sprintf(_("Unable to delete VFS recursively: %s.")$deleteContents->getMessage()));
  475.         }
  476.  
  477.         /* Now delete everything inside the folder. */
  478.         $sql sprintf('DELETE FROM %s WHERE vfs_path %s',
  479.                        $this->_params['table'],
  480.                        (!strlen($path&& $this->_write_db->dbsyntax == 'oci8'' IS NULL' ' = ' $this->_write_db->quote($folderPath));
  481.         $this->log($sqlPEAR_LOG_DEBUG);
  482.         $delete $this->_write_db->query($sql);
  483.         if (is_a($delete'PEAR_Error')) {
  484.             $this->log($deletePEAR_LOG_ERR);
  485.             return PEAR::raiseError(sprintf(_("Unable to delete VFS directory: %s.")$delete->getMessage()));
  486.         }
  487.  
  488.         /* All ok now delete the actual folder */
  489.         $sql sprintf('DELETE FROM %s WHERE vfs_path %s AND vfs_name = ?',
  490.                        $this->_params['table'],
  491.                        (!strlen($path&& $this->_write_db->dbsyntax == 'oci8'' IS NULL' ' = ' $this->_write_db->quote($path));
  492.         $values = array($name);
  493.         $this->log($sqlPEAR_LOG_DEBUG);
  494.         $delete $this->_write_db->query($sql$values);
  495.         if (is_a($delete'PEAR_Error')) {
  496.             $this->log($deletePEAR_LOG_ERR);
  497.             return PEAR::raiseError(sprintf(_("Unable to delete VFS directory: %s.")$delete->getMessage()));
  498.         }
  499.  
  500.         return $delete;
  501.     }
  502.  
  503.     /**
  504.      * Return a list of the contents of a folder.
  505.      *
  506.      * @param string $path       The directory path.
  507.      * @param mixed $filter      String/hash of items to filter based on
  508.      *                            filename.
  509.      * @param boolean $dotfiles  Show dotfiles?
  510.      * @param boolean $dironly   Show directories only?
  511.      *
  512.      * @return mixed  File list on success or false on failure.
  513.      */
  514.     function _listFolder($path$filter = null$dotfiles = true,
  515.                          $dironly = false)
  516.     {
  517.         $result $this->_connect();
  518.         if (is_a($result'PEAR_Error')) {
  519.             return $result;
  520.         }
  521.  
  522.         $path $this->_convertPath($path);
  523.  
  524.         // Fix for Oracle not differentiating between '' and NULL.
  525.         if (!strlen($path&& $this->_db->dbsyntax == 'oci8'{
  526.             $where 'vfs_path IS NULL';
  527.         else {
  528.             $where 'vfs_path = ' $this->_db->quote($path);
  529.         }
  530.  
  531.         $length_op $this->_getFileSizeOp();
  532.         $sql sprintf('SELECT vfs_name, vfs_type, %s(vfs_data), vfs_modified, vfs_owner FROM %s WHERE %s',
  533.                        $length_op,
  534.                        $this->_params['table'],
  535.                        $where);
  536.         $this->log($sqlPEAR_LOG_DEBUG);
  537.         $fileList $this->_db->getAll($sql);
  538.         if (is_a($fileList'PEAR_Error')) {
  539.             return $fileList;
  540.         }
  541.  
  542.         $files = array();
  543.         foreach ($fileList as $line{
  544.             // Filter out dotfiles if they aren't wanted.
  545.             if (!$dotfiles && substr($line[0]01== '.'{
  546.                 continue;
  547.             }
  548.  
  549.             $file['name'$line[0];
  550.  
  551.             if ($line[1== VFS_FILE{
  552.                 $name explode('.'$line[0]);
  553.  
  554.                 if (count($name== 1{
  555.                     $file['type''**none';
  556.                 else {
  557.                     $file['type'VFS::strtolower($name[count($name- 1]);
  558.                 }
  559.  
  560.                 $file['size'$line[2];
  561.             elseif ($line[1== VFS_FOLDER{
  562.                 $file['type''**dir';
  563.                 $file['size'= -1;
  564.             }
  565.  
  566.             $file['date'$line[3];
  567.             $file['owner'$line[4];
  568.             $file['perms''';
  569.             $file['group''';
  570.  
  571.             // filtering
  572.             if ($this->_filterMatch($filter$file['name'])) {
  573.                 unset($file);
  574.                 continue;
  575.             }
  576.             if ($dironly && $file['type'!== '**dir'{
  577.                 unset($file);
  578.                 continue;
  579.             }
  580.  
  581.             $files[$file['name']] $file;
  582.             unset($file);
  583.        }
  584.  
  585.         return $files;
  586.     }
  587.  
  588.     /**
  589.      * Returns a sorted list of folders in specified directory.
  590.      *
  591.      * @param string $path         The path of the directory to get the
  592.      *                              directory list for.
  593.      * @param mixed $filter        String/hash of items to filter based on
  594.      *                              folderlist.
  595.      * @param boolean $dotfolders  Include dotfolders?
  596.      *
  597.      * @return mixed  Folder list on success or PEAR_Error object on failure.
  598.      */
  599.     function listFolders($path ''$filter = array()$dotfolders = true)
  600.     {
  601.         $result $this->_connect();
  602.         if (is_a($result'PEAR_Error')) {
  603.             return $result;
  604.         }
  605.  
  606.         $path $this->_convertPath($path);
  607.  
  608.         $sql  'SELECT vfs_name, vfs_path FROM ' $this->_params['table'];
  609.         $sql .= ' WHERE vfs_path = ? AND vfs_type = ?';
  610.         $this->log($sqlPEAR_LOG_DEBUG);
  611.  
  612.         $values = array($pathVFS_FOLDER);
  613.  
  614.         $folderList $this->_db->getAll($sql$values);
  615.         if (is_a($folderList'PEAR_Error')) {
  616.             return $folderList;
  617.         }
  618.  
  619.         $folders = array();
  620.         foreach ($folderList as $line{
  621.             $folder['val'$this->_getNativePath($line[1]$line[0]);
  622.             $folder['abbrev''';
  623.             $folder['label''';
  624.  
  625.             $count substr_count($folder['val']'/');
  626.  
  627.             $x = 0;
  628.             while ($x $count{
  629.                 $folder['abbrev'.= '    ';
  630.                 $folder['label'.= '    ';
  631.                 $x++;
  632.             }
  633.  
  634.             $folder['abbrev'.= $line[0];
  635.             $folder['label'.= $line[0];
  636.  
  637.             $strlen VFS::strlen($folder['label']);
  638.             if ($strlen > 26{
  639.                 $folder['abbrev'substr($folder['label']0($count * 4));
  640.                 $length (29 - ($count * 4)) / 2;
  641.                 $folder['abbrev'.= substr($folder['label']($count * 4)$length);
  642.                 $folder['abbrev'.= '...';
  643.                 $folder['abbrev'.= substr($folder['label']-1 * $length$length);
  644.             }
  645.  
  646.             $found = false;
  647.             foreach ($filter as $fltr{
  648.                 if ($folder['val'== $fltr{
  649.                     $found = true;
  650.                 }
  651.             }
  652.  
  653.             if (!$found{
  654.                 $folders[$folder['val']] $folder;
  655.             }
  656.         }
  657.  
  658.         ksort($folders);
  659.         return $folders;
  660.     }
  661.  
  662.     /**
  663.      * Garbage collect files in the VFS storage system.
  664.      *
  665.      * @param string $path   The VFS path to clean.
  666.      * @param integer $secs  The minimum amount of time (in seconds) required
  667.      *                        before a file is removed.
  668.      */
  669.     function gc($path$secs = 345600)
  670.     {
  671.         $result $this->_connect();
  672.         if (is_a($result'PEAR_Error')) {
  673.             return $result;
  674.         }
  675.  
  676.         $sql 'DELETE FROM ' $this->_params['table']
  677.             . ' WHERE vfs_type = ? AND vfs_modified < ? AND (vfs_path = ? OR vfs_path LIKE ?)';
  678.         $this->log($sqlPEAR_LOG_DEBUG);
  679.  
  680.         $values = array(VFS_FILE,
  681.                         time($secs,
  682.                         $this->_convertPath($path),
  683.                         $this->_convertPath($path'/%');
  684.  
  685.         return $this->_write_db->query($sql$values);
  686.     }
  687.  
  688.     /**
  689.      * Renames all child paths.
  690.      *
  691.      * @access private
  692.      *
  693.      * @param string $path  The path of the folder to rename.
  694.      * @param string $name  The foldername to use.
  695.      *
  696.      * @return mixed  True on success or a PEAR_Error object on failure.
  697.      */
  698.     function _recursiveRename($oldpath$oldname$newpath$newname)
  699.     {
  700.         $oldpath $this->_convertPath($oldpath);
  701.         $newpath $this->_convertPath($newpath);
  702.  
  703.         $sql  'SELECT vfs_name FROM ' $this->_params['table'];
  704.         $sql .= ' WHERE vfs_type = ? AND vfs_path = ?';
  705.         $this->log($sqlPEAR_LOG_DEBUG);
  706.  
  707.         $values = array(VFS_FOLDER$this->_getNativePath($oldpath$oldname));
  708.  
  709.         $folderList $this->_db->getCol($sql0$values);
  710.  
  711.         foreach ($folderList as $folder{
  712.             $this->_recursiveRename($this->_getNativePath($oldpath$oldname)$folder$this->_getNativePath($newpath$newname)$folder);
  713.         }
  714.  
  715.         $sql 'UPDATE ' $this->_params['table'' SET vfs_path = ? WHERE vfs_path = ?';
  716.         $this->log($sqlPEAR_LOG_DEBUG);
  717.  
  718.         $values = array($this->_getNativePath($newpath$newname)$this->_getNativePath($oldpath$oldname));
  719.  
  720.         return $this->_write_db->query($sql$values);
  721.     }
  722.  
  723.     /**
  724.      * Return a full filename on the native filesystem, from a VFS
  725.      * path and name.
  726.      *
  727.      * @access private
  728.      *
  729.      * @param string $path  The VFS file path.
  730.      * @param string $name  The VFS filename.
  731.      *
  732.      * @return string  The full native filename.
  733.      */
  734.     function _getNativePath($path$name)
  735.     {
  736.         if (!strlen($path)) {
  737.             return $name;
  738.         }
  739.  
  740.         if (isset($this->_params['home']&&
  741.             preg_match('|^~/?(.*)$|'$path$matches)) {
  742.             $path $this->_params['home''/' $matches[1];
  743.         }
  744.  
  745.         return $path '/' $name;
  746.     }
  747.  
  748.     /**
  749.      * Attempts to open a persistent connection to the SQL server.
  750.      *
  751.      * @access private
  752.      *
  753.      * @return mixed  True on success or a PEAR_Error object on failure.
  754.      */
  755.     function _connect()
  756.     {
  757.         if ($this->_connected{
  758.             return true;
  759.         }
  760.  
  761.         if (!is_array($this->_params)) {
  762.             return PEAR::raiseError(_("No configuration information specified for SQL VFS."));
  763.         }
  764.  
  765.         $required = array('phptype');
  766.         foreach ($required as $val{
  767.             if (!isset($this->_params[$val])) {
  768.                 return PEAR::raiseError(sprintf(_("Required \"%s\" not specified in VFS configuration.")$val));
  769.             }
  770.         }
  771.  
  772.         if (!isset($this->_params['database'])) {
  773.             $this->_params['database''';
  774.         }
  775.         if (!isset($this->_params['username'])) {
  776.             $this->_params['username''';
  777.         }
  778.         if (!isset($this->_params['hostspec'])) {
  779.             $this->_params['hostspec''';
  780.         }
  781.         if (!isset($this->_params['table'])) {
  782.             $this->_params['table''horde_vfs';
  783.         }
  784.  
  785.         /* Connect to the SQL server using the supplied parameters. */
  786.         require_once 'DB.php';
  787.         $this->_write_db &DB::connect($this->_params,
  788.                                         array('persistent' => !empty($this->_params['persistent']),
  789.                                               'ssl' => !empty($this->_params['ssl'])));
  790.         if (is_a($this->_write_db'PEAR_Error')) {
  791.             $this->log($this->_write_dbPEAR_LOG_ERR);
  792.             $error $this->_write_db;
  793.             $this->_write_db = false;
  794.             return $error;
  795.         }
  796.  
  797.         // Set DB portability options.
  798.         switch ($this->_write_db->phptype{
  799.         case 'mssql':
  800.             $this->_write_db->setOption('portability'DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
  801.             break;
  802.         default:
  803.             $this->_write_db->setOption('portability'DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
  804.         }
  805.  
  806.         /* Check if we need to set up the read DB connection
  807.          * seperately. */
  808.         if (!empty($this->_params['splitread'])) {
  809.             $params array_merge($this->_params$this->_params['read']);
  810.             $this->_db &DB::connect($params,
  811.                                       array('persistent' => !empty($params['persistent']),
  812.                                             'ssl' => !empty($params['ssl'])));
  813.             if (is_a($this->_db'PEAR_Error')) {
  814.                 return $this->_db;
  815.             }
  816.  
  817.             // Set DB portability options.
  818.             switch ($this->_db->phptype{
  819.             case 'mssql':
  820.                 $this->_db->setOption('portability'DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
  821.                 break;
  822.             default:
  823.                 $this->_db->setOption('portability'DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
  824.             }
  825.  
  826.         else {
  827.             /* Default to the same DB handle for reads. */
  828.             $this->_db =$this->_write_db;
  829.         }
  830.  
  831.         $this->_connected = true;
  832.         return true;
  833.     }
  834.  
  835.     /**
  836.      * Read file data from the SQL VFS backend.
  837.      *
  838.      * @access private
  839.      *
  840.      * @param string $table    The VFS table name.
  841.      * @param string $field    TODO
  842.      * @param array $criteria  TODO
  843.      *
  844.      * @return mixed  TODO
  845.      */
  846.     function _readBlob($table$field$criteria)
  847.     {
  848.         if (!count($criteria)) {
  849.             return PEAR::raiseError('You must specify the fetch criteria');
  850.         }
  851.  
  852.         $where '';
  853.  
  854.         switch ($this->_db->dbsyntax{
  855.         case 'oci8':
  856.             foreach ($criteria as $key => $value{
  857.                 if (!empty($where)) {
  858.                     $where .= ' AND ';
  859.                 }
  860.                 if (!strlen($value)) {
  861.                     $where .= $key ' IS NULL';
  862.                 else {
  863.                     $where .= $key ' = ' $this->_db->quote($value);
  864.                 }
  865.             }
  866.  
  867.             $statement = OCIParse($this->_db->connection,
  868.                                   sprintf('SELECT %s FROM %s WHERE %s',
  869.                                           $field$table$where));
  870.             OCIExecute($statement);
  871.             if (OCIFetchInto($statement$lob)) {
  872.                 $result $lob[0]->load();
  873.                 if (is_null($result)) {
  874.                     $result = PEAR::raiseError('Unable to load SQL data.');
  875.                 }
  876.             else {
  877.                 $result = PEAR::raiseError('Unable to load SQL data.');
  878.             }
  879.             OCIFreeStatement($statement);
  880.             break;
  881.  
  882.         default:
  883.             foreach ($criteria as $key => $value{
  884.                 if (!empty($where)) {
  885.                     $where .= ' AND ';
  886.                 }
  887.                 $where .= $key ' = ' $this->_db->quote($value);
  888.             }
  889.  
  890.             $sql sprintf('SELECT %s FROM %s WHERE %s',
  891.                            $field$table$where);
  892.             $this->log($sqlPEAR_LOG_DEBUG);
  893.             $result $this->_db->getOne($sql);
  894.  
  895.             if (is_null($result)) {
  896.                 $result = PEAR::raiseError('Unable to load SQL data.');
  897.             else {
  898.                 switch ($this->_db->dbsyntax{
  899.                 case 'pgsql':
  900.                     $result pack('H' strlen($result)$result);
  901.                     break;
  902.                 }
  903.             }
  904.         }
  905.  
  906.         return $result;
  907.     }
  908.  
  909.     /**
  910.      * TODO
  911.      *
  912.      * @access private
  913.      *
  914.      * @param string $table       TODO
  915.      * @param string $field       TODO
  916.      * @param string $data        TODO
  917.      * @param string $attributes  TODO
  918.      *
  919.      * @return mixed  TODO
  920.      */
  921.     function _insertBlob($table$field$data$attributes)
  922.     {
  923.         $fields = array();
  924.         $values = array();
  925.  
  926.         switch ($this->_write_db->dbsyntax{
  927.         case 'oci8':
  928.             foreach ($attributes as $key => $value{
  929.                 $fields[$key;
  930.                 $values[$this->_write_db->quoteSmart($value);
  931.             }
  932.  
  933.             $statement = OCIParse($this->_write_db->connection,
  934.                                   sprintf('INSERT INTO %s (%s, %s)' .
  935.                                           ' VALUES (%s, EMPTY_BLOB()) RETURNING %s INTO :blob',
  936.                                           $table,
  937.                                           implode(', '$fields),
  938.                                           $field,
  939.                                           implode(', '$values),
  940.                                           $field));
  941.  
  942.             $lob = OCINewDescriptor($this->_write_db->connection);
  943.             OCIBindByName($statement':blob'$lob-1SQLT_BLOB);
  944.             OCIExecute($statementOCI_DEFAULT);
  945.             $lob->save($data);
  946.             $result = OCICommit($this->_write_db->connection);
  947.             $lob->free();
  948.             OCIFreeStatement($statement);
  949.             return $result ? true : PEAR::raiseError('Unknown Error');
  950.  
  951.         default:
  952.             foreach ($attributes as $key => $value{
  953.                 $fields[$key;
  954.                 $values[$value;
  955.             }
  956.  
  957.             $query sprintf('INSERT INTO %s (%s, %s) VALUES (%s)',
  958.                              $table,
  959.                              implode(', '$fields),
  960.                              $field,
  961.                              '?' str_repeat(', ?'count($values)));
  962.             break;
  963.         }
  964.  
  965.         switch ($this->_write_db->dbsyntax{
  966.         case 'mssql':
  967.         case 'pgsql':
  968.             $values[bin2hex($data);
  969.             break;
  970.  
  971.         default:
  972.             $values[$data;
  973.         }
  974.  
  975.         /* Execute the query. */
  976.         $this->log($queryPEAR_LOG_DEBUG);
  977.         return $this->_write_db->query($query$values);
  978.     }
  979.  
  980.     /**
  981.      * TODO
  982.      *
  983.      * @access private
  984.      *
  985.      * @param string $table      TODO
  986.      * @param string $field      TODO
  987.      * @param string $data       TODO
  988.      * @param string $where      TODO
  989.      * @param array $alsoupdate  TODO
  990.      *
  991.      * @return mixed  TODO
  992.      */
  993.     function _updateBlob($table$field$data$where$alsoupdate)
  994.     {
  995.         $fields = array();
  996.         $values = array();
  997.  
  998.         switch ($this->_write_db->dbsyntax{
  999.         case 'oci8':
  1000.             $wherestring '';
  1001.             foreach ($where as $key => $value{
  1002.                 if (!empty($wherestring)) {
  1003.                     $wherestring .= ' AND ';
  1004.                 }
  1005.                 $wherestring .= $key ' = ' $this->_write_db->quote($value);
  1006.             }
  1007.  
  1008.             $statement = OCIParse($this->_write_db->connection,
  1009.                                   sprintf('SELECT %s FROM %s WHERE %s FOR UPDATE',
  1010.                                           $field,
  1011.                                           $table,
  1012.                                           $wherestring));
  1013.  
  1014.             OCIExecute($statementOCI_DEFAULT);
  1015.             OCIFetchInto($statement$lob);
  1016.             $lob[0]->save($data);
  1017.             $result = OCICommit($this->_write_db->connection);
  1018.             $lob[0]->free();
  1019.             OCIFreeStatement($statement);
  1020.             return $result ? true : PEAR::raiseError('Unknown Error');
  1021.  
  1022.         default:
  1023.             $updatestring '';
  1024.             $values = array();
  1025.             foreach ($alsoupdate as $key => $value{
  1026.                 $updatestring .= $key ' = ?, ';
  1027.                 $values[$value;
  1028.             }
  1029.             $updatestring .= $field ' = ?';
  1030.             switch ($this->_write_db->dbsyntax{
  1031.             case 'mssql':
  1032.             case 'pgsql':
  1033.                 $values[bin2hex($data);
  1034.                 break;
  1035.  
  1036.             default:
  1037.                 $values[$data;
  1038.             }
  1039.  
  1040.             $wherestring '';
  1041.             foreach ($where as $key => $value{
  1042.                 if (!empty($wherestring)) {
  1043.                     $wherestring .= ' AND ';
  1044.                 }
  1045.                 $wherestring .= $key ' = ?';
  1046.                 $values[$value;
  1047.             }
  1048.  
  1049.             $query sprintf('UPDATE %s SET %s WHERE %s',
  1050.                              $table,
  1051.                              $updatestring,
  1052.                              $wherestring);
  1053.             break;
  1054.         }
  1055.  
  1056.         /* Execute the query. */
  1057.         $this->log($queryPEAR_LOG_DEBUG);
  1058.         return $this->_write_db->query($query$values);
  1059.     }
  1060.  
  1061.     /**
  1062.      * Converts the path name from regular filesystem form to the internal
  1063.      * format needed to access the file in the database.
  1064.      *
  1065.      * Namely, we will treat '/' as a base directory as this is pretty much
  1066.      * the standard way to access base directories over most filesystems.
  1067.      *
  1068.      * @access private
  1069.      *
  1070.      * @param string $path  A VFS path.
  1071.      *
  1072.      * @return string  The path with any surrouding slashes stripped off.
  1073.      */
  1074.     function _convertPath($path)
  1075.     {
  1076.         return trim($path'/');
  1077.     }
  1078.  
  1079.     /**
  1080.      * TODO
  1081.      */
  1082.     function _getFileSizeOp()
  1083.     {
  1084.         switch ($this->_db->dbsyntax{
  1085.         case 'mysql':
  1086.             return 'LENGTH';
  1087.  
  1088.         case 'oci8':
  1089.             return 'LENGTHB';
  1090.  
  1091.         case 'mssql':
  1092.         case 'sybase':
  1093.             return 'DATALENGTH';
  1094.  
  1095.         case 'pgsql':
  1096.         default:
  1097.             return 'OCTET_LENGTH';
  1098.         }
  1099.     }
  1100.  
  1101.     /**
  1102.      * VFS_sql override of isFolder() to check for root folder.
  1103.      *
  1104.      * @param string $path  Path to possible folder
  1105.      * @param string $name  Name of possible folder
  1106.      *
  1107.      * @return boolean        True if $path/$name is a folder
  1108.      */
  1109.     function isFolder($path$name)
  1110.     {
  1111.         if ($path == '' && $name == ''{
  1112.             // The root of VFS is always a folder.
  1113.             return true;
  1114.         }
  1115.         return parent::isFolder($path$name);
  1116.     }
  1117.  
  1118. }

Documentation generated on Mon, 11 Mar 2019 15:34:56 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.