用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - php代码库

大文件上传

2020-07-18 作者:云代码会员举报

[php]代码库

<?php
function testLog($content)
{
    file_put_contents("a.txt",   var_export($content, true)."\r\n", FILE_APPEND);
}
/**
 * [helper 取值简便方法]
 * @param  [String] $query   [post.arg get.arg server.arg cookie.arg]
 * @param  [type] $default [默认值]
 * @return [type]          [description]
 */
function helper($query,$default=null){
	$qus = explode('.', $query);
	if(count($qus) === 1){
		$type = strtolower($_SERVER['REQUEST_METHOD']);
	}else{
		$type = strtolower($qus[0]);
		$query = $qus[1];
	}
	switch ($type) {
		case 'post':
			return isset($_POST[$query]) ? $_POST[$query] : $default;
		case 'get':
			return isset($_GET[$query]) ? $_GET[$query] : $default;
		case 'server':
			return isset($_SERVER[$query]) ? $_SERVER[$query] : $default;
		case 'cookie':
			return isset($_COOKIE[$query]) ? $_COOKIE[$query] : $default;
		default:
			return $default;
	}
}
date_default_timezone_set('PRC');
header('Content-type: application/json');
//上传文件
testLog($_FILES);
if ($_SERVER['REQUEST_METHOD'] === 'POST'){

	if (!empty($_FILES)){
		foreach ($_FILES as $file) {
			$uploader = new Uploader();
			$info = $uploader->upload($file);
			//目前块只包含一个文件
			echo json_encode($uploader->getResult());
			die;
		}
	}
}else if($_SERVER['REQUEST_METHOD'] === 'GET'){
	//断点上传
	//获取文件基本信息
	$uploader = new Uploader();
	$upload = $uploader->getUploadInfo();
	echo json_encode($upload);
}





/**
 * 分隔文件处理
 */
class Uploader{

	/**
	 * 临时文件上传保存目录
	 */
	const UPLOAD_TMP_PATH = './_tmp/';
	/**
	 * 合并后的文件保存目录
	 */
	const UPLOAD_REAL_PATH = './upload/';

	/**
	 * 文件上传成功状态
	 */
	const STATUS_SUCCESS = 0;

	/**
	 * 文件上传失败状态
	 */
	const STATUS_MOVE_ERROR = 1;

	/**
	 * [$error 错误消息]
	 * @var string
	 */
	protected $error = '';
	/**
	 * [$code 消息代码]
	 * @var integer
	 */
	protected $code = 0;

	/**
	 * [
	 * __construct 构造方法,主要获取上传的基本信息.和服务端的数据进行对比.
	 * NOTE:可以结合文件的hash值实现文件秒传功能,原理差不多了
	 * ]
	 */
	public function __construct(){
		$this->config = array(
			'filename' => helper('filename'),
			'filesize' => intval(helper('filesize')),
			'filetype' => helper('filetype'),
			'modified' => intval(helper('modified')),
			'trunksize'=> intval(helper('trunksize'))
		);
		$this->hash = md5(serialize($this->config));
	}

	/**
	 * [upload 上传文件]
	 * @param  [type] $file [$_FILES[0]前端上传的FILE]
	 * @return [type]       [description]
	 */
	public function upload($file){
		// print_r($this->config);
		$trunk = intval(helper('post.trunk'));
		$total = helper('post.total');
		// print_r($file);
		//文件移动成功,记录文件上传指针
		$trunkname = self::UPLOAD_TMP_PATH . $this->hash . '.part.'.$trunk;

		if(@move_uploaded_file($file['tmp_name'], $trunkname)){

			static::log('success','文件'.$this->config['filename'].',块'.$trunk.'移动成功');

			$upload = $this->_uploadSuccess($trunk,$trunkname);
			if(count($upload) == $total){
				//合并文件
				$this->combineTrunkFile();
			}
			
			$this->setCode(self::STATUS_SUCCESS,'ok');
			return true;
		}

		static::log('error','文件'.$this->config['filename'].',块'.$trunk.'移动失败');

		$this->setCode(self::STATUS_MOVE_ERROR,'移动上传块'.$trunk.'失败');
		return false;
	}

	/**
	 * [setCode 设置返回消息]
	 * @param [type] $code [code]
	 * @param string $msg  [消息]
	 */
	protected function setCode($code,$msg=''){
		$this->error = $msg;
		$this->code = $code;
	}

	/**
	 * [getResult 获取结果]
	 * @return [type] [result]
	 */
	public function getResult(){
		return [
			'code'  => $this->code,
			'error' => $this->error
		];
	}

	/**
	 * [_uploadSuccess 记录上传成功的块]
	 * @param  [type] $trunk [块id]
	 * @return [type]        [返回上传所有已经上传的块]
	 */
	protected function _uploadSuccess($trunk,$trunkname){

		$log = self::UPLOAD_TMP_PATH .$this->hash.'.log';

		$uploadLog = $this->getUploadInfo();


		if(false === array_key_exists($trunk, $uploadLog['record']) 
			|| $uploadLog['record'][$trunk] < $uploadLog['trunksize']){
			$uploadLog['record'][ $trunk ] = filesize($trunkname);
			file_put_contents( $log,serialize($uploadLog) );
		}

		return $uploadLog['record'];
	}

	/**
	 * [getUploadInfo 获取服务端保存的文件上传信息]
	 * @return [type] [description]
	 */
	public function getUploadInfo(){
		$log = self::UPLOAD_TMP_PATH .$this->hash.'.log';

		if(file_exists($log)){
			$uploadLog = unserialize(file_get_contents($log));
		}else{
			$uploadLog = $this->config;
			$uploadLog['total'] = helper('post.total',0);
			$uploadLog['record'] = [];
		}

		return $uploadLog;
	}

	/**
	 * [combineTrunkFile 合并文件]
	 * @param  [type] $config [文件碎片信息]
	 * @return [type]         [description]
	 */
	public function combineTrunkFile(){
		$config = $this->getUploadInfo();

		$partname = self::UPLOAD_TMP_PATH . $this->hash . '.part.';

		$fp = fopen(self::UPLOAD_REAL_PATH . $config['filename'], 'w');
		//注意,切割的文件编号从1开始的
		for ($i=1; $i <= $config['total']; $i++) { 
			fwrite($fp, file_get_contents( $partname.$i ));
			//产出文件
			unlink($partname.$i);
		}

		static::log('success','文件'.$config['filename'].'合并成功');

		fclose($fp);
	}

	/**
	 * [log 记录上传日志]
	 * @param  string $type [description]
	 * @param  string $msg  [description]
	 * @return [type]       [description]
	 */
	public static function log($type='', $msg=''){
		$str =  sprintf('[%s] %s => %s'.PHP_EOL,date('Y-m-d H:i:s'),strtoupper($type),$msg);

		if (($fp = fopen('upload_log.log', 'a+')) !== false) {
	        fputs($fp, $str);
	        fclose($fp);
	    }

	}


}


分享到:
更多

网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。