在本文中,我将解释 php 文件上传的基础知识。首先,我们将介绍成功上传文件所需的 PHP 配置选项。之后,我们将开发一个如何上传文件的真实示例。
配置 PHP 设置
您需要预先检查几个 PHP 配置设置以确保文件上传成功。在本节中,我们将介绍有关 PHP 文件上传的每个重要选项。这些选项可以在php.ini 文件中配置。
如果您不确定在哪里可以找到您的 php.ini 文件,您可以使用 php_ini_loaded_file() 找到它。只需使用以下行在您的服务器上创建一个 PHP 文件,然后从浏览器中打开它。
<?php echo php_ini_loaded_file(); ?>
这是安装文件的摘录,其中包含一些有用的默认值。
; Whether to allow HTTP file uploads. file_uploads = On ; Temporary directory for HTTP uploaded files. ; Will use system default if not set. ;upload_tmp_dir = ; Maximum allowed size for uploaded files. upload_max_filesize = 16M ; Maximum number of files that can be uploaded via a single request max_file_uploads = 20 ; Maximum size of post data that PHP will accept. post_max_size = 20M max_input_time = 60 memory_limit = 128M max_execution_time = 30
关键设置
file_uploads
该 file_uploads 指令的值应设置 On 为允许文件上传。该指令的默认值为 On.
upload_max_filesize
该 upload_max_filesize 指令允许您配置上传文件的最大大小。默认情况下,它设置为 2M (2 MB),您可以使用 . htaccess 文件也是如此。按照今天的标准,2 兆字节并不算多,因此您可能必须增加它。file exceeds upload_max_filesize 如果您在尝试上传文件时收到错误 消息,则需要增加此值。如果你这样做,一定要增加 post_max_size (见下文)。
upload_tmp_dir
设置一个临时目录,用于存储上传的文件。在大多数情况下,您无需担心此设置。如果不设置,将使用系统默认的临时目录。
post_max_size
该 post_max_size 指令允许您配置 POST 数据的最大大小。由于文件是通过 POST 请求上传的,因此该值必须大于您为 upload_max_filesize 指令设置的值。例如,如果您 upload_max_filesize 是 16M (16 兆字节),您可能希望设置 post_max_size 为 20M.
max_file_uploads
它允许您设置一次可以上传的最大文件数。默认值为 20,一个合理的数量。
max_input_time
这是允许脚本解析输入数据的最大秒数。如果您正在处理大文件上传,则应将其设置为合理的值。 60 (60 秒)对于大多数应用程序来说是一个不错的值。
memory_limit
该 memory_limit指令指示脚本可以消耗的最大内存量。如果您在上传大文件时遇到问题,您需要确保该指令的值大于您为该post_max_size 指令设置的值。默认值为 128M (128 兆字节),因此除非您有一个非常大的 post_max_size and upload_max_filesize,否则您无需担心这一点。
max_execution_time
这是允许脚本运行的最大秒数。如果您在上传大文件时遇到问题,可以考虑增加此值。30 (30 秒)应该适用于大多数应用程序。
现在让我们构建一个真实的示例来演示 PHP 中的文件上传。
创建html表单
配置 PHP 设置后,您就可以尝试 PHP 文件上传功能了。
我们的 GitHub 存储库有一些示例代码 ,我将在本文中讨论这些示例代码。因此,如果您想继续学习,请继续从 GitHub 下载它。
我们将创建两个 PHP 文件: index.php 和 upload.php。index.php 文件包含负责显示文件上传表单的代码。 另一方面, upload.php 文件负责将文件上传到服务器。
此外,文件将被上传到 upload_files 目录中,因此您需要确保该文件夹存在并且 web-server 用户可写。
在本节中,我们将介绍 index.php 文件的关键部分。
我们来看看 GitHub 上的index.php文件:
<?php session_start(); ?> <!DOCTYPE html> <html> <head> <title>PHP File Upload</title> </head> <body> <?php if (isset($_SESSION['message']) && $_SESSION['message']) { echo '<p class="notification">'.$_SESSION['message']).'</p>'; unset($_SESSION['message']); } ?> <form method="POST" action="upload.php" enctype="multipart/form-data"> <div class="upload-wrapper"> <span class="file-name">Choose a file...</span> <label for="file-upload">Browse<input type="file" id="file-upload" name="uploadedFile"></label> </div> <input type="submit" name="uploadBtn" value="Upload" /> </form> </body> </html>
您可以使用以下css使表单更具吸引力。
div.upload-wrapper { color: white; font-weight: bold; display: flex; } input[type="file"] { position: absolute; left: -9999px; } input[type="submit"] { border: 3px solid #555; color: white; background: #666; margin: 10px 0; border-radius: 5px; font-weight: bold; padding: 5px 20px; cursor: pointer; } input[type="submit"]:hover { background: #555; } label[for="file-upload"] { padding: 0.7rem; display: inline-block; background: #fa5200; cursor: pointer; border: 3px solid #ca3103; border-radius: 0 5px 5px 0; border-left: 0; } label[for="file-upload"]:hover { background: #ca3103; } span.file-name { padding: 0.7rem 3rem 0.7rem 0.7rem; white-space: nowrap; overflow: hidden; background: #ffb543; color: black; border: 3px solid #f0980f; border-radius: 5px 0 0 5px; border-right: 0; }
CSS 基本上隐藏了原始文件 input 并为其随附 span 的 label 元素设置样式。
尽管它可能看起来像一个典型的 PHP 表单,但标签的enctype 属性 值有一个重要的区别 。 由于表单包含文件字段<form>,因此需要将其设置为 。multipart/form-data
该 enctype 属性指定提交表单时应使用的编码类型,它采用以下三个值之一:
application/x-www-form-urlencoded:当您没有 enctype 明确设置属性值时,这是默认值。在这种情况下,字符在发送到服务器之前被编码。如果表单中没有文件字段,则应将此值用于 enctype 属性。
multipart/form-data:当您使用属性的 multipart/form-data 值时 enctype ,它允许您使用 POST 方法上传文件。此外,它确保在提交表单时不会对字符进行编码。
text/plain: 这个一般不用。使用此设置,数据以未编码的方式发送。
接下来,我们输出文件字段,它允许您从计算机中选择一个文件。
<input type="file" name="uploadedFile" />
除此之外,我们还在表单顶部显示了一条消息。此消息显示文件上传的状态,它会由 upload.php 脚本设置在会话变量中。我们将在下一节中对此进行更多讨论。
<?php if (isset($_SESSION['message']) && $_SESSION['message']) { echo '<p class="notification">'.$_SESSION['message']).'</p>'; unset($_SESSION['message']); } ?>
这样就总结了 index.php 文件。在下一节中,我们将看到如何在服务器端处理上传的文件。
创建上传逻辑
在上一节中,我们创建了显示在客户端并允许您从计算机上传文件的 HTML 表单。在本节中,我们将看到允许您处理上传文件的服务器端对应项。
从 GitHub 上的 upload.php 文件中提取代码。我们将浏览该文件的重要部分。
在 upload.php 文件中,我们首先检查了它是否是一个有效的POST 请求。
if (isset($_POST['uploadBtn']) && $_POST['uploadBtn'] == 'Upload') {...}
在 PHP 中,当上传文件时, $_FILES 超全局变量会填充有关上传文件的所有信息。它被初始化为一个数组,并且可能包含以下信息以成功上传文件。
tmp_name: 文件上传的临时路径存放在这个变量中。
name:文件的实际名称存储在此变量中。
size:表示上传文件的大小,以字节为单位。
type: 包含上传文件的 mime 类型。
error:如果文件上传过程中出现错误,此变量将填充相应的错误消息。在文件上传成功的情况下,它包含0,您可以使用 UPLOAD_ERR_OK const ant进行比较。
验证 POST 请求后,我们检查文件上传是否成功。
if (isset($_FILES['uploadedFile']) && $_FILES['uploadedFile']['error'] === UPLOAD_ERR_OK) {...}
可以看到 $_FILES 变量是一个多维数组,第一个元素是文件字段的名称,第二个元素是上传文件的信息,正如我们上面刚刚讨论的。
如果文件上传成功,我们用上传文件的信息初始化一些变量。
// get details of the uploaded file $fileTmpPath = $_FILES['uploadedFile']['tmp_name']; $fileName = $_FILES['uploadedFile']['name']; $fileSize = $_FILES['uploadedFile']['size']; $fileType = $_FILES['uploadedFile']['type']; $fileNameCmps = explode(".", $fileName); $fileExtension = strtolower(end($fileNameCmps));
在上面的代码片段中,我们还计算了上传文件的扩展名并将其存储在 $fileExtension 变量中。
由于上传的文件可能包含空格和其他特殊字符,因此最好对文件名进行清理,这正是我们在以下代码段中所做的。
$newFileName = md5(time() . $fileName) . '.' . $fileExtension;
重要的是您要确定可以上传到某些扩展名的文件类型,并且不允许使用上传表单进行所有操作。我们通过使用一组我们希望允许上传的扩展名检查上传文件的扩展名来做到这一点。
$allowedfileExtensions = array('jpg', 'gif', 'png', 'zip', 'txt', 'xls', 'doc'); if (in_array($fileExtension, $allowedfileExtensions)) { ... }
最后,我们使用该 move_uploaded_file 函数将上传的文件移动到我们选择的特定位置。
// directory in which the uploaded file will be moved $uploadFileDir = './uploaded_files/'; $dest_path = $uploadFileDir . $newFileName; if(move_uploaded_file($fileTmpPath, $dest_path)) { $message ='File is successfully uploaded.'; } else { $message = 'There was some error moving the file to upload directory. Please make sure the upload directory is writable by web server.'; }
该 move_uploaded_file 函数有两个参数。第一个参数是上传文件的文件名,第二个参数是要移动文件的目标路径。
最后,我们将用户重定向到 index.php 文件。此外,我们在 session 变量中设置了相应的消息,这些消息将在 index.php 文件中重定向后显示给用户。
这一切如何协同工作
不要忘记创建 uploaded_files 目录并使其可由 网络服务器 用户写入。接下来,继续运行 index.php 文件,该文件应显示文件上传表单,如下所示:
单击“ 浏览” 按钮—这将打开一个对话框,允许您从计算机中选择一个文件。选择具有我们脚本中允许的扩展名之一的文件,然后单击 上传 按钮。
那应该提交表单,如果一切顺利,您应该会在 upload_files 目录中看到上传的 文件 。您也可以尝试上传其他不允许的扩展名的文件,并检查我们的脚本公关事件是否是此类上传。
解决常见错误
在文件上传过程中,很多事情都可能出错,这可能会导致错误。您可以使用 . 检查上传过程中发生的确切错误 $_FILES['uploadedFile']['error']。以下是对这些错误的解释:
文件太大
UPLOAD_ERR_INI_SIZE 并且 UPLOAD_ERR_FORM_SIZE当上传文件的大小大于分别在php.ini或 HTML 表单中指定的值时发生。您可以通过增加上传大小限制或让用户事先了解它们来消除此错误。
临时文件夹丢失
UPLOAD_ERR_NO_TMP_DIR 当上传文件的临时文件夹丢失时会报告。 UPLOAD_ERR_NO_FILE 无文件上传时报。
部分上传或无法写入磁盘
UPLOAD_ERR_PARTIAL 如果文件只能部分上传并且 UPLOAD_ERR_CANT_WRITE 文件无法写入磁盘,您将得到 。
PHP 扩展停止了文件上传
有时,您会收到错误消息 UPLOAD_ERR_EXTENSION ,因为某些扩展程序停止了文件上传。这需要您进行更多调查,以找出导致问题的扩展。
这是 upload.php的完整代码,它将在上传成功或失败的情况下在上传页面上向用户显示一条消息。有关上传成功或失败的信息存储在 $_SESSION['message'].
<?php session_start(); $message = ''; if (isset($_POST['uploadBtn']) && $_POST['uploadBtn'] == 'Upload') { if (isset($_FILES['uploadedFile']) && $_FILES['uploadedFile']['error'] === UPLOAD_ERR_OK) { // get details of the uploaded file $fileTmpPath = $_FILES['uploadedFile']['tmp_name']; $fileName = $_FILES['uploadedFile']['name']; $fileSize = $_FILES['uploadedFile']['size']; $fileType = $_FILES['uploadedFile']['type']; $fileNameCmps = explode(".", $fileName); $fileExtension = strtolower(end($fileNameCmps)); // sanitize file-name $newFileName = md5(time() . $fileName) . '.' . $fileExtension; // check if file has one of the following extensions $allowedfileExtensions = array('jpg', 'gif', 'png', 'zip', 'txt', 'xls', 'doc'); if (in_array($fileExtension, $allowedfileExtensions)) { // directory in which the uploaded file will be moved $uploadFileDir = './uploaded_files/'; $dest_path = $uploadFileDir . $newFileName; if(move_uploaded_file($fileTmpPath, $dest_path)) { $message ='File is successfully uploaded.'; } else { $message = 'There was some error moving the file to upload directory. Please make sure the upload directory is writable by web server.'; } } else { $message = 'Upload failed. Allowed file types: ' . implode(',', $allowedfileExtensions); } } else { $message = 'There is some error in the file upload. Please check the following error.<br>'; $message .= 'Error:' . $_FILES['uploadedFile']['error']; } } $_SESSION['message'] = $message; header("Location: index.php");
讨论
今天,我们讨论了 PHP 中文件上传的基础知识。在文章的前半部分,我们讨论了文件上传工作所需的不同配置选项。然后我们查看了一个真实的示例,该示例演示了文件上传在 PHP 中的工作方式。
- 关键设置
- file_uploads
- upload_max_filesize
- upload_tmp_dir
- post_max_size
- max_file_uploads
- max_input_time
- memory_limit
- max_execution_time
- 文件太大
- 临时文件夹丢失
- 部分上传或无法写入磁盘
- PHP 扩展停止了文件上传