docDir = $this->request->server('DOCUMENT_ROOT'); $this->rootDir = $this->request->root(); $this->basePath = $this->docDir . $this->rootDir . '/uploads'; $this->saveDirectory = 'temp'; error_reporting(E_ERROR | E_WARNING); Config::set('url_common_param', true); header("Content-Type: text/html; charset=utf-8"); } //上传文件 private function upFile($fileField, $config = array()) { $result = array('state' => "ERROR_UNKNOWN 未知错误"); $file = $this->request->file($fileField); if (empty($file)) { $file = $this->request->file('upfile'); } // $error = $this->validate( // ['file' => $file], ['file' => 'image|fileSize:40000000|fileExt:jpg,jpeg,gif,png'], ['file.image' => '上传文件必须为图片', 'file.fileSize' => '上传文件过大', 'file.fileExt' => '上传文件后缀名必须为jpg,jpeg,gif,png'] // ); $error = true; if (true !== $error || empty($file)) { return json_encode(['state' => "ERROR " . $error]); } else { // 移动到框架应用根目录/public/uploads/ 目录下 $saveDirectory = $this->saveDirectory . '/' . date('Y/md') . '/'; // 使用自定义的文件保存规则 $info = $file->rule(function($file) { return md5(mt_rand()); })->move($this->basePath . '/' . $saveDirectory); if ($info) { $result = array( 'state' => 'SUCCESS', 'url' => '/uploads/' . $saveDirectory . $info->getFilename(), 'title' => $info->getFilename(), 'original' => $info->getFilename(), 'type' => '.' . $info->getExtension(), 'size' => $info->getSize(), ); //图片加水印 $ext = strtolower($info->getExtension()); if (in_array($ext, ['gif', 'jpg', 'jpeg', 'png', 'bmp'])) { $this->watermark('/uploads/' . $saveDirectory . $info->getFilename()); } } else { $result['state'] = 'ERROR ' . $file->getError(); } } return json_encode($result); } /* * 处理base64编码的图片上传 * 例如:涂鸦图片上传 */ private function upBase64($fileField, $config) { $base64Data = $this->request->post($fileField); $img = base64_decode($base64Data); $dirname = $this->basePath . '/' . $this->saveDirectory . '/'; $file['filesize'] = strlen($img); $file['oriName'] = $config['oriName']; $file['ext'] = strtolower(strrchr($config['oriName'], '.')); $file['name'] = uniqid() . $file['ext']; $file['fullName'] = $dirname . $file['name']; $fullName = $file['fullName']; //检查文件大小是否超出限制 if ($file['filesize'] >= ($config["maxSize"])) { $data = array( 'state' => '文件大小超出网站限制', ); return json_encode($data); } //创建目录失败 if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) { $data = array( 'state' => '目录创建失败', ); return json_encode($data); } else if (!is_writeable($dirname)) { $data = array( 'state' => '目录没有写权限', ); return json_encode($data); } //移动文件 if (!(file_put_contents($fullName, $img) && file_exists($fullName))) { //移动失败 $data = array( 'state' => '写入文件内容错误', ); } else { //移动成功 $data = array( 'state' => 'SUCCESS', 'url' => substr($file['fullName'], 1), 'title' => $file['name'], 'original' => $file['oriName'], 'type' => $file['ext'], 'size' => $file['filesize'], ); } return json_encode($data); } //列出图片 private function listFile($allowFiles, $listSize, $get) { $dirname = $this->basePath . '/' . $this->saveDirectory . '/'; $allowFiles = substr(str_replace(".", "|", join("", $allowFiles)), 1); /* 获取参数 */ $size = isset($get['size']) ? htmlspecialchars($get['size']) : $listSize; $start = isset($get['start']) ? htmlspecialchars($get['start']) : 0; $end = $start + $size; /* 获取文件列表 */ $path = $dirname; $files = $this->getFiles($path, $allowFiles); if (!count($files)) { return json_encode(array( "state" => "no match file", "list" => array(), "start" => $start, "total" => count($files) )); } /* 获取指定范围的列表 */ $len = count($files); for ($i = min($end, $len) - 1, $list = array(); $i < $len && $i >= 0 && $i >= $start; $i--) { $list[] = $files[$i]; } // /* 倒序 */ // for ($i = $end, $list = array(); $i < $len && $i < $end; $i++) { // $list[] = $files[$i]; // } /* 返回数据 */ $result = json_encode(array( "state" => "SUCCESS", "list" => $list, "start" => $start, "total" => count($files) )); return $result; } /* * 遍历获取目录下的指定类型的文件 * @param $path * @param array $files * @return array */ private function getFiles($path, $allowFiles, &$files = array()) { if (!is_dir($path)) return null; if (substr($path, strlen($path) - 1) != '/') $path .= '/'; $handle = opendir($path); while (false !== ($file = readdir($handle))) { if ($file != '.' && $file != '..') { $path2 = $path . $file; if (is_dir($path2)) { $this->getFiles($path2, $allowFiles, $files); } else { if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) { $files[] = array( 'url' => substr($path2, strlen($_SERVER['DOCUMENT_ROOT'])), 'mtime' => filemtime($path2) ); } } } } return $files; } /** * 拉取远程图片 * @return mixed */ private function saveRemotess($fieldName, $config) { $imgUrl = htmlspecialchars($fieldName); $imgUrl = str_replace("&", "&", $imgUrl); //http开头验证 if (strpos($imgUrl, "http") !== 0) { $data = array( 'state' => '链接不是http链接', ); return json_encode($data); } //获取请求头并检测死链 $heads = get_headers($imgUrl); if (!(stristr($heads[0], "200") && stristr($heads[0], "OK"))) { $data = array( 'state' => '链接不可用', ); return json_encode($data); } //格式验证(扩展名验证和Content-Type验证) $fileType = strtolower(strrchr($imgUrl, '.')); if (!in_array($fileType, $config['allowFiles']) || stristr($heads['Content-Type'], "image")) { $data = array( 'state' => '链接contentType不正确', ); return json_encode($data); } //打开输出缓冲区并获取远程图片 ob_start(); $context = stream_context_create( array('http' => array( 'follow_location' => false // don't follow redirects )) ); readfile($imgUrl, false, $context); $img = ob_get_contents(); ob_end_clean(); preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $m); $dirname = $this->basePath . '/' . $this->saveDirectory . '/' . date('Y/md') . '/'; $file['oriName'] = $m ? $m[1] : ""; $file['filesize'] = strlen($img); $file['ext'] = strtolower(strrchr($config['oriName'], '.')); $file['name'] = md5(mt_rand()) . $file['ext']; $file['fullName'] = $dirname . $file['name']; $fullName = $file['fullName']; //检查文件大小是否超出限制 if ($file['filesize'] >= ($config["maxSize"])) { $data = array( 'state' => '文件大小超出网站限制', ); return json_encode($data); } //创建目录失败 if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) { $data = array( 'state' => '目录创建失败', ); return json_encode($data); } else if (!is_writeable($dirname)) { $data = array( 'state' => '目录没有写权限', ); return json_encode($data); } //移动文件 if (!(file_put_contents($fullName, $img) && file_exists($fullName))) { //移动失败 $data = array( 'state' => '写入文件内容错误', ); return json_encode($data); } else { //移动成功 $data = array( 'state' => 'SUCCESS', 'url' => substr($file['fullName'], strlen($this->docDir . $this->rootDir)), 'title' => $file['name'], 'original' => $file['oriName'], 'type' => $file['ext'], 'size' => $file['filesize'], ); } return json_encode($data); } /** * 拉取远程图片 * @return mixed */ private function saveRemote($fileField, $config = array()) { $imgUrl = htmlspecialchars($fileField); $imgUrl = str_replace("&", "&", $imgUrl); //http开头验证 if (strpos($imgUrl, "http") !== 0) { $data = array( 'state' => '链接不是http链接', ); return json_encode($data); } preg_match('/(^https*:\/\/[^:\/]+)/', $imgUrl, $matches); $host_with_protocol = count($matches) > 1 ? $matches[1] : ''; // 判断是否是合法 url if (!filter_var($host_with_protocol, FILTER_VALIDATE_URL)) { $data = array( 'state' => 'INVALID_URL', ); return json_encode($data); } preg_match('/^https*:\/\/(.+)/', $host_with_protocol, $matches); $host_without_protocol = count($matches) > 1 ? $matches[1] : ''; // 此时提取出来的可能是 ip 也有可能是域名,先获取 ip $ip = gethostbyname($host_without_protocol); // 判断是否是私有 ip if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) { $data = array( 'state' => 'INVALID_IP', ); return json_encode($data); } //获取请求头并检测死链 $heads = get_headers($imgUrl); if (!(stristr($heads[0], "200") && stristr($heads[0], "OK"))) { $data = array( 'state' => '链接不可用', ); return json_encode($data); } //格式验证(扩展名验证和Content-Type验证) $fileType = strtolower(strrchr($imgUrl, '.')); if (!in_array($fileType, $config['allowFiles']) || stristr($heads['Content-Type'], "image")) { $data = array( 'state' => '链接contentType不正确', ); return json_encode($data); } //打开输出缓冲区并获取远程图片 ob_start(); $context = stream_context_create(array('http' => array( 'follow_location' => false // don't follow redirects )) ); readfile($imgUrl, false, $context); $img = ob_get_contents(); ob_end_clean(); preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $m); $dirname = $this->basePath . '/' . $this->saveDirectory . '/' . date('Y/md') . '/'; $file['oriName'] = $m ? $m[1] : ""; $file['filesize'] = strlen($img); $file['ext'] = strtolower(strrchr($config['oriName'], '.')); $file['name'] = md5(mt_rand()) . $file['ext']; $file['fullName'] = $dirname . $file['name']; $fullName = $file['fullName']; //检查文件大小是否超出限制 if ($file['filesize'] >= ($config["maxSize"])) { $data = array( 'state' => '文件大小超出网站限制', ); return json_encode($data); } //创建目录失败 if (!is_dir($dirname) && !mkdir($dirname, 0777, true)) { $data = array( 'state' => '目录创建失败', ); return json_encode($data); } else if (!is_writeable($dirname)) { $data = array( 'state' => '目录没有写权限', ); return json_encode($data); } //移动文件 if (!(file_put_contents($fullName, $img) && is_file($fullName))) { //移动失败 $data = array( 'state' => '写入文件内容错误', ); return json_encode($data); } else { //移动成功 //$this->watermark(substr($file['fullName'], strlen($this->docDir . $this->rootDir))); $data = array( 'state' => 'SUCCESS', 'url' => substr($file['fullName'], strlen($this->docDir . $this->rootDir)), 'title' => $file['name'], 'original' => $file['oriName'], 'type' => $file['ext'], 'size' => $file['filesize'], ); } return json_encode($data); } public function watermark($return_url = '/uploads/nopic.jpg') { $iswatermark = Config::get('watermark'); $return_data = ['watermark' => $iswatermark]; if ($iswatermark) { $wmconfig = [ 'watermark' => $iswatermark, 'mark_type' => Config::get('mark_type'), 'mark_image' => Config::get('mark_image'), 'mark_width_height' => Config::get('mark_width_height'), 'mark_text' => Config::get('mark_text'), 'mark_text_color' => Config::get('mark_text_color'), 'mark_degree' => Config::get('mark_degree'), 'mark_quality' => Config::get('mark_quality'), 'mark_position' => Config::get('mark_position'), ]; $imgresource = '.' . $return_url; $image = Image::open($imgresource); //$image->open($imgresource); $return_data['mark_type'] = $wmconfig['mark_type']; if ($image->width() > $wmconfig['mark_width_height']['width'] && $image->height() > $wmconfig['mark_width_height']['height']) { $save_filename = $this->basePath . '/original_image' . substr($return_url, 8); //截取 /uploads 后的内容 if (!is_dir(dirname($save_filename))) { mkdir(dirname($save_filename), 0777, true); } $image->save($save_filename, null, 100); if ($wmconfig['mark_type'] == 'text') { //$image->text($wmconfig['mark_text'],'./hgzb.ttf',20,'#000000',9)->save($imgresource); $ttf = './hgzb.ttf'; if (file_exists($ttf)) { $size = $wmconfig['mark_text_size'] ? $wmconfig['mark_text_size'] : 30; $color = $wmconfig['mark_text_color'] ? : '#000000'; if (!preg_match('/^#[0-9a-fA-F]{6}$/', $color)) { $color = '#000000'; } $transparency = intval((100 - $wmconfig['mark_degree']) * (127 / 100)); $color .= dechex($transparency); $image->open($imgresource)->text($wmconfig['mark_text'], $ttf, $size, $color, $wmconfig['mark_position'])->save($imgresource); $return_data['mark_text'] = $wmconfig['mark_text']; } } else { //$image->water('.'.$wmconfig['mark_img'],9,$wmconfig['mark_degree'])->save($imgresource); $waterPath = '.' . $wmconfig['mark_image']; $quality = $wmconfig['mark_quality'] ? $wmconfig['mark_quality'] : 80; $waterTempPath = dirname($waterPath) . '/temp_' . basename($waterPath); $image->open($waterPath)->save($waterTempPath, null, $quality); $image->open($imgresource)->water($waterTempPath, $wmconfig['mark_position'], $wmconfig['mark_degree'])->save($imgresource); @unlink($waterTempPath); } } } return $return_data; } /** * 规则替换命名文件 * @param $path * @return string */ private function getFullPath($path) { //替换日期事件 $t = time(); $d = explode('-', date("Y-y-m-d-H-i-s")); $format = $path; $format = str_replace("{yyyy}", $d[0], $format); $format = str_replace("{yy}", $d[1], $format); $format = str_replace("{mm}", $d[2], $format); $format = str_replace("{dd}", $d[3], $format); $format = str_replace("{hh}", $d[4], $format); $format = str_replace("{ii}", $d[5], $format); $format = str_replace("{ss}", $d[6], $format); $format = str_replace("{uid}", $this->user_id, $format); return $format; } private function format_exts($exts) { $data = array(); foreach ($exts as $key => $value) { $data[] = ltrim($value, '.'); } return $data; } }