<?php
namespace Upload\Src\Store;

use Dever;
use Dever\String\Helper as Helper;
use Dever\Loader\Config;

class Core
{
	protected $data;

	protected $config;

	protected $handle;

	protected $img;

	protected $output;

	protected $limit;

	protected $name;

	protected $path;

	protected $ext = '';

	protected $file;

	protected $size;

	protected $base = '';
	
	/**
	 * __construct
	 * 
	 * @return mixed
	 */
	public function __construct($data = array())
	{
		$this->data = $data;
	}

	/**
	 * 获取根目录
	 * 
	 * @return mixed
	 */
	protected function root()
	{
		if (!$this->base) {
			$path = Config::data();
			$this->base = Dever::path($path . 'upload/');
		}

		return $this->base;
	}
	
	/**
	 * 验证数据
	 * 
	 * @return mixed
	 */
	private function check($param)
	{
		foreach ($param as $k => $v) {
			$method = 'check_' . $v;
			$this->$method();
			
			if ($this->output['status'] == -1) {
				break;
			}
		}
	}
	
	/**
	 * 验证key是否包含有后续处理的方法
	 * 
	 * @return mixed
	 */
	private function check_handle()
	{
		if (isset($this->data['key']) && strpos($this->data['key'], '_') !== false) {
			$temp = explode('_', $this->data['key']);
			$this->data['key'] = $temp[0];
			unset($temp[0]);
			foreach ($temp as $k => $v) {
				$this->handle[] = explode('=', $v);
			}
		}
	}
	
	/**
	 * 验证文件是否存在
	 * 
	 * @return mixed
	 */
	private function check_file()
	{
		if ($this->data['file']['tmp_name'] == '') {
			$this->output['status'] = -1;
			$this->output['message'] = '没有选择文件';
		}
	}
	
	/**
	 * 验证基本配置
	 * 
	 * @return mixed
	 */
	private function check_key()
	{
		if (trim($this->data['key']) == '') {
			$this->output['status'] = -1;
			$this->output['message'] = '请添加配置key';
		} else {
			$this->config = Dever::load('upload/upload-one', $this->data['key']);
			
			if (!$this->config) {
				$this->output['status'] = -1;
				$this->output['message'] = '此配置不存在';
			}
		}
	}
	
	/**
	 * 验证文件类型
	 * 
	 * @return mixed
	 */
	private function check_type()
	{
		if (!$this->ext) {
			$ext = $this->getExt($this->data['file']['tmp_name']);
			if (strpos($this->config['type'], $ext) === false) {
				$this->output['status'] = -1;
				$this->output['message'] = '文件格式不符合要求';
			}
			$this->ext = '.' . $ext;
		}
	}
	
	/**
	 * 验证文件大小
	 * 
	 * @return mixed
	 */
	private function check_size()
	{
		if ($this->config['width'] > 0 || $this->config['height'] > 0) {
			$this->limit = getimagesize($this->data['file']['tmp_name']);
		}

		# 默认30M
		$size = $this->config['size'] > 0 ? 1024*$this->config['size'] : 30*1024*1024;

		$this->size = $this->data['file']['size'];
		
		if (($size < $this->data['file']['size']) && $size > 0) {
			$this->output['status'] = -1;
			$this->output['message'] = '文件不能超过'.$size.'k';
		} elseif ($this->config['width'] > 0 && $this->config['width'] < $this->limit[0]) {
			$this->output['status'] = -1;
			$this->output['message'] = '图片宽度不能超过' . $this->config['width'] . 'px';
		} elseif ($this->config['height'] > 0 && $this->config['height'] < $this->limit[1]) {
			$this->output['status'] = -1;
			$this->output['message'] = '图片高度不能超过' . $this->config['height'] . 'px';
		}
	}
	
	/**
	 * 上传操作
	 * 
	 * @return mixed
	 */
	public function copy()
	{
		$this->output['status'] = 1; 

		if (is_string($this->data['file'])) {
			/*
			if (strpos($this->data['file'], 'http') !== false) {
				$this->output['status'] = -1;
				$this->output['message'] = '暂时不支持复制网络文件';
				return $this->output;
			}
			*/
			$this->root();

			header('Content-type: text/json; charset=utf-8');

			$path = Dever::path($this->base, 'tmp/');
			$name = urldecode($this->data['file']);
			$this->data['file'] = array();
			$this->data['file']['name'] = 'Tmp' . sha1($name);
			//$this->data['file']['name'] = 'Tmp' . Helper::rand(8) . md5(microtime() . rand(0,1000)) . '.jpg';
			$this->data['file']['tmp_name'] = $path . $this->data['file']['name'];

			if (!is_file($this->data['file']['tmp_name'])) {
				$file = Dever::curl($name);
				if (stristr($file, 'webp')) {
					$this->ext = '.jpg';
				}
				file_put_contents($this->data['file']['tmp_name'], $file);
			}
			$this->data['file']['size'] = filesize($this->data['file']['tmp_name']);
			
		} else {
			header("Content-type: application/json; charset=utf-8");
		}

		$this->check(array('handle', 'file', 'key', 'type', 'size'));

		if ($this->output['status'] == -1) {
			$this->delete();
			return $this->output;
		}
		
		$this->save();
		
		if ($this->output['status'] == -1) {
			return $this->output;
		}
		
		if (isset($this->handle) && is_array($this->handle)) {
			foreach ($this->handle as $k => $v) {
				$method = 'handle_' . $v[0];
				if (method_exists($this, $method)) {
					$this->$method($v);
				}
				$this->$method($v[1]);
			}
		} elseif (isset($this->config['alter']) && $this->config['alter']) {
			parse_str($this->config['alter'], $handle);
			if ($handle) {
				foreach ($handle as $k => $v) {
					$method = 'handle_' . $k;
					if (method_exists($this, $method)) {
						$this->$method($v);
					}
				}
			}
		}

		$this->output['status'] = 1;
		$this->output['name'] = $this->data['file']['name'];

		return $this->output;
	}

	protected function update($id)
	{
		$param['set_name'] = $this->name;
		$param['set_source_name'] = $this->data['file']['name'];
		$param['set_file'] = $this->file;
		$param['set_key'] = md5($this->output['url']);
		$param['set_ext'] = $this->ext;

		if ($this->limit) {
			$param['set_width'] = $this->limit[0];
			$param['set_height'] = $this->limit[1];
		}
		
		if ($this->size) {
			$param['set_size'] = $this->size;
		}
		
		$param['where_id'] = $id;

		Dever::load('upload/file-update', $param);
	}

	protected function insert()
	{
		$param['add_name'] = $this->name;
		$param['add_source_name'] = $this->data['file']['name'];
		$param['add_file'] = $this->file;
		$param['add_key'] = md5($this->output['url']);
		$param['add_ext'] = $this->ext;
		$param['add_upload'] = $this->data['key'];

		if ($this->limit) {
			$param['add_width'] = $this->limit[0];
			$param['add_height'] = $this->limit[1];
		}
		
		if ($this->size) {
			$param['add_size'] = $this->size;
		}
		
		$param['add_state'] = 1;


		//file_put_contents(DEVER_PATH . 'data/test', var_export($param,true));

		Dever::load('upload/file-insert', $param);
	}

	/**
	 * getExt
	 * 
	 * @return mixed
	 */
	protected function getExt($filename)
	{
		if (isset($this->data['file']['type'])) {
			$ext = $this->getExtByMine($this->data['file']['type']);
		} elseif (function_exists('finfo_open')) {
			$finfo = finfo_open(FILEINFO_MIME); // 返回 mime 类型
			$code = finfo_file($finfo, $filename);
			finfo_close($finfo);
			$temp = explode(';', $code);
			$ext = $this->getExtByMine($temp[0]);
		} else {
			$ext = $this->getExtByByte($filename);
		}
		
		if (!$ext || $ext == 'txt' || $ext == 'exe') {
			if (isset($this->data['file']['type'])) {
				$ext = $this->getExtByMine($this->data['file']['type']);
			}
			if (!$ext || $ext == 'txt' || $ext == 'exe') {
				$ext = $this->getExtByByte($filename);
			}
		}

		return $ext;
	}

	public function delete()
	{
		@unlink($this->data['file']['tmp_name']);
	}

	/**
	 * 根据mime类型获取文件扩展名
	 * 
	 * @return mixed
	 */
	protected function getExtByMine($mine)
	{
		$mine = trim($mine);
		$config = array
		(
			'application/envoy' => 'evy',
			'application/fractals' => 'fif',
			'application/futuresplash' => 'spl',
			'application/hta' => 'hta',
			'application/internet-property-stream' => 'acx',
			'application/mac-binhex40' => 'hqx',
			'application/msword' => 'doc',
			'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
			'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
			'video/x-m4v' => 'mp4',
			'video/mp4' => 'mp4',
			'application/octet-stream' => 'exe',
			'application/oda' => 'oda',
			'application/olescript' => 'axs',
			'application/pdf' => 'pdf',
			'application/pics-rules' => 'prf',
			'application/pkcs10' => 'p10',
			'application/pkix-crl' => 'crl',
			'application/postscript' => 'ai',
			'application/postscript' => 'eps',
			'application/postscript' => 'ps',
			'application/rtf' => 'rtf',
			'application/set-payment-initiation' => 'setpay',
			'application/set-registration-initiation' => 'setreg',
			'application/vnd.ms-excel' => 'xls',
			'application/vnd.ms-outlook' => 'msg',
			'application/vnd.ms-pkicertstore' => 'sst',
			'application/vnd.ms-pkiseccat' => 'cat',
			'application/vnd.ms-pkistl' => 'stl',
			'application/vnd.ms-powerpoint' => 'ppt',
			'application/vnd.ms-project' => 'mpp',
			'application/vnd.ms-works' => 'wps',
			'application/winhlp' => 'hlp',
			'application/x-bcpio' => 'bcpio',
			'application/x-cdf' => 'cdf',
			'application/x-compress' => 'z',
			'application/x-compressed' => 'tgz',
			'application/x-cpio' => 'cpio',
			'application/x-csh' => 'csh',
			'application/x-director' => 'dir',
			'application/x-dvi' => 'dvi',
			'application/x-gtar' => 'gtar',
			'application/x-gzip' => 'gz',
			'application/x-hdf' => 'hdf',
			'application/x-internet-signup' => 'isp',
			'application/x-iphone' => 'iii',
			'application/x-javascript' => 'js',
			'application/x-latex' => 'latex',
			'application/x-msaccess' => 'mdb',
			'application/x-mscardfile' => 'crd',
			'application/x-msclip' => 'clp',
			'application/x-msdownload' => 'dll',
			'application/x-msmediaview' => 'mvb',
			'application/x-msmetafile' => 'wmf',
			'application/x-msmoney' => 'mny',
			'application/x-mspublisher' => 'pub',
			'application/x-msschedule' => 'scd',
			'application/x-msterminal' => 'trm',
			'application/x-mswrite' => 'wri',
			'application/x-netcdf' => 'cdf',
			'application/x-netcdf' => 'nc',
			'application/x-perfmon' => 'pma',
			'application/x-pkcs12' => 'p12',
			'application/x-pkcs12' => 'pfx',
			'application/x-pkcs7-certificates' => 'p7b',
			'application/x-pkcs7-certreqresp' => 'p7r',
			'application/x-pkcs7-mime' => 'p7c',
			'application/x-pkcs7-signature' => 'p7s',
			'application/x-sh' => 'sh',
			'application/x-shar' => 'shar',
			'application/x-shockwave-flash' => 'swf',
			'application/x-stuffit' => 'sit',
			'application/x-sv4cpio' => 'sv4cpio',
			'application/x-sv4crc' => 'sv4crc',
			'application/x-tar' => 'tar',
			'application/x-tcl' => 'tcl',
			'application/x-tex' => 'tex',
			'application/x-texinfo' => 'texi',
			'application/x-texinfo' => 'texinfo',
			'application/x-troff' => 'roff',
			'application/x-troff' => 't',
			'application/x-troff' => 'tr',
			'application/x-troff-man' => 'man',
			'application/x-troff-me' => 'me',
			'application/x-troff-ms' => 'ms',
			'application/x-ustar' => 'ustar',
			'application/x-wais-source' => 'src',
			'application/x-x509-ca-cert' => 'cer',
			'application/ynd.ms-pkipko' => 'pko',
			'application/zip' => 'zip',
			'audio/basic' => 'au',
			'audio/basic' => 'snd',
			'audio/mid' => 'mid',
			'audio/mid' => 'rmi',
			'audio/mpeg' => 'mp3',
			'audio/mp3' => 'mp3',
			'audio/x-aiff' => 'aif',
			'audio/x-aiff' => 'aifc',
			'audio/x-aiff' => 'aiff',
			'audio/x-mpegurl' => 'm3u',
			'audio/x-pn-realaudio' => 'ram',
			'audio/x-wav' => 'wav',
			'image/bmp' => 'bmp',
			'image/cis-cod' => 'cod',
			'image/gif' => 'gif',
			'image/ief' => 'ief',
			'image/jpeg' => 'jpg',
			'image/pipeg' => 'jfif',
			'image/svg+xml' => 'svg',
			'image/tiff' => 'tif',
			'image/tiff' => 'tiff',
			'image/x-cmu-raster' => 'ras',
			'image/x-cmx' => 'cmx',
			'image/x-icon' => 'ico',
			'image/x-portable-anymap' => 'pnm',
			'image/x-portable-bitmap' => 'pbm',
			'image/x-portable-graymap' => 'pgm',
			'image/x-portable-pixmap' => 'ppm',
			'image/x-rgb' => 'rgb',
			'image/x-xbitmap' => 'xbm',
			'image/x-xpixmap' => 'xpm',
			'image/x-xwindowdump' => 'xwd',
			'message/rfc822' => 'mht',
			'message/rfc822' => 'mhtml',
			'message/rfc822' => 'nws',
			'text/css' => 'css',
			'text/h323' => '323',
			'text/html' => 'html',
			'text/iuls' => 'uls',
			'text/plain' => 'txt',
			'text/richtext' => 'rtx',
			'text/scriptlet' => 'sct',
			'text/tab-separated-values' => 'tsv',
			'text/webviewhtml' => 'htt',
			'text/x-component' => 'htc',
			'text/x-setext' => 'etx',
			'text/x-vcard' => 'vcf',
			'video/mpeg' => 'mpeg',
			'video/quicktime' => 'mov',
			'video/x-ms-asf' => 'asx',
			'video/x-msvideo' => 'avi',
			'video/x-sgi-movie' => 'movie',
			'x-world/x-vrml' => 'flr',
			'application/x-rar' => 'rar',
		);

		if (isset($config[$mine])) {
			return $config[$mine];
		} else {
			return false;
		}
	}
	
	/**
	 * getExt
	 * 
	 * @return mixed
	 */
	protected function getExtByByte($filename)
	{
		$file = fopen($filename,"rb");
		$bin = fread($file,2);
		fclose($file);
		$strInfo = @unpack("c2chars",$bin);
		$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
		$fileType = '';
		switch ($typeCode) {
			case 7790:
				$fileType = 'exe';
				break;
			case 7784:
				$fileType = 'midi';
				break;
			case 8297:
				$fileType = 'rar';
				break;
			case 255216:
				$fileType = 'jpg';
				break;
			case 7173:
				$fileType = 'gif';
				break;
			case 13780:
				$fileType = 'png';
				break;
			case 6677:
				$fileType = 'bmp';
				break;
			case 6787:
				$fileType = 'swf';
				break;
			case 6063;
				$fileType = 'php|xml';
				break;
			case 6033:
				$fileType = 'html|htm|shtml';
				break;
			case 8075:
				$fileType = 'zip';
				break;
			case 6782:
			case 1310:
				$fileType = 'txt';
				break;
			case 4742:
				$fileType = 'js';
				break;
			case 8273:
				$fileType = 'wav';
				break;
			case 7368:
				$fileType = 'mp3';
				break;
			case 3780:
				$fileType = 'pdf';
				break;
			default:
				$fileType = 'unknown'.$typeCode;
			break;
		}
		if ($strInfo['chars1'] == '-1' && $strInfo['chars2'] == '-40') {
			return 'jpg';
		}
		if ($strInfo['chars1'] == '-119' && $strInfo['chars2'] == '80') {
			return 'png';
		}
		if ($strInfo['chars1'] == '-48' && $strInfo['chars2'] == '-49') {
			return 'msi';
		}

		return $fileType;
	}
}
