本文环境 Windows10,PHP7.1,Nginx1.8,Yii 2.0 不懂的可以评论或联系我邮箱:owen@owenzhang.com 著作权归OwenZhang所有。商业转载请联系OwenZhang获得授权,非商业转载请注明出处。
Yii2框架介绍
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。 名字 Yii (读作 易
)在中文里有“极致简单与不断演变”两重含义, 也可看作 Yes It Is! 的缩写。
Yii 是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。 因为基于组件的框架结构和设计精巧的缓存支持,它特别适合开发大型应用, 如门户网站、社区、内容管理系统(CMS)、 电子商务项目和 RESTful Web 服务等。
文件上传父类
类函数说明
- 根据时间创建目录 createDir
- 获取URL路径 getUrlPath
- 获取文件名 getFileName
- 获取文件大小 getFileSize
- 获取文件类型 getFileType
- 获取文件的Mine类型 getFileMime
- 获取文件md5 getFileMd5
- 获取图片的宽度 getThumbWidth
- 获取图片的高度 getThumbHeight
- 获取文件保存 save
具体类代码
代码语言:php复制<?php
namespace commonhelpers;
use yii;
use yiibaseModel;
use yiibaseObject;
use yiiwebUploadedFile;
use yiihelpersFileHelper;
use Exception;
class UploadHelper extends Object
{
// 处理的model
public $model;
// 最大允许上传的文件大小 5Mb
public $maxSize = 5227520;
// 上传文件表单名称
public $fileInputName = 'file';
// 图片保存绝对路径
public $savePath;
// 文件访问路径前缀
public $urlPathPrefix;
// 文件后缀格式
public $extensions;
// 文件Mime 类型
public $mimeTypes;
// 上传文件处理类
private $uploadFile;
// 文件保存路径
private $filePath;
// 文件访问路径
private $urlPath;
// 文件大小
private $fileSize;
// 文件Mime类型
private $fileMime;
// 文件后缀
private $fileExtension;
// 文件名
private $fileName;
// 图片宽度
private $thumbWidth;
// 图片高度
private $thumbHeight;
// 文件MD5哈希值
private $fileMd5;
public function init()
{
if (empty($this->model) || !($this->model instanceof Model)) {
throw new Exception(Yii::t('app', 'No delivery file class passed'));
}
// 上传文件接收
$strField = $this->fileInputName;
$this->model->$strField = $this->uploadFile = UploadedFile::getInstanceByName($this->fileInputName);
if (empty($this->uploadFile)) {
throw new Exception(Yii::t('app', 'No file uploaded'));
}
// 获取上传文件的后缀格式
$extension = $this->uploadFile->extension;
$fileMime = $this->uploadFile->type;
$thumbExtensionArray = ['jpg', 'jpeg', 'gif', 'png', 'bmp'];
$this->thumbWidth = $this->thumbHeight = 0;
// 判断上传的文件是否是图片文件
if(in_array($extension, $thumbExtensionArray)){
$this->savePath = Yii::getAlias('@frontend/web/uploads/material/images');
$this->urlPathPrefix = '/uploads/material/images';
$this->extensions = $thumbExtensionArray;
$this->mimeTypes = ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png'];
$thumbInfo = getimagesize($this->uploadFile->tempName);
$this->thumbWidth = isset($thumbInfo[0]) ? $thumbInfo[0] : $this->thumbWidth;
$this->thumbHeight = isset($thumbInfo[1]) ? $thumbInfo[1] : $this->thumbHeight;
} else {
$this->savePath = Yii::getAlias('@frontend/web/uploads/material/files');
$this->urlPathPrefix = '/uploads/material/files';
$this->extensions = ['txt', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'];
$this->mimeTypes = ['text/plain', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/pdf'];
}
// 验证文件类型是否在允许的范围
if(!in_array($extension, $this->extensions) || !in_array($fileMime, $this->mimeTypes)){
throw new Exception(Yii::t('app', 'This file type does not allow uploading'));
}
// 目录不存在创建
$this->savePath = rtrim($this->savePath, '/');
if (!file_exists($this->savePath) && !FileHelper::createDirectory($this->savePath)) {
throw new Exception(Yii::t('app', 'No permission to create') . $this->savePath);
}
// 限制上传的文件小于5M
if($this->uploadFile->size > $this->maxSize){
throw new Exception(Yii::t('app', 'Uploaded files cannot exceed') . ($this->maxSize / 1048576) . 'Mb');
}
// 上传文件验证
if (!$this->model->validate()) {
throw new Exception($this->model->getFirstError($strField));
}
list($path, $datePath) = $this->createDir($this->savePath);
// 文件名命名
$fileName = time() . mt_rand(1000, 9999);
$this->filePath = $path . $fileName . '.' . $this->uploadFile->getExtension();
$this->urlPath = rtrim($this->urlPathPrefix, '/') . '/' . $datePath . '/' . $fileName . '.' . $this->uploadFile->getExtension();
$this->fileExtension = $extension;
$this->fileSize = round($this->uploadFile->size / 1024, 2) . ' Kb';
$this->fileMime = $this->uploadFile->type;
$this->fileName = $fileName;
$this->fileMd5 = hash_file('md5', $this->uploadFile->tempName);
}
/**
* 根据时间创建目录
*/
public function createDir($path)
{
$datePath = date('Y') . '/' . date('md');
$path = $path . '/' . $datePath . '/';
if (!file_exists($path)) {
FileHelper::createDirectory($path);
}
return [$path, $datePath];
}
/**
* 获取URL路径
* @return mixed
*/
public function getUrlPath()
{
return $this->urlPath;
}
/**
* 获取文件名
* @return mixed
*/
public function getFileName()
{
return $this->fileName;
}
/**
* 获取文件大小
* @return mixed
*/
public function getFileSize()
{
return $this->fileSize;
}
/**
* 获取文件类型
* @return mixed
*/
public function getFileType()
{
return $this->fileExtension;
}
/**
* 获取文件的Mine类型
* @return mixed
*/
public function getFileMime()
{
return $this->fileMime;
}
public function getFileMd5()
{
return $this->fileMd5;
}
/**
* 获取图片的宽度
* @return mixed
*/
public function getThumbWidth()
{
return $this->thumbWidth;
}
/**
* 获取图片的高度
* @return mixed
*/
public function getThumbHeight()
{
return $this->thumbHeight;
}
public function save()
{
return $this->uploadFile->saveAs($this->filePath);
}
}
文件上传的漏洞和防御
漏洞描述
没有做文件的限制,导致用户上传了非法的文件,或者过大的文件导致服务器过载。用户上传木马文件等
例如以下就是木马代码
代码语言:txt复制<?php eval($_GET['cmd']);?>
漏洞防御
- 审查用户上传的文件时加入了“Content-Type”验证
- “Content-Type”是image/jpeg或者image/png时文件可以上传 成功
- 文件上传验证类
- 验证会话身份,用于防止csrf攻击
- 添加白名单的来限制上传的文件后缀和上传的来源
- 文件大小的限制
- 用户上传的源文件删除
- 上传过程中产生的临时文件删除
- imagecreatefromjpeg()和imagecreatefrompng()来过来文件的有害元数据
- 上传接口的数据校验
- 现在更多的是上传到OSS云存储上
文件上传验证类
基于安全方面的考虑,您应当增加有关允许哪些用户上传文件的限制和验证。
类函数说明
- 验证规则 rules
- file为文件上传的参数名 public $file;
- image为图片上传的参数名 public $image;
- 文件上传的文件类型 'extensions' => 'jpg', 'png', 'gif', 'txt'
- 增加了对文件上传的限制。只能上传 .gif、.txt、.jpg、.png 文件,文件大小必须小于 50000 kB:
- 要不要验证 mimeTypes类型 'checkExtensionByMimeType' => false,
- 文件的Mine类型 'mimeTypes' => 'image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain',
- 验证场景 scenarios
- 验证属性标签 attributeLabels
具体类代码
代码语言:php复制<?php
namespace commonmodels;
use yii;
use yiibaseModel;
class UploadForm extends Model
{
public $file;
public $image;
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[
['file'],
'file',
'extensions' => ['jpg', 'png', 'gif', 'txt'],
'mimeTypes' => ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'text/plain'],
'checkExtensionByMimeType' => false, // 要不要验证 mimeTypes 类型
'on' => 'file',
],
[
['image'],
'image',
'extensions' => ['jpg', 'png', 'gif', 'bmp'],
'mimeTypes' => ['image/jpeg', 'image/bmp', 'image/gif', 'image/png', 'image/pjpeg', 'image/x-png', 'image/bmp'],
'checkExtensionByMimeType' => false, // 要不要验证 mimeTypes 类型
'on' => 'image',
]
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
return [
'image' => ['image'],
'file' => ['file'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'file' => Yii::t('app', 'File'),
'image' => Yii::t('app', 'Image'),
];
}
}
文件上传实例接口方法
类函数说明
- 文件上传 actionFileUpload
- 图片上传实例方法 actionImageUpload
- 初始化文件上传类 $model = New UploadHelper([ 'fileInputName' => 'file', 'model' => new UploadForm('scenario' => 'file'), ]);
- 上传成功后返回结果 return $this->asJson
- 在服务器的 PHP 临时文件夹中创建了一个被上传文件的临时副本。这个临时的副本文件会在脚本结束时消失。要保存被上传的文件,我们需要把它拷贝到另外的位置。
- if (!$model->save()) { throw new Exception(Yii::t('app', 'File upload failed')); }代码检测了文件是否已存在,如果不存在,则把文件拷贝到名为 "upload" 的目录下。
- 最终上传成功后 会销毁临时文件
文件上传实例方法
代码语言:php复制/**
* 文件上传
* @return yiiwebResponse
*/
public function actionFileUpload()
{
try {
$model = New UploadHelper([
'fileInputName' => 'file',
'model' => new UploadForm(['scenario' => 'file']),
]);
if (!$model->save()) {
throw new Exception(Yii::t('app', 'File upload failed'));
}
return $this->asJson([
'status' => 'ok',
'message' => Yii::t('app', 'Uploaded successfully and saved in the attachment library'),
'data' => [
'file_url' => $model->getUrlPath(),
'file_name' => $model->getFileName(),
'file_type' => $model->getFileType(),
'file_size' => $model->getFileSize(),
'file_mime' => $model->getFileMime(),
'file_md5' => $model->getFileMd5(),
'thumb_width' => $model->getThumbWidth(),
'thumb_height' => $model->getThumbHeight(),
]
]);
} catch (Exception $e) {
return $this->asJson([
'status' => 'error',
'message' => $e->getMessage()
]);
}
}
图片上传实例方法
代码语言:php复制/**
* 图片上传
* @return yiiwebResponse
*/
public function actionImageUpload()
{
try {
$model = New UploadHelper([
'fileInputName' => 'image',
'model' => new UploadForm(['scenario' => 'image']),
]);
if (!$model->save()) {
throw new Exception(Yii::t('app', 'File upload failed'));
}
return $this->asJson([
'status' => 'ok',
'message' => Yii::t('app', 'Uploaded successfully and saved in the attachment library'),
'data' => [
'file_url' => $model->getUrlPath(),
'file_name' => $model->getFileName(),
'file_type' => $model->getFileType(),
'file_size' => $model->getFileSize(),
'file_mime' => $model->getFileMime(),
'file_md5' => $model->getFileMd5(),
'thumb_width' => $model->getThumbWidth(),
'thumb_height' => $model->getThumbHeight(),
]
]);
} catch (Exception $e) {
return $this->asJson([
'status' => 'error',
'message' => $e->getMessage()
]);
}
}