对不起我是新来的,在你问到之后,我已经添加了完整的代码:我知道我的代码很糟糕:)
if ((($_FILES["image_name"]["type"] == "image/gif")
($_FILES["image_name"]["type"] == "image/jpeg")
($_FILES["image_name"]["type"] == "image/png")
($_FILES["image_name"]["type"] == "image/pjpeg")))
{
$year = date('y');
$month = date('m');
$date = date('d');
if(file_exists('./uploads/'.$year)){
if(file_exists('./uploads/'.$year.'/'.$month)){
if(file_exists('./uploads/'.$year.'/'.$month.'/'.$date)){
$target_path='./uploads/'.$year.'/'.$month.'/'.$date.'/'.$_FILES["image_name"]["name"];
}
else{
mkdir('./uploads/'.$year.'/'.$month.'/'.$date);
}
}
else{
mkdir('./uploads/'.$year.'/'.$month);
}
}
else{
mkdir('./uploads/'.$year);
mkdir('./uploads/'.$year.'/'.$month);
mkdir('./uploads/'.$year.'/'.$month.'/'.$date);
}
if ($_FILES['image_name']['error'] > 0)
{
echo 'Return Code: ' . $_FILES['image_name']['error'] . '<br />';
}
else
{
move_uploaded_file($_FILES['image_name']['tmp_name'],
'./uploads/'.$year.'/'.$month.'/'.$date.'/'.$_FILES['image_name']['name']);
$target_path='./uploads/'.$year.'/'.$month.'/'.$date.'/'.$_FILES["image_name"]["name"];
}
}
$ target_path 变量的打印方式如下:
上传/ 13/03/15 / image_name.jpg
但它打印出来:
S / 13/03/15 / image_name.jpg
怎么了?
答案 0 :(得分:4)
首先,关于文件上传的重要说明:type
和name
键使用起来不安全。这是因为它们是由客户端定义的,它们是将恶意代码注入您的站点的潜在机制。考虑一下,如果我将文件名设置为../../../../../index.php
,或者我将MIME类型设置为image/gif
但是上传了一个PHP文件会发生什么?
接下来,有关图像上传的重要说明:您无法信任客户端上传的图像数据。也可以将恶意代码嵌入外观的内容中,就像图像一样。您需要将像素数据复制出文件并创建一个新数据。这通常通过GD扩展来完成。
接下来,在mkdir()
上 - 它有第三个参数,如果你将true
传递给第三个参数,它会递归地创建目录树,所以你不需要在一个单独的创建每个级别操作。另请注意(与许多事情一样)mkdir()
可能会失败,如果发生这种情况,它将返回false
,您应该检查这一点。
现在,为了回答实际问题(并暂时忽略上述安全问题),以下是我如何简化代码:
// Configuration
$allowedTypes = array(
"image/gif", "image/jpeg", "image/png", "image/pjpeg"
);
$baseDir = './uploads';
// Check file was uploaded successfully
if ($_FILES['image_name']['error'] > 0) {
exit('Return Code: ' . $_FILES['image_name']['error'] . '<br />');
}
// Check file type
if (!in_array($_FILES["image_name"]["type"], $allowedTypes)) {
exit('Invalid file type: ' . $_FILES['image_name']['type'] . '<br />');
}
// Check/create target directory
list($year, $month, $day) = explode('-', date('y-m-d'));
$targetDir = $baseDir . '/' . $year . '/' . $month . '/' . $day;
if (!is_dir($targetDir)) {
if (!mkdir($targetDir, 0644, true)) {
exit('Failed to create destination directory<br />');
}
}
// Store the uploaded file permanently
$targetPath = $targetDir . '/' . .$_FILES['image_name']['name'];
if (!move_uploaded_file($_FILES['image_name']['tmp_name'], $targetPath)) {
exit('Failed to move temporary file<br />');
}
但是,我不会这样做。
文件上传是一项非常常见的任务,我使用的通用代码看起来像this。看起来很复杂不是吗?嗯,这是因为处理文件上传并不简单。但是,这种复杂性的作用是提供一种很好的直接方法来解决我上面概述的安全问题。它内置了对图像的支持,包括以干净简单的方式调整大小的选项。
让我们看看我们如何在您的代码中使用它:
$baseDir = './uploads';
// Very simple autoloader for demo purposes
spl_autoload_register(function($class) {
require strtolower(basename($class)).'.php';
});
// When you instantiate this the $_FILES superglobal is destroyed
// You must access all uploaded files via this API from this point onwards
$uploadManager = new \Upload\Manager;
// Fetches a FileCollection associated with the named form control
$control = $uploadManager->getControl('image_name');
// getControl returns NULL if there are no files associated with that name
if (!isset($control)) {
exit('No file was uploaded in the image_name control');
}
// Check/create target directory
// You still need to do this, it's not magic ;-)
list($year, $month, $day) = explode('-', date('y-m-d'));
$targetDir = $baseDir . '/' . $year . '/' . $month . '/' . $day;
if (!is_dir($targetDir)) {
if (!mkdir($targetDir, 0644, true)) {
exit('Failed to create destination directory');
}
}
// This also handles multiple uploads in a single control, so we need to loop
foreach ($control as $image) {
// You need to determine a file name to use, most likely not from user
// input. This is a high-entropy low collision-risk random approach.
$targetFile = $targetDir . '/' . uniquid('upload-', true);
try {
$image->save($targetFile, true, IMAGETYPE_ORIGINAL);
} catch (\Exception $e) {
exit("Oh noes! Something went badly wrong: ".$e->getMessage());
}
}
这背后有许多事情可以解决我之前概述的安全问题。它会自动检测图像是否为有效的识别类型,并将正确的文件扩展名应用于保存的文件。
答案 1 :(得分:0)
对潜在代码问题的快速解答:
else{
mkdir('./uploads/'.$year.'/'.$month);
}
这需要第二个mkdir:
else{
mkdir('./uploads/'.$year.'/'.$month);
mkdir('./uploads/'.$year.'/'.$month.'/'.$date);
}
然后,您可以通过设置$target_path
我们需要看看在设置$target_path
之后会发生什么,以便我们看到变量在被制作和输出之间会发生什么。
在调试期间,我建议在设置后立即快速将其值输出到日志文件,以查看该点是否正常,但稍后会更改。