php 图片上传有个小BUG,求大神解答。以下是我的一些代码

$link=mysql_connect('localhost','root','123456');
mysql_query("set names 'UTF8'");
mysql_select_db('zhenyu',$link);
$pkind=$_POST['pkind'];
$pname=$_POST['pname'];
$pshow=$_POST['pshow'];
$mysql=mysql_query("insert into product (pkind,pname,ppicture,pshow) values ('".$pkind."','".$pname."','"."product/".$_FILES["file"]["name"]."','".$pshow."')");//上传文件保存在product文件夹
if($mysql)
{
move_uploaded_file($_FILES["file"]["tmp_name"],"product/".$_FILES["file"]["name"]);
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo "Stored in: " . "product/" . $_FILES["file"]["name"].'<br />';
echo '<a href="pfabu.html">返回</a>';
echo '<script>alert("success");</script>';}

如果上传的图片名不超过3个汉字或者包含英文字符,则一切正常。但是如果图片名字数超过3个且只有汉字跟数字,图片不会上传到指定文件夹,其他的输出语句和数据库都还是正常。
这种情况应该是 move_uploaded_file($_FILES["file"]["tmp_name"],"product/".$_FILES["file"]["name"]);这句话没有执行,可是是为什么呢?
怎么才能解决这个问题,求高手指教

您好,这个是 PHP 的一个 BUG(毕竟是外国人做的,中文支持不太好)。

PHP 中,上传中文文件基本上都会出错,所以只要在移动文件时,将文件重命名就可以了。

(如果需要原文件名,只需要将原文件名和重命名后的文件名保存在数据库中就可以了)

代码如下(您的代码有一些漏洞与不规范之处,这里已更正):

// 检测文件MIME类型,如果不是图片则阻止本次上传
// 不要相信$_FILES['file']['type'],这是可以伪造的

// 如果 PHP >= 5.3.0,则使用finfo函数来获取文件类型
// 因为 PHP >= 5.3.0 放弃了 mime_content_type() 函数
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
    $f     = finfo(FILEINFO_MIME_TYPE);
    $ftype = explode('/', finfo_file($f, $_FILES['file']['tmp_name']));
    finfo_close($f);
    $f     = NULL;
    if ($ftype[0] !== 'image') {
        @unlink($_FILES['file']['tmp_file']);
        die('文件上传失败!<br />请重新上传。<br /><a href="pfabu.html">返回</a>');
    }
    $ftype = NULL;
}
else {
    $ftype = explode('/', mime_content_type($_FILES['file']));
    if ($ftype[0] !== 'image') {
        @unlink($_FILES['file']['tmp_file']);
        die('文件上传失败!<br />请重新上传。<br /><a href="pfabu.html">返回</a>');
    }
    $ftype = NULL;
}

$link  = mysql_connect('localhost','root','123456');
mysql_query('set names \'UTF8\'');
mysql_select_db('zhenyu', $link);

// 为了防止SQL注入,对数据进行转义
$pkind = addslashes($_POST['pkind']);
$pname = addslashes($_POST['pname']);
$pshow = addslashes($_POST['pshow']);

$filename_upload = $_FILES['file']['name'];

// Base64 编码后的字符只含有 a-z A-Z 0-9 以及+,/,=
$filename   = base64_encode($filename_upload);
// Base64 编码中有一些非文件名可用的字符,把它们替换掉
$filename   = strtr($filename, array(
        '+' => '.',
        '/' => '_',
        '=' => '-'
    )
);
// 上传后的文件保存在product文件夹
$file_move  = 'product/' . $filename;

// 如果文件已存在,则在文件名后加上-和一个随机数
// 当然,这一部分也可以您自己更改,不会影响结果
if(file_exists($file_move)) {
    $rand             = '-' . strval(rand(0, 9999));
    $file_move       .= $rand;
    $filename_upload .= $rand;
    // 因为 $rand 被其它变量引用,不能直接注销
    // 所以将其赋值为 NULL,也可达到同样的释放内存的效果
    $rand = NULL;
}

// 判断文件是否是通过 HTTP POST 上传的
// 这可以用来确保恶意用户无法欺骗程序去访问本不该访问的文件,例如/etc/passwd
if (!is_uploaded($_FILES['file']['tmp_name'])) {
    @unlink($_FILES['file']['tmp_name']);
    die('文件上传失败!<br />请重新上传。<br /><a href="pfabu.html">返回</a>');
}
// 如果文件移动失败,则显示错误信息
// 这样就不会导致数据库存储正常,但文件上传失败的情况了
elseif (!move_uploaded_file($_FILES['file']['tmp_name'], $file_move)) {
    @unlink($_FILES['file']['tmp_name']);
    die('文件上传失败!<br />请重新上传。<br /><a href="pfabu.html">返回</a>');
}

// 这里将重命名后的文件名与原文件名储存在同一个字段中,用竖线(|)隔开
// 读取时只需要用 explode() 分开就可以了
if($mysql = mysql_query("INSERT INTO product(pkind,pname,ppicture,pshow) VALUES('{$pkind}','{$pname}','{$file_move}|{$_FILES['file']['name']}','{$pshow}')")) {
       // 显示文件上传信息
       echo 'Upload: ', $filename_upload, '<br />';    
       echo 'Size: ', strval($_FILES['file']['size'] / 1024.0), ' KB<br />';
       echo 'Stored in: ', $file_move, '<br />';
       echo '<a href="pfabu.html">返回</a>';
       echo '<script>alert("success");</script>';
}
// 如果存入数据库时失败
// 则显示错误信息
else {
    @unlink($_FILES['file']['tmp_name']);
    die('文件上传失败!<br />请重新上传。<br /><a href="pfabu.html">返回</a>');
}

这样就可以了。

由于没有测试,代码难免会出现一些错误,请随意指出,谢谢!


另外,您还应该考虑到不同用户上传同一个文件名的文件的情况,最好是为每个用户单独分配一个文件夹。

而且,当一个文件夹下的文件过多(>300)时,会导致读写速度变慢,这一点要注意。

解决:

当一个用户的文件夹下文件有300个时,用户再上传文件,就将新的文件保存在另一个文件夹中(如:用户名加上这个用户已有的文件夹数量)。


如果还有后续问题,可以联系我的邮箱:

[email protected]

谢谢!

温馨提示:答案为网友推荐,仅供参考
第1个回答  2013-09-14
这个BUG我也碰到过,最简单的办法就是把现在的文件名为短MD5+时间,可以防重名的
第2个回答  2013-09-14
上传后重新命个名就不存在这个问题了,即在move_upload_file()那里改一下,不要用原来的文件名,重新命个名字,比如 ‘product/’.time().mt_rand(100, 999).'原来图片的后缀';多说几句呀,依代码看这代码不光是一点小BUG,一般人都不会这么写吧,即不做过滤检测也不是判断是否是真实上传的内容,也不判断上传的是不是图片,这应该是楼主拿来自己写的玩的吧,
第3个回答  2013-09-14
move_uploaded_file($_FILES["file"]["tmp_name"],"product/".$_FILES["file"]["name"])

没有后缀名
相似回答