How to modify PHP FTP upload script to download files instead - php

I have found a PHP script for transferring FTP files, and it works exactly as I need for one part of my project. The script can upload files via FTP to another server just fine, and can output the progress as it goes.
The code I am using is:
$fp = fopen($local_file, 'r');
$conn_id = ftp_connect($source_ftp_server);
$login_result = ftp_login($conn_id, $source_ftp_user_name, $source_ftp_user_pass);
$ret = ftp_nb_fput($conn_id, $remote_file, $fp, FTP_BINARY);
while ($ret == FTP_MOREDATA) {
// Establish a new connection to FTP server
if(!isset($conn_id2)) {
$conn_id2 = ftp_connect($source_ftp_server);
$login_result2 = ftp_login($conn_id2, $source_ftp_user_name, $source_ftp_user_pass);
}
// Retreive size of uploaded file.
if(isset($conn_id2)) {
clearstatcache(); // <- this must be included!!
$remote_file_size = ftp_size($conn_id2, $remote_file);
}
// Calculate upload progress
$local_file_size = filesize($local_file);
if (isset($remote_file_size) && $remote_file_size > 0 ){
$i = ($remote_file_size/$local_file_size)*100;
printf("%d%% uploaded<br>", $i);
flush();
}
$ret = ftp_nb_continue($conn_id);
}
if ($ret != FTP_FINISHED) {
echo "<span style='color:red;'><b>There was an error uploading the file...</b></span><br>";
exit(1);
}
else {
echo "<br>Files successfully uploaded!<br><br>";
}
fclose($fp);
I took out some unimportant parts, such as extra information that is echoed by the script, etc.
This code works perfectly for uploading files to the other server. However, I also need to download a file from the server using FTP as well.
I'd really like to use the same code as above, with the progress indicator, etc, but am not sure how to modify this code to download a file instead of uploading one.
It may be a couple of simple changes are all that is needed.
Are there any parts of this code in particular that will need to be changed, or can this not work the same for downloads as it does for uploads?
I'd really appreciate it if someone could point me in somewhat of the right direction to sort this out.
Is it as simple as changing the ftp_nb_fput command to a ftp_nb_get command? I don't really understand all of this code so it's difficult to tell what would need to be changed.
Thanks for your help.

You are looking for ftp_get
Looks like it should be used something like the following:
$conn_id = ftp_connect($source_ftp_server);
$login_result = ftp_login($conn_id, $source_ftp_user_name, $source_ftp_user_pass);
$success = ftp_get($conn_id, $local_file, $server_file, FTP_BINARY);
http://php.net/manual/en/function.ftp-get.php

Here's the script, with the necessary modifications to make it download a file instead:
$fp = fopen($local_file2, 'w+');
$conn_id = ftp_connect($source_ftp_server);
$login_result = ftp_login($conn_id, $source_ftp_user_name, $source_ftp_user_pass);
$ret = ftp_nb_fget($conn_id, $fp, $remote_file2, FTP_BINARY);
while ($ret == FTP_MOREDATA) {
// Establish a new connection to FTP server
if(!isset($conn_id2)) {
$conn_id2 = ftp_connect($source_ftp_server);
$login_result2 = ftp_login($conn_id2, $source_ftp_user_name, $source_ftp_user_pass);
}
// Retreive size of source file.
if(isset($conn_id2)) {
clearstatcache(); // <- this must be included!!
$remote_file2_size = ftp_size($conn_id2, $remote_file2);
}
// Calculate download progress
$local_file2_size = filesize($local_file2);
if (isset($remote_file2_size) && $remote_file2_size > 0 ){
$i = ($local_file2_size/$remote_file2_size)*100;
printf("%d%% downloaded<br>", $i);
}
$ret = ftp_nb_continue($conn_id);
}
if ($ret != FTP_FINISHED) {
echo "<span style='color:red;'><b>There was an error downloading the file...</b></span><br>";
exit(1);
}
echo "<br>Files successfully downloaded!<br><br>";
fclose($fp);

Related

PHP FTP Get the status when copying large files [duplicate]

I have a working FTP file download script.
The files I am downloading will be about 2-4 GB per day.
I was wondering if there was a way to get the percent of the file where it's at?
I have looked on php.net and on here but I couldn't find any similar questions and rather spend more time looking I figure I would ask people much smarter than myself.
I was thinking about if there was a function to see where it's at in the download, but I couldn't find one since ftp_get would have to complete first so that eliminated the chance of flushing the buffer every few seconds to display a new percent.
Anyone?
Here is my code: I hid all of my variables above it.
$conn_id = ftp_connect($ftp_server);
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
if (ftp_get($conn_id, $local_file, $server_file, FTP_BINARY)) {
echo "Successfully written to $local_file\n";
} else {
echo "There was a problem\n";
}
ftp_close($conn_id);
EDIT:
I added ftp_nb_get and here is my code for that. It keeps downloading fine, just doesn't echo it out to the browser.
$ret = ftp_nb_get($conn_id, $local_file, $server_file, FTP_BINARY, $size);
while ($ret == FTP_MOREDATA) {
echo round((filesize($local_file)/$server_size)*100)."%\n";
$ret = ftp_nb_continue($conn_id);
}
Try using the non-blocking version ftp_nb_get() and ftp_nb_continue() in a loop, and check for the saved file's size.
It can be implemented easily using FTP URL protocol wrappers:
$url = "ftp://username:password#ftp.example.com/remote/source/path/file.zip";
$size = filesize($url) or die("Cannot retrieve size file");
$hin = fopen($url, "rb") or die("Cannot open source file");
$hout = fopen("/local/dest/path/file.zip", "wb") or die("Cannot open destination file");
while (!feof($hin))
{
$buf = fread($hin, 10240);
fwrite($hout, $buf);
echo "\r".intval(ftell($hout)/$size*100)."%";
}
echo "\n";
fclose($hout);
fclose($hin);
Regarding your attempts using ftp_nb_get:
The filesize caches the results, so calling it repeatedly will get you the same value. You have to call clearstatcache.
A full code is like:
$conn_id = ftp_connect("ftp.example.com");
ftp_login($conn_id, "username", "password");
ftp_pasv($conn_id, true);
$local_path = "/local/dest/path/file.zip";
$remote_path = "/remote/source/path/file.zip";
$size = ftp_size($conn_id, $remote_path);
$ret = ftp_nb_get($conn_id, $local_path, $remote_path, FTP_BINARY);
while ($ret == FTP_MOREDATA)
{
clearstatcache(false, $local_path);
echo "\r".intval(filesize($local_path)/$size*100)."%";
$ret = ftp_nb_continue($conn_id);
}
echo "\n";
Alternatively use ftp_nb_fget and query the file handle, like my first example.
You should try buffer flush - ob_flush() and flush().
This technique works, I already used it.
here is a tutorial
I am sure that you can wind yourself some more.
Just google "progress php flush buffer"

PHP copy file from HTTP URL to FTP server

I have this link: http://gdlp01.c-wss.com/gds/6/0300002536/03/PSG11_CUG_EN_03.pdf and I want to copy this file to my FTP server. I tried:
$file = "http://gdlp01.c-wss.com/gds/6/0300002536/03/PSG11_CUG_EN_03.pdf";
$data = file_get_contents($url);
$ftp_server = "ftp_server";
$ftp_user = "ftp_user";
$ftp_pass = "ftp_pass";
$ftp = ftp_connect($ftp_server,21) or die("Couldn't connect to $ftp_server");
if (ftp_login($ftp, $ftp_user, $ftp_pass)) {
echo "Connecté en tant que $ftp_user#$ftp_server\n";
} else {
echo "Connexion impossible en tant que $ftp_user\n";
}
The connection was successful, but after that I do not know how to start.
You'll have to use ftp_fput, but I'm not sure if this function is able to handle an URL (I don't think so), so I decided to put your existing variable into the memory and to fake a file handler:
$tmpFile = fopen('php://memory', 'r+');
fputs($tmpFile, $data);
rewind($tmpFile);
if (ftp_fput($ftp, 'manual.pdf', $tmpFile, FTP_ASCII)) {
echo "worked";
} else {
echo "did not work";
}
If you have URL wrappers enabled, it's as easy as:
$file = "http://gdlp01.c-wss.com/gds/6/0300002536/03/PSG11_CUG_EN_03.pdf";
$ftp_server = "ftp_server";
$ftp_user = "ftp_user";
$ftp_pass = "ftp_pass";
copy($file, "ftp://$ftp_user:$ftp_pass#$ftp_server/PSG11_CUG_EN_03.pdf");
If you need a greater control over the writing (transfer mode, passive mode, offset, reading limit, etc), use the ftp_fput with a handle to the php://temp (or the php://memory) stream.
See Transfer in-memory data to FTP server without using intermediate file.

PHP - Export CSV to FTP rather than download in browser

I have been trying for a few hours now to no avail. I have successfully output my CSV as a download in the browser using:
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=".$csv_filename."");
However I want that output to now go to an FTP server instead, I have got the connection and temp file part sorted but cannot seem to edit the file to output my results.
// create empty variable to be filled with export data
$csv_export = '';
for($i = 0; $i < $field; $i++) {
$csv_export.= mysql_field_name($query,$i).',';
}
// newline (seems to work both on Linux & Windows servers)
$csv_export.= '
';
// loop through database query and fill export variable
while($row = mysql_fetch_array($query)) {
// create line with field values
for($i = 0; $i < $field; $i++) {
$csv_export.= '"'.$row[mysql_field_name($query,$i)].'",';
}
$csv_export.= '
';
}
Above is the part that gets the query data and puts it into the CSV, I have tried incorporating both fputs and fputcsv in the loops to write the rows to the file.
//Upload the temporary file to server
ftp_fput($ftpstream, '/httpdocs/.../abandoned.csv', $temp, FTP_ASCII);
$fp = fopen('var/www/vhosts/.../abandoned.csv', 'w');
fputs($fp, '$csv_export');
fclose($fp);
echo($csv_export);
So, echoing the output works absolutely fine - all I want is that echo'd data written into a CSV file and uploaded to the FTP.
The error I've been given is:
Array ( [type] => 2 [message] => fclose() expects parameter 1 to be resource,
boolean given
So the fp is causing the problem... is it at the open stage or at the writing of csv_export?
Thanks in advance.
Try this
//Write the contents to the temp file
fputs($temp, $csv_export);
//upload the temp file
ftp_fput($ftpstream, '/httpdocs/.../abandoned.csv', $temp, FTP_ASCII);
//close the temp file
fclose($temp);
Your current code is creating an empty file, uploading it, and then creating a separate file. Even if you get it working on a local server, it is an unnecessary step.
Try this, not tested:
$filename = 'abandoned.csv';
$content = $csv_export;
$host = 'yourhost';
$user = 'youruser';
$password = 'yourpass';
//open connection to your ftp server
$stream = stream_context_create(array('ftp' => array('overwrite' => true)));
//authenticate to your ftp server, normal uri syntax
$uri = sprintf('ftp://%s:%s#%s/%s', $user, $password, $host, $filename);
file_put_contents($uri, $content, 0, $stream);
In phpinfo(); you can look for Registered PHP Streams and just use this in most of any cases:
file_put_contents('ftp://user:password#server/your/directory/file.csv', $csvData);
ftp_fput is a right way here.
But you have to prepare FTP connection and authenticate first. Assuming you have $csv_export string in memory:
// connect
$ftp_conn = ftp_connect('ftp.yourserver.net');
// authenticate
$login_result = ftp_login($conn_id, 'ftp_username', 'password');
// prepare output stream
$stream = fopen('data://text/plain,' . $csv_export, 'r');
// try to upload
if (ftp_fput($ftp_conn, '/httpdocs/.../abandoned.csv', $stream, FTP_ASCII)) {
echo "Successfully uploaded\n";
} else {
echo "There was a problem while uploading\n";
}
// close the connection and the file handler
ftp_close($ftp_conn);
fclose($stream);
You're receiving that error because fopen is returning false, which indicates that it was unable to open the file.
If I'm understanding your code, you're uploading abandoned.csv (which presumably exists) to the ftp after opening it in $temp. Is $temp pointing at your local copy of abandon.csv? Because if so, you should close the file stream pointing to it before opening a second one with fopen.
If that's not the issue, then abandoned.csv may not actually exist, in which case you may just be trying to fopen a missing file.

PHP not writing to file from one source

I have an issue I can't seem to find the solution for. I am trying to write to a flat text file. I have echoed all variables out on the screen, verified permissions for the user (www-data) and just for grins set everything in the whole folder to 777 - all to no avail. Worst part is I can call on the same function from another file and it writes. I can't see to find the common thread here.....
function ReplaceAreaInFile($AreaStart, $AreaEnd, $File, $ReplaceWith){
$FileContents = GetFileAsString($File);
$Section = GetAreaFromFile($AreaStart, $AreaEnd, $FileContents, TRUE);
if(isset($Section)){
$SectionTop = $AreaStart."\n";
$SectionTop .= $ReplaceWith;
$NewContents = str_replace($Section, $SectionTop, $FileContents);
if (!$Handle = fopen($File, 'w')) {
return "Cannot open file ($File)";
exit;
}/*
if(!flock($Handle, LOCK_EX | LOCK_NB)) {
echo 'Unable to obtain file lock';
exit(-1);
}*/
if (fwrite($Handle, $NewContents) === FALSE) {
return "Cannot write to file ($File)";
exit;
}else{
return $NewContents;
}
}else{
return "<p align=\"center\">There was an issue saving your settings. Please try again. If the issue persists contact your provider.</p>";
}
}
Try with...
$Handle = fopen($File, 'w');
if ($Handle === false) {
die("Cannot open file ($File)");
}
$written = fwrite($Handle, $NewContents);
if ($written === false) {
die("Invalid arguments - could not write to file ($File)");
}
if ((strlen($NewContents) > 0) && ($written < strlen($NewContents))) {
die("There was a problem writing to $File - $written chars written");
}
fclose($Handle);
echo "Wrote $written bytes to $File\n"; // or log to a file
return $NewContents;
and also check for any problems in the error log. There should be something, assuming you've enabled error logging.
You need to check for number of characters written since in PHP fwrite behaves like this:
After having problems with fwrite() returning 0 in cases where one
would fully expect a return value of false, I took a look at the
source code for php's fwrite() itself. The function will only return
false if you pass in invalid arguments. Any other error, just as a
broken pipe or closed connection, will result in a return value of
less than strlen($string), in most cases 0.
Also, note that you might be writing to a file, but to a different file that you're expecting to write. Absolute paths might help with tracking this.
The final solution I ended up using for this:
function ReplaceAreaInFile($AreaStart, $AreaEnd, $File, $ReplaceWith){
$FileContents = GetFileAsString($File);
$Section = GetAreaFromFile($AreaStart, $AreaEnd, $FileContents, TRUE);
if(isset($Section)){
$SectionTop = $AreaStart."\n";
$SectionTop .= $ReplaceWith;
$NewContents = str_replace($Section, $SectionTop, $FileContents);
return $NewContents;
}else{
return "<p align=\"center\">There was an issue saving your settings.</p>";
}
}
function WriteNewConfigToFile($File2WriteName, $ContentsForFile){
file_put_contents($File2WriteName, $ContentsForFile, LOCK_EX);
}
I did end up using absolute file paths and had to check the permissions on the files. I had to make sure the www-data user in Apache was able to write to the files and was also the user running the script.

PHP Display a percentage of progress of ftp_get?

I have a working FTP file download script.
The files I am downloading will be about 2-4 GB per day.
I was wondering if there was a way to get the percent of the file where it's at?
I have looked on php.net and on here but I couldn't find any similar questions and rather spend more time looking I figure I would ask people much smarter than myself.
I was thinking about if there was a function to see where it's at in the download, but I couldn't find one since ftp_get would have to complete first so that eliminated the chance of flushing the buffer every few seconds to display a new percent.
Anyone?
Here is my code: I hid all of my variables above it.
$conn_id = ftp_connect($ftp_server);
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
if (ftp_get($conn_id, $local_file, $server_file, FTP_BINARY)) {
echo "Successfully written to $local_file\n";
} else {
echo "There was a problem\n";
}
ftp_close($conn_id);
EDIT:
I added ftp_nb_get and here is my code for that. It keeps downloading fine, just doesn't echo it out to the browser.
$ret = ftp_nb_get($conn_id, $local_file, $server_file, FTP_BINARY, $size);
while ($ret == FTP_MOREDATA) {
echo round((filesize($local_file)/$server_size)*100)."%\n";
$ret = ftp_nb_continue($conn_id);
}
Try using the non-blocking version ftp_nb_get() and ftp_nb_continue() in a loop, and check for the saved file's size.
It can be implemented easily using FTP URL protocol wrappers:
$url = "ftp://username:password#ftp.example.com/remote/source/path/file.zip";
$size = filesize($url) or die("Cannot retrieve size file");
$hin = fopen($url, "rb") or die("Cannot open source file");
$hout = fopen("/local/dest/path/file.zip", "wb") or die("Cannot open destination file");
while (!feof($hin))
{
$buf = fread($hin, 10240);
fwrite($hout, $buf);
echo "\r".intval(ftell($hout)/$size*100)."%";
}
echo "\n";
fclose($hout);
fclose($hin);
Regarding your attempts using ftp_nb_get:
The filesize caches the results, so calling it repeatedly will get you the same value. You have to call clearstatcache.
A full code is like:
$conn_id = ftp_connect("ftp.example.com");
ftp_login($conn_id, "username", "password");
ftp_pasv($conn_id, true);
$local_path = "/local/dest/path/file.zip";
$remote_path = "/remote/source/path/file.zip";
$size = ftp_size($conn_id, $remote_path);
$ret = ftp_nb_get($conn_id, $local_path, $remote_path, FTP_BINARY);
while ($ret == FTP_MOREDATA)
{
clearstatcache(false, $local_path);
echo "\r".intval(filesize($local_path)/$size*100)."%";
$ret = ftp_nb_continue($conn_id);
}
echo "\n";
Alternatively use ftp_nb_fget and query the file handle, like my first example.
You should try buffer flush - ob_flush() and flush().
This technique works, I already used it.
here is a tutorial
I am sure that you can wind yourself some more.
Just google "progress php flush buffer"

Categories