30.7.3 多文件上载的处理

文件上载代码是一个单独的文件upload.php,该文件的完整代码如程序清单30-16所示。

程序清单30-16 upload.php——上载新闻信件所需的所有文件脚本


<?php

//this functionality is in a separate file to allow us to be

//more paranoid with it

//if anything goes wrong,we will exit

$max_size=50000;

include('include_fns.php');

session_start();

//only admin users can upload files

if(!check_admin_user()){

echo"<p>You do not seem to be authorized to use this page.</p>";

exit;

}

//set up the admin toolbar buttons

$buttons=array();

$buttons[0]='change-password';

$buttons[1]='create-list';

$buttons[2]='create-mail';

$buttons[3]='view-mail';

$buttons[4]='log-out';

$buttons[5]='show-all-lists';

$buttons[6]='show-my-lists';

$buttons[7]='show-other-lists';

do_html_header('Pyramid-MLM-Upload Files');

display_toolbar($buttons);

//check that the page is being called with the required data

if((!$_FILES['userfile']['name'][0])||

(!$_FILES['userfile']['name'][1])||

(!$_POST['subject']||!$_POST['list'])){

echo"<p>Problem:You did not fill out the form fully.

The images are the only optional fields.

Each message needs a subject,text version

and an HTML version.</p>";

do_html_footer();

exit;

}

$list=$_POST['list'];

$subject=$_POST['subject'];

if(!($conn=db_connect())){

echo"<p>Could not connect to db.</p>";

do_html_footer();

exit;

}

//add mail details to the DB

$query="insert into mail values(NULL,

'".$_SESSION['admin_user']."',

'".$subject."',

'".$list."',

'STORED',NULL,NULL)";

$result=$conn->query($query);

if(!$result){

do_html_footer();

exit;

}

//get the id MySQL assigned to this mail

$mailid=$conn->insert_id;

if(!$mailid){

do_html_footer();

exit;

}

//creating directory will fail if this is not the first message archived

//that's ok

@mkdir('archive/'.$list,0700);

//it is a problem if creating the specific directory for this mail fails

if(!mkdir('archive/'.$list.'/'.$mailid,0700)){

do_html_footer();

exit;

}

//iterate through the array of uploaded files

$i=0;

while(($_FILES['userfile']['name'][$i])&&

($_FILES['userfile']['name'][$i]!='none')){

echo"<p>Uploading".$_FILES['userfile']['name'][$i]."-".

$_FILES['userfile']['size'][$i]."bytes.</p>";

if($_FILES['userfile']['size'][$i]==0){

echo"<p>Problem:".$_FILES['userfile']['name'][$i].

"is zero length";

$i++;

continue;

}

if($_FILES['userfile']['size'][$i]>$max_size){

echo"<p>Problem:".$_FILES['userfile']['name'][$i]."is over"

.$max_size."bytes";

$i++;

continue;

}

//we would like to check that the uploaded image is an image

//if getimagesize()can work out its size,it probably is.

if(($i>1)&&(!getimagesize($_FILES['userfile']['tmp_name'][$i]))){

echo"<p>Problem:".$_FILES['userfile']['name'][$i].

"is corrupt,or not a gif,jpeg or png.</p>";

$i++;

continue;

}

//file 0(the text message)and file 1(the html message)are special cases

if($i==0){

$destination="archive/".$list."/".$mailid."/text.txt";

}else if($i==1){

$destination="archive/".$list."/".$mailid."/index.html";

}else{

$destination="archive/".$list."/".$mailid."/"

.$_FILES['userfile']['name'][$i];

$query="insert into images values('".$mailid."',

'".$_FILES['userfile']['name'][$i]."',

'".$_FILES['userfile']['type'][$i]."')";

$result=$conn->query($query);

}

if(!is_uploaded_file($_FILES['userfile']['tmp_name'][$i])){

//possible file upload attack detected

echo"<p>Something funny happening with"

.$_FILES['userfile']['name'].",not uploading.";

do_html_footer();

exit;

}

move_uploaded_file($_FILES['userfile']['tmp_name'][$i],

$destination);

$i++;

}

display_preview_button($list,$mailid,'preview-html');

display_preview_button($list,$mailid,'preview-text');

display_button('send',"&id=$mailid");

echo"<p style=\"padding-bottom:50px\"> </p>";

do_html_footer();

?>


下面,让我们来分析一下上载文件的步骤。首先,开始一个会话并检验用户是否以管理员身份登录——我们不希望其他的用户能够上载文件。

严格地讲,我们可能还需要对list和mailid变量进行检验,检查这些变量是否包含不希望的字符,在这里,我们只是从简化代码的角度考虑,忽略了该功能。

接下来,我们建立并发送页面的标题,并检验该表单已经正确填写。这非常重要,因为对用户来说,它是一个相当复杂的表单。

接着,需要在数据库中为该邮件创建一条记录,并且在存档目录中创建一个用来保存邮件的目录。

接下来就是脚本程序的主要部分,该部分将检查并转移上载的文件。在上载多个文件时,该部分还有一点不同。这里我们需要处理4个数组。这些数组分别是$_FILES['userfile']['name']、$_FILES['userfile']['tmp_name']、$_FILES['userfile']['size']和$_FILES['userfile']['type']。它们对应单文件上载时与之命名相似的变量,只是在这里它们都是数组。表单中第一个文件的详细内容在$_FILES['userfile']['tmp_name'][0]、$_FILES['userfile']['name'][0]、$_FILES['userfile']['size'][0]和$_FILES['userfile']['type'][0]中。

针对这3个数组,我们将进行常规的安全检查并将文件转移到存档中。

最后,我们为管理员提供几个按钮,在发送新闻信件前,这些按钮可以用来预览已经上传的新闻信件文件。图30-13所示的是upload.php的输出。

30.7.3 多文件上载的处理 - 图1

图 30-13 上传脚本将报告所上载的文件及其大小