<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- // | Copyright (c) 2009 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- // $Id$ /** +------------------------------------------------------------------------------ * 文件上傳類 +------------------------------------------------------------------------------ * @category ORG * @package ORG * @subpackage Net * @author liu21st <liu21st@gmail.com> * @version $Id$ +------------------------------------------------------------------------------ */ class UploadFile {//類定義開始 // 上傳文件的最大值 public $maxSize = -1; // 是否支持多文件上傳 public $supportMulti = true; // 容許上傳的文件後綴 // 留空不做後綴檢查 public $allowExts = array(); // 容許上傳的文件類型 // 留空不作檢查 public $allowTypes = array(); // 使用對上傳圖片進行縮略圖處理 public $thumb = true; // 縮略圖最大寬度 public $thumbWidth=400; // 縮略圖最大高度 public $thumbHeight=400; // 縮略圖前綴 public $thumbPrefix = 'thumb_'; public $thumbSuffix = ','; // 縮略圖保存路徑 public $thumbPath = ''; // 縮略圖文件名 public $thumbFile =''; // 是否移除原圖 public $thumbRemoveOrigin =true; // 啓用子目錄保存文件 public $autoSub = false; // 子目錄建立方式 能夠使用hash date public $subType = 'date'; public $dateFormat = 'Ym'; public $hashLevel = 1; // hash的目錄層次 // 上傳文件保存路徑 public $savePath = ''; public $autoCheck = true; // 是否自動檢查附件 // 存在同名是否覆蓋 public $uploadReplace = false; // 上傳文件命名規則 // 例如能夠是 time uniqid com_create_guid 等 // 必須是一個無需任何參數的函數名 能夠使用自定義函數 public $saveRule = 'uniqid'; // 錯誤信息 private $error = ''; // 上傳成功的文件信息 private $uploadFileInfo ; /** +---------------------------------------------------------- * 架構函數 +---------------------------------------------------------- * @access public +---------------------------------------------------------- */ public function __construct($maxSize='',$allowExts='',$allowTypes='',$savePath='',$saveRule='') { if(!empty($maxSize) && is_numeric($maxSize)) { $this->maxSize = $maxSize; } if(!empty($allowExts)) { if(is_array($allowExts)) { $this->allowExts = array_map('strtolower',$allowExts); }else { $this->allowExts = explode(',',strtolower($allowExts)); } } if(!empty($allowTypes)) { if(is_array($allowTypes)) { $this->allowTypes = array_map('strtolower',$allowTypes); }else { $this->allowTypes = explode(',',strtolower($allowTypes)); } } if(!empty($saveRule)) { $this->saveRule = $saveRule; } $this->savePath .= $savePath; } /** +---------------------------------------------------------- * 上傳一個文件 +---------------------------------------------------------- * @access public +---------------------------------------------------------- * @param mixed $name 數據 * @param string $value 數據表名 +---------------------------------------------------------- * @return string +---------------------------------------------------------- * @throws ThinkExecption +---------------------------------------------------------- */ private function save(&$file) { $filename = $file['savepath'].$file['savename']; if(!$this->uploadReplace && is_file($filename)) { // 不覆蓋同名文件 $this->error = '文件已經存在!'.$filename; return false; } // 若是是圖像文件 檢測文件格式 if( in_array(strtolower($file['extension']),array('gif','jpg','jpeg','bmp','png','swf')) && false === getimagesize($file['tmp_name'])) { $this->error = '非法圖像文件'; return false; } if(!move_uploaded_file($file['tmp_name'],$filename)) { $this->error = '文件上傳保存錯誤!'; return false; } if($this->thumb && in_array(strtolower($file['extension']),array('gif','jpg','jpeg','bmp','png'))) { $image = getimagesize($filename); if(false !== $image) { //是圖像文件生成縮略圖 $thumbPath = $this->thumbPath?$this->thumbPath:$file['savepath']; $realFilename = $this->autoSub?basename($file['savename']):$file['savename']; $thumbname=$this->thumbPrefix.substr($realFilename,0,strrpos($realFilename, '.')).'.'.$file['extension']; if(Image::thumb($filename,$thumbPath.$thumbname,'',$this->thumbWidth,$this->thumbHeight,true)){ $file['thumb']=$thumbname; } if($this->thumbRemoveOrigin) { // 生成縮略圖以後刪除原圖 unlink($filename); } } } return true; } /** +---------------------------------------------------------- * 上傳全部文件 +---------------------------------------------------------- * @access public +---------------------------------------------------------- * @param string $savePath 上傳文件保存路徑 +---------------------------------------------------------- * @return string +---------------------------------------------------------- * @throws ThinkExecption +---------------------------------------------------------- */ public function upload($savePath ='') { //若是不指定保存文件名,則由系統默認 if(empty($savePath)) $savePath = $this->savePath; // 檢查上傳目錄 if(!is_dir($savePath)) { // 檢查目錄是否編碼後的 if(is_dir(base64_decode($savePath))) { $savePath = base64_decode($savePath); }else{ // 嘗試建立目錄 if(!mkdir($savePath)){ $this->error = '上傳目錄'.$savePath.'不存在'; return false; } } }else { if(!is_writeable($savePath)) { $this->error = '上傳目錄'.$savePath.'不可寫'; return false; } } $fileInfo = array(); $isUpload = false; // 獲取上傳的文件信息 // 對$_FILES數組信息處理 $files = $this->dealFiles($_FILES); foreach($files as $key => $file) { //過濾無效的上傳 if(!empty($file['name'])) { //登記上傳文件的擴展信息 $file['key'] = $key; $file['extension'] = $this->getExt($file['name']); $file['savepath'] = $savePath; $file['savename'] = $this->getSaveName($file); // 自動檢查附件 if($this->autoCheck) { if(!$this->check($file)) return false; } //保存上傳文件 if(!$this->save($file)) return false; //上傳成功後保存文件信息,供其餘地方調用 unset($file['tmp_name'],$file['error']); $fileInfo[] = $file; $isUpload = true; } } if($isUpload) { $this->uploadFileInfo = $fileInfo; return true; }else { $this->error = '沒有選擇上傳文件'; return false; } } /** +---------------------------------------------------------- * 上傳單個上傳字段中的文件 支持多附件 +---------------------------------------------------------- * @access public +---------------------------------------------------------- * @param array $file 上傳文件信息 * @param string $savePath 上傳文件保存路徑 +---------------------------------------------------------- * @return string +---------------------------------------------------------- * @throws ThinkExecption +---------------------------------------------------------- */ public function uploadOne($file,$savePath=''){ //若是不指定保存文件名,則由系統默認 if(empty($savePath)) $savePath = $this->savePath; // 檢查上傳目錄 if(!is_dir($savePath)) { // 嘗試建立目錄 if(!mkdir($savePath)){ $this->error = '上傳目錄'.$savePath.'不存在'; return false; } }else { if(!is_writeable($savePath)) { $this->error = '上傳目錄'.$savePath.'不可寫'; return false; } } //過濾無效的上傳 if(!empty($file['name'])) { $fileArray = array(); if(is_array($file['name'])) { $keys = array_keys($file); $count = count($file['name']); for ($i=0; $i<$count; $i++) { foreach ($keys as $key) $fileArray[$i][$key] = $file[$key][$i]; } }else{ $fileArray[] = $file; } $info = array(); foreach ($fileArray as $key=>$file){ //登記上傳文件的擴展信息 $file['extension'] = $this->getExt($file['name']); $file['savepath'] = $savePath; $file['savename'] = $this->getSaveName($file); // 自動檢查附件 if($this->autoCheck) { if(!$this->check($file)) return false; } //保存上傳文件 if(!$this->save($file)) return false; unset($file['tmp_name'],$file['error']); $info[] = $file; $isUpload=true; } if($isUpload) { $this->uploadFileInfo = $info; return true; // 返回上傳的文件信息 } }else { $this->error = '沒有選擇上傳文件'; return false; } } /** +---------------------------------------------------------- * 轉換上傳文件數組變量爲正確的方式 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param array $files 上傳的文件變量 +---------------------------------------------------------- * @return array +---------------------------------------------------------- */ private function dealFiles($files) { $fileArray = array(); $n = 0; foreach ($files as $file){ if(is_array($file['name'])) { $keys = array_keys($file); $count = count($file['name']); for ($i=0; $i<$count; $i++) { foreach ($keys as $key) $fileArray[$n][$key] = $file[$key][$i]; $n++; } }else{ $fileArray[$n] = $file; $n++; } } return $fileArray; } /** +---------------------------------------------------------- * 獲取錯誤代碼信息 +---------------------------------------------------------- * @access public +---------------------------------------------------------- * @param string $errorNo 錯誤號碼 +---------------------------------------------------------- * @return void +---------------------------------------------------------- * @throws ThinkExecption +---------------------------------------------------------- */ protected function error($errorNo) { switch($errorNo) { case 1: $this->error = '上傳的文件超過了 php.ini 中 upload_max_filesize 選項限制的值'; break; case 2: $this->error = '上傳文件的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值'; break; case 3: $this->error = '文件只有部分被上傳'; break; case 4: $this->error = '沒有文件被上傳'; break; case 6: $this->error = '找不到臨時文件夾'; break; case 7: $this->error = '文件寫入失敗'; break; default: $this->error = '未知上傳錯誤!'; } return ; } /** +---------------------------------------------------------- * 根據上傳文件命名規則取得保存文件名 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param string $filename 數據 +---------------------------------------------------------- * @return string +---------------------------------------------------------- */ private function getSaveName($filename) { $rule = $this->saveRule; if(empty($rule)) {//沒有定義命名規則,則保持文件名不變 $saveName = $filename['name']; }else { if(function_exists($rule)) { //使用函數生成一個惟一文件標識號 $saveName = $rule().".".$filename['extension']; }else { //使用給定的文件名做爲標識號 $saveName = $rule.".".$filename['extension']; } } if($this->autoSub) { // 使用子目錄保存文件 $filename['savename'] = $saveName; $saveName = $this->getSubName($filename).'/'.$saveName; } return $saveName; } /** +---------------------------------------------------------- * 獲取子目錄的名稱 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param array $file 上傳的文件信息 +---------------------------------------------------------- * @return string +---------------------------------------------------------- */ private function getSubName($file) { switch($this->subType) { case 'date': $dir = date($this->dateFormat,time()); break; case 'hash': default: $name = md5($file['savename']); $dir = ''; for($i=0;$i<$this->hashLevel;$i++) { $dir .= $name{$i}.'/'; } break; } if(!is_dir($file['savepath'].$dir)) { mkdir($file['savepath'].$dir); } return $dir; } /** +---------------------------------------------------------- * 檢查上傳的文件 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param array $file 文件信息 +---------------------------------------------------------- * @return boolean +---------------------------------------------------------- */ private function check($file) { if($file['error']!== 0) { //文件上傳失敗 //捕獲錯誤代碼 $this->error($file['error']); return false; } //文件上傳成功,進行自定義規則檢查 //檢查文件大小 if(!$this->checkSize($file['size'])) { $this->error = '上傳文件大小不符!'; return false; } //檢查文件Mime類型 if(!$this->checkType($file['type'])) { $this->error = '上傳文件MIME類型不容許!'; return false; } //檢查文件類型 if(!$this->checkExt($file['extension'])) { $this->error ='上傳文件類型不容許'; return false; } //檢查是否合法上傳 if(!$this->checkUpload($file['tmp_name'])) { $this->error = '非法上傳文件!'; return false; } return true; } /** +---------------------------------------------------------- * 檢查上傳的文件類型是否合法 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param string $type 數據 +---------------------------------------------------------- * @return boolean +---------------------------------------------------------- */ private function checkType($type) { if(!empty($this->allowTypes)) return in_array(strtolower($type),$this->allowTypes); return true; } /** +---------------------------------------------------------- * 檢查上傳的文件後綴是否合法 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param string $ext 後綴名 +---------------------------------------------------------- * @return boolean +---------------------------------------------------------- */ private function checkExt($ext) { if(!empty($this->allowExts)) return in_array(strtolower($ext),$this->allowExts,true); return true; } /** +---------------------------------------------------------- * 檢查文件大小是否合法 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param integer $size 數據 +---------------------------------------------------------- * @return boolean +---------------------------------------------------------- */ private function checkSize($size) { return !($size > $this->maxSize) || (-1 == $this->maxSize); } /** +---------------------------------------------------------- * 檢查文件是否非法提交 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param string $filename 文件名 +---------------------------------------------------------- * @return boolean +---------------------------------------------------------- */ private function checkUpload($filename) { return is_uploaded_file($filename); } /** +---------------------------------------------------------- * 取得上傳文件的後綴 +---------------------------------------------------------- * @access private +---------------------------------------------------------- * @param string $filename 文件名 +---------------------------------------------------------- * @return boolean +---------------------------------------------------------- */ private function getExt($filename) { $pathinfo = pathinfo($filename); return $pathinfo['extension']; } /** +---------------------------------------------------------- * 取得上傳文件的信息 +---------------------------------------------------------- * @access public +---------------------------------------------------------- * @return array +---------------------------------------------------------- */ public function getUploadFileInfo() { return $this->uploadFileInfo; } /** +---------------------------------------------------------- * 取得最後一次錯誤信息 +---------------------------------------------------------- * @access public +---------------------------------------------------------- * @return string +---------------------------------------------------------- */ public function getErrorMsg() { return $this->error; } }//類定義結束 ?> <?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- // | Copyright (c) 2009 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- // $Id$ /** +------------------------------------------------------------------------------ * 圖像操做類庫 +------------------------------------------------------------------------------ * @category ORG * @package ORG * @subpackage Util * @author liu21st <liu21st@gmail.com> * @version $Id$ +------------------------------------------------------------------------------ */ class Image{//類定義開始 /** +---------------------------------------------------------- * 取得圖像信息 * +---------------------------------------------------------- * @static * @access public +---------------------------------------------------------- * @param string $image 圖像文件名 +---------------------------------------------------------- * @return mixed +---------------------------------------------------------- */ static function getImageInfo($img) { $imageInfo = getimagesize($img); if ($imageInfo !== false) { $imageType = strtolower(substr(image_type_to_extension($imageInfo[2]), 1)); $imageSize = filesize($img); $info = array( "width" => $imageInfo[0], "height" => $imageInfo[1], "type" => $imageType, "size" => $imageSize, "mime" => $imageInfo['mime'] ); return $info; } else { return false; } } /** +---------------------------------------------------------- * 爲圖片添加水印 +---------------------------------------------------------- * @static public +---------------------------------------------------------- * @param string $source 原文件名 * @param string $water 水印圖片 * @param string $$savename 添加水印後的圖片名 * @param string $alpha 水印的透明度 +---------------------------------------------------------- * @return string +---------------------------------------------------------- * @throws ThinkExecption +---------------------------------------------------------- */ static public function water($source, $water, $savename=null, $alpha=80) { //檢查文件是否存在 if (!file_exists($source) || !file_exists($water)) return false; //圖片信息 $sInfo = self::getImageInfo($source); $wInfo = self::getImageInfo($water); //若是圖片小於水印圖片,不生成圖片 if ($sInfo["width"] < $wInfo["width"] || $sInfo['height'] < $wInfo['height']) return false; //創建圖像 $sCreateFun = "imagecreatefrom" . $sInfo['type']; $sImage = $sCreateFun($source); $wCreateFun = "imagecreatefrom" . $wInfo['type']; $wImage = $wCreateFun($water); //設定圖像的混色模式 imagealphablending($wImage, true); //圖像位置,默認爲右下角右對齊 $posY = $sInfo["height"] - $wInfo["height"]; $posX = $sInfo["width"] - $wInfo["width"]; //生成混合圖像 imagecopymerge($sImage, $wImage, $posX, $posY, 0, 0, $wInfo['width'], $wInfo['height'], $alpha); //輸出圖像 $ImageFun = 'Image' . $sInfo['type']; //若是沒有給出保存文件名,默認爲原圖像名 if (!$savename) { $savename = $source; @unlink($source); } //保存圖像 $ImageFun($sImage, $savename); imagedestroy($sImage); return true; } /** +---------------------------------------------------------- * 生成縮略圖 +---------------------------------------------------------- * @static * @access public +---------------------------------------------------------- * @param string $image 原圖 * @param string $type 圖像格式 * @param string $thumbname 縮略圖文件名 * @param string $maxWidth 寬度 * @param string $maxHeight 高度 * @param string $position 縮略圖保存目錄 * @param boolean $interlace 啓用隔行掃描 +---------------------------------------------------------- * @return void +---------------------------------------------------------- */ static function thumb($image, $thumbname, $type='', $maxWidth=200, $maxHeight=50, $interlace=true) { // 獲取原圖信息 $info = Image::getImageInfo($image); if ($info !== false) { $srcWidth = $info['width']; $srcHeight = $info['height']; $type = empty($type) ? $info['type'] : $type; $type = strtolower($type); $interlace = $interlace ? 1 : 0; unset($info); $scale = min($maxWidth / $srcWidth, $maxHeight / $srcHeight); // 計算縮放比例 if ($scale >= 1) { // 超過原圖大小再也不縮略 $width = $srcWidth; $height = $srcHeight; } else { // 縮略圖尺寸 $width = (int) ($srcWidth * $scale); $height = (int) ($srcHeight * $scale); } // 載入原圖 $createFun = 'ImageCreateFrom' . ($type == 'jpg' ? 'jpeg' : $type); $srcImg = $createFun($image); //建立縮略圖 if ($type != 'gif' && function_exists('imagecreatetruecolor')) $thumbImg = imagecreatetruecolor($width, $height); else $thumbImg = imagecreate($width, $height); // 複製圖片 if (function_exists("ImageCopyResampled")) imagecopyresampled($thumbImg, $srcImg, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight); else imagecopyresized($thumbImg, $srcImg, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight); if ('gif' == $type || 'png' == $type) { //imagealphablending($thumbImg, false);//取消默認的混色模式 //imagesavealpha($thumbImg,true);//設定保存完整的 alpha 通道信息 $background_color = imagecolorallocate($thumbImg, 0, 255, 0); // 指派一個綠色 imagecolortransparent($thumbImg, $background_color); // 設置爲透明色,若註釋掉該行則輸出綠色的圖 } // 對jpeg圖形設置隔行掃描 if ('jpg' == $type || 'jpeg' == $type) imageinterlace($thumbImg, $interlace); //$gray=ImageColorAllocate($thumbImg,255,0,0); //ImageString($thumbImg,2,5,5,"ThinkPHP",$gray); // 生成圖片 $imageFun = 'image' . ($type == 'jpg' ? 'jpeg' : $type); $imageFun($thumbImg, $thumbname); imagedestroy($thumbImg); imagedestroy($srcImg); return $thumbname; } return false; } } //類定義結束 ?> 測試文件 <?php header("Content-type:text/html;charset=utf-8"); require "UploadFile.class.php"; require "Image.class.php"; $upload=new UploadFile(); if(!$upload->uploadOne($_FILES['name'],ROOT.'upload/')){ $upload->getErrorMsg(); }else{ $list=$upload->getUploadFileInfo(); $info=array(); foreach ($list as $val){ $info=$val; } $water=ROOT.'data/logo.png'; $source=$info['savepath'].$info['thumb']; $savename='water'.$info['savename']; if(Image::water($source, $water)){ } var_dump($info); } ?>