将文件上传至另一台服务器

在开发中应该如何上传到另一台服务器?
常见解决方案有:
1、虚拟主机等权限低的,一般在上传成功或者图片处理完成以后通过ftp协议等把文件推到其它服务器上
2、上传地址随机生成,指向到不同的服务器,以达到每个服务器上传压力和存储负载均衡
3、上传服务器上有事件监听事件,有新文件上传,可以使用rsync等协议将文件推到其它服务器
4、通过CDN等方式在有需要的时候,将文件同步到其它服务器

在使用php开发中可以通过用ftp函数集完成将图片推到其他服务器上

存放文件的服务器需要安装ftp服务,参考ubuntu14.10安装vsftpd与本地用户配置
以下CI框架的FTP类,该类封装就标准的FTP操作,稍微修改了一下具体使用可以参考ci文档

http://codeigniter.com/user_guide/libraries/ftp.html
<?php
 
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		CodeIgniter
 * @author		EllisLab Dev Team
 * @copyright		Copyright (c) 2008 - 2014, EllisLab, Inc.
 * @copyright		Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://codeigniter.com
 * @since		Version 1.0
 * @filesource
 */
// ------------------------------------------------------------------------
 
/**
 * FTP Class
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author		EllisLab Dev Team
 * @link		http://codeigniter.com/user_guide/libraries/ftp.html
 */
class CI_FTP {
 
    private $hostname = '';
    private $username = '';
    private $password = '';
    private $port = 21;
    private $passive = TRUE;
    private $debug = FALSE;
    private $conn_id = FALSE;
 
    /**
     * Constructor - Sets Preferences
     *
     * The constructor can be passed an array of config values
     */
    public function __construct($config = array()) {
        if (count($config) > 0) {
            $this->initialize($config);
        }
 
//        log_message('debug', "FTP Class Initialized");
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Initialize preferences
     *
     * @access	public
     * @param	array
     * @return	void
     */
    private function initialize($config = array()) {
        foreach ($config as $key => $val) {
            if (isset($this->$key)) {
                $this->$key = $val;
            }
        }
 
        // Prep the hostname
        $this->hostname = preg_replace('|.+?://|', '', $this->hostname);
    }
 
    // --------------------------------------------------------------------
 
    /**
     * FTP Connect
     *
     * @access	public
     * @param	array	 the connection values
     * @return	bool
     */
    public function connect($config = array()) {
        if (count($config) > 0) {
            $this->initialize($config);
        }
 
        if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port))) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_connect');
            }
            return FALSE;
        }
 
        if (!$this->_login()) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_login');
            }
            return FALSE;
        }
 
        // Set passive mode if needed
        if ($this->passive == TRUE) {
            ftp_pasv($this->conn_id, TRUE);
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * FTP Login
     *
     * @access	private
     * @return	bool
     */
    private function _login() {
        return @ftp_login($this->conn_id, $this->username, $this->password);
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Validates the connection ID
     *
     * @access	private
     * @return	bool
     */
    private function _is_conn() {
        if (!is_resource($this->conn_id)) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_no_connection');
            }
            return FALSE;
        }
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Change directory
     *
     * The second parameter lets us momentarily turn off debugging so that
     * this function can be used to test for the existence of a folder
     * without throwing an error.  There's no FTP equivalent to is_dir()
     * so we do it by trying to change to a particular directory.
     * Internally, this parameter is only used by the "mirror" function below.
     *
     * @access	public
     * @param	string
     * @param	bool
     * @return	bool
     */
    public function changedir($path = '', $supress_debug = FALSE) {
        if ($path == '' OR ! $this->_is_conn()) {
            return FALSE;
        }
 
        $result = @ftp_chdir($this->conn_id, $path);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE AND $supress_debug == FALSE) {
                $this->_error('ftp_unable_to_changedir');
            }
            return FALSE;
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Create a directory
     *
     * @access	public
     * @param	string
     * @return	bool
     */
    public function mkdir($path = '', $permissions = NULL) {
        if ($path == '' OR ! $this->_is_conn()) {
            return FALSE;
        }
 
        $result = @ftp_mkdir($this->conn_id, $path);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_makdir');
            }
            return FALSE;
        }
 
        // Set file permissions if needed
        if (!is_null($permissions)) {
            $this->chmod($path, (int) $permissions);
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Upload a file to the server
     *
     * @access	public
     * @param	string
     * @param	string
     * @param	string
     * @return	bool
     */
    public function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL) {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        if (!file_exists($locpath)) {
            $this->_error('ftp_no_source_file');
            return FALSE;
        }
 
        // Set the mode if not specified
        if ($mode == 'auto') {
            // Get the file extension so we can set the upload type
            $ext = $this->_getext($locpath);
            $mode = $this->_settype($ext);
        }
 
        $mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;
 
        $result = @ftp_put($this->conn_id, $rempath, $locpath, $mode);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_upload');
            }
            return FALSE;
        }
 
        // Set file permissions if needed
        if (!is_null($permissions)) {
            $this->chmod($rempath, (int) $permissions);
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Download a file from a remote server to the local server
     *
     * @access	public
     * @param	string
     * @param	string
     * @param	string
     * @return	bool
     */
    public function download($rempath, $locpath, $mode = 'auto') {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        // Set the mode if not specified
        if ($mode == 'auto') {
            // Get the file extension so we can set the upload type
            $ext = $this->_getext($rempath);
            $mode = $this->_settype($ext);
        }
 
        $mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;
 
        $result = @ftp_get($this->conn_id, $locpath, $rempath, $mode);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_download');
            }
            return FALSE;
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Rename (or move) a file
     *
     * @access	public
     * @param	string
     * @param	string
     * @param	bool
     * @return	bool
     */
    public function rename($old_file, $new_file, $move = FALSE) {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        $result = @ftp_rename($this->conn_id, $old_file, $new_file);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $msg = ($move == FALSE) ? 'ftp_unable_to_rename' : 'ftp_unable_to_move';
 
                $this->_error($msg);
            }
            return FALSE;
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Move a file
     *
     * @access	public
     * @param	string
     * @param	string
     * @return	bool
     */
    public function move($old_file, $new_file) {
        return $this->rename($old_file, $new_file, TRUE);
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Rename (or move) a file
     *
     * @access	public
     * @param	string
     * @return	bool
     */
    public function delete_file($filepath) {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        $result = @ftp_delete($this->conn_id, $filepath);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_delete');
            }
            return FALSE;
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Delete a folder and recursively delete everything (including sub-folders)
     * containted within it.
     *
     * @access	public
     * @param	string
     * @return	bool
     */
    public function delete_dir($filepath) {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        // Add a trailing slash to the file path if needed
        $filepath = preg_replace("/(.+?)\/*$/", "\\1/", $filepath);
 
        $list = $this->list_files($filepath);
 
        if ($list !== FALSE AND count($list) > 0) {
            foreach ($list as $item) {
                // If we can't delete the item it's probaly a folder so
                // we'll recursively call delete_dir()
                if (!@ftp_delete($this->conn_id, $item)) {
                    $this->delete_dir($item);
                }
            }
        }
 
        $result = @ftp_rmdir($this->conn_id, $filepath);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_delete');
            }
            return FALSE;
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Set file permissions
     *
     * @access	public
     * @param	string	the file path
     * @param	string	the permissions
     * @return	bool
     */
    public function chmod($path, $perm) {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        if (!function_exists('ftp_chmod')) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_chmod');
            }
            return FALSE;
        }
 
        $result = @ftp_chmod($this->conn_id, $perm, $path);
 
        if ($result === FALSE) {
            if ($this->debug == TRUE) {
                $this->_error('ftp_unable_to_chmod');
            }
            return FALSE;
        }
 
        return TRUE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * FTP List files in the specified directory
     *
     * @access	public
     * @return	array
     */
    public function list_files($path = '.') {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        return ftp_nlist($this->conn_id, $path);
    }
 
    // ------------------------------------------------------------------------
 
    /**
     * Read a directory and recreate it remotely
     *
     * This function recursively reads a folder and everything it contains (including
     * sub-folders) and creates a mirror via FTP based on it.  Whatever the directory structure
     * of the original file path will be recreated on the server.
     *
     * @access	public
     * @param	string	path to source with trailing slash
     * @param	string	path to destination - include the base folder with trailing slash
     * @return	bool
     */
    public function mirror($locpath, $rempath) {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        // Open the local file path
        if ($fp = @opendir($locpath)) {
            // Attempt to open the remote file path.
            if (!$this->changedir($rempath, TRUE)) {
                // If it doesn't exist we'll attempt to create the direcotory
                if (!$this->mkdir($rempath) OR ! $this->changedir($rempath)) {
                    return FALSE;
                }
            }
 
            // Recursively read the local directory
            while (FALSE !== ($file = readdir($fp))) {
                if (@is_dir($locpath . $file) && substr($file, 0, 1) != '.') {
                    $this->mirror($locpath . $file . "/", $rempath . $file . "/");
                } elseif (substr($file, 0, 1) != ".") {
                    // Get the file extension so we can se the upload type
                    $ext = $this->_getext($file);
                    $mode = $this->_settype($ext);
 
                    $this->upload($locpath . $file, $rempath . $file, $mode);
                }
            }
            return TRUE;
        }
 
        return FALSE;
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Extract the file extension
     *
     * @access	private
     * @param	string
     * @return	string
     */
    private function _getext($filename) {
        if (FALSE === strpos($filename, '.')) {
            return 'txt';
        }
 
        $x = explode('.', $filename);
        return end($x);
    }
 
    // --------------------------------------------------------------------
 
    /**
     * Set the upload type
     *
     * @access	private
     * @param	string
     * @return	string
     */
    private function _settype($ext) {
        $text_types = array(
            'txt',
            'text',
            'php',
            'phps',
            'php4',
            'js',
            'css',
            'htm',
            'html',
            'phtml',
            'shtml',
            'log',
            'xml'
        );
 
 
        return (in_array($ext, $text_types)) ? 'ascii' : 'binary';
    }
 
    // ------------------------------------------------------------------------
 
    /**
     * Close the connection
     *
     * @access	public
     * @param	string	path to source
     * @param	string	path to destination
     * @return	bool
     */
    public function close() {
        if (!$this->_is_conn()) {
            return FALSE;
        }
 
        @ftp_close($this->conn_id);
    }
 
    // ------------------------------------------------------------------------
 
    /**
     * Display error message
     *
     * @access	private
     * @param	string
     * @return	bool
     */
    private function _error($line) {
        try {
            throw new Exception($line);
        } catch (Exception $exc) {
            echo $exc->getMessage();
        }
    }
 
}

使用例子

<?php
include 'Ftp.php';
$ftp_conf = [
    'hostname'=>'10.5.26.134',
    'username'=>'ftpsite',
    'password'=>'123123',
];
$ftp = new CI_FTP();
$ftp->connect($ftp_conf);
$rs = $ftp->upload('ax.js','assets/aa.js');
var_dump($rs);
$ftp->close();
标签:

ubuntu14.10安装vsftpd与本地用户配置

三 13th, 2015
ubuntu14.10安装vsftpd与本地用户配置已关闭评论

安装:

sudo apt-get install vsftpd

配置:vsftpd.conf

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
ftpd_banner=Welcome to blah FTP service.
chroot_local_user=YES
allow_writeable_chroot=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd.allowuser

配置后重新启动下服务

sudo service vsftpd restart

创建本地用户帐号供ftp登录使用
添加用户并设置home目录

sudo useradd -d /home/ftpsite/ -s /usr/sbin/nologin ftpsite

设置密码

sudo passwd ftpsite

配置允许登录到ftp文件vsftpd.allowuser

ftpsite

登录是可能出现下面错误

[右] 331 Please specify the password.
[右] PASS (hidden)
[右] 530 Login incorrect.
[右] 连接失败

可以试下注释/etc/pam.d/vsftpd文件中的auth required pam_shells.so
当我们限定了用户不能跳出其主目录之后,即设置chroot_local_user=YES
使用该用户登录FTP时往往会遇到这个错误:
500 OOPS: vsftpd: refusing to run with writable root inside chroot()
这个问题发生在最新的这是由于下面的更新造成的
从2.3.5之后,vsftpd增强了安全检查,如果用户被限定在了其主目录下,则该用户的主目录不能再具有写权限了!如果检查发现还有写权限,就会报该错误。
要修复这个错误,可以用命令chmod a-w /home/user去除用户主目录的写权限,注意把目录替换成你自己的。或者你可以在vsftpd的配置文件中增加:allow_writeable_chroot=YES