I'm trying to write a script that will upload the entire contents of a directory stored on my server to other servers via ftp.
I've been reading through the documentation on www.php.net, but can't seem to find a way to upload more then one file at a time.
Is there a way to do this, or is there a script that will index that directory and create an array of files to upload?
Thanks in advance for your help!
Once you have a connection open, uploading the contents of a directory serially is simple:
foreach (glob("/directory/to/upload/*.*") as $filename)
ftp_put($ftp_stream, basename($filename) , $filename, FTP_BINARY);
Uploading all files in parallel would be more difficult.
So, I took #iYETER's code, and wrapped it as a class object.
You can call this code by these lines:
$ftp = new FtpNew("hostname");
$ftpSession = $ftp->login("username", "password");
if (!$ftpSession) die("Failed to connect.");
$errorList = $ftp->send_recursive_directory("/local/dir/", "/remote/dir/");
print_r($errorList);
$ftp->disconnect();
It recursively crawls local dir, and places it on remote dir relative. If it hits any errors, it creates a array hierarchy of every file and their exception code (I only capture 2 so far, if it's another error, it throws it default route for now)
The class this is wrapped into:
<?php
//Thanks for iYETER on http://stackoverflow.com/questions/927341/upload-entire-directory-via-php-ftp
class FtpNew {
private $connectionID;
private $ftpSession = false;
private $blackList = array('.', '..', 'Thumbs.db');
public function __construct($ftpHost = "") {
if ($ftpHost != "") $this->connectionID = ftp_connect($ftpHost);
}
public function __destruct() {
$this->disconnect();
}
public function connect($ftpHost) {
$this->disconnect();
$this->connectionID = ftp_connect($ftpHost);
return $this->connectionID;
}
public function login($ftpUser, $ftpPass) {
if (!$this->connectionID) throw new Exception("Connection not established.", -1);
$this->ftpSession = ftp_login($this->connectionID, $ftpUser, $ftpPass);
return $this->ftpSession;
}
public function disconnect() {
if (isset($this->connectionID)) {
ftp_close($this->connectionID);
unset($this->connectionID);
}
}
public function send_recursive_directory($localPath, $remotePath) {
return $this->recurse_directory($localPath, $localPath, $remotePath);
}
private function recurse_directory($rootPath, $localPath, $remotePath) {
$errorList = array();
if (!is_dir($localPath)) throw new Exception("Invalid directory: $localPath");
chdir($localPath);
$directory = opendir(".");
while ($file = readdir($directory)) {
if (in_array($file, $this->blackList)) continue;
if (is_dir($file)) {
$errorList["$remotePath/$file"] = $this->make_directory("$remotePath/$file");
$errorList[] = $this->recurse_directory($rootPath, "$localPath/$file", "$remotePath/$file");
chdir($localPath);
} else {
$errorList["$remotePath/$file"] = $this->put_file("$localPath/$file", "$remotePath/$file");
}
}
return $errorList;
}
public function make_directory($remotePath) {
$error = "";
try {
ftp_mkdir($this->connectionID, $remotePath);
} catch (Exception $e) {
if ($e->getCode() == 2) $error = $e->getMessage();
}
return $error;
}
public function put_file($localPath, $remotePath) {
$error = "";
try {
ftp_put($this->connectionID, $remotePath, $localPath, FTP_BINARY);
} catch (Exception $e) {
if ($e->getCode() == 2) $error = $e->getMessage();
}
return $error;
}
}
Do it in a loop, iterating through all the files in the folder
$servername = $GLOBALS["servername"];
$ftpUser = $GLOBALS["ftpUser"];
$ftpPass = $GLOBALS["ftpPass"];
$conn_id = ftp_connect($servername) or die("<p style=\"color:red\">Error connecting to $servername </p>");
if(ftp_login($conn_id, $ftpUser, $ftpPass))
{
$dir_handle = #opendir($path) or die("Error opening $path");
while ($file = readdir($dir_handle)) {
ftp_put($conn_id, PATH_TO_REMOTE_FILE, $file)
}
}
I coded it, the script uploads whole folder with it's subfolders and files.
I hope it will help you.
<?php
ob_start();
set_time_limit(0);
//r10.net fatal
$anadizin="uploadedeceginizdizin"; //this is the folder that you want to upload with all subfolder and files of it.
$ftpsunucu="domain.com"; //ftp domain name
$ftpusername="ftpuser"; //ftp user name
$ftppass="ftppass"; //ftp passowrd
$ftpdizin="/public_html"; //ftp main folder
$arkadaslarlabardaydik = ftp_connect($ftpsunucu);
$ictikguldukeglendik = ftp_login($arkadaslarlabardaydik, $ftpusername, $ftppass);
if((!$arkadaslarlabardaydik) || (!$ictikguldukeglendik))
{
echo "cant connect!";
die();
}
function klasoruoku($dizinadi)
{
global $nerdeyiz,$fulldizin,$ftpdizin,$arkadaslarlabardaydik,$ftpdizin;
chdir($dizinadi."\\");
$dizin = opendir(".");
while($bilgi=readdir($dizin))
{
if ($bilgi!='.' and $bilgi!='..' and $bilgi!="Thumbs.db")
{
$tamyol="$dizinadi\\$bilgi";
$lokalkla=str_replace("".$nerdeyiz."\\","",$dizinadi)."";
$lokaldosya="$lokalkla\\$bilgi";
$ftpyeyolla=str_replace(array("\\\\","\\"),array("/","/"),"$ftpdizin\\".str_replace("".$fulldizin."","",$dizinadi)."\\$bilgi");
if(!is_dir($bilgi))
{
$yükleme = ftp_put($arkadaslarlabardaydik, $ftpyeyolla, $tamyol, FTP_BINARY);
if (!$yükleme)
{
echo "$lokaldosya <font color=red>uploaded</font>"; echo "<br>"; fls();
}
else
{
echo "$lokaldosya <font color=green>not uploaded</font>"; echo "<br>"; fls();
}
}
else
{
ftp_mkdir($arkadaslarlabardaydik, $ftpyeyolla);
klasoruoku("$dizinadi\\$bilgi");
chdir($dizinadi."\\");
fls();
}
}
}
closedir ($dizin);
}
function fls()
{
ob_end_flush();
ob_flush();
flush();
ob_start();
}
$nerdeyiz=getcwd();
$fulldizin=$nerdeyiz."\\$anadizin";
klasoruoku($fulldizin);
ftp_close($arkadaslarlabardaydik);
?>
If you want to have multiple files uploaded at once, you'll need to use thread or fork.
I'm not sure of a Thread implentation in PHP, but you should take a look at the PHP SPL and/or PEAR
Edit: Thanks to Frank Farmer to let me know that there was a fork() function in PHP known as pcntl_fork()
You'll also have to get the whole content directory recursively to be able to upload all the file for a given directory.
Related
I have an issue with my host (and maybe my internet connection) : i use filezilla to upload several huge .zip on my website (each .zip weighs ca. 500Mo) and the connection closes before the upload's end.
So, i thought i would upload a folder containing my photographies (in that way, filezilla uploads several little files and not ONE HUGE file), and then i will make an archive of these by passing through a php script.
Here is the code i did :
/*
params :
string $nom_archive: archive's name in '.zip' (ex. 'archive.zip', 'test.zip', etc.)
string $adr_dossier: the path of the folder to archive (ex. 'images', '../dossier1/dossier2', etc.)
string $dossier_destination : path of the folder where we will copy/paste the archive (ex. 'images/zip', '../archives', etc.)
DOn't change the params $zip and $dossier_base
*/
function zipper_repertoire_recursif($nom_archive, $adr_dossier, $dossier_destination = '', $zip=null, $dossier_base = '') {
if($zip===null) {
$zip = new ZipArchive();
if($zip->open($nom_archive, ZipArchive::CREATE) !== TRUE) {
return false;
}
}
if(substr($adr_dossier, -1)!='/') {
$adr_dossier .= '/';
}
if($dossier_base=="") {
$dossier_base=$adr_dossier;
}
if(file_exists($adr_dossier)) {
if(#$dossier = opendir($adr_dossier)) {
while(false !== ($fichier = readdir($dossier))) {
if($fichier != '.' && $fichier != '..') {
if(is_dir($adr_dossier.$fichier)) {
$zip->addEmptyDir($adr_dossier.$fichier);
zipper_repertoire_recursif($nom_archive, $adr_dossier.$fichier, $dossier_destination, $zip, $dossier_base);
}
else {
$zip->addFile($adr_dossier.$fichier);
}
}
}
}
}
if($dossier_base==$adr_dossier) {
$zip->close();
if($dossier_destination!='') {
if(substr($dossier_destination, -1)!='/') {
$dossier_destination .= '/';
}
if(rename($nom_archive, $dossier_destination.$nom_archive)) {
return true;
}
else {
return false;
}
}
else {
return true;
}
}
}
And then, i call my function that way :
zipper_repertoire_recursif('Myriam&Fabien_byGFernandez_Originales.zip', './Myriam&Fabien/Photos/originales/photos_originales', './Myriam&Fabien/Photos/originales')
But it won't work, and i don't know why.
I've checked if zip is enabled on my server and it is.
DO you have any idea on my problem?
Maybe I'm using ZipArchive the wrong way, but i can't figure out what i did wrong.
COuld you help me, please?
Thank you very much.
I am downloading zip files from FTP server using PHP ftp function.I used binary and passive mode to get file.
The problem is that when I stopped the ftp operation before the completion of ftp operation(ie ftp_close() was not called) and when it was started again it shows the following Warning-
ftp_login() [http://php.net/function.ftp-login]: service unavailable
FTP connection has failed!
And the FTP operation was failed.I have written the following code for FTP operation.
$connId = ftp_connect($host);
$loginResult = ftp_login($connId, $user, $password);
if ((!$connId) || (!$loginResult)) {
echo "FTP connection has failed!";
exit;
}
ftp_pasv($connId, true);
if (!ftp_chdir($connId, $remoteDir))
return false;
if (!ftp_get($connId, $localDir.$localFile,$remoteFile,FTP_BINARY))
return false;
ftp_close($connId);
How to forcefully destroy ftp connection which has started getting files in binary mode and the connection is in passive mode?
Rebooting the machine or deleting the session cookies did not help me.What might be the possible solution for it?
Rebooting a machine always closes all connections made by or to that machine.
ftp_login() [http://php.net/function.ftp-login]: service unavailable
FTP connection has failed!
It looks like the remote FTP server is terminating the connection before you ever get to the login step. Check that your credentials are correct and check to make sure the FTP server is operating correctly.
This question is way old, but one I had some issues with recently. I put together a quick FTP helper class that will automatically and cleanly close connections. Hope this helps others looking for a simpler way to perform basic FTP operations.
//
define("SMOKE_TEST", TRUE);
//
// Define main FTP class.
//
class C_FTP {
// Connection handle.
//
public $h = FALSE;
// Close connection.
//
public function _Close() {
if ($this->h) {
ftp_close($this->h);
$this->h = FALSE;
}
}
// Connect.
//
public function __construct($sDNSName) {
$this->_Close();
$this->h = ftp_connect($sDNSName);
}
// Destructor.
//
public function __destruct() {
$this->_Close();
}
// Authenticate.
//
public function login($sUsername = "", $sPassword = "") {
$sError = "";
do {
//
if (!$this->h) {
$sError = "Not connected";
break;
}
if (!ftp_login($this->h, $sUsername, $sPassword)) {
$sError = "Unrecognized username or password";
break;
}
ftp_pasv($this->h, TRUE);
//
} while (0);
return ($sError);
}
// Change directory.
//
public function cd($sFolder) {
$sError = "";
do {
if (!ftp_chdir($this->h, $sFolder)) {
$sError = "Unable to change directory";
break;
}
} while (0);
return ($sError);
}
// List files in current directory.
//
public function dir(&$aFiles) {
$sError = "";
do {
if (($aFiles = ftp_nlist($this->h, ".")) === FALSE) {
$sError = "Unable to list files in current directory";
break;
}
} while (0);
return ($sError);
}
// Get file from remote site into specified local file.
//
public function get($sLocalFile, $sRemoteFilename) {
$sError = "";
do {
if (!ftp_get($this->h, $sLocalFile, $sRemoteFilename, FTP_BINARY)) {
$sError = "Could not perform file get";
break;
}
} while (0);
return ($sError);
}
// Put file from remote site into current directory.
//
public function put($sLocalFile, $sRemoteFilename) {
$sError = "";
do {
if (!ftp_put($this->h, $sRemoteFilename, $sLocalFile, FTP_BINARY)) {
$sError = "Could not perform file put";
break;
}
} while (0);
return ($sError);
}
// ...end FTP class.
//
}
// If we are running a stand-alone test of this class,
// set SMOKE_TEST to TRUE and invoke from CLI.
// For example: c:\php\php C_FTP.php
//
if (SMOKE_TEST) {
//
function IsError($sMessage) {
if (strlen($sMessage)) {
echo("Error: ".$sMessage);
return (true);
} else {
return (false);
}
}
//
do {
//
$aFiles = array();
//
$cFTP = new C_FTP(FTP_DNS_NAME);
if (IsError($cFTP->login(FTP_USER, FTP_PASSWORD))) { break; }
if (IsError($cFTP->cd("Env"))) { break; }
if (IsError($cFTP->get("foo.txt", "SomeRemoteFile.txt"))) { break; }
if (IsError($cFTP->dir($aFiles))) { break; }
var_dump($aFiles);
//
} while (0);
//
}
?>
Please note that this forces passive mode for data transfer, so if you need active, you'll need to adjust accordingly.
I'm using Codeigniter to create a web site, and I tried to create a function to upload the entire directory via FTP to a remote host, but nothing is working
I tried 2 functions I found, but also not working, only few files uploaded, and some files size is 0 bytes
Functions Used :
// 1St Function
public function ftp_copy($src_dir, $dst_dir) {
$d = dir($src_dir);
while($file = $d->read()) {
if ($file != "." && $file != "..") {
if (is_dir($src_dir."/".$file)) {
if (!#ftp_chdir($this->conn_id, $dst_dir."/".$file)) {
ftp_mkdir($this->conn_id, $dst_dir."/".$file);
}
ftp_copy($src_dir."/".$file, $dst_dir."/".$file);
}
else {
$upload = ftp_put($this->conn_id, $dst_dir."/".$file, $src_dir."/".$file, FTP_BINARY);
}
}
}
$d->close();
}
// 2nd Solution from Stackoverflow question
foreach (glob("/directory/to/upload/*.*") as $filename)
ftp_put($ftp_stream, basename($filename) , $filename, FTP_BINARY);
Any solution ??
If you are using codeigniter you can use $this->ftp->mirror() from their FTP Library.
http://codeigniter.com/user_guide/libraries/ftp.html
$this->load->library('ftp');
$config['hostname'] = 'ftp.example.com';
$config['username'] = 'your-username';
$config['password'] = 'your-password';
$config['debug'] = TRUE;
$this->ftp->connect($config);
$this->ftp->mirror('/path/to/myfolder/', '/public_html/myfolder/');
$this->ftp->close();
I have a web application that generate some php files for new members in sub-directories, I'm using PHP copy function to do that, but members web pages gives 500 Internal Server Error, and the script is working fine if uploaded by FTP, with the hosting account, or the root account.
I think the problem is with the "apache apache" group, because after uploading files with the "root root" group, files are working fine, please help!
this is the function used to copy the whole files in my directory to users ones :
function smartCopy($source, $dest, $options=array('folderPermission'=>0775,'filePermission'=>0775))
{
$result=false;
if (is_file($source)) {
if ($dest[strlen($dest)-1]=='/') {
if (!file_exists($dest)) {
cmfcDirectory::makeAll($dest,$options['folderPermission'],true);
}
$__dest=$dest."/".basename($source);
} else {
$__dest=$dest;
}
$result=copy($source, $__dest);
chmod($__dest,$options['filePermission']);
} elseif(is_dir($source)) {
if ($dest[strlen($dest)-1]=='/') {
if ($source[strlen($source)-1]=='/') {
//Copy only contents
} else {
//Change parent itself and its contents
$dest=$dest.basename($source);
#mkdir($dest);
chmod($dest,$options['filePermission']);
}
} else {
if ($source[strlen($source)-1]=='/') {
//Copy parent directory with new name and all its content
#mkdir($dest,$options['folderPermission']);
chmod($dest,$options['filePermission']);
} else {
//Copy parent directory with new name and all its content
#mkdir($dest,$options['folderPermission']);
chmod($dest,$options['filePermission']);
}
}
$dirHandle=opendir($source);
while($file=readdir($dirHandle))
{
if($file!="." && $file!="..")
{
if(!is_dir($source."/".$file)) {
$__dest=$dest."/".$file;
} else {
$__dest=$dest."/".$file;
}
//echo "$source/$file ||| $__dest<br />";
$result=smartCopy($source."/".$file, $__dest, $options);
}
}
closedir($dirHandle);
} else {
$result=false;
}
return $result;
}
Notice : there are no problem with permissions.
I used this function to solve my problem :
$oldmask = umask(0);
mkdir("apps/$appid", 0755);
umask($oldmask);
I have searched the forum but the closest question which is about the control stream did not help or I did not understand so I want to ask a different question.
I have an html form which uploads multiples files to a directory. The upload manager that handles the upload resides in the same script with a different code which I need to pass the file names to for processing.
The problem is that the files get uploaded but they don't get processed by the the other code. I am not sure about the right way to pass the $_FILES['uploadedFile']['tmp_name']) in the adjoining code so the files can be processed with the remaining code. Please find below the script.
More specif explanation:
this script does specifically 2 things. the first part handles file uploads and the second part starting from the italised comment extracts data from the numerous uploaded files. This part has a variable $_infile which is array which is suppose to get the uploaded files. I need to pass the files into this array. so far I struggled and did this: $inFiles = ($_FILES['uploadedFile']['tmp_name']); which is not working. You can see it also in the full code sample below. there is no error but the files are not passed and they are not processed after uploading.
<?php
// This part uploads text files
if (isset($_POST['uploadfiles'])) {
if (isset($_POST['uploadfiles'])) {
$number_of_uploaded_files = 0;
$number_of_moved_files = 0;
$uploaded_files = array();
$upload_directory = dirname(__file__) . '/Uploads/';
for ($i = 0; $i < count($_FILES['uploadedFile']['name']); $i++) {
//$number_of_file_fields++;
if ($_FILES['uploadedFile']['name'][$i] != '') { //check if file field empty or not
$number_of_uploaded_files++;
$uploaded_files[] = $_FILES['uploadedFile']['name'][$i];
//if (is_uploaded_file($_FILES['uploadedFile']['name'])){
if (move_uploaded_file($_FILES['uploadedFile']['tmp_name'][$i], $upload_directory . $_FILES['uploadedFile']['name'][$i])) {
$number_of_moved_files++;
}
}
}
}
echo "Files successfully uploaded . <br/>" ;
echo "Number of files submitted $number_of_uploaded_files . <br/>";
echo "Number of successfully moved files $number_of_moved_files . <br/>";
echo "File Names are <br/>" . implode(',', $uploaded_files);
*/* This is the start of a script to accept the uploaded into another array of it own for* processing.*/
$searchCriteria = array('$GPRMC');
//creating a reference for multiple text files in an array
**$inFiles = ($_FILES['uploadedFile']['tmp_name']);**
$outFile = fopen("outputRMC.txt", "w");
$outFile2 = fopen("outputGGA.txt", "w");
//processing individual files in the array called $inFiles via foreach loop
if (is_array($inFiles)) {
foreach($inFiles as $inFileName) {
$numLines = 1;
//opening the input file
$inFiles = fopen($inFileName,"r");
//This line below initially was used to obtain the the output of each textfile processed.
//dirname($inFileName).basename($inFileName,'.txt').'_out.txt',"w");
//reading the inFile line by line and outputting the line if searchCriteria is met
while(!feof($inFiles)) {
$line = fgets($inFiles);
$lineTokens = explode(',',$line);
if(in_array($lineTokens[0],$searchCriteria)) {
if (fwrite($outFile,$line)===FALSE){
echo "Problem w*riting to file\n";
}
$numLines++;
}
// Defining search criteria for $GPGGA
$lineTokens = explode(',',$line);
$searchCriteria2 = array('$GPGGA');
if(in_array($lineTokens[0],$searchCriteria2)) {
if (fwrite($outFile2,$line)===FALSE){
echo "Problem writing to file\n";
}
}
}
}
echo "<p>For the file ".$inFileName." read ".$numLines;
//close the in files
fclose($_FILES['uploadedFile']['tmp_name']);
fflush($outFile);
fflush($outFile2);
}
fclose($outFile);
fclose($outFile2);
}
?>
Try this upload class instead and see if it helps:
To use it simply Upload::files('/to/this/directory/');
It returns an array of file names that where uploaded. (it may rename the file if it already exists in the upload directory)
class Upload {
public static function file($file, $directory) {
if (!is_dir($directory)) {
if (!#mkdir($directory)) {
throw new Exception('Upload directory does not exists and could not be created');
}
if (!#chmod($directory, 0777)) {
throw new Exception('Could not modify upload directory permissions');
}
}
if ($file['error'] != 0) {
throw new Exception('Error uploading file: '.$file['error']);
}
$file_name = $directory.$file['name'];
$i = 2;
while (file_exists($file_name)) {
$parts = explode('.', $file['name']);
$parts[0] .= '('.$i.')';
$new_file_name = $directory.implode('.', $parts);
if (!file_exists($new_file_name)) {
$file_name = $new_file_name;
}
$i++;
}
if (!#move_uploaded_file($file['tmp_name'], $file_name)) {
throw new Exception('Could not move uploaded file ('.$file['tmp_name'].') to: '.$file_name);
}
if (!#chmod($file_name, 0777)) {
throw new Exception('Could not modify uploaded file ('.$file_name.') permissions');
}
return $file_name;
}
public static function files($directory) {
if (sizeof($_FILES) > 0) {
$uploads = array();
foreach ($_FILES as $file) {
if (!is_uploaded_file($file['tmp_name'])) {
continue;
}
$file_name = static::file($file, $directory);
array_push($uploads, $file_name);
}
return $uploads;
}
return null;
}
}