tp6 bingher/ueditor(百度编辑器)(七牛、阿里OSS第三方云)详情图文教程

插件官网:GitHub - hbh112233abc/ueditor: thinkphp6 ueditor plugin

一、安装

composer require bingher/ueditor

二、资源及数据库配置

php think ueditor:publish
php think migrate:run

在命令运行,只要生成配置表,会自动在你数据库中插入一个ueditor_config表

三、网页html中引用(引入多个)

3.1 html代码

<script id="content" type="text/plain" style="width:100%;height:500px;">{notempty name="$rs.content"}{$rs.content|raw}{else/}详情{/notempty}</script>

 3.2 js代码

与上面①②对应,保持一样的名称

<!--百度编辑器 开始-->
<script type="text/javascript" charset="utf-8" src="__STATIC__/bingher/ueditor/ueditor.config.js"></script>
<script type="text/javascript" charset="utf-8" src="__STATIC__/bingher/ueditor/ueditor.all.js"> </script>
<!--建议手动加在语言,避免在ie下有时因为加载语言失败导致编辑器加载失败-->
<!--这里加载的语言文件会覆盖你在配置项目里添加的语言类型,比如你在配置项目里配置的是英文,这里加载的中文,那最后就是中文-->
<script type="text/javascript" charset="utf-8" src="__STATIC__/bingher/ueditor/lang/zh-cn/zh-cn.js"></script>
<script type="text/javascript">
	var pc_ue = UE.getEditor('onlineservice_invitation_content_pc', {
		initialFrameHeight:100,
		autoHeightEnabled: true,
		zIndex: 100,
		autoFloatEnabled: true
		,toolbars: [[
       'fullscreen', 'source', '|', 'undo', 'redo', '|',
        'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|',
        // 'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
        'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
        // 'directionalityltr', 'directionalityrtl', 'indent', '|',
        'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
        // 'link', 'unlink', 'anchor', '|', 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
        // 'simpleupload', 'insertimage', 'emotion', 'scrawl', 'insertvideo', 'music', 'attachment', 'map', 'gmap', 'insertframe', 'insertcode', 'webapp', 'pagebreak', 'template', 'background', '|',
        // 'horizontal', 'date', 'time', 'spechars', 'snapscreen', 'wordimage', '|',
        // 'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols', 'charts', '|',
        // 'print', 'preview', 'searchreplace', 'drafts', 'help'
	    ]]
        //  ,initialContent: "<p>请在这里输入正文...</p>"//默认内容
         ,elementPathEnabled: false//元素路径
         ,wordCount: true//字数统计
         ,enableAutoSave: false //自动保存
         ,autoSyncData: false//自动同步编辑器要提交的数据
         ,autoFloatEnabled:false//工具栏悬浮
         ,enableContextMenu:false //右键菜单
         ,lineheight:['1', '1.5','1.75','2', '3', '4', '5']//行高
         ,pasteplain:true //是否默认为纯文本粘贴
         ,catchRemoteImageEnable:false//远程图片抓取关闭
         ,imagePopup:false//图片操作的浮层开关,默认打开
	});
	var h5_ue = UE.getEditor('onlineservice_invitation_content_h5', {
		initialFrameHeight:100,
		autoHeightEnabled: true,
		zIndex: 100,
		autoFloatEnabled: true
		,toolbars: [[
       'fullscreen', 'source', '|', 'undo', 'redo', '|',
        'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|',
        // 'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
        'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
        // 'directionalityltr', 'directionalityrtl', 'indent', '|',
        'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
        // 'link', 'unlink', 'anchor', '|', 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
        // 'simpleupload', 'insertimage', 'emotion', 'scrawl', 'insertvideo', 'music', 'attachment', 'map', 'gmap', 'insertframe', 'insertcode', 'webapp', 'pagebreak', 'template', 'background', '|',
        // 'horizontal', 'date', 'time', 'spechars', 'snapscreen', 'wordimage', '|',
        // 'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols', 'charts', '|',
        // 'print', 'preview', 'searchreplace', 'drafts', 'help'
	    ]]
        //  ,initialContent: "<p>请在这里输入正文...</p>"//默认内容
         ,elementPathEnabled: false//元素路径
         ,wordCount: true//字数统计
         ,enableAutoSave: false //自动保存
         ,autoSyncData: false//自动同步编辑器要提交的数据
         ,autoFloatEnabled:false//工具栏悬浮
         ,enableContextMenu:false //右键菜单
         ,lineheight:['1', '1.5','1.75','2', '3', '4', '5']//行高
         ,pasteplain:true //是否默认为纯文本粘贴
         ,catchRemoteImageEnable:false//远程图片抓取关闭
         ,imagePopup:false//图片操作的浮层开关,默认打开
	});
</script>
<!--百度编辑器 结束--> 

3.3 JS取值

		var onlineservice_invitation_content_pc = pc_ue.getContent();
		var onlineservice_invitation_content_h5 = h5_ue.getContent();

与上面①②对应,保持一样的名称

四、配置与使用

1、打开下面这两个网址,看看是否配置正常

http://你的域名/ueditor/demo/view      


http://你的域名/ueditor/demo/setting

打开显示错误:

ueditor  [ue_setting] bingher ueditor demo 配置信息表不存在

2、需要修改文件:Setting.php  UeConfig.php【官方已经修正】

 /vendor/bingher/ueditor/src/controller/Setting.php

/vendor/bingher/ueditor/src/config/UeConfig.php

文件中的ueditor_config连接方式

官方默认是用:

 $config = Db::table('ueditor_config')->column('value,remark', 'name');

但是我系统是加前缀的,所以需要修改

 $config = Db::name('ueditor_config')->column('value,remark', 'name');

还要修改下面两个地方

刷新正常

2、修改接授网址:public/static/bingher/ueditor/ueditor.config.js【官方已经修正】

serverUrl:  "/ueditor/index"

四、配置登录权限(安全设置)

http://你的域名/ueditor/demo/view
http://你的域名/ueditor/demo/setting

这两个网址如果不设置权限,那么谁都可以随便修改

官方规定:关闭APP_DEBUG(生产环境)后,默认会验证session(session_uid_key)是否有值,如果配置你的系统不是存储session('uid'),请自行配置对应的用于验证权限的键名,默认验证方法是check_uid

打开http://你的域名/ueditor/demo/setting

修改成为自己系统的一样

五、上传到七牛、阿里OSS第三方云

首先安装 TP6 第三方filesystem扩展包(支持阿里云、七牛云)thans/thinkphp-filesystem-cloud ——https://gitee.com/thans/thinkphp-filesystem-cloud

安装和作用教程:tp6 第三方filesystem扩展包(thans/thinkphp-filesystem-cloud)(支持阿里云OSS和七牛和腾讯云COS) 使用教程调用手册_php菜鸟技术天地-CSDN博客

只要修改文件:/vendor/bingher/ueditor/src/controller/Ueditor.php

$this->fs       = $this->config->initFilesystem();

		//读取系统缓存,//判断是上传到哪里   0=服务器本身,1=七牛 2=阿里OSS 3=腾讯
		$systemConfigArr=[];$systemConfig=[];$system_upload_type=0;$path='';
		$systemConfig=Cache::get('systemConfig');
		if(empty($systemConfig)){
			//重新生成缓存
			$CacheData = new CacheModel();
			$systemConfig = $CacheData -> makeSystemData();
		}
		$systemConfigArr=json_decode($systemConfig,true);
		// var_dump($systemConfigArr['fieldValueAll']);die;
		$system_upload_type=$systemConfigArr['fieldValueAll']['system_upload_type'];
		$this->system_upload_type = $system_upload_type; 
		switch ($system_upload_type)
		{
		case 3:
			$Filesystem='qcloud';
			break;
		case 2:
			$Filesystem='aliyun';
			break;
		case 1:
			$Filesystem='qiniu';
			break;
		default:
			$Filesystem='';
		}
		if($system_upload_type>0){//第三方
			$path=$Filesystem.'/';
			
			//取得第三方的访问域名
			$this-> ossurl = '';
			$fsConfig = Config::get('filesystem');
			// var_dump($fsConfig['disks'][$Filesystem]['url']);die;
			if (!empty($fsConfig['disks'][$Filesystem])) {
				$this-> ossurl = $fsConfig['disks'][$Filesystem]['url'];
				// var_dump($this->ossurl);die;
			}
			$this->fs       = $this->config->initFilesystem($Filesystem);
		}else{//本地
			$this->fs       = $this->config->initFilesystem();
		}

$Filesystem=第三方的标识 /config/filesystem.php

当然了还要修改显示路径

 $this->savePath = path_join($path.'ueditor', $this->uid);

再修改下上传文件格式和大小 

搞定收工

保存远程图片到OSS上,默认是保存服务器上的

修改后的function _saveRemot()代码:

    /**
     * 拉取远程图片
     *
     * @param array  $config    配置信息
     * @param string $fieldName 字段名
     *
     * @return mixed
     */
    private function _saveRemote($config, $fieldName)
    {
        $imgUrl = htmlspecialchars($fieldName);
        $imgUrl = str_replace("&amp;", "&", $imgUrl);

        //http开头验证
        if (strpos($imgUrl, "http") !== 0) {
            $this->error = '链接不是http|https链接';
            return false;
        }
        //获取请求头并检测死链
        $heads = get_headers($imgUrl, true);
        if (!(stristr($heads[0], "200") && stristr($heads[0], "OK"))) {
            $this->error = '链接不可用';
            return false;
        }
        //格式验证(扩展名验证和Content-Type验证)
        $fileType = strtolower(strrchr(strrchr($imgUrl, '/'), '.'));
        //img链接后缀可能为空,Content-Type须为image
        if ((!empty($fileType) && !in_array($fileType, $config['allowFiles']))
            || stristr($heads['Content-Type'], "image") === -1
        ) {
            $this->error = '链接contentType不正确';
            return false;
        }

        //解析出域名作为http_referer
        $urlArr      = explode('/', $imgUrl);
        $protocol    = str_replace(':', '', $urlArr[0]);
        $httpReferer = $protocol . ':' . '//' . $urlArr[2];

        //打开输出缓冲区并获取远程图片
        ob_start();
        $context = stream_context_create(
            [
                'http' => array(
                    //'header' => "Referer:$httpReferer",  //突破防盗链,不可用
                    'user_agent'      => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36', //突破防盗链
                    'follow_location' => false, // don't follow redirects
                ),
            ]
        );
        $res     = false;
        $message = '';
        try {
            $res = readfile($imgUrl, false, $context);
        } catch (\Exception $e) {
            $message = $e->getMessage();
        }

        $img = ob_get_contents();
        ob_end_clean();

        if ($res === false) {
            $this->error = $message;
            return false;
        }

        preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $fileName);
        $savePath         = path_join($this->savePath, date('Ymd'));
        $dirname          = path_join($this->rootPath, $savePath);
        $file['oriName']  = $fileName ? $fileName[1] : "";
        $file['filesize'] = strlen($img);
        $file['ext']      = strtolower(strrchr($config['oriName'], '.'));
        $file['name']     = uniqid() . $file['ext'];
        $file['fullName'] = $dirname . $file['name'];
        $fullName         = $file['fullName'];

        //检查文件大小是否超出限制
        if ($file['filesize'] >= ($config["maxSize"])) {
            $this->error = '文件大小超出网站限制';
            return false;
        }
        //创建目录失败
        $dirname='./upload/'.$this->savePath;
        if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) {
            $this->error = '目录创建失败';
            return false;
        } else if (!is_writeable($dirname)) {
            $this->error = '目录没有写权限';
            return false;
        }

        //移动文件
        if (!(file_put_contents($fullName, $img) && file_exists($fullName))) {
            //移动失败
            $this->error = '写入文件内容错误';
            return false;
        }

        $url='/upload/'.$savePath.$file['name'];

        //20210603 上传到OSS
        $CommonModel = new CommonModel();
        $ossImgUrl=$savePath.$file['name'];
        $ecsPath='/upload/'.$savePath.$file['name'];
        $OssData=$CommonModel -> customUploadOss($ossImgUrl,$ecsPath,$file['ext'],$file['name']);
        if($OssData['code']!=200 || empty($OssData['data']['img'])){
            $this->error = '上传OSS失败';
        }
        $url=$OssData['data']['img'];
        // dump($OssData);

        //删除刚刚上传到ECS服务器的图片文件,只保留OSS上的文件
        $delIs=unlink($fullName);
        if(!$delIs){
            $this->error = '删除图片失败';
        }
       

        //移动成功
        $data = array(
            'state'    => 'SUCCESS',
            'url'      => $url,
            // 'url'      => path_join($this->urlPath, $savePath, $file['name']),
            'title'    => $file['name'],
            'original' => $file['oriName'],
            'type'     => $file['ext'],
            'size'     => $file['filesize'],
        );
        return $data;
    }

加入

        //20210603 上传到OSS
        $CommonModel = new CommonModel();
        $ossImgUrl=$savePath.$file['name'];
        $ecsPath='/upload/'.$savePath.$file['name'];
        $OssData=$CommonModel -> customUploadOss($ossImgUrl,$ecsPath,$file['ext'],$file['name']);
        if($OssData['code']!=200 || empty($OssData['data']['img'])){
            $this->error = '上传OSS失败';
        }
        $url=$OssData['data']['img'];
        // dump($OssData);

        //删除刚刚上传到ECS服务器的图片文件,只保留OSS上的文件
        $delIs=unlink($fullName);
        if(!$delIs){
            $this->error = '删除图片失败';
        }

customUploadOss()代码

安装了第三方filesystem扩展包(支持阿里云、七牛云)thans/thinkphp-filesystem-cloud ——https://gitee.com/thans/thinkphp-filesystem-cloud

引入:use OSS\OssClient;

	/**
	*Description: 自定义上传远程图片到第三方OSS、本地(先下载到自己服务器再上传到OSS然后再删除自己服务器上的图片)
	*Author:
	*Date:2021-06-02
	*Param:$ossUrlImgName str/必填 保存图片到OSS上的完整路径 oss:ueditor/20210603/2021060360b84f39c0418.png
	*Param:$ecsPath str/必填 图片下载到自己服务器上的路径-相对路径:./upload/ueditor/20210603/2021060360b84f39c0418.png
	*Param:$ext str/必填 图片后缀 : .png
	*Param:$imgName str/必填 图片名称 : 60b84f39c0418.png
	*Param:$imgUrl str/必填 图片路径(可以是本地电脑的图片路径(/sdfk/01.jpg)也可以是远程图片完整网址)  远程图片完整网址例子:https://static.cnbetacdn.com/article/2021/06/5311492ac72d54f.png
	*Ruturn:
	*/
	public function customUploadOss($ossUrlImgName,$ecsPath,$imgName=null,$ext=null,$imgUrl=null){
		// $imgUrl='https://static.cnbetacdn.com/article/2021/06/5311492ac72d54f.png';
		$data=[];$img_url=null;$code=200;$msg='成功';
		$systemConfigArr=[];$systemConfig=[];$system_upload_type=0;$path='';$system_website=null;

		$systemConfig=Cache::get('systemConfig');
		if(empty($systemConfig)){
			//重新生成缓存
			$CacheData = new CacheModel();
			$systemConfig = $CacheData -> makeSystemData();
		}
		$systemConfigArr=json_decode($systemConfig,true)['fieldValueAll'];
		// dump($systemConfigArr);die;
		$system_website = $systemConfigArr['system_website'];//
		$system_upload_type=$systemConfigArr['system_upload_type'];
		try {
			if(empty($ossUrlImgName)){
				throw new \Exception('图片服务器路径为空');
			}
			if(empty($ecsPath)){
				throw new \Exception('图片OSS路径为空');
			}
			if(empty($imgName)){
				throw new \Exception('图片名称为空');
			}
			if(empty($ext)){
				throw new \Exception('图片后缀为空');
			}
			if(empty($systemConfigArr)){
				throw new \Exception('系统配置缓存为空');
			}
			
			if($system_upload_type==1){//1=七牛

			}elseif($system_upload_type==2){//2=阿里OSS
				// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
				$accessKeyId = $systemConfigArr['oss_aliyun_accessKey'];
				$accessKeySecret = $systemConfigArr['oss_aliyun_secretKey'];
				$endpoint =  $systemConfigArr['oss_aliyun_Endpoint'];// Endpoint(地域节点) oss-cn-shenzhen.aliyuncs.com
				$bucket=  $systemConfigArr['oss_aliyun_storage_name'];// 设置存储空间名称。
				if(empty($accessKeyId) || !$accessKeySecret || !$endpoint|| !$bucket){
					throw new \Exception('阿里云OSS必填参数为空');
				}
				$ossClient = new OssClient($accessKeyId,$accessKeySecret,$endpoint);
				$ecsPath='.'.$ecsPath;
				$result = $ossClient->uploadFile($bucket, $ossUrlImgName, $ecsPath);
				// dump($result);
				if(!$result || empty($result['info']['url'])){
					throw new \Exception('上传失败');
				}
				$img_url=!empty($result['info']['url'])?$result['info']['url']:'';
			}elseif($system_upload_type==3){//3=腾讯

			}else{//0=服务器本身
				$img_url=$system_website.$ecsPath;
			}

			if(!$img_url){
				throw new \Exception('完整图片网址为空');
			}


			$data['img']=$img_url;//图片完整网址
			
		} catch (\Exception $e) {
			// 这是进行异常捕获
			$code=-200;$msg=$e->getMessage();
		}
		return ['code' => $code,'msg' =>$msg,'data' =>$data];
	}

最后给出完整的修改文件Ueditor.php代码:(\vendor\bingher\ueditor\src\controller\Ueditor.php)

<?php

namespace bingher\ueditor\controller;

use think\facade\Request;
use think\Image;


//20210601 上传到第三方 
use think\Facade\Cache;
use app\admin\model\CacheModel;
use think\facade\Config;
use app\admin\model\CommonModel;

/**
 * Ueditor后端服务接口
 */
class Ueditor extends Base
{
    protected $uid;
    protected $error;
    protected $upfile;
    protected $fs;

    /**
     * 构造函数
     *
     * @return self
     */
    public function __construct()
    {
        parent::__construct();


		//20210601 上传到第三方  读取系统缓存,//判断是上传到哪里   0=服务器本身,1=七牛 2=阿里OSS 3=腾讯
		$systemConfigArr=[];$systemConfig=[];$system_upload_type=0;$path='';
		$systemConfig=Cache::get('systemConfig');
		if(empty($systemConfig)){
			//重新生成缓存
			$CacheData = new CacheModel();
			$systemConfig = $CacheData -> makeSystemData();
		}
		$systemConfigArr=json_decode($systemConfig,true);
		// var_dump($systemConfigArr['fieldValueAll']);die;
		$system_upload_type=$systemConfigArr['fieldValueAll']['system_upload_type'];
		$this->system_img_format=explode(',',$systemConfigArr['fieldValueAll']['system_img_format']);//允许图片上传格式
		$this->system_img_size=$systemConfigArr['fieldValueAll']['system_img_size']*1024;//允许图片上传大小
		$this->system_file_format=explode(',',$systemConfigArr['fieldValueAll']['system_file_format']);//上传文件格式
		$this->system_file_size=$systemConfigArr['fieldValueAll']['system_file_size']*1024;//上传文件大小
		
		$this->system_upload_type = $system_upload_type; 
		switch ($system_upload_type)
		{
		case 3:
			$Filesystem='qcloud';
			break;
		case 2:
			$Filesystem='aliyun';
			break;
		case 1:
			$Filesystem='qiniu';
			break;
		default:
			$Filesystem='';
		}
        $this->Filesystem = $Filesystem; 
		if($system_upload_type>0){//第三方
			$path=$Filesystem.'/';
			
			//取得第三方的访问域名
			$this-> ossurl = '';
			$fsConfig = Config::get('filesystem');
			// var_dump($fsConfig['disks'][$Filesystem]['url']);die;
			if (!empty($fsConfig['disks'][$Filesystem])) {
				$this-> ossurl = $fsConfig['disks'][$Filesystem]['url'];
				// var_dump($this->ossurl);die;
			}
			$this->fs       = $this->config->initFilesystem($Filesystem);
		}else{//本地
			$this->fs       = $this->config->initFilesystem();
		}

        $uidKey         = $this->config->get('session_uid_key', 'uid');
        $this->uid      = session($uidKey) ? strval(session($uidKey)) : '';
        $this->upField  = $this->config->get('upload_field_name', 'upfile');
        // $this->fs       = $this->config->initFilesystem();
        $this->rootPath = $this->config->get('filesystem_root');
        $this->urlPath  = $this->config->get('filesystem_url');
        $this->savePath = path_join('ueditor', date('Ymd'));
        // $this->savePath = path_join('ueditor', $this->uid);
    }

    /**
     * 针对ueditor的请求链接
     * 因为注册了路由,请求路径为 http://domain/ueditor/index
     * @return \think\Response
    */
    public function index()
    {
        $action = Request::param('action', '');
        switch ($action) {
            case 'config':
                return $this->config->json();
                break;

            /* 上传图片 */
            case 'upload_image':
                $config = [
                    // "maxSize"    => $this->config->get('imageMaxSize'),
                    // "allowFiles" => $this->config->get('imageAllowFiles'),
                    "maxSize"    => $this->system_img_size,
                    "allowFiles" => $this->system_img_format,
                ];
                $result = $this->_upFile($config);
                break;

            /* 上传涂鸦 */
            case 'upload_scrawl':
                $config = [
                    "maxSize"    => $this->config->get('scrawlMaxSize'),
                    "allowFiles" => $this->config->get('scrawlAllowFiles'),
                    "oriName"    => "scrawl.png",
                ];
                $result = $this->_upBase64($config);
                break;

            /* 上传视频 */
            case 'upload_video':
                $config = [
                    // "maxSize"    => $this->config->get('videoMaxSize'),
                    // "allowFiles" => $this->config->get('videoAllowFiles'),
                    "maxSize"    =>  $this->system_file_size,
                    "allowFiles" => $this->system_file_format,
                ];
                $result = $this->_upFile($config);
                break;

            /* 上传音频 */
            case 'upload_audio':
                $config = [
                    // "maxSize"    => $this->config->get('audioMaxSize'),
                    // "allowFiles" => $this->config->get('audioAllowFiles'),
                    "maxSize"    => $this->system_file_size,
                    "allowFiles" => $this->system_file_format,
                ];
                $result = $this->_upFile($config);
                break;

            /* 上传文件 */
            case 'upload_file':
                // default:
                $config = [
                    // "maxSize"    => $this->config->get('fileMaxSize'),
                    // "allowFiles" => $this->config->get('fileAllowFiles'),
                    "maxSize"    => $this->system_file_size,
                    "allowFiles" => $this->system_file_format,
                ];
                $result = $this->_upFile($config);
                break;

            /* 列出图片 */
            case 'list_image':
                $allowFiles = $this->config->get('imageManagerAllowFiles');
                $listSize   = $this->config->get('imageManagerListSize');
                $path       = $this->config->get('imageManagerListPath');
                $get        = Request::param();
                $result     = $this->_fileList($allowFiles, $listSize, $get);
                break;

            /* 列出文件 */
            case 'list_file':
                $allowFiles = $this->config->get('fileManagerAllowFiles');
                $listSize   = $this->config->get('fileManagerListSize');
                $path       = $this->config->get('fileManagerListPath');
                $get        = Request::param();
                $result     = $this->_fileList($allowFiles, $listSize, $get);
                break;

            /* 抓取远程文件 */
            case 'catch_image':
                $config = [
                    "pathFormat" => $this->config->get('catcherPathFormat'),
                    "maxSize"    => $this->config->get('catcherMaxSize'),
                    "allowFiles" => $this->config->get('catcherAllowFiles'),
                    "oriName"    => "remote.png",
                ];

                /* 抓取远程图片 */
                $list     = [];
                $failList = []; //错误的列表
                $source   = Request::param($this->upField);
                if (empty($source)) {
                    return $this->error('参数错误');
                }

                foreach ($source as $imgUrl) {
                    $remoteResult = $this->_saveRemote($config, $imgUrl);
                    if ($remoteResult === false) {
                        array_push($failList, [
                            "state"  => $this->error,
                            "source" => htmlspecialchars($imgUrl),
                        ]);
                    } else {
                        array_push(
                            $list,
                            [
                                "state"    => $remoteResult["state"],
                                "url"      => $remoteResult["url"],
                                "size"     => $remoteResult["size"],
                                "title"    => htmlspecialchars($remoteResult["title"]),
                                "original" => htmlspecialchars($remoteResult["original"]),
                                "source"   => htmlspecialchars($imgUrl),
                            ]
                        );
                    }
                }

                $result = [
                    'state'     => count($list) ? 'SUCCESS' : 'ERROR',
                    'list'      => $list,
                    'fail_list' => $failList,
                ];
                break;

            default:
                return $this->error('请求地址出错');
                break;
        }

        /* 错误信息 */
        if ($result === false) {
            return $this->error($this->error);
        }

        $callback = Request::param('callback');
        if (empty($callback)) {
            return $this->success($result);
        }

        if (!preg_match('/^[\w_]+$/', $callback)) {
            return $this->error('callback参数不合法');
        }

        return htmlspecialchars($callback . '(' . json_encode($result) . ')');
    }

    /**
     * 上传文件的主处理方法
     *
     * @param array $config 配置信息
     *
     * @return array
     */
    private function _upFile($config)
    {
        $file  = request()->file($this->upField);
        $check = $this->check($config, $file);
        if ($check !== true) {
            return $check;
        }
        // dump($file);
        // dump($this->savePath);die;
        $saveName = $this->fs->putFile($this->savePath, $file);
        // dump($saveName);die;
        if (!$saveName) {
            $this->error = '文件上传失败';
            return false;
        }
        $filePath = $this->fs->path($saveName);
        $ext      = $file->getExtension();
        if ($this->isImage($ext)) {
            try {
                $this->imageHandle($filePath, $ext);
            } catch (\Exception $e) {
                $this->error = $e->getMessage();
                return false;
            }
        }

		//20210601 修改 第三方
		$size=0;$url='';
		// var_dump($this->urlPath);die;
		if($this->system_upload_type>0){//第三方
			$url = path_join('', $saveName);
			$url = $this-> ossurl.$url;
		}else{//0=本地服务器
			$url = path_join($this->urlPath, $saveName);
		}
        // $size=$file->getSize();

        $data = [
            // 'url'      => path_join($this->urlPath, $saveName),
            'url'      => $url,
            'title'    => $_FILES[$this->upField]['name'],
            'original' => $_FILES[$this->upField]['name'],
            'type'     => '.' . $ext,
            'size'     => $file->getSize(),
        ];

        return $data;
    }

    /**
     * 图片再处理(压缩,水印)
     *
     * @param string $filePath 文件路径
     * @param string $ext      文件后缀
     *
     * @return string 文件路径
     */
    protected function imageHandle($filePath, $ext)
    {
        $thumbType = $this->config->get('thumb_type', 0);
        //获取图片清晰度设置,默认是80
        $quality = $this->config->get('image_upload_quality', 80);
        //获取图片宽高的最大限制值,0为不限制
        $maxLimit = $this->config->get('image_upload_max_limit', 680);

        $image = Image::open($filePath);
        if ($maxLimit > 0 && $thumbType > 0) {
            //设置缩略图模式,按宽最大680或高最大680压缩
            $image->thumb($maxLimit, $maxLimit, $thumbType);
        }
        if ($this->water == 1) {
            $font = $this->config->get(
                'water_font_path',
                __DIR__ . '/../assets/zhttfs/1.ttf'
            );
            $image->text(
                $this->config->get('water_text'),
                $font,
                10,
                '#FFCC66',
                $this->config->get('water_position'),
                [-8, -8]
            )->save($filePath, $ext, $quality);
        } else if ($this->water == 2) {
            $image->water(
                $this->config->get('water_image'),
                $this->config->get('water_position'),
                80
            )->save($filePath, $ext, $quality);
        } else {
            $image->save($filePath, $ext, $quality);
        }
        return $filePath;
    }

    /**
     * 根据文件后缀判断是不是图片
     *
     * @param string $ext 文件后缀
     *
     * @return boolean
     */
    protected function isImage($ext)
    {
        $imageExts = self::formatExts($this->config->get('imageAllowFiles', []));
        return in_array($ext, $imageExts);
    }

    /**
     * 处理base64编码的图片上传
     *
     * @param array $config 配置信息
     *
     * @return array
     */
    private function _upBase64($config)
    {
        $base64Data = Request::post($this->upfile);
        if (empty($base64Data)) {
            $this->error = '参数数据为空';
            return false;
        }
        $img = base64_decode($base64Data);

        $savePath         = $this->savePath;
        $dirname          = path_join($this->rootPath, $savePath);
        $file['filesize'] = strlen($img);
        $file['oriName']  = $config['oriName'];
        $file['ext']      = strtolower(strrchr($config['oriName'], '.'));
        $file['name']     = uniqid() . $file['ext'];
        $file['fullName'] = path_join($dirname, $file['name']);
        $fullName         = $file['fullName'];

        //检查文件大小是否超出限制
        if ($file['filesize'] >= ($config["maxSize"])) {
            $this->error = '文件大小超出网站限制';
            return false;
        }

        //创建目录失败
        if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) {
            $this->error = '目录创建失败';
            return false;
        } else if (!is_writeable($dirname)) {
            $this->error = '目录没有写权限';
            return false;
        }

        //移动文件
        if (!(file_put_contents($fullName, $img) && file_exists($fullName))) {
            //移动失败
            $this->error = '写入文件内容错误';
            return false;
        }

        //移动成功
        $data = [
            'url'      => path_join($this->urlPath, $savePath, $file['name']),
            'title'    => $file['name'],
            'original' => $file['oriName'],
            'type'     => $file['ext'],
            'size'     => $file['filesize'],
        ];

        return $data;
    }

    /**
     * 拉取远程图片
     *
     * @param array  $config    配置信息
     * @param string $fieldName 字段名
     *
     * @return mixed
     */
    private function _saveRemote($config, $fieldName)
    {
        $imgUrl = htmlspecialchars($fieldName);
        $imgUrl = str_replace("&amp;", "&", $imgUrl);

        //http开头验证
        if (strpos($imgUrl, "http") !== 0) {
            $this->error = '链接不是http|https链接';
            return false;
        }
        //获取请求头并检测死链
        $heads = get_headers($imgUrl, true);
        if (!(stristr($heads[0], "200") && stristr($heads[0], "OK"))) {
            $this->error = '链接不可用';
            return false;
        }
        //格式验证(扩展名验证和Content-Type验证)
        $fileType = strtolower(strrchr(strrchr($imgUrl, '/'), '.'));
        //img链接后缀可能为空,Content-Type须为image
        if ((!empty($fileType) && !in_array($fileType, $config['allowFiles']))
            || stristr($heads['Content-Type'], "image") === -1
        ) {
            $this->error = '链接contentType不正确';
            return false;
        }

        //解析出域名作为http_referer
        $urlArr      = explode('/', $imgUrl);
        $protocol    = str_replace(':', '', $urlArr[0]);
        $httpReferer = $protocol . ':' . '//' . $urlArr[2];

        //打开输出缓冲区并获取远程图片
        ob_start();
        $context = stream_context_create(
            [
                'http' => array(
                    //'header' => "Referer:$httpReferer",  //突破防盗链,不可用
                    'user_agent'      => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36', //突破防盗链
                    'follow_location' => false, // don't follow redirects
                ),
            ]
        );
        $res     = false;
        $message = '';
        try {
            $res = readfile($imgUrl, false, $context);
        } catch (\Exception $e) {
            $message = $e->getMessage();
        }

        $img = ob_get_contents();
        ob_end_clean();

        if ($res === false) {
            $this->error = $message;
            return false;
        }

        preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $fileName);
        $savePath         = path_join($this->savePath, date('Ymd'));
        $dirname          = path_join($this->rootPath, $savePath);
        $file['oriName']  = $fileName ? $fileName[1] : "";
        $file['filesize'] = strlen($img);
        $file['ext']      = strtolower(strrchr($config['oriName'], '.'));
        $file['name']     = uniqid() . $file['ext'];
        $file['fullName'] = $dirname . $file['name'];
        $fullName         = $file['fullName'];

        //检查文件大小是否超出限制
        if ($file['filesize'] >= ($config["maxSize"])) {
            $this->error = '文件大小超出网站限制';
            return false;
        }
        //创建目录失败
        $dirname='./upload/'.$this->savePath;
        if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) {
            $this->error = '目录创建失败';
            return false;
        } else if (!is_writeable($dirname)) {
            $this->error = '目录没有写权限';
            return false;
        }

        //移动文件
        if (!(file_put_contents($fullName, $img) && file_exists($fullName))) {
            //移动失败
            $this->error = '写入文件内容错误';
            return false;
        }

        $url='/upload/'.$savePath.$file['name'];

        //20210603 上传到OSS
        $CommonModel = new CommonModel();
        $ossImgUrl=$savePath.$file['name'];
        $ecsPath='/upload/'.$savePath.$file['name'];
        $OssData=$CommonModel -> customUploadOss($ossImgUrl,$ecsPath,$file['ext'],$file['name']);
        if($OssData['code']!=200 || empty($OssData['data']['img'])){
            $this->error = '上传OSS失败';
        }
        $url=$OssData['data']['img'];
        // dump($OssData);

        //删除刚刚上传到ECS服务器的图片文件,只保留OSS上的文件
        $delIs=unlink($fullName);
        if(!$delIs){
            $this->error = '删除图片失败';
        }
       

        //移动成功
        $data = array(
            'state'    => 'SUCCESS',
            'url'      => $url,
            // 'url'      => path_join($this->urlPath, $savePath, $file['name']),
            'title'    => $file['name'],
            'original' => $file['oriName'],
            'type'     => $file['ext'],
            'size'     => $file['filesize'],
        );
        return $data;
    }

    /**
     * 文件列表
     *
     * @param array $allowFiles 指定的文件后缀数组
     * @param int   $listSize   列表分页数量
     * @param array $get        ['size'=>xxx,'start'=>xxx]
     *
     * @return array
     */
    private function _fileList($allowFiles, $listSize, $get)
    {
        $dirname = path_join($this->rootPath, 'ueditor');
        if ($this->uid != $this->config->get('super_admin_uid', 'admin')) {
            $dirname = path_join($dirname, $this->uid);
        }

        $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;

        /* 获取文件列表 */
        $files = $this->_getFiles($dirname, $allowFiles);
        if (!count($files)) {
            return [
                "state" => "no match file",
                "list"  => [],
                "start" => $start,
                "total" => count($files),
            ];
        }

        /* 获取指定范围的列表 */
        $len  = count($files);
        $list = [];
        for ($i = min($end, $len) - 1; $i < $len && $i >= 0 && $i >= $start; $i--) {
            $list[] = $files[$i];
        }

        /* 返回数据 */
        $result = [
            "state" => "SUCCESS",
            "list"  => $list,
            "start" => $start,
            "total" => count($files),
        ];

        return $result;
    }

    /**
     * 遍历获取目录下的指定类型的文件
     *
     * @param string $path       文件路径
     * @param string $allowFiles 指定的文件后缀,以|分隔的文本
     * @param array  $files      文件数组
     *
     * @return array
     */
    private function _getFiles($path, $allowFiles, &$files = [])
    {
        if (!is_dir($path)) {
            return [];
        }
        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'   => preg_replace(
                                '/(.*)upload/i',
                                '/upload',
                                $path2
                            ),
                            'mtime' => filemtime($path2),
                        );
                    }
                }
            }
        }

        return $files;
    }

    /**
     * [formatUrl 格式化url,用于将getFiles返回的文件路径进行格式化,起因是中文文件名的不支持浏览]
     *
     * @param array $files [文件数组]
     *
     * @return array   [格式化后的文件数组]
     */
    public static function formatUrl($files)
    {
        if (!is_array($files)) {
            return $files;
        }

        foreach ($files as $key => $value) {
            $data = [];
            $data = explode('/', $value);
            foreach ($data as $k => $v) {
                if ($v != '.' && $v != '..') {
                    $data[$k] = urlencode($v);
                    $data[$k] = str_replace("+", "%20", $data[$k]);
                }
            }
            $files[$key] = implode('/', $data);
        }

        return $files;
    }

    /**
     * 格式化文件后缀
     * 去除后缀名前面的.,例".exe"=>"exe"
     *
     * @param array $exts 文件后缀数组
     *
     * @return array
     */
    public static function formatExts(array $exts): array
    {
        $data = [];
        foreach ($exts as $key => $value) {
            $data[] = ltrim($value, '.');
        }
        return $data;
    }

    /**
     * 上传文件验证
     * 1. 验证文件大小
     * 2. 验证文件后缀
     *
     * @param array  $config 配置信息
     * @param Object $file   文件对象
     *
     * @return bool
     */
    protected function check($config, $file)
    {
        try {
            $rule = [
                $this->upField => [
                    'fileSize' => $config['maxSize'],
                    'fileExt'  => self::formatExts($config['allowFiles']),
                ],
            ];
            validate($rule)->check([$this->upField => $file]);
            return true;
        } catch (\think\exception\ValidateException $e) {
            $this->error = $e->getMessage();
            return false;
        }
    }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值