让thinkphp真正的支持FTP上传。删除。
原创by default7#zbphp.com,如需转载请保留作者信息。
/**
* This is not a free software, All Copyright @F.Z.B
* Date: 2014/10/21 10:51
* File: MyFtpUpload.php
* Author: default7 <default7@zbphp.com>
*/
include 'Ftp.php';
class MyFtpUpload
{
//必须支持swf jpg jpeg png gif bmp txt log
public $allowType = 'swf|png|jpg|gif|jpeg';
public $locFolder = 'uploads';
static $ftpHandler = null;
static $config = null;
public function __construct()
{
if (self::$config === null) {
self::$config = C('MY_CI_FTP_CONFIG');
}
}
public function __destruct()
{
if (self::$ftpHandler !== null) {
self::$ftpHandler->close();
}
}
/**
* @description 单例模式
* @return null
*/
public function getInstance()
{
if (self::$ftpHandler === null) {
$ftp = new CI_FTP(self::$config);
$ftp->connect();
self::$ftpHandler = $ftp;
}
return self::$ftpHandler;
}
/**
* @description 检測文件大小是否溢出
*
* @param $size
*
* @return bool
*/
function isSizeOver($size)
{
return !empty(self::$config['maxsize']) && $size > self::$config['maxsize'] ? true : false;
}
/**
* @description 一行上传 支持单个
*
* @param $file
* @param string $saveFolder
* @param string $allowType
*
* @return array
*/
public function autoUpload($file, $saveFolder = '', $allowType = '')
{
if (empty($allowType)) $allowType = $this->allowType;
$ext = $this->getExt($file['name']);
if (!$this->isAllowExt($ext, $allowType)) {
return array(false, '不同意的格式' . $ext);
}
$savePath = $this->mkSavePath($saveFolder, $ext);
if (!$this->ftpUpload($file['tmp_name'], $savePath)) {
return array(false, '文件上传失败,请联系管理员或重试。');
}
return array(true, $savePath);
}
/**
* @description 输入本地的存放地址路径。输入远程的存放路径
*
* @param $localPath
* @param $savePath
*
* @return mixed
*/
function ftpUpload($localPath, $savePath)
{
if (!self::$config) return false;
$dir = trim(dirname($savePath));
if (!self::getInstance()->changedir($dir)) {
self::getInstance()->mkdir($dir);
self::getInstance()->chmod($dir, 0777);
}
$result = self::getInstance()->upload($localPath, $savePath);
return $result;
}
//先保存到本地 再上传到远程
public function saveTxtFile($savePath, $content, $locFolder = 'uploads')
{
$locPath = $locFolder . $savePath;
$arr = explode('/', dirname($locPath));
$dir = '.';
foreach ($arr as $d) {
$comma = '/';
$dir .= $comma . $d;
if (!is_dir($dir) && !mkdir($dir)) return false;
}
//保存文件失败
if (empty($content)) $content = ' ';//防止 file_put_content 保存失败
if (!file_put_contents($locPath, $content)) {
return false;
}
return $this->ftpUpload($locPath, $savePath);
}
//读取远程文件 先读取本地。否则读取远程
public function readTxtFile($filePath, $locFolder = 'uploads')
{
$content = '';
$locPath = './' . $locFolder . $filePath;
if (!(file_exists($locPath) && is_file($locPath))) {
self::getInstance()->download($filePath, $locPath);
}
if (is_file($locPath)) $content = file_get_contents($locPath);
return $content;
}
/**
* @description 删除本地 同一时候删除远程
*
* @param $path
* @param string $locFolder
* @param string $allowType
*
* @return bool
*/
public function delTxtFile($path, $locFolder = 'uploads', $allowType = '')
{
if (!empty($path)) {
if (empty($allowType)) $allowType = $this->allowType;
$ext = $this->getExt($path);
if ($this->isAllowExt($ext, $allowType)) {
$locPath = './' . $locFolder . $path;
if (file_exists($locPath)) {
@unlink($locPath);
}
return $this->ftpDelFile($path, $allowType);
}
}
return array(false, '文件' . $path . '删除失败,请联系管理员!
');
}
/**
* @description 文件名称中含有 至少2个数字表示非默认文件
*
* @param $filepath
*
* @return bool
*/
public function isDefaultFile($filepath)
{
return preg_match('/\d{2,}/', basename($filepath)) ? false : true;
}
/**
* @description 默认图片/文件是不同意删除!
*
* @param $filePath
* @param string $allowType
*
* @return array
*/
public function ftpDelFile($filePath, $allowType = '')
{
if (!self::$config) return array(false, '未配置FTP登录信息');
//是否是默认图片
if ($this->isDefaultFile($filePath)) {
return array(false, '默认图片不同意删除!
');
}
if (strpos($filePath, '..') !== false) {
return array(false, '文件或文件夹地址中不能包括 .. !');
}
if (empty($allowType)) $allowType = $this->allowType;
$ext = $this->getExt($filePath);
if (!$this->isAllowExt($ext, $allowType)) {
return array(false, '不同意的删除格式!
');
}
$result = self::getInstance()->delete_file($filePath);
return array($result, '');
}
/**
* @param $filename
*
* @return string
*/
function getExt($filename)
{
if (false === strpos($filename, '.')) {
return '';
}
$x = explode('.', $filename);
return '.' . strtolower(end($x));
}
/**
* @description 输入的扩展名必须以.开头
*
* @param $ext
* @param string $allowType
*
* @return bool
*/
function isAllowExt($ext, $allowType = '')
{
if ($allowType == '*') return true;
if (empty($allowType)) $allowType = $this->allowType;
return $ext && preg_match('/^\.(' . $allowType . ')$/i', $ext) ? true : false;
}
/**
* @description 生成上传地址 完整上传地址
* 开头必须是 斜杠,包括完整扩展名
*
* @param string $folder
* @param string $ext
*
* @return mixed
*/
public function mkSavePath($folder = '', $ext = '')
{
$savePath = '/' . $folder . '/' . date('ym') . '/' . date('ymdHis_') . rand(10, 99) . $ext;
return str_replace('//', '/', $savePath);
}
/**
* @description 检測是否是图片文件
*
* @param $filepath
* @param string $ext
*
* @return bool
*/
public function isImageFile($filepath, $ext = '')
{
$imginfo = getimagesize($filepath);
if (empty($imginfo) || ($ext == 'gif' && empty($imginfo['bits']))) {
return false;
}
return true;
}
/**
* @description 通过保存路径获取网址
*
* @param $savePath
*
* @return string
*/
public function getUrl($savePath)
{
$url = '';
if (preg_match('/^https?:/', $savePath)) {
$url = $savePath;
} else if (!empty($savePath)) {
$url .= self::$config['siteurl'];
$url .= $savePath;
}
return $url;
}
}
// ------------------------------------------------------------------------
/**
* FTP Class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author ExpressionEngine Dev Team
* @link http://codeigniter.com/user_guide/libraries/ftp.html
*/
class CI_FTP {
var $hostname = '';
var $username = '';
var $password = '';
var $port = 21;
var $passive = TRUE;
var $debug = FALSE;
var $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);
}
}
// --------------------------------------------------------------------
/**
* Initialize preferences
*
* @access public
* @param array
* @return void
*/
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
*/
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
*/
function _login()
{
return @ftp_login($this->conn_id, $this->username, $this->password);
}
// --------------------------------------------------------------------
/**
* Validates the connection ID
*
* @access private
* @return bool
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
function chmod($path, $perm)
{
if ( ! $this->_is_conn())
{
return FALSE;
}
// Permissions can only be set when running PHP 5
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
*/
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
*/
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
*/
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
*/
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
*/
function close()
{
if ( ! $this->_is_conn())
{
return FALSE;
}
@ftp_close($this->conn_id);
}
// ------------------------------------------------------------------------
/**
* Display error message
*
* @access private
* @param string
* @return bool
*/
function _error($line)
{
exit($line);
// $CI =& get_instance();
// $CI->lang->load('ftp');
// show_error($CI->lang->line($line));
}
}
// END FTP Class
/* End of file Ftp.php */
/* Location: ./system/libraries/Ftp.php */
#配置config.php#
//本地測试环境
'MY_CI_FTP_CONFIG' => array(
'hostname' => '127.0.0.1',
'username' => 'php',
'password' => '123456',
'debug' => false,
'passive' => false,
'maxsize' => 1048576,//最大上传1M
'siteurl' => 'http://localhost',//结尾不要有反斜杠
),
#用法#
$file = $_FILES['upfile'];
import('Common.Vendor.CodeIgniter.MyFtpUpload', '', '.php');
$myFtp = new \MyFtpUpload();
if (is_uploaded_file($file['tmp_name'])) {
if ($myFtp->isSizeOver(filesize($file['tmp_name']))) {
$this->error("上传文件不能超过1MB");
}
$ext = $myFtp->getExt($file['name']);
if (!($myFtp->isAllowExt($ext, 'jpg|gif|png|jpeg') && $myFtp->isImageFile($file['tmp_name'], $ext))) {
$this->error("不支持的文件格式!上传的头像必须是图片!");
}
$savePath = '/avatar/' . $UserId . $ext;
if (!$myFtp->ftpUpload($file['tmp_name'], $savePath)) {
$this->error("头像上传失败!");
}
$newHeadphoto = $data['avatar'] = $savePath;
}