关于上传文件部分的危险,一直以来都有听说,但是之前为了方便,一直都是直接放到项目根目录,方便访问。只是现在项目越来越大,安全问题虽然不用刻意追求,但这些基本的地方还是要注意一下的。上传的路径最好是项目不能直接访问到的。
PHP 安全:如何防范用户上传 PHP 可执行文件
如链接文章所言,现在的jpg
里面也能编辑一些代码,所以上传的路径最好是项目不能直接访问到的。比如项目B在:/soft/www/B,
那么文件最好上传到/soft/www/images
这样的话,外界不能通过域名直接访问,会比较安全。包括下载的excel,csv
等文件,涉及到上传下载的部分都应该注意。
是的,我们成功的把图片上传到了非项目目录,我们已经预防了黑客们的一次进攻,lets cheers
。正在博主高兴的时候,前端展示图片的页面突然出问题了。是的,原来我们都是通过路径直接找到图片存储的位置,可是现在根本就无法通过路径去找到它。。。
1、直接绝对路径,试试文件协议访问
直接拼接地址,想要在本地直接看:C/project/images/aaa.png
答案: 这样访问不到,因为img
的src
默认是http
协议的,而我们这种写法是file
协议的,所以无法在网页上直接访问
2、使用js直接访问本地图片,然后转化为base64显示?
答案: 不可以,浏览器出于安全考虑,不允许web直接访问用户的文件系统。除非用input标签,或者小程序的平台(比如微信)有提供相应的接口。存储数据,微信有wx.setStorage
,H5有localstorage
、IndexedDB
。
在网上搜素的大部分答案都是需要用input
的file
文件上传来获取file
对象,我们这里不需要使用input
的上传标签,所以我在试了好几种方法之后无奈放弃
3、考虑写入文件,由JS读取文件
这个方案是在存储图片的时候,顺带存储一份base64
到文件吗,由JS
读取文件。
缺点:
(1)由JS
读取文件,那么php
每次刷新页面,文件都要重写
(2)js
读取之后,要在首先进行拆分,其次是按照id来拿到base64
,最后赋值给img
,性能上可能会慢很多,而且写入文件的话,会存在文件锁的问题,如果是多人访问的系统,尽量还是不要这么做。
(3)其次是写入的json
,为了让js
能读取到,那势必要放入到可访问目录的,通过ajax
的url
去访问json
文件,
ajax
是让js
能主动发起http
请求,达到不需要跳转url
就能发起请求拿到数据,那么意味着这个json
文件在浏览器上也是可访问的,这样的话为什么咱们不把图片直接上传到项目目录下呢?既然不准备上传到项目目录下,那用这个json
文件貌似也没意义。
(4)这个方案已经放弃,但是关于js读取文件还是可以学习的
js读取text文件:https://blog.csdn.net/qq_37338983/article/details/81567542
js读取json文件: var configure_json = $.ajax({url: “./json/configure.json”,async: false}).responseText;
var configure_json_val = $.parseJSON(configure_json);
alert(configure_json_val[0].holiday);
php使用file_get_contens写入json到json文件: https://zhidao.baidu.com/question/235095737.html
类似的方法: https://www.douban.com/note/710707937/
如果输出到页面JS接收,要注意编码一定要utf-8(json_encode 默认的就是utf-8编码)
4、使用基类直接生成随略图存起来
直接生成缩略图的话,最后还是避不开存储的问题。如果还是存储在项目内部,那其实是没有起到安全的作用。存在项目外的话,照样是能直接访问的。不过相对于直接上传文件存在项目内部,缩略图能稍微安全点。其次就是需要存储在数据库,要是用额外的字段去存储它。
具体的仁者见仁智者见智吧,感觉不是很好,并没有避过上面提出的安全问题。
想来想去,为了能成功访问到图片,并且避免跨域问题,尽量是转化为base64
返回。既然使用JS
无法达到目的,那就只能继续磨练我们的php
了。
(1)php转化图片路径为base64
生成缩略图基类下载地址:链接: https://pan.baidu.com/s/1L_C4hmmF-iLRrKcfyb13wA 提取码: h8yk
获取图片流并生成base64码:参考:https://blog.csdn.net/LJFPHP/article/details/79111844
php代码:
$img_path = $dir.$images; // 图片的哭啼路径
$thumb = new Thumbnail(100, 100); //设置缩略图大小为100*100
ob_start(); //开启缓冲,获取图片流
$thumb->loadFile($img_path);
$thumb->buildThumb();
$imageString = base64_encode(ob_get_contents()); //把获取的图片流转化为base64编码
ob_end_clean();
$base64_image = 'data:' .$thumb->getMine() . ';base64,' .$imageString; //拼接图片需要的base64格式
(2)js匹配id,给图片的src赋值
js代码:
if (data.code === "200") { //请求成功就进行赋值
if(data.images.length > 1){
$("#preview").css("display","block"); //图片显示
$("#portrait").attr("src",data.images); //给图片的src赋值
}
}
这样我们终于可以在前端页面上展示了我们的图片:
问题:
(1)页面上的base64可能会有几十个,占用大量的页面的资源,感觉是不好。
(2)其次是图片越大,最后生成的base64就越长,
(3)当base64很长的时候,也会影响到页面的加载速度。
(4)在页面加载之处,就把这些图片转化的base64都传输到页面上,本身反应速度也会受到影响
相关优化:
(1)使用一个生成缩略图的基类
(2)使用基类把图片生成较小的缩略图,然后直接把生成的图片流转化为base64的文件流,然后拼接返回给前端页面
优点:可以通过缩略图控制图片的大小,缩略图的图片小了之后,生成的base64码也少了,不会很影响加载速度
缺点: (1)页面上还是会有一部分显示base64的地方
(2)当页面上的base64码很多的时候,会影响页面的加载速度。这部分我们可以通过分页来避免一下
虽然我们的图片是展示出来了,但是速度实在堪忧。需要继续优化。
优化篇:
网页上的base64码太长?科普base64到底是啥
end