百度编辑器上传失败问题--转码问题mb_convert_encoding与iconv_errorexception: mb_convert_encoding(): object is n-程序员宅基地

技术标签: php  

纳尼?我...... 多么正常的编辑器,我本地跑的好好的,我赶紧去试了一下,果然报错,WTF......

但是:虽然报错,当点击“在线管理”(就是选择服务器上已存在的文件)的时候,却发现之前那张图是传上去了的,有些个尴尬,马上和环宇说其实已传上去了,可以直接在“在线管理”里先用着...为了要给客户弄好内容,他没有多言,应声了下来,但很明显,环宇虽然口头不说,但心里肯定在骂“我*”,我想bug还是得改,于是:

解bug第一式:用Chrome浏览器,按下F12,打开Network,去上传一波,然后我就看到这样的画面:

技术分享

技术分享

大家都是明白人,其他就不多说了,找到了对应的后端代码,也看到了返回值,那赶紧找到此这个文件看看代码再说。

好吧,路径是个绝对路径,就是Ueditor的上传文件的后台代码实现(不过是PHP版而已),目录结构是这样的:


此处略去N个字,contoller.php调用了action_upload.php,再调用了Uploader.class.php。

解bug第二式:打断点,打了尼玛好多,终于找到出问题的代码是在这里:


也就是说是iconv这个函数引起了报错,一看上下文,这也没什么特别的用处,就是把一句提示信息转一下码而已,只要注释掉这句就可以了,程序照常运行,也不会报错,先回复环宇说bug已解,可以正常使用。

<?php

/**
* Created by JetBrains PhpStorm.
* User: taoqili
* Date: 12-7-18
* Time: 上午11: 32
* UEditor编辑器通用上传类
*/
class Uploader
{
private $fileField; //文件域名
private $file; //文件上传对象
private $base64; //文件上传对象
private $config; //配置信息
private $oriName; //原始文件名
private $fileName; //新文件名
private $fullName; //完整文件名,即从当前配置目录开始的URL
private $filePath; //完整文件名,即从当前配置目录开始的URL
private $fileSize; //文件大小
private $fileType; //文件类型
private $stateInfo; //上传状态信息,
private $stateMap = array( //上传状态映射表,国际化用户需考虑此处数据的国际化
"SUCCESS", //上传成功标记,在UEditor中内不可改变,否则flash判断会出错
"文件大小超出 upload_max_filesize 限制",
"文件大小超出 MAX_FILE_SIZE 限制",
"文件未被完整上传",
"没有文件被上传",
"上传文件为空",
"ERROR_TMP_FILE" => "临时文件错误",
"ERROR_TMP_FILE_NOT_FOUND" => "找不到临时文件",
"ERROR_SIZE_EXCEED" => "文件大小超出网站限制",
"ERROR_TYPE_NOT_ALLOWED" => "文件类型不允许",
"ERROR_CREATE_DIR" => "目录创建失败",
"ERROR_DIR_NOT_WRITEABLE" => "目录没有写权限",
"ERROR_FILE_MOVE" => "文件保存时出错",
"ERROR_FILE_NOT_FOUND" => "找不到上传文件",
"ERROR_WRITE_CONTENT" => "写入文件内容错误",
"ERROR_UNKNOWN" => "未知错误",
"ERROR_DEAD_LINK" => "链接不可用",
"ERROR_HTTP_LINK" => "链接不是http链接",
"ERROR_HTTP_CONTENTTYPE" => "链接contentType不正确",
"INVALID_URL" => "非法 URL",
"INVALID_IP" => "非法 IP"
);

/**
* 构造函数
* @param string $fileField 表单名称
* @param array $config 配置项
* @param bool $base64 是否解析base64编码,可省略。若开启,则$fileField代表的是base64编码的字符串表单名
*/
public function __construct($fileField, $config, $type = "upload")
{
    $this->fileField = $fileField;
    $this->config = $config;
    $this->type = $type;
    if ($type == "remote") {
        $this->saveRemote();
    } else if($type == "base64") {
        $this->upBase64();
    } else {
        $this->upFile();
    }

    $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘] = iconv(‘unicode‘, ‘utf-8‘, $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘]);
}


回头来看这句 $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘] = iconv(‘unicode‘, ‘utf-8‘, $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘]); 是个什么鬼,我的疑问有三点:

1.为毛这里要转这一句提示信息,而不转其他的?

2.iconv是什么函数?

3.就算要转,为毛写死了unicode到utf-8,为毛不是gb2312或gbk?

是的,我来解答这几个问题,首先第一个....不 我先说第二个:

iconv是一个从PHP4以后有的函数,功能是把字符串从一种编码转换成另一种编码,详情在这里可以查看:http://php.net/manual/en/function.iconv.php

那编码又是什么意思呢,大概就是计算机存储信息时最终是二进制,然全世界有很多国家和语言,慢慢变成同样的二进制数字表示的字符不一样,通常听到的UTF-8,GB2312等,就是不同的编码方式的意思,而ANSI,Unicode等就是不同的字符集的意思,详情可以查看:http://blog.jobbole.com/84903/ ,或者 http://blog.csdn.net/wabil/article/details/50807240 。这里不多讲。

那为什么要写死了了unicode到utf-8呢?那我就不知道了,一脸懵逼的时候,看到头部:

/**
* Created by JetBrains PhpStorm.
* User: taoqili
* Date: 12-7-18
* Time: 上午11: 32
* UEditor编辑器通用上传类
*/

好吧,解bug第三式:百度一下taoqili,第一条便是https://my.oschina.net/taoqili/ ,嗯,看起来是其作者本人的主页,因为这个主页进去第一篇文章依然是5年前说Ueditor上线的文章 ....

技术分享

于是进去此文章 https://www.oschina.net/news/37279/ueditor-1-2-5 ,无非就是说新版本上线了,文章 最后附了Ueditor的链接:

技术分享

是链接到 http://ueditor.baidu.com/website/download.html#ueditor ,好吧,官网的页面....,然后引人注目的是这句话:


再次懵逼的我,又打开了这个链接 https://github.com/fex-team/ueditor/blob/dev-1.5.0/php/Uploader.class.php ,不错,这个文件内容是替换了的(不死心的我还下载了此页面下方一些其他版本,看到Uploader.class.php的内容是和本地一样) ,然回到此页面的上一级 https://github.com/fex-team/ueditor/tree/dev-1.5.0/php ,如图:


就是说其他文件在4年前就搬到git,这个文件是最近修改过了(PS:https://github.com/fex-team 是百度前端的git主页),下载此文件,做了对比,也没啥特别的,重要的是:


直接把上面有bug的给换了个函数,我汗,那这个mb_convert_encoding又是做嘛的?http://www.php.net/manual/en/function.mb-convert-encoding.php ,和iconv类似,也是转编码用的,但为啥换成这个了? 其大概意思是iconv在中文(或者说非英文)时会有一些乱码问题,比如有增加后缀 //TRANSLIT 和 //IGNORE 的用法,并且需要指定从啥转换成啥的两个”啥“,而mb_convert_encoding可以不用指定从啥到啥,因为有个万能的”auto“参数,具体的大家自己百度有一堆文章在讲这两个函数,这里不多讲,最重要的结论就是:mb_convert_encoding兼容好一些,但效率差一些...

好吧,我就认了,跳过...但是上上图中


提到的是修复了ssrf的安全漏洞....可刚才替换iconv的函数和ssrf好像没半毛钱关系(这就是所谓的掩人耳目吗),好吧,继续对比两份文件,在后面一个saveRemote 方法里(这个方法是编辑器允许引用一张在网络上已存在的真实的图片地址,一般是指绝对路径的URL),新版的代码多了几行:

//检查文件内容是否真的是图片
if (substr(mime_content_type($this->filePath), 0, 5) != ‘image‘) {
    $this->stateInfo = $this->getStateInfo("ERROR_TYPE_NOT_ALLOWED");
    return;
}

bingo 就是他了,那么问题来了,什么是ssrf?好吧

SSRF(Server-Side Request Forgery ,服务器端请求伪造)是一种由攻击者构造形成由服务器发起请求的一个安全漏洞,SSRF的主要攻击目标为外网无法访问的内部系统
原因?
SSRF形成的原因是服务端提供了从其他服务器应用获取数据的功能,在用户可控的情况下,未对目标地址进行过滤与限制,导致此漏洞的产生。
比如从指定URL地址获取网页文本内容,加载指定地址的图片等,都是SSRF容易出现的点。详情依然请大家自行百度。

简单来讲就是服务器上会访问其信任的第三方URL,如下面一个实例:

http://www.douban.com/***/service?image=http://www.baidu.com/img/bd_logo1.png

所以理论上要信任这个URL,是需要做一些限制和判断的,很多网页的分享功能,就有类似的原理,而上面的:检查文件内容是否真的图片,就是对其文件格式做了判断,避免非图片的URL被访问到了。

回头再倒个序:当我发现是那iconv引起的bug时,我突然想起前几日严旭同学和航航写公告功能的时候,加了Ueditor的,所以跑去库里追他的代码,发现他其实自己给前端写了一个上传文件的接口,走我们mhi常用的common/upload去了,然再跟发现,他最终实现上传的代码,依然是拷的Ueditor的Uploader.class.php来实现的,并且,他把那句iconv函数的注释了,然后我就问他为啥要注释呢,他说因为那句不注释就要报错~~,我俩就尴尬的对视着,5秒之后我说好吧我知道了,然再5秒之后他问我:那你知道为啥要报错吗,sorry,又是尴尬的对视,我说:我也不知道,画面大家自行脑补。。。


好吧,说了那么多,绕的挻远的,回头总结一下我本身想记的坑,也是本文的小结:

1.多语言造成的字符集和字符编码的问题,比如常用的Unicode和ANSI字符集,UTF-8和GBK编码,导致在windows和Linux、中文和英文操作系统里、中文编码的代码文件和英文编码的数据库间,需要用字符编码转换函数进行转换来解决乱码的问题,特别是开发环境是windows,生产环境是Linux时要注意;

2.iconv和mb_convert_encoding都是php中转换编码的函数,大概区别在于:1.iconv效率高,但容易出错,2.mb_convert_encoding兼容性好,但效率偏低,3两个函数是依赖于不同的php扩展;

3.ssrf漏洞是指:当服务器允许访问第三方URL,并且这个第三方URL是由用户决定,那如果对这个URL未做严格的控制,可能会有漏洞;

4.Ueditor官网上的代码,是5年前的了,要继续用这个编辑器的童鞋,请到百度前端git页去下载 https://github.com/fex-team/ueditor

Well,如果你很偏执,你可能会问我上面提的三个问题中第一个问题我好像没回答,那我现在回答你:我没找到答案......

所以,晚了,躺下就睡吧。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zjhwqx/article/details/79989292

智能推荐

Java学习笔记(二)——变量与常量-程序员宅基地

文章浏览阅读79次。一、java中的关键字 Java 语言中有一些具有特殊用途的词被称为关键字。关键字对 Java 的编译器有着特殊的意义,在程序中应用时一定要慎重哦!! 二、认识Java标识符 1、定义 标识符就是用于给 Java 程序中变量、类、方法等命名的符号 2、使用标识符时,需要遵守几条规则: (1) 标识符可以由字母、数字、下划线(_)、美元符($)组成,但不能包含..._对基本数据类型变量来说,变量中存储的是( )。

Jeesite架构师系列教程之云端部署及发布_jeesite cloud 部署-程序员宅基地

文章浏览阅读757次。Jeesite架构师系列教程之云端发布及部署课程目录00-Jeesite架构师系列之云端部署课前介绍01-Jeesite架构师系列之云端部署开篇讲解02-Jeesite架构师系列之云端部署什么是云端讲解03-Jeesite架构师系列之云端部署阿里云讲解04-Jeesite架构师系列之云端部署阿里云更换操作系统讲解05-Jeesite架构师系列之云端部署WinSCP讲解0_jeesite cloud 部署

CNN vs RNN vs ANN——3 种神经网络分析模型,你 Pick 谁?-程序员宅基地

文章浏览阅读2.4k次。作者丨ARAVIND PAI编译 | 火火酱 责编丨Carol出品 | AI科技大本营(ID:rgznai100)为什么选择深度学习? 这个问题很有意义。机器学习算法并没有什么不足之处,..._基于三种神经网络的实践对比

【学习Python】Python内置函数dir()详解_python __dir__-程序员宅基地

文章浏览阅读1.8w次,点赞6次,收藏29次。描述dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。语法dir 语法:dir([object])参数说明:object -- 对象、变量、类型。返回值返回模块_python __dir__

PowerDesigner 16.5破解版安装教程_power disgner16.5激活-程序员宅基地

文章浏览阅读310次。1,下载:https://pan.baidu.com/s/1awNu_2i8wGqNldYqj02JRQ 2,放到PowerDesigner 安装目录替换_power disgner16.5激活

win10如何以管理员身份运行程序?_microsoft 怎样用应用管理员运行-程序员宅基地

文章浏览阅读2.6k次。我们在运行win10系统某些应用程序时,有时候会遇到需要使用管理员权限打开程序的情况,如果有小伙伴不知道怎样打开管理员权限的话,可以参考下面小编带给你的方法。操作完以上步骤,我们就能够以管理员权限运行此程序了,如果大家电脑上还有其它软件需要管理员权限,也可以用同样的方法进行设置。1、首先我们用鼠标右键选择需要管理员权限运行的软件,然后点击属性,这里随便找了一个软件进行操作。2、在进入软件的属性界面后,点击上方的兼容性,然后勾选以管理员身份运行此程序。_microsoft 怎样用应用管理员运行

随便推点

[Tensorflow2] 梯度反转层(GRL)与域对抗训练神经网络(DANN)的实现_domain-adversarial training of neural networks-程序员宅基地

文章浏览阅读5.1k次,点赞13次,收藏55次。梯度反转层 Gradient reversal layer (GRL)域对抗训练 Domain-Adversarial Training of Neural Networks (DANN)Tensorflow2 keras_domain-adversarial training of neural networks

赠书 | 如何建设数据中台?看这份企业数据能力测评就够了!-程序员宅基地

文章浏览阅读2.6k次。作者 | 耿立超来源 |《大数据平台架构与原型实现:数据中台建设实战》“我的企业目前在数据应用上处于什么水平?接下来应该朝哪个方向努力?”本文试图帮助企业决策者和IT负责人解答这一问题..._应用了数据中台的系统采取从下层到上层的驱动模式,在满足上层业务的同时不断完善,

转正实录 | 编写测试用例(一)-程序员宅基地

文章浏览阅读436次,点赞11次,收藏9次。我司的测试平台,是在 MeterSphere 的基础上做了二次开发,想了解的可以跳转至。万一哪一天,公司引入 MeterSphere,需要在平台上维护用例,而你已经适应了按照这个模板填写,到时候转换过来,也不会有什么困难。我的模板文件是在 MeterSphere 上导出的,如果公司还没有形成规范的模板文件,那可以参考我的。看看别人是怎么写的,先模仿着写,基本不会出错。如果公司已经有了规范的模板,直接用就好,今天分享到这里,有疑问的可以告诉我~使用这个模板文件的好处也是有的。先来说说 Excel表格。

Apache Click 框架入门-程序员宅基地

文章浏览阅读4.6k次。简介:Apache Click 是一个先进的Java企业版的Web应用程序框架,提供一个基于浏览器的富客户端编程模型。非常简单和易用,一般的开发人员在一天内就可以上手使用。基于组件设计的方法,而且进行了优化,从而更加易用。它提供了一个面向页面的设计模式、基于组件与事件的编程模型。Click包括了40多个开盒即用的组件,对应了HTML中主要的元素。这样使得编程很简单了。Click的_apache click

如何在C#中调用点云库PCL_c#能不能操作pcl-程序员宅基地

文章浏览阅读1.2w次,点赞5次,收藏48次。如何在C#中调用点云库PCL由于写界面用C#比较方便,而PCL点云库是用C++写的。自己封装来实现调用确实是一种比较靠谱的方法,但对于时间成本来说较高。网上找了一圈,Justin Bruening已经在对于PCL中的函数进行了封装。下面将调用的方法和步骤整理如下。方法一:通过程序包管理器控制台来加载PCLsharp来实现C#中调用PCL1.打开VS菜单栏中的工具->NuGet包管理器-..._c#能不能操作pcl

Elasticsearch(五) idea es环境搭建以及对ES基本操作_idea配置springboot中es-程序员宅基地

文章浏览阅读2.8k次,点赞2次,收藏5次。步骤一、创建一个SpringBoot工程,pom.xml 如下:<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http._idea配置springboot中es