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

Source for file ssh2.php

Documentation is available at ssh2.php

  1. <?php
  2. /**
  3.  * VFS implementation for an SSH2 server.
  4.  * This module requires the SSH2 (version 0.10+) PECL package.
  5.  *
  6.  * Required values for $params:<pre>
  7.  *      'username'       The username with which to connect to the ssh2 server.
  8.  *      'password'       The password with which to connect to the ssh2 server.
  9.  *      'hostspec'       The ssh2 server to connect to.</pre>
  10.  *
  11.  * Optional values for $params:<pre>
  12.  *      'port'           The port used to connect to the ssh2 server if other
  13.  *                       than 22.</pre>
  14.  *
  15.  * $Horde: framework/VFS/lib/VFS/ssh2.php,v 1.1.2.15 2009/10/15 17:18:48 jan Exp $
  16.  *
  17.  * Copyright 2006-2009 The Horde Project (http://www.horde.org/)
  18.  *
  19.  * See the enclosed file COPYING for license information (LGPL). If you
  20.  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  21.  *
  22.  * @editor  Cliff Green <green@umdnj.edu>
  23.  * @since   Horde 3.2
  24.  * @package VFS
  25.  */
  26. class VFS_ssh2 extends VFS {
  27.  
  28.     /**
  29.      * List of additional credentials required for this VFS backend.
  30.      *
  31.      * @var array 
  32.      */
  33.     var $_credentials = array('username''password');
  34.  
  35.     /**
  36.      * List of permissions and if they can be changed in this VFS backend.
  37.      *
  38.      * @var array 
  39.      */
  40.     var $_permissions = array(
  41.         'owner' => array('read' => true'write' => true'execute' => true),
  42.         'group' => array('read' => true'write' => true'execute' => true),
  43.         'all'   => array('read' => true'write' => true'execute' => true));
  44.  
  45.     /**
  46.      * Variable holding the connection to the ssh2 server.
  47.      *
  48.      * @var resource 
  49.      */
  50.     var $_stream = false;
  51.  
  52.     /**
  53.      * The SFTP resource stream.
  54.      *
  55.      * @var resource 
  56.      */
  57.     var $_sftp;
  58.  
  59.     /**
  60.      * The current working directory.
  61.      *
  62.      * @var string 
  63.      */
  64.     var $_cwd;
  65.  
  66.     /**
  67.      * Local cache array for user IDs.
  68.      *
  69.      * @var array 
  70.      */
  71.     var $_uids = array();
  72.  
  73.     /**
  74.      * Local cache array for group IDs.
  75.      *
  76.      * @var array 
  77.      */
  78.     var $_gids = array();
  79.  
  80.     /**
  81.      * Returns the size of a file.
  82.      *
  83.      * @access public
  84.      *
  85.      * @param string $path  The path of the file.
  86.      * @param string $name  The filename.
  87.      *
  88.      * @return integer  The size of the file in bytes or PEAR_Error on
  89.      *                   failure.
  90.      */
  91.     function size($path$name)
  92.     {
  93.         $conn $this->_connect();
  94.         if (is_a($conn'PEAR_Error')) {
  95.             return $conn;
  96.         }
  97.  
  98.         $statinfo @ssh2_sftp_stat($this->_sftp$this->_getPath($path$name));
  99.         if (($size $statinfo['size']=== false{
  100.             return PEAR::raiseError(sprintf(_("Unable to check file size of \"%s\".")$this->_getPath($path$name)));
  101.         }
  102.  
  103.         return $size;
  104.     }
  105.  
  106.     /**
  107.      * Retrieves a file from the VFS.
  108.      *
  109.      * @param string $path  The pathname to the file.
  110.      * @param string $name  The filename to retrieve.
  111.      *
  112.      * @return string  The file data.
  113.      */
  114.     function read($path$name)
  115.     {
  116.         $file $this->readFile($path$name);
  117.         if (is_a($file'PEAR_Error')) {
  118.             return $file;
  119.         }
  120.  
  121.         $size filesize($file);
  122.         if ($size === 0{
  123.             return '';
  124.         }
  125.  
  126.         return file_get_contents($file);
  127.     }
  128.  
  129.     /**
  130.      * Retrieves a file from the VFS as an on-disk local file.
  131.      *
  132.      * This function provides a file on local disk with the data of a VFS file
  133.      * in it. This file <em>cannot</em> be modified! The behavior if you do
  134.      * modify it is undefined. It will be removed at the end of the request.
  135.      *
  136.      * @param string $path  The pathname to the file.
  137.      * @param string $name  The filename to retrieve.
  138.      *
  139.      * @return string A local filename.
  140.      */
  141.     function readFile($path$name)
  142.     {
  143.         $result $this->_connect();
  144.         if (is_a($result'PEAR_Error')) {
  145.             return $result;
  146.         }
  147.  
  148.         // Create a temporary file and register it for deletion at the
  149.         // end of this request.
  150.         $localFile $this->_getTempFile();
  151.         if (!$localFile{
  152.             return PEAR::raiseError(_("Unable to create temporary file."));
  153.         }
  154.         register_shutdown_function(create_function('''unlink(\'' addslashes($localFile'\');'));
  155.  
  156.         if (!$this->_recv($this->_getPath($path$name)$localFile)) {
  157.             return PEAR::raiseError(sprintf(_("Unable to open VFS file \"%s\".")$this->_getPath($path$name)));
  158.         }
  159.  
  160.         return $localFile;
  161.     }
  162.  
  163.     /**
  164.      * Open a stream to a file in the VFS.
  165.      *
  166.      * @param string $path  The pathname to the file.
  167.      * @param string $name  The filename to retrieve.
  168.      *
  169.      * @return resource  The stream.
  170.      */
  171.     function readStream($path$name)
  172.     {
  173.         $file $this->readFile($path$name);
  174.         if (is_a($file'PEAR_Error')) {
  175.             return $file;
  176.         }
  177.  
  178.         $mode = OS_WINDOWS ? 'rb' 'r';
  179.         return fopen($file$mode);
  180.     }
  181.  
  182.     /**
  183.      * Stores a file in the VFS.
  184.      *
  185.      * @param string $path         The path to store the file in.
  186.      * @param string $name         The filename to use.
  187.      * @param string $tmpFile      The temporary file containing the data to
  188.      *                              be stored.
  189.      * @param boolean $autocreate  Automatically create directories?
  190.      *
  191.      * @return mixed  True on success or a PEAR_Error object on failure.
  192.      */
  193.     function write($path$name$tmpFile$autocreate = false)
  194.     {
  195.         $conn $this->_connect();
  196.         if (is_a($conn'PEAR_Error')) {
  197.             return $conn;
  198.         }
  199.  
  200.         $res $this->_checkQuotaWrite('file'$tmpFile);
  201.         if (is_a($res'PEAR_Error')) {
  202.             return $res;
  203.         }
  204.  
  205.         if (!$this->_send($tmpFile$this->_getPath($path$name)))  {
  206.             if ($autocreate{
  207.                 $result $this->autocreatePath($path);
  208.                 if (is_a($result'PEAR_Error')) {
  209.                     return $result;
  210.                 }
  211.                 if (!$this->_send($tmpFile$this->_getPath($path$name))) {
  212.                     return PEAR::raiseError(sprintf(_("Unable to write VFS file \"%s\".")$this->_getPath($path$name)));
  213.                 }
  214.             else {
  215.                 return PEAR::raiseError(sprintf(_("Unable to write VFS file \"%s\".")$this->_getPath($path$name)));
  216.             }
  217.         }
  218.  
  219.         return true;
  220.     }
  221.  
  222.     /**
  223.      * Stores a file in the VFS from raw data.
  224.      *
  225.      * @param string $path         The path to store the file in.
  226.      * @param string $name         The filename to use.
  227.      * @param string $data         The file data.
  228.      * @param boolean $autocreate  Automatically create directories?
  229.      *
  230.      * @return mixed  True on success or a PEAR_Error object on failure.
  231.      */
  232.     function writeData($path$name$data$autocreate = false)
  233.     {
  234.         $res $this->_checkQuotaWrite('string'$data);
  235.         if (is_a($res'PEAR_Error')) {
  236.             return $res;
  237.         }
  238.  
  239.         $tmpFile $this->_getTempFile();
  240.         if (function_exists('file_put_contents')) {
  241.             file_put_contents($tmpFile$data);
  242.         else {
  243.             $fp fopen($tmpFile'wb');
  244.             fwrite($fp$data);
  245.             fclose($fp);
  246.         }
  247.  
  248.         $result $this->write($path$name$tmpFile$autocreate);
  249.         unlink($tmpFile);
  250.         return $result;
  251.     }
  252.  
  253.     /**
  254.      * Deletes a file from the VFS.
  255.      *
  256.      * @param string $path  The path to delete the file from.
  257.      * @param string $name  The filename to delete.
  258.      *
  259.      * @return mixed  True on success or a PEAR_Error object on failure.
  260.      */
  261.     function deleteFile($path$name)
  262.     {
  263.         $res $this->_checkQuotaDelete($path$name);
  264.         if (is_a($res'PEAR_Error')) {
  265.             return $res;
  266.         }
  267.  
  268.         $conn $this->_connect();
  269.         if (is_a($conn'PEAR_Error')) {
  270.             return $conn;
  271.         }
  272.  
  273.         if (!@ssh2_sftp_unlink($this->_sftp$this->_getPath($path$name))) {
  274.             return PEAR::raiseError(sprintf(_("Unable to delete VFS file \"%s\".")$this->_getPath($path$name)));
  275.         }
  276.  
  277.         return true;
  278.     }
  279.  
  280.     /**
  281.      * Checks if a given item is a folder.
  282.      *
  283.      * @param string $path  The parent folder.
  284.      * @param string $name  The item name.
  285.      *
  286.      * @return boolean  True if it is a folder, false otherwise.
  287.      */
  288.     function isFolder($path$name)
  289.     {
  290.         $conn $this->_connect();
  291.         if (is_a($conn'PEAR_Error')) {
  292.             return $conn;
  293.         }
  294.  
  295.         /* See if we can stat the remote filename. ANDed with 040000 is true
  296.          * if it is a directory. */
  297.         $statinfo @ssh2_sftp_stat($this->_sftp$this->_getPath($path$name));
  298.         return $statinfo['mode'040000;
  299.     }
  300.  
  301.     /**
  302.      * Deletes a folder from the VFS.
  303.      *
  304.      * @param string $path        The parent folder.
  305.      * @param string $name        The name of the folder to delete.
  306.      * @param boolean $recursive  Force a recursive delete?
  307.      *
  308.      * @return mixed  True on success or a PEAR_Error object on failure.
  309.      */
  310.     function deleteFolder($path$name$recursive = false)
  311.     {
  312.         $conn $this->_connect();
  313.         if (is_a($conn'PEAR_Error')) {
  314.             return $conn;
  315.         }
  316.  
  317.         $isDir = false;
  318.         $dirCheck $this->listFolder($path);
  319.         foreach ($dirCheck as $file{
  320.             if ($file['name'== $name && $file['type'== '**dir'{
  321.                 $isDir = true;
  322.                 break;
  323.             }
  324.         }
  325.  
  326.         if ($isDir{
  327.             $file_list $this->listFolder($this->_getPath($path$name));
  328.             if (is_a($file_list'PEAR_Error')) {
  329.                 return $file_list;
  330.             }
  331.  
  332.             if (count($file_list&& !$recursive{
  333.                 return PEAR::raiseError(sprintf(_("Unable to delete \"%s\", the directory is not empty."),
  334.                                                 $this->_getPath($path$name)));
  335.             }
  336.             foreach ($file_list as $file{
  337.                 if ($file['type'== '**dir'{
  338.                     $result $this->deleteFolder($this->_getPath($path$name)$file['name']$recursive);
  339.                 else {
  340.                     $result $this->deleteFile($this->_getPath($path$name)$file['name']);
  341.                 }
  342.                 if (is_a($result'PEAR_Error')) {
  343.                     return $result;
  344.                 }
  345.             }
  346.  
  347.             if (!@ssh2_sftp_rmdir($this->_sftp$this->_getPath($path$name))) {
  348.                 return PEAR::raiseError(sprintf(_("Cannot remove directory \"%s\".")$this->_getPath($path$name)));
  349.             }
  350.         else {
  351.             if (!@ssh2_sftp_unlink($this->_sftp$this->_getPath($path$name))) {
  352.                 return PEAR::raiseError(sprintf(_("Cannot delete file \"%s\".")$this->_getPath($path$name)));
  353.             }
  354.         }
  355.  
  356.         return true;
  357.     }
  358.  
  359.     /**
  360.      * Renames a file in the VFS.
  361.      *
  362.      * @param string $oldpath  The old path to the file.
  363.      * @param string $oldname  The old filename.
  364.      * @param string $newpath  The new path of the file.
  365.      * @param string $newname  The new filename.
  366.      *
  367.      * @return mixed  True on success or a PEAR_Error object on failure.
  368.      */
  369.     function rename($oldpath$oldname$newpath$newname)
  370.     {
  371.         $conn $this->_connect();
  372.         if (is_a($conn'PEAR_Error')) {
  373.             return $conn;
  374.         }
  375.  
  376.         if (is_a($res $this->autocreatePath($newpath)'PEAR_Error')) {
  377.             return $res;
  378.         }
  379.  
  380.         if (!@ssh2_sftp_rename($this->_sftp$this->_getPath($oldpath$oldname)$this->_getPath($newpath$newname))) {
  381.             return PEAR::raiseError(sprintf(_("Unable to rename VFS file \"%s\".")$this->_getPath($oldpath$oldname)));
  382.         }
  383.  
  384.         return true;
  385.     }
  386.  
  387.     /**
  388.      * Creates a folder on the VFS.
  389.      *
  390.      * @param string $path  The parent folder.
  391.      * @param string $name  The name of the new folder.
  392.      *
  393.      * @return mixed  True on success or a PEAR_Error object on failure.
  394.      */
  395.     function createFolder($path$name)
  396.     {
  397.         $conn $this->_connect();
  398.         if (is_a($conn'PEAR_Error')) {
  399.             return $conn;
  400.         }
  401.  
  402.         if (!@ssh2_sftp_mkdir($this->_sftp$this->_getPath($path$name))) {
  403.             return PEAR::raiseError(sprintf(_("Unable to create VFS directory \"%s\".")$this->_getPath($path$name)));
  404.         }
  405.  
  406.         return true;
  407.     }
  408.  
  409.     /**
  410.      * Changes permissions for an item on the VFS.
  411.      *
  412.      * @param string $path        The parent folder of the item.
  413.      * @param string $name        The name of the item.
  414.      * @param string $permission  The permission to set.
  415.      *
  416.      * @return mixed  True on success or a PEAR_Error object on failure.
  417.      */
  418.     function changePermissions($path$name$permission)
  419.     {
  420.         $conn $this->_connect();
  421.         if (is_a($conn'PEAR_Error')) {
  422.             return $conn;
  423.         }
  424.  
  425.         if (!@ssh2_exec($this->_stream'chmod ' escapeshellarg($permission' ' escapeshellarg($this->_getPath($path$name)))) {
  426.             return PEAR::raiseError(sprintf(_("Unable to change permission for VFS file \"%s\".")$this->_getPath($path$name)));
  427.         }
  428.  
  429.         return true;
  430.     }
  431.  
  432.     /**
  433.      * Returns an an unsorted file list of the specified directory.
  434.      *
  435.      * @param string $path       The path of the directory.
  436.      * @param mixed $filter      String/hash to filter file/dirname on.
  437.      * @param boolean $dotfiles  Show dotfiles?
  438.      * @param boolean $dironly   Show only directories?
  439.      *
  440.      * @return array  File list on success or PEAR_Error on failure.
  441.      */
  442.     function _listFolder($path ''$filter = null$dotfiles = true,
  443.                          $dironly = false)
  444.     {
  445.         $conn $this->_connect();
  446.         if (is_a($conn'PEAR_Error')) {
  447.             return $conn;
  448.         }
  449.  
  450.         $files = array();
  451.  
  452.         /* If 'maplocalids' is set, check for the POSIX extension. */
  453.         $mapids = false;
  454.         if (!empty($this->_params['maplocalids']&&
  455.             extension_loaded('posix')) {
  456.             $mapids = true;
  457.         }
  458.  
  459.         // THIS IS A PROBLEM....  there is no builtin systype() fn for SSH2.
  460.         // Go with unix-style listings for now...
  461.         $type 'unix';
  462.  
  463.         $olddir $this->getCurrentDirectory();
  464.         if (strlen($path)) {
  465.             $res $this->_setPath($path);
  466.             if (is_a($res'PEAR_Error')) {
  467.                 return $res;
  468.             }
  469.         }
  470.  
  471.         if ($type == 'unix'{
  472.             $ls_args 'l';
  473.  
  474.             // Get numeric ids if we're going to use posix_* functions to
  475.             // map them.
  476.             if ($mapids{
  477.                 $ls_args .= 'n';
  478.             }
  479.  
  480.             // If we don't want dotfiles, We can save work here by not doing
  481.             // an ls -a and then not doing the check later (by setting
  482.             // $dotfiles to true, the if is short-circuited).
  483.             if ($dotfiles{
  484.                 $ls_args .= 'a';
  485.                 $dotfiles = true;
  486.             }
  487.  
  488.             $stream @ssh2_exec($this->_stream'LC_TIME=C ls -' $ls_args ' ' escapeshellarg($path));
  489.         else {
  490.             $stream @ssh2_exec($this->_stream'');
  491.         }
  492.  
  493.         stream_set_blocking($streamtrue);
  494.         unset($list);
  495.         while (!feof($stream)) {
  496.             $line fgets($stream);
  497.             if ($line === false{
  498.                 break;
  499.             }
  500.             $list[trim($line);
  501.         }
  502.         fclose($stream);
  503.  
  504.         if (!is_array($list)) {
  505.             if (isset($olddir)) {
  506.                 $res $this->_setPath($olddir);
  507.                 if (is_a($res'PEAR_Error')) {
  508.                     return $res;
  509.                 }
  510.             }
  511.             return array();
  512.         }
  513.  
  514.         $currtime time();
  515.  
  516.         foreach ($list as $line{
  517.             $file = array();
  518.             $item preg_split('/\s+/'$line);
  519.             if (($type == 'unix'||
  520.                 (($type == 'win'&&
  521.                  !preg_match('|\d\d-\d\d-\d\d|'$item[0]))) {
  522.                 if ((count($item< 8|| (substr($line05== 'total')) {
  523.                     continue;
  524.                 }
  525.                 $file['perms'$item[0];
  526.                 if ($mapids{
  527.                     if (!isset($this->_uids[$item[2]])) {
  528.                         $entry posix_getpwuid($item[2]);
  529.                         $this->_uids[$item[2]] (empty($entry)) $item[2$entry['name'];
  530.                     }
  531.                     $file['owner'$this->_uids[$item[2]];
  532.                     if (!isset($this->_uids[$item[3]])) {
  533.                         $entry posix_getgrgid($item[3]);
  534.                         $this->_uids[$item[3]] (empty($entry)) $item[3$entry['name'];
  535.                     }
  536.                     $file['group'$this->_uids[$item[3]];
  537.  
  538.                 else {
  539.                     $file['owner'$item[2];
  540.                     $file['group'$item[3];
  541.                 }
  542.                 $file['name'substr($linestrpos($linesprintf("%s %2s %5s"$item[5]$item[6]$item[7])) + 13);
  543.  
  544.                 // Filter out '.' and '..' entries.
  545.                 if (preg_match('/^\.\.?\/?$/'$file['name'])) {
  546.                     continue;
  547.                 }
  548.  
  549.                 // Filter out dotfiles if they aren't wanted.
  550.                 if (!$dotfiles && (substr($file['name']01== '.')) {
  551.                     continue;
  552.                 }
  553.  
  554.                 $p1 substr($file['perms']01);
  555.                 if ($p1 === 'l'{
  556.                     $file['link'substr($file['name']strpos($file['name']'->'+ 3);
  557.                     $file['name'substr($file['name']0strpos($file['name']'->'- 1);
  558.                     $file['type''**sym';
  559.  
  560.                    if ($this->isFolder(''$file['link'])) {
  561.                        $file['linktype''**dir';
  562.                    else {
  563.                        $parts explode('/'$file['link']);
  564.                        $name explode('.'array_pop($parts));
  565.                        if ((count($name== 1||
  566.                            (($name[0=== ''&& (count($name== 2))) {
  567.                            $file['linktype''**none';
  568.                        else {
  569.                            $file['linktype'VFS::strtolower(array_pop($name));
  570.                        }
  571.                    }
  572.                 elseif ($p1 === 'd'{
  573.                     $file['type''**dir';
  574.                 else {
  575.                     $name explode('.'$file['name']);
  576.                     if ((count($name== 1||
  577.                         ((substr($file['name']01=== '.'&&
  578.                          (count($name== 2))) {
  579.                         $file['type''**none';
  580.                     else {
  581.                         $file['type'VFS::strtolower($name[count($name- 1]);
  582.                     }
  583.                 }
  584.                 if ($file['type'== '**dir'{
  585.                     $file['size'= -1;
  586.                 else {
  587.                     $file['size'$item[4];
  588.                 }
  589.                 if (strpos($item[7]':'!== false{
  590.                     $file['date'strtotime($item[7':00' $item[5' ' $item[6' ' date('Y'$currtime));
  591.                     // If the ssh2 server reports a file modification date more
  592.                     // less than one day in the future, don't try to subtract
  593.                     // a year from the date.  There is no way to know, for
  594.                     // example, if the VFS server and the ssh2 server reside
  595.                     // in different timezones.  We should simply report to the
  596.                     //  user what the SSH2 server is returning.
  597.                     if ($file['date'($currtime + 86400)) {
  598.                         $file['date'strtotime($item[7':00' $item[5' ' $item[6' ' (date('Y'$currtime- 1));
  599.                     }
  600.                 else {
  601.                     $file['date'strtotime('00:00:00' $item[5' ' $item[6' ' $item[7]);
  602.                 }
  603.             elseif ($type == 'netware'{
  604.                 $file = Array();
  605.                 $file['perms'$item[1];
  606.                 $file['owner'$item[2];
  607.                 if ($item[0== 'd'{
  608.                     $file['type''**dir';
  609.                 else {
  610.                     $file['type''**none';
  611.                 }
  612.                 $file['size'$item[3];
  613.                 $file['name'$item[7];
  614.                 $index = 8;
  615.                 while ($index count($item)) {
  616.                     $file['name'.= ' ' $item[$index];
  617.                     $index++;
  618.                 }
  619.             else {
  620.                 /* Handle Windows SSH2 servers returning DOS-style file
  621.                  * listings. */
  622.                 $file['perms''';
  623.                 $file['owner''';
  624.                 $file['group''';
  625.                 $file['name'$item[3];
  626.                 $index = 4;
  627.                 while ($index count($item)) {
  628.                     $file['name'.= ' ' $item[$index];
  629.                     $index++;
  630.                 }
  631.                 $file['date'strtotime($item[0' ' $item[1]);
  632.                 if ($item[2== '<DIR>'{
  633.                     $file['type''**dir';
  634.                     $file['size'= -1;
  635.                 else {
  636.                     $file['size'$item[2];
  637.                     $name explode('.'$file['name']);
  638.                     if ((count($name== 1||
  639.                         ((substr($file['name']01=== '.'&&
  640.                          (count($name== 2))) {
  641.                         $file['type''**none';
  642.                     else {
  643.                         $file['type'VFS::strtolower($name[count($name- 1]);
  644.                     }
  645.                 }
  646.             }
  647.  
  648.             // Filtering.
  649.             if ($this->_filterMatch($filter$file['name'])) {
  650.                 unset($file);
  651.                 continue;
  652.             }
  653.             if ($dironly && $file['type'!== '**dir'{
  654.                 unset($file);
  655.                 continue;
  656.             }
  657.  
  658.             $files[$file['name']] $file;
  659.             unset($file);
  660.         }
  661.  
  662.         if (isset($olddir)) {
  663.             $res $this->_setPath($olddir);
  664.             if (is_a($res'PEAR_Error')) {
  665.                 return $res;
  666.             }
  667.         }
  668.  
  669.         return $files;
  670.     }
  671.  
  672.     /**
  673.      * Returns a sorted list of folders in the specified directory.
  674.      *
  675.      * @param string $path         The path of the directory to get the
  676.      *                              directory list for.
  677.      * @param mixed $filter        Hash of items to filter based on folderlist.
  678.      * @param boolean $dotfolders  Include dotfolders?
  679.      *
  680.      * @return mixed  Folder list on success or a PEAR_Error object on failure.
  681.      */
  682.     function listFolders($path ''$filter = null$dotfolders = true)
  683.     {
  684.         $conn $this->_connect();
  685.         if (is_a($conn'PEAR_Error')) {
  686.             return $conn;
  687.         }
  688.  
  689.         $folders = array();
  690.         $folder = array();
  691.  
  692.         $folderList $this->listFolder($pathnull$dotfolderstrue);
  693.         if (is_a($folderList'PEAR_Error')) {
  694.             return $folderList;
  695.         }
  696.  
  697.         $folder['val'$this->_parentDir($path);
  698.         $folder['abbrev'$folder['label''..';
  699.  
  700.         $folders[$folder['val']] $folder;
  701.  
  702.         foreach ($folderList as $files{
  703.             $folder['val'$this->_getPath($path$files['name']);
  704.             $folder['abbrev'$files['name'];
  705.             $folder['label'$folder['val'];
  706.  
  707.             $folders[$folder['val']] $folder;
  708.         }
  709.  
  710.         ksort($folders);
  711.         return $folders;
  712.     }
  713.  
  714.     /**
  715.      * Copies a file through the backend.
  716.      *
  717.      * @param string $path         The path of the original file.
  718.      * @param string $name         The name of the original file.
  719.      * @param string $dest         The name of the destination directory.
  720.      * @param boolean $autocreate  Auto-create the directory if it doesn't
  721.      *                              exist?
  722.      *
  723.      * @return mixed  True on success or a PEAR_Error object on failure.
  724.      */
  725.     function copy($path$name$dest$autocreate = false)
  726.     {
  727.         $orig $this->_getPath($path$name);
  728.         if (preg_match('|^' preg_quote($orig'/?$|'$dest)) {
  729.             return PEAR::raiseError(_("Cannot copy file(s) - source and destination are the same."));
  730.         }
  731.  
  732.         $conn $this->_connect();
  733.         if (is_a($conn'PEAR_Error')) {
  734.             return $conn;
  735.         }
  736.  
  737.         if ($autocreate{
  738.             $res $this->autocreatePath($dest);
  739.             if (is_a($res'PEAR_Error')) {
  740.                 return $res;
  741.             }
  742.         }
  743.         $fileCheck $this->listFolder($destnulltrue);
  744.         if (is_a($fileCheck'PEAR_Error')) {
  745.             return $fileCheck;
  746.         }
  747.  
  748.         foreach ($fileCheck as $file{
  749.             if ($file['name'== $name{
  750.                 return PEAR::raiseError(sprintf(_("%s already exists.")$this->_getPath($dest$name)));
  751.             }
  752.         }
  753.  
  754.         if ($this->isFolder($path$name)) {
  755.             $result $this->_copyRecursive($path$name$dest);
  756.             if (is_a($result'PEAR_Error')) {
  757.                 return $result;
  758.             }
  759.         else {
  760.             $tmpFile $this->_getTempFile();
  761.             $fetch $this->_recv($orig$tmpFile);
  762.             if (!$fetch{
  763.                 unlink($tmpFile);
  764.                 return PEAR::raiseError(sprintf(_("Failed to copy from \"%s\".")$orig));
  765.             }
  766.  
  767.             $res $this->_checkQuotaWrite('file'$tmpFile);
  768.             if (is_a($res'PEAR_Error')) {
  769.                 return $res;
  770.             }
  771.  
  772.             if (!$this->_send($tmpFile$this->_getPath($dest$name))) {
  773.                 unlink($tmpFile);
  774.                 return PEAR::raiseError(sprintf(_("Failed to copy to \"%s\".")$this->_getPath($dest$name)));
  775.             }
  776.  
  777.             unlink($tmpFile);
  778.         }
  779.  
  780.         return true;
  781.     }
  782.  
  783.     /**
  784.      * Moves a file through the backend.
  785.      *
  786.      * @param string $path         The path of the original file.
  787.      * @param string $name         The name of the original file.
  788.      * @param string $dest         The destination file name.
  789.      * @param boolean $autocreate  Auto-create the directory if it doesn't
  790.      *                              exist?
  791.      *
  792.      * @return mixed  True on success or a PEAR_Error object on failure.
  793.      */
  794.     function move($path$name$dest$autocreate = false)
  795.     {
  796.         $orig $this->_getPath($path$name);
  797.         if (preg_match('|^' preg_quote($orig'/?$|'$dest)) {
  798.             return PEAR::raiseError(_("Cannot move file(s) - destination is within source."));
  799.         }
  800.  
  801.         $conn $this->_connect();
  802.         if (is_a($conn'PEAR_Error')) {
  803.             return $conn;
  804.         }
  805.  
  806.         if ($autocreate{
  807.             $res $this->autocreatePath($dest);
  808.             if (is_a($res'PEAR_Error')) {
  809.                 return $res;
  810.             }
  811.         }
  812.  
  813.         $fileCheck $this->listFolder($destnulltrue);
  814.         if (is_a($fileCheck'PEAR_Error')) {
  815.             return $fileCheck;
  816.         }
  817.  
  818.         foreach ($fileCheck as $file{
  819.             if ($file['name'== $name{
  820.                 return PEAR::raiseError(sprintf(_("%s already exists.")$this->_getPath($dest$name)));
  821.             }
  822.         }
  823.  
  824.         if (!@ssh2_sftp_rename($this->_sftp$orig$this->_getPath($dest$name))) {
  825.             return PEAR::raiseError(sprintf(_("Failed to move to \"%s\".")$this->_getPath($dest$name)));
  826.         }
  827.  
  828.         return true;
  829.     }
  830.  
  831.     /**
  832.      * Returns the current working directory on the SSH2 server.
  833.      *
  834.      * @return string  The current working directory.
  835.      */
  836.     function getCurrentDirectory()
  837.     {
  838.         if (is_a($res $this->_connect()'PEAR_Error')) {
  839.             return $res;
  840.         }
  841.         if (!strlen($this->_cwd)) {
  842.             $stream @ssh2_exec($this->_stream'pwd');
  843.             stream_set_blocking($streamtrue);
  844.             $this->_cwd trim(fgets($stream));
  845.         }
  846.         return $this->_cwd;
  847.     }
  848.  
  849.     /**
  850.      * Changes the current directory on the server.
  851.      *
  852.      * @access private
  853.      *
  854.      * @param string $path  The path to change to.
  855.      *
  856.      * @return boolean  True on success, or a PEAR_Error on failure.
  857.      */
  858.     function _setPath($path)
  859.     {
  860.         if ($stream @ssh2_exec($this->_stream'cd ' escapeshellarg($path'; pwd')) {
  861.             stream_set_blocking($streamtrue);
  862.             $this->_cwd trim(fgets($stream));
  863.             fclose($stream);
  864.             return true;
  865.         else {
  866.             return PEAR::raiseError(sprintf(_("Unable to change to %s.")$path));
  867.         }
  868.     }
  869.  
  870.     /**
  871.      * Returns the full path of an item.
  872.      *
  873.      * @access private
  874.      *
  875.      * @param string $path  The directory of the item.
  876.      * @param string $name  The name of the item.
  877.      *
  878.      * @return mixed  Full path to the file when $path is not empty and just
  879.      *                 $name when not set.
  880.      */
  881.     function _getPath($path$name)
  882.     {
  883.         if ($path !== ''{
  884.             return ($path '/' $name);
  885.         }
  886.         return $name;
  887.     }
  888.  
  889.     /**
  890.      * Returns the parent directory of the specified path.
  891.      *
  892.      * @access private
  893.      *
  894.      * @param string $path  The path to get the parent of.
  895.      *
  896.      * @return string  The parent directory (string) on success or a PEAR_Error
  897.      *                  object on failure.
  898.      */
  899.     function _parentDir($path)
  900.     {
  901.         $conn $this->_connect();
  902.         if (is_a($conn'PEAR_Error')) {
  903.             return $conn;
  904.         }
  905.  
  906.         $this->_setPath('cd ' $path '/..');
  907.         return $this->getCurrentDirectory();
  908.     }
  909.  
  910.     /**
  911.      * Attempts to open a connection to the SSH2 server.
  912.      *
  913.      * @access private
  914.      *
  915.      * @return mixed  True on success or a PEAR_Error object on failure.
  916.      */
  917.     function _connect()
  918.     {
  919.         if ($this->_stream === false{
  920.             if (!extension_loaded('ssh2')) {
  921.                 return PEAR::raiseError(_("The SSH2 PECL extension is not available."));
  922.             }
  923.  
  924.             if (!is_array($this->_params)) {
  925.                 return PEAR::raiseError(_("No configuration information specified for SSH2 VFS."));
  926.             }
  927.  
  928.             $required = array('hostspec''username''password');
  929.             foreach ($required as $val{
  930.                 if (!isset($this->_params[$val])) {
  931.                     return PEAR::raiseError(sprintf(_("Required \"%s\" not specified in VFS configuration.")$val));
  932.                 }
  933.             }
  934.  
  935.             /* Connect to the ssh2 server using the supplied parameters. */
  936.             if (empty($this->_params['port'])) {
  937.                 $this->_stream @ssh2_connect($this->_params['hostspec']);
  938.             else {
  939.                 $this->_stream @ssh2_connect($this->_params['hostspec']$this->_params['port']);
  940.             }
  941.             if (!$this->_stream{
  942.                 return PEAR::raiseError(_("Connection to SSH2 server failed."));
  943.             }
  944.  
  945.             $connected @ssh2_auth_password($this->_stream$this->_params['username']$this->_params['password']);
  946.             if (!$connected{
  947.                 $this->_stream = false;
  948.                 return PEAR::raiseError(_("Authentication to SSH2 server failed."));
  949.             }
  950.  
  951.             /* Create sftp resource. */
  952.             $this->_sftp @ssh2_sftp($this->_stream);
  953.         }
  954.  
  955.         return true;
  956.     }
  957.  
  958.     /**
  959.      * Sends local file to remote host.
  960.      * This function exists because the php_scp_* functions doesn't seem to work on some hosts.
  961.      *
  962.      * @access private
  963.      *
  964.      * @param string $local   Full path to the local file.
  965.      * @param string $remote  Full path to the remote location.
  966.      *
  967.      * @return boolean TRUE on success, FALSE on failure.
  968.      */
  969.     function _send($local$remote)
  970.     {
  971.         return @copy($local$this->_wrap($remote));
  972.     }
  973.  
  974.     /**
  975.      * Receives file from remote host.
  976.      * This function exists because the php_scp_* functions doesn't seem to work on some hosts.
  977.      *
  978.      * @access private
  979.      *
  980.      * @param string $local  Full path to the local file.
  981.      * @param string $remote Full path to the remote location.
  982.      *
  983.      * @return boolean TRUE on success, FALSE on failure.
  984.      */
  985.     function _recv($remote$local)
  986.     {
  987.         return @copy($this->_wrap($remote)$local);
  988.     }
  989.  
  990.     /**
  991.      * Generate a stream wrapper file spec for a remote file path
  992.      *
  993.      * @access private
  994.      *
  995.      * @param string $remote  Full path to the remote location
  996.      *
  997.      * @return string  A full stream wrapper path to the remote location
  998.      */
  999.     function _wrap($remote)
  1000.     {
  1001.         return 'ssh2.sftp://' $this->_params['username'':' $this->_params['password']
  1002.             . '@' $this->_params['hostspec'':' $this->_params['port'$remote;
  1003.     }
  1004.  
  1005. }

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