import os import datetime from pathlib import Path from typing import Dict def save_face_to_up_images( client_ip: str, face_name: str, image_bytes: bytes, image_format: str = "jpg" ) -> Dict[str, str]: """ 保存人脸图片到 `/up_images/用户IP/人脸名字/` 路径 确保db_path以 /api/file/up_images 开头,且统一使用正斜杠 本地不创建/api/file/文件夹,仅URL访问时使用该前缀路由 参数: client_ip: 客户端IP(原始格式,如192.168.1.101) face_name: 人脸名称(用户输入,可为空) image_bytes: 人脸图片二进制数据 image_format: 图片格式(默认jpg) 返回: 字典:success(是否成功)、db_path(存数据库的路径,带/api/file/前缀)、local_abs_path(本地绝对路径)、msg(提示) """ try: # 1. 基础参数校验(不变) if not client_ip.strip(): return {"success": False, "db_path": "", "local_abs_path": "", "msg": "客户端IP不能为空"} if not image_bytes: return {"success": False, "db_path": "", "local_abs_path": "", "msg": "图片二进制数据为空"} if image_format.lower() not in ["jpg", "jpeg", "png"]: return {"success": False, "db_path": "", "local_abs_path": "", "msg": "仅支持jpg/jpeg/png格式"} # 2. 处理特殊字符(避免路径错误)(不变) safe_ip = client_ip.strip().replace(".", "_") # IP中的.替换为_ safe_face_name = face_name.strip() if (face_name and face_name.strip()) else "未命名" safe_face_name = "".join([c for c in safe_face_name if c not in r'\/:*?"<>|']) # 过滤非法字符 # 3. 构建根目录(强制转为绝对路径,避免相对路径混淆) root_dir = Path("up_images").resolve() if not root_dir.exists(): root_dir.mkdir(parents=True, exist_ok=True) print(f"[FileUtil] 已创建up_images根目录:{root_dir}") # 4. 构建文件层级路径(确保在root_dir子目录下)(不变) ip_dir = root_dir / safe_ip face_name_dir = ip_dir / safe_face_name face_name_dir.mkdir(parents=True, exist_ok=True) print(f"[FileUtil] 图片存储目录(本地):{face_name_dir}") # 5. 生成唯一文件名(毫秒级时间戳)(不变) timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3] image_filename = f"face_{safe_ip}_{timestamp}.{image_format.lower()}" local_abs_path = face_name_dir / image_filename if not local_abs_path.resolve().is_relative_to(root_dir.resolve()): raise Exception(f"图片路径不在up_images根目录下(安全校验失败):{local_abs_path}") # 数据库存储路径:核心修改——在原有relative_path前添加 /api/file/ 前缀 relative_path = local_abs_path.relative_to(root_dir.parent) relative_path_str = str(relative_path).replace("\\", "/") # 2. 再拼接/api/file/前缀 db_path = f"/api/file/{relative_path_str}" # 7. 写入图片文件(不变) with open(local_abs_path, "wb") as f: f.write(image_bytes) print(f"[FileUtil] 图片保存成功:") print(f" 数据库路径(带/api/file/前缀):{db_path}") print(f" 本地绝对路径(无/api/file/):{local_abs_path}") return { "success": True, "db_path": db_path, "local_abs_path": str(local_abs_path), "msg": "图片保存成功" } except Exception as e: error_msg = f"图片保存失败:{str(e)}" print(f"[FileUtil] 错误:{error_msg}") return {"success": False, "db_path": "", "local_abs_path": "", "msg": error_msg}