使用thinkphp開發app后端中,需要實現一個處理上傳圖片隊列的功能
這是個上傳多圖片保存並且需要對其中一張圖片進行壓縮的功能
(使用的html5 mui框架開發app,如果直接載入原圖,app客戶端列表中圖稍微多幾張就會使得webview十分卡頓,建議在開發中,一定要對用戶上傳的圖片進行服務器端的壓縮)
之前已經寫過一篇關入如何使用html5+的uploader上傳多張圖片到服務器的博客:
http://www.cnblogs.com/devilyouwei/p/6790255.html
並且實現了在前端進行壓縮的功能(這是第一次壓縮,有用戶手機端進行)
上傳到服務器后我們還需對圖片進行處理,我這里使用的php作為后端語言,框架為thinkphp5
需要用到thinkphp的File類和Image類
File類:前者獲取到用戶上傳的file(文件)並進行路徑和文件名的操作
File類下的方法眾多,主要有以下一些,使用之前應該先打印看一下,隨意找一個文件測試一下效果,可以看的更加明白些:
$file = new File(ROOT_PATH."/public/uploads/20170506/abc.jpg");
$arr = [
'getATime' => $file->getATime(), //最后訪問時間
'getBasename' => $file->getBasename(), //獲取無路徑的basename
'getCTime' => $file->getCTime(), //獲取inode修改時間
'getExtension' => $file->getExtension(), //文件擴展名
'getFilename' => $file->getFilename(), //獲取文件名
'getGroup' => $file->getGroup(), //獲取文件組
'getInode' => $file->getInode(), //獲取文件inode
'getLinkTarget' => $file->getLinkTarget(), //獲取文件鏈接目標文件
'getMTime' => $file->getMTime(), //獲取最后修改時間
'getOwner' => $file->getOwner(), //文件擁有者
'getPath' => $file->getPath(), //不帶文件名的文件路徑
'getPathInfo' => $file->getPathInfo(), //上級路徑的SplFileInfo對象
'getPathname' => $file->getPathname(), //全路徑
'getPerms' => $file->getPerms(), //文件權限
'getRealPath' => $file->getRealPath(), //文件絕對路徑
'getSize' => $file->getSize(),//文件大小,單位字節
'getType' => $file->getType(),//文件類型 file dir link
'isDir' => $file->isDir(), //是否是目錄
'isFile' => $file->isFile(), //是否是文件
'isLink' => $file->isLink(), //是否是快捷鏈接
'isExecutable' => $file->isExecutable(), //是否可執行
'isReadable' => $file->isReadable(), //是否可讀
'isWritable' => $file->isWritable() //是否可寫
];
print_r($arr);
return false;
print_r打印到瀏覽器后:
Array
(
[getATime] => 1494041766
[getBasename] => abc.jpg
[getCTime] => 1494041766
[getExtension] => jpg
[getFilename] => abc.jpg
[getGroup] => 0
[getInode] => 0
[getLinkTarget] => D:\wamp\www\dashen\public\uploads\20170506\abc.jpg
[getMTime] => 1494041766
[getOwner] => 0
[getPath] => D:\wamp\www\dashen\/public/uploads/20170506
[getPathInfo] => SplFileInfo Object
(
[pathName:SplFileInfo:private] => D:\wamp\www\dashen\/public/uploads/20170506
[fileName:SplFileInfo:private] => 20170506
)
[getPathname] => D:\wamp\www\dashen\/public/uploads/20170506/abc.jpg
[getPerms] => 33206
[getRealPath] => D:\wamp\www\dashen\public\uploads\20170506\abc.jpg
[getSize] => 571800
[getType] => file
[isDir] =>
[isFile] => 1
[isLink] =>
[isExecutable] =>
[isReadable] => 1
[isWritable] => 1
)
關於如何用thinkphp5處理上傳的多張圖片文件,專門寫一個private方法來處理,最后返回處理好的圖片的路徑的數組
圖片處理包括:
- 將用戶上傳的圖片保存到public/uploads/目錄下
- 按照日期建立目錄,md5的編碼時間作為文件名
- 壓縮其中第一張圖片為縮略圖,專門用於預覽(也要保存到數據庫)
- 返回所有處理過圖片的路徑數組,由調用者處理后保存數據庫
代碼:
// 用戶提交疑難
public function addQues() {
// 驗證登陸session
if (!session("?user_info"))
return ['info'=>'登錄狀態失效', 'login'=>0];
$ajax['title_id'] = input('post.title_id/d');
$ajax['content'] = input('post.content/s');
$ajax['star'] = input("post.star/s");
$ajax['reward'] = input('post.reward/s');
$ajax['message'] = input('post.message/s');
$ajax['price'] = input('post.price/f');
if($ajax['reward']!="金錢懸賞")
$ajax['price'] = 0;
if ($ajax['title_id'] == null || $ajax['content'] == null || $ajax['star'] == null || $ajax['reward'] == null)
return ['info'=>'標題,內容,難度,懸賞方式不能為空', 'status'=>0];
if ($ajax['title_id'] == 0 || $ajax['content'] == "" || $ajax['star'] == "" || $ajax['reward'] == "")
return ['info'=>'標題,內容,難度,懸賞方式不能為空', 'status'=>0];
// 上傳圖片
$ajax['uid'] = session("user_info")['id'];
$ajax['create_time'] = time();
$ajax['update_time'] = $ajax['create_time'];
$ajax['ip'] = get_client_ip();
if (request()->file() != null) {
$imgs = $this->upload();
//根據imgs是否為數組鑒定是否有上傳錯誤和超范圍
if(!is_array($imgs))
return['status'=>0,'info'=>$imgs];
$ajax = array_merge($ajax, $imgs);
}
$ajax['is_del'] = 0;
$ajax['is_effect'] = 1;
$ajax['state'] = 0;
$f = db("Ques")->insert($ajax);
if ($f >= 1)
return ['status'=>1, 'info'=>'需求單提交成功'];
else
return ['status'=>0, 'info'=>'數據插入失敗'];
}
此方法中,壓縮第一張圖時需要用到原圖的文件路徑,名稱等,我保存在原圖同一目錄下,在原圖前面加上“thumb_”前綴作為區別。
調用upload方法的控制器方法(外部方法):
// 文件上傳轉儲(多文件)
// 暫且按照UNIX路徑存儲
private function upload() {
//創建的目錄名稱,日期(相對項目目錄。用於數據庫保存)
$dirName = "public".DS."uploads".DS.(date('Ymd'));
//創建保存目錄(絕對路徑。用於保存文件)
$saveDir = ROOT_PATH.DS.$dirName;
if (!file_exists($saveDir)){
mkdir($saveDir);
}
$files = request()->file();//取得上傳文件名
foreach ( $files as $key => $file ) {
// 自動生成文件名
$info = $file->rule("get_rand")->validate(['ext'=>UPLOAD_EXT,'size'=>UPLOAD_SIZE])->move($saveDir,true,false);
if ($info) {
//保存到數據的值
$data[$key] = $dirName .DS. $info->getFileName();
} else {
return $file->getError();
}
// 壓縮第一張圖
if ($key == 'img0') {
$image = Image::open($info->getRealPath());
// 保存
$thumbName = $saveDir.DS.$info->getFilename();
// 絕對路徑加上文件名
$save = $saveDir.DS."thumb_" . $info->getFilename();
$image->thumb(300, 200, Image::THUMB_CENTER)->save($save);
$data['thumbnail'] = $dirName.DS.$thumbName;
}
}
return $data;
}
}
注意:thinkphp批量上傳可能會出現同名文件覆蓋的問題,因此我們重新規定了rule()方法使用的函數,在common.php寫下一個隨機生成函數,加上時間戳,這樣重復的可能性就幾乎為0了,極不易出現重名覆蓋問題
同名覆蓋問題可能來源於上傳文件並發的轉儲,時間太短了,因為php是秒級別的UNIX時間戳,導致了產生了相同的時間戳,從而用thinkphp官方的文檔中的上傳示例代碼導致了重名覆蓋問題
//隨機生成器
function get_rand(){
$now = $_SERVER['REQUEST_TIME'];//當前系統時間,比time()多5秒
return rand().$now;
}