PHP实现上传文件并自动创建递归目录的完整代码

月亮慢半拍
月亮慢半拍
发布时间:2026-10-14 | 2人浏览过
原创

在开发用户头像或文件存储功能时,常常需要根据用户ID动态生成多层级的存储目录(如 D/AV/IC/...)。如果目标目录不存在且未提前创建,上传操作会失败。本文将通过一段PHP代码演示如何结合路径解析、递归目录创建与标准文件上传接口,实现“路径不存在则自动创建,存在则直接移动”的自动化流程。

核心逻辑与结构

该方案主要包含三个部分:路径生成器、递归目录创建函数以及主上传控制逻辑。整体流程为:根据输入参数计算文件应存放的物理路径 → 提取路径中的目录部分 → 调用递归函数确保所有上级目录存在 → 检查临时文件上传状态 → 将文件从临时位置移动到最终目标路径。

准备条件与环境设置

在使用此代码前,请确保运行环境满足以下条件:

  • PHP版本:至少支持 >=5.0 的标准环境,现代环境建议使用 PHP 7.4 或 PHP 8.x 以获得更好的性能和安全特性。
  • 目录权限:Web服务器进程(如 Nginx 的 www-data 或 Apache 的 apache)必须对目标根目录(例如 D:/avic/discuz/uc_server/data/avatar/)具有写入权限。若权限不足,mkdir 操作会静默失败。
  • POST大小限制:确保 php.ini 中的 upload_max_filesize 和 post_max_size 设置了允许的文件上限,否则 $_FILES 可能无法获取数据。

第1步:构建目标路径逻辑

为了避免单一目录下文件过多导致读写瓶颈,通常将文件分散存储到子文件夹中。本例通过 get_avatar() 函数模拟了这一过程。

目的:将用户ID转化为稳定的多级目录结构,并确保文件名符合规范。

代码说明:

  1. 安全截断:使用 abs(intval($uid)) 确保UID为正整数,防止恶意构造非法字符。
  2. 层级分割:将9位数字的UID分割为3-2-2-2的四段,分别作为一级、二级、三级子目录名。
  3. 后缀追加:根据类型添加 _real 后缀,并拼接尺寸标识(如 _middle)和扩展名。
//返回图片要存储的路径
function get_avatar($uid, $size = 'middle', $type = '') {
	$size = in_array($size, array('big', 'middle', 'small')) ? $size : 'middle';
	$uid = abs(intval($uid));
	$uid = sprintf("%09d", $uid);
	$dir1 = substr($uid, 0, 3);
	$dir2 = substr($uid, 3, 2);
	$dir3 = substr($uid, 5, 2);
	$typeadd = $type == 'real' ? '_real' : '';
	return $dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).$typeadd."_avatar_$size.jpg";
}

第2步:实现递归目录创建

直接使用 mkdir() 仅能创建最深层目录,若父目录不存在则会报错。因此需要使用递归算法逐层向上检查。

入口:接收待创建的绝对或相对目录路径 $dir。

动作:

  • 首先判断 is_dir($dir),若已存在则直接返回 true,避免重复创建。
  • 若不存在,先递归调用自身创建其父目录 dirname($dir)。
  • 父目录确认存在后,调用 mkdir($dir, 0777) 创建当前层级。
  • 注意:生产环境中不建议使用 0777 这种完全开放的权限,建议根据需求设置为 0755 以防止其他用户随意修改。
//递归创建目录,若传的$dir不是绝对路径,则会和运行此方法的目录同级
function mkdirs($dir){
	if(!is_dir($dir)){
		if(!mkdirs(dirname($dir))){
			return false;
		}
	 if(!mkdir($dir,0777)){
			return false;
		}
	}
return true;
}

第3步:执行上传与控制流

这是整个逻辑的主控部分,负责协调目录创建与文件转移。

重要参数:依赖全局变量 $_REQUEST['uid'] 和 $_FILES['pic']。

操作步骤:

  1. 组合路径:将基础存储路径与前文生成的相对路径拼接,得到物理路径 $avatar。
  2. 提取目录:使用 dirname($avatar) 获取文件所属的文件夹路径。
  3. 创建目录:调用 mkdirs($dir)。只有在此步骤成功(返回 true)后,才继续执行文件移动,以避免因目录缺失导致的移动失败。
  4. 验证错误码:检查 $_FILES["pic"]["error"]。标准HTTP上传中,错误码为 0 表示无错误;虽然原文逻辑写的是 >= 0,但这通常意味着只要没有产生致命的系统级错误(如未选择文件时的特定状态),就尝试移动。更严谨的做法是严格判断 == UPLOAD_ERR_OK。
  5. 移动文件:调用 move_uploaded_file($_FILES['pic']['tmp_name'], $avatar)。该函数会确保文件是通过HTTP POST上传的,防止跨站请求伪造攻击。
$uid=$_REQUEST['uid'];
//假设 $size, $type, $uid 已有合理赋值
$avatar = 'D:/avic/discuz/uc_server/data/avatar/'.get_avatar($uid, $size, $type);
$dir=dirname($avatar);

$errorcode=1;
$errormsg="";

//创建目录成功后移动临时文件
if(mkdirs($dir)){
	// 建议在实际使用中明确判断 error == 0
	if(isset($_FILES["pic"]) && $_FILES["pic"]["error"] == 0){
		if(move_uploaded_file($_FILES['pic']['tmp_name'],$avatar)){
			$errorcode=1;
		}else{
			$errorcode=0;
			$errormsg="文件移动失败";
		}
	}else{
		$errorcode=0;
		$errormsg="上传文件出错: ".$_FILES['pic']['error'];
	}
}else{
	$errorcode=0;
	$errormsg="无法创建目录";
}

$back=array("errorcode"=>$errorcode,'errormsg'=>$errormsg);
header('Content-Type: application/json');
echo json_encode($back);

完成判断与排错指南

执行完毕后,API将返回JSON格式结果:{"errorcode":1,"errormsg":""} 表示成功。errorcode 为0表示失败,errormsg 会提供具体原因。

若遇到失败,请按以下顺序排查:

  • 权限拒绝:检查Web服务器用户对 D:/avic/discuz/uc_server/data/avatar/ 是否拥有写权限。可通过 chmod 或Windows属性设置调整。
  • 磁盘空间:确认目标分区剩余空间充足。
  • 文件被占用:如果在Windows环境下,某些杀毒软件可能会锁定刚上传的文件导致 move_uploaded_file 失败,可稍后重试或添加延迟。

以上就是PHP上传文件并自动创建递归目录的详细内容,更多关于PHP文件操作与目录管理的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表