问题描述
我正在尝试找到一种将文件从服务器传输到服务器的方法.源服务器可以是任何平台,我们甚至可能对它一无所知,只知道它支持 FTP.
我在 SO 上找到的一些帖子建议为此目的使用 scp、sftp、rsync 或 wget.鉴于这个 PHP 脚本每次都需要工作,而我们唯一确定的是源服务器支持 FTP,那么如何实现呢?
我在 SO 上找到了几个 FTP 示例,但没有很好地解释.
我们需要能够下载所有文件和文件夹,同时保持相同的目录结构.
我找到了一个 PHP 类,它可以使递归 FTP 上传和下载变得容易.可以在这里找到/p>
他们使用的代码如下(顶部的代码是下载、上传和错误检查的示例代码):
<?php//示例设置时间限制(0);需要'ftp.php';$ftp = 新的 ftp();$ftp->conn('主机', '用户名', '密码');$ftp->get('下载/演示', '/demo');//下载 live "/demo" 文件夹到本地 "download/demo"$ftp->put('/demo/test', '上传/vjtest');//上传本地upload/vjtest"到直播/demo/test"$arr = $ftp->getLogData();if ($arr['error'] != "")echo '<h2>错误:</h2>'.内爆('<br/>', $arr['error']);if ($arr['ok'] != "")echo '<h2>成功:</h2>'.内爆('<br/>', $arr['ok']);
<小时>
类 ftp {私人 $conn, $login_result, $logData, $ftpUser, $ftpPass, $ftpHost, $retry, $ftpPasv, $ftpMode, $verbose, $logPath, $createMask;//--------------------------------------------------------------------/*** 构造方法** @param 数组键[passive_mode(true|false)|transfer_mode(FTP_ASCII|FTP_BINARY)|reattempts(int)|log_path|verbose(true|false)|create_mask(default:0777)]* @return 无效*/函数 __construct(){$this->retry = (isset($o['reattempts'])) ?$o['reattempts'] : 3;$this->ftpPasv = (isset($o['passive_mode'])) ?$o['passive_mode'] :真;$this->ftpMode = (isset($o['transfer_mode'])) ?$o['transfer_mode'] : FTP_BINARY;$this->verbose = (isset($o['verbose'])) ?$o['verbose'] :假;$this->logPath = (isset($o['log_path'])) ?$o['log_path'] : 目录名(__FILE__).'log';$this->createMask = (isset($o['create_mask'])) ?$o['create_mask'] : 0777;}//--------------------------------------------------------------------/*** 连接方式** @param 字符串主机名* @param 字符串用户名* @param 字符串密码* @return 无效*/公共函数 conn($hostname, $username, $password){$this->ftpUser = $username;$this->ftpPass = $password;$this->ftpHost = $主机名;$this->initConn();}//--------------------------------------------------------------------/*** 初始化连接方式 - 连接到 ftp 服务器并设置被动模式** @return 布尔值*/函数 initConn(){$this->conn = ftp_connect($this->ftpHost);$this->login_result = ftp_login($this->conn, $this->ftpUser, $this->ftpPass);if($this->conn && $this->login_result){ftp_pasv($this->conn, $this->ftpPasv);返回真;}返回假;}//--------------------------------------------------------------------/*** Put 方法 - 上传文件(文件夹)到 ftp 服务器** @param string 指向 ftp 上目标文件/文件夹的路径* @param string 本地磁盘上源文件/文件夹的路径* @param int 仅用于识别重新尝试,请勿使用此参数* @return 布尔值*/公共函数 put($destinationFile, $sourceFile, $retry = 0){如果(文件存在($sourceFile)){if(!$this->isDir($sourceFile, true)){$this->createSubDirs($destinationFile);if(!ftp_put($this->conn, $destinationFile, $sourceFile, $this->ftpMode)){$重试++;if($重试>$this->重试){$this->logData('上传文件时出错:'.$sourceFile.' => '.$destinationFile, 'error');返回假;}if($this->verbose) echo 'Retry: '.$retry."
";$this->reconnect();$this->put($destinationFile, $sourceFile, $retry);}别的{$this->logData('上传:'.$sourceFile.' => '.$destinationFile, 'ok');返回真;}}别的{$this->recursive($destinationFile, $sourceFile, 'put');}}}//--------------------------------------------------------------------/*** 获取方法 - 从 ftp 服务器下载文件(文件夹)** @param string 本地磁盘上目标文件/文件夹的路径* @param string 指向 ftp 服务器上源文件/文件夹的路径* @param int 仅用于识别重新尝试,请勿使用此参数* @return 布尔值*/公共函数 get($destinationFile, $sourceFile, $retry = 0){if(!$this->isDir($sourceFile, false)){if($this->verbose)echo $sourceFile.'=>'.$destinationFile."
";$this->createSubDirs($destinationFile, false, true);if(!ftp_get($this->conn, $destinationFile, $sourceFile, $this->ftpMode)){$重试++;if($重试>$this->重试){$this->logData('下载文件时出错:'.$sourceFile.' => '.$destinationFile, 'error');返回假;}if($this->verbose) echo 'Retry: '.$retry."
";$this->reconnect();$this->get($destinationFile, $sourceFile, $retry);}别的{$this->logData('下载:'.$sourceFile.' => '.$destinationFile, 'ok');返回真;}}别的{$this->recursive($destinationFile, $sourceFile, 'get');}}//--------------------------------------------------------------------/*** 制作目录方法 - 在 ftp 服务器或本地磁盘上制作文件夹** @param string ftp 或本地磁盘上destionation 文件夹的路径* @param bool 本地为真,ftp 为假* @return 布尔值*/公共函数 makeDir($dir, $local = false){如果($本地){if(!file_exists($dir) && !is_dir($dir))return mkdir($dir, $this->createMask);否则返回真;}别的{ftp_mkdir($this->conn,$dir);return ftp_chmod($this->conn, $this->createMask, $dir);}}//--------------------------------------------------------------------/*** Cd up 方法 - 改变工作目录** @param bool 本地为真,ftp 为假* @return 布尔值*/公共函数 cdUp($local){返回 $local ?chdir('..') : ftp_cdup($this->conn);}//--------------------------------------------------------------------/*** List contents of dir 方法 - 列出指定目录下的所有文件** @param string ftp 或本地磁盘上destionation 文件夹的路径* @param bool 本地为真,ftp 为假* @return 布尔值*/公共函数 listFiles($file, $local = false){if(!$this->isDir($file, $local))return false;如果($本地){返回扫描目录($文件);}别的{if(!preg_match('///', $file)){返回 ftp_nlist($this->conn, $file);}别的{$dirs = explode('/', $file);foreach($dirs 作为 $dir){$this->changeDir($dir, $local);}$last = count($dirs)-1;$this->cdUp($local);$list = ftp_nlist($this->conn, $dirs[$last]);$i = 0;foreach($dirs 作为 $dir){if($i < $last) $this->cdUp($local);$i++;}返回$列表;}}}//--------------------------------------------------------------------/*** 返回当前工作目录** @param bool 本地为真,ftp 为假* @return 布尔值*/公共函数 pwd($local = false){返回 $local ?getcwd() : ftp_pwd($this->conn);}//--------------------------------------------------------------------/*** 更改当前工作目录** @param 字符串目录名* @param bool 本地为真,ftp 为假* @return 布尔值*/公共函数 changeDir($dir, $local = false){返回 $local ?chdir($dir) : @ftp_chdir($this->conn, $dir);}//--------------------------------------------------------------------/*** 创建子目录** @param 字符串路径* @param 布尔值* @param bool 本地为真,ftp 为假* @param bool 改变当前工作目录* @return 无效*/函数 createSubDirs($file, $last = false, $local = false, $chDirBack = true){if(preg_match('///',$file)){$origin = $this->pwd($local);if(!$last) $file = substr($file, 0, strrpos($file,'/'));$dirs = explode('/',$file);foreach($dirs 作为 $dir){if(!$this->isDir($dir, $local)){$this->makeDir($dir, $local);$this->changeDir($dir, $local);}别的{$this->changeDir($dir, $local);}}if($chDirBack) $this->changeDir($origin, $local);}}//--------------------------------------------------------------------/*** 递归** @param 字符串目标文件/文件夹* @param 字符串源文件/文件夹* @param 字符串放置或获取* @return 无效*/函数递归($destinationFile,$sourceFile,$mode){$local = ($mode == 'put') ?真假;$list = $this->listFiles($sourceFile, $local);if($this->verbose) echo "
".'Folder: '.$sourceFile."
";$this->logData(($mode=='get')?('Download:'):('Upload:').$sourceFile.' => '.$destinationFile, 'ok');if($this->verbose) print_r($list);$x=0;$z=0;if(count($list)==2)//空白文件夹{if($mode == 'get')$this->makeDir($destinationFile, true);if($mode == 'put')$this->makeDir($destinationFile);}foreach($list 作为 $file){if($file == '.' || $file == '..')继续;$destFile = $destinationFile.'/'.$file;$srcFile = $sourceFile.'/'.$file;if($this->isDir($srcFile,$local)){$this->recursive($destFile, $srcFile, $mode);}别的{如果($本地){$this->put($destFile, $srcFile);}别的{$this->get($destFile, $srcFile);}}}}//--------------------------------------------------------------------/*** 检查是否是目录** @param string 文件夹路径* @return 布尔值*/公共函数 isDir($dir, $local){if($local) 返回 is_dir($dir);if($this->changeDir($dir))return $this->cdUp(0);返回假;}//--------------------------------------------------------------------/*** 将日志数据保存到数组** @param 字符串数据* @param 字符串类型(错误|确定)* @return 无效*/函数 logData($data, $type){$this->logData[$type][] = $data;}//--------------------------------------------------------------------/*** 获取日志数据数组** @return 数组*/公共函数 getLogData(){返回 $this->logData;}//--------------------------------------------------------------------/*** 将日志数据保存到文件** @return 无效*/公共函数 logDataToFiles(){if(!$this->logPath) 返回 false;$this->makeDir($this->logPath, true);$log = $this->getLogData();$sep = "
".date('y-m-d H:i:s').'';if($log['error'] != ""){$logc = date('y-m-d H:i:s').''.join($sep,$log['error'])."
";$this->addToFile($this->logPath.'/'.$this->ftpUser.'-error.log',$logc);}if($log['ok'] != ""){$logc = date('y-m-d H:i:s').''.join($sep,$log['ok'])."
";$this->addToFile($this->logPath.'/'.$this->ftpUser.'-ok.log',$logc);}}//--------------------------------------------------------------------/*** 重连方法** @return 无效*/公共函数重新连接(){$this->closeConn();$this->initConn();}//--------------------------------------------------------------------/*** 关闭连接方式** @return 无效*/公共函数 closeConn(){返回 ftp_close($this->conn);}//--------------------------------------------------------------------/*** 写入文件** @param 字符串文件路径* @param 字符串文本* @param string fopen 模式* @return 无效*/函数 addToFile($file, $ins, $mode = 'a'){$fp = fopen($file, $mode);fwrite($fp,$ins);fclose($fp);}//--------------------------------------------------------------------/*** Destruct 方法 - 关闭连接并将日志数据保存到文件** @return 无效*/函数 __destruct(){$this->closeConn();$this->logDataToFiles();}}//结束 ftp 类/* 文件 ftp.php 结束 *//* 位置:ftp.php */
I am trying to find a way to transfer files from server-to-server. The source server can be any platform, and we may not even really know anything about it except that it supports FTP.
A number of posts I have found on SO recommend using scp, sftp, rsync, or wget for this purpose. Given that this PHP script needs to work every time, and the only thing we know for sure is that the source server supports FTP, how can this be achieved?
I found a couple FTP examples on SO, but they weren't explained very well.
We need to be able to download all files and folders, keeping the same directory structure as well.
I have found a PHP class that makes recursive FTP uploads and downloads easy. It can be found here
The code they used is below (The code at the top is example code for downloads, uploads, and error checking):
<?php // example
set_time_limit(0);
require 'ftp.php';
$ftp = new ftp();
$ftp->conn('host', 'username', 'password');
$ftp->get('download/demo', '/demo'); // download live "/demo" folder to local "download/demo"
$ftp->put('/demo/test', 'upload/vjtest'); // upload local "upload/vjtest" to live "/demo/test"
$arr = $ftp->getLogData();
if ($arr['error'] != "")
echo '<h2>Error:</h2>' . implode('<br />', $arr['error']);
if ($arr['ok'] != "")
echo '<h2>Success:</h2>' . implode('<br />', $arr['ok']);
class ftp {
private $conn, $login_result, $logData, $ftpUser, $ftpPass, $ftpHost, $retry, $ftpPasv, $ftpMode, $verbose, $logPath, $createMask;
// --------------------------------------------------------------------
/**
* Construct method
*
* @param array keys[passive_mode(true|false)|transfer_mode(FTP_ASCII|FTP_BINARY)|reattempts(int)|log_path|verbose(true|false)|create_mask(default:0777)]
* @return void
*/
function __construct()
{
$this->retry = (isset($o['reattempts'])) ? $o['reattempts'] : 3;
$this->ftpPasv = (isset($o['passive_mode'])) ? $o['passive_mode'] : true;
$this->ftpMode = (isset($o['transfer_mode'])) ? $o['transfer_mode'] : FTP_BINARY;
$this->verbose = (isset($o['verbose'])) ? $o['verbose'] : false;
$this->logPath = (isset($o['log_path'])) ? $o['log_path'] : dirname(__FILE__).'log';
$this->createMask = (isset($o['create_mask'])) ? $o['create_mask'] : 0777;
}
// --------------------------------------------------------------------
/**
* Connection method
*
* @param string hostname
* @param string username
* @param string password
* @return void
*/
public function conn($hostname, $username, $password)
{
$this->ftpUser = $username;
$this->ftpPass = $password;
$this->ftpHost = $hostname;
$this->initConn();
}
// --------------------------------------------------------------------
/**
* Init connection method - connect to ftp server and set passive mode
*
* @return bool
*/
function initConn()
{
$this->conn = ftp_connect($this->ftpHost);
$this->login_result = ftp_login($this->conn, $this->ftpUser, $this->ftpPass);
if($this->conn && $this->login_result)
{
ftp_pasv($this->conn, $this->ftpPasv);
return true;
}
return false;
}
// --------------------------------------------------------------------
/**
* Put method - upload files(folders) to ftp server
*
* @param string path to destionation file/folder on ftp
* @param string path to source file/folder on local disk
* @param int only for identify reattempt, dont use this param
* @return bool
*/
public function put($destinationFile, $sourceFile, $retry = 0)
{
if(file_exists($sourceFile))
{
if(!$this->isDir($sourceFile, true))
{
$this->createSubDirs($destinationFile);
if(!ftp_put($this->conn, $destinationFile, $sourceFile, $this->ftpMode))
{
$retry++;
if($retry > $this->retry)
{
$this->logData('Error when uploading file: '.$sourceFile.' => '.$destinationFile, 'error');
return false;
}
if($this->verbose) echo 'Retry: '.$retry."
";
$this->reconnect();
$this->put($destinationFile, $sourceFile, $retry);
}
else
{
$this->logData('Upload:'.$sourceFile.' => '.$destinationFile, 'ok');
return true;
}
}
else
{
$this->recursive($destinationFile, $sourceFile, 'put');
}
}
}
// --------------------------------------------------------------------
/**
* Get method - download files(folders) from ftp server
*
* @param string path to destionation file/folder on local disk
* @param string path to source file/folder on ftp server
* @param int only for identify reattempt, dont use this param
* @return bool
*/
public function get($destinationFile, $sourceFile, $retry = 0)
{
if(!$this->isDir($sourceFile, false))
{
if($this->verbose)echo $sourceFile.' => '.$destinationFile."
";
$this->createSubDirs($destinationFile, false, true);
if(!ftp_get($this->conn, $destinationFile, $sourceFile, $this->ftpMode))
{
$retry++;
if($retry > $this->retry)
{
$this->logData('Error when downloading file: '.$sourceFile.' => '.$destinationFile, 'error');
return false;
}
if($this->verbose) echo 'Retry: '.$retry."
";
$this->reconnect();
$this->get($destinationFile, $sourceFile, $retry);
}
else
{
$this->logData('Download:'.$sourceFile.' => '.$destinationFile, 'ok');
return true;
}
}
else
{
$this->recursive($destinationFile, $sourceFile, 'get');
}
}
// --------------------------------------------------------------------
/**
* Make dir method - make folder on ftp server or local disk
*
* @param string path to destionation folder on ftp or local disk
* @param bool true for local, false for ftp
* @return bool
*/
public function makeDir($dir, $local = false)
{
if($local)
{
if(!file_exists($dir) && !is_dir($dir))return mkdir($dir, $this->createMask); else return true;
}
else
{
ftp_mkdir($this->conn,$dir);
return ftp_chmod($this->conn, $this->createMask, $dir);
}
}
// --------------------------------------------------------------------
/**
* Cd up method - change working dir up
*
* @param bool true for local, false for ftp
* @return bool
*/
public function cdUp($local)
{
return $local ? chdir('..') : ftp_cdup($this->conn);
}
// --------------------------------------------------------------------
/**
* List contents of dir method - list all files in specified directory
*
* @param string path to destionation folder on ftp or local disk
* @param bool true for local, false for ftp
* @return bool
*/
public function listFiles($file, $local = false)
{
if(!$this->isDir($file, $local))return false;
if($local)
{
return scandir($file);
}
else
{
if(!preg_match('///', $file))
{
return ftp_nlist($this->conn, $file);
}else
{
$dirs = explode('/', $file);
foreach($dirs as $dir)
{
$this->changeDir($dir, $local);
}
$last = count($dirs)-1;
$this->cdUp($local);
$list = ftp_nlist($this->conn, $dirs[$last]);
$i = 0;
foreach($dirs as $dir)
{
if($i < $last) $this->cdUp($local);
$i++;
}
return $list;
}
}
}
// --------------------------------------------------------------------
/**
* Returns current working directory
*
* @param bool true for local, false for ftp
* @return bool
*/
public function pwd($local = false)
{
return $local ? getcwd() : ftp_pwd($this->conn);
}
// --------------------------------------------------------------------
/**
* Change current working directory
*
* @param string dir name
* @param bool true for local, false for ftp
* @return bool
*/
public function changeDir($dir, $local = false)
{
return $local ? chdir($dir) : @ftp_chdir($this->conn, $dir);
}
// --------------------------------------------------------------------
/**
* Create subdirectories
*
* @param string path
* @param bool
* @param bool true for local, false for ftp
* @param bool change current working directory back
* @return void
*/
function createSubDirs($file, $last = false, $local = false, $chDirBack = true)
{
if(preg_match('///',$file))
{
$origin = $this->pwd($local);
if(!$last) $file = substr($file, 0, strrpos($file,'/'));
$dirs = explode('/',$file);
foreach($dirs as $dir)
{
if(!$this->isDir($dir, $local))
{
$this->makeDir($dir, $local);
$this->changeDir($dir, $local);
}
else
{
$this->changeDir($dir, $local);
}
}
if($chDirBack) $this->changeDir($origin, $local);
}
}
// --------------------------------------------------------------------
/**
* Recursion
*
* @param string destionation file/folder
* @param string source file/folder
* @param string put or get
* @return void
*/
function recursive($destinationFile, $sourceFile, $mode)
{
$local = ($mode == 'put') ? true : false;
$list = $this->listFiles($sourceFile, $local);
if($this->verbose) echo "
".'Folder: '.$sourceFile."
";
$this->logData(($mode=='get')?('Download:'):('Upload:').$sourceFile.' => '.$destinationFile, 'ok');
if($this->verbose) print_r($list);
$x=0;
$z=0;
if(count($list)==2)// blank folder
{
if($mode == 'get')
$this->makeDir($destinationFile, true);
if($mode == 'put')
$this->makeDir($destinationFile);
}
foreach($list as $file)
{
if($file == '.' || $file == '..')continue;
$destFile = $destinationFile.'/'.$file;
$srcFile = $sourceFile.'/'.$file;
if($this->isDir($srcFile,$local))
{
$this->recursive($destFile, $srcFile, $mode);
}
else
{
if($local)
{
$this->put($destFile, $srcFile);
}
else
{
$this->get($destFile, $srcFile);
}
}
}
}
// --------------------------------------------------------------------
/**
* Check if is dir
*
* @param string path to folder
* @return bool
*/
public function isDir($dir, $local)
{
if($local) return is_dir($dir);
if($this->changeDir($dir))return $this->cdUp(0);
return false;
}
// --------------------------------------------------------------------
/**
* Save log data to array
*
* @param string data
* @param string type(error|ok)
* @return void
*/
function logData($data, $type)
{
$this->logData[$type][] = $data;
}
// --------------------------------------------------------------------
/**
* Get log data array
*
* @return array
*/
public function getLogData()
{
return $this->logData;
}
// --------------------------------------------------------------------
/**
* Save log data to file
*
* @return void
*/
public function logDataToFiles()
{
if(!$this->logPath) return false;
$this->makeDir($this->logPath, true);
$log = $this->getLogData();
$sep = "
".date('y-m-d H:i:s').' ';
if($log['error'] != "")
{
$logc = date('y-m-d H:i:s').' '.join($sep,$log['error'])."
";
$this->addToFile($this->logPath.'/'.$this->ftpUser.'-error.log',$logc);
}
if($log['ok'] != "")
{
$logc = date('y-m-d H:i:s').' '.join($sep,$log['ok'])."
";
$this->addToFile($this->logPath.'/'.$this->ftpUser.'-ok.log',$logc);
}
}
// --------------------------------------------------------------------
/**
* Reconnect method
*
* @return void
*/
public function reconnect()
{
$this->closeConn();
$this->initConn();
}
// --------------------------------------------------------------------
/**
* Close connection method
*
* @return void
*/
public function closeConn()
{
return ftp_close($this->conn);
}
// --------------------------------------------------------------------
/**
* Write to file
*
* @param string path to file
* @param string text
* @param string fopen mode
* @return void
*/
function addToFile($file, $ins, $mode = 'a')
{
$fp = fopen($file, $mode);
fwrite($fp,$ins);
fclose($fp);
}
// --------------------------------------------------------------------
/**
* Destruct method - close connection and save log data to file
*
* @return void
*/
function __destruct()
{
$this->closeConn();
$this->logDataToFiles();
}
}
// END ftp class
/* End of file ftp.php */
/* Location: ftp.php */
这篇关于如何在 PHP 中使用 FTP 从另一台服务器传输文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!