php 完整的安全图像上传脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38509334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Full Secure Image Upload Script
提问by Simon
I don't know if this going to happen, but I will try it.
我不知道这是否会发生,但我会尝试。
For past hour I did research on image upload safety. I learned that there a lot of functions to test the upload.
在过去的一个小时里,我研究了图片上传的安全性。我了解到有很多功能可以测试上传。
In my project, I need to be safe with images uploaded. There also may be a really big amount of it and it may require a lot of bandwidth, so buying an API is not an option.
在我的项目中,我需要确保上传图片的安全。它也可能非常多,并且可能需要大量带宽,因此购买 API 不是一种选择。
So I decided to get a full PHP script for REALLY secure image upload. I also think it will help for many of people out there, because it's impossible to find really secure one. But I am not expert in php, so it's really headache for me to add some functions, so I will ask for this community help to create one full script of REALLY secure image upload.
所以我决定获取一个完整的 PHP 脚本来真正安全地上传图片。我也认为这对很多人都有帮助,因为很难找到真正安全的。但是我不是php方面的专家,所以添加一些功能对我来说真的很头疼,所以我会请求这个社区帮助创建一个真正安全的图像上传的完整脚本。
Really great topics about that are here (however, they are just telling what is needed to do the trick, but not how to do this, and as I said I am not a master on PHP, so I am not able to do this all by myself): PHP image upload security check listhttps://security.stackexchange.com/questions/32852/risks-of-a-php-image-upload-form
关于这方面的真正伟大的话题在这里(但是,他们只是告诉我们需要什么来完成这个技巧,而不是如何做到这一点,正如我所说,我不是 PHP 的高手,所以我无法做到这一切本人): PHP图片上传安全检查清单https://security.stackexchange.com/questions/32852/risks-of-a-php-image-upload-form
In summary, they are telling that this is what is needed for security image upload (I will quote from the above pages):
总之,他们告诉我们这是安全图像上传所需要的(我将引用上述页面):
- Disable PHP from running inside the upload folder using .httaccess.
- Do not allow upload if the file name contains string "php".
- Allow only extensions: jpg,jpeg,gif and png.
- Allow only image file type.
- Disallow image with two file type.
- Change the image name. Upload to a sub-directory not root directory.
Also:
- Re-process the image using GD (or Imagick) and save the processed image. All others are just fun boring for hackers"
- As rr pointed out, use move_uploaded_file() for any upload"
- By the way, you'd want to be very restrictive about your upload folder. Those places are one of the dark corners where many exploits
happen. This is valid for any type of upload and any programming
language/server. Check
https://www.owasp.org/index.php/Unrestricted_File_Upload- Level 1: Check the extension (extension file ends with)
- Level 2: Check the MIME type ($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
- Level 3: Read first 100 bytes and check if they have any bytes in the following range: ASCII 0-8, 12-31 (decimal).
- Level 4: Check for magic numbers in the header (first 10-20 bytes of the file). You can find some of the files header bytes from here:
http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples- You might want to run "is_uploaded_file" on the $_FILES['my_files']['tmp_name'] as well. See
http://php.net/manual/en/function.is-uploaded-file.php
- 使用 .httaccess 禁止 PHP 在上传文件夹内运行。
- 如果文件名包含字符串“php”,则不允许上传。
- 仅允许扩展名:jpg、jpeg、gif 和 png。
- 仅允许图像文件类型。
- 禁止使用两种文件类型的图像。
- 更改图像名称。上传到子目录而不是根目录。
还:
- 使用 GD(或 Imagick)重新处理图像并保存处理后的图像。所有其他人对黑客来说只是有趣无聊”
- 正如 rr 所指出的,使用 move_uploaded_file() 进行任何上传”
- 顺便说一句,您希望对上传文件夹进行严格限制。这些地方是
发生许多漏洞的黑暗角落之一。这适用于任何类型的上传和任何编程
语言/服务器。检查
https://www.owasp.org/index.php/Unrestricted_File_Upload- 级别 1:检查扩展名(扩展名文件以)
- 级别 2:检查 MIME 类型 ($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
- 级别 3:读取前 100 个字节并检查它们是否有以下范围内的任何字节:ASCII 0-8、12-31(十进制)。
- 第 4 级:检查标题中的幻数(文件的前 10-20 个字节)。您可以从这里找到一些文件头字节:http:
//en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples- 您可能还想在 $_FILES['my_files']['tmp_name'] 上运行“is_uploaded_file”。见
http://php.net/manual/en/function.is-uploaded-file.php
Here's a big part of it, but still that's not all. (If you know something more which could help to make the upload even safier, please share.)
这是其中的很大一部分,但这还不是全部。(如果您知道更多有助于使上传更安全的内容,请分享。)
THIS IS WHAT WE GOT NOW
这就是我们现在得到的
Main PHP:
function uploadFile ($file_field = null, $check_image = false, $random_name = false) { //Config Section //Set file upload path $path = 'uploads/'; //with trailing slash //Set max file size in bytes $max_size = 1000000; //Set default file extension whitelist $whitelist_ext = array('jpeg','jpg','png','gif'); //Set default file type whitelist $whitelist_type = array('image/jpeg', 'image/jpg', 'image/png','image/gif'); //The Validation // Create an array to hold any output $out = array('error'=>null); if (!$file_field) { $out['error'][] = "Please specify a valid form field name"; } if (!$path) { $out['error'][] = "Please specify a valid upload path"; } if (count($out['error'])>0) { return $out; } //Make sure that there is a file if((!empty($_FILES[$file_field])) && ($_FILES[$file_field]['error'] == 0)) { // Get filename $file_info = pathinfo($_FILES[$file_field]['name']); $name = $file_info['filename']; $ext = $file_info['extension']; //Check file has the right extension if (!in_array($ext, $whitelist_ext)) { $out['error'][] = "Invalid file Extension"; } //Check that the file is of the right type if (!in_array($_FILES[$file_field]["type"], $whitelist_type)) { $out['error'][] = "Invalid file Type"; } //Check that the file is not too big if ($_FILES[$file_field]["size"] > $max_size) { $out['error'][] = "File is too big"; } //If $check image is set as true if ($check_image) { if (!getimagesize($_FILES[$file_field]['tmp_name'])) { $out['error'][] = "Uploaded file is not a valid image"; } } //Create full filename including path if ($random_name) { // Generate random filename $tmp = str_replace(array('.',' '), array('',''), microtime()); if (!$tmp || $tmp == '') { $out['error'][] = "File must have a name"; } $newname = $tmp.'.'.$ext; } else { $newname = $name.'.'.$ext; } //Check if file already exists on server if (file_exists($path.$newname)) { $out['error'][] = "A file with this name already exists"; } if (count($out['error'])>0) { //The file has not correctly validated return $out; } if (move_uploaded_file($_FILES[$file_field]['tmp_name'], $path.$newname)) { //Success $out['filepath'] = $path; $out['filename'] = $newname; return $out; } else { $out['error'][] = "Server Error!"; } } else { $out['error'][] = "No file uploaded"; return $out; } } if (isset($_POST['submit'])) { $file = uploadFile('file', true, true); if (is_array($file['error'])) { $message = ''; foreach ($file['error'] as $msg) { $message .= '<p>'.$msg.'</p>'; } } else { $message = "File uploaded successfully".$newname; } echo $message; }
And the form:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data" name="form1" id="form1"> <input name="file" type="file" id="imagee" /> <input name="submit" type="submit" value="Upload" /> </form>
主要PHP:
function uploadFile ($file_field = null, $check_image = false, $random_name = false) { //Config Section //Set file upload path $path = 'uploads/'; //with trailing slash //Set max file size in bytes $max_size = 1000000; //Set default file extension whitelist $whitelist_ext = array('jpeg','jpg','png','gif'); //Set default file type whitelist $whitelist_type = array('image/jpeg', 'image/jpg', 'image/png','image/gif'); //The Validation // Create an array to hold any output $out = array('error'=>null); if (!$file_field) { $out['error'][] = "Please specify a valid form field name"; } if (!$path) { $out['error'][] = "Please specify a valid upload path"; } if (count($out['error'])>0) { return $out; } //Make sure that there is a file if((!empty($_FILES[$file_field])) && ($_FILES[$file_field]['error'] == 0)) { // Get filename $file_info = pathinfo($_FILES[$file_field]['name']); $name = $file_info['filename']; $ext = $file_info['extension']; //Check file has the right extension if (!in_array($ext, $whitelist_ext)) { $out['error'][] = "Invalid file Extension"; } //Check that the file is of the right type if (!in_array($_FILES[$file_field]["type"], $whitelist_type)) { $out['error'][] = "Invalid file Type"; } //Check that the file is not too big if ($_FILES[$file_field]["size"] > $max_size) { $out['error'][] = "File is too big"; } //If $check image is set as true if ($check_image) { if (!getimagesize($_FILES[$file_field]['tmp_name'])) { $out['error'][] = "Uploaded file is not a valid image"; } } //Create full filename including path if ($random_name) { // Generate random filename $tmp = str_replace(array('.',' '), array('',''), microtime()); if (!$tmp || $tmp == '') { $out['error'][] = "File must have a name"; } $newname = $tmp.'.'.$ext; } else { $newname = $name.'.'.$ext; } //Check if file already exists on server if (file_exists($path.$newname)) { $out['error'][] = "A file with this name already exists"; } if (count($out['error'])>0) { //The file has not correctly validated return $out; } if (move_uploaded_file($_FILES[$file_field]['tmp_name'], $path.$newname)) { //Success $out['filepath'] = $path; $out['filename'] = $newname; return $out; } else { $out['error'][] = "Server Error!"; } } else { $out['error'][] = "No file uploaded"; return $out; } } if (isset($_POST['submit'])) { $file = uploadFile('file', true, true); if (is_array($file['error'])) { $message = ''; foreach ($file['error'] as $msg) { $message .= '<p>'.$msg.'</p>'; } } else { $message = "File uploaded successfully".$newname; } echo $message; }
和形式:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data" name="form1" id="form1"> <input name="file" type="file" id="imagee" /> <input name="submit" type="submit" value="Upload" /> </form>
So, what I am asking is to help by posting snippets of codes which will help me (and everyone else) to make this Image Upload Script to make super secure. Or by sharing/creating a full script with all the snippets added.
所以,我要问的是通过发布代码片段来帮助我(和其他所有人)使这个图像上传脚本变得超级安全。或者通过共享/创建添加了所有片段的完整脚本。
回答by icecub
When you start working on a secure image upload script, there are many things to consider. Now I'm no where near an expert on this, but I've been asked to develop this once in the past. I'm gonna walk through the entire process I've been through here so you can follow along. For this I'm gonna start with a very basic html form and php script that handles the files.
当您开始处理安全图像上传脚本时,需要考虑很多事情。现在我远不是这方面的专家,但我过去曾被要求开发这个。我将介绍我在这里经历的整个过程,以便您可以跟随。为此,我将从一个非常基本的 html 表单和处理文件的 php 脚本开始。
HTML form:
HTML表单:
<form name="upload" action="upload.php" method="POST" enctype="multipart/form-data">
Select image to upload: <input type="file" name="image">
<input type="submit" name="upload" value="upload">
</form>
PHP file:
PHP文件:
<?php
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['image']['name']);
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
echo "Image succesfully uploaded.";
} else {
echo "Image uploading failed.";
}
?>
First problem: File types
Attackers don't have to use the form on your website to upload files to your server. POST requests can be intercepted in a number of ways. Think about browser addons, proxies, Perl scripts. No matter how hard we try, we can't prevent an attacker from trying to upload something (s)he isn't supposed to. So all of our security has to be done serverside.
第一个问题:文件类型
攻击者不必使用您网站上的表单将文件上传到您的服务器。可以通过多种方式拦截 POST 请求。想想浏览器插件、代理、Perl 脚本。无论我们多么努力,我们都无法阻止攻击者尝试上传他不应该上传的内容。所以我们所有的安全都必须在服务器端完成。
The first problem is file types. In the script above an attacker could upload anything (s)he wants, like a php script for example, and follow a direct link to execute it. So to prevent this, we implement Content-type verification:
第一个问题是文件类型。在上面的脚本中,攻击者可以上传他想要的任何东西,例如 php 脚本,然后点击直接链接来执行它。所以为了防止这种情况,我们实现了内容类型验证:
<?php
if($_FILES['image']['type'] != "image/png") {
echo "Only PNG images are allowed!";
exit;
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['image']['name']);
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
echo "Image succesfully uploaded.";
} else {
echo "Image uploading failed.";
}
?>
Unfortunately this isn't enough. As I mentioned before, the attacker has full control over the request. Nothing will prevent him/her from modifying the request headers and simply change the Content type to "image/png". So instead of just relying on the Content-type header, it would be better to also validate the content of the uploaded file. Here's where the php GD library comes in handy. Using getimagesize()
, we'll be processing the image with the GD library. If it isn't an image, this will fail and therefor the entire upload will fail:
不幸的是,这还不够。正如我之前提到的,攻击者可以完全控制请求。没有什么可以阻止他/她修改请求标头,只需将内容类型更改为“image/png”。因此,与其仅仅依赖 Content-type 标头,还不如验证上传文件的内容。这就是 php GD 库派上用场的地方。使用getimagesize()
,我们将使用GD 库处理图像。如果它不是图像,这将失败,因此整个上传将失败:
<?php
$verifyimg = getimagesize($_FILES['image']['tmp_name']);
if($verifyimg['mime'] != 'image/png') {
echo "Only PNG images are allowed!";
exit;
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['image']['name']);
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
echo "Image succesfully uploaded.";
} else {
echo "Image uploading failed.";
}
?>
We're still not there yet though. Most image file types allow text comments added to them. Again, nothing prevents the attacker from adding some php code as a comment. The GD library will evaluate this as a perfectly valid image. The PHP interpreter would completely ignore the image and run the php code in the comment. It's true that it depends on the php configuration which file extensions are processed by the php interpreter and which not, but since there are many developers out there that have no control over this configuration due to the use of a VPS, we can't assume the php interpreter won't process the image. This is why adding a file extension white list isn't safe enough either.
我们还没有到那里。大多数图像文件类型允许添加文本注释。同样,没有什么可以阻止攻击者添加一些 php 代码作为注释。GD 库会将其评估为完全有效的图像。PHP 解释器将完全忽略图像并运行注释中的 php 代码。确实,这取决于 php 配置,哪些文件扩展名由 php 解释器处理,哪些不处理,但是由于有许多开发人员由于使用 VPS 而无法控制此配置,因此我们不能假设php 解释器不会处理图像。这就是为什么添加文件扩展名白名单也不够安全的原因。
The solution to this would be to store the images in a location where an attacker can't access the file directly. This could be outside of the document root or in a directory protected by a .htaccess file:
解决方案是将图像存储在攻击者无法直接访问文件的位置。这可能在文档根目录之外或在受 .htaccess 文件保护的目录中:
order deny,allow
deny from all
allow from 127.0.0.1
Edit: After talking with some other PHP programmers, I highly suggest using a folder outside of the document root, because htaccess isn't always reliable.
编辑:与其他一些 PHP 程序员交谈后,我强烈建议使用文档根目录之外的文件夹,因为 htaccess 并不总是可靠的。
We still need the user or any other visitor to be able to view the image though. So we'll use php to retrieve the image for them:
我们仍然需要用户或任何其他访问者能够查看图像。所以我们将使用 php 为他们检索图像:
<?php
$uploaddir = 'uploads/';
$name = $_GET['name']; // Assuming the file name is in the URL for this example
readfile($uploaddir.$name);
?>
Second problem: Local file inclusion attacks
Although our script is reasonably secure by now, we can't assume the server doesn't suffer from other vulnerabilities. A common security vulnerability is known as Local file inclusion. To explain this I need to add an example code:
第二个问题:本地文件包含攻击
虽然我们的脚本现在相当安全,但我们不能假设服务器没有其他漏洞。一个常见的安全漏洞称为本地文件包含。为了解释这一点,我需要添加一个示例代码:
<?php
if(isset($_COOKIE['lang'])) {
$lang = $_COOKIE['lang'];
} elseif (isset($_GET['lang'])) {
$lang = $_GET['lang'];
} else {
$lang = 'english';
}
include("language/$lang.php");
?>
In this example we're talking about a multi language website. The sites language is not something considered to be "high risk" information. We try to get the visitors preferred language through a cookie or a GET request and include the required file based on it. Now consider what will happen when the attacker enters the following url:
在这个例子中,我们谈论的是一个多语言网站。网站语言不被视为“高风险”信息。我们尝试通过 cookie 或 GET 请求获取访问者的首选语言,并基于它包含所需的文件。现在考虑当攻击者输入以下 url 时会发生什么:
www.example.com/index.php?lang=../uploads/my_evil_image.jpg
www.example.com/index.php?lang=../uploads/my_evil_image.jpg
PHP will include the file uploaded by the attacker bypassing the fact that (s)he can't access the file directly and we're back at square one.
PHP 将包含攻击者上传的文件,绕过他无法直接访问该文件的事实,我们又回到了原点。
The solution to this problem is to make sure the user doesn't know the filename on the server. Instead, we'll change the file name and even the extension using a database to keep track of it:
此问题的解决方案是确保用户不知道服务器上的文件名。相反,我们将使用数据库更改文件名甚至扩展名来跟踪它:
CREATE TABLE `uploads` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64) NOT NULL,
`original_name` VARCHAR(64) NOT NULL,
`mime_type` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
<?php
if(!empty($_POST['upload']) && !empty($_FILES['image']) && $_FILES['image']['error'] == 0)) {
$uploaddir = 'uploads/';
/* Generates random filename and extension */
function tempnam_sfx($path, $suffix){
do {
$file = $path."/".mt_rand().$suffix;
$fp = @fopen($file, 'x');
}
while(!$fp);
fclose($fp);
return $file;
}
/* Process image with GD library */
$verifyimg = getimagesize($_FILES['image']['tmp_name']);
/* Make sure the MIME type is an image */
$pattern = "#^(image/)[^\s\n<]+$#i";
if(!preg_match($pattern, $verifyimg['mime']){
die("Only image files are allowed!");
}
/* Rename both the image and the extension */
$uploadfile = tempnam_sfx($uploaddir, ".tmp");
/* Upload the file to a secure directory with the new name and extension */
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
/* Setup a database connection with PDO */
$dbhost = "localhost";
$dbuser = "";
$dbpass = "";
$dbname = "";
// Set DSN
$dsn = 'mysql:host='.$dbhost.';dbname='.$dbname;
// Set options
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
$db = new PDO($dsn, $dbuser, $dbpass, $options);
}
catch(PDOException $e){
die("Error!: " . $e->getMessage());
}
/* Setup query */
$query = 'INSERT INTO uploads (name, original_name, mime_type) VALUES (:name, :oriname, :mime)';
/* Prepare query */
$db->prepare($query);
/* Bind parameters */
$db->bindParam(':name', basename($uploadfile));
$db->bindParam(':oriname', basename($_FILES['image']['name']));
$db->bindParam(':mime', $_FILES['image']['type']);
/* Execute query */
try {
$db->execute();
}
catch(PDOException $e){
// Remove the uploaded file
unlink($uploadfile);
die("Error!: " . $e->getMessage());
}
} else {
die("Image upload failed!");
}
}
?>
So now we've done the following:
所以现在我们已经完成了以下工作:
- We've created a secure place to save the images
- We've processed the image with the GD library
- We've checked the image MIME type
- We've renamed the file name and changed the extension
- We've saved both the new and original filename in our database
- We've also saved the MIME type in our database
- 我们创建了一个安全的地方来保存图像
- 我们已经使用 GD 库处理了图像
- 我们已经检查了图像 MIME 类型
- 我们重命名了文件名并更改了扩展名
- 我们已经在我们的数据库中保存了新的和原始的文件名
- 我们还在我们的数据库中保存了 MIME 类型
We still need to be able to display the image to visitors. We simply use the id column of our database to do this:
我们仍然需要能够向访问者显示图像。我们只需使用数据库的 id 列来执行此操作:
<?php
$uploaddir = 'uploads/';
$id = 1;
/* Setup a database connection with PDO */
$dbhost = "localhost";
$dbuser = "";
$dbpass = "";
$dbname = "";
// Set DSN
$dsn = 'mysql:host='.$dbhost.';dbname='.$dbname;
// Set options
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
$db = new PDO($dsn, $dbuser, $dbpass, $options);
}
catch(PDOException $e){
die("Error!: " . $e->getMessage());
}
/* Setup query */
$query = 'SELECT name, original_name, mime_type FROM uploads WHERE id=:id';
/* Prepare query */
$db->prepare($query);
/* Bind parameters */
$db->bindParam(':id', $id);
/* Execute query */
try {
$db->execute();
$result = $db->fetch(PDO::FETCH_ASSOC);
}
catch(PDOException $e){
die("Error!: " . $e->getMessage());
}
/* Get the original filename */
$newfile = $result['original_name'];
/* Send headers and file to visitor */
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.basename($newfile));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($uploaddir.$result['name']));
header("Content-Type: " . $result['mime_type']);
readfile($uploaddir.$result['name']);
?>
Thanks to this script the visitor will be able to view the image or download it with its original filename. However, (s)he can't access the file on your server directly nor will (s)he be able to fool your server to access the file for him/her as (s)he has no way of knowing which file it is. (S)he can't brute force your upload directory either as it simply doesn't allow anyone to access the directory except the server itself.
借助此脚本,访问者将能够查看图像或使用其原始文件名下载图像。但是,他无法直接访问您服务器上的文件,也无法欺骗您的服务器为他/她访问文件,因为他无法知道这是哪个文件. (S)他也不能暴力破解你的上传目录,因为它不允许任何人访问除了服务器本身之外的目录。
And that concludes my secure image upload script.
我的安全图片上传脚本到此结束。
I'd like to add that I didn't include a maximum file size into this script, but you should easily be able to do that yourself.
我想补充一点,我没有在此脚本中包含最大文件大小,但您应该可以轻松地自己做到这一点。
ImageUpload Class
Due to the high demand of this script, I've written an ImageUpload class that should make it a lot easier for all of you to securely handle images uploaded by your website visitors. The class can handle both single and multiple files at once, and provides you with additional features like displaying, downloading and deleting images.
ImageUpload 类
由于此脚本的需求量很大,我编写了一个 ImageUpload 类,它应该可以让所有人更轻松地安全地处理网站访问者上传的图像。该类可以同时处理单个和多个文件,并为您提供显示、下载和删除图像等附加功能。
Since the code is simply to large to post here, you can download the class from MEGA here:
由于代码太大而无法在此处发布,因此您可以从 MEGA 下载该类:
Just read the README.txt and follow the instructions.
只需阅读 README.txt 并按照说明进行操作。
Going Open Source
The Image Secure class project is now also available on my Githubprofile. This so that others (you?) can contribute towards the project and make this a great library for everyone.
走向开源
Image Secure 类项目现在也可以在我的Github个人资料中找到。这样其他人(你?)就可以为这个项目做出贡献,并使它成为一个适合所有人的伟大图书馆。
回答by Olaf
To upload files in PHP is easy and secure. I would recommend learning about:
在 PHP 中上传文件既简单又安全。我建议学习以下内容:
- pathinfo- Returns information about a file path
- move_uploaded_file- Moves an uploaded file to a new location
- copy- Copies a file
- finfo_open- Creates a new
fileinfo
resource
- pathinfo- 返回有关文件路径的信息
- move_uploaded_file- 将上传的文件移动到新位置
- copy- 复制文件
- finfo_open- 创建一个新
fileinfo
资源
To upload a file in PHP you have two methods: PUT
and POST
.
To use the POST
method with HTML you need to enable enctype
on your form like this:
要在 PHP 中上传文件,您有两种方法:PUT
和POST
. 要在POST
HTML 中使用该方法,您需要enctype
在表单上启用,如下所示:
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
Then in you PHP you need get your uploaded file with $_FILES
like this:
然后在您的 PHP 中,您需要$_FILES
像这样获取上传的文件:
$_FILES['file']
Then you need move the file from temp("upload") with move_uploaded_file
:
然后您需要使用以下命令从 temp("upload") 移动文件move_uploaded_file
:
if (move_uploaded_file($_FILES['file']['tmp_name'], YOUR_PATH)) {
// ...
}
And after you uploaded the file, you need check the file's extension. The best way to do this is using pathinfo
like this:
上传文件后,您需要检查文件的扩展名。最好的方法是使用pathinfo
这样的:
$extension = pathinfo($_FILES['file']['tmp_name'], PATHINFO_EXTENSION);
But the extension is not secure because you can upload a file with extension .jpg
but with mimetype text/php
and this is a backdoor.
So, I recommend checking the real mimetype with finfo_open
like this:
但是扩展名并不安全,因为您可以上传带有扩展名.jpg
但带有 mimetype的文件,text/php
这是一个后门。所以,我建议finfo_open
像这样检查真正的 mimetype :
$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $_FILES['file']['tmp_name']);
And don't use $_FILES['file']['type']
because sometimes,
depending your browser and client OS, you may receive
application/octet-stream
and this mimetype is not the real
mimetype of your uploaded file.
并且不要使用,$_FILES['file']['type']
因为有时,根据您的浏览器和客户端操作系统,您可能会收到
application/octet-stream
并且此 mimetype 不是您上传文件的真实 mimetype。
I think you can upload files securely with this scenario.
我认为您可以在这种情况下安全地上传文件。
Sorry for my English, bye!
对不起我的英语,再见!