PHP ftp_put fails randomly - php

When moving our site to a new host we went from PHP5 (I think) to PHP7. We also added SSL to the site for the first time. Ever since moving the site a function to copy image files to an FTP has been failing randomly.
After doing some research I learned that there is no way to get an error message more detailed that "ftp_put has failed".
$dir = 'path/to/folder';
$a = scandir($dir);
$ftp_server = "ftp.server.com";
$ftp_conn = ftp_connect($ftp_server);
$ftp_username = 'myuser';
$ftp_userpass = 'mypass';
$login = ftp_login($ftp_conn, $ftp_username, $ftp_userpass);
ftp_pasv($ftp_conn, true);
foreach ($a as $value) {
if(strlen($value) > 4){
$file = $dir.$value;
$name = $value;
if (ftp_put($ftp_conn, $name, $file, FTP_BINARY)){
echo "<br><br><span style='color: green'>Successfully uploaded $file.</span><br><br>";
}
else{
echo "<br><br><span style='color: green'>Error uploading $file.</span><br><br>";
}
}
}
The output from the code above is:
Successfully uploaded ../../img/bil/AAA123/AAA123-1.jpg.
Successfully uploaded ../../img/bil/AAA123/AAA123-2.jpg.
Successfully uploaded ../../img/bil/AAA123/AAA123-3.jpg.
Error uploading ../../img/bil/AAA123/AAA123-4.jpg.
Error uploading ../../img/bil/AAA123/AAA123-5.jpg.
Successfully uploaded ../../img/bil/AAA123/AAA123-6.jpg.
Error uploading ../../img/bil/AAA123/AAA123-7.jpg.
Successfully uploaded ../../img/bil/AAA123/AAA123-8.jpg.
This output differs, running it again will successfully upload other images and fail other.
I have tried stripping down the code, removing the scandir and foreach parts and using a direct path to one image file as $file with the same result.
I have no idea what could be wrong. I suspect moving to PHP7 and possibly SSL is the problem since this all started then. Not being able to get a detailed error message why ftp_put fails leaves me completely stuck.
Is there anything I can do to find out whats wrong?
edit:
Adding error_reporting(-1) and printing out error_get_last() gives me this:
Array (
[type] => 2
[message] => ftp_put(): Type set to I
[file] => path/to/file.php
[line] => 51
)

Any network communication can fail.
Uploading a large number of files without zipping them up first via FTP is a good way to ensure some of your uploads will fail. If you don't want to zip them up into a single request than a good alternative is to retry failed responses, adding a delay between retries but don't make an infinite loop. Retry 3 times and if it still fails than your problem is much bigger than minor network issues or FTP server bugs and you are better off skipping the file and trying the next. Also don't forget to close any connection you open.
$dir = 'path/to/folder';
$a = scandir($dir);
foreach ($a as $value) {
if(strlen($value) > 4){
for($retry = 0; $retry < 3; $retry++) {
$ftp_server = "ftp.server.com";
$ftp_conn = ftp_connect($ftp_server);
$ftp_username = 'myuser';
$ftp_userpass = 'mypass';
$login = ftp_login($ftp_conn, $ftp_username, $ftp_userpass);
ftp_pasv($ftp_conn, true);
$file = $dir.$value;
$name = $value;
if (ftp_put($ftp_conn, $name, $file, FTP_BINARY)){
echo "<br><br><span style='color: green'>Successfully uploaded $file.</span><br><br>";
break;
} else {
if ($retry < 2) {
echo "<br><br><span style='color: green'>Error uploading $file Will retry....</span><br><br>";
sleep(2);
} else {
echo "<br><br><span style='color: green'>Error uploading $file.</span><br><br>";
}
}
ftp_close($ftp_conn);
}
}
}

Related

PHP script saves empty image files when run as cron job

I have a script that downloads images from the external server and saves them in a folder at the root of the website. The script file is also in the root of the website.
folder for images: /public_html/images/
script: /public_html/script.php
When i run file manually (example.com/script.php) all downloaded image files are saved in the folder correctly. But when the file is executed by the cron job all the images are saved with sizes of 0 bytes.
I've tried to empty the folder before the cron job run. I've changed the permissions to 777. Log file when the script runs manually and as cron looks the same.
The cron job is set up in the cpanel crontab.
Please help me figure out what is going on.
$dir = "/home/example/public_html/images/";
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') continue;
unlink($dir.DIRECTORY_SEPARATOR.$item);
}
$ftp_server = 'www2.housescape.org.uk';
$ftp_conn = ftp_connect($ftp_server);
$ftp_user = 'user';
$ftp_pass = 'password';
ftp_set_option($ftp_conn, FTP_TIMEOUT_SEC, 3600);
if(ftp_login($ftp_conn, $ftp_user, $ftp_pass)){
ftp_pasv($ftp_conn, true);
$images = ftp_nlist($ftp_conn, '/images/');
$c = 0;
foreach($images as $image){
$c = $c + 1;
echo "ftp://user:password#www2.housescape.org.uk:21".$image." / ";
$urltoget="ftp://user:password#www2.housescape.org.uk:21".$image;
echo $thefile=basename($image);
echo "<br>";
$content = file_get_contents("ftp://user:password#www2.housescape.org.uk:21".$image);
file_put_contents("/home/example/public_html/images/".$thefile, $content);
}
if ($count1>0) { echo "No File Change"; }
ftp_close($ftp_conn);
}
else{
echo 'Failed Login!';
}
This is only a suggestion to help track down the error, not an answer:
Did you check whether the CRON PHP environment has allow_url_fopen enabled?
<?php
if (!ini_get('allow_url_fopen')) {
die("'allow_url_fopen' is not enabled in the php.ini");
}

ftp_put(): Opening data channel for file upload to server of "/xxx.txt"

I am working on to upload the file to FTP using PHP FTP. while putting the file to the server, its throw error.
what I did:
$ftp_conn = ftp_connect(SAP_SERVER_HOST, SAP_SERVER_PORT, 60);
if (!ftp_login($ftp_conn, SAP_SERVER_USER, SAP_SERVER_PASSWORD)) {
echo 'not connected<br/>';
} else {
$localfile = '/abc/txt/15375127769260.txt';
$serverfile = '/folder/15375127769260.txt';
// echo ftp_pwd($ftp_conn);
if (ftp_put($ftp_conn, $serverfile, $localfile, FTP_BINARY)) {
echo "Successfully uploaded $localfile.";
} else {
echo "Error uploading $localfile.";
}
// close connection
ftp_close($ftp_conn);
}
Suggest Me, what I miss in this code.
For anyone stumbling upon this:
my file was sent correctly after adding ftp_pasv($conn_id, true);
Note that it must be added after ftp_login().
ftp-pasv on php.net
are you using right folders and ports ?
$ftp_conn = ftp_connect(SAP_SERVER_HOST, SAP_SERVER_PORT, 60);
it should be port 21
and in local file you must get get the realpath of the file whit realpath() function
and for remote server the path is based on ftp base folder
Take a look of realpath http://php.net/manual/pt_BR/function.realpath.php

How to check if files exists on a folder? [duplicate]

How can I check if a specific file exists on a remote server using PHP via FTP connections?
Some suggestions:
Use ftp_size, which returns -1 if it doesn't exist: http://www.php.net/manual/en/function.ftp-size.php
Use fopen, e.g. fopen("ftp://user:password#example.com/somefile.txt", "r")
Use ftp_nlist, check to see if the filename you want is in the list: http://www.php.net/manual/en/function.ftp-nlist.php
I used this, a bit easier:
// the server you wish to connect to - you can also use the server ip ex. 107.23.17.20
$ftp_server = "ftp.example.com";
// set up a connection to the server we chose or die and show an error
$conn_id = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");
ftp_login($conn_id,"ftpserver_username","ftpserver_password");
// check if a file exist
$path = "/SERVER_FOLDER/"; //the path where the file is located
$file = "file.html"; //the file you are looking for
$check_file_exist = $path.$file; //combine string for easy use
$contents_on_server = ftp_nlist($conn_id, $path); //Returns an array of filenames from the specified directory on success or FALSE on error.
// Test if file is in the ftp_nlist array
if (in_array($check_file_exist, $contents_on_server))
{
echo "<br>";
echo "I found ".$check_file_exist." in directory : ".$path;
}
else
{
echo "<br>";
echo $check_file_exist." not found in directory : ".$path;
};
// output $contents_on_server, shows all the files it found, helps for debugging, you can use print_r() as well
var_dump($contents_on_server);
// remember to always close your ftp connection
ftp_close($conn_id);
Functions used: (thanks to middaparka)
Login using ftp_connect
Get the remote file list via ftp_nlist
Use in_array to see if the file was present in the array
Just check the size of a file. If the size is -1, it doesn't exist, so:
$file_size = ftp_size($ftp_connection, "example.txt");
if ($file_size != -1) {
echo "File exists";
} else {
echo "File does not exist";
}
If the size is 0, the file does exist, it's just 0 bytes.
Source
A general solution would be to:
Login using ftp_connect
Navigate to the relevant directory via ftp_chdir
Get the remote file list via ftp_nlist or ftp_rawlist
Use in_array to see if the file was present in the array returned by ftp_rawlist
That said, you could potentially simply use file_exists if you have the relevant URL wrappers available. (See the PHP FTP and FTPS protocols and wrappers manual page for more information.)
This is an optimization of #JohanPretorius solution, and an answer for comments about "slow and inefficient for large dirs" of #Andrew and other: if you need more than one "file_exist checking", this function is a optimal solution.
ftp_file_exists() caching last folder
function ftp_file_exists(
$file, // the file that you looking for
$path = "SERVER_FOLDER", // the remote folder where it is
$ftp_server = "ftp.example.com", //Server to connect to
$ftp_user = "ftpserver_username", //Server username
$ftp_pwd = "ftpserver_password", //Server password
$useCache = 1 // ALERT: do not $useCache when changing the remote folder $path.
){
static $cache_ftp_nlist = array();
static $cache_signature = '';
$new_signature = "$ftp_server/$path";
if(!$useCache || $new_signature!=$cache_signature)
{
$useCache = 0;
//$new_signature = $cache_signature;
$cache_signature = $new_signature;
// setup the connection
$conn_id = ftp_connect($ftp_server) or die("Error connecting $ftp_server");
$ftp_login = ftp_login($conn_id, $ftp_user, $ftp_pwd);
$cache_ftp_nlist = ftp_nlist($conn_id, $path);
if ($cache_ftp_nlist===FALSE)die("erro no ftp_nlist");
}
//$check_file_exist = "$path/$file";
$check_file_exist = "$file";
if(in_array($check_file_exist, $cache_ftp_nlist))
{
echo "Found: ".$check_file_exist." in folder: ".$path;
}
else
{
echo "Not Found: ".$check_file_exist." in folder: ".$path;
};
// use for debuging: var_dump($cache_ftp_nlist);
if(!$useCache) ftp_close($conn_id);
} //function end
//Output messages
echo ftp_file_exists("file1-to-find.ext"); // do FTP
echo ftp_file_exists("file2-to-find.ext"); // using cache
echo ftp_file_exists("file3-to-find.ext"); // using cache
echo ftp_file_exists("file-to-find.ext","OTHER_FOLDER"); // do FTP
You can use ftp_nlist to list all the files on the remote server. Then you should search into the result array to check if the file what you was looking for exists.
http://www.php.net/manual/en/function.ftp-nlist.php
The code has been written by: #Drmzindec should be change a little:
if (in_array($check_file_exist, $contents_on_server))
to
if (in_array($file, $contents_on_server))

I am not able to trasfer file and folder from one server to another server

Please find the following code. In addition to this I forget to state that I am actually running this script on magento web store but it doesn't matter since I am getting all things okay except file transfer.
<?php
require_once('app/Mage.php');
Mage::app();
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('*');
$array1=array();
$array2=array();
echo $destination_dir = dirname(__FILE__);
$remote_file = '/B303501/_Datenblatt.pdf';
$ftp_server = "*******";
$ftp_user = "************";
$ftp_pass = "******";
$local_file = '/E212002M';
$conn_id = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");
foreach ($products as $product) {
array_push($array1,$product->getData("sku"));
array_push($array2,$product->getData("image"));
}
// try to login
if (#ftp_login($conn_id, $ftp_user, $ftp_pass)) {
//echo "Connected as $ftp_user#$ftp_server";
ftp_pasv($conn_id, true);
if(!#copy('/B303501/_Datenblatt.pdf','/media/catalog/product/demo/'))
{
$errors= error_get_last();
echo "COPY ERROR: ".$errors['type'];
echo "<br />\n".$errors['message'];
} else {
echo "File copied from remote!";
}
$i = 0;
$contents = ftp_nlist($conn_id, ".");
foreach ($contents as $cont) {
if(in_array($cont,$array1)){
echo $cont. "</br>";
$buff = ftp_rawlist($conn_id, '/'.$cont.'/');
echo "<pre>";
print_r($buff);
echo "</pre>";
$tobecopied = 'http://www.example.com/index.html';
$target = $destination_dir . '/media/catalog/product/demo/';
foreach($buff as $key){
if(!#copy('/'.$cont.'/'.$key,'/media/catalog/product/demo/'))
{
$errors= error_get_last();
echo "COPY ERROR: ".$errors['type'];
echo "<br />\n".$errors['message'];
} else {
echo "File copied from remote!";
}
}
$i++;
}
}
} else {
echo "Couldn't connect as $ftp_user\n";
}
I am getting following error while file transfer from one server to another server.
I have both live server and I am also get logged-in successfully but can't figure out what's happening while file transfer.
The following is the error.
/var/www/clients/client348/web979/web
COPY ERROR: 2
copy(/B303501/_Datenblatt.pdf): failed to open stream: No such file or directoryB303501
Any help would be highly appreciate.
Let me know if you need any further information regarding above.
Thanks
I think you should use ftp_get not copy. Also make sure that directory hierarchy exists at your destination because either ftp_get nor copy won't create missing directories for you.
I finally sort it out issue. The ftp you I am using is just normal ftp but In order to loggedin into another server you need SFTP credentials except this all above is in working mode.
Thanks for your support

How can I check if a file exists on a remote server using PHP?

How can I check if a specific file exists on a remote server using PHP via FTP connections?
Some suggestions:
Use ftp_size, which returns -1 if it doesn't exist: http://www.php.net/manual/en/function.ftp-size.php
Use fopen, e.g. fopen("ftp://user:password#example.com/somefile.txt", "r")
Use ftp_nlist, check to see if the filename you want is in the list: http://www.php.net/manual/en/function.ftp-nlist.php
I used this, a bit easier:
// the server you wish to connect to - you can also use the server ip ex. 107.23.17.20
$ftp_server = "ftp.example.com";
// set up a connection to the server we chose or die and show an error
$conn_id = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");
ftp_login($conn_id,"ftpserver_username","ftpserver_password");
// check if a file exist
$path = "/SERVER_FOLDER/"; //the path where the file is located
$file = "file.html"; //the file you are looking for
$check_file_exist = $path.$file; //combine string for easy use
$contents_on_server = ftp_nlist($conn_id, $path); //Returns an array of filenames from the specified directory on success or FALSE on error.
// Test if file is in the ftp_nlist array
if (in_array($check_file_exist, $contents_on_server))
{
echo "<br>";
echo "I found ".$check_file_exist." in directory : ".$path;
}
else
{
echo "<br>";
echo $check_file_exist." not found in directory : ".$path;
};
// output $contents_on_server, shows all the files it found, helps for debugging, you can use print_r() as well
var_dump($contents_on_server);
// remember to always close your ftp connection
ftp_close($conn_id);
Functions used: (thanks to middaparka)
Login using ftp_connect
Get the remote file list via ftp_nlist
Use in_array to see if the file was present in the array
Just check the size of a file. If the size is -1, it doesn't exist, so:
$file_size = ftp_size($ftp_connection, "example.txt");
if ($file_size != -1) {
echo "File exists";
} else {
echo "File does not exist";
}
If the size is 0, the file does exist, it's just 0 bytes.
Source
A general solution would be to:
Login using ftp_connect
Navigate to the relevant directory via ftp_chdir
Get the remote file list via ftp_nlist or ftp_rawlist
Use in_array to see if the file was present in the array returned by ftp_rawlist
That said, you could potentially simply use file_exists if you have the relevant URL wrappers available. (See the PHP FTP and FTPS protocols and wrappers manual page for more information.)
This is an optimization of #JohanPretorius solution, and an answer for comments about "slow and inefficient for large dirs" of #Andrew and other: if you need more than one "file_exist checking", this function is a optimal solution.
ftp_file_exists() caching last folder
function ftp_file_exists(
$file, // the file that you looking for
$path = "SERVER_FOLDER", // the remote folder where it is
$ftp_server = "ftp.example.com", //Server to connect to
$ftp_user = "ftpserver_username", //Server username
$ftp_pwd = "ftpserver_password", //Server password
$useCache = 1 // ALERT: do not $useCache when changing the remote folder $path.
){
static $cache_ftp_nlist = array();
static $cache_signature = '';
$new_signature = "$ftp_server/$path";
if(!$useCache || $new_signature!=$cache_signature)
{
$useCache = 0;
//$new_signature = $cache_signature;
$cache_signature = $new_signature;
// setup the connection
$conn_id = ftp_connect($ftp_server) or die("Error connecting $ftp_server");
$ftp_login = ftp_login($conn_id, $ftp_user, $ftp_pwd);
$cache_ftp_nlist = ftp_nlist($conn_id, $path);
if ($cache_ftp_nlist===FALSE)die("erro no ftp_nlist");
}
//$check_file_exist = "$path/$file";
$check_file_exist = "$file";
if(in_array($check_file_exist, $cache_ftp_nlist))
{
echo "Found: ".$check_file_exist." in folder: ".$path;
}
else
{
echo "Not Found: ".$check_file_exist." in folder: ".$path;
};
// use for debuging: var_dump($cache_ftp_nlist);
if(!$useCache) ftp_close($conn_id);
} //function end
//Output messages
echo ftp_file_exists("file1-to-find.ext"); // do FTP
echo ftp_file_exists("file2-to-find.ext"); // using cache
echo ftp_file_exists("file3-to-find.ext"); // using cache
echo ftp_file_exists("file-to-find.ext","OTHER_FOLDER"); // do FTP
You can use ftp_nlist to list all the files on the remote server. Then you should search into the result array to check if the file what you was looking for exists.
http://www.php.net/manual/en/function.ftp-nlist.php
The code has been written by: #Drmzindec should be change a little:
if (in_array($check_file_exist, $contents_on_server))
to
if (in_array($file, $contents_on_server))

Categories