PHP5文件上传篇

51 views
Skip to first unread message

zq_g...@sohu.com

unread,
Feb 28, 2008, 9:02:08 AM2/28/08
to 说你说我
1、 全局变量$_FILES[‘xxx’];

PHP5新创了一个$_$_FILES全局变量来接收文件的上传。这和以往版本有些差别。在旧版本里,你可以打开
register_globals=on直接使用全局变量,或使用$HTTP_POST_FILSE[‘xxx’],这里只研究PHP5



2、文件上传表单

1,上传文件的表单使用post方式(和get的区别不用说了);还要加上enctype='multipart/form-data'。
2,一般要加上隐藏域:
<input type=hidden name='MAX_FILE_SIZE' value=”30000”>,位置在file域前面。value
的值是上传文件的客户端字节限制。据说可以减少文件超标时客户端的等待时间,不过我没觉得有什么区别。
注意:MAX_FILE_SIZE 的值只是对浏览器的一个建议,实际上它可以被简单的绕过。因此不要把对浏览器的限制寄希望于该值。实际
上,PHP.ini 设置中的上传文件最大值,是不会失效的。但是最好还是在表单中加上 MAX_FILE_SIZE,因为它可以避免用户在花时间等待
上传大文件之后才发现该文件太大了的麻烦。
3,出于安全考虑,file域是不许赋值的。随便在file域输入字符串,然后按submit也不会有反应。必须是第二个字符是冒号的时候(比
如空格跟随冒号可以上传一个长度为0字节的“文件”),submit才同意“服务”——不过这个是客户端的措施,跟MAX_FILE_SIZE一样很容
易绕过去。



Page1.php:

<form enctype="multipart/form-data" action="page2.php" method="POST">

<input type="hidden" name="MAX_FILE_SIZE" value="8388608">

上传文件: <input name="userfile" type="file">

<input type="submit" value="提交">

</form>

3、上传8M以下文件如何设置php.ini;



打开php.ini,首先找到
File Uploads区域,

有影响文件上传的以下几个参数:
file_uploads = on ;是否允许通过HTTP上传文件的开关。默认为ON即是开
upload_tmp_dir ;文件上传至服务器上存储临时文件的地方,如果没指定就会用系统默认的临时文件夹
upload_max_filesize = 8388608 ;望文生意,即允许上传文件大小的最大值。默认为2M,必须换算成byte单位:
1M=1024K;1K=1024byte

Data Handling ;区域,
还有一项:post_max_size = 8m ;指通过表单POST给PHP的所能接收的最大值,包括表单里的所有值。默认为8M
一般地,设置好上述四个参数后,在网络正常的情况下,上传<=8M的文件是不成问题。



4、 上传大于8M文件如何设置php.ini;



如果要上传>8M的大体积文件,只设置上述四项还一定能行的通。除非你的网络真有100M/S的上传高速,否则你还得关心关心下面的参数:

Resource Limits
max_execution_time = 600 ;每个PHP页面运行的最大时间值(秒),默认30秒
max_input_time = 600 ;每个PHP页面接收数据所需的最大时间,默认60秒
memory_limit = 8m ;每个PHP页面所吃掉的最大内存,默认8M
把上述参数修改后,在网络所允许的正常情况下,就可以上传大体积文件了。
好了,设置好现在就可以一试。点击一个200大M的文件上传一下,在你听歌、想MM或上厕所回来过程中,程序会告诉你上传成功啦~在本机上测试上传
200M的文件成功。

另外,据说上传大文件最好用FTP方法,我对PHP的FTP不太熟,这里就不研究了。



5、 文件上传错误代码

预定义变量$_FILES数组有5个内容:
$_FILES['userfile']['name']——客户端机器文件的原名称
$_FILES['userfile']['type']——文件的 MIME 类型
$_FILES['userfile']['size']——已上传文件的大小,单位为字节
$_FILES['userfile']['tmp_name']——文件被上传后在服务端储存的临时文件名
$_FILES['userfile']['error']——和该文件上传相关的错误代码

其中$_FILES['userfile']['error']的可以有下列取值和意义:
0——没有错误发生,文件上传成功。
1——上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
2——上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
3——文件只有部分被上传。
4——没有文件被上传。



1~3不用说了。“没有文件被上传”(4)是指表单的file域没有内容,是空字符串。
“文件上传成功”(0)不一定真的有文件上传了。比如你打了个“c:”给file域,就可以“上传成功”——错误代码是0,['name']
是“c:”,['type']是“application/octet-stream”,['size']是0,['tmp_name']
是“xxx.tmp”(xxx是服务器起的名字)



这里我有个小发现,起初使用PHP5.14时,无论page1.php里面<input name="userfile"
type="file">的name等于什么,在上传处理脚本中都只能用$_FILES['userfile']来接收;

后来改用PHP5.16,发现$_FILES['userfile']必须和<input name="userfile" type="file">
命名相对应了。比如name=”book”,则处理脚本必须用$_FILES['book']来接收。请大家注意一下自己的版本号。



6、上传文件大小限制
限制上传文件大小的因素有
1,客户端限制:隐藏域MAX_FILE_SIZE的数值(可以被绕开)。
2,服务器端限制:upload_max_filesize,post_max_size和memory_limit。这几项不能够用脚本来设
置,也可以在php.ini里设置,参考本文3、4条。

3,自定义限制。

7、上传文件格式检验

1、检验文件格式的方法应该很多,可以检测MIME类型,也可以用正则表达式判断,这里推
荐一种我常用的:

//自定义允许的文件上传格式;

$upload_type=".jpeg,.png,.gif,.rar,.zip,.chm,.html,.htm";

//检验上传文件是否符合格式的函数。

function check_type($upload_type){

$file_name=$_FILES['$form']['name'];

$findtype=strtolower(strrchr($file_name,"."));

$allow=strpos($upload_type,$findtype);

if($allow===false){

echo"文件格式不符";

exit;

}

}

2、 关于通过$_FILES['userfile']['type']——文件MIME类型来检查上传格式,有必要对MIME进行一些讨
论。

什么是MIME?(不必深入了解,粗知大略即可)
MIME表示多用途Internet邮件扩允协议。MIME扩允了基本的面向文本的Internet邮件系统,以便可以在消息中包含二进制附




RFC822在消息体的内容中做了一点限制:就是只能使用简单的ASCII文本。所以,MIME信息由正常的Internet文本邮件组成,文本邮件拥
有一些特别的符合RFC822的信息头和格式化过的信息体(用ASCII的子集来表示的附件)。这些MIME头给出了一种在邮件中表示附件的特别的方
法。

MIME信息包含了哪些东西?

一个普通的文本邮件的信息包含一个头部分(To: From: Subject: 等等)和一个体部分(Hello Mr.,等等)。在一个符合
MIME的信息中,邮件的各个部分叫做MIME段,每段前也缀以一个特别的头。MIME邮件只是基于RFC 822邮件的一个扩展。然而它有着自已的
RFC规范集。

头字段

MIME头根据在邮件包中的位置,大体上分为MIME信息头和MIME段头,MIME信息头指整个邮件的头,而MIME段头只每个MIME段的头。

MIME信息头有:

MIME-Version:
这个头提供了所用MIME的版本号。这个值习惯上为1.0。

Content-Type:
它定义了数据的类型,以便数据能被适当的处理。有效的类型有:text,image,
audio,video,applications,multipart和message。注意任何一个二进制附件都应该被叫做
application/octet-stream。这个头的一些用例为:image/jpg, application/
mswork,multipart/mixed 。

Content-Transfer-Encoding:
它说明了对数据所执行的编码方式,客户/MUA将用它对附件进行解码。对于每个附件,可以使用7bit,8bit,binary ,quoted-
printable,base64和custom中的一种编码方式。7bit编码是用在US ASCII字符集上的常用的一种编码方式。8bit 和
binary编码一般不用。对可读的标准文本,如果传输要经过对格式有影响的网关时对其进行保护,可以使用quoted
printable 。Base64是一种通用方法,在需要决定使用哪一种编码方法时,它提供了一个不用费脑子的选择;它通常用在二进制,非文本数据
上。注意,任何非7bit 数据必须用一种模式编码,这样它就可以通过Internet邮件网关。

Content-ID:
如果Content-Type是message/external-body或multipart/alternative时,这个头就有用了。

Content-Descrīption:
这是一个可选的头。它是任何信息段内容的自由文本描述。描述必须使用us-ascii码。

Content-Disposition:
这是一个试验性的头,它用于给客户程序/MUA提供提示,来决定是否在行内显示附件或作为单独的附件。



当然,在使用PHP检查上传格式时,没有必要把MIME搞得那么复杂,对那些高深的理论,粗知大略就可以了。倘若我们要上传ZIP和RAR的文件,你可
以在接收文件的php中写上:
$filetype=$_FILES['userfile']['type'];
echo"$filetype";
就可看到上传文件的mime类型.
ZIP的MIME类型用application/x-zip-compressed
RAR的MIME类型用application/octet-stream

然后再用如下代码判断格式:

switch ($_FILES['userfile']['type']) {
case "application/x-zip-compressed":
break;
case "application/octet-stream":
break;
case "text/plain":
break;
default:
print "您上传的文件类型不对";
exit(0);
break;
}



个人认为上传文件最好的办法使用一个功能齐全的类,自己写的话太麻烦了。PHP的竞争对手ASP.NET都把文件上传,广告轮显等功能做成组件了,可视
化操作,瞧得让人眼热——当然,眼热归眼热,我还是会极力克制自己不去学的。理由很简单,无论是ASP.NET,PHP还是JSP,其作用都是做网站。
既然作用都一样,那么好比杀猪,用剔骨尖刀是杀猪,用太极剑法是杀猪,即使你聪明英俊才华盖世玉树临风,精通太极剑,剔骨刀,宰牛刀三种武艺来杀猪,其
结果也只有一个——猪被杀死了;那么,我宁肯只学一刀,只精通一刀,我也能把猪杀的很不错。有那么多时间、那么多精力去重复学习一些作用相同的技术,倒
不如学点别的,比如为人处事,经营管理,或者琢磨一下如何追MM,以解决程序员找对象老大难的问题等。

PHP对组件的支持非常不好,这是它的一个缺点。但传说Zend公司许诺明年将发布Zendbox,大力支持组件,也不知效果如何。Zend今年给我们
太多的承诺了,说明年这也发布那也发布……强力期盼中……



8、开始上传文件

//上接page1.php,这里为了说明原理,省略了对上传文件格式、大小的判断。

Page2.php

<?php

// 在 4.1.0 以前的 PHP 中,需要用 $HTTP_POST_FILES 代替 $_FILES。

// 在 4.0.3 以前的 PHP 中,需要用 copy()来代替 move_uploaded_file()。



//上传文件的路径,这里是基于linux的,如有需要请自行修改。

$uploaddir = '/var/www/uploads/';

$uploadfile = $uploaddir. $_FILES['userfile']['name'];

print "<pre>";

if (is_uploaded_file($_FILES['userfile'])) {

if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile))
{

print "文件上传成功:\n";

print_r($_FILES);

} else {

print "文件上传失败:\n";

print_r($_FILES);

}

}

print "</pre>";

?>

is_uploaded_file():该函数用来判断文件到底是客户端上传的呢还是本机原有的。传说中国外有个软件,它可以迷惑服务器,并使其误把本
机文件当成是客户端上传的。这就很危险了:如果在linux服务器下,不法分子把包含root密码的敏感文件窃而走之,你的主机就马上变肉鸡,任人宰割
了。

move_uploaded_file()把客户端上传的文件从临时文件里移走。和copy相比,该函数显得安全多了。它只移走客户端上传的文件;至于
移动本机文件,还是用copy吧.



9、下面演示一个简单的文件上传例子(20M—25M):

Php.ini设定:

post_max_size=23068672

file_uploads = On

upload_max_filesize=26214400

max_execution_time = 600
max_input_time = 600
memory_limit = 10M

设定完记得重启apache或IIS。



Page1.php:

<form enctype="multipart/form-data" action="page2.php" method="POST">

<input type="hidden" name="MAX_FILE_SIZE" value="8388608">

上传文件: <input name="myup" type="file">

<input type="submit" value="提交">

</form>

Page2.php

<html>

<head>

<title>文件上传</title>

=========================
10、一个简单的文件上传类:

这个类很简单的,功能并不齐全;我另有一个功能强大的宝贝类,独家收藏,绝不外传…….呵呵,其实也是从phpchina找到的。本人学习文件上传的方
法就是:在phpchina搜索相关的帖子,全部保存下来,然后潜行研究,务求精熟,这样你会发现很多书本上没有的知识,如果不嫌我的办法笨的
话,phper朋友们可以试试。

class upload{

public $formname="userfile";//表单元素file的名字;

public $upload_path="upload/";//上传文件的保存路径;

public $upload_file_size="10485760";//允许上传文件的大小;

public
$upload_type=".jpeg,.png,.gif,.rar,.zip,.chm,.html,.htm";



function __construct($formname1="userfile",
$upload_file_size1="10485760",$upload_path1="upload/",
$upload_type1=".jpeg,.png,.gif,.rar,.zip,.chm,.html,.htm"){

$this->upload_false();

}

//少数浏览器支持PUT方法而不支持POST,可以据check_method()函数检验;

function check_method(){

if($_SERVER['REQUEST_METHOD']!='POST'){

echo"对不起,您的浏览器不支持POST方法上传,如要继续使用本站,请使用IE或Firefox浏览
器!";

exit;

}

}

//检查文件格式是否符合规定;

function check_type($upload_type1){

$form=$this->formname;

$file_name=$_FILES['$form']['name'];

$findtype=strtolower(strrchr($file_name,"."));

$allow=strpos($upload_type,$findtype);

if($allow===false){

echo"文件格式不符";

exit;

}

}

//检验是否从本地上传文件;

function startup(){

if(!is_uploaded_file($_FILES[$this->formname]
['name'])){

echo "不允许从服务器端向服务器端上传文件!";

exit;

}

$path=$this->upload_path;

$filename=$path."/".$_FILES[$this->formname]['name'];

if(!move_uploaded_file($_FILES[$this->formname]
['tmp_name'],$filename)){

echo "文件无法移动,上传失败!";

exit;

}

echo "文件上传成功!";

}

function upload_false(){

$the_error=$_FILES[$this->formname]['error'];

switch ($the_error){

case 0:echo "文件上传成功!";break;

case 1:echo "上传文件的大小超出规定!";break;

case 2:echo "上传文件的大小超过了MAX_FILE_SIZE的指定
值!";break;

case 3:echo "文件只有部分被上传!";break;

case 4:echo "文件没有被上传!";break;

}

$this->startup();

$this->check_type();

$this->check_method();

}

}

zq_g...@sohu.com

unread,
Feb 28, 2008, 9:11:43 AM2/28/08
to 说你说我
php4文件上传实例学习参考

Date: Sun Sep 08, 2002 12:39 pm
Topic: Article 1: Uploading binary files to mySQL
Views: 35214

Welcome to my 1st article on PHP4.COM... Hopefully more to come.. If
you have suggests about
what you'd like to have an article/how-to on, be sure to drop me an
email.

Before writing this article I did a quick google search for others who
had dabbled in this
area and only found 1 half-decent article. It was on phpbuilder.com
written by a fellow
named Florian. Now it worked ok, but was written with PHP3 in mind and
I'm fairly certain
designed to handle small files, which is not the case in the real
world. I'll be pointing out
some of the advantages of doing it the way I went. Also be sure now
that everyone is in the
world of PHP4, be sure to disable global var tracking!!

So what's with storing binary files in mySQL databases? Some might say
it's a terrible
idea, some might say it's a good idea... It all depends on the
application. Storing
files on disk is much simpler but itself has some limitations. Let's
say you need to store
20GB of data and grow by 10GB/month.. Pretty soon that can easily fill
up your webserver
disk space.. And how do you add more? Drop in another disk, eventually
you'll not be
able to hookup any more disks, not to mention the downtime installing
the new drive(s).
How about NFS/SMB network shares? That's not a bad idea either but not
without it's problems.

I've used mySQL binary storage in a few different applications now
with good results. The
biggest advantage is easily scalability. If tomorrow I needed to add
50GB of storage onto
the system, you just grab yourself another Pentium II+ computer, drop
a disk in it, install
a base Linux OS on it and MySQL. Then in the case of my applications,
there is a master database
that controls all the location of the files. You just tell it that
there is another storage
server available, it's IP address, login, password, etc. And now it's
available for use. This
causes no downtime of any kind. Virtually unlimited scalability, you
keep adding storage servers
as demand for storage increases and if the webserver becomes
overloaded handing the number of
requests, you simply setup another mirrored webserver in a load-
balanced environment and they
both handle requests, cross connecting to the correct storage server
to fulfill the frontend
requests.

Now onto database design theory.. In most other examples, people took
the easy way out. They went
with a basic table design of:

CREATE TABLE binary_data (
id INT(4) NOT NULL AUTO_INCREMENT PRIMARY KEY,
description CHAR(50),
bin_data LONGBLOB,
filename CHAR(50),
filesize CHAR(50),
filetype CHAR(50)
);

----------
Now this example stores the file metadata and binary data all in 1
table.. A bad idea in my opinion.
Also they use the column type of LONGBLOB.. This works ok for small
files.. But as soon as you get into
files larger than 1MB you're in trouble. mySQL by default has
configured certain run-time variables
quite low for this type of application use. Such variables as
max_allowed_packet... You can boost
these variables to higher runtime values.. But with my example you
don't need to...

Another problem with the table definition above is that all the data
for the file is stored in 1 row..
So using a basic select you'll have to pull all the data from the
mysql database to the webserver
before sending it to the client.. With small files this doesn't
matter, but say you had a 100MB file
in the database, that means PHP on the webserver side will have to
store 100MB of data in memory while
it's being downloaded.. This is a bad thing as it can quickly eat up
server memory on a busy site.
Now there are ways around this such as looping thru and sub selecting
pieces of the binary data
from mysql.. But I prefer to stay away from this situation
completely.

Let's begin with my example layout.. Please note the table design/code
presented here are snippets
from various application classes .. you should implement this code/
design in classes that handle
this type of operation.

Firstly lets start with my basic table layouts for the 2 required
tables:

CREATE DATABASE storage1;
use storage1;

CREATE TABLE file (
id mediumint(8) unsigned NOT NULL auto_increment,
datatype varchar(60) NOT NULL default 'application/octet-stream',
name varchar(120) NOT NULL default '',
size bigint(20) unsigned NOT NULL default '1024',
filedate datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id) ) TYPE=MyISAM

CREATE TABLE filedata (
id mediumint(8) unsigned NOT NULL auto_increment,
masterid mediumint(8) unsigned NOT NULL default '0',
filedata blob NOT NULL,
PRIMARY KEY (id),
KEY master_idx (masterid) ) TYPE=MyISAM

----------

So as you can see there are 2 tables... 1 stores the meta-data for the
file (name, size, etc) And
the other stores all the binary data in BLOB columns (64K) chunks..
These chunks could also be compared
to inodes which makeup filesystems. The advantage to using a smaller
column size is that you can
request the rows 1 by 1 from the webserver and stream them out to the
client, using low memory overhead.
It will result in a persistent connection to the database being up for
sometime (depending on filesize
and client download speed), but with mysql being to handle 100
connections by default, I have yet to
top out a storage server. The other nice thing about using 2 tables,
is if say your just going to be
listing the files in it.. You now only need to deal with a very small
table for the file's meta-data
not scan a very large file containing meta-data and binary text which
would take much more database
execution time.

Start with this example upload script (uploadpage.php):


Code/Quote:

<form method="post" action="uploadprocess.php" enctype="multipart/form-
data">
<input type="file" name="file1" size="20">
<input type="submit" name="submit" value="submit">
</form>

----------

Then with a basic processor script (uploadprocess.php):

Code/Quote:

<?
// Upload processor script
// At this point your script would determine what storage server to
connect to
// I'm just going to hardcode it here

$Storage_IP = "172.21.5.100";
$Storage_Port = 3306;
$Storage_User = "root";
$Storage_Passwd = "secret";
$Storage_DB = "storage1";

$connectto = $Storage_IP . ":" . $Storage_Port;

if (!$linkid = @mysql_connect($connectto, $Storage_User,
$Storage_Passwd)) {
&nbsp;&nbsp;die("Unable to connect to storage server!");
}

if (!mysql_select_db($Storage_DB, $linkid)) {
die("Unable to connect to storage database!");
}

// Init values - these are used incase you want to upload multiple
files, you just
// add them to the source form as file1, file2, file3, etc.
$STARTFILE = 1;
$ONFILE = "file" . $STARTFILE;

while (isset($HTTP_POST_FILES["$ONFILE"])) {

// Try!
$SrcPathFile = $HTTP_POST_FILES["$ONFILE"]["tmp_name"];
$SrcFileType = $HTTP_POST_FILES["$ONFILE"]["type"];
$DstFileName = $HTTP_POST_FILES["$ONFILE"]["name"];

clearstatcache();
$time = filemtime($SrcPathFile);
$storedate = date("Y-m-d H:i:s", $time);

// File Processing
if (file_exists($SrcPathFile)) {

// Insert into file table
$SQL = "insert into file (datatype, name, size, filedate) values
('";
$SQL .= $SrcFileType . "', '" . $DstFileName . "', " .
filesize($SrcPathFile);
$SQL .= ", '" . $storedate . "')";

if (!$RES = mysql_query($SQL, $linkid)) {
die("Failure on insert to file table!");
}

$fileid = mysql_insert_id($linkid);

// Insert into the filedata table
$fp = fopen($SrcPathFile, "rb");
while (!feof($fp)) {

// Make the data mysql insert safe
$binarydata = addslashes(fread($fp, 65535));

$SQL = "insert into filedata (masterid, filedata) values (";
$SQL .= $fileid . ", '" . $binarydata . "')";

if (!mysql_query($SQL, $linkid)) {
die("Failure to insert binary inode data row!");
}
}

fclose($fp);
}

$STARTFILE ++;
$ONFILE = "file" . $STARTFILE;
}

echo "Upload Complete";
?>

----------

That's the basic jist of it... Please note.. This script is not an
exact cut-paste from production
code... So before leaving a note that it doesn't work.. be sure to
throughly debug it.. Or better
yet, just use the concept/example code and write your own code
(perhaps better) .. ;)

Now if you want to retrieve and stream this data down to the end user
you can take a look at this very
simple example script (download.php) called like download.php?id=1 :

Code/Quote:

<?
// Download script.. streams data from a mysql database, thru the
webserver to a client browser

if (isset($_GET["id"])) {

$Storage_IP = "172.21.5.100";
$Storage_Port = 3306;
$Storage_User = "root";
$Storage_Passwd = "secret";
$Storage_DB = "storage1";

$connectto = $Storage_IP . ":" . $Storage_Port;

if (!$linkid = @mysql_connect($connectto, $Storage_User,
$Storage_Passwd)) {
die("Unable to connect to storage server!");
}

if (!mysql_select_db($Storage_DB, $linkid)) {
die("Unable to connect to storage database!");
}

$nodelist = array();

// Pull file meta-data
$SQL = "select * from file where id = " . $_GET["id"];
if (!$RES = mysql_query($SQL, $linkid)) {
die("Failure to retrive file metadata");
}

if (mysql_num_rows($RES) != 1) {
die("Not a valid file id!");
}

$FileObj = mysql_fetch_object($RES);

// Pull the list of file inodes
$SQL = "SELECT id FROM filedata WHERE masterid = " . $_GET["id"] . "
order by id";

if (!$RES = mysql_query($SQL, $linkid)) {
die("Failure to retrive list of file inodes");
}

while ($CUR = mysql_fetch_object($RES)) {
$nodelist[] = $CUR->id;
}

// Send down the header to the client
Header ( "Content-Type: $FileObj->datatype" );
Header ( "Content-Length: " . $FileObj->size );
Header ( "Content-Disposition: attachment; filename=$FileObj-
>name" );

// Loop thru and stream the nodes 1 by 1

for ($Z = 0 ; $Z < count($nodelist) ; $Z++) {
$SQL = "select filedata from filedata where id = " .
$nodelist[$Z];

if (!$RESX = mysql_query($SQL, $linkid)) {
die("Failure to retrive file node data");
}

$DataObj = mysql_fetch_object($RESX);
echo $DataObj->filedata;
}
}
?>

----------

I've just tested these scripts to be working correctly... they work
well with streaming images.. Feel
free to post any questions about them and I'll do my best to answer
(as well as anyone else online).

Latz. B0nFire. (b0n...@dreamwerx.net)


zq_g...@sohu.com

unread,
Feb 28, 2008, 9:41:45 AM2/28/08
to 说你说我
php上传图片到mysql并显示
本文转自 : http://hi.baidu.com/jingweidu/blog/item/7107d533b29dea43ad4b5fcc.html

mysql可以直接保存二进制的数据,数据类型是blob。

 通常在数据库中所使用的文本或整数类型的字段和需要用来保存图片的字段的不同之
处就在于两者所需要保存的数据量不同。MySQL数据库使用专门的字段来保存大容量的数据,数据
类型为BLOB。
  MySQL数据库为BLOB做出的定义如下:BLOB数据类型是一种大型的二进制对象,可以保存可
变数量的数据。BLOB具有四种类型,分别是TINYBLOB,BLOB, MEDIUMBLOB 和LONGBLOB,区别在于各自所能够保存的
最大数据长度不同。

建立数据库
CREATE TABLE ccs_image (
id int(4) unsigned NOT NULL auto_increment,
description varchar(250) default NULL,
bin_data longblob,
filename varchar(50) default NULL,
filesize varchar(50) default NULL,
filetype varchar(50) default NULL,
PRIMARY KEY (id)
)

接着是上传文件的页面,upload.php,code如下:

<HTML>
<HEAD><TITLE>Store binary data into SQL Database</TITLE></HEAD>
<BODY>

<?php


if (isset($_POST['submit'])) {
$form_description = $_POST['form_description'];
$form_data_name = $_FILES['form_data']['name'];
$form_data_size = $_FILES['form_data']['size'];
$form_data_type = $_FILES['form_data']['type'];
$form_data = $_FILES['form_data']['tmp_name'];

$connect = MYSQL_CONNECT( "localhost", "root", "") or die("Unable to
connect to MySQL server");
mysql_select_db( "test") or die("Unable to select database");

$data = addslashes(fread(fopen($form_data, "r"),
filesize($form_data)));

//echo "mysqlPicture=".$data;


$result=MYSQL_QUERY( "INSERT INTO ccs_image
(description,bin_data,filename,filesize,filetype) VALUES
('$form_description','$data','$form_data_name','$form_data_size','$form_data_type')");

$id= mysql_insert_id();
print "<p>This file has the following Database ID: <a
href='getdata.php?id=$id'><b>$id</b></a>";


MYSQL_CLOSE();

} else {

?>
<center>
<form method="post" action="http://localhost/temp/1018/upload.php"
enctype="multipart/form-data">
File Description:
<input type="text" name="form_description" size="40">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000000"> <br>
File to upload/store in database:
<input type="file" name="form_data" size="40">
<p><input type="submit" name="submit" value="submit">
</form>
</center>

<?php

}

?>
</BODY>
</HTML>

上文中的$_FILES['form_data']['name']; 等是获取刚上传来的文件的信息,php manual中有提到

注: 要确保文件上传表单的属性是 enctype="multipart/form-data",否则文件上传不了。

全局变量 $_FILES 自 PHP 4.1.0 起存在(在更早的版本中用 $HTTP_POST_FILES 替代)。此数组包含有所有上传的文
件信息。

以上范例中 $_FILES 数组的内容如下所示。我们假设文件上传字段的名称如上例所示,为 userfile。名称可随意命名。

$_FILES['userfile']['name']

客户端机器文件的原名称。
$_FILES['userfile']['type']

文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是“image/gif”。不过此 MIME 类型在 PHP 端并不检查,因此
不要想当然认为有这个值。
$_FILES['userfile']['size']

已上传文件的大小,单位为字节。
$_FILES['userfile']['tmp_name']

文件被上传后在服务端储存的临时文件名。
$_FILES['userfile']['error']

和该文件上传相关的错误代码。此项目是在 PHP 4.2.0 版本中增加的。

$data = addslashes(fread(fopen($form_data, "r"),
filesize($form_data)));

默认情况下,PHP 指令 magic_quotes_gpc 为 on,它主要是对所有的 GET、POST 和 COOKIE 数据自动运
行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层
转义。遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。

显示图片,getdata.php,code如下

<?php
if(isset($_GET['id'])) {
$id = $_GET['id'];
$connect = MYSQL_CONNECT( "localhost", "root", "") or die("Unable
to connect to MySQL server");
mysql_select_db( "test") or die("Unable to select database");

$query = "select bin_data,filetype from ccs_image where id=$id";
$result = @MYSQL_QUERY($query);

$data = @MYSQL_RESULT($result,0, "bin_data");
$type = @MYSQL_RESULT($result,0, "filetype");

Header( "Content-type: $type");
echo $data;
}
?>

这样就算完成了,但这样只是显示单张图片

编写两个文件。其中,第一个文件作为HTML页面的模板,定位图片的显示位置。第二个文件则被用来从数据库中实际输出文件流,作为<IMG>标
签的SRC属性。其实第二个文件就是getdata.php。第一个文件的代码如下:

<HTML>
<BODY>
<?php
$connect = MYSQL_CONNECT( "localhost", "root", "") or die("Unable
to connect to MySQL server");
mysql_select_db( "test") or die("Unable to select database");
$result=mysql_query("SELECT * FROM ccs_image") or die("Can't
Perform Query");
While ($row=mysql_fetch_object($result)){
echo "<img src=\"show.php?id=".$row->Id."\">winson<br>";
}
?>
</BODY>
</HTML>

最后提醒一点,header()函数使用前一定不能有任何输出,就算"<?php"前有个空格都不行!

Reply all
Reply to author
Forward
0 new messages