thinkphp收件箱开发必须规范status和created_at字段建表及查询:status需not null default 0,created_at需default current_timestamp;查询须用预处理+session校验,发信强制取session('id'),并同步更新未读缓存。

ThinkPHP里查收件箱,别直接拼session('id')进SQL
很多人写where('to_id = '.session('id')),看着能跑,但这是SQL注入温床——只要session被劫持或伪造,攻击者就能拖走全表消息。更隐蔽的是:当session('id')为空、非数字或类型错乱时,查询可能返回空结果或报错,前端只显示空白,根本看不出哪出问题。
- 必须用预处理:
$messages = M('Email')->where(['to_id' => session('id')])->order('created_at DESC')->select(); - 查之前加校验:
if (!session('id') || !is_numeric(session('id'))) { $this->error('登录失效'); } - 关联用户真名要用
join,但别手写ON t1.to_id = t2.id这种裸字符串,ThinkPHP 3.2+ 支持数组条件,更安全
status字段不设默认值,未读红点就成玄学
只建status TINYINT却不设DEFAULT 0,新消息插入时status为NULL,后续查WHERE status = 0就漏掉这批数据;前端“未读数”统计要么不准,要么要额外OR status IS NULL,逻辑越补越乱。
- 建表必须写:
status TINYINT NOT NULL DEFAULT 0 COMMENT '0未读,1已读' - 标记已读不能只改
status,得同步更新用户未读缓存(比如Redis里user:123:unread),否则首页小红点刷新延迟甚至变负数 - 批量已读操作(如“全部标为已读”)要用
UPDATE ... WHERE to_id = ? AND status = 0,避免重复更新已读消息
发私信时sender_id必须强制绑定当前用户,不能靠前端传
如果接口接收$_POST['sender_id']并直接入库,恶意用户改个ID就能冒充管理员发系统通知——哪怕你前端做了隐藏域或JS校验,HTTP请求本身毫无可信度。
- 控制器里一律取自会话:
$data['sender_id'] = session('id');,删掉所有接收sender_id参数的逻辑 - 若需支持系统公告(
sender_id为0或NULL),则receiver_id字段不能设NOT NULL,同时加type TINYINT DEFAULT 1区分私信/公告/群发 - 发信前检查接收者是否存在:
if (!M('User')->find($receiverId)) { $this->error('用户不存在'); },避免无效消息堆积
ThinkPHP分页和时间排序,created_at没设DEFAULT CURRENT_TIMESTAMP就废了
建表时只写created_at DATETIME不设默认值,插入时不显式赋值,MySQL 5.7+ 会报错;5.6及以下则填0000-00-00 00:00:00,导致新消息排在最底下,用户永远看不到最新那条。
- 必须写:
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP - 分页用
paginate()没问题,但注意它底层是LIMIT+OFFSET,数据量大时慎用ORDER BY created_at DESC配合OFFSET 10000,会慢 - 如果用户收件箱超5万条,考虑按月分表(如
messages_202603),或加INDEX(to_id, created_at)联合索引
status和created_at这两个字段没按规范建——它们看着小,却决定了已读状态能不能准、新消息会不会丢、分页有没有序。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











