php文件上传类

<?php
/**
 * 文件上传类Upload.php
 *   
 * @author ihelloworld2010@gmail.com   
 * @version $Id: Upload.php,v 1.0 2012/06/14 14:47:43 ihelloworld Exp $   
 * @package system   
 *
 */

class Gsite_File_Upload {
	// 常见的扩展名
	const EXT_IMAGE = 'bmp|jpg|jpeg|png|gif';
	const EXT_DOC = 'txt|csv|doc|xls|ppt|docx|xlsx|pptx|wps';
	const EXT_FLASH = 'swf|fla|flv';
	const EXT_MEDIA = 'asf|avi|wmv|mid|mov|mp3|mp4|mpc|mpeg|mpg|rm|rmi|rmvb';
	const EXT_COMPRESSION = 'rar|zip|tar|tgz|gz';
	
	// 允许上传的扩展名内置模式
	const ALLOW_MODE_DEFAULT = 0;
	const ALLOW_MODE_GENERAL = 1;
	const ALLOW_MODE_IMAGE = 2;
	const ALLOW_MODE_DOC = 3;
	const ALLOW_MODE_FLASH = 4;
	const ALLOW_MODE_MEDIA = 5;
	const ALLOW_MODE_COMP = 6;
	
	// 子目录生成模式
	const SUB_DIR_MODE_DEFAULT = 0;
	const SUB_DIR_MODE_FULLDATE = 1;
	const SUB_DIR_MODE_YEAR = 2;
	const SUB_DIR_MODE_YEARMONTH = 3;
	const SUB_DIR_MODE_YEARMONTHDAY = 4;

	// 文件名生成规则
	// time uniqid com_create_guid getFilenameByTime
	const FILENAME_RULE_DEFAULT = 0;
	const FILENAME_RULE_TIMESTAMP = 1;
	const FILENAME_RULE_UNIQID = 2;
	const FILENAME_RULE_COM_CREATE_GUID = 3;
	const FILENAME_RULE_DATETIME = 4;

	// 上传错误代码
	const UPLOAD_ERR_BAD_FILENAME = 8;
	const UPLOAD_ERR_NO_FILEPATH = 9;
	const UPLOAD_ERR_NOT_WRITABLE = 10;
	const UPLOAD_ERR_NO_FILE_SELECTED = 11;
	const UPLOAD_ERR_INVALID_FILETYPE = 12;
	const UPLOAD_ERR_INVALID_FILESIZE = 13;
	const UPLOAD_ERR_DESTINATION_ERROR = 14;

	// 最大字节限制
	private $maxSize = -1;
	// 允许的文件扩展名
	private $allowExts = array();
	// 不允许的文件扩展名
	private $notAllowExts = array();
	// 文件名存在时是否覆盖
	private $overwrite = false; 
	// 文件名是否删除空格
	private $removeSpace = true;
	// 子目录生成模式
	private $subDirMode = 0;
	// 文件名生成规则
	private $filenameRule = 0;

	// 保存路径
	private $savePath = '';
	// 当前上传的文件名
	private $filename = '';
	// 当前上传的文件扩展名
	private $fileExt = '';
	// 文件大小
	private $fileSize = 0;

	// 错误代码
	private $errorCode = 0;
	// 错误信息数组
	private $errorMessages = array();

	// 过虑文件名中的特殊字符
	// 生成文件名
	// 创建目录
	// 设置允许的文件类型
	// 是否为图片文件
	
	public function __construct($config = array()) {
		$this->initialize($config);
	}
	
	/**
	 * 参数初始化方法
	 * @param array $config 配置项数组
	 * @return void 
	 */
	public function initialize($config = array()) {
		$default = array(
			'maxSize' => -1,
			'allowMode' => self::ALLOW_MODE_DEFAULT,
			'notAllowExts' => array(),
			'overwrite' => false,
			'removeSpace' => true,
			'subDirMode' => self::SUB_DIR_MODE_DEFAULT,
			'filenameRule' => self::FILENAME_RULE_DEFAULT,
			'savePath' => '',
		);
		
		foreach($default as $key => $val) {
			if (isset($config[$key])) {
				$method = 'set' . ucfirst($key);
				if (method_exists($this, $method)) {
					$this->$method($config[$key]);
				} else {
					$this->$key = $val;
				}
			} else {
				$this->$key = $val;
			}
		}

	}

	/**
	 * 设置文件最大允许的字节数
	 * @param int size 字节数
	 * @return void
	 */
	public function setMaxSize($size) {
		$this->maxSize = (int) $size;
	}

	/**
	 * 设置允许的扩展名模式
	 * @param int $mode 模式编号
	 * @return void
	 */
	public function setAllowMode($mode) {
		switch((int)$mode) {
			case self::ALLOW_MODE_GENERAL :
				$this->addAllowExts(self::EXT_IMAGE);
				$this->addAllowExts(self::EXT_OFFICE);
				$this->addAllowExts(self::EXT_FLASH);
				$this->addAllowExts(self::EXT_MEDIA);
				$this->addAllowExts(self::EXT_COMPRESSION);
				break;
			case self::ALLOW_MODE_IMAGE :
				$this->addAllowExts(self::EXT_IMAGE);
				break;
			case self::ALLOW_MODE_DOC :
				$this->addAllowExts(self::EXT_DOC);
				break;
			case self::ALLOW_MODE_FLASH :
				$this->addAllowExts(self::EXT_FLASH);
				break;
			case self::ALLOW_MODE_MEDIA :
				$this->addAllowExts(self::EXT_MEDIA);
				break;
			case self::ALLOW_MODE_COMP : 
				$this->addAllowExts(self::EXT_COMPRESSION);
				break;
			case self::ALLOW_MODE_DEFAULT : 
			default :
				$this->clearAllowExts();
		}
	}
	/**
	 * 设置文件名存在时是否覆盖
	 * @param bool $overwrite 是否覆盖
	 * @return void 
	 */
	public function setOverwrite($overwrite) {
		$this->overwrite = (bool) $overwrite;
	}
	
	/**
	 * 设置是否清除文件名中的空格
	 * @param bool $removeSpace 是否清除空格
	 * @return void
	 */
	public function setRemoveSpace($removeSpace) {
		$this->isRemoveSpace = (bool)$removeSpace;
	}
	
	/**
	 * 设置子目录生成模式
	 * @param int $mode 模式代码
	 * @return void 
	 */
	public function setSubDirMode($mode) {
		$mode = (int)$mode;

		$modes = array(
			self::SUB_DIR_MODE_DEFAULT,
			self::SUB_DIR_MODE_FULLDATE,
			self::SUB_DIR_MODE_YEAR,
			self::SUB_DIR_MODE_YEARMONTH,
			self::SUB_DIR_MODE_YEARMONTHDAY
		);

		if (in_array($mode, $modes)) {
			$this->subDirMode = $mode;
		} else {
			$this->subDirMode = self::SUB_DIR_MODE_DEFAULT;
		}
	}
	
	/**
	 * 设置文件名生成规则
	 * @param int $rule 规则代码
	 * @return void 
	 */
	public function setFilenameRule($rule) {
		$rule = (int)$rule;

		$rules = array(
			self::FILENAME_RULE_DEFAULT,
			self::FILENAME_RULE_TIMESTAMP,
			self::FILENAME_RULE_UNIQID,
			self::FILENAME_RULE_COM_CREATE_GUID,
			self::FILENAME_RULE_DATETIME
		);

		if (in_array($rule, $rules)) {
			$this->filenameRule = $rule;
		} else {
			$this->filenameRule = self::FILENAME_RULE_DEFAULT;
		}
	}
	
	/**
	 * 设置保存路径
	 * @param string $path 路径
	 * @return void 
	 */
	public function setSavePath($path) {
		$this->savePath = rtrim($path, '/') . '/';
	}
	
	/**
	 * 设置文件名
	 * @param string $path 路径
	 * @param string $filename 文件名
	 * @return void 
	 */
	public function setFilename($path, $filename) {
		if (!file_exists($path . $filename)) {
			return $filename;
		}
		
		$filename = str_replace('.' . $this->fileExt, '', $filename);

		$newFilename = '';
		
		for($i = 1; $i <= 10000000; $i++) {
			if (!file_exists($path . $filename . $i . '.' . $this->fileExt)) {
				$newFilename = $filename . $i . '.' . $this->fileExt;
				break;
			}
		}
		/*
		$newFilename = $this->getFilenameByTime() . '.' . $this->fileExt;;
		*/
		if (strlen($newFilename) === 0) {
			$this->setError(self::UPLOAD_ERR_BAD_FILENAME);
			return false;
		} else {
			return $newFilename;
		}
	}
	
	/**
	 * 添加允许的扩展名
	 * @params string/array $types 扩展名
	 * @return void
	 */
	public function addAllowExts($types) {
		$exts = null;
		if (!is_array($types)) {
			$exts = explode('|', trim($types));
		} else {
			$exts = $types;
		}

		foreach ($exts as $ext) {
			if (strlen($ext)) {
				$this->allowExts[] = $ext;
			}
		}	
	}

	/**
	 * 对充许的扩展名数组清空
	 * @param void 
	 * @return void
	 */
	public function clearAllowExts() {
		$this->allowExts = array();
	}
	
	/**
	 * 设置不允许的扩展名
	 * @params string/array $types 扩展名
	 * @return void
	 */
	public function setNotAllowExts($types) {
		$this->addNotAllowExts($types);
	}

	/**
	 * 添加不允许的扩展名
	 * @params string/array $types 扩展名
	 * @return void
	 */
	public function addNotAllowExts($types) {
		$exts = null;
		if (!is_array($types)) {
			$exts = explode('|', trim($types));
		} else {
			$exts = $types;
		}

		foreach ($exts as $ext) {
			if (strlen($ext)) {
				$this->notAllowExts[] = $ext;
			}		
		}	
	}

	/**
	 * 对不充许的扩展名数组清空
	 * @param void 
	 * @return void
	 */
	public function clearNotAllowExts() {
		$this->notAllowExts = array();
	}

	/**
	 * 设置错误代码
	 * @param int $code 错误代码
	 * @return void 
	 */
	public function setError($code) {
		$this->errorCode = $code;	
	}

	/**
	 * 获取子目录路径
	 * @param void 
	 * @return string
	 */
	public function getSubDirPath() {
		$path = null;

		switch ($this->subDirMode) {
			case self::SUB_DIR_MODE_FULLDATE :
				$path = date('Ymd') . '/';
				break;
			case self::SUB_DIR_MODE_YEAR :
				$path = date('Y') . '/';
				break;
			case self::SUB_DIR_MODE_YEARMONTH :
				$path = date('Y') . '/' . date('m') . '/';
				break;
			case self::SUB_DIR_MODE_YEARMONTHDAY :
				$path = date('Y') . '/' . date('m') . '/' . date('d') . '/';
				break;
			default :
				$path = '';						
		}

		return $path;
	}

	/**
	 * 获取错误信息
	 * @param void 
	 * @return string
	 */
	public function getErrorMessage() {
		if (empty($this->errorMessages)) {
			$this->errorMessages = array(	
		//		0 => '没有错误发生,文件上传成功。',
				1 => '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。',
				2 => '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。',
				3 => '文件只有部分被上传。',
				4 => '没有文件被上传。',
				6 => '找不到临时文件夹。',
				7 => '文件写入失败。',
				8 => '错误的文件名。',
				9 => '无效的上传目录。',
				10 => '上传目录不可写。',
				11 => '没有选择文件。',
				12 => !empty($this->allowExts) ? sprintf('文件类型只能是%s的扩展名。', implode(',', $this->allowExts)) : sprintf('文件类型只能是除%s之外的扩展名。', implode(',', $this->notAllowExts)), 
				13 => sprintf('文件大小超出限制, 最大%sK。', round($this->maxSize / 1024, 2)),
				14 => '文件保存失败。'
			);
		}
		return $this->errorMessages[$this->errorCode];
	}
	
	/**
	 * 上传文件
	 * @param string $field 客户端控件名
	 * @param string $savePath 保存路径
	 * @param string $filename 文件名
	 * @return bool/string
	 */
	public function upload($field, $savePath = null, $filename = null) {
		// 检查$_FILES数组是否为空
		if (!isset($_FILES[$field])) {
			$this->setError(self::UPLOAD_ERR_NO_FILE_SELECTED);
			return false;
		}
		
		if (!is_uploaded_file($_FILES[$field]['tmp_name'])) {// 上传错误
			$error = (!isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];

			switch($error) {
				case 1:	// UPLOAD_ERR_INI_SIZE
					$this->setError(UPLOAD_ERR_INI_SIZE);
					break;
				case 2: // UPLOAD_ERR_FORM_SIZE
					$this->setError(UPLOAD_ERR_FORM_SIZE);
					break;
				case 3: // UPLOAD_ERR_PARTIAL
					$this->setError(UPLOAD_ERR_PARTIAL);
					break;
				case 4: // UPLOAD_ERR_NO_FILE
					$this->setError(UPLOAD_ERR_NO_FILE);
					break;
				case 6: // UPLOAD_ERR_NO_TMP_DIR
					$this->setError(UPLOAD_ERR_NO_TMP_DIR);
					break;
				case 7: // UPLOAD_ERR_CANT_WRITE
					$this->setError(UPLOAD_ERR_CANT_WRITE);
					break;
				default :   
					$this->setError(self::UPLOAD_ERR_NO_FILE_SELECTED);
					break;
			}

			return false;
		}
		
		$this->fileSize = $_FILES[$field]['size'];		
		$this->fileExt = $this->getExt($_FILES[$field]['name']);
		
		if (!$this->isAllowedFileExt()) {// 检查扩展名
			$this->setError(self::UPLOAD_ERR_INVALID_FILETYPE);
			return false;	
		}

		if (!$this->isAllowedFilesize()) {// 检查文件大小
			$this->setError(self::UPLOAD_ERR_INVALID_FILESIZE);
			return false;
		}

		if (strlen($savePath)) {
			$this->setSavePath($savePath);
		}
		// 获取子目录路径
		$subDirPath = $this->getSubDirPath();
	
		$this->savePath = $subDirPath ? $this->savePath . $subDirPath : $this->savePath;
		
		if (!$this->validateUploadPath($this->savePath)) {// 验证上传目录
			return false;
		}

		if (strlen($filename) === 0) {// 生成文件名
			$this->filename = $this->generateFilename($field);
		} else {
			$this->filename = $filename;
		}

		if ($this->removeSpace) {// 转换空格
			$this->filename = preg_replace('/\s+/', '_', $this->filename);
		}		

		if ($this->overwrite == false) {// 不覆盖, 生成类似的文件名
			$this->filename = $this->setFilename($this->savePath, $this->filename);
			if (!$this->filename) {
				return false;
			}
		}
	
		// 保存文件
		if (!@copy($_FILES[$field]['tmp_name'], $this->savePath . $this->filename)) {
			if (!@move_uploaded_file($_FILES[$field]['tmp_name'], $this->savePath . $this->filename)) {
				$this->setError(self::UPLOAD_ERR_DESTINATION_ERROR);
				return false;
			}
		}

		return $this->savePath . $this->filename;

	}	

	/**
	 * 验证上传路径是否合法
	 * @param void 
	 * @return bool
	 */
	private function validateUploadPath() {
		if ($this->savePath == '') {
			$this->setError(self::UPLOAD_ERR_NO_FILEPATH);
			return false;
		}

		if (@realpath($this->savePath) !== false) {
			$this->savePath = str_replace('\\', '/', realpath($this->savePath)) . '/';
		}

		if (!is_dir($this->savePath)) {
			if (!$this->mkdir($this->savePath)) {
				$this->setError(self::UPLOAD_ERR_NO_FILEPATH);
				return false;
			}
		}

		if (!$this->isReallyWritable($this->savePath)) {
			$this->setError(self::UPLOAD_ERR_NOT_WRITABLE);
			return false;
		}

	//	$this->savePath = preg_replace('/(.+?)\/*$/', '\\1', $this->savePath);

		return true;
	}

	/**
	 * 创建目录
	 * @param string $path 路径
	 * @return bool
	 */
	private function mkdir($path) {
		if (is_dir($path)) {
			return true;
		}

		/*
		$paths = explode('/', $path);

		$currentPath = '';
		foreach ($paths as $dir) {
			if (strlen($dir) === 0) {
				continue;
			}

			$currentPath = strlen($currentPath) ? $currentPath . '/' . $dir : $dir;
			if (is_dir($currentPath)) {
				continue;
			}

			if (!mkdir($currentPath, 0777)) {
				return false;
			}
		}
		
		return true;
		*/
		return @mkdir($path, 0777, true);
	}
	
	/**
	 * 检查目录或文件是否可写
	 * @param string $file 目录路径或文件全路径
	 * @return bool
	 */
	private function isReallyWritable($file) {	
		// If we're on a Unix server with safe_mode off we call is_writable
		if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == false) {
			return is_writable($file);
		}

		// For windows servers and safe_mode "on" installations we'll actually
		// write a file then read it.  Bah...
		if (is_dir($file)) {
			$file = rtrim($file, '/') . '/' . md5(rand(1, 100));

			if (($fp = @fopen($file, 'ab')) === false) {
				return false;
			}

			fclose($fp);
			@chmod($file, 0777);
			@unlink($file);
			return true;
		} elseif (($fp = @fopen($file, 'ab')) === false) {
			return false;
		}

		fclose($fp);
		return true;
	}
	
	/**
	 * 将文件名的空格替换为下划线
	 * @param string $filename 文件名
	 * @return string
	 */
	private function removeSpaces($filename) {
		return preg_replace('/\s+', '_', $filename);
	}

	/**
	 * 检查扩展名是否允许
	 * @param void 
	 * @return bool
	 */
	private function isAllowedFileExt() {
		if (!empty($this->allowExts)) {
			return in_array($this->fileExt, $this->allowExts);
		} else if (!empty($this->notAllowExts)) {// 当没有设置允许时,检查不允许列表
			return !in_array($this->fileExt, $this->notAllowExts);
		} else {// 没有设置允许,同时没有设置不允许,表示类型都不限
			return true;
		}
	}
	
	/**
	 * 检查文件大小是否超出限制
	 * @param void 
	 * @return bool
	 */
	private function isAllowedFilesize() {
		if ($this->maxSize > 0 && $this->fileSize > $this->maxSize) {
			return false;
		}
		return true;
	}
	
	/**
	 * 获取扩展名
	 * @param string $filename 文件名
	 * @return string
	 */
	private function getExt($filename) {
		$array = explode('.', $filename);
		return $array ? strtolower(end($array)) : '';
	}
	
	/**
	 * 根据生成规则生成文件名
	 * @param string $field 客户端控件名
	 * @return string
	 */
	private function generateFilename($field) {
		$filename = null;
	
		switch($this->filenameRule) {
			case self::FILENAME_RULE_TIMESTAMP :
				$filename = time();
				break;
			case self::FILENAME_RULE_UNIQID :
				$filename = uniqid();
				break;
			case self::FILENAME_RULE_COM_CREATE_GUID :
				$filename = com_create_guid();
				break;
			case self::FILENAME_RULE_DATETIME : 
				$filename = $this->getFilenameByTime();
				break;
			default :
				$filename = str_replace('.' . $this->fileExt, '', $_FILES[$field]['name']);
		}

		return $filename . '.' . $this->fileExt;
	}
	
	/**
	 * 根据时间,随机数生成文件名
	 * @param void
	 * @return string
	 */
	private function getFilenameByTime() {
		$rand = mt_rand(0, 1000);
		return date('YmdHis') . str_pad($rand, 4, STR_PAD_LEFT);
	}

}

使用示例:

<?php
header('content-type:text/html; charset=utf-8');

require_once('FirePHPCore/FirePHP.class.php');

$firephp = FirePHP::getInstance(true);
$firephp->log($_POST, 'post');

$rootPath = dirname(__FILE__);

require_once 'Upload.php';

$config = array(
	'maxSize' => 1024,
	'allowMode' => Gsite_File_Upload::ALLOW_MODE_DOC,
	//'notAllowExts' => 'php',
	'overwrite' => false,
	'subDirMode' => Gsite_File_Upload::SUB_DIR_MODE_YEARMONTHDAY,
	'filenameRule' => Gsite_File_Upload::FILENAME_RULE_DEFAULT,
	'savePath' => $rootPath . '/upload'
);

$upload = new Gsite_File_Upload($config);
$result = $upload->upload('fileToUpload');
if (!$result) {
	echo json_encode(array('error' => '上传失败: ' . $upload->getErrorMessage()));
} else {
	echo json_encode(array('error' => '', 'msg' => '上传成功 ' . $result));
}
//$firephp = FirePHP::getInstance(true);
//$firephp->log($str, 'debug');

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
文件上传是网站开发中常用的功能之一,PHP文件上传可以帮助我们实现文件上传功能。当用户需要上传文件时,可以使用PHP文件上传来处理文件上传的逻辑。PHP文件上传可以实现对上传文件的各种验证,例如文件型、大小、保存路径等。通过使用PHP文件上传,可以让文件上传变得更加安全、简单和高效。 PHP文件上传可以通过封装上传文件的函数来实现文件的上传和下载。上传文件的功能通过对文件的验证和处理,将文件保存到服务器指定的位置。而下载文件的功能通过设置文件的下载头信息,实现对指定文件的下载操作。PHP文件上传还可以处理文件重名、文件大小限制、文件型限制等问题,保证文件上传过程中的安全性和完整性。 在使用PHP文件上传的过程中,需要注意对上传文件的安全性进行严格的检查,避免出现恶意文件上传或者文件被非法下载的情况。同时,需要确保服务器环境对文件上传和下载的操作进行了正确的配置,以确保文件上传和下载功能的正常运行。 总的来说,PHP文件上传可以极大地方便我们在网站开发中对文件的上传和下载操作,帮助我们完成文件处理的各种功能。无论是图片、文档还是音视频文件,PHP文件上传都可以帮助我们完成文件上传和下载功能,为网站的用户提供更好的使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值