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

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