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

Documentation generated on Mon, 11 Mar 2019 14:39:01 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.