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-13 上传脚本将报告所上载的文件及其大小