123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- <?php
- // +---------------------------------------------------------------------
- // | ThinkCMF [ WE CAN DO IT MORE SIMPLE ]
- // +---------------------------------------------------------------------
- // | Copyright (c) 2013-2014 http://www.thinkcmf.com All rights reserved.
- // +---------------------------------------------------------------------
- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
- // +---------------------------------------------------------------------
- // | Author: Dean <zxxjjforever@163.com>
- // +---------------------------------------------------------------------
- namespace cmf\lib;
- use huo\model\agent\AssetModel;
- use think\File;
- /**
- * ThinkCMF上传类,分块上传
- */
- class Upload {
- private $request;
- private $error = false;
- private $fileType;
- private $formName = 'file';
- public function __construct() {
- $this->request = request();
- }
- public function getError() {
- return $this->error;
- }
- public function setFileType($fileType) {
- $this->fileType = $fileType;
- }
- public function setFormName($name) {
- $this->formName = $name;
- }
- public function upload($agent_id = 0, $to_file_path = '') {
- $uploadSetting = cmf_get_upload_setting();
- $arrFileTypes = [
- 'image' => ['title' => 'Image files', 'extensions' => $uploadSetting['file_types']['image']['extensions']],
- 'video' => ['title' => 'Video files', 'extensions' => $uploadSetting['file_types']['video']['extensions']],
- 'audio' => ['title' => 'Audio files', 'extensions' => $uploadSetting['file_types']['audio']['extensions']],
- 'file' => ['title' => 'Custom files', 'extensions' => $uploadSetting['file_types']['file']['extensions']]
- ];
- $arrData = $this->request->param();
- if (empty($arrData["filetype"])) {
- $arrData["filetype"] = "image";
- }
- $fileType = $this->fileType;
- if (empty($this->fileType)) {
- $fileType = $arrData["filetype"];
- }
- if (array_key_exists($arrData["filetype"], $arrFileTypes)) {
- $extensions = $uploadSetting['file_types'][$arrData["filetype"]]['extensions'];
- $fileTypeUploadMaxFileSize = $uploadSetting['file_types'][$fileType]['upload_max_filesize'];
- } else {
- $this->error = '上传文件类型配置错误!';
- return false;
- }
- //$strPostMaxSize = ini_get("post_max_size");
- //$strUploadMaxFileSize = ini_get("upload_max_filesize");
- /**
- * 断点续传 need
- */
- header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
- header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
- header("Cache-Control: no-store, no-cache, must-revalidate");
- header("Cache-Control: post-check=0, pre-check=0", false);
- header("Pragma: no-cache");
- header("Access-Control-Allow-Origin: *"); // Support CORS
- if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { // other CORS headers if any...
- exit; // finish preflight CORS requests here
- }
- @set_time_limit(24 * 60 * 60);
- $cleanupTargetDir = false; // Remove old files
- $maxFileAge = 5 * 3600; // Temp file age in seconds
- /**
- * 断点续传 end
- */
- $app = $this->request->param('app');
- if (empty($app) || !file_exists(APP_PATH.$app)) {
- $app = 'default';
- }
- $fileImage = $this->request->file($this->formName);
- $originalName = $fileImage->getInfo('name');
- $arrAllowedExtensions = explode(',', $arrFileTypes[$fileType]['extensions']);
- $strFileExtension = strtolower(cmf_get_file_extension($originalName));
- if (!in_array($strFileExtension, $arrAllowedExtensions) || $strFileExtension == 'php') {
- $this->error = "非法文件类型!";
- return false;
- }
- $fileUploadMaxFileSize = $uploadSetting['upload_max_filesize'][$strFileExtension];
- $fileUploadMaxFileSize = empty($fileUploadMaxFileSize) ? 2097152 : $fileUploadMaxFileSize;//默认2M
- $strWebPath = "";//"upload" . DS;
- $strId = $this->request->post("id");
- $strDate = date('Ymd');
- $adminId = empty($agent_id) ? $agent_id : cmf_get_current_admin_id();
- $userId = cmf_get_current_user_id();
- $userId = empty($adminId) ? $userId : $adminId;
- $targetDir = RUNTIME_PATH."upload".DS.$userId.DS; // 断点续传 need
- if (!file_exists($targetDir)) {
- mkdir($targetDir, 0777, true);
- }
- /**
- * 断点续传 need
- */
- $strFilePath = md5($originalName);
- $chunk = $this->request->param("chunk", 0, "intval");
- $chunks = $this->request->param("chunks", 1, "intval");
- if (!$fileImage->isValid()) {
- $this->error = "非法文件!";
- return false;
- }
- if ($cleanupTargetDir) {
- if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
- $this->error = "Failed to open temp directory!";
- return false;
- }
- while (($file = readdir($dir)) !== false) {
- $tmpFilePath = $targetDir.$file;
- if ($tmpFilePath == "{$strFilePath}_{$chunk}.part"
- || $tmpFilePath == "{$strFilePath}_{$chunk}.parttmp") {
- continue;
- }
- if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpFilePath) < time() - $maxFileAge)) {
- @unlink($tmpFilePath);
- }
- }
- closedir($dir);
- }
- // Open temp file
- if (!$out = @fopen($targetDir."{$strFilePath}_{$chunk}.parttmp", "wb")) {
- $this->error = "上传文件临时目录不可写".$targetDir;
- return false;
- }
- // Read binary input stream and append it to temp file
- if (!$in = @fopen($fileImage->getInfo("tmp_name"), "rb")) {
- $this->error = "Failed to open input stream!";
- return false;
- }
- while ($buff = fread($in, 4096)) {
- fwrite($out, $buff);
- }
- @fclose($out);
- @fclose($in);
- rename($targetDir."{$strFilePath}_{$chunk}.parttmp", $targetDir."{$strFilePath}_{$chunk}.part");
- $done = true;
- for ($index = 0; $index < $chunks; $index++) {
- if (!file_exists($targetDir."{$strFilePath}_{$index}.part")) {
- $done = false;
- break;
- }
- }
- if (!$done) {
- die('');//分片没上传完
- }
- $fileSaveName = (empty($app) ? '' : $app.'/').$strDate.'/'.md5(uniqid()).".".$strFileExtension;
- $strSaveFilePath = CMF_ROOT.'public/upload/'.$fileSaveName; //TODO 测试 windows 下
- $strSaveFileDir = dirname($strSaveFilePath);
- if (!file_exists($strSaveFileDir)) {
- mkdir($strSaveFileDir, 0777, true);
- }
- // 合并临时文件
- if (!$out = @fopen($strSaveFilePath, "wb")) {
- $this->error = "上传目录不可写";
- return false;
- }
- if (flock($out, LOCK_EX)) {
- for ($index = 0; $index < $chunks; $index++) {
- if (!$in = @fopen($targetDir."{$strFilePath}_{$index}.part", "rb")) {
- break;
- }
- while ($buff = fread($in, 4096)) {
- fwrite($out, $buff);
- }
- fclose($in);
- unlink("{$targetDir}{$strFilePath}_{$index}.part");
- }
- flock($out, LOCK_UN);
- }
- @fclose($out);
- $fileImage = new File($strSaveFilePath, 'r');
- $arrInfo = [
- "name" => $originalName,
- "type" => $fileImage->getMime(),
- "tmp_name" => $strSaveFilePath,
- "error" => 0,
- "size" => $fileImage->getSize(),
- ];
- $fileImage->setSaveName($fileSaveName);
- $fileImage->setUploadInfo($arrInfo);
- /**
- * 断点续传 end
- */
- if (!$fileImage->validate(['size' => $fileUploadMaxFileSize])->check()) {
- $error = $fileImage->getError();
- unset($fileImage);
- unlink($strSaveFilePath);
- $this->error = $error;
- return false;
- }
- // $url=$first['url'];
- $storageSetting = cmf_get_cmf_settings('storage');
- $qiniuSetting = $storageSetting['Qiniu']['setting'];
- //$url=preg_replace('/^https/', $qiniu_setting['protocol'], $url);
- //$url=preg_replace('/^http/', $qiniu_setting['protocol'], $url);
- $arrInfo = [];
- if (config('FILE_UPLOAD_TYPE') == 'Qiniu' && $qiniuSetting['enable_picture_protect']) {
- //todo qiniu code ...
- // $previewUrl = $url.$qiniuSetting['style_separator'].$qiniuSetting['styles']['thumbnail300x300'];
- // $url= $url.$qiniuSetting['style_separator'].$qiniuSetting['styles']['watermark'];
- } else {
- if (empty($fileImage)) {
- $this->error = $fileImage->getError();
- return false;
- } else {
- $arrInfo["user_id"] = $userId;
- $arrInfo["file_size"] = $fileImage->getSize();
- $arrInfo["create_time"] = time();
- $arrInfo["file_md5"] = md5_file($strSaveFilePath);
- $arrInfo["file_sha1"] = sha1_file($strSaveFilePath);
- $arrInfo["file_key"] = $arrInfo["file_md5"].md5($arrInfo["file_sha1"]);
- $arrInfo["filename"] = $fileImage->getInfo("name");
- $arrInfo["file_path"] = $strWebPath.$fileSaveName;
- $arrInfo["suffix"] = $fileImage->getExtension();
- }
- }
- /* favicon.ico 图标上传特殊处理 名称为favicon.ico 并且应用为admin 替换 */
- if ('favicon.ico' == $fileImage->getInfo('name') && 'admin' == $app) {
- @copy($strSaveFilePath, CMF_ROOT.'public/admin/favicon.ico');
- @copy($strSaveFilePath, CMF_ROOT.'public/h5/favicon.ico');
- @copy($strSaveFilePath, CMF_ROOT.'public/h5m/favicon.ico');
- @copy($strSaveFilePath, CMF_ROOT.'public/agent/favicon.ico');
- @copy($strSaveFilePath, CMF_ROOT.'public/mobile/favicon.ico');
- @copy($strSaveFilePath, CMF_ROOT.'public/web/favicon.ico');
- @rename($strSaveFilePath, './favicon.ico');
- $fileImage = null;
- return [
- 'filepath' => '/favicon.ico',
- "name" => 'favicon.ico',
- 'id' => $strId,
- 'preview_url' => '/favicon.ico?'.rand(1, 9999),
- 'url' => '/favicon.ico',
- ];
- }
- /* icon-logo.png 图标上传特殊处理,SDK浮点图标 名称为icon-logo.png 并且应用为admin 替换 */
- if ('icon-logo.png' == $fileImage->getInfo('name') && 'admin' == $app) {
- @copy($strSaveFilePath, CMF_ROOT.'public/static/h5sdk/images/icon-logo.png');
- @rename($strSaveFilePath, CMF_ROOT.'public/static/sdk/images/icon-logo.png');
- $fileImage = null;
- return [
- 'filepath' => '/h5sdk/images/icon-logo.png',
- "name" => 'icon-logo.png',
- 'id' => $strId,
- 'preview_url' => STATICSITE.'/h5sdk/images/icon-logo.png?'.rand(1, 9999),
- 'url' => '/h5sdk/images/icon-logo.png',
- ];
- }
- //关闭文件对象
- $fileImage = null;
- //检查文件是否已经存在
- $assetModel = new AssetModel();
- $objAsset = $assetModel->where(["user_id" => $userId, "file_key" => $arrInfo["file_key"]])->find();
- $storage = cmf_get_option('storage');
- if (empty($storage['type'])) {
- $storage['type'] = 'Local';
- }
- $needUploadToRemoteStorage = false;//是否要上传到云存储
- if ($objAsset && $storage['type'] == 'Local') {
- $arrAsset = $objAsset->toArray();
- //$arrInfo["url"] = $this->request->domain() . $arrAsset["file_path"];
- $arrInfo["file_path"] = $arrAsset["file_path"];
- if (file_exists(CMF_ROOT.'public/upload/'.$arrInfo["file_path"])) {
- @unlink($strSaveFilePath); // 删除已经上传的文件
- } else {
- $oldFileDir = dirname(CMF_ROOT.'public/upload/'.$arrInfo["file_path"]);
- if (!file_exists($oldFileDir)) {
- mkdir($oldFileDir, 0777, true);
- }
- if (!empty($to_file_path)) {
- @rename($strSaveFilePath, $to_file_path);
- } else {
- @rename($strSaveFilePath, CMF_ROOT.'public/upload/'.$arrInfo["file_path"]);
- }
- }
- } else {
- $needUploadToRemoteStorage = true;
- $assetModel->data($arrInfo)->allowField(true)->save();
- }
- //删除临时文件
- // for ($index = 0; $index < $chunks; $index++) {
- // // echo $targetDir . "{$strFilePath}_{$index}.part";
- // @unlink($targetDir . "{$strFilePath}_{$index}.part");
- // }
- @rmdir($targetDir);
- if ($storage['type'] != 'Local') { // 增加存储驱动
- $watermark = cmf_get_plugin_config($storage['type']);
- $storage = new Storage($storage['type'], $storage['storages'][$storage['type']]);
- if ($needUploadToRemoteStorage) {
- session_write_close();
- $result = $storage->upload($arrInfo["file_path"], CMF_ROOT.'public/upload/'.$arrInfo["file_path"], $fileType);
- if (!empty($result)) {
- return array_merge(
- [
- 'filepath' => $arrInfo["file_path"],
- "name" => $arrInfo["filename"],
- "file_md5" => $arrInfo["file_md5"],
- 'id' => $strId,
- 'preview_url' => STATICSITE.'/upload/'.$arrInfo["file_path"],
- 'url' => STATICSITE.'/upload/'.$arrInfo["file_path"],
- ], $result
- );
- }
- } else {
- $previewUrl = $fileType == 'image' ? $storage->getPreviewUrl($arrInfo["file_path"])
- : $storage->getFileDownloadUrl($arrInfo["file_path"]);
- $url = $fileType == 'image' ? $storage->getImageUrl(
- $arrInfo["file_path"], $watermark['styles_watermark']
- ) : $storage->getFileDownloadUrl($arrInfo["file_path"]);
- //测试ing
- return [
- 'filepath' => $arrInfo["file_path"],
- "name" => $arrInfo["filename"],
- "file_md5" => $arrInfo["file_md5"],
- 'id' => $strId,
- 'preview_url' => $previewUrl,
- 'url' => $url,
- ];
- }
- }
- return [
- 'filepath' => $arrInfo["file_path"],
- "name" => $arrInfo["filename"],
- "file_md5" => $arrInfo["file_md5"],
- 'id' => $strId,
- 'preview_url' => STATICSITE.'/upload/'.$arrInfo["file_path"],
- 'url' => STATICSITE.'/upload/'.$arrInfo["file_path"],
- ];
- }
- }
|