上传是一个网站里必不可少的功能,我们借助TP的上传类,可以方便的支持上传回调和云空间上传。
## 编辑器上传
为了简化问题,我们只允许编辑器里上传图片。
然后编辑器配置里指定了上传的方法
![2015-06-22/558804a303675](http://box.kancloud.cn/2015-06-22_558804a303675.png)
然后虽然对应方法只有几行代码:
~~~
public function ueditor(){
$data = new \Org\Util\Ueditor();
die($data->output());
}
~~~
但是还要设置对应的json配置
![2015-06-22/558805272baff](http://box.kancloud.cn/2015-06-22_558805272baff.png)
如对应的保存目录、后缀等规则。
这里注意,编辑器上传的类里把不同文件类型的划分了不同的action。
![2015-06-22/558805c82074d](http://box.kancloud.cn/2015-06-22_558805c82074d.png)
而我的图片上传插件plupload由于返回和系统上传的不一样,我干脆就利用了编辑器上传,通过穿参上传图片。
![2015-06-22/5588062d34ead](http://box.kancloud.cn/2015-06-22_5588062d34ead.png)
~~~
public function plupload(){
$data = new \Org\Util\Ueditor();
$json = $data->output();
$result = json_decode($json, 1);
if('SUCCESS' == $result['state']){
$output = array(
'ok'=>1,
'path'=>$result['url'],
);
}else{
$output = array(
'ok'=>0,
'code'=>$result['state'],
);
}
die(json_encode($output));
}
~~~
## 系统上传
系统上传主要把上传的对象定位图片和文件两种类型。
然后参照OneThink,给不同类型设置不同的驱动和上传配置。两种类型的文件分别存在File表和Picture表里。
上传配置:
~~~
'PICTURE_UPLOAD_DRIVER'=>'Local',
'FILE_UPLOAD_DRIVER'=>'Local',
/* 文件上传相关配置 */
'FILE_UPLOAD' => array(
'mimes' => '', //允许上传的文件MiMe类型
'maxSize' => 1024*1024*1024, //上传的文件大小限制 (0-不做限制)
'exts' => 'jpg,gif,png,jpeg,zip,rar,tar,gz,7z,doc,docx,txt,xml,mp3,mp4', //允许上传的文件后缀
'autoSub' => true, //自动子目录保存文件
'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组
'rootPath' => './Uploads/file/', //保存根路径
'savePath' => '', //保存路径
'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组
'saveExt' => '', //文件保存后缀,空则使用原后缀
'replace' => false, //存在同名是否覆盖
'hash' => true, //是否生成hash编码
'callback' => false, //检测文件是否存在回调函数,如果存在返回文件信息数组
), //下载模型上传配置(文件上传类配置)
/* 图片上传相关配置 */
'PICTURE_UPLOAD' => array(
'mimes' => '', //允许上传的文件MiMe类型
'maxSize' => 2*1024*1024, //上传的文件大小限制 (0-不做限制)
'exts' => 'jpg,gif,png,jpeg,tmp', //允许上传的文件后缀
'autoSub' => true, //自动子目录保存文件
'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组
'rootPath' => './Uploads/picture/', //保存根路径
'savePath' => '', //保存路径
'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组
'saveExt' => '', //文件保存后缀,空则使用原后缀
'replace' => false, //存在同名是否覆盖
'hash' => true, //是否生成hash编码
'callback' => false, //检测文件是否存在回调函数,如果存在返回文件信息数组
), //图片上传相关配置(文件上传类配置)
~~~
上传主要代码:
~~~
public function ajaxUpload($model= 'File',$field='file') {
$params = array('model'=>$model, 'field'=>$field);
slog($params);
$result = $this->upload($params);
if ($result['status']) {
$result['info'] = '上传成功';
} else {
$result['status'] = 0;
$result['info'] = '上传失败'.$result['info'];
}
$this->ajaxReturn($result);
}
protected function upload($params) {
slog($params);
/* 返回标准数据 */
$return = array('status' => 1, 'info' => '上传成功', 'data' => '');
$model = $params['model'] == 'Picture'? 'Picture' : 'File';
/* 调用文件上传组件上传文件 */
$table = D($model);
$driver = C("{$model}_UPLOAD_DRIVER");
d_f('upload', $driver);
$upload_config = C("{$model}_UPLOAD");
d_f('upload', $upload_config);
if(isset($params['rootPath']))
$upload_config['rootPath'] = $params['rootPath'];
$info = $table->upload($_FILES, $upload_config, $driver, C("UPLOAD_{$driver}_CONFIG"));
d_f('upload', $info);
/* 记录图片信息 */
if ($info) {
$return['status'] = 1;
$return = array_merge($info[$params['field']], $return);
if (method_exists($this, 'after_upload')) {
$this->after_upload(CONTROLLER_NAME, $info, $result);
}
} else {
$return['status'] = 0;
$return['info'] = $table->getError();
}
d_f('upload', $return);
return $return;
}
~~~
先是封装了一个上传方法,并且支持回调`after_upload`。
然后,封装了一个系统用的ajaxUpload 方法用于返回json响应。
上传方法中调用对应模型的upload方法,比如FileModel的upload
~~~
/**
* 文件上传
* @param array $files 要上传的文件列表(通常是$_FILES数组)
* @param array $setting 文件上传配置
* @param string $driver 上传驱动名称
* @param array $config 上传驱动配置
* @return array 文件上传成功后的信息
*/
public function upload($files, $setting, $driver = 'Local', $config = null){
/* 上传文件 */
$setting['callback'] = array($this, 'isFile');
$setting['removeTrash'] = array($this, 'removeTrash');
$Upload = new Upload($setting, $driver, $config);
$info = $Upload->upload($files);
/* 设置文件保存位置 */
$this->_auto[] = array('location', 'ftp' === strtolower($driver) ? 1 : 0, self::MODEL_INSERT);
if($info){ //文件上传成功,记录文件信息
foreach ($info as $key => &$value) {
/* 已经存在文件记录 */
if(isset($value['id']) && is_numeric($value['id'])){
$value['path'] = substr($setting['rootPath'], 1).$value['savepath'].$value['savename']; //在模板里的url路径
continue;
}
/* 记录文件信息 */
$value['path'] = substr($setting['rootPath'], 1).$value['savepath'].$value['savename']; //在模板里的url路径
if($this->create($value) && ($id = $this->add())){
$value['id'] = $id;
} else {
//TODO: 文件上传成功,但是记录文件信息失败,需记录日志
unset($info[$key]);
}
}
return $info; //文件上传成功
} else {
$this->error = $Upload->getError();
return false;
}
}
~~~
方法进行了文件重复的上传判断和上传完毕后入库的操作。
为了方便在没有slog的时候调试。我还写了一个`d_f`函数 替代f函数写文件记录调试信息。
~~~
/**
* 快速文件数据读取和保存 针对简单类型数据 字符串、数组
* @param string $name 缓存名称
* @param mixed $value 缓存值
* @param string $path 缓存路径
* @return mixed
*/
function d_f($name, $value, $path = DATA_PATH) {
static $_cache = array();
$filename = $path . $name . '.php';
if ('' !== $value) {
if (is_null($value)) {
// 删除缓存
// return false !== strpos($name,'*')?array_map("unlink", glob($filename)):unlink($filename);
} else {
// 缓存数据
$dir = dirname($filename);
// 目录不存在则创建
if (!is_dir($dir))
mkdir($dir, 0755, true);
$_cache[$name] = $value;
$content = strip_whitespace("<?php\treturn " . var_export($value, true) . ";?>") . PHP_EOL;
return file_put_contents($filename, $content, FILE_APPEND);
}
}
if (isset($_cache[$name]))
return $_cache[$name];
// 获取缓存数据
if (is_file($filename)) {
$value = include $filename;
$_cache[$name] = $value;
} else {
$value = false;
}
return $value;
}
~~~
他比f函数直接写日志的优势是,追加记录文件。
像这样
![2015-06-22/558809f9db5e9](http://box.kancloud.cn/2015-06-22_558809f9db5e9.png)
默认记录在runtime 下data目录里。
- 序
- 前言
- 内容简介
- 目录
- 基础知识
- 起步
- 控制器
- 模型
- 模板
- 命名空间
- 进阶知识
- 路由
- 配置
- 缓存
- 权限
- 扩展
- 国际化
- 安全
- 单元测试
- 拿来主义
- 调试方法
- 调试的步骤
- 调试工具
- 显示trace信息
- 开启调试和关闭调试的区别
- netbeans+xdebug
- Socketlog
- PHP常见错误
- 小黄鸭调试法,每个程序员都要知道的
- 应用场景
- 第三方登录
- 图片处理
- 博客
- SAE
- REST实践
- Cli
- ajax分页
- barcode条形码
- excel
- 发邮件
- 汉字转全拼和首字母,支持带声调
- 中文分词
- 浏览器useragent解析
- freelog项目实战
- 需求分析
- 数据库设计
- 编码实践
- 前端实现
- rest接口
- 文章发布
- 文件上传
- 视频播放
- 音乐播放
- 图片幻灯片展示
- 注册和登录
- 个人资料更新
- 第三方登录的使用
- 后台
- 微信的开发
- 首页及个人主页
- 列表
- 归档
- 搜索
- 分页
- 总结经验
- 自我提升
- 进行小项目的锻炼
- 对现有轮子的重构和移植
- 写技术博客
- 制作视频教程
- 学习PHP的知识和新特性
- 和同行直接沟通、交流
- 学好英语,走向国际
- 如何参与
- 浏览官网和极思维还有看云
- 回答ThinkPHP新手的问题
- 尝试发现ThinkPHP的bug,告诉官方人员或者push request
- 开发能提高效率的ThinkPHP工具
- 尝试翻译官方文档
- 帮新手入门
- 创造基于ThinkPHP的产品,进行连带推广
- 展望未来
- OneThink
- ThinkPHP4
- 附录