PHP - SSH2 SFTP Downloads With Progress
Asked Answered
G

2

7

I feel this deserves a question as StackOverflow doesn't seem to have enough on the subject.

I want to SFTP, using PHP with a Progress Bar

I love progress bars. However, this time I want to do something a little different. I want to do the following with PHP, and this one looks a lot harder than the last:

  • Perform downloads via SFTP (over SSH?)
  • Give the user a visible indication of download progress
  • Enable the pausing and continuing of downloads

Think FileZilla, but in-browser, built with PHP. I don't want to hack Apache or add any Apache mods.


Options for the actual download

There are plenty of questions here, here, here and here for the basic SFTP download.

These document PHP's SSH2 extension (which I am using at the moment - you install this via pecl) and the alternative PHPSecLib, which I'm not using, but may look into later.
My interface allows swapping in/out easily - coding to the interface rather than the implementation etc...

That's great, but they just perform the actual download and that's it.

The download progress

PHP has a really interesting callback called stream_notification_callback, which you can read more about here.

This looks great, and was a promising step until someone looked into the source code of PHP and found that, unfortunately, SSH2 / SFTP doesn't allow integration with this.
Thanks to hek2mgl for putting in the effort to research this.

The idea with stream_notification_callback was to pass a notification of the current download size every time data is retrieved; therefore giving the data required to calculate a percentage using the currently downloaded amount and the total file size. But that doesn't go with SSH2 and SFTP...

And what about the pausing / continuing?

In my opinion, this would be the hardest to accomplish. Downloading data to a temporary file would be possible... Here's what I managed to dig up: http://ee.php.net/manual/en/function.fread.php#84115 - But integrating that sort of code with the progress bar seems crazy.

Finally

There's also cURL, however I didn't see the pausing / resuming of downloads as possible with this over SFTP. Correct me if I'm wrong.

So, how would I go about integration of the aforementioned requirements in-browser using PHP? Forget the client-side stuff, just getting the data to the browser is enough, so recommendations to perform this would be great.

Graybill answered 27/3, 2013 at 16:34 Comment(2)
Research! It has research!Bitterling
I think that you may be able to do what you need by using the OS built in sftp client (or another one by your choice) with verbose enabled into a log which you read by php, it would not be a full php solution to your problem but simple, slick and pretty easyGatekeeper
D
2

Here is a sample I took from this site:

    // Write from our remote stream to our local stream
    $read = 0;
    $fileSize = filesize("ssh2.sftp://$sftp/$fileName");
    while ($read < $fileSize && ($buffer = fread($remoteStream, $fileSize - $read))) {
        // Increase our bytes read
        $read += strlen($buffer);

        // Write to our local file
        if (fwrite($localStream, $buffer) === FALSE) {
            throw new Exception("Unable to write to local file: /localdir/$fileName");
        }
    }

Since you have the size of the file and you read from it with fread it is trivial to determine your progress.

Pausing can be done by checking a value from lets say APC that you set if user clicks on the Pause button (do this in an iframe so you do not stop the main script).

Descend answered 9/9, 2013 at 1:55 Comment(0)
B
1

Check out Server fails when downloading large files with PHP . Might give you some ideas.

Summing it up... one of the answers suggests modifying phpseclib to echo out data everytime a chunk is received. Another answer proposes just downloading in chunks and outputting the chunks as they're download.

Seems like that's pretty in-line with your idea of using stream_notification_callback.

Good luck!

Botnick answered 27/3, 2013 at 19:25 Comment(1)
I have thought about reading-in data in small amounts relative to the total file size, thus giving an approximate percentage. This may also allow pausing / continuing. I'll look into it, thanks!Graybill

© 2022 - 2024 — McMap. All rights reserved.