Download all contents from FTP server without time limit

Refresh

April 2019

Views

45 time

1

I want to download the contents (files, folders, and sub-folders) of a directory from a FTP server using PHP.

I was able to do it using this function:

function ftp_sync ($dir) { 

    global $conn_id; 

    if ($dir != ".") { 
        if (ftp_chdir($conn_id, $dir) == false) { 
            echo ("Change Dir Failed: $dir<BR>\r\n"); 
            return; 
        } 
        if (!(is_dir($dir))) 
            mkdir($dir); 
        chdir ($dir); 
    } 

    $contents = ftp_nlist($conn_id, "."); 
    foreach ($contents as $file) { 

        if ($file == '.' || $file == '..') 
            continue; 

        if (@ftp_chdir($conn_id, $file)) { 
            ftp_chdir ($conn_id, ".."); 
            ftp_sync ($file); 
        } 
        else 
            ftp_get($conn_id, $file, $file, FTP_BINARY); 
    } 

    ftp_chdir ($conn_id, ".."); 
    chdir (".."); 

}

Source: https://stackoverflow.com/a/5650503/10349407

But after some time; the script times out from the browser because it takes so long time as the contents of the folder are large.

I tried to set:

ini_set('max_execution_time', 0);
set_time_limit(0);

but I still get the error Warning: set_time_limit() has been disabled for security reasons as I am on a shared hosting.

So, my question: Is it possible to do redirects in the above PHP function so it starts a new page for each file that it downloads (this is my suggestion to prevent the timeout limit)

So a line like:

header("Location: " . __FILE__ . "?file=$file");

where it should download the file which is the value of $_GET['file'] then redirect again and so on until it finishes downloading the whole contents.

EDIT: This is my try but it doesn't work :/

function ftp_sync ($dir) { 

    global $conn_id; 

    if( isset($_GET['cd']) ) {
        $dir = $_GET['cd'];
    }

    if ($dir != ".") { 
        if (ftp_chdir($conn_id, $dir) == false) { 
            echo ("Change Dir Failed: $dir<BR>\r\n"); 
            return; 
        } 
        if (!(is_dir($dir))) 
            mkdir($dir); 
        chdir ($dir); 
    } 

    $contents = ftp_nlist($conn_id, "."); 
    foreach ($contents as $file) { 

        if ($file == '.' || $file == '..') 
            continue; 

        if (@ftp_chdir($conn_id, $file)) { 
            ftp_chdir ($conn_id, ".."); 
            ftp_sync ($file); 
            header("refresh:0.5;url=" . "ftp.php" . "?file=$file&cd=" . ftp_pwd($conn_id));
            die();
        } 
        else {
            ftp_get($conn_id, $file, $file, FTP_BINARY); 
        }
    } 

    ftp_chdir ($conn_id, ".."); 
    chdir (".."); 

} 

1 answers

4

I finally did it on my own!

All what I needed was a way to list ALL the contents of the FTP server recursively (files, directories, sub-directories).

And I found this awesome class: https://www.phpclasses.org/package/7707-PHP-List-recursively-all-files-in-a-FTP-server.html

So, all what you've to do is to download this class and write this script which I've spent hours on (although it is simple xD).

<?php
error_reporting(0);
set_time_limit(0);
session_start();

// SETTINGS
$ftp_hostname = "";
$ftp_port = 21;
$ftp_username = "";
$ftp_password = "";
$where_to_download = "."; // Without the last slash!
// ---------------------

// NOTE: If you want to end the current session; go to http://example.com/filename.php?end

if( isset($_GET['end']) ) {
    session_unset();
    session_destroy();
    die("Successfully ended the session.");
}

include("ftpcrawler.php");
$ftpcrawler = new ftpcrawler;
$ftpcrawler->server = "ftp://$ftp_username:[email protected]$ftp_hostname:$ftp_port/";
if( !isset($_SESSION['array']) ) {
    $_SESSION['array'] = $ftpcrawler->crawl();
}
if( empty($_SESSION['array']) ) {
    echo "Finished downloading everything , or theres no files to download.";
    session_unset();
    session_destroy();
    die();
}
foreach($_SESSION['array'] as $item) {
    if( $item['type'] == "file" ) {
        $ITEM_DIRECTORY = str_replace($item['name'], "", $item['path']);
    }
    if( $item['type'] == "directory" ) {
        $ITEM_DIRECTORY = $item['path'];
    }
    if (!file_exists($where_to_download . $ITEM_DIRECTORY) && !is_dir($where_to_download . $ITEM_DIRECTORY)) {
        mkdir($where_to_download . $ITEM_DIRECTORY, 0777, TRUE);         
    }
    if( $item['type'] == "file" ) {
        $data = @file_get_contents("ftp://$ftp_username:[email protected]$ftp_hostname:$ftp_port" . $item['path']);
        file_put_contents($where_to_download . $item['path'], $data);
    }
    unset($_SESSION['array'][$item['path']]); // Remove the item from the array.
    echo "Downloaded/Created Folder " . $item['path'] . " !";
    header( "refresh:0.2;url=" . basename(__FILE__) );
    die();
}
?>

Save the file with the name you need and make sure that ftpcrawler.php is in the same directory of the script.