当前位置:首页>python>Python Web开发:文件上传与下载

Python Web开发:文件上传与下载

  • 2026-06-28 02:45:05
Python Web开发:文件上传与下载
副标题

: 90%的人不知道,正确的文件处理能避免90%的安全漏洞

痛点:为什么你的文件上传功能总是有问题?

2025年某项目文件上传被用来攻击服务器,上传了恶意脚本。问题出在哪?工程师没有验证文件类型和大小。

真相

:文件上传需要严格验证、安全存储、正确响应。

安全要点重要性实现难度
文件类型验证
文件大小限制
文件名安全
存储位置隔离
访问控制

一、基础文件上传

1.1 FastAPI文件上传

from fastapi import FastAPI, UploadFile, File, HTTPException

from fastapi.responses import FileResponse

import shutil

from pathlib import Path

import uuid

import os

app = FastAPI()

UPLOAD_DIR = Path("uploads")

UPLOAD_DIR.mkdir(exist_ok=True)

@app.post("/upload/")

async def upload_file(file: UploadFile = File(...)):

"""基础文件上传"""

# 验证文件类型

allowed_types = ["image/jpeg", "image/png", "image/gif", "application/pdf"]

if file.content_type not in allowed_types:

raise HTTPException(status_code=400, detail="不支持的文件类型")

# 生成安全文件名

file_extension = file.filename.split(".")[-1]

safe_filename = f"{uuid.uuid4().hex}.{file_extension}"

# 保存文件

file_path = UPLOAD_DIR / safe_filename

with open(file_path, "wb") as buffer:

shutil.copyfileobj(file.file, buffer)

return {

"filename": file.filename,

"saved_as": safe_filename,

"size": file_path.stat().st_size,

"content_type": file.content_type

}

1.2 多文件上传

from typing import List

@app.post("/upload/multiple/")

async def upload_multiple_files(

files: List[UploadFile] = File(...)

):

"""多文件上传"""

results = []

for file in files:

# 验证

if file.content_type not in ["image/jpeg", "image/png"]:

continue

# 保存

file_extension = file.filename.split(".")[-1]

safe_filename = f"{uuid.uuid4().hex}.{file_extension}"

file_path = UPLOAD_DIR / safe_filename

with open(file_path, "wb") as buffer:

shutil.copyfileobj(file.file, buffer)

results.append({

"original": file.filename,

"saved_as": safe_filename,

"size": file_path.stat().st_size

})

return {"uploaded": results, "count": len(results)}

1.3 带表单的上传

from fastapi import Form

@app.post("/upload/profile/")

async def upload_profile(

file: UploadFile = File(...),

user_id: int = Form(...),

description: str = Form(...)

):

"""带表单数据的文件上传"""

# 验证用户

if user_id <= 0:

raise HTTPException(status_code=400, detail="无效的用户ID")

# 验证文件

if not file.filename.endswith((".jpg", ".jpeg", ".png")):

raise HTTPException(status_code=400, detail="只支持图片")

# 保存

safe_filename = f"{uuid.uuid4().hex}.jpg"

file_path = UPLOAD_DIR / "profiles" / safe_filename

file_path.parent.mkdir(exist_ok=True)

with open(file_path, "wb") as buffer:

shutil.copyfileobj(file.file, buffer)

return {

"user_id": user_id,

"description": description,

"avatar": safe_filename

}

二、文件验证

2.1 文件类型验证

import magic  # pip install python-magic

ALLOWED_MIME_TYPES = {

"image/jpeg": [".jpg", ".jpeg"],

"image/png": [".png"],

"image/gif": [".gif"],

"application/pdf": [".pdf"],

"text/plain": [".txt"],

}

def validate_file_type(file: UploadFile) -> tuple[bool, str]:

"""验证文件类型"""

# 检查扩展名

if not file.filename:

return False, "文件名为空"

extension = "." + file.filename.split(".")[-1].lower()

# 检查MIME类型

if file.content_type not in ALLOWED_MIME_TYPES:

return False, f"不支持的文件类型: {file.content_type}"

# 检查扩展名是否匹配MIME

if extension not in ALLOWED_MIME_TYPES.get(file.content_type, []):

return False, "文件扩展名与类型不匹配"

return True, "验证通过"

使用

@app.post("/upload/validated/")

async def upload_validated(file: UploadFile = File(...)):

is_valid, message = validate_file_type(file)

if not is_valid:

raise HTTPException(status_code=400, detail=message)

# 继续处理...

2.2 文件大小验证

MAX_FILE_SIZE = 10  1024  1024  # 10MB

def validate_file_size(file: UploadFile, max_size: int = MAX_FILE_SIZE) -> tuple[bool, str]:

"""验证文件大小"""

# 读取文件内容获取大小

content = file.file.read()

file.file.seek(0) # 重置指针

if len(content) > max_size:

return False, f"文件过大,最大允许 {max_size // 1024 // 1024}MB"

if len(content) == 0:

return False, "文件为空"

return True, "验证通过"

使用

@app.post("/upload/size-checked/")

async def upload_size_checked(file: UploadFile = File(...)):

is_valid, message = validate_file_size(file)

if not is_valid:

raise HTTPException(status_code=400, detail=message)

# 继续处理...

2.3 文件名安全

import re

def sanitize_filename(filename: str) -> str:

"""清理文件名"""

if not filename:

raise ValueError("文件名为空")

# 移除路径遍历字符

filename = os.path.basename(filename)

# 移除特殊字符

filename = re.sub(r'[<>:"/\\|?*]', '_', filename)

# 限制长度

if len(filename) > 255:

name, ext = os.path.splitext(filename)

filename = name[:255-len(ext)] + ext

return filename

def generate_safe_filename(original: str) -> str:

"""生成安全的文件名"""

# 获取扩展名

extension = os.path.splitext(original)[1].lower()

# 生成UUID

safe_name = f"{uuid.uuid4().hex}{extension}"

return safe_name

2.4 综合验证器

from dataclasses import dataclass

from typing import Optional

@dataclass

class FileValidationResult:

is_valid: bool

error: Optional[str] = None

safe_filename: Optional[str] = None

file_size: Optional[int] = None

class FileValidator:

"""文件验证器"""

def __init__(

self,

allowed_types: list[str] = None,

max_size: int = 10 1024 1024,

allowed_extensions: list[str] = None

):

self.allowed_types = allowed_types or ["image/jpeg", "image/png", "image/gif"]

self.max_size = max_size

self.allowed_extensions = allowed_extensions or [".jpg", ".jpeg", ".png", ".gif"]

def validate(self, file: UploadFile) -> FileValidationResult:

# 检查文件名

if not file.filename:

return FileValidationResult(is_valid=False, error="文件名为空")

# 检查扩展名

extension = os.path.splitext(file.filename)[1].lower()

if extension not in self.allowed_extensions:

return FileValidationResult(

is_valid=False,

error=f"不支持的文件扩展名: {extension}"

)

# 检查MIME类型

if file.content_type not in self.allowed_types:

return FileValidationResult(

is_valid=False,

error=f"不支持的文件类型: {file.content_type}"

)

# 检查大小

content = file.file.read()

file.file.seek(0)

if len(content) > self.max_size:

return FileValidationResult(

is_valid=False,

error=f"文件过大,最大允许 {self.max_size // 1024 // 1024}MB"

)

if len(content) == 0:

return FileValidationResult(

is_valid=False,

error="文件为空"

)

# 生成安全文件名

safe_filename = f"{uuid.uuid4().hex}{extension}"

return FileValidationResult(

is_valid=True,

safe_filename=safe_filename,

file_size=len(content)

)

使用

validator = FileValidator(

allowed_types=["image/jpeg", "image/png"],

max_size=5 1024 1024, # 5MB

allowed_extensions=[".jpg", ".jpeg", ".png"]

)

@app.post("/upload/strict/")

async def upload_strict(file: UploadFile = File(...)):

result = validator.validate(file)

if not result.is_valid:

raise HTTPException(status_code=400, detail=result.error)

# 保存文件

file_path = UPLOAD_DIR / result.safe_filename

with open(file_path, "wb") as buffer:

shutil.copyfileobj(file.file, buffer)

return {

"filename": result.safe_filename,

"size": result.file_size

}

三、文件下载

3.1 基础文件下载

from fastapi.responses import FileResponse, StreamingResponse

from pathlib import Path

@app.get("/download/{filename}")

async def download_file(filename: str):

"""下载文件"""

# 验证文件名

safe_filename = os.path.basename(filename)

file_path = UPLOAD_DIR / safe_filename

if not file_path.exists():

raise HTTPException(status_code=404, detail="文件不存在")

return FileResponse(

path=file_path,

filename=safe_filename,

media_type="application/octet-stream"

)

3.2 大文件流式下载

def file_iterator(file_path: Path, chunk_size: int = 8192):

"""文件迭代器"""

with open(file_path, "rb") as f:

while chunk := f.read(chunk_size):

yield chunk

@app.get("/download/large/{filename}")

async def download_large_file(filename: str):

"""大文件流式下载"""

safe_filename = os.path.basename(filename)

file_path = UPLOAD_DIR / safe_filename

if not file_path.exists():

raise HTTPException(status_code=404, detail="文件不存在")

return StreamingResponse(

file_iterator(file_path),

media_type="application/octet-stream",

headers={

"Content-Disposition": f'attachment; filename="{safe_filename}"'

}

)

3.3 带权限的下载

from fastapi import Depends

def get_current_user(token: str = Depends(oauth2_scheme)):

# 验证token,返回用户信息

...

@app.get("/files/{file_id}/download")

async def download_file(

file_id: int,

current_user: dict = Depends(get_current_user)

):

"""带权限的文件下载"""

# 从数据库获取文件信息

file_info = get_file_from_db(file_id)

if not file_info:

raise HTTPException(status_code=404, detail="文件不存在")

# 检查权限

if file_info.owner_id != current_user["id"] and not current_user.get("is_admin"):

raise HTTPException(status_code=403, detail="无权访问")

file_path = Path(file_info.file_path)

if not file_path.exists():

raise HTTPException(status_code=404, detail="文件不存在")

return FileResponse(

path=file_path,

filename=file_info.original_name,

media_type=file_info.content_type

)

四、图片处理

4.1 图片上传与缩略图

from PIL import Image

import io

@app.post("/upload/image/")

async def upload_image(file: UploadFile = File(...)):

"""上传图片并生成缩略图"""

# 验证

if file.content_type not in ["image/jpeg", "image/png", "image/gif"]:

raise HTTPException(status_code=400, detail="只支持图片")

# 读取图片

image = Image.open(file.file)

# 验证图片有效性

image.verify()

file.file.seek(0)

image = Image.open(file.file)

# 生成缩略图

thumbnail = image.copy()

thumbnail.thumbnail((200, 200))

# 保存原图

original_filename = f"{uuid.uuid4().hex}.jpg"

original_path = UPLOAD_DIR / "original" / original_filename

original_path.parent.mkdir(exist_ok=True)

image.save(original_path, quality=95)

# 保存缩略图

thumbnail_filename = f"{uuid.uuid4().hex}_thumb.jpg"

thumbnail_path = UPLOAD_DIR / "thumbnail" / thumbnail_filename

thumbnail_path.parent.mkdir(exist_ok=True)

thumbnail.save(thumbnail_path, quality=80)

return {

"original": original_filename,

"thumbnail": thumbnail_filename,

"size": image.size

}

4.2 图片格式转换

@app.post("/convert/")

async def convert_image(

file: UploadFile = File(...),

format: str = "webp"

):

"""转换图片格式"""

if file.content_type not in ["image/jpeg", "image/png", "image/gif"]:

raise HTTPException(status_code=400, detail="只支持图片")

# 读取图片

image = Image.open(file.file)

# 转换格式

output = io.BytesIO()

format_map = {

"jpg": "JPEG",

"jpeg": "JPEG",

"png": "PNG",

"webp": "WEBP",

"gif": "GIF"

}

image.save(output, format=format_map.get(format.lower(), "JPEG"))

output.seek(0)

return StreamingResponse(

output,

media_type=f"image/{format}",

headers={"Content-Disposition": f'attachment; filename="converted.{format}"'}

)

五、云存储集成

5.1 AWS S3上传

import boto3

from botocore.exceptions import ClientError

s3_client = boto3.client(

"s3",

aws_access_key_id=os.getenv("AWS_ACCESS_KEY"),

aws_secret_access_key=os.getenv("AWS_SECRET_KEY"),

region_name="us-east-1"

)

BUCKET_NAME = "my-app-uploads"

@app.post("/upload/s3/")

async def upload_to_s3(file: UploadFile = File(...)):

"""上传到S3"""

# 验证

result = validator.validate(file)

if not result.is_valid:

raise HTTPException(status_code=400, detail=result.error)

# 生成S3对象键

s3_key = f"uploads/{result.safe_filename}"

try:

s3_client.upload_fileobj(

file.file,

BUCKET_NAME,

s3_key,

ExtraArgs={

"ContentType": file.content_type,

"ACL": "private"

}

)

return {

"key": s3_key,

"url": f"https://{BUCKET_NAME}.s3.amazonaws.com/{s3_key}"

}

except ClientError as e:

raise HTTPException(status_code=500, detail=str(e))

5.2 预签名URL

@app.get("/files/{s3_key}/url")

async def get_presigned_url(s3_key: str):

"""获取预签名URL"""

try:

url = s3_client.generate_presigned_url(

"get_object",

Params={

"Bucket": BUCKET_NAME,

"Key": s3_key

},

ExpiresIn=3600 # 1小时有效

)

return {"url": url}

except ClientError as e:

raise HTTPException(status_code=500, detail=str(e))

六、安全最佳实践

6.1 安全检查清单

class SecureFileHandler:

"""安全文件处理器"""

def __init__(self, upload_dir: Path):

self.upload_dir = upload_dir.resolve() # 获取绝对路径

def save_file(self, file: UploadFile) -> Path:

"""安全保存文件"""

# 1. 验证文件

result = validator.validate(file)

if not result.is_valid:

raise ValueError(result.error)

# 2. 生成安全文件名

safe_filename = result.safe_filename

# 3. 确保路径在上传目录内

file_path = (self.upload_dir / safe_filename).resolve()

# 检查路径遍历攻击

if not str(file_path).startswith(str(self.upload_dir)):

raise ValueError("非法的文件路径")

# 4. 确保目录存在

file_path.parent.mkdir(parents=True, exist_ok=True)

# 5. 保存文件

with open(file_path, "wb") as f:

shutil.copyfileobj(file.file, f)

# 6. 设置文件权限

os.chmod(file_path, 0o644)

return file_path

def serve_file(self, filename: str) -> Path:

"""安全提供文件"""

# 1. 清理文件名

safe_filename = os.path.basename(filename)

# 2. 构建路径

file_path = (self.upload_dir / safe_filename).resolve()

# 3. 检查路径遍历

if not str(file_path).startswith(str(self.upload_dir)):

raise ValueError("非法的文件路径")

# 4. 检查存在

if not file_path.exists():

raise FileNotFoundError("文件不存在")

return file_path

6.2 防CSRF文件上传

from fastapi import Request, HTTPException

import secrets

生成上传令牌

def generate_upload_token() -> str:

return secrets.token_urlsafe(32)

存储令牌(生产环境用Redis)

upload_tokens: dict = {}

@app.post("/upload/protected/")

async def upload_protected(

file: UploadFile = File(...),

token: str = Form(...),

request: Request = None

):

"""带CSRF保护的文件上传"""

# 验证令牌

if token not in upload_tokens:

raise HTTPException(status_code=403, detail="无效的令牌")

# 验证令牌来源

stored_token = upload_tokens[token]

if stored_token["session_id"] != request.session.get("session_id"):

raise HTTPException(status_code=403, detail="令牌不匹配")

# 验证文件

result = validator.validate(file)

if not result.is_valid:

raise HTTPException(status_code=400, detail=result.error)

# 删除已使用的令牌

del upload_tokens[token]

# 保存文件...

七、实战案例

7.1 完整文件管理系统

from fastapi import FastAPI, UploadFile, File, HTTPException, Depends, status

from fastapi.responses import FileResponse

from pydantic import BaseModel

from typing import Optional

from datetime import datetime

from pathlib import Path

import uuid

import os

app = FastAPI()

配置

UPLOAD_DIR = Path("uploads")

MAX_FILE_SIZE = 50 1024 1024 # 50MB

ALLOWED_TYPES = ["image/jpeg", "image/png", "image/gif", "application/pdf"]

数据库模型(简化)

class FileRecord(BaseModel):

id: str

original_name: str

saved_name: str

size: int

content_type: str

owner_id: int

created_at: datetime

is_public: bool = False

内存存储(生产环境用数据库)

files_db: dict = {}

class FileValidator:

"""文件验证器"""

def validate(self, file: UploadFile) -> tuple[bool, str, str]:

# 检查扩展名

allowed_extensions = [".jpg", ".jpeg", ".png", ".gif", ".pdf"]

extension = os.path.splitext(file.filename)[1].lower()

if extension not in allowed_extensions:

return False, f"不支持的文件类型: {extension}", ""

# 检查MIME

if file.content_type not in ALLOWED_TYPES:

return False, f"不支持的文件类型: {file.content_type}", ""

# 检查大小

content = file.file.read()

file.file.seek(0)

if len(content) > MAX_FILE_SIZE:

return False, f"文件过大,最大允许 {MAX_FILE_SIZE // 1024 // 1024}MB", ""

if len(content) == 0:

return False, "文件为空", ""

# 生成安全文件名

safe_name = f"{uuid.uuid4().hex}{extension}"

return True, "验证通过", safe_name

validator = FileValidator()

class FileUploadResponse(BaseModel):

id: str

original_name: str

saved_name: str

size: int

content_type: str

url: str

@app.post("/files/upload/", response_model=FileUploadResponse)

async def upload_file(

file: UploadFile = File(...),

owner_id: int = Depends(lambda: 1) # 从认证获取

):

"""上传文件"""

# 验证

is_valid, message, safe_name = validator.validate(file)

if not is_valid:

raise HTTPException(status_code=400, detail=message)

# 保存

file_path = UPLOAD_DIR / safe_name

file_path.parent.mkdir(exist_ok=True)

with open(file_path, "wb") as buffer:

shutil.copyfileobj(file.file, buffer)

# 创建记录

file_id = str(uuid.uuid4())

record = FileRecord(

id=file_id,

original_name=file.filename,

saved_name=safe_name,

size=file_path.stat().st_size,

content_type=file.content_type,

owner_id=owner_id,

created_at=datetime.utcnow()

)

files_db[file_id] = record

return FileUploadResponse(

id=file_id,

original_name=file.filename,

saved_name=safe_name,

size=record.size,

content_type=record.content_type,

url=f"/files/{file_id}/download"

)

@app.get("/files/{file_id}/download")

async def download_file(file_id: str):

"""下载文件"""

record = files_db.get(file_id)

if not record:

raise HTTPException(status_code=404, detail="文件不存在")

# 检查权限

# if record.owner_id != current_user_id and not record.is_public:

# raise HTTPException(status_code=403, detail="无权访问")

file_path = UPLOAD_DIR / record.saved_name

if not file_path.exists():

raise HTTPException(status_code=404, detail="文件不存在")

return FileResponse(

path=file_path,

filename=record.original_name,

media_type=record.content_type

)

@app.get("/files/{file_id}")

async def get_file_info(file_id: str):

"""获取文件信息"""

record = files_db.get(file_id)

if not record:

raise HTTPException(status_code=404, detail="文件不存在")

return record

@app.delete("/files/{file_id}")

async def delete_file(file_id: str, owner_id: int = Depends(lambda: 1)):

"""删除文件"""

record = files_db.get(file_id)

if not record:

raise HTTPException(status_code=404, detail="文件不存在")

# 检查权限

if record.owner_id != owner_id:

raise HTTPException(status_code=403, detail="无权删除")

# 删除文件

file_path = UPLOAD_DIR / record.saved_name

if file_path.exists():

file_path.unlink()

# 删除记录

del files_db[file_id]

return {"message": "文件已删除"}

@app.get("/files/")

async def list_files(

owner_id: int = Depends(lambda: 1),

limit: int = 20,

skip: int = 0

):

"""列出文件"""

user_files = [

f for f in files_db.values()

if f.owner_id == owner_id

][skip:skip + limit]

return {

"files": user_files,

"total": len([f for f in files_db.values() if f.owner_id == owner_id])

}

常见坑自查清单

现象自查方法修复方案
路径遍历访问非法文件检查文件名用os.path.basename
文件覆盖数据丢失检查文件名生成用UUID
恶意上传服务器被攻击检查文件类型验证MIME+扩展名
磁盘满服务不可用检查大小限制限制文件大小
权限泄露未授权访问检查访问控制添加权限验证

结语

关键洞察

  • 验证文件类型和大小
  • 使用UUID生成文件名
  • 限制上传目录访问
  • 实现权限控制

互动

  1. 1.你用本地存储还是云存储?
  2. 2.遇到过文件上传的安全问题吗?
  3. 3.图片处理用PIL还是其他库?
版本: V1.0 | 2026-05-26 | Python Web开发系列

📚 推荐阅读

📝 摘要:今天深入学习静态代码分析技术,这是安全审计的核心技能。从 Python AST 模块到检测模式设计,收获满满!

发布于 202603

01-Python 环境搭建与第一个脚本

发布于 202603

【优化】Python代码优化与调试技巧

发布于 202603

KEYWORDS

IL, Python, python, 类, 对象

💡 如果你觉得这篇文章有帮助,请点个在看,分享给更多需要的人!

📝 关注我,获取更多实用干货~

🤝 有问题欢迎评论区留言交流!

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 08:28:48 HTTP/2.0 GET : https://f.mffb.com.cn/a/498801.html
  2. 运行时间 : 0.175548s [ 吞吐率:5.70req/s ] 内存消耗:4,648.62kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=2913ee7d32a7d938b04deb40d3bc6a94
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000517s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000554s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000576s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000298s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000511s ]
  6. SELECT * FROM `set` [ RunTime:0.001677s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000610s ]
  8. SELECT * FROM `article` WHERE `id` = 498801 LIMIT 1 [ RunTime:0.025122s ]
  9. UPDATE `article` SET `lasttime` = 1783038528 WHERE `id` = 498801 [ RunTime:0.009826s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000327s ]
  11. SELECT * FROM `article` WHERE `id` < 498801 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000593s ]
  12. SELECT * FROM `article` WHERE `id` > 498801 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.011713s ]
  13. SELECT * FROM `article` WHERE `id` < 498801 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002082s ]
  14. SELECT * FROM `article` WHERE `id` < 498801 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.045984s ]
  15. SELECT * FROM `article` WHERE `id` < 498801 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.007468s ]
0.177192s