ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ThinkPHP家政评价系统开发实战:从库表设计到部署上线

2026/9/19 1:00:24 拓冰建站 浏览量
ThinkPHP家政评价系统开发实战:从库表设计到部署上线 开头直接进入主题。先说清楚这个项目是做什么的。昆明西山区那边的家政服务市场挺有意思——老小区多、新楼盘也密集家庭对保洁、月嫂、育儿嫂、养老护理的需求一直很旺。但线下找阿姨基本靠邻居推荐和朋友圈转发服务怎么样完全凭运气。被介绍来的阿姨到底靠不靠谱、有没有不良记录、之前服务过的家庭评价如何这些信息全是黑盒。我接到的这个项目就是给西山区一个本土家政平台开发一套评价系统让用户下单、阿姨上门、服务完评价、评价展示沉淀成一条完整的数据链。整体技术方案在ThinkPHP和Laravel之间反复比较过最终落地用的是ThinkPHP 8。这篇博文会把整个项目从业务拆解、技术选型、库表设计、功能实现到部署上线的完整过程都翻出来讲讲重点说清楚那些写代码时容易漏、但上线后一定会踩的坑比如关联删除、评价审核流程、二级域名部署等等。适合正在做类似评价类系统、或者准备在ThinkPHP框架下做业务系统的朋友参考。1. 业务盘点家政评价这潭水里藏着哪些需求1.1 西山区市场的一个关键特征西山区的用户群体很有意思。一方面是大规模回迁房和刚需盘居住密度高双职工家庭多请保洁是刚需另一方面是这类家庭对“安全性”的敏感度非常高——让一个陌生人进家门服务质量差一点可以忍但人的基本情况靠不靠谱这是第一道门槛。所以这个评价系统从一开始就不是简单地搞个“好评差评”按钮。它要解决的是三个层面的问题给用户一个表达真实体验的出口包括工完是否及时、工具是否自带、是否损坏物品、态度如何、有没有额外收费。给平台一个审核和风控的抓手把不靠谱的服务人员挡在推荐池之外。给新用户一个可信任的决策参考而不是听平台自卖自夸。按照这个思路系统角色分了三种普通用户端微信端网页为主、家政人员端同样在网页端、平台管理端后台审核与数据运营。整体功能按角色分域设计评价不是孤立的它需要和用户、订单、阿姨档案、投诉工单四个模块联动。1.2 评价不是“打分器”而是服务闭环的一部分在设计需求的时候平台方一度把评价系统理解成“订单完成后弹个窗让用户打几颗星”。这太单薄了。真实的家政场景里评价至少要和这几个东西挂钩订单必须一单一评没有订单的评价没有参考价值也防不住刷单。阿姨档案评价会聚合到阿姨的个人页上形成好评率和服务标签云直接影响阿姨之后的派单权重。结算与奖惩平台通过评价数据给阿姨评级连续差评会触发约谈甚至下架。投诉与申诉差评要允许家政人员发起申诉避免恶意差评或者用户主观臆断毁掉一个阿姨的接单生涯。所以我在做需求评审时直接把系统定义成“以订单为链路、以评价为核心的轻量CRM”。评价表的设计必须能支撑这些业务动作而不是孤零零一张打分表。1.3 三类用户的诉求差异把需求拆细一点会发现三方诉求完全不同在设计功能时都要照顾到。用户关注的是评价是否方便、是否能匿名、内容是否真实。很多用户其实不愿意让阿姨知道自己给了差评怕后续尴尬甚至被纠缠所以匿名评价必须是强需求。这个点我在功能设计时直接做成默认开启用户手动取消。家政人员关注的是被差评了有没有申诉的权利、评价是否公开了敏感个人信息。所以评价展示里绝对不能直接展示用户手机号、详细住址只能展示小区名或片区比如“西山区金碧街道某小区”黑白名单机制由此而来。平台关注的是数据能不能辅助运营。比如通过评价关键词的分析发现某个片区的阿姨普遍被反映“工具不全”就可以在阿姨培训时做针对性提醒。这些功能我们在后台做了一套简单的关键词聚合不需要多高级的人工智能光是分组统计就很有用了。2. 框架取舍为什么选了ThinkPHP而不是Laravel2.1 项目标题里同时出现两个框架的原因标题里写了“Thinkphp_Laravel框架”很多人可能会疑惑到底是用了哪个实际情况是项目初期团队内部有人提过用Laravel因为Laravel的生态确实更现代、队列和事件机制用起来更顺手。而且Laravel对规范的要求更高适合长期演进的大型项目。但经过一周的评估我们最终选择ThinkPHP。原因很实在逐个说对比维度ThinkPHP 8Laravel 11PHP版本要求PHP 8.0兼容性好PHP 8.2要求更高部署环境国内虚拟主机和面板都能直接跑对伪静态和目录权限要求更严格中文文档与学习成本文档齐全中文资料多文档优秀但中文生态稍弱全家桶程度MVC各层都有现成封装组件更灵活但要自己选型二次开发维护国内开发者基数大找人容易招人渠道相对窄一些性能基准基础性能不错ORM够用功能丰富但默认加载内容多说到底这个项目不是SaaS级产品不需要分布式、不需要复杂队列核心就是把业务快而稳地跑起来。ThinkPHP的模型关联、软删除、验证器、中间件这些能力已经覆盖了评价系统90%的需求没有理由引入更重的框架增加团队学习成本。2.2 两个框架在评价系统场景下的实际表现如果纯粹从功能实现角度对比两者差异在评价系统这个场景里其实不明显。比如模型关联Laravel有Eloquent的with预加载ThinkPHP同样支持关联预加载软删除两者都有验证器也都有现成组件。真正的差异在部署和运维。小皮面板phpStudy这类国内环境ThinkPHP能直接跑运行目录设置好伪静态写完就完事。Laravel在Windows开发环境和Linux线上环境之间经常遇到storage权限、composer依赖不一致、public目录软链等问题处理起来比较折腾。还有一点家政平台运营方是本土中小团队后续维护很可能找一个本地外包公司来做。与其用一个他们不熟悉的框架不如用一个生态更普及、中文资料搜索即得的技术栈。技术选型不是给自己炫技是要对项目未来一年、三年的维护成本负责。所以最终结构是ThinkPHP 8 MySQL 5.7 Nginx小皮面板环境前端用服务端渲染加少量原生JavaScript管理后台直接使用模板引擎这套方案能最大化降低整体复杂度。2.3 目录结构与分层思路ThinkPHP 8 默认的多应用模式非常适合这个项目。我把前后台拆成两个应用project_root ├── app │ ├── index // 用户端应用 │ │ ├── controller │ │ ├── model │ │ └── view │ ├── admin // 管理后台应用 │ │ ├── controller │ │ ├── model │ │ └── view │ └── api // 接口应用小程序/客户端预留 ├── config ├── public // Web运行目录 │ ├── index.php │ └── static ├── route └── vendor评价相关业务放在app/api里做接口前端页面通过ajax调用。这样的好处是以后如果要出微信小程序可以直接复用这套接口不用再单独开发一套后端。路由方面使用ThinkPHP的路由规则把评价提交、审核、申诉这些接口都定义了明确的伪静态路径。3. 核心库表设计评价数据怎么组织才扛得住业务变化3.1 整体表结构规划评价系统涉及的表面看起来只有一张评价表但只要一细想就会发现图集、标签、回复、申诉、审核日志这些全部要落库。我这边的核心表如下users用户表service_providers家政服务人员表orders订单表evaluations评价主表evaluation_images评价图片表evaluation_tags评价标签表evaluation_replies评价回复表商家/平台回复evaluation_appeals申诉表audit_logs审核日志表system_users后台管理员表外键没有在数据库层面去强约束统一在模型层维护。这是ThinkPHP项目常用的做法方便后续分库分表也不至于MySQL在删除时被外键卡住。3.2 评价主表字段设计评价主表是核心字段设计一点都不能含糊。我贴一下简化后的建表语句保留关键字段CREATE TABLE evaluations ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, order_id bigint(20) unsigned NOT NULL COMMENT 订单ID, user_id bigint(20) unsigned NOT NULL COMMENT 用户ID, provider_id bigint(20) unsigned NOT NULL COMMENT 家政人员ID, service_type tinyint(4) NOT NULL DEFAULT 0 COMMENT 服务类型1保洁 2月嫂 3育儿嫂 4养老护理, star_level tinyint(4) NOT NULL DEFAULT 5 COMMENT 综合评分1-5, price_score tinyint(4) NOT NULL DEFAULT 5 COMMENT 价格评分, attitude_score tinyint(4) NOT NULL DEFAULT 5 COMMENT 服务态度评分, quality_score tinyint(4) NOT NULL DEFAULT 5 COMMENT 服务质量评分, punctuality_score tinyint(4) NOT NULL DEFAULT 5 COMMENT 守时评分, content text COMMENT 评价内容, is_anonymous tinyint(1) NOT NULL DEFAULT 1 COMMENT 是否匿名, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态 0待审核 1已通过 2已驳回 3已删除, audit_admin_id bigint(20) DEFAULT NULL COMMENT 审核管理员ID, audit_remark varchar(255) DEFAULT NULL COMMENT 审核备注, audit_time datetime DEFAULT NULL COMMENT 审核时间, like_count int(11) NOT NULL DEFAULT 0 COMMENT 点赞数, created_at datetime DEFAULT NULL, updated_at datetime DEFAULT NULL, deleted_at datetime DEFAULT NULL COMMENT 软删除时间, PRIMARY KEY (id), KEY idx_order_id (order_id), KEY idx_provider_id (provider_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT家政服务评价表;几个字段单独说一下为什么这么设计多维度评分。家政行业的体验不是一个“总星”能概括的。比如阿姨干活很干净但总迟到或者态度特别好但收纳水平不行都需要分维度展示。我在前端评价表单里把综合评分拆成四个子项列表页展示综合分详情页展示四维雷达图。数据上多存几个int型字段成本不高但体验完全不同。status状态机。评价不是提交后立刻上墙的尤其家政行业直接进家门用户情绪化差评、恶意差评、虚假评价都可能有所以审核状态必须落库。0待审核、1已通过、2已驳回、3已删除这四个状态对应完整的操作流。is_anonymous默认1。前面提到匿名是刚需为了最大程度保护用户评价意愿默认是匿名状态用户如果愿意展示自己可以手动关掉。很多平台把默认设成不匿名结果用户根本不敢真实评价这个细节非常影响数据质量。3.3 标签表和图片表非结构化内容的结构化沉淀评价光有一段文字是不够的。家政用户特别喜欢用“守时”“工具齐全”“干活麻利”“沟通顺畅”“价格公道”这类词如果让用户自己打字输入成本高而且信息不结构化。所以我在表单里提供标签点选用户可以直接点选多个标签。标签表设计CREATE TABLE evaluation_tags ( id int(11) unsigned NOT NULL AUTO_INCREMENT, evaluation_id bigint(20) unsigned NOT NULL, tag_name varchar(30) NOT NULL COMMENT 标签名, tag_type tinyint(4) NOT NULL DEFAULT 1 COMMENT 1好评标签 2差评标签, PRIMARY KEY (id), KEY idx_evaluation_id (evaluation_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;标签值本来可以像很多系统一样用逗号拼在一个字段里但我还是用了子表。原因是后续要按标签聚合统计比如想知道这个月西山区的阿姨被好评最多的标签是什么、差评最集中的标签是什么SQL直接group by tag_name就能出结果字符串字段没法高效做这事。图片表设计相对来说简单一个evaluation_id外键加上图片URL、排序权重、创建时间。需要注意的是一定要在上传时就做压缩和防盗链不然前端页面容易被大图拖慢速度图片URL还会被别站直接盗用。压缩这块我在上传时用ThinkPHP的think\Image类做了尺寸限制超过1200px的等比压缩。3.4 订单与评价的绑定关系评价不能凭空产生必须挂在一个真实的订单下。所以订单表和评价表是严格一对一的关系。为保证这一点我在orders表加了一个evaluation_status字段用来记录这个订单是否已经评价过。同时在评价提交接口里做了强制校验一个订单只能提交一次评价。两条防线一起作用避免并发请求下出现一单多评的脏数据。家政务的订单状态是待支付 → 待服务 → 服务中 → 已完成 → 已取消。只有状态为“已完成”的订单才能发起评价服务中或已取消的订单后端一律拒绝。评价之后订单表里的evaluation_status更新为1同时把评价ID回填到订单表的evaluation_id字段查询时直接关联减少一次检索。4. 从提交评价到审核上墙全流程功能实现4.1 评价提交接口与参数校验用户端评价提交通道设计成一个单独的接口POST /api/evaluation/submit。控制器层面的逻辑分三步身份校验、订单验证、参数验证。参数验证用ThinkPHP的验证器来做?php namespace app\api\validate; use think\Validate; class EvaluationValidate extends Validate { protected $rule [ order_id require|integer|gt:0, star_level require|between:1,5, price_score require|between:1,5, attitude_score require|between:1,5, quality_score require|between:1,5, punctuality_score require|between:1,5, content max:500, images array|max:6, tags array|max:10, is_anonymous in:0,1, ]; protected $message [ order_id.require 订单参数缺失, star_level.between 综合评分必须在1-5之间, content.max 评价内容不能超过500字, images.array 图片格式错误, ]; }这里有一点要注意content不是必填用户完全可以只点标签不打字。但至少要有内容或者标签其中一样否则一个空壳评价没有参考价值。这个逻辑在控制器里单独判断if (empty($data[content]) empty($data[tags])) { return json([code 400, msg 请填写评价内容或选择标签]); }4.2 一单一评的幂等处理评价提交最大的风险是重复提交。用户手一抖点两次提交按钮或者前端没有做loading禁用请求就会并发进来。如果后端不做幂等处理一条评价就变成两条了。我的处理方案是三层校验数据库唯一索引给evaluations表的order_id添加唯一索引UNIQUE KEY uk_order_id (order_id)。这是最硬的一层保障就算应用层有逻辑漏洞数据库也会直接拒绝第二条插入。订单状态预检查提交时先查订单的evaluation_status如果已经是1直接返回“该订单已评价”。事务包裹评价主表和评价标签、图片子表在一个事务里写入任何一个子表写入失败则整体回滚。最后这点尤其重要。万一主表插入成功、标签表插入失败就会出现一条没有标签、没有图片的半残评价数据不一致很难排查。用事务包裹以后这种问题直接从根上杜绝。4.3 敏感词过滤与自动审核流程评价系统的审核流程是这个项目的重头戏。家政平台上的评价一旦展示出来就会直接影响其他人是否约这个阿姨所以审核不能形同虚设。但纯人工审核又有问题单量少还好单量一多审核就变成瓶颈评价要及时上墙才能给用户好的反馈体验。我的方案是“自动审核为主、人工审核兜底”。自动审核的规则分三块敏感词过滤。维护一个敏感词表覆盖政治敏感、辱骂人身攻击、涉黄涉暴、垃圾广告等词汇。用ThinkPHP的字符串匹配方式逐条跑一遍如果命中状态直接置为2并记录驳回原因。图片安全检测。评价上传的图片必须过一遍鉴黄接口。平台刚起步没必要自建模型直接对接云厂商的内容安全API返回pass的才允许进入展示review或block的进入人工复审或直接拒绝。垃圾内容检测。比如相同内容短时间内被多个账号提交、包含微信号或手机号之类的引流内容这类要单独识别通常直接放进待人工审核状态由管理员确认是真实评价还是广告。自动审核的代码大致长这样public function autoAudit(Evaluation $evaluation) { // 1. 敏感词检查 if (SensitiveWordService::check($evaluation-content)) { $evaluation-status 2; $evaluation-audit_remark 包含敏感词; $evaluation-save(); return; } // 2. 图片检查存在图片时 if ($evaluation-images()-count() 0) { $checkResult ImageAuditService::check($evaluation-images()-column(url)); if ($checkResult[status] block) { $evaluation-status 2; $evaluation-audit_remark 图片内容违规; $evaluation-save(); return; } } // 3. 通过自动审核 $evaluation-status 1; $evaluation-audit_admin_id 0; // 系统自动审核 $evaluation-audit_time date(Y-m-d H:i:s); $evaluation-save(); }这里有一个细节就是评价提交后不能立刻显示在前台。所以前端提交后要跳转到一个“审核中”的提示页告诉用户“评价已提交审核通过后将展示在阿姨主页”。等审核通过后再通过刷新或消息通知让用户看到自己的评价已经上墙。4.4 审核后如何聚合到前台评价通过审核之后不只是简单地在评价列表里多一条记录。它至少要同步影响到三个地方家政人员主页的评价聚合平均分、好评率、评价条数、标签云。平台首页的推荐逻辑综合评分高的阿姨排名靠前。后台的数据看板今日新增评价数、通过率、驳回率、平均分变化趋势。我用ThinkPHP的模型观察器来做这个联动Evaluation模型定义afterInsert、afterUpdate事件在评价写入或状态变更时触发对应的统计任务。public static function onAfterUpdate(Evaluation $evaluation) { // 只有当状态变为已通过时才重新聚合 if ($evaluation-status 1) { ProviderStatService::refresh($evaluation-provider_id); } }ProviderStatService里的逻辑就是重新算一遍该服务人员的平均分和各维度的均值更新到service_providers表的冗余字段里。这样前台查询阿姨列表的时候不用去evaluations表里现算avg()直接读冗余字段性能上好很多。4.5 商家回复与申诉机制评价审核通过上墙了不代表这件事就结束了。家政平台上一个差评对阿姨影响很大所以必须给家政人员端配“回复”功能和“申诉”功能。回复功能比较简单就是evaluation_replies表一个评价允许一条商家回复回复内容同样要走敏感词过滤。考虑到家政人员文化水平跨度比较大后台我把回复框做成了模板选择加自定义两种方式推荐话术模板直接生成“尊敬的客户感谢您的反馈我们会改进XX问题”降低回复门槛。申诉功能则是当家政人员认为某条差评不实或者属于恶意评价时提交申诉工单附上聊天记录截图或录音证据。管理员在后台看到申诉后可以决定维持原评还是隐藏评价。被隐藏的评价状态标记为“已隐藏”前端不再展示但保留在数据库里供平台分析。5. 最容易被忽视的删除逻辑关联数据处理实战5.1 删除业务数据的几种真实场景评价系统的“删除”比想象中复杂得多。日常运营中会遇到这些情况用户申请注销账号他名下所有评价怎么处理家政人员离职或者被平台清退他名下的历史评价怎么处理用户在后台联系客服说“我这条评价写错了帮我删掉”运营人员删掉评价后关联的图片、标签、回复怎么处理有一些违规评价被强制删除删除后是否要在前台留一个占位提示新手最容易犯的错就是在控制器里直接delete()一条主表记录然后发现评价详情页报错、图片残留、统计数字对不上、分离的碎片数据越来越多。这个项目里所有删除操作全部走了软删除和关联清理机制系统性解决数据一致性的问题。5.2 ThinkPHP的软删除与模型事件ThinkPHP的模型层提供了SoftDeleteTrait在模型里引入后delete()方法不会真正执行数据库删除而是把deleted_at字段写入当前时间查询时默认带上deleted_at IS NULL条件。但软删除只是第一步关联数据的清理才是重点。我的处理方式是给Evaluation模型注册模型事件在删除时同步清理关联子表?php namespace app\common\model; use think\model\concern\SoftDelete; use app\common\model\EvaluationImage; use app\common\model\EvaluationTag; use app\common\model\EvaluationReply; class Evaluation extends BaseModel { use SoftDelete; protected $name evaluations; protected $deleteTime deleted_at; public static function onBeforeDelete($evaluation) { // 删除评价时同步清理关联的图片和标签 EvaluationImage::where(evaluation_id, $evaluation-id)-delete(); EvaluationTag::where(evaluation_id, $evaluation-id)-delete(); } public static function onAfterDelete($evaluation) { // 如果有商家回复也一并软删除 EvaluationReply::where(evaluation_id, $evaluation-id)-delete(); // 刷新家政人员的统计数据 if ($evaluation-provider_id) { ProviderStatService::refresh($evaluation-provider_id); } } }这里解释一下为什么不用数据库外键ON DELETE CASCADE。家政评价数据属于业务核心数据直接物理级联删除的风险太大万一误删想恢复都难。用模型事件的方式以后想改逻辑、想加个回收站都很灵活。而且ThinkPHP的模型事件在软删除时也会触发正好满足“删除后同步处理关联”的需求。5.3 三个典型场景的具体处理策略场景一用户注销账号用户注销不意味着评价要跟着消失。如果用户注销后评价全部消失家政人员的评分、好评率瞬间就崩了这对平台生态不公平也容易被阿姨投诉。我的做法是用户注销后他名下的评价保留但统一做匿名化处理——user_id置为0is_anonymous置为1昵称显示为“已注销用户”。这样既保护了注销用户的信息又保留了对家政人员有用的评价数据。具体代码在用户控制器注销逻辑里补一段Evaluation::where(user_id, $userId)-update([ user_id 0, is_anonymous 1 ]);场景二家政人员下架或离职家政人员被清退后他在前台的主页要下线但已产生的订单评价还需要仲裁依据平台方可能因此涉及用户退费或者法律纠纷。所以不能物理删除只能操作service_providers表的status字段切换到“已下架”状态。历史评价仍然保留但前台展示时打上一个“该服务人员已暂停服务”的标识用户可以继续看到评价内容作为参考但不能预约下单。场景三运营后台软删除违规评价运营人员在前台看到一条违规评价处理路径是后台搜索确认 → 点“删除” → 模型事件自动清理图片和标签 → 评价状态变为已删除 → 前台列表不再展示 → 聚合统计重新计算。一套流程下来前台体验无感知但后台数据没有任何残留和断层。这套“软删除模型事件统计刷新”的组合在评价系统里是最省心的维护方案。6. 部署上线运行目录、二级域名和那些安全细节6.1 小皮面板建站与运行目录设置这个项目部署使用的Windows服务器加小皮面板phpStudy环境是Nginx PHP 8.1 MySQL 5.7。很多人在本地开发好好的一部署到小皮面板就各种404、500原因多半是运行目录没有指向public。ThinkPHP的入口文件在public/index.phpNginx的站点根目录必须指向public目录。如果直接指向项目根目录访问会出现两种情况首页能打开但所有静态资源都404或者直接报错。更严重的是如果根目录配置不当用户直接访问/app、/.env这类路径源码和数据库配置会被直接暴露这是高危漏洞。小皮面板创建站点时要在“运行目录”里选择/public同时开启“防跨站”选项把目录锁定在站点范围内。这一步做完常规的目录穿越攻击就能挡住大部分。6.2 用户端和管理端的二级域名配置这个项目有两个面向端用户端评价展示页、管理后台审核页。两个端使用同一个ThinkPHP多应用项目通过二级域名区分路由用户端www.xxx.com管理后台admin.xxx.com小皮面板的操作步骤是先在域名解析商那里给两个子域名配好A记录指向服务器IP。在Nginx里创建两个server块分别设置server_name。admin域名的root同样指向public因为ThinkPHP多应用模式只靠URL前缀区分应用不靠不同的目录。然后修改config/app.php把后台应用的域名绑定设置好app_map [ admin admin, ], domain_bind [ admin.xxx.com admin, ],这样访问admin.xxx.com时直接进入后台应用不会在URL里出现/admin前缀更干净也更好记。6.3 伪静态配置与URL美化ThinkPHP默认的URL带/index.php?s/...既不美观又有暴露框架路径的风险。用Nginx重写可以去掉index.phplocation / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } }注意这一段一定要写在location /块内并且root指向的是public目录。如果伪静态配完还是404优先检查root路径对不对其次看看是不是try_files和rewrite冲突了。伪静态配置完成后评价详情的URL就变成/evaluation/detail/123.html这样的形式对SEO也友好一些。6.4 图片存储与安全加固评价图片的上传是安全重灾区。我在设计上传接口时做了几个限制类型白名单只允许jpg、jpeg、png、webp禁止上传php、phtml、asp等任何可执行文件。文件头校验不只检查扩展名还要用finfo_open读文件的MIME类型防止有人改扩展名绕过。随机文件名上传后的文件名用uniqid 随机串重新生成不保留用户原始文件名避免包含路径穿越字符。存储路径隔离图片存放在public/uploads/evaluation/{日期}/目录下Nginx配置里对uploads目录禁止执行PHP脚本。最后这一点很多人会忽略。如果上传目录里被塞了一个shell.php而Nginx又允许PHP执行那整个服务器就沦陷了。只要在Nginx配置里加一行就可以解决location ~* ^/uploads/.*\.(php|php5)$ { deny all; }6.5 数据备份与灰度切换家政评价系统虽然业务量不如电商那么大但如果数据丢了用户的评价记录、家政人员的评分档案全部清零这个损失是平台方完全无法承受的。我用的备份策略很简单但也够用MySQL定时任务每天凌晨3点执行mysqldump保留最近7天的备份文件。图片异地备份因为图片量还不算大每周把uploads目录压缩同步到另一台存储空间。手工快照每次上线新版本前先打一次数据库快照出问题可以即时回滚。家政评价系统的数据量在早期不会太大不需要上分库分表那一套但备份一定不能省。这是上线前做过多次压力测试后得出的经验越是看着规模小的系统越要防止雪崩式流失。这套系统从立项到上线用了三周多的时间总体不算快也不算慢。核心功能跑通之后平台方最满意的反而是两件事一是每个订单都能严格一单一评数据很干净二是运营后台审核评价的流程很顺畅不用跨系统去操作。开发过程中的那些坑基本都出现在我上面提到的位置——选型纠结、表结构设计反复改、删除逻辑差点漏掉关联数据、部署时目录不对导致404。把这个项目过程整理出来希望对你设计和开发同类评价系统有所帮助。