文件上傳
上傳表單
在ThinkPHP中使用上傳功能無需進行特別處理。例如,下面是一個帶有附件上傳的表單提交:
<form action="__URL__/upload" enctype="multipart/form-data" method="post" >
<input type="text" name="name" />
<input type="file" name="photo" />
<input type="submit" value="提交" >
</form>
注意,要使用上傳功能 你的表單需要設置 enctype="multipart/form-data"
多文件上傳支持
如果需要使用多個文件上傳,只需要修改表單,把
<input type='file' name='photo'>
改為
<input type='file' name='photo1'>
<input type='file' name='photo2'>
<input type='file' name='photo3'>
或者
<input type='file' name='photo[]'>
<input type='file' name='photo[]'>
<input type='file' name='photo[]'>
兩種方式的多附件上傳系統的文件上傳類都可以自動識別。
上傳操作
ThinkPHP文件上傳操作使用Think\Upload
類,假設前面的表單提交到當前控制器的upload方法,我們來看下upload方法的實現代碼:
public function upload(){
$upload = new \Think\Upload();// 實例化上傳類
$upload->maxSize = 3145728 ;// 設置附件上傳大小
$upload->exts = array('jpg', 'gif', 'png', 'jpeg');// 設置附件上傳類型
$upload->rootPath = './Uploads/'; // 設置附件上傳根目錄
$upload->savePath = ''; // 設置附件上傳(子)目錄
// 上傳文件
$info = $upload->upload();
if(!$info) {// 上傳錯誤提示錯誤信息
$this->error($upload->getError());
}else{// 上傳成功
$this->success('上傳成功!');
}
}
上傳類對圖片文件的上傳安全做了支持,如果企圖上傳非法的圖像文件,系統會提示
非法圖像文件
。 為了更好的使用上傳功能,建議你的服務器開啟finfo
模塊支持
上傳參數
在上傳操作之前,我們可以對上傳的屬性進行一些設置,Upload類支持的屬性設置包括:
屬性 | 描述 |
---|---|
maxSize | 文件上傳的最大文件大小(以字節為單位),0為不限大小 |
rootPath | 文件上傳保存的根路徑 |
savePath | 文件上傳的保存路徑(相對於根路徑) |
saveName | 上傳文件的保存規則,支持數組和字符串方式定義 |
saveExt | 上傳文件的保存后綴,不設置的話使用原文件后綴 |
replace | 存在同名文件是否是覆蓋,默認為false |
exts | 允許上傳的文件后綴(留空為不限制),使用數組或者逗號分隔的字符串設置,默認為空 |
mimes | 允許上傳的文件類型(留空為不限制),使用數組或者逗號分隔的字符串設置,默認為空 |
autoSub | 自動使用子目錄保存上傳文件 默認為true |
subName | 子目錄創建方式,采用數組或者字符串方式定義 |
hash | 是否生成文件的hash編碼 默認為true |
callback | 檢測文件是否存在回調,如果存在返回文件信息數組 |
上面的屬性可以通過兩種方式傳入:
實例化傳入
我們可以在實例化的時候直接傳入參數數組,例如:
$config = array(
'maxSize' => 3145728,
'rootPath' => './Uploads/',
'savePath' => '',
'saveName' => array('uniqid',''),
'exts' => array('jpg', 'gif', 'png', 'jpeg'),
'autoSub' => true,
'subName' => array('date','Ymd'),
);
$upload = new \Think\Upload($config);// 實例化上傳類
關於saveName和subName的使用后面我們會有詳細的描述。
動態賦值
支持在實例化后動態賦值上傳參數,例如:
$upload = new \Think\Upload();// 實例化上傳類
$upload->maxSize = 3145728;
$upload->rootPath = './Uploads/';
$upload->savePath = '';
$upload->saveName = array('uniqid','');
$upload->exts = array('jpg', 'gif', 'png', 'jpeg');
$upload->autoSub = true;
$upload->subName = array('date','Ymd');
上面的設置和實例化傳入的效果是一致的。
上傳文件信息
設置好上傳的參數后,就可以調用Think\Upload
類的upload方法進行附件上傳,如果失敗,返回false,並且用getError方法獲取錯誤提示信息;如果上傳成功,就返回成功上傳的文件信息數組。
$upload = new \Think\Upload();// 實例化上傳類
$upload->maxSize = 3145728 ;// 設置附件上傳大小
$upload->exts = array('jpg', 'gif', 'png', 'jpeg');// 設置附件上傳類型
$upload->rootPath = './Uploads/'; // 設置附件上傳根目錄
$upload->savePath = ''; // 設置附件上傳(子)目錄
// 上傳文件
$info = $upload->upload();
if(!$info) {// 上傳錯誤提示錯誤信息
$this->error($upload->getError());
}else{// 上傳成功 獲取上傳文件信息
foreach($info as $file){
echo $file['savepath'].$file['savename'];
}
}
每個文件信息又是一個記錄了下面信息的數組,包括:
屬性 | 描述 |
---|---|
key | 附件上傳的表單名稱 |
savepath | 上傳文件的保存路徑 |
name | 上傳文件的原始名稱 |
savename | 上傳文件的保存名稱 |
size | 上傳文件的大小 |
type | 上傳文件的MIME類型 |
ext | 上傳文件的后綴類型 |
md5 | 上傳文件的md5哈希驗證字符串 僅當hash設置開啟后有效 |
sha1 | 上傳文件的sha1哈希驗證字符串 僅當hash設置開啟后有效 |
文件上傳成功后,就可以使用這些文件信息來進行其他的數據操作,例如保存到當前數據表或者單獨的附件數據表。
例如,下面表示把上傳信息保存到數據表的字段:
$model = M('Photo');
// 取得成功上傳的文件信息
$info = $upload->upload();
// 保存當前數據對象
$data['photo'] = $info['photo']['savename'];
$data['create_time'] = NOW_TIME;
$model->add($data);
單文件上傳
upload方法支持多文件上傳,有時候,我們只需要上傳一個文件,就可以使用Upload類提供的uploadOne方法上傳單個文件,例如:
public function upload(){
$upload = new \Think\Upload();// 實例化上傳類
$upload->maxSize = 3145728 ;// 設置附件上傳大小
$upload->exts = array('jpg', 'gif', 'png', 'jpeg');// 設置附件上傳類型
$upload->rootPath = './Uploads/'; // 設置附件上傳根目錄
// 上傳單個文件
$info = $upload->uploadOne($_FILES['photo1']);
if(!$info) {// 上傳錯誤提示錯誤信息
$this->error($upload->getError());
}else{// 上傳成功 獲取上傳文件信息
echo $info['savepath'].$info['savename'];
}
}
uploadOne方法上傳成功后返回的文件信息和upload方法的區別是只有單個文件信息的一維數組。
上傳文件的命名規則
上傳文件的命名規則(saveName)用於確保文件不會產生沖突或者覆蓋的情況。命名規則的定義可以根據你的業務邏輯來調整,不是固定的。例如,如果你采用時間戳的方式來定義命名規范,那么在同時上傳多個文件的時候可能產生沖突(因為同一秒內可以上傳多個文件),因此你需要根據你的業務需求來設置合適的上傳命名規則。這里順便來說下saveName參數的具體用法。
采用函數方式
如果傳入的字符串是一個函數名,那么表示采用函數動態生成上傳文件名(不包括文件后綴),例如:
// 采用時間戳命名
$upload->saveName = 'time';
// 采用GUID序列命名
$upload->saveName = 'com_create_guid';
也可以采用用戶自定義函數
// 采用自定義函數命名
$upload->saveName = 'myfun';
默認的命名規則設置是采用uniqid函數生成一個唯一的字符串序列。
saveName的值支持數組和字符串兩種方式,如果是只有一個參數或者沒有參數的函數,直接使用字符串設置即可,如果需要傳入額外的參數,可以使用數組方式,例如:
// 采用date函數生成命名規則 傳入Y-m-d參數
$upload->saveName = array('date','Y-m-d');
// 如果有多個參數需要傳入的話 可以使用數組
$upload->saveName = array('myFun',array('__FILE__','val1','val2'));
如果需要使用上傳的原始文件名,可以采用**FILE**傳入,所以上面的定義規則,最終的結果是 myFun('上傳文件名','val1','val2')
執行的結果。
直接設置上傳文件名
如果傳入的參數不是一個函數名,那么就會直接當做是上傳文件名,例如:
$upload->saveName = time().'_'.mt_rand();
表示上傳的文件命名采用時間戳加一個隨機數的組合字符串方式。
當然,如果覺得有必要,你還可以固定設置一個上傳文件的命名規則,用於固定保存某個上傳文件。
$upload->saveName = 'ThinkPHP';
保持上傳文件名不變
如果你想保持上傳的文件名不變,那么只需要設置命名規范為空即可,例如:
$upload->saveName = '';
一般來說不建議保持不變,因為會導致相同的文件名上傳后被覆蓋的情況。
子目錄保存
saveName只是用於設置文件的保存規則,不涉及到目錄,如果希望對上傳的文件分子目錄保存,可以設置autoSub
和subName
參數來完成,例如:
// 開啟子目錄保存 並以日期(格式為Ymd)為子目錄
$upload->autoSub = true;
$upload->subName = array('date','Ymd');
可以使用自定義函數來保存,例如:
// 開啟子目錄保存 並調用自定義函數get_user_id生成子目錄
$upload->autoSub = true;
$upload->subName = 'get_user_id';
和saveName參數一樣,subName的定義可以采用數組和字符串的方式。
注意:如果get_user_id函數未定義的話,會直接以get_user_id字符串作為子目錄的名稱保存。
子目錄保存和文件命名規則可以結合使用。
上傳驅動
上傳類可以支持不同的環境,通過相應的上傳驅動來解決,默認情況下使用本地(Local)上傳驅動,當然,你還可以設置當前默認的上傳驅動類型,例如:
'FILE_UPLOAD_TYPE' => 'Ftp',
'UPLOAD_TYPE_CONFIG' => array(
'host' => '192.168.1.200', //服務器
'port' => 21, //端口
'timeout' => 90, //超時時間
'username' => 'ftp_user', //用戶名
'password' => 'ftp_pwd', //密碼 ),
表示當前使用Ftp作為上傳類的驅動,上傳的文件會通過FTP傳到指定的遠程服務器。
也可以在實例化上傳類的時候指定,例如:
$config = array(
'maxSize' = 3145728,
'rootPath' = './Uploads/',
'savePath' = '',
'saveName' = array('uniqid',''),
'exts' = array('jpg', 'gif', 'png', 'jpeg'),
'autoSub' = true,
'subName' = array('date','Ymd'),
);
$ftpConfig = array(
'host' => '192.168.1.200', //服務器
'port' => 21, //端口
'timeout' => 90, //超時時間
'username' => 'ftp_user', //用戶名
'password' => 'ftp_pwd', //密碼 );
$upload = new \Think\Upload($config,'Ftp',$ftpConfig);// 實例化上傳類
圖像處理
使用Think\Image類進行圖像處理功能,支持Gd庫和Imagick庫,包括對GIf圖像處理的支持。
實例化類庫
$image = new \Think\Image();
默認使用GD庫進行圖像操作,如果需要使用Imagick庫操作的話,需要改成:
$image = new \Think\Image(\Think\Image::IMAGE_IMAGICK);
// 或者采用
$image = new \Think\Image('Imagick');
圖像操作
下面來看下基礎的圖像操作功能的使用方法。
打開圖像文件
假設當前入口文件目錄下面有一個1.jpg文件,如圖所示:
使用open方法打開圖像文件進行相關操作:
$image = new \Think\Image();
$image->open('./1.jpg');
也可以簡化成下面的方式:
$image = new \Think\Image(\Think\Image::IMAGE_GD,'./1.jpg'); // GD庫
// 或者
$image = new \Think\Image(\Think\Image::IMAGE_IMAGICK,'./1.jpg'); // imagick庫
獲取圖像信息
可以獲取打開圖片的信息,包括圖像大小、類型等,例如:
$image = new \Think\Image();
$image->open('./1.jpg');
$width = $image->width(); // 返回圖片的寬度
$height = $image->height(); // 返回圖片的高度
$type = $image->type(); // 返回圖片的類型
$mime = $image->mime(); // 返回圖片的mime類型
$size = $image->size(); // 返回圖片的尺寸數組 0 圖片寬度 1 圖片高度
裁剪圖片
使用crop和save方法完成裁剪圖片功能。
$image = new \Think\Image();
$image->open('./1.jpg');
//將圖片裁剪為400x400並保存為corp.jpg
$image->crop(400, 400)->save('./crop.jpg');
生成的圖片如圖:
支持從某個坐標開始裁剪,例如下面從(100,30)開始裁剪:
$image = new \Think\Image();
$image->open('./1.jpg');
//將圖片裁剪為400x400並保存為corp.jpg
$image->crop(400, 400,100,30)->save('./crop.jpg');
生成的圖片如圖:
生成縮略圖
使用thumb方法生成縮略圖
$image = new \Think\Image();
$image->open('./1.jpg');
// 按照原圖的比例生成一個最大為150*150的縮略圖並保存為thumb.jpg
$image->thumb(150, 150)->save('./thumb.jpg');
生成的縮略圖如圖所示:
我們看到實際生成的縮略圖並不是150*150,因為默認采用原圖等比例縮放的方式生成縮略圖,最大寬度是150。
可以支持其他類型的縮略圖生成,設置包括Think\Image的下列常量或者對應的數字:
IMAGE_THUMB_SCALE = 1 ; //等比例縮放類型
IMAGE_THUMB_FILLED = 2 ; //縮放后填充類型
IMAGE_THUMB_CENTER = 3 ; //居中裁剪類型
IMAGE_THUMB_NORTHWEST = 4 ; //左上角裁剪類型
IMAGE_THUMB_SOUTHEAST = 5 ; //右下角裁剪類型
IMAGE_THUMB_FIXED = 6 ; //固定尺寸縮放類型
例如:
居中裁剪
$image = new \Think\Image();
$image->open('./1.jpg');
// 生成一個居中裁剪為150*150的縮略圖並保存為thumb.jpg
$image->thumb(150, 150,\Think\Image::IMAGE_THUMB_CENTER)->save('./thumb.jpg');
居中裁剪后生成的縮略圖效果如圖:
左上角剪裁
$image = new \Think\Image();
$image->open('./1.jpg');
// 生成一個左上角裁剪為150*150的縮略圖並保存為thumb.jpg
$image->thumb(150, 150,\Think\Image::IMAGE_THUMB_NORTHWEST)->save('./thumb.jpg');
左上角裁剪后生成的縮略圖效果如圖:
縮放填充
$image = new \Think\Image();
$image->open('./1.jpg');
// 生成一個縮放后填充大小150*150的縮略圖並保存為thumb.jpg
$image->thumb(150, 150,\Think\Image::IMAGE_THUMB_FILLED)->save('./thumb.jpg');
縮放填充后生成的縮略圖效果如圖:
固定大小
$image = new \Think\Image();
$image->open('./1.jpg');
// 生成一個固定大小為150*150的縮略圖並保存為thumb.jpg
$image->thumb(150, 150,\Think\Image::IMAGE_THUMB_FIXED)->save('./thumb.jpg');
采用固定大小的縮略圖可能會有所變形,生成的縮略圖效果如圖:
添加圖片水印
$image = new \Think\Image();
$image->open('./1.jpg');
//將圖片裁剪為440x440並保存為corp.jpg
$image->crop(440, 440)->save('./crop.jpg');
// 給裁剪后的圖片添加圖片水印(水印文件位於./logo.png),位置為右下角,保存為water.gif
$image->water('./logo.png')->save("water.gif");
// 給原圖添加水印並保存為water_o.gif(需要重新打開原圖)
$image->open('./1.jpg')->water('./logo.png')->save("water_o.gif");
water方法的第二個參數表示水印的位置,可以傳入下列Think\Image類的常量或者對應的數字:
IMAGE_WATER_NORTHWEST = 1 ; //左上角水印
IMAGE_WATER_NORTH = 2 ; //上居中水印
IMAGE_WATER_NORTHEAST = 3 ; //右上角水印
IMAGE_WATER_WEST = 4 ; //左居中水印
IMAGE_WATER_CENTER = 5 ; //居中水印
IMAGE_WATER_EAST = 6 ; //右居中水印
IMAGE_WATER_SOUTHWEST = 7 ; //左下角水印
IMAGE_WATER_SOUTH = 8 ; //下居中水印
IMAGE_WATER_SOUTHEAST = 9 ; //右下角水印
例如:
$image = new \Think\Image();
// 在圖片左上角添加水印(水印文件位於./logo.png) 並保存為water.jpg
$image->open('./1.jpg')->water('./logo.png',\Think\Image::IMAGE_WATER_NORTHWEST)->save("water.jpg");
生成的圖片效果如下:
還可以支持水印圖片的透明度(0~100,默認值是80),例如:
$image = new \Think\Image();
// 在圖片左上角添加水印(水印文件位於./logo.png) 水印圖片的透明度為50 並保存為water.jpg
$image->open('./1.jpg')->water('./logo.png',\Think\Image::IMAGE_WATER_NORTHWEST,50)->save("water.jpg");
生成的效果如下:
也可以支持給圖片添加文字水印(假設在入口文件的同級目錄下存在1.ttf字體文件),例如:
$image = new \Think\Image();
// 在圖片右下角添加水印文字 ThinkPHP 並保存為new.jpg
$image->open('./1.jpg')->text('ThinkPHP','./1.ttf',20,'#000000',\Think\Image::IMAGE_WATER_SOUTHEAST)->save("new.jpg");
生成的圖片效果:
目前已經支持的上傳驅動包括Local、Ftp、Sae、Bcs、七牛和又拍雲等。