<?php
// 附件模型类
class AttachmentModel extends Model {
	private $module;
	private $field;
	private $savePath;
	private $maxSize;
	private $imgResizeWidth;
	private $imgResizeHeight;
	private $imageExts = array('gif', 'jpg', 'jpeg', 'png', 'bmp');
	public $addTable = true;
	// 回调函数,用于模型初始化
	protected function _initialize($module = '') {
		// $this -> tableName = 'xxx';
		$this -> module = $module;
		$this -> maxSize = C('uploadmaxsize', 0, 'attachment');
		$this -> savePath = C('uploaddir', 0, 'attachment') . '/' . date('Y/md/');
	}
	public function setImgResize($width, $height) {
		$this -> imgResizeWidth = $width;
		$this -> imgResizeHeight = $height;
	}
	public function upload($field, $alowExts = 'jpg|jpeg|gif|bmp|png|doc|docx|xls|ppt|pdf|txt|rar|zip', $dir = '', $maxSize = 0, $isAttach = 0) {
		$this -> field = $field;
		if ($dir)$this -> savePath = $dir;
		if ($maxSize)$this -> maxSize = $maxSize;
		$uploadFiles = array();
		$description = R($field . '_description', 'post');
		if (is_array($_FILES[$field]['error'])) {
			foreach($_FILES[$field]['error'] as $key => $error) {
				if ($error == 4) continue;
				if ($error != 0) {
					$this -> error = $error;
					return false;
				}
				$uploadFiles[$key] = array('tmp_name' => $_FILES[$field]['tmp_name'][$key], 'name' => $_FILES[$field]['name'][$key], 'type' => $_FILES[$field]['type'][$key], 'size' => $_FILES[$field]['size'][$key], 'error' => $_FILES[$field]['error'][$key], 'description' => isset($description[$key])?$description[$key]:'');
			}
		} else {
			if ($_FILES[$field]['error']) {
				$this -> error = $_FILES[$field]['error'];
				return false;
			}
			$uploadFiles[0] = array('tmp_name' => $_FILES[$field]['tmp_name'], 'name' => $_FILES[$field]['name'], 'type' => $_FILES[$field]['type'], 'size' => $_FILES[$field]['size'], 'error' => $_FILES[$field]['error'], 'description' => $description);
		}
		if (!FileUtil :: create($this -> savePath)) {
			$this -> error = 8;
			return false;
		}
		if (!is_writeable($this -> savePath)) {
			$this -> error = 9;
			return false;
		}
		$attachments = array();
		foreach($uploadFiles as $k => $file) {
			$fileext = FileUtil :: fileExt($file['name']);
			if (!preg_match("/^(" . $alowExts . ")$/", $fileext)) {
				$this -> error = 10;
				return false;
			}
			if ($this -> maxSize && $file['size'] > $this -> maxSize) {
				$this -> error = 11;
				return false;
			}
			if (!$this -> isUploadFile($file['tmp_name'])) {
				$this -> error = 12;
				return false;
			}
			$saveFile = $this -> getFile($fileext, $this -> savePath);
			$saveFile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i", "_\\1\\2", $saveFile);
			if (@move_uploaded_file($file['tmp_name'], $saveFile) || @copy($file['tmp_name'], $saveFile)) {
				@chmod($saveFile, 0644);
				if (in_array($fileext, array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'swf'))) {
					$imageinfo = getimagesize($saveFile);
					list($width, $height, $type) = empty($imageinfo)?array('', '', ''):$imageinfo;
					$size = $width * $height;
					if ($size > 16777216 || $size < 16 || !in_array($type, array(1, 2, 3, 4, 6, 13))) {
						@unlink($saveFile);
						$this -> error = 5;
						return false;
					}
					if ($this -> imageCheck($saveFile) && $this -> imgResizew && $this -> imgResizeh) {
						$this -> imageResize($saveFile, $this -> imgResizew, $this -> imgResizeh);
						$file['size'] = filesize($saveFile);
					}
				}
				@unlink($file['tmp_name']);
				$tmp = array('name' => $file['name'], 'path' => $saveFile);
				if ($this -> addTable) {
					$uploadFile = array('filename' => $file['name'], 'filepath' => $saveFile, 'filesize' => $file['size'], 'fileext' => $fileext, 'description' => $file['description'], 'isimage' => in_array($fileext, $this -> imageExts)?1:0, 'isattach' => $isAttach);
					$tmp['aid'] = $this -> save($uploadFile);
				}
				$attachments[] = $tmp;
			}
		}
		if (C('deltime', 0, 'attachment')) {
			$this -> del(array('contentid=0', 'uploadtime<' . $time));
		}
		return $attachments;
	}
	public function html5Upload($name, $alowExts = 'jpg|jpeg|gif|bmp|png|doc|docx|xls|ppt|pdf|txt|rar|zip', $dir = '', $maxSize = 0, $isAttach = 0) {
		$name = urldecode($name);
		$AllowExts or $AllowExts = C('remotetype', 0, 'attachment');
		if ($dir)$this -> savePath = $dir;
		if ($maxSize)$this -> maxSize = $maxSize;
		if (!FileUtil :: create($this -> savePath)) {
			$this -> error = 8;
			return false;
		}
		if (!is_writeable($this -> savePath)) {
			$this -> error = 9;
			return false;
		}
		$fileExt = FileUtil :: fileExt($name);
		if (!preg_match("/^(" . $alowExts . ")$/", $fileExt)) {
			$this -> error = 10;
			return false;
		}
		$attachments = array();
		$saveFile = $this -> getFile($fileExt, $this -> savePath);
		$saveFile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i", "_\\1\\2", $saveFile);
		if (@file_put_contents($saveFile, file_get_contents("php://input"))) {
			$fileSize = filesize($saveFile);
			if ($this -> maxSize && $fileSize > $this -> maxSize) {
				@unlink($saveFile);
				$this -> error = 11;
				return false;
			}
			@chmod($saveFile, 0644);
			$tmp = array('name' => $name, 'path' => $saveFile);
			if ($this -> addTable) {
				$uploadFile = array('filename' => $name, 'filepath' => $saveFile, 'filesize' => filesize($saveFile), 'fileext' => $fileExt, 'description' => '', 'isimage' => in_array($fileExt, $this -> imageExts)?1:0, 'isattach' => $isAttach);
				$tmp['aid'] = $this -> save($uploadFile);
			}
			$attachments[] = $tmp;
		}
		if (C('deltime', 0, 'attachment')) {
			$this -> del(array('contentid=0', 'uploadtime<' . $time));
		}
		return $attachments;
	}
	// 删除附件
	public function del($where, $outArray = array()) {
		$r = $this -> field(array('aid', 'filepath')) -> where($where) -> select();
		if (is_array($r)) {
			$aids = array();
			foreach($r as $v) {
				if (empty($outArray) or !in_array($v['filepath'], $outArray)) {
					if (!strstr($v['filepath'], '://') && $this -> where("filepath=$v[filepath]") -> count() == 1 && file_exists($v['filepath'])) {
						@unlink($v['filepath']);
						$v['filepath'] = str_replace('.', '*.', $v['filepath']);
						foreach (glob($v['filepath']) as $filename) @unlink($filename);
					}
					$aids[] = $v['aid'];
				}
			}
			if (!empty($aids)) $this -> where('aid IN (' . implode(', ', $aids) . ')') -> delete();
		}
	}
	// 附件审核,用于内容编辑,检查是不是有些附件在内容中没有使用
	public function check($attachments, $contentid) {
		$contentid = intval($contentid);
		foreach($attachments as $k => $v) {
			strstr($v, '_thumb.') && $attachments[$k] = str_replace('_thumb.', '.', $v);
		}
		empty($attachments) or $attachments = array_unique($attachments);
		$this -> del(array('module' => $this -> module, 'contentid' => $contentid), $attachments);
	}
	public function setContentId($attachments, $contentid) {
		if (!is_array($attachments)) return false;
		foreach($attachments as $attachment) {
			$where = array('contentid' => 0, 'module' => $this -> module, 'userid' => get_cookie('userid'), 'filepath' => $attachment);
			$this -> create(array('contentid' => $contentid)) -> where($where) -> limit(1) -> update();
		}
	}
	// 附件处理(非编辑器中上传)
	public function attachement($attachments, $contentid) {
		$contentid = intval($contentid);
		if ($contentid < 1 || !is_array($attachments)) return false;
		$attachments = array_unique($attachments);
		foreach($attachments as $attachment) {
			if (!empty($attachment)) {
				$where = array('isattach' => 1, 'module' => $this -> module, 'filepath' => $attachment);
				$r = $this -> field(array('aid', 'contentid')) -> where($where) -> select();
				$isAdd = true;
				if (is_array($r)) {
					foreach($r as $t) {
						if ($t['contentid'] == 0 || $t['contentid'] == $contentid) {
							if ($t['contentid'] == 0) {
								$this -> setContentId(array($attachment), $contentid);
							}
							$isAdd = false;
							break;
						}
					}
				}
				if ($isAdd) {
					$file = pathinfo($attachment);
					$attachement = array('filename' => $file['basename'], 'filepath' => $attachment, 'filesize' => $this -> getFileSize($attachment), 'fileext' => $file['extension'], 'isimage' => in_array($file['extension'], $this -> imageExts)?1:0, 'isattach' => 1, 'contentid' => $contentid);
					$this -> save($attachement);
				}
			}
		}
	}
	public function getFileSize($attachment) {
		if (!strstr($attachment, '://')) return filesize($attachment);
		$attachment = parse_url($attachment);
		if ($fp = @fsockopen($attachment['host'], empty($attachment['port'])?80:$attachment['port'], $error)) {
			fputs($fp, "GET " . (empty($attachment['path'])?'/':$attachment['path']) . " HTTP/1.1\r\n");
			fputs($fp, "Host:$attachment[host]\r\n\r\n");
			while (!feof($fp)) {
				$tmp = fgets($fp);
				if (trim($tmp) == '') {
					break;
				} else if (preg_match('/Content-Length:(.*)/si', $tmp, $arr)) {
					return trim($arr[1]);
				}
			}
			return null;
		} else {
			return null;
		}
	}
	private function save($uploadFile) {
		if (empty($uploadFile['aid'])) {
			if (isset($uploadFile['aid'])) unset($uploadFile['aid']);
			if (empty($uploadFile['module'])) $uploadFile['module'] = $this -> module;
			$uploadFile['userid'] = get_cookie('userid');
			$uploadFile['uploadtime'] = TIME;
			$uploadFile['uploadip'] = IP;
			return $this -> create($uploadFile) -> add();
		} else {
			return $this -> create($uploadFile) -> update();
		}
	}
	private function isUploadFile($file) {
		return is_uploaded_file($file) || is_uploaded_file(str_replace('\\\\', '\\', $file));
	}
	private function getFile($fileext, $path) {
		$file = $path . date('his') . mt_rand(1000, 9999) . '.' . $fileext;
		if (file_exists($file))$this -> getFile($fileext, $path);
		return $file;
	}
	private function imageCheck($image) {
		return extension_loaded('gd') && preg_match("/\.(jpg|jpeg|gif|png)/i", $image, $m) && function_exists('imagecreatefrom' . ($m[1] == 'jpg'?'jpeg':$m[1]));
	}
	/**
	 * 缩图片自动生成函数，支持gif、jpg、png
	 */
	public function imageResize($srcFile, $dstWidth, $dstHeight, $toFile = '') {
		if (!$this -> imageCheck($srcFile)) return false;
		$toFile or $toFile = $srcFile;
		$srcInfo = getimagesize($srcFile);
		switch ($srcInfo[2]) {
			case 1:
				$im = imagecreatefromgif($srcFile);
				break;
			case 2:
				$im = imagecreatefromjpeg($srcFile);
				break;
			case 3:
				$im = imagecreatefrompng($srcFile);
				break;
			default:
				return false;
		}
		$rs = true;
		$srcWidth = ImageSX($im);
		$srcHeight = ImageSY($im);
		$dst_w = $dstWidth;
		$dst_h = $dstHeight;
		$dst_src = $dstWidth / $dstHeight - $srcWidth / $srcHeight;
		if ($dst_src > 0) {
			$dst_w = $srcWidth * ($dstHeight / $srcHeight);
		} elseif ($dst_src < 0) {
			$dst_h = $srcHeight * ($dstWidth / $srcWidth);
		}
		if ($srcWidth > $dst_w or $srcHeight > $dst_h) {
			if (function_exists("imagecreatetruecolor")) {
				$ni = imagecreatetruecolor($dst_w, $dst_h);
				if ($ni) imagecopyresampled($ni, $im, 0, 0, 0, 0, $dst_w, $dst_h, $srcWidth, $srcHeight);
				else {
					$ni = imagecreate($dst_w, $dst_h);
					imagecopyresized($ni, $im, 0, 0, 0, 0, $dst_w, $dst_h, $srcWidth, $srcHeight);
				}
			} else {
				$ni = imagecreate($dst_w, $dst_h);
				imagecopyresized($ni, $im, 0, 0, 0, 0, $dst_w, $dst_h, $srcWidth, $srcHeight);
			}
			switch ($srcInfo[2]) {
				case 1:
					imagegif($ni, $toFile);
					break;
				case 2:
					imagejpeg($ni, $toFile, C('constrainq', 0, 'attachment'));
					break;
				case 3:
					imagepng($ni, $toFile);
					break;
				default:
					$rs = false;
					break;
			}
			imagedestroy($ni);
		} else $rs = false;
		imagedestroy($im);
		return $rs;
	}
	/**
	 * 加水印
	 */
	public function waterMark($source, $target = '', $w_pos = 0, $w_img = '', $w_text = '', $w_font = 0, $w_color = '') {
		if (!$this -> imageCheck($source)) return false;
		if (!$target) $target = $source;
		$w_pos or $w_pos = C('watermarkpos', 0, 'attachment');
		$w_img or $w_img = JXCMS_ROOT . C('watermarkimg', 0, 'attachment');
		$w_text or $w_text = C('watermarktext', 0, 'attachment');
		$w_font or $w_font = C('watermarkfont', 0, 'attachment');
		$w_color or $w_color = C('watermarkcolor', 0, 'attachment');
		$source_info = getimagesize($source);
		$source_w = $source_info[0];
		$source_h = $source_info[1];
		if ($source_w < C('watermarkw', 0, 'attachment') || $source_h < C('watermarkh', 0, 'attachment')) return false;
		switch ($source_info[2]) {
			case 1 :
				$source_img = imagecreatefromgif($source);
				break;
			case 2 :
				$source_img = imagecreatefromjpeg($source);
				break;
			case 3 :
				$source_img = imagecreatefrompng($source);
				break;
			default :
				return false;
		}
		if (C('watermarktype', 0, 'attachment') == 1 && !empty($w_img) && file_exists($w_img)) {
			$ifwaterimage = 1;
			$water_info = getimagesize($w_img);
			$width = $water_info[0];
			$height = $water_info[1];
			switch ($water_info[2]) {
				case 1 :
					$water_img = imagecreatefromgif($w_img);
					break;
				case 2 :
					$water_img = imagecreatefromjpeg($w_img);
					break;
				case 3 :
					$water_img = imagecreatefrompng($w_img);
					break;
				default :
					return false;
			}
		} else {
			$ifwaterimage = 0;
			$font = C('watermarkfontn', 0, 'attachment');
			if (empty($font)) {
				$fonts = glob(JXCMS_ROOT . 'statics/mark/*.ttf');
				$rand = mt_rand(0, count($fonts) - 1);
				$font = basename($fonts[$rand]);
			}
			$font = JXCMS_ROOT . 'statics/mark/' . $font;
			$box = imagettfbbox($w_font, 0, $font, $w_text); //取得使用 truetype 字体的文本的范围
			$width = max($box[2], $box[4]) - min($box[0], $box[6]);
			$height = max($box[1], $box[3]) - min($box[5], $box[7]);
			$ax = min($box[0], $box[6]);
			$ay = min($box[5], $box[7]);
			unset($box);
		}
		$offset = 10;
		switch ($w_pos) {
			case 0:
				$wx = mt_rand($offset, ($source_w - $width - $offset));
				$wy = mt_rand($offset, ($source_h - $height - $offset));
				break;
			case 1:
				$wx = + $offset;
				$wy = + $offset;
				break;
			case 2:
				$wx = ($source_w - $width) / 2;
				$wy = + $offset;
				break;
			case 3:
				$wx = $source_w - $width - $offset;
				$wy = + $offset;
				break;
			case 4:
				$wx = + $offset;
				$wy = ($source_h - $height) / 2;
				break;
			case 5:
				$wx = ($source_w - $width) / 2;
				$wy = ($source_h - $height) / 2;
				break;
			case 6:
				$wx = $source_w - $width - $offset;
				$wy = ($source_h - $height) / 2;
				break;
			case 7:
				$wx = + $offset;
				$wy = $source_h - $height - $offset;
				break;
			case 8:
				$wx = ($source_w - $width) / 2;
				$wy = $source_h - $height - $offset;
				break;
			case 9:
				$wx = $source_w - $width - $offset;
				$wy = $source_h - $height - $offset;
				break;
		}
		imagealphablending($source_img, true);
		if ($ifwaterimage) {
			if ($water_info[2] == 3) {
				imagecopy($source_img, $water_img, $wx, $wy, 0, 0, $width, $height); //拷贝水印到目标文件
			} else {
				imagecopymerge($source_img, $water_img, $wx, $wy, 0, 0, $width, $height, C('watermarkpct', 0, 'attachment')); //拷贝水印到目标文件
			}
		} else {
			if (!empty($w_color) && (strlen($w_color) == 7)) {
				$r = hexdec(substr($w_color, 1, 2));
				$g = hexdec(substr($w_color, 3, 2));
				$b = hexdec(substr($w_color, 5));
				$bjRGB = imagecolorallocate($source_img, $r, $g, $b);
				if (function_exists('imagettftext')) {
					imagettftext($source_img, $w_font, 0, $wx - $ax, $wy - $ay, $bjRGB, $font, $w_text);
				} else {
					imagestring($source_img, $w_font, $wx, $wy, $w_text, imagecolorallocate($source_img, $r, $g, $b));
				}
			} else {
				return false;
			}
		}
		switch ($source_info[2]) {
			case 1 :
				imagegif($source_img, $target);
				break;
			case 2 :
				imagejpeg($source_img, $target, C('watermarkq', 0, 'attachment'));
				break;
			case 3 :
				imagepng($source_img, $target);
				break;
			default :
				return false;
		}
		if (isset($water_info)) {
			unset($water_info);
		}
		if (isset($water_img)) {
			imagedestroy($water_img);
		}
		unset($source_info);
		imagedestroy($source_img);
		return true;
	}
	// 分析内容,提取地址,自动上传
	public function remote($content, $AllowExts = '') {
		if (MAGIC_QUOTES_GPC)$content = stripslashes($content);
		$array = array();
		$AllowExts or $AllowExts = C('remotetype', 0, 'attachment');
		preg_match_all("/(=|\()[\"']*(http:\/\/[^\"'>]+\.($AllowExts))/i", $content, $array);
		$array = array_unique($array[2]);
		if (is_array($array)) {
			if (!FileUtil :: create($this -> savePath)) $this -> error = 8;
			else {
				$datas = FileUtil :: getMoreContent($array);
				foreach($datas as $k => $data) {
					if ($data) {
						$fileext = FileUtil :: fileExt($array[$k]); //取得扩展名
						$saveFile = $this -> getFile($fileext, $this -> savePath);
						$saveFile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i", "_\\1\\2", $saveFile);
						if (@file_put_contents($saveFile, $data)) {
							if (C('spiderwatermark', 0, 'attachment')) $this -> waterMark($saveFile);
							@chmod($saveFile, 0644);
							$content = preg_replace('/' . str_replace('/', '\/', $array[$k]) . '/', $saveFile, $content);
							$this -> addTable($saveFile, $fileext);
						}
					}
				}
			}
		}
		return MAGIC_QUOTES_GPC?addslashes($content):$content;
	}
	// 分析内容，获取第1张图片
	public function getFirstPic($content) {
		$content = stripslashes($content);
		$tmp = @preg_match("/src\s*=\s*[\"']?([^\"'>]+\.(gif|jpg|jpeg|bmp|png))/i", $content, $rs)?$rs[1]:'';
		return $tmp;
	}
	// 分析内容,提取已上传的附件地址
	public function getAttachments($content, $uploaddir = '', $AllowExts = '') {
		$content = stripslashes($content);
		$uploaddir or $uploaddir = C('uploaddir', 0, 'attachment');
		$AllowExts or $AllowExts = C('uploadimage', 0, 'attachment') . '|' . C('uploadflash', 0, 'attachment') . '|' . C('uploadmedia', 0, 'attachment') . '|' . C('uploadfile', 0, 'attachment');
		$array = array();
		preg_match_all("/(=|\()[\"']*($uploaddir\/[^\"'>]+\.($AllowExts))/i", $content, $array);
		return array_unique($array[2]);
	}
	public function remoteOneImg($path, $isThumb = 0) {
		$ext = FileUtil :: fileExt($path); //取得扩展名
		$saveFile = $this -> getFile($ext, $this -> savePath);
		if (!FileUtil :: create($this -> savePath)) {
			$this -> error = 8;
			return false;
		}
		if (C('remotemode', 0, 'attachment') == 'copy' && ini_get('allow_url_fopen')) {
			@copy($path, $saveFile);
		} else {
			$data = FileUtil :: fsockGetContents($path);
			if ($data) {
				@file_put_contents($saveFile, $data);
				@chmod($saveFile, 0644);
			}
		}
		$this -> addTable($saveFile, $ext, $isThumb);
		return $saveFile;
	}
	public function thump($path, $constrainw = 0, $constrainh = 0) {
		if (!$this -> imageCheck($path)) return '';
		$constrainw or $constrainw = C('constrainw', 0, 'attachment');
		$constrainh or $constrainh = C('constrainh', 0, 'attachment');
		if (strstr($path, '://')) {
			$path = $this -> remoteOneImg($path, 1);
			$thumb = str_replace('.', '_thumb.', $path);
			if ($this -> imageResize($path, $constrainw, $constrainh, $thumb) == false) $thumb = $path;
		} else {
			if (strstr($path, '_thumb.')) return $path;
			$thumb = str_replace('.', '_thumb.', $path);
			if ($this -> imageResize($path, $constrainw, $constrainh, $thumb) == false) $thumb = $path;
			else $this -> create(array('isthumb' => 1)) -> where('filepath = ' . $path) -> update();
		}
		return $thumb;
	}
	// 根据缩略图返回原图
	public function source($path) {
		if (strstr($path, '_thumb.')) $path = str_replace('_thumb.', '.', $path);
		return $path;
	}
	private function addTable($saveFile, $fileext, $isthumb = 0) {
		if ($this -> addTable) {
			$p = pathinfo($saveFile);
			$uploadFile = array('filename' => $p['basename'], 'filepath' => $saveFile, 'filesize' => filesize($saveFile), 'fileext' => $fileext, 'isimage' => in_array($fileext, $this -> imageExts)?1:0, 'isthumb' => $isthumb);
			return $this -> save($uploadFile);
		}
		return false;
	}
	public function error() {
		$UPLOAD_ERROR = array(0 => '文件上传成功',
			1 => '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值',
			2 => '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值',
			3 => '文件只有部分被上传',
			4 => '没有文件被上传',
			5 => '您上传的文件可能有问题',
			6 => '找不到临时文件夹。',
			7 => '文件写入临时文件夹失败',
			8 => '附件目录创建不成功',
			9 => '附件目录没有写入权限',
			10 => '不允许上传该类型文件',
			11 => '文件超过了管理员限定的大小',
			12 => '非法上传文件'
			);
		return $UPLOAD_ERROR[$this -> error];
	}
}
