4

I am trying to access a file in an SFTP folder server using phpseclib. But when I try using $sftp->get, it returns false. I am not sure how to debug the problem at all.

public function get_file_from_ftps_server()
{
    $sftp = new \phpseclib\Net\SFTP(getenv('INSTRUM_SERVER'));
    if (!$sftp->login(getenv('INSTRUM_USERNAME'), getenv('INSTRUM_PASSWORD'))) {
        exit('Login Failed');
    }

    $this->load->helper('file');           
    $root  = dirname(dirname(__FILE__));
    $root .= '/third_party/collections_get/';
    $path_to_server = 'testdownload/';
    $result = $sftp->get($path_to_server, $root);

    var_dump($result);
}

In the $result, I get a false and I am not sure why its happening, I read their documentation but still not sure. Root is the directory where I want my information to be stored. Right now I only added a trial.xml file there, but also wondering how can I get multiple files if its in the folder.

Here is a picture of the server structure:

structure

Christian
  • 27,509
  • 17
  • 111
  • 155
Masnad Nihit
  • 1,986
  • 2
  • 21
  • 40
  • If you want to download a _folder_ with phpseclib try the technique described at https://stackoverflow.com/a/36558913/569976 – neubert Nov 16 '17 at 17:53
  • @neubert thats a whole folder, why not just the file? – Masnad Nihit Nov 16 '17 at 18:47
  • As Martin Prikryl pointed out, your post makes it sound like you're asking about a folder. Anyway, it looks like Martin Prikryl is on the right track. – neubert Nov 16 '17 at 22:34

4 Answers4

3

Normally when I use sftp, I normally change directory and then try to download the information.

$sftp->pwd(); // This will show you are in the root after connection.
$sftp->chdir('./testdownload'); // this will go inside the test directory.
$get_path = $sftp->pwd()
//If you want to download multiple data, use
$x = $sftp->nlist();
//Loop through `x` and then download the file using.
$result = $sftp->get($get_path); // Normally I use the string information that is returned and then download using

file_put_contents($root, $result);

// Root is your directory, and result is the string.
XAF
  • 1,462
  • 1
  • 11
  • 22
  • how is this downloading the file to your local? aren't you just writing the content of a file from $get_path into string $result and then writing it into a file in the path $root? – Bahman.A May 10 '18 at 20:19
  • how is your `file_put_contents` working? isn't `($fileName, $result)`? – Drenyl Jun 29 '18 at 02:46
2

The Net_SFTP.get method can download a single file only. You cannot use it to download a whole directory.

If you want to download whole directory, you have to use one of the "list" methods (Net_SFTP.nlist or Net_SFTP.rawlist) to retrieve list of files and then download the files one-by-one.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • I could not even download one file in the start. I can try the list method afterwards, first I need to get 1 file. – Masnad Nihit Nov 16 '17 at 15:13
  • 1
    But your code cannot work. You cannot specify a path to a *folder* as `$remote_file` and `$local_file`. You have to use a path to a *file*: `$sftp->get("/testdownload/trial.xml", "/third_party/collections_get/trial.xml");` – Martin Prikryl Nov 16 '17 at 15:14
  • 1
    “Doesn’t work” doesn’t work as problem description. Show us a log file. – Martin Prikryl Nov 16 '17 at 21:04
  • Hi Martin sorry for the late reply, but when I try to var_dump( $result ) I only get true or false, how can I show you the log file? – Masnad Nihit Nov 17 '17 at 08:42
  • I made the edits to the code just like you said, it just returns a false in result. – Masnad Nihit Nov 17 '17 at 08:44
  • `echo $sftp->getSFTPLog();` (first hit in google for *“phpseclib logging”*) – Martin Prikryl Nov 17 '17 at 08:55
  • even the sftp->getSFTPLog() returns false. – Masnad Nihit Nov 17 '17 at 09:13
  • You have to put `define('NET_SFTP_LOGGING', NET_SFTP_LOG_COMPLEX);` before the `new`? – Martin Prikryl Nov 17 '17 at 09:41
  • This is what I get Array ( [0] => -> NET_SFTP_INIT (0.0007s) [1] => <- NET_SFTP_VERSION (0.0469s) [2] => -> NET_SFTP_REALPATH (0.0007s) [3] => <- NET_SFTP_NAME (0.0472s) [4] => -> NET_SFTP_OPEN (0.0007s) [5] => <- NET_SFTP_STATUS (0.0471s) ) – Masnad Nihit Nov 17 '17 at 11:40
  • What does `getLastSFTPError()` return? Are you using a correct path? Are you using the same credentials as in FileZilla? – Martin Prikryl Nov 17 '17 at 15:38
  • Do `define('NET_SFTP_LOGGING', SFTP::LOG_COMPLEX');`. `NET_SFTP_LOG_COMPLEX` is what you do for the 1.0 branch - not for the 2.0 branch. So do `SFTP::LOG_COMPLEX`, put the output on pastebin.com and post the link. – neubert Nov 17 '17 at 17:57
  • @Bahman That's too many questions to be answered in a comment. Post a separate question. – Martin Prikryl May 11 '18 at 05:56
0
<?php
use phpseclib\Net\SFTP;

$sftp = new SFTP("server");

if(!$sftp->login("username", "password")) {
    throw new Exception("Connection failed");
}

// The directory you want to download the contents of
$sftp->chdir("/remote/system/path/");

// Loop through each file and download
foreach($sftp->nlist() as $file) {
    if($file != "." && $file != "..")
        $sftp->get("/remote/system/path/$file", "/local/system/path/$file");
}
?>
c0nfus3d
  • 1,403
  • 3
  • 13
  • 25
0

I'm a bit late but nonetheless I wanted to share this. The approach I take is to use zip files to download folders. The reason for this is that you will have a feedback that something is being downloaded.

If you don't want that, simply remove the things related to zip. Then, remove the headers and replace them with $sftp->get("remote/file", "local/file");

<?PHP
use phpseclib\Net\SFTP;

$sftp = new SFTP("IP:Port");

if(!$sftp->login("username", "password")) throw new Exception("Connection failed");

# Create directory variable
$directory =  "/remote/path/";

# Set directory
$sftp->chdir($directory);

# File Name
$name =  'file';

# Retrieve file
$file = $sftp->get('file');

# Check if is folder
if ($sftp->is_dir($file)) {

  # Temporarily file
  $tmp = sys_get_temp_dir()."\\yourSite_".rand().".zip";

  # Create new Zip Archive.
  $zip = new ZipArchive();  

  # Open new Zip file
  $zip->open($tmp,  ZipArchive::CREATE | ZipArchive::OVERWRITE);

  function recursive($src, $zip, $sftp) {

    # Loop Through files
    foreach ($sftp->nlist($src) as $file) {

     # Skip . & ..
     if ($file == "." || $file == "..") continue;

     if (!$sftp->is_file($src . "/" . $file)) {

          # Make directory
          $zip->addEmptyDir($src . "/" . $file);

          # Run the loop again
          recursive($src . "/" . $file, $zip, $sftp);

        } else {
          # Add file to zip within folder
          $zip->addFromString($src . "/" . $file,  $sftp->get($src . "/" . $file));

      }

    }

  }

  # Run Recursive loop
  recursive($name, $zip, $sftp);

  # Close zip file
  $zip->close();

  header('Content-Description', 'File Transfer');
  header('Content-type', 'application/zip');
  header('Content-Disposition', 'attachment; filename="' . $name . '.zip"');
  header('Content-length', filesize($tmp));

  echo file_get_contents($tmp);

  # Delete temporarily file
  unlink($tmp);
  return;

}

# Otherwise download single file
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=\"". $name ."\"");

echo $file;
return;