/** * 静态方法, 单例统一访问入口 * @return object 返回对象的唯一实例 */ public static function getInstance() { if (is_null(self::$_instance) || !isset(self::$_instance)) { self::$_instance = new self(); } return self::$_instance; }
/** * 迷你存储报俊 * @param string $path 用户文件的存储路径 * @param string $signature 文件sha1 * @param int $size 文件大小,单位字节 * @param int $nodeId 迷你存储节点值 */ public function report($path, $signature, $size, $nodeId) { //防止重复文件通过网页上传,生成多条记录 $version = MiniVersion::getInstance()->getBySignature($signature); if (empty($version)) { //创建version/versionMeta数据 $pathParts = pathinfo($path); $type = MiniUtil::getMimeType($pathParts["basename"]); $version = MiniVersion::getInstance()->create($signature, $size, $type); MiniVersionMeta::getInstance()->create($version["id"], "store_id", $nodeId); //更新迷你存储节点状态,把新上传的文件数+1 PluginMiniStoreNode::getInstance()->newUploadFile($nodeId); //清理垃圾数据 PluginMiniBreakFile::getInstance()->deleteBySignature($signature); } //执行文件秒传逻辑 $filesController = new MFileSecondsController(); $filesController->invoke(); }
/** *根据文件的Hash值下载内容 * @param string $signature 文件hash值 * @throws 404错误 */ public function downloadTxt($signature) { $version = MiniVersion::getInstance()->getBySignature($signature); if (!empty($version)) { //根据文件内容输出文件内容 $meta = MiniVersionMeta::getInstance()->getMeta($version["id"], "doc_id"); if (!empty($meta)) { $url = PluginMiniDocNode::getInstance()->getDownloadUrl($meta["meta_value"], $version, "txt"); if (!empty($url)) { header("HTTP/1.1 " . MConst::HTTP_CODE_301 . " Moved Permanently"); header("Location: " . $url); exit; } } else { //文本类文件直接下载 MiniFile::getInstance()->getContentBySignature($signature, $signature, $version["mime_type"]); } } throw new MFileopsException(Yii::t('api', 'File Not Found'), 404); }
/** * 获得有效文件下载服务器节点 * 找到min(downloaded_file_count) and status=1的记录分配 * @param string $signature 文件内容hash * @return array */ private function getDownloadNode($signature) { $version = MiniVersion::getInstance()->getBySignature($signature); if (!empty($version)) { $metaKey = "store_id"; $meta = MiniVersionMeta::getInstance()->getMeta($version["id"], $metaKey); if (!empty($meta)) { $value = $meta["meta_value"]; $ids = explode(",", $value); $nodes = $this->getNodeList(); $validNodes = array(); foreach ($nodes as $node) { //先找到当前文件存储的节点 $isValidNode = false; foreach ($ids as $validNodeId) { if ($validNodeId == $node["id"]) { $isValidNode = true; } } if (!$isValidNode) { continue; } //然后判断节点是否有效,并在有效的节点找到下载次数最小的节点 if ($node["status"] == 1) { array_push($validNodes, $node); } } //选出downloaded_file_count最小的个节点 $validNodes = MiniUtil::arraySort($validNodes, "downloaded_file_count", SORT_ASC); $nodes = MiniUtil::getFistArray($validNodes, 1); if (count($nodes) > 0) { $node = $nodes[0]; $urlInfo = parse_url($node["host"]); if ($urlInfo["host"] == "127.0.0.1") { //说明迷你存储在本机,直接把127.0.0.1替换为迷你存储端口 $defaultHost = MiniHttp::getMiniHost(); $miniHostInfo = parse_url($defaultHost); $node['host'] = $miniHostInfo["scheme"] . "://" . $miniHostInfo["host"] . ":" . $urlInfo["port"] . $miniHostInfo["path"]; } return $node; } return null; } } return null; }
/** * 更改文档转换状态 * doc_convert_status:-1 表示转换失败 * doc_convert_status:0 表示尚未转换 * doc_convert_status:1 表示正在转换 * doc_convert_status:2 表示转换成功 * @param int $nodeId 文档转换节点ID * @param string $signature 文件内容hash值 * @param int $status 文件转换状态值 * @return boolean */ public function updateDocConvertStatus($nodeId, $signature, $status) { $versionItem = FileVersion::model()->find("file_signature=:signature", array("signature" => $signature)); if (isset($versionItem)) { $versionItem["doc_convert_status"] = $status; $versionItem->save(); //文档转换成功,为meta添加记录,便于二次寻找迷你文档服务器 if ($status == 2) { MiniVersionMeta::getInstance()->create($versionItem->id, "doc_id", $nodeId); } return true; } return false; }
/** * 删除记录 * @param $id */ public function deleteById($id) { $item = FileVersion::model()->findByPk($id); if (isset($item)) { MiniVersionMeta::getInstance()->deleteByVersionId($id); $item->delete(); } }
/** * 获得迷你文档转换服务器节点 * @param string $signature * @return string */ public function getConvertNode($signature) { //寻找以前迷你文档节点 $version = PluginMiniDocVersion::getInstance()->getBySignature($signature); if (!empty($version)) { $meta = MiniVersionMeta::getInstance()->getMeta($version["id"], "doc_id"); if (!empty($meta)) { $nodeId = $meta["meta_value"]; $node = $this->getNodeById($nodeId); if ($node["status"] == 1) { return $node; } } } //返回随机converted_file_count最小的节点 $nodes = $this->getNodeList(); $validNodes = array(); foreach ($nodes as $itemNode) { if ($itemNode["status"] == 1) { array_push($validNodes, $itemNode); } } //选出converted_file_count最小的个节点 $validNodes = MiniUtil::arraySort($validNodes, "converted_file_count", SORT_ASC); $nodes = MiniUtil::getFistArray($validNodes, 1); if (count($nodes) > 0) { return $nodes[0]; } return null; }
/** * 创建对象 */ public function create() { // 查询文件信息 $path = MiniUtil::getAbsolutePath($this->user_id, $this->path); $file = MiniFile::getInstance()->getByPath($path); if (empty($file)) { throw new MException(Yii::t('api', MConst::PATH_ERROR), MConst::HTTP_CODE_404); } $fileName = $file["file_name"]; $fileSize = $file["file_size"]; $versionId = $file["version_id"]; // 检查是否支持缩略图 $this->checkExistThumbnail($fileName, $fileSize); // 获取文件版本 $version = MFileVersions::queryFileVersionByID($versionId); if (count($version) == 0) { throw new MException(Yii::t('api', MConst::PATH_ERROR), MConst::HTTP_CODE_404); } // 获取文件存储路径 $isTmp = false; $signature = $_REQUEST["signature"]; if (empty($signature) || $signature === "undefined") { $signature = $version[0]["file_signature"]; } // 缩略图大小 $sizeInfo = self::$sizes[$this->size]; if ($sizeInfo === NULL) { $sizeStr = strtolower($this->size); $sizeList = explode("x", $sizeStr); $sizeInfo = array("w" => $sizeList[0], "h" => $sizeList[1]); } $this->width = $sizeInfo["w"]; $this->height = $sizeInfo["h"]; // 检查缩略图是否存在 $thumbnail = THUMBNAIL_TEMP . MiniUtil::getPathBySplitStr($signature); $thumbnail .= "_{$this->width}_{$this->height}.{$this->format}"; if (file_exists($thumbnail) == true) { //直接跳转,避免重复生成缩略图 $url = MiniHttp::getMiniHost() . "assets/thumbnails/" . MiniUtil::getPathBySplitStr($signature); $url .= "_{$this->width}_{$this->height}.{$this->format}"; header('Location: ' . $url); exit; } //判断文件是否在迷你存储中,兼容非迷你存储的文件 $version = MiniVersion::getInstance()->getBySignature($signature); $meta = MiniVersionMeta::getInstance()->getMeta($version["id"], "store_id"); $thumbnailData = array(); if (!empty($meta)) { //为迷你存储缩略图添加hook $thumbnailData["signature"] = $signature; $storePath = apply_filters("image_path", $thumbnailData); } if (empty($storePath) || $storePath === $thumbnailData) { //data源处理对象 $dataObj = Yii::app()->data; $signaturePath = MiniUtil::getPathBySplitStr($signature); if ($dataObj->isExistLocal()) { $storePath = $dataObj->documentStorePath($signaturePath) . $signaturePath; } } if (file_exists($storePath) == false) { throw new MException(Yii::t('api', "The file path was not found."), MConst::HTTP_CODE_404); } $pathInfo = MUtils::pathinfo_utf($fileName); $extension = $pathInfo["extension"]; $tmpPath = DOCUMENT_TEMP . $signature . ".{$extension}"; // 缩略图对象 $this->handler = NULL; $this->image = $tmpPath; $this->resize = true; // 创建缩略图片父目录 if (file_exists(dirname($thumbnail)) == false) { if (MUtils::MkDirsLocal(dirname($thumbnail)) == false) { throw new MException(Yii::t('api', "The file path was not found."), MConst::HTTP_CODE_404); } } // 临时文件父目录 if (file_exists(dirname($tmpPath)) == false) { if (MUtils::MkDirsLocal(dirname($tmpPath)) == false) { throw new MException(Yii::t('api', "The file path was not found."), MConst::HTTP_CODE_404); } } // 拷贝文件到临时目录 if (file_exists($tmpPath) == false) { if (copy($storePath, $tmpPath) == false) { throw new MException(Yii::t('api', "The file path was not found."), MConst::HTTP_CODE_404); } } // 如果图片格式与后缀不一致,转换为一致的 if ($this->format != strtolower($extension)) { $fm = new Image($tmpPath); $format_path = DOCUMENT_TEMP . $signature . ".{$this->format}"; $fm->save($format_path); // 转换成功删除临时文件 unlink($tmpPath); $this->image = $format_path; } if ($isTmp) { unlink($storePath); } // 初始化图像对象 try { $this->handler = new Image($this->image, isset($this->config) ? $this->config : NULL); } catch (MException $e) { Yii::log("Exception : {$e->getTraceAsString()}"); throw new MException(Yii::t('api', "The image is invalid and cannot be thumbnailed."), MConst::HTTP_CODE_415); } // 生成缩略图 if ($this->resize == true) { $this->handler->resize($this->width, $this->height)->rotate(0)->quality(75)->sharpen(20); $chmod = 0644; $keep_actions = true; try { $this->handler->save($thumbnail, $chmod, $keep_actions); $this->handler->setImageFile($thumbnail); $this->image = $thumbnail; @unlink($format_path); } catch (MException $e) { Yii::trace("Exception : {$e}", "miniyun.api"); throw new MException(Yii::t('api', "The image is invalid and cannot be thumbnailed."), MConst::HTTP_CODE_415); } } }