[MT Hack]MT上传文件的改动

MT的上传文件实在是太罗嗦了。向导式的多重选择,倒让人眼花缭乱,为了方便使用,决定修改之。
修改目标如下:

1。让上传文件自动过滤掉原文件名字中中文等非ascii名字,并自动小写。
这个是为了方便访问而已,何况自己的服务器是对大小写敏感的,MT上传文件是不改变原始名字的,这个是好处也是坏处,现在就是保留其对字母,数字名字的不改名,和对非字母,数字名字自动改名。

2。简化输出,直接上传后就有显示HTML代码的选项。
因为估计大家一般都选择生成HTML代码吧? 顺手根据自己习惯删除了“弹出式代码”,都是“include代码”了。但是并没有删除“以上传的文件/图片建立一个新Blog”的选择,只是把它放在了第2位而已。

3。删除了图片的缩略图功能。
缩略图觉得功能不大,这个对Perl来讲,资源消耗还是比较可观的,故删除之,但是作为补充,添加了如果上传图片宽度大于530px,则生成的HTML代码为按比例缩小尺寸的带原尺寸连接的代码。

具体修改流程如下:

1。先修改上传文件名字过滤及大小写问题。
这个在lib/MT/APP/CMS.pm 的函数sub upload_file { }里面。
原来文件名字的代码是

my $basename = $q->param('file') || $q->param('fname');
$basename =~ s!\\!/!g; ## Change backslashes to forward slashes
$basename =~ s!^.*/!!; ## Get rid of full directory paths

看的出来,只是简单处理掉了路径而已,我们在这个模块最后里添加一个自定义函数,作为再次处理名字的工具(为什么做函数呢,我想方便以后再次调用 :P ),代码如下:
# by EasunLee
sub _trim_name
{
my ($app,$fname) = @_;
$fname =~ s/^\s+|\s+$//gs;
$fname = lc($fname);
$fname =~s/[^\w.-]//g;
$fname = time().$fname if ($fname =~/^\./);
$fname;
}

然后定位回到上面的$basename处理后,添加
$basename = $app->_trim_name($basename); # by EasunLee

止此,第一步修改完成。


2。简化输出及删除缩略图。
第一次提交输出的定位函数依然是sub upload_file { };而HTML输出的函数来自sub _process_post_upload { }。这个就要求 upload_file函数中调用 _process_post_upload 。
于是定位到sub upload_file { }函数中

if ($param{is_image}) {
eval { require MT::Image; MT::Image->new or die; };
$param{do_thumb} = !$@ ? 1 : 0;
MT->run_callbacks('CMSUploadFile',
File => $local_file, Url => $url, Size => $bytes,
Type => 'image',
Blog => $blog);
MT->run_callbacks('CMSUploadImage',
File => $local_file, Url => $url, Size => $bytes,
Height => $h, Width => $w,
Type => 'image',
ImageType => $id,
Blog => $blog);
} else {
MT->run_callbacks('CMSUploadFile',
File => $local_file, Url => $url, Size => $bytes,
Type => 'file',
Blog => $blog);
}

修改
if ($param{is_image}) {
$q->param('include', '1');
# eval { require MT::Image; MT::Image->new or die; };
# $param{do_thumb} = !$@ ? 1 : 0;
MT->run_callbacks('CMSUploadFile',
File => $local_file, Url => $url, Size => $bytes,
Type => 'image',
Blog => $blog);
MT->run_callbacks('CMSUploadImage',
File => $local_file, Url => $url, Size => $bytes,
Height => $h, Width => $w,
Type => 'image',
ImageType => $id,
Blog => $blog);
} else {
$q->param('link', '1');
MT->run_callbacks('CMSUploadFile',
File => $local_file, Url => $url, Size => $bytes,
Type => 'file',
Blog => $blog);
}

并且在其后面添加
$q->param('url', $param{url});
$q->param('site_path', $param{site_path});
$q->param('fname', $param{fname});
$q->param('width', $param{width});
$q->param('height', $param{height});
$q->param('image_type', $param{image_type});

这些部分和前段修改中用颜色强调语句都是给_process_post_upload 函数初始化参数。
再在其后添加
$param{upload_html} =$app->_process_post_upload;

到这里upload_file函数已经添加了输出HTML功能。我们还需要修改_process_post_upload 函数来改进输出的HTML代码格式和修改输出模版文件(tmpl文件) tmpl/cms/upload_complete.tmpl 来完成输出界面的支持。
先说修改输出的HTML代码格式,定位函数 sub _process_post_upload{},
找到
my($thumb, $thumb_width, $thumb_height);
if ($thumb = $q->param('thumb')) {
require MT::Image;
my $base_path = $q->param('site_path') ?
$blog->site_path : $blog->archive_path;
my $file = $q->param('fname');
if ($file =~ m!\.\.|\0|\|!) {
return $app->error($app->translate("Invalid filename '[_1]'", $file));
}
my $i_file = File::Spec->catfile($base_path, $file);
## Untaint. We checked $file for security holes above.
($i_file) = $i_file =~ /(.+)/s;
my $fmgr = $blog->file_mgr;
my $data = $fmgr->get_data($i_file, 'upload')
or return $app->error($app->translate(
"Reading '[_1]' failed: [_2]", $i_file, $fmgr->errstr));
my $image_type = scalar $q->param('image_type');
my $img = MT::Image->new( Data => $data,
Type => $image_type )
or return $app->error($app->translate(
"Thumbnail failed: [_1]", MT::Image->errstr));
my($w, $h) = map $q->param($_), qw( thumb_width thumb_height );
(my($blob), $thumb_width, $thumb_height) =
$img->scale( Width => $w, Height => $h )
or return $app->error($app->translate("Thumbnail failed: [_1]",
$img->errstr));
require File::Basename;
my($base, $path, $ext) = File::Basename::fileparse($i_file, '\.[^.]*');
my $t_file = $path . $base . '-thumb' . $ext;
$fmgr->put_data($blob, $t_file, 'upload')
or return $app->error($app->translate(
"Error writing to '[_1]': [_2]", $t_file, $fmgr->errstr));

$file =~ s/\Q$base$ext\E$//;
my $url = $q->param('site_path') ? $blog->site_url : $blog->archive_url;
$url .= '/' unless $url =~ m!/$!;
$url .= $file;
$thumb = $url . encode_url($base . '-thumb' . $ext);
MT->run_callbacks('CMSUploadFile',
File => $t_file, Url => $thumb, Size => length($blob),
Type => 'thumbnail',
Blog => $blog);
MT->run_callbacks('CMSUploadImage',
File => $t_file, Url => $thumb,
Width => $thumb_width, Height => $thumb_height,
ImageType => $image_type,
Size => length($blob),
Type => 'thumbnail',
Blog => $blog);
}


这段为缩略图生成,彻底删除
然后紧接着的代码

if ($q->param('popup')) {
require MT::Template;
if (my $tmpl = MT::Template->load({ blog_id => $blog_id,
type => 'popup_image' })) {
(my $rel_path = $q->param('fname')) =~ s!\.[^.]*$!!;
if ($rel_path =~ m!\.\.|\0|\|!) {
return $app->error($app->translate(
"Invalid basename '[_1]'", $rel_path));
}
my $ext = $blog->file_extension || '';
$ext = '.' . $ext if $ext ne '';
require MT::Template::Context;
my $ctx = MT::Template::Context->new;
$ctx->stash('image_url', $url);
$ctx->stash('image_width', $width);
$ctx->stash('image_height', $height);
my $popup = $tmpl->build($ctx);
my $fmgr = $blog->file_mgr;
my $root_path = $q->param('site_path') ?
$blog->site_path : $blog->archive_path;
my $abs_file_path = File::Spec->catfile($root_path, $rel_path . $ext);

## If the popup filename already exists, we don't want to overwrite
## it, because it could contain valuable data; so we'll just make
## sure to generate the name uniquely.
my($i, $rel_path_ext) = (0, $rel_path . $ext);
while ($fmgr->exists($abs_file_path)) {
$rel_path_ext = $rel_path . ++$i . $ext;
$abs_file_path = File::Spec->catfile($root_path, $rel_path_ext);
}
my ($vol, $dirs, $basename) = File::Spec->splitpath($rel_path_ext);
my $rel_url_ext = File::Spec->catpath($vol, $dirs, encode_url($basename));

## Untaint. We have checked for security holes above, so we
## should be safe.
($abs_file_path) = $abs_file_path =~ /(.+)/s;
$fmgr->put_data($popup, $abs_file_path, 'upload')
or return $app->error($app->translate(
"Error writing to '[_1]': [_2]", $abs_file_path,
$fmgr->errstr));
$url = $q->param('site_path') ?
$blog->site_url : $blog->archive_url;
$url .= '/' unless $url =~ m!/$!;
$rel_url_ext =~ s!^/!!;
$url .= $rel_url_ext;
MT->run_callbacks('CMSUploadFile',
File => $abs_file_path, Url => $url,
Size => length($popup),
Type => 'popup',
Blog => $blog);
}
my $link = $thumb ? qq(<img src="$thumb" width="$thumb_width" height="$thumb_height" alt="" />) : q{<MT_TRANS phrase="View image">};
return $app->translate_templatized(<<"HTML");
<a href="$url" onclick="window.open('$url','popup','width=$width,height=$height,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false">$link</a>
HTML
}


这段是“弹出式图片”的HTML输出,也删除之。
下面的就是"include"方式图片和文件连接的代码了,
代码为:
elsif ($q->param('include') || $q->param('popup')) {
if ($thumb) {
return <<"HTML";
<a href="$url"><img alt="$fname" src="$thumb" width="$thumb_width" height="$thumb_height" /></a>
HTML
} else {
return <<"HTML";
<img alt="$fname" src="$url" width="$width" height="$height" />
HTML
}
} elsif ($q->param('link')) {
return $app->translate_templatized(<<"HTML");
<a href="$url"><MT_TRANS phrase="Download file"></a>
HTML
}

修改

if ($q->param('include') || $q->param('popup')) { #其实$q->param('popup')可以删除了,担心tmpl文件没有修改完,添在这里了
if ($width >530 ) {
return $app->translate_templatized(<<"HTML");
<a href="$url"><img alt="$fname" src="$url" width="530" title="<MT_TRANS phrase="View image">" /></a>
HTML
} else {
return <<"HTML";
<img alt="$fname" src="$url" width="$width" height="$height" />
HTML
}
} elsif ($q->param('link')) {
return $app->translate_templatized(<<"HTML");
<a href="$url"><MT_TRANS phrase="Download file"></a>
HTML
}

到此程序修改完成,我们去修改tmpl文件 tmpl/cms/upload_complete.tmpl (输出模版)。
这里都是些HTML代码,就不细说了,顺手加了段div和js和添加了HTML代码显示,修改完成的upload_complete.tmpl 文件内容如下:

<TMPL_INCLUDE NAME="header-popup.tmpl">
<!-- Modify By EasunLee 2006/09/28 -->

<script type="text/javascript">
<!--

function doClick (f, mode) {
<TMPL_IF NAME=CAN_POST>
if (f.new_entry[1].checked)
doStartEntry(f, mode);
else
</TMPL_IF>
window.close();
}

function doShowHTML (mode) {
var _divs= document.getElementById("ShowHtmlDIV");
if (mode == 1) _divs.style.display="block";
else _divs.style.display="none";
}

function doStartEntry (f, mode) {
var url = '<TMPL_VAR NAME=SCRIPT_URL>?__mode=start_upload_entry&blog_id=<TMPL_VAR NAME=BLOG_ID>&url=<TMPL_VAR NAME=URL ESCAPE=URL>&site_path=<TMPL_VAR NAME=SITE_PATH>&fname=<TMPL_VAR NAME=FNAME ESCAPE=URL>&' + mode;
window.opener.location = url;
window.close();
}

//-->
</script>

<form action="<TMPL_VAR NAME=SCRIPT_URL>" onsubmit="return false;">

<h2><span class="weblog-title-highlight"><TMPL_VAR NAME=BLOG_NAME ESCAPE=HTML>:</span> <MT_TRANS phrase="Upload File"></h2>

<p><MT_TRANS phrase="The file named '[_1]' has been uploaded. Size: [quant,_2,byte]." params="<TMPL_VAR NAME=FNAME ESCAPE=HTML>%%<TMPL_VAR NAME=BYTES>"></p>
<label><input type="radio" name="new_entry" value="0" checked="checked" onClick="doShowHTML('1')" /> <MT_TRANS phrase="Show me the HTML"></label>

<div id="ShowHtmlDIV" name="ShowHtmlDIV">
<p><label for="html"><MT_TRANS phrase="Copy and paste this HTML into your entry."></label></p>
<p>
<textarea name="html" id="html" rows="10" style="width: 100%;"><TMPL_VAR NAME=UPLOAD_HTML ESCAPE=HTML></textarea>
</p>
</div>

<TMPL_IF NAME=CAN_POST>
<p>
<label><input type="radio" name="new_entry" value="1" onClick="doShowHTML('0')" /> <MT_TRANS phrase="Create a new entry using this uploaded file"></label> <a href="#" onclick="return openManual('file_upload', 'creating_a_new_entry')" class="help">?</a><br />
</p>
</TMPL_IF>

<div>
<TMPL_IF NAME=IS_IMAGE>
<input type="button" onclick="doClick(this.form, 'include=1&width=<TMPL_VAR NAME=WIDTH>&height=<TMPL_VAR NAME=HEIGHT>&image_type=<TMPL_VAR NAME=IMAGE_TYPE>')" value="<MT_TRANS phrase="Go">/<MT_TRANS phrase="Close">" />
<TMPL_ELSE>
<input type="button" onclick="doClick(this.form, 'link=1')" value="<MT_TRANS phrase="Go">/<MT_TRANS phrase="Close">" />
</TMPL_IF>
<input type="button" onclick="window.location='<TMPL_VAR NAME=SCRIPT_URL>?__mode=start_upload&amp;blog_id=<TMPL_VAR NAME=BLOG_ID>'" value="<MT_TRANS phrase="Upload Another">" />
</div>

</form>

<TMPL_INCLUDE NAME="footer-popup.tmpl">

至此,所有的 Hack 工作完成,后台上传几个文件/图片测试,一切符合要求。
完成后显示界面如下:
1159408739.png

看来,折腾 MT ,也是其乐融融哦:)
By 路杨(Easun) 2006/09/28