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

Source for file smb.php

Documentation is available at smb.php

  1. <?php
  2. /**
  3.  * Stateless VFS implementation for a SMB server, based on smbclient.
  4.  *
  5.  * Required values for $params:
  6.  * <pre>
  7.  *   'username'  - The username with which to connect to the SMB server.
  8.  *   'password'  - The password with which to connect to the SMB server.
  9.  *   'hostspec'  - The SMB server to connect to.
  10.  *   'port'      - The SMB port number to connect to.
  11.  *   'share'     - The share to access on the SMB server.
  12.  *   'smbclient' - The path to the 'smbclient' executable.
  13.  * </pre>
  14.  *
  15.  * Optional values for $params:
  16.  * <pre>
  17.  *   'ipaddress' - The address of the server to connect to.
  18.  * </pre>
  19.  *
  20.  * Functions not implemented:
  21.  *   - changePermissions(): The SMB permission style does not fit with the
  22.  *                          module.
  23.  *
  24.  * $Horde: framework/VFS/lib/VFS/smb.php,v 1.1 2007/12/07 00:24:22 chuck Exp $
  25.  *
  26.  * Codebase copyright 2002 Paul Gareau <paul@xhawk.net>.  Adapted with
  27.  * permission by Patrice Levesque <wayne@ptaff.ca> from phpsmb-0.8 code, and
  28.  * converted to the LGPL.  Please do not taunt original author, contact
  29.  * Patrice Levesque or dev@lists.horde.org.
  30.  *
  31.  * See the enclosed file COPYING for license information (LGPL). If you
  32.  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  33.  *
  34.  * @author  Paul Gareau <paul@xhawk.net>
  35.  * @author  Patrice Levesque <wayne@ptaff.ca>
  36.  * @since   Horde 3.1
  37.  * @package VFS
  38.  */
  39. class VFS_smb extends VFS {
  40.  
  41.     /**
  42.      * List of additional credentials required for this VFS backend.
  43.      *
  44.      * @var array 
  45.      */
  46.     var $_credentials = array('username''password');
  47.  
  48.     /**
  49.      * List of permissions and if they can be changed in this VFS backend.
  50.      *
  51.      * @var array 
  52.      */
  53.     var $_permissions = array(
  54.         'owner' => array('read' => false'write' => false'execute' => false),
  55.         'group' => array('read' => false'write' => false'execute' => false),
  56.         'all'   => array('read' => false'write' => false'execute' => false));
  57.  
  58.     /**
  59.      * Authenticates a user on the SMB server and share.
  60.      *
  61.      * @access private
  62.      *
  63.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  64.      */
  65.     function _connect()
  66.     {
  67.         $cmd = array('quit');
  68.         $err $this->_command(''$cmd);
  69.         if (is_a($err'PEAR_Error')) {
  70.             return PEAR::raiseError(_("Authentication to the SMB server failed."));
  71.         }
  72.         return true;
  73.     }
  74.  
  75.     /**
  76.      * Retrieves a file from the VFS.
  77.      *
  78.      * @param string $path  The pathname to the file.
  79.      * @param string $name  The filename to retrieve.
  80.      *
  81.      * @return string  The file data.
  82.      */
  83.     function read($path$name)
  84.     {
  85.         list($path$name$this->_escapeShellCommand($path$name);
  86.         $temp $this->_getTempFile();
  87.         $cmd = array('get \"' $name '\" ' $temp);
  88.         $err $this->_command($path$cmd);
  89.         if (is_a($err'PEAR_Error')) {
  90.             return $err;
  91.         }
  92.         if (!file_exists($temp)) {
  93.             return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\".")$this->_getPath($path$name)));
  94.         }
  95.  
  96.         $file file_get_contents($temp);
  97.         unlink($temp);
  98.         if ($file !== false{
  99.             return $file;
  100.         else {
  101.             return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\".")$this->_getPath($path$name)));
  102.         }
  103.     }
  104.  
  105.     /**
  106.      * Stores a file in the VFS.
  107.      *
  108.      * @param string $path         The path to store the file in.
  109.      * @param string $name         The filename to use.
  110.      * @param string $tmpFile      The temporary file containing the data to be
  111.      *                              stored.
  112.      * @param boolean $autocreate  Automatically create directories?
  113.      *
  114.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  115.      */
  116.     function write($path$name$tmpFile$autocreate = false)
  117.     {
  118.         // Double quotes not allowed in SMB filename.
  119.         $name str_replace('"'"'"$name);
  120.  
  121.         list($path$name$this->_escapeShellCommand($path$name);
  122.         $cmd = array('put \"' $tmpFile '\" \"' $name '\"');
  123.         // do we need to first autocreate the directory?
  124.         if ($autocreate{
  125.             $result $this->autocreatePath($path);
  126.             if (is_a($result'PEAR_Error')) {
  127.                 return $result;
  128.             }
  129.         }
  130.         $err $this->_command($path$cmd);
  131.         if (is_a($err'PEAR_Error')) {
  132.             return $err;
  133.         }
  134.         return true;
  135.     }
  136.  
  137.     /**
  138.      * Stores a file in the VFS from raw data.
  139.      *
  140.      * @param string $path         The path to store the file in.
  141.      * @param string $name         The filename to use.
  142.      * @param string $data         The file data.
  143.      * @param boolean $autocreate  Automatically create directories?
  144.      *
  145.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  146.      */
  147.     function writeData($path$name$data$autocreate = false)
  148.     {
  149.         $tmpFile $this->_getTempFile();
  150.         $fp fopen($tmpFile'wb');
  151.         fwrite($fp$data);
  152.         fclose($fp);
  153.         $result $this->write($path$name$tmpFile$autocreate);
  154.         unlink($tmpFile);
  155.         return $result;
  156.     }
  157.  
  158.     /**
  159.      * Deletes a file from the VFS.
  160.      *
  161.      * @param string $path  The path to delete the file from.
  162.      * @param string $name  The filename to use.
  163.      *
  164.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  165.      */
  166.     function deleteFile($path$name)
  167.     {
  168.         // In some samba versions after samba-3.0.25-pre2, $path must
  169.         // end in a trailing slash.
  170.         if (substr($path-1!= '/'{
  171.             $path .= '/';
  172.         }
  173.  
  174.         list($path$name$this->_escapeShellCommand($path$name);
  175.         $cmd = array('del \"' $name '\"');
  176.         $err $this->_command($path$cmd);
  177.         if (is_a($err'PEAR_Error')) {
  178.             return $err;
  179.         }
  180.         return true;
  181.     }
  182.  
  183.     /**
  184.      * Checks if a given pathname is a folder.
  185.      *
  186.      * @param string $path  The path to the folder.
  187.      * @param string $name  The file or folder name.
  188.      *
  189.      * @return boolean  True if it is a folder, false otherwise.
  190.      */
  191.     function isFolder($path$name)
  192.     {
  193.         list($path$name$this->_escapeShellCommand($path$name);
  194.         $cmd = array('quit');
  195.         $err $this->_command($this->_getPath($path$name)$cmd);
  196.         if (is_a($err'PEAR_Error')) {
  197.             return false;
  198.         }
  199.         return true;
  200.     }
  201.  
  202.     /**
  203.      * Deletes a folder from the VFS.
  204.      *
  205.      * @param string $path        The path to delete the folder from.
  206.      * @param string $name        The name of the folder to delete.
  207.      * @param boolean $recursive  Force a recursive delete?
  208.      *
  209.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  210.      */
  211.     function deleteFolder($path$name$recursive = false)
  212.     {
  213.         // In some samba versions after samba-3.0.25-pre2, $path must
  214.         // end in a trailing slash.
  215.         if (substr($path-1!= '/'{
  216.             $path .= '/';
  217.         }
  218.  
  219.         if (!$this->isFolder($path$name)) {
  220.             return PEAR::raiseError(sprintf(_("\"%s\" is not a directory.")$path '/' $name));
  221.         }
  222.  
  223.         $file_list $this->listFolder($this->_getPath($path$name));
  224.         if (is_a($file_list'PEAR_Error')) {
  225.             return $file_list;
  226.         }
  227.  
  228.         if ($file_list && !$recursive{
  229.             return PEAR::raiseError(sprintf(_("Unable to delete \"%s\", the directory is not empty."),
  230.                                             $this->_getPath($path$name)));
  231.         }
  232.  
  233.         foreach ($file_list as $file{
  234.             if ($file['type'== '**dir'{
  235.                 $result $this->deleteFolder($this->_getPath($path$name)$file['name']$recursive);
  236.             else {
  237.                 $result $this->deleteFile($this->_getPath($path$name)$file['name']);
  238.             }
  239.             if (is_a($result'PEAR_Error')) {
  240.                 return $result;
  241.             }
  242.         }
  243.  
  244.         // Really delete the folder.
  245.         list($path$name$this->_escapeShellCommand($path$name);
  246.         $cmd = array('rmdir \"' $name '\"');
  247.         $err $this->_command($path$cmd);
  248.         if (is_a($err'PEAR_Error')) {
  249.             return PEAR::raiseError(sprintf(_("Unable to delete VFS folder \"%s\".")$this->_getPath($path$name)));
  250.         else {
  251.             return true;
  252.         }
  253.     }
  254.  
  255.     /**
  256.      * Renames a file in the VFS.
  257.      *
  258.      * @param string $oldpath  The old path to the file.
  259.      * @param string $oldname  The old filename.
  260.      * @param string $newpath  The new path of the file.
  261.      * @param string $newname  The new filename.
  262.      *
  263.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  264.      */
  265.     function rename($oldpath$oldname$newpath$newname)
  266.     {
  267.         if (is_a($result $this->autocreatePath($newpath)'PEAR_Error')) {
  268.             return $result;
  269.         }
  270.  
  271.         // Double quotes not allowed in SMB filename.
  272.         $newname str_replace('"'"'"$newname);
  273.  
  274.         list($file$name$this->_escapeShellCommand($oldname$newname);
  275.         $cmd = array('rename \"' .  str_replace('/''\\\\'$oldpath'\\' $file '\" \"' .
  276.                                     str_replace('/''\\\\'$newpath'\\' $name '\"');
  277.         if (is_a($err $this->_command(''$cmd)'PEAR_Error')) {
  278.             return PEAR::raiseError(sprintf(_("Unable to rename VFS file \"%s\".")$this->_getPath($path$name)));
  279.         }
  280.  
  281.         return true;
  282.     }
  283.  
  284.     /**
  285.      * Creates a folder on the VFS.
  286.      *
  287.      * @param string $path  The path of directory to create folder.
  288.      * @param string $name  The name of the new folder.
  289.      *
  290.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  291.      */
  292.     function createFolder($path$name)
  293.     {
  294.         // In some samba versions after samba-3.0.25-pre2, $path must
  295.         // end in a trailing slash.
  296.         if (substr($path-1!= '/'{
  297.             $path .= '/';
  298.         }
  299.  
  300.         // Double quotes not allowed in SMB filename.
  301.         $name str_replace('"'"'"$name);
  302.  
  303.         list($dir$mkdir$this->_escapeShellCommand($path$name);
  304.         $cmd = array('mkdir \"' $mkdir '\"');
  305.         $err $this->_command($dir$cmd);
  306.         if (is_a($err'PEAR_Error')) {
  307.             return PEAR::raiseError(sprintf(_("Unable to create VFS folder \"%s\".")$this->_getPath($path$name)));
  308.         }
  309.         return true;
  310.     }
  311.  
  312.     /**
  313.      * Returns an unsorted file list.
  314.      *
  315.      * @param string $path       The path of the directory to get the file list
  316.      *                            for.
  317.      * @param mixed $filter      Hash of items to filter based on filename.
  318.      * @param boolean $dotfiles  Show dotfiles? This is irrelevant with
  319.      *                            smbclient.
  320.      * @param boolean $dironly   Show directories only?
  321.      *
  322.      * @return boolean|PEAR_Error File list on success or a PEAR_Error on
  323.      *                              failure.
  324.      */
  325.     function listFolder($path ''$filter = null$dotfiles = true$dironly = false)
  326.     {
  327.         list($path$this->_escapeShellCommand($path);
  328.         $cmd = array('ls');
  329.         $res $this->_command($path$cmd);
  330.         if (is_a($res'PEAR_Error')) {
  331.             return $res;
  332.         }
  333.         $num_lines count($res);
  334.         $files = array();
  335.         for ($r = 0; $r $num_lines$r++{
  336.             // Match file listing.
  337.             if (preg_match('/^(\s\s.+\s{6,})/'$res[$r])) {
  338.                 // Split into columns at every six spaces
  339.                 $split1 preg_split('/\s{6,}/'trim($res[$r]));
  340.                 // If the file name isn't . or ..
  341.                 if ($split1[0!= '.' && $split1[0!= '..'{
  342.                     if (isset($split1[2])) {
  343.                         // If there is a small file size, inf could be split
  344.                         // into 3 cols.
  345.                         $split1[1.= ' ' $split1[2];
  346.                     }
  347.                     // Split file inf at every one or more spaces.
  348.                     $split2 preg_split('/\s+/'$split1[1]);
  349.                     if (is_numeric($split2[0])) {
  350.                         // If there is no file attr, shift cols over.
  351.                         array_unshift($split2'');
  352.                     }
  353.                     $my_name $split1[0];
  354.  
  355.                     // Filter out dotfiles if they aren't wanted.
  356.                     if (!$dotfiles && substr($my_name01== '.'{
  357.                         continue;
  358.                     }
  359.  
  360.                     $my_size $split2[1];
  361.                     $ext_name explode('.'$my_name);
  362.  
  363.                     if ((strpos($split2[0]'D'!== false)) {
  364.                         $my_type '**dir';
  365.                         $my_size = -1;
  366.                     else {
  367.                         $my_type VFS::strtolower($ext_name[count($ext_name- 1]);
  368.                     }
  369.                     $my_date strtotime($split2[4' ' $split2[3' ' .
  370.                                          $split2[6' ' $split2[5]);
  371.                     $filedata = array('owner' => '',
  372.                                       'group' => '',
  373.                                       'perms' => '',
  374.                                       'name' => $my_name,
  375.                                       'type' => $my_type,
  376.                                       'date' => $my_date,
  377.                                       'size' => $my_size);
  378.                     // watch for filters and dironly
  379.                     if ($this->_filterMatch($filter$my_name)) {
  380.                         unset($file);
  381.                         continue;
  382.                     }
  383.                     if ($dironly && $my_type !== '**dir'{
  384.                         unset($file);
  385.                         continue;
  386.                     }
  387.  
  388.                     $files[$filedata['name']] $filedata;
  389.                 }
  390.             }
  391.         }
  392.         return $files;
  393.     }
  394.  
  395.     /**
  396.      * Returns a sorted list of folders in specified directory.
  397.      *
  398.      * @param string $path         The path of the directory to get the
  399.      *                              directory list for.
  400.      * @param mixed $filter        Hash of items to filter based on folderlist.
  401.      * @param boolean $dotfolders  Include dotfolders? Irrelevant for SMB.
  402.      *
  403.      * @return boolean|PEAR_Error Folder list on success or a PEAR_Error on
  404.      *                              failure.
  405.      */
  406.     function listFolders($path ''$filter = null$dotfolders = true)
  407.     {
  408.         $folders = array();
  409.         $folder = array();
  410.  
  411.         $folderList $this->listFolder($pathnull$dotfolderstrue);
  412.         if (is_a($folderList'PEAR_Error')) {
  413.             return $folderList;
  414.         }
  415.  
  416.         // dirname will strip last component from path, even on a directory
  417.         $folder['val'dirname($path);
  418.         $folder['abbrev''..';
  419.         $folder['label''..';
  420.  
  421.         $folders[$folder['val']] $folder;
  422.  
  423.         foreach ($folderList as $files{
  424.             $folder['val'$this->_getPath($path$files['name']);
  425.             $folder['abbrev'$files['name'];
  426.             $folder['label'$folder['val'];
  427.  
  428.             $folders[$folder['val']] $folder;
  429.         }
  430.  
  431.         ksort($folders);
  432.         return $folders;
  433.     }
  434.  
  435.     /**
  436.      * Copies a file through the backend.
  437.      *
  438.      * @param string $path         The path to store the file in.
  439.      * @param string $name         The filename to use.
  440.      * @param string $dest         The destination of the file.
  441.      * @param boolean $autocreate  Automatically create directories?
  442.      *
  443.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  444.      */
  445.     function copy($path$name$dest$autocreate = false)
  446.     {
  447.         $orig $this->_getPath($path$name);
  448.         if (preg_match('|^' preg_quote($orig'/?$|'$dest)) {
  449.             return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
  450.         }
  451.  
  452.         if ($autocreate{
  453.             $result $this->autocreatePath($dest);
  454.             if (is_a($result'PEAR_Error')) {
  455.                 return $result;
  456.             }
  457.         }
  458.  
  459.         $fileCheck $this->listFolder($destnulltrue);
  460.         if (is_a($fileCheck'PEAR_Error')) {
  461.             return $fileCheck;
  462.         }
  463.         foreach ($fileCheck as $file{
  464.             if ($file['name'== $name{
  465.                 return PEAR::raiseError(sprintf(_("%s already exists."),
  466.                                                 $this->_getPath($dest$name)));
  467.             }
  468.         }
  469.  
  470.         if ($this->isFolder($path$name)) {
  471.             if (is_a($result $this->_copyRecursive($path$name$dest)'PEAR_Error')) {
  472.                 return $result;
  473.             }
  474.         else {
  475.             $tmpFile $this->_createTempFile($path$name);
  476.             if (is_a($tmpFile'PEAR_Error')) {
  477.                 return PEAR::raiseError(sprintf(_("Failed to retrieve: %s")$orig));
  478.             }
  479.  
  480.             $res $this->write($dest$name$tmpFile);
  481.             unlink($tmpFile);
  482.             if (is_a($res'PEAR_Error')) {
  483.                 return PEAR::raiseError(sprintf(_("Copy failed: %s"),
  484.                                                 $this->_getPath($dest$name)));
  485.             }
  486.         }
  487.  
  488.         return true;
  489.     }
  490.  
  491.     /**
  492.      * Moves a file through the backend.
  493.      *
  494.      * @param string $path         The path to store the file in.
  495.      * @param string $name         The filename to use.
  496.      * @param string $dest         The destination of the file.
  497.      * @param boolean $autocreate  Automatically create directories?
  498.      *
  499.      * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
  500.      */
  501.     function move($path$name$dest$autocreate = false)
  502.     {
  503.         $orig $this->_getPath($path$name);
  504.         if (preg_match('|^' preg_quote($orig'/?$|'$dest)) {
  505.             return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
  506.         }
  507.  
  508.         if ($autocreate{
  509.             $result $this->autocreatePath($dest);
  510.             if (is_a($result'PEAR_Error')) {
  511.                 return $result;
  512.             }
  513.         }
  514.  
  515.         $fileCheck $this->listFolder($destnulltrue);
  516.         if (is_a($fileCheck'PEAR_Error')) {
  517.             return $fileCheck;
  518.         }
  519.         foreach ($fileCheck as $file{
  520.             if ($file['name'== $name{
  521.                 return PEAR::raiseError(sprintf(_("%s already exists."),
  522.                                                 $this->_getPath($dest$name)));
  523.             }
  524.         }
  525.  
  526.         $err $this->rename($path$name$dest$name);
  527.         if (is_a($err'PEAR_Error')) {
  528.             return PEAR::raiseError(sprintf(_("Failed to move to \"%s\"."),
  529.                                             $this->_getPath($dest$name)));
  530.         }
  531.         return true;
  532.     }
  533.  
  534.     /**
  535.      * Replacement for escapeshellcmd(), variable length args, as we only want
  536.      * certain characters escaped.
  537.      *
  538.      * @access private
  539.      *
  540.      * @param array $array  Strings to escape.
  541.      *
  542.      * @return array 
  543.      */
  544.     function _escapeShellCommand()
  545.     {
  546.         $ret = array();
  547.         $args func_get_args();
  548.         foreach ($args as $arg{
  549.             $ret[str_replace(array(';''\\')array('\;''\\\\')$arg);
  550.         }
  551.         return $ret;
  552.     }
  553.  
  554.     /**
  555.      * Executes a command and returns output lines in array.
  556.      *
  557.      * @access private
  558.      *
  559.      * @param string $cmd  Command to be executed
  560.      *
  561.      * @return mixed  Array on success, false on failure.
  562.      */
  563.     function _execute($cmd)
  564.     {
  565.         $cmd str_replace('"-U%"''-N'$cmd);
  566.         exec($cmd$out$ret);
  567.  
  568.         // In some cases, (like trying to delete a nonexistant file),
  569.         // smbclient will return success (at least on 2.2.7 version I'm
  570.         // testing on). So try to match error strings, even after success.
  571.         if ($ret != 0{
  572.             $err '';
  573.             foreach ($out as $line{
  574.                 if (strpos($line'Usage:'=== 0{
  575.                     $err 'Command syntax incorrect';
  576.                     break;
  577.                 }
  578.                 if (strpos($line'ERRSRV'!== false ||
  579.                     strpos($line'ERRDOS'!== false{
  580.                     $err preg_replace('/.*\((.+)\).*/''\\1'$line);
  581.                     if (!$err{
  582.                         $err $line;
  583.                     }
  584.                     break;
  585.                 }
  586.             }
  587.             if (!$err{
  588.                 $err $out $out[count($out- 1$ret;
  589.             }
  590.             return PEAR::raiseError($err);
  591.         }
  592.  
  593.         // Check for errors even on success.
  594.         $err '';
  595.         foreach ($out as $line{
  596.             if (strpos($line'NT_STATUS_NO_SUCH_FILE'!== false ||
  597.                 strpos($line'NT_STATUS_OBJECT_NAME_NOT_FOUND'!== false{
  598.                 $err _("No such file");
  599.                 break;
  600.             elseif (strpos($line'NT_STATUS_ACCESS_DENIED'!== false{
  601.                 $err _("Permission Denied");
  602.                 break;
  603.             }
  604.         }
  605.  
  606.         if ($err{
  607.             return PEAR::raiseError($err);
  608.         }
  609.  
  610.         return $out;
  611.     }
  612.  
  613.     /**
  614.      * Executes SMB commands - without authentication - and returns output
  615.      * lines in array.
  616.      *
  617.      * @access private
  618.      *
  619.      * @param array $path  Base path for command.
  620.      * @param array $cmd   Commands to be executed.
  621.      *
  622.      * @return mixed  Array on success, false on failure.
  623.      */
  624.     function _command($path$cmd)
  625.     {
  626.         list($share$this->_escapeShellCommand($this->_params['share']);
  627.         putenv('PASSWD=' $this->_params['password']);
  628.         $ipoption (isset($this->_params['ipaddress'])) (' -I ' $this->_params['ipaddress']: null;
  629.         $fullcmd $this->_params['smbclient'.
  630.             ' "//' $this->_params['hostspec''/' $share '"' .
  631.             ' "-p' $this->_params['port''"' .
  632.             ' "-U' $this->_params['username''"' .
  633.             ' -D "' $path '" ' .
  634.             $ipoption .
  635.             ' -c "';
  636.         foreach ($cmd as $c{
  637.             $fullcmd .= $c ";";
  638.         }
  639.         $fullcmd .= '"';
  640.         return $this->_execute($fullcmd);
  641.     }
  642.  
  643.     /**
  644.      * Retrieves a file from the VFS and stores it to a temporary file.
  645.      *
  646.      * @access private
  647.      *
  648.      * @param string $path  The pathname to the file.
  649.      * @param string $name  The filename to retrieve.
  650.      *
  651.      * @return mixed  The temporary filename or a PEAR_Error on failure.
  652.      */
  653.     function _createTempFile($path$name)
  654.     {
  655.         list($path$name$this->_escapeShellCommand($path$name);
  656.         $temp $this->_getTempFile();
  657.         $cmd = array('get \"' $name '\" ' $temp);
  658.         $err $this->_command($path$cmd);
  659.         if (is_a($err'PEAR_Error')) {
  660.             return $err;
  661.         }
  662.         if (!file_exists($temp)) {
  663.             return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\".")$this->_getPath($path$name)));
  664.         }
  665.         return $temp;
  666.     }
  667.  
  668. }

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