正式接触PHP cms模块开发后.开发了几个功能 模块.其中遇到了需要批量上传 图片 的问题.于是开始挖掘PHP cms里面的swfupload的用法 .
在PHP cms里面自带 的内容 类型里面能够直接指定图片 组.不过这样的图片 组功能 并不是我想用的.我需要上传 一整个静态的html文件 .需要
能够找到一个方法 上传 整个文件 夹.并且能够保留原来的文件 名称 .
目的总结如下:
1,不改变系统的文件 和目录结构.
在PHP cms中自带 了附件上传 的功能 .我想去用swfupload功能 ,而这个功能 被PHP cms的附件上传 功能 集成进去了.那我要做的就是抽出来并加以修改 .
第一步,我来研究研究这个是怎么调用 的.
首先,打开firefox浏览器的firebug 打开网络面板.找到PHP cm中swfupload呗调出的那个按钮.看看系统是请求的什么连接.
?m=attachment&c=attachments&a=swfupload&args=10,1&module=&catid=&authkey=b756a93dea2e627293e88fa9d62af709&pc_hash=iXFbo1
我们捕捉到一串这样的请求.
调用 了attachment模块的attachements控制器里面的swfupload
方法 .
我们去找到这个模块中的这个控制器里面的这个方法 .
在PHP cms/modoules/attachemet/attachemts.PHP 里面
打开看看,代码 如下 public function swfupload(){
$grouplist = getcache('grouplist','member');
if(isset($_POST['dosubmit'])){
//if里面的
内容 我们暂时不看.因为这是
上传 之后的处理.我们要先找到是如何引入swfupload的.
} else {
if($this->isadmin==0 && !$grouplist[$this->groupid]['allowattachment']) showmessage(L('att_no_permission'));
$args = $_GET['args'];//得到参数
$authkey = $_GET['authkey'];//得到密匙
if(upload_key($args) != $authkey) showmessage(L('attachment_parameter_error'));//验证密匙
extract(getswfinit($_GET['args']));//拆分参数
$siteid = $this->get_siteid();//得到网站id
$site_setting = get_site_setting($siteid);//得到网站设置
$file_size_limit = sizecount($site_setting['upload_maxsize']*1024);//允许
上传 大小
$att_not_used = param::get_cookie('att_json');//得到未处理的
文件 列表
if(empty($att_not_used) || !isset($att_not_used)) $tab_status = ' class="on"';//如果有未处理的设置
标签 样式为on
if(!empty($att_not_used)) $div_status = ' hidden';//否则隐藏
标签 $att = $this->att_not_used();//
获取 临时未处理
文件 列表
include $this->admin_tpl('swfupload');//这个地方才是关键.加载了这个模板.
}
}
前面的我们就先不管了,那是处理
上传 的东西.我从else开始看.首先验证了是否允许附件
上传
然后从$_GET里面得到swfupload的参数args,然后去验证了密匙,密匙通过了去解析args.得到网站的id,得到网站的设置,得到允许上传 附件的大小.从cookie里面得到未使用的附件列表.
设置模板里面的各种显示 .最后也是最关键的.它使用了swfupload模板.也就是说我要找到这个模板.看看swfupload是怎么引过来的.
模板在这里:PHP cms/modules/attachment/templates/swfupload.tpl.PHP
打开模板文件 .模板文件 上面引入了一堆文件 :
403"> admin_tpl('header','attachment');?>
首先是引入了头
文件 .我大概看里一下.里面有jquery什么的.是必要
文件 .所以一会我们要用的时候也要引入这个头.
之后是swfupload的样式文件 和必要的JS.这里调用 了一个系统函数 initupload,这个函数 到底是干嘛的.
千万别小觑这行.整个swfupload的配置都在这里了.
我们去找找看这个函数 .
在PHP cms/modules/attachment/functions/golable.func.PHP 里面找到了它的踪迹.代码 如下,这个函数 的主要作用就是配置swfupload这个插件 .
/* flash
上传 初始化
* 初始化swfupload
上传 中需要的参数
* @param $module 模块
名称 * @param $catid 栏目id
* @param $args 传递参数
* @param $userid
用户 id
* @param $groupid
用户 组id
* @param $isadmin 是否为
管理员 模式
*/
function initupload($module,$catid,$userid,$groupid = '8',$isadmin = '0'){
$grouplist = getcache('grouplist','member');
if($isadmin==0 && !$grouplist[$groupid]['allowattachment']) return false;
extract(getswfinit($args));
$siteid = param::get_cookie('siteid');
$site_setting = get_site_setting($siteid);
$file_size_limit = $site_setting['upload_maxsize'];
$sess_id = SYS_TIME;
$swf_auth_key = md5(pc_base::load_config('system','auth_key').$sess_id);
$init = 'var swfu = \'\';
$(document).ready(function(){
swfu = new SWFUpload({
flash_url:"'.JS_PATH.'swfupload/swfupload.swf?"+Math.random(),
upload_url:"'.APP_PATH.'index.
PHP ?m=attachment&c=attachments&a=swfupload&dosubmit=1",
file_post_name : "Filedata",
post_params:{"SWFUPLOADSESSID":"'.$sess_id.'","module":"'.$module.'","catid":"'.$_GET['catid'].'","userid":"'.$userid.'","siteid":"'.$siteid.'","dosubmit":"1","thumb_width":"'.$thumb_width.'","thumb_height":"'.$thumb_height.'","watermark_enable":"'.$watermark_enable.'","filetype_post":"'.$file_types_post.'","swf_auth_key":"'.$swf_auth_key.'","isadmin":"'.$isadmin.'","groupid":"'.$groupid.'"},
file_size_limit:"'.$file_size_limit.'",
file_types:"'.$file_types.'",
file_types_description:"All Files",
file_upload_limit:"'.$file_upload_limit.'",
custom_settings : {progressTarget : "fsUploadProgress",cancelButtonId : "btnCancel"},
button_image_url: "", button_width: 75, button_height: 28, button_placeholder_id: "buttonPlaceHolder", button_text_style: "", button_text_top_padding: 3, button_text_left_padding: 12, button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT, button_cursor: SWFUpload.CURSOR.HAND,
file_dialog_start_handler : fileDialogStart, file_queued_handler : fileQueued, file_queue_error_handler:fileQueueError, file_dialog_complete_handler:fileDialogComplete, upload_progress_handler:uploadProgress, upload_error_handler:uploadError, upload_success_handler:uploadSuccess, upload_complete_handler:uploadComplete }); })'; return $init; }
回到正题.我们来看模板swfupload.tpl.
PHP
这个模板使用了一个js来控制
以页签的形式显示 .我们可以用firebug去找到带有我们要找到的swfupload按钮的那个页签的id
那个id是tab_swf_1
这个是一个div 代码 如下. 在这里我们看到有一个span id是buttonPlaceHolder 而在
配置文件 中有这么一行button_placeholder_id: "buttonPlaceHolder",很明显.当
页面 被加载的时候 id为buttonPlaceHolder的元素会被JS替换成swfupload的
上传 控件.
之后一步我们要在点选完文件 之后触发swf的上传 方法
会在代码 中找到如下代码 .这里面调用 了swfu.startUpload()方法 .这个方法 定义的地方在swfupload.js里面.我们无需理会.
至此.我们已经找到了swfupload的上传 控件使用方法
怎么在我的程序里面调用 这个东东呢
首先一点 我们需要在这个控件出现的模板里面引入这些必要的文件
代码 如上所示.
然后在我们的模板里面想要放置swfupload的地方写上这样的标签
上传等功能 .
但是这样还不能达到我们的需求.而且有一个问题.我们把文件 上传 到神马地方去了.那我们就来找找我们把文件 上传 到神马地方去了
在配置文件 (用initupload函数 输出 的)里面有这样一行
upload_url:"'.APP_PATH.'index.
PHP ?m=attachment&c=attachments&a=swfupload&dosubmit=1",
这个很明显就透露出了我们把文件 上传 到了attachment模块中attachments控制器里面的swfupload方法 去处理了
这个地方也就是我之前没有关注的if里面的东西.
拿出来看看
if( $_POST['swf_auth_key'] != md5(pc_base::load_config('system','auth_key').$_POST['SWFUPLOADSESSID']) || ($_POST['isadmin']==0 && !$grouplist[$_POST['groupid']]['allowattachment'])) exit(); pc_base::load_sys_class('attachment','',0); $attachment = new attachment($_POST['module'],$_POST['catid'],$_POST['siteid']); $attachment->set_userid($_POST['userid']); $aids = $attachment->upload('Filedata',$_POST['filetype_post'],array($_POST['thumb_width'],$_POST['thumb_height']),$_POST['watermark_enable']); if($aids[0]) { $filename= (strtolower(CHARSET) != 'utf-8') ? iconv('gbk','utf-8',$attachment->uploadedfiles[0]['filename']) : $attachment->uploadedfiles[0]['filename']; if($attachment->uploadedfiles[0]['isimage']) { echo $aids[0].','.$this->upload_url.$attachment->uploadedfiles[0]['filepath'].','.$attachment->uploadedfiles[0]['isimage'].','.$filename; } else { $fileext = $attachment->uploadedfiles[0]['fileext']; if($fileext == 'zip' || $fileext == 'rar') $fileext = 'rar'; elseif($fileext == 'doc' || $fileext == 'docx') $fileext = 'doc'; elseif($fileext == 'xls' || $fileext == 'xlsx') $fileext = 'xls'; elseif($fileext == 'ppt' || $fileext == 'pptx') $fileext = 'ppt'; elseif ($fileext == 'flv' || $fileext == 'swf' || $fileext == 'rm' || $fileext == 'rmvb') $fileext = 'flv'; else $fileext = 'do'; echo $aids[0].','.$fileext.','.$filename; } exit; } else { echo '0,'.$attachment->error(); exit;
这个里面有几行是比较重要的.
首先它载入了系统的attachment类.并且用到了里面的方法 .
程序对上传 成功做了echo操作.返回的东西是 返回了编号,上传 后的地址,拓展名,文件 名.
这些东西是给谁用的啊 我们还得回去看配置文件 .
配置文件 里面有一段是上传 过程中各个事件将触发的方法 . 有开始上传 的.有上传 成功的,有上传 失败的.等等.
我们可以看见有一个方法 是file_dialog_complete_handler:fileDialogComplete,
其实这些已经升级 到swfupload的范畴了.有兴趣可以去研究研究
然后我们在PHP cms/static/swfupload/handler.js里面找到这个方法 .
看见上传 成功后echo出来的数据被解析了.
解析的方法 如下 function att_show(serverData,file)
{
var serverData = serverData.replace(/
/g,''); var data = serverData.split(','); var id = data[0]; var src = data[1]; var ext = data[2]; var filename = data[3]; if(id == 0) { alert(src) return false; } if(ext == 1) { var img = ' '; } else { var img = ' '; } $.get('index.PHP ?m=attachment&c=attachments&a=swfupload_json&aid='+id+'&src='+src+'&filename='+filename); $('#fsUploadProgress').append(''); $('#attachment_'+id).html(img); $('#att-status').append('|'+src); $('#att-name').append('|'+filename); }
这个方法 的目的是在id为fsuuploadprogress的元素里面添加 我们上传 成功的附件.但是我们还木有找到文件 到底去哪里了
关键的地方来了.我们在swfupload方法 里面不是有个attachment的系统类的实例么
真正上传 附件是在这里实现的.我们调用 了attachment里面的upload方法 来实现了文件 的上传 .
这个attachment文件 里面的upload方法 在系统类里面 也就是PHP cms/libs/classes/attachment.class.PHP 里面
在这个类里面我们可以找到upload方法 里面有这样一行
$this->savepath = $this->upload_root.$this->upload_dir.date('Y/md/');
这个自然就是指定了上传 到的目录.文件 名是通过getname方法 来获取 的.
到这里我们就理清思路了.
系统是这么运行的
首先在模板里面引用swfupload(配置文件 是用函数 生成 的)->上传 文件 ->attachment模块里的swfupload方法 处理(使用系统的attachment类里面的upload方法 循环上传 附件.并返回结果给swfupload方法 )->处理结果通过swfupload的方法 (fileDialogComplete)返回给页面 .
在上面我们已经实现了在模板里面引入swfupload.但是我们使用的配置文件 和上传 附件的方法 等都是系统原来自带 的.并不能实现我想要的目录结构和文件 命名方法 .怎么办..
改.
怎么改,首先们要把配置文件 改掉. 在自己的模块里面的functions文件 夹里面建立自己的函数 .我们用自己的函数 名称 文件 命名为global.func.PHP 这样系统会通过auto_load把我们的函数 加载
进去我们把系统中attachment模块functions文件 夹下面的global.func.PHP 里面的initupload函数 全盘拷贝进来.只修改 其中的一行
upload_url:"'.APP_PATH.'index.
PHP ?m=你的模块
名称 &c=你的控制器
名称 &a=你的
方法 名称 &dosubmit=1",
这样文件 就会提交到我们的控制器下面.并且调用 我们自己写的方法
然后我们去改系统的attachment类 我们在自己的模块下的classes文件 夹下面建立一个myattachment.class.PHP
写一个我们自己的类.去集成系统的attachment类.(记得吧里面的私有方法 copy过来.)我们需要修改 几行.首先一点是吧upload方法 里面的上传目录 改掉.然后是改掉文件 名的命名方法 .
function upload($field,$alowexts = '',$maxsize = 0,$overwrite = 0,$thumb_setting = array(),$watermark_enable = 1) {
if(!isset($_FILES[$field])) {
$this->error = UPLOAD_ERR_OK;
return false;
}
if(empty($alowexts) || $alowexts == '') {
$site_setting = $this->_get_site_setting($this->siteid);
$alowexts = $site_setting['upload_allowext'];
}
$fn = $_GET['CKEditorFuncNum'] ? $_GET['CKEditorFuncNum'] : '1';
$this->field = $field; $this->savepath = $this->upload_root.$this->upload_dir.date('Ymd');//这里我们需要修改 下.也可以不修改 .在我们实例化这个类的时候再来指定目录. $this->alowexts = $alowexts; $this->maxsize = $maxsize; $this->overwrite = $overwrite; $uploadfiles = array(); $description = isset($GLOBALS[$field.'_description']) ? $GLOBALS[$field.'_description'] : array(); if(is_array($_FILES[$field]['error'])) { $this->uploads = count($_FILES[$field]['error']); foreach($_FILES[$field]['error'] as $key => $error) { if($error === UPLOAD_ERR_NO_FILE) continue; if($error !== UPLOAD_ERR_OK) { $this->error = $error; return false; } $uploadfiles[$key] = array('tmp_name' => $_FILES[$field]['tmp_name'][$key],'name' => $_FILES[$field]['name'][$key],'type' => $_FILES[$field]['type'][$key],'size' => $_FILES[$field]['size'][$key],'error' => $_FILES[$field]['error'][$key],'description'=>$description[$key],'fn'=>$fn); } } else { $this->uploads = 1; if(!$description) $description = ''; $uploadfiles[0] = array('tmp_name' => $_FILES[$field]['tmp_name'],'name' => $_FILES[$field]['name'],'type' => $_FILES[$field]['type'],'size' => $_FILES[$field]['size'],'error' => $_FILES[$field]['error'],'description'=>$description,'fn'=>$fn); }
if(!dir_create($this->savepath)) { $this->error = '8'; return false; } if(!is_dir($this->savepath)) { $this->error = '8'; return false; } @chmod($this->savepath,0777);
if(!is_writeable($this->savepath)) { $this->error = '9'; return false; } if(!$this->is_allow_upload()) { $this->error = '13'; return false; } $aids = array(); foreach($uploadfiles as $k=>$file) { $fileext = fileext($file['name']); if($file['error'] != 0) { $this->error = $file['error']; return false; } if(!preg_match("/^(".$this->alowexts.")$/",$fileext)) { $this->error = '10'; return false; } if($this->maxsize && $file['size'] > $this->maxsize) { $this->error = '11'; return false; } if(!$this->isuploadedfile($file['tmp_name'])) { $this->error = '12'; return false; } //$temp_filename = $this->getname($fileext);//名称 在这里.我们需要修改 下 $temp_filename = $file['tmp_name'].$fileext; //修改 成原来的系统文件 名称 . $savefile = $this->savepath.$temp_filename; $savefile = preg_replace("/(PHP |phtml|PHP 3|PHP 4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i","_\\1\\2",$savefile); $filepath = preg_replace(new_addslashes("|^".$this->upload_root."|"),"",$savefile); if(!$this->overwrite && file_exists($savefile)) continue; $upload_func = $this->upload_func; if(@$upload_func($file['tmp_name'],$savefile)) { $this->uploadeds++; @chmod($savefile,0644); @unlink($file['tmp_name']); $file['name'] = iconv("utf-8",CHARSET,$file['name']); $uploadedfile = array('filename'=>$file['name'],'filepath'=>$filepath,'filesize'=>$file['size'],'fileext'=>$fileext,'fn'=>$file['fn']); $thumb_enable = is_array($thumb_setting) && ($thumb_setting[0] > 0 || $thumb_setting[1] > 0 ) ? 1 : 0; $image = new image($thumb_enable,$this->siteid); if($thumb_enable) { $image->thumb($savefile,$thumb_setting[0],$thumb_setting[1]); } if($watermark_enable) { $image->watermark($savefile,$savefile); } $aids[] = $this->add($uploadedfile); } } return $aids; }
注:这里我们可以再系统的attachment模块下建立MY_attachment.PHP 但是这样会影响系统的附件上传 功能 .
在我们自己的控制器里面.我们这个时候就需要加载自己写的类了. pc_base::load_app_class('你的模块名',0);
其余的操作可以参照系统的attachment模块下的attachments控制器里面的swfupload方法 来修改 .
至此.我便完成了我的目的.在不改变系统文件 目录的基础上.完成我自己想要的文件 上传 功能 .