7.8 KiB
7.8 KiB
URIOp 类技术文档
概述
URIOp 是一个用于处理 URI(统一资源标识符)与文件系统操作的 Python 类,主要用于在指定网站根目录范围内安全地进行文件和目录的读写、创建、重命名、删除等操作。该类通过配置文件获取网站根路径,并确保所有操作均限制在该目录范围内,防止越权访问。
此外,还定义了一个自定义异常 URIopException,用于统一抛出与 URI 操作相关的错误。
依赖模块
import os
import codecs
from appPublic.jsonConfig import getConfig
from appPublic.folderUtils import folderInfo
os: 提供操作系统接口,用于路径拼接、目录创建、文件重命名等。codecs: 以指定编码方式打开和读写文本文件。appPublic.jsonConfig.getConfig: 获取全局 JSON 配置对象。appPublic.folderUtils.folderInfo: 获取指定路径下的文件/目录列表信息。
自定义异常:URIopException
描述
表示 URI 操作过程中发生的错误,包含错误类型和详细消息。
构造函数
def __init__(self, errtype, errmsg)
参数:
errtype(str): 错误类型标识,如'url scope error'errmsg(str): 错误描述或触发错误的 URI
示例:
raise URIopException('url scope error', '/../malicious')
方法
| 方法 | 说明 |
|---|---|
__str__() |
返回格式化字符串:errtype=xxx,errmsg=xxx |
核心类:URIOp
描述
封装了基于 URI 的安全文件系统操作,所有操作都会被限制在配置中定义的 website.root 目录下。
初始化方法
def __init__(self)
功能:
- 加载全局配置:
getConfig() - 设置
realPath为网站根目录的绝对路径
属性初始化:
self.conf: 配置对象(通常来自jsonConfig)self.realPath: 网站根目录的绝对路径(os.path.abspath(conf.website.root))
⚠️ 要求配置中存在
website.root和website.coding字段。
公共方法
abspath(uri=None)
将相对 URI 转换为安全的绝对文件系统路径。
参数:
uri(str, 可选): 相对路径,例如"images/logo.png"或"/css/style.css"
返回值:
- (str) 对应的绝对路径字符串
异常:
- 若路径超出允许范围(即不在
realPath下),抛出URIopException('url scope error', uri)
实现逻辑:
- 从
conf.website.root开始构建基础路径 - 如果
uri不为空且以/开头,则去除开头斜杠 - 使用
os.path.join将 URI 分段拼接到根路径上 - 调用
os.path.abspath()规范化路径 - 检查生成路径是否在
realPath范围内(防止路径穿越攻击)
示例:
op = URIOp()
path = op.abspath("/uploads/file.txt")
# 结果类似:/var/www/uploads/file.txt(前提是根目录为 /var/www)
fileList(uri='')
列出指定 URI 所指向目录中的所有文件和子目录。
参数:
uri(str): 要列出内容的目录 URI,默认为根目录
返回值:
字典结构:
{
'total': int, # 文件总数
'rows': [ # 文件/目录列表
{
'id': str, # 文件路径 ID(路径分隔符替换为 '_#_')
'text': str, # 显示名称
'type': 'dir'|'file',
'mtime': float, # 修改时间戳
'size': int, # 文件大小(目录为 0)
'state': 'closed' if type=='dir' else None
},
...
]
}
注:此方法依赖
folderInfo(root_path, sub_uri)返回可迭代的文件信息。
特殊处理:
- 所有目录项添加
'state': 'closed' id中的/被替换为_#_,便于前端解析使用
示例:
files = op.fileList("/docs")
print(files['total']) # 输出文件数量
mkdir(at_uri, name)
在指定 URI 对应的目录下创建新目录。
参数:
at_uri(str): 父目录的 URI,如/projectsname(str): 新目录名称,如'new_folder'
实现步骤:
- 使用
abspath(at_uri)获取父目录绝对路径 - 使用
os.path.join()拼接完整路径 - 调用
os.mkdir(p)创建目录
示例:
op.mkdir("/data", "backup")
# 在 data 目录下创建 backup 子目录
rename(uri, newname)
重命名文件或目录。
参数:
uri(str): 原始文件/目录的 URInewname(str): 新的名字(仅名字,不含路径)
注意事项:
- 不支持跨目录移动,只能改名
- 新名称不能包含路径分隔符
实现步骤:
- 获取原路径绝对地址
- 获取其所在目录
- 构造新路径:
os.path.join(dirname, newname) - 调用
os.rename(old_path, new_path)
示例:
op.rename("/old_name.txt", "new_name.txt")
delete(uri)
删除指定 URI 指向的文件。
参数:
uri(str): 要删除的文件 URI
行为:
- 仅支持删除文件
- 不支持删除非空目录(若需删除目录,请先清空)
如需删除目录,建议扩展功能或使用其他工具。
示例:
op.delete("/temp/unwanted.log")
read(uri)
读取指定 URI 指向的文本文件内容。
参数:
uri(str): 文件 URI
返回值:
- (str) 文件内容字符串
编码:
- 使用配置项
conf.website.coding指定编码(如'utf-8') - 使用
codecs.open(..., 'r', encoding)安全读取
示例:
content = op.read("/config/settings.json")
save(uri, data)
保存数据到指定 URI 的文件中(覆盖写入)。
参数:
uri(str): 目标文件 URIdata(str): 要写入的字符串内容
行为:
- 若文件已存在则覆盖
- 若路径不存在会引发 OSError(建议提前创建目录)
编码:
- 使用
conf.website.coding进行编码写入
示例:
op.save("/notes.txt", "Hello World!")
write(uri, data)
功能与 save(uri, data) 完全相同。
当前代码中
write是save的重复实现,建议合并或保留其一以避免冗余。
建议改进:
def save(self, uri, data):
return self.write(uri, data)
# 或反之
安全性说明
- 所有路径操作都经过
abspath()的边界检查,防止路径穿越(如../../../etc/passwd) - 使用
os.path.abspath和前缀比对双重验证路径合法性 - 不直接暴露底层文件系统路径给外部调用者
配置要求
URIOp 依赖以下配置项(由 getConfig() 提供):
{
"website": {
"root": "/path/to/your/site/root",
"coding": "utf-8"
}
}
root: 网站资源根目录(推荐使用绝对路径)coding: 文件读写的默认字符编码
使用示例
from your_module import URIOp
op = URIOp()
# 列出根目录文件
files = op.fileList("/")
print(files)
# 创建目录
op.mkdir("/", "new_folder")
# 写入文件
op.save("/new_folder/hello.txt", "Hi there!")
# 读取文件
text = op.read("/new_folder/hello.txt")
print(text)
# 重命名
op.rename("/new_folder/hello.txt", "greeting.txt")
# 删除文件
op.delete("/new_folder/greeting.txt")
已知限制与改进建议
| 问题 | 建议 |
|---|---|
write 与 save 方法重复 |
合并为单一方法,或让其一作为别名 |
| 不支持递归删除目录 | 可增加 rmdir(uri, recursive=False) 方法 |
fileList 返回结构固定,不易扩展 |
可增加参数控制返回字段或排序 |
| 异常缺少 traceback 支持 | 可继承更丰富的异常基类或记录日志 |
版权与许可
© 2025 Your Organization.
本模块属于 appPublic 工具集的一部分,遵循项目整体开源协议(请参考 LICENSE 文件)。