Files
2024-10-29 14:04:59 +08:00

469 lines
18 KiB
PHP
Executable File

<?php
namespace app\admin\controller;
use think\Lang;
use think\Loader;
use think\Config;
use image\Image;
class Ueditor extends BaseController {
private $basePath = '/';
private $saveDirectory = 'default';
private $config; //配置信息
public function __construct() {
parent::__construct();
date_default_timezone_set("Asia/Shanghai");
$this->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("&amp;", "&", $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("&amp;", "&", $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;
}
}