效果图
1.上传文件
2.压缩包文件
3.itemno1文件
4.上传到系统路径\ItemNo
5.更名后的itemno1文件(命名:当天日期+六位随机数)
代码
<form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'UTF-8'); ?>" method="post" enctype="multipart/form-data">
<input type="hidden" name="FormID" value="<?php echo $_SESSION['FormID']; ?>">
<input type="file" name="folderArchive[]" accept=".zip" multiple>
<input type="submit" value="上传" name="update">
</form>
<?php
//指定路径
$target_dir = "ItemNo/";
// 临时解压目录(新建后会被删除)
$unpack_dir = 'ItemNo_Updates/';
//开始上传
if (isset($_POST['update'])) {
// 判断是否有上传的文件
if (isset($_FILES['folderArchive']) && !empty($_FILES['folderArchive']['name'])) {
//设定一个变量,值为上传的文件信息
$zip_files = $_FILES['folderArchive'];
//对上传的文件的name值(例如test.zip)进行遍历
foreach ($zip_files['name'] as $key => $file_name) {
//检验文件是否是zip文件
// pathinfo() 函数用于解析路径信息:PATHINFO_EXTENSION参数,表明它会返回文件路径中的扩展名部分(如zip、txt 等)
// 将 pathinfo() 返回的扩展名转换为小写形式,
if (strtolower(pathinfo($file_name, PATHINFO_EXTENSION)) !== 'zip') {
// sprintf 函数:格式化字符串输出的函数
prnMsg(sprintf(_('文件 "%s" 不是ZIP格式,请上传ZIP文件.'), $file_name), 'error');
// 如果不是zip文件就,跳过此文件(将不再做上传等操作),继续执行后面的上传文件
continue;
}
//判断每一条数据的error值:看是否上传成功(UPLOAD_ERR_OK表示长传成功)
if ($zip_files['error'][$key] === UPLOAD_ERR_OK) {
//取出该条数据的tmp_name值(获取上传文件的临时存储路径)
$temp_file = $zip_files['tmp_name'][$key];
// 先创建并打开 ZipArchive 对象,创建一个新的ZipArchive对象(ZipArchive用于读取、创建、更新和提取ZIP格式的压缩文件)
$zip = new ZipArchive;
//打开压缩文件
if ($zip->open($temp_file) === TRUE) {
//创建临时解压目录
mkdir($unpack_dir, 0755, true);
// 验证ZIP文件结构
//设置一个变量用于判断结构是否合规
$structure_valid = true;
//遍历ZipArchive对象(通过 $zip 引用)中的所有文件.numFiles是压缩包内的文件数量
for ($i = 0; $i < $zip->numFiles && $structure_valid; $i++) {
// 获取指定索引 $i 处的ZIP压缩包内文件的名称
$filename = $zip->getNameIndex($i);
//将返回一个数组,数组中的每个元素对应于字符串中两个斜杠(/)之间的部分
$path_parts = explode('/', $filename);
// 检查文件路径分隔符个数,必须是两层结构
if (count($path_parts) != 2) {
//如果不是两层结构,结构不正确
$structure_valid = false;
prnMsg(sprintf(_('文件 "%s" 的内部结构不符合要求(必须是 ZIP -> (一级目录) -> 文件 的结构,至少要有一级子目录).'), $file_name), 'error');
//跳出循环
break;
}
}
//如果结构正确
if ($structure_valid) {
// 解压缩文件
$zip->extractTo($unpack_dir);
// 关闭已经打开的 ZipArchive 对象的(与open对应)
$zip->close();
// 获取解压后每个料号(子文件夹)的路径,取$target_dir目录下的所有子目录名称,并将这些名称作为一个数组赋值给$subDirs。
// $target_dir . '*':表示匹配$target_dir目录下的任何子字符串(在这里实际上指的是子目录名)
// GLOB_ONLYDIR 是 glob() 函数的一个标志参数,当设置这个标志时,glob() 函数只会返回与指定模式匹配的目录名
$subDirs = glob($unpack_dir . '*', GLOB_ONLYDIR);
//遍历每个文件夹的文件
foreach ($subDirs as $subDir) {
// 获取料号名称(文件夹名称)
$itemNo = basename($subDir);
// 获取子文件夹中的所有文件
$temp_sub_dir_files = glob($subDir . '/*');
//循环子文件中的文件
foreach ($temp_sub_dir_files as $file) {
// 如果 $file 是一个目录,跳过
if (is_dir($file)) {
continue;
}
//验证文件是否已在目标目录中存在
//获取文件名称
$fileName = basename($file);
// 获取目标目录下所有文件和目录的名字
$existingFiles = scandir($target_dir);
// 如果文件不在目标目录现存文件列表中,则是新上传的文件
if (!in_array($fileName, $existingFiles)) {
//获取当前日期
$dateForFilename = date('Ymd');
//生成随机数
$random_number = generateUniqueRandomNumber($target_dir, $dateForFilename);
// 构建新的文件名YMD_六位随机数(pathinfo用于从文件路径 $file 中提取出文件扩展名。)
$newFileName = $dateForFilename . '_' . sprintf('%06d', $random_number) . '.' . pathinfo($file, PATHINFO_EXTENSION);
//新文件路径
$new_path = $subDir . '/' . $newFileName;
// 重命名文件
rename($file, $new_path);
// $target_dir 是一个变量,它包含了目标目录的完整路径。
// $itemNo 是另一个变量,它代表了要创建的子目录的名称或者是某种项目的唯一标识符。
$targetSubDir = $target_dir . $itemNo;
// 检查 $targetSubDir 是否已经存在且是一个目录
if (!is_dir($targetSubDir)) {
// 调用 mkdir() 函数尝试创建这个子目录
// 第一个参数是待创建目录的路径名,即 $targetSubDir。
// 第二个参数 0755 是指创建的目录的权限模式。这是一个八进制数,转换成二进制后表示所有者有读写执行权限,同组用户和其他用户有读和执行权限,但没有写入权限。
// 第三个参数 true 表示如果父级目录不存在,也将递归创建它们(即允许创建多级目录)。
mkdir($targetSubDir, 0755, true);
}
// 将处理完的文件移动到最终目标目录
rename($new_path, $targetSubDir . '/' . $newFileName);
// 插入数据库
$time = time();
//获取文件名称(去掉后缀)
$baseNameWithoutExt = pathinfo($new_path, PATHINFO_FILENAME);
$sql = "INSERT INTO bom_headers_all_file
(
bom_header_id,
file_name,
file_desc,
file_patch,
creation_date,
created_by,
last_update_by,
last_update_date,
enable_flag
)
VALUES (
'1',
'" . $baseNameWithoutExt . "',
'" . $itemNo . "',
'" . $targetSubDir . '/' . $newFileName . "',
'" . $time . "',
'" . $_SESSION['UserID'] . "',
'" . $time . "',
'" . $_SESSION['UserID'] . "',
'Y'
)";
$result = DB_query($sql, $db);
// prnMsg(sprintf(_('文件 "%s" 在料号 "%s" 下已成功上传并重命名为 "%s" 并已插入数据库.'), basename($file), $itemNo, $newFileName), 'success');
}
}
}
// 删除临时解压目录及其内容
delTree($unpack_dir);
prnMsg(sprintf(_('文件 "%s" 上传成功.'), $file_name), 'success');
} else {
// 结构不合法,关闭ZIP资源并删除临时解压目录
$zip->close();
delTree($unpack_dir);
continue; // 跳过该文件,进入下一个文件的处理
}
} else {
prnMsg(sprintf(_('文件 "%s" 上传成功但无法解压.'), $file_name), 'error');
}
} else {
prnMsg(sprintf(_('文件 "%s" 上传失败.'), $file_name), 'error');
}
}
unset($_POST['update']);
} else {
prnMsg(_('附件上传失败!'), 'error');
}
}
// 定义一个函数,生成当天内不重复的六位随机数
function generateUniqueRandomNumber($dir, $dateForFilename)
{
//用do-while循环去判断文件名是否存在,如果存在就在此循环直到不存在为止
do {
// 生成一个介于100000到999999之间的随机整数
$random_number = mt_rand(100000, 999999);
//拼接字符串(/path/YMD_123456.ext 的字符串)(.ext 是一个占位符,表示文件的扩展名,实际应用中应替换为具体的文件类型如 .jpg, .txt, .pdf 等。)
$filePath = $dir . '/' . $dateForFilename . '_' . sprintf('%06d', $random_number) . '.ext';
} while (file_exists($filePath)); //检查指定的文件路径 $filePath 是否存在。
//跳出循环后返回随机数
return $random_number;
}
// 定义一个递归删除目录及其内容的函数
function delTree($dir)
{
// array_diff(scandir($dir), array('.', '..')) 从上述数组中排除.
// (当前目录)和 ..(上级目录),得到的就是该目录下所有实际的文件和子目录名称,然后将其赋值给 $files。
$files = array_diff(scandir($dir), array('.', '..'));
// 使用 foreach 循环遍历 $files 数组中的每一个文件或子目录
foreach ($files as $file) {
// (is_dir("$dir/$file")) 判断当前 $file 是否为子目录。
// 如果 $file 是子目录,则调用 delTree("$dir/$file") 函数递归删除这个子目录及其内部的所有文件和子目录。
// 如果 $file 不是子目录(即普通文件),则调用 unlink("$dir/$file") 函数删除这个文件。
(is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
}
// 删除最初传入的 $dir 目录本身。注意,只有当该目录为空时,rmdir() 才能成功删除目录。
return rmdir($dir);
}
?>