
简介PHP外卖点餐源码是一套面向在线餐饮行业的完整网站应用解决方案适合PHP初中级开发者、自由职业者及中小餐饮商户用于快速搭建或定制外卖订餐平台。源码基于PHP语言开发覆盖用户注册登录、菜单浏览、购物车、下单支付、订单追踪等完整业务流程同时体现响应式布局、MySQL数据库管理、第三方支付接口对接、服务端业务逻辑与常见安全防护等核心技术界面美观且功能结构清晰。压缩包共包含1166个文件约5.13MB其中以193个php逻辑文件、83个js交互脚本、19个css样式、53个html页面及大量jpg/gif图片素材为主体辅以db数据库、htm说明文档和系统流程图图片素材丰富可直接用于菜品展示与界面设计。目前该资源已有1814人学习下载。开发者可依据源码说明、安装指南、使用必读与更新日志快速部署结合授权文件了解使用约束既能借此进行PHP全栈实战训练也能在现有框架上继续扩展多商户、优惠券、订单管理等功能是入门外卖系统二次开发的不错起点。1. 从「看不上」到「自建外卖系统」这份源码的真实价值见过太多想做个外卖点餐网站的人第一反应是去定制外包开口就是几千等代码拿回来一看前后端耦合、没有注释、数据库字段全靠猜改一个功能恨不得重写半个项目。这份 PHP 外卖点餐源码不一样它是那种「你在本地一跑就能看到完整业务流」的完整工程用户端、商户端、配送端三套入口齐全界面干净核心功能清晰适合三种人想快速交付一个可演示项目的开发者需要一套代码研究订单流程的学生以及想低成本启盘私域外卖的个体老板。它也确实是 PHP 里很少见的「不劝退源码」——前提是你能把部署环境填平这正是接下来要讲的。2. 跑通本地环境PHP 版本选错后面全是玄学坑2.1 环境选型为什么我坚持用 PHP 5.6 兼容模式跑旧源码拿到源码第一件事不是看代码而是看根目录下有没有composer.json。这份资源用的是 PHP 原生开发没有引入重量级框架依赖主要在include和class目录里。常见做法是本地装一个集成环境我一般用 PHPStudy因为它可以一键切换 PHP 版本。这里有个关键参数很多老 PHP 项目在 PHP 7.0 以上会直接抛mcrypt相关报错或者each()函数被移除导致白屏。你拿到这份源码后先确认编码风格——如果大量使用mysql_*系列函数那铁定要跑 PHP 5.6如果代码里已经换成mysqli或PDO那 PHP 7.x 也能跑。我的建议是直接切到 PHP 5.6 兼容模式理由就一条这套代码的 sql 导入文件是 utf8_general_ci 排序规则在老版本 MySQL 上兼容最稳。# Windows 环境下的 PHPStudy 切换指令假设安装在 D 盘 cd D:\phpstudy_pro\Extensions # 查看当前可用的 PHP 版本目录 ls | grep php逻辑说明上面这两条命令用于确认本地是否具备多版本 PHP 切换能力。如果你用的是集成环境面板通常在「软件管理 - PHP」里直接切换不一定要走命令行。参数说明切换到 PHP 5.6 之后记得在 php.ini 里打开php_mysqli.dll和php_gd2.dll两个扩展GD2 缺失会导致验证码图片不显示。2.2 数据库导入与站点根目录指向源码包解压之后你会看到一个sql文件夹里面是完整的数据库备份。不要直接双击导入先用记事本打开这个.sql文件搜索一下有没有CREATE DATABASE语句。很多老源码里会写死数据库名比如db_order如果你本地的 MySQL 账号没有建库权限导入就会失败。-- 推荐做法先手工建库再导入 CREATE DATABASE IF NOT EXISTS db_order DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE db_order; SOURCE D:/phpstudy_pro/WWW/order/sql/order.sql;逻辑说明先建库再导表的好处是避免导入过程中因为字符集不匹配导致的中文乱码。SOURCE命令是 MySQL 命令行客户端的专用导入指令它比在 phpMyAdmin 里粘贴 SQL 更不容易超时。参数说明DEFAULT CHARACTER SET utf8指定了库的默认字符集如果你的数据库连接串里没有设置charsetutf8那页面查询出来的中文大概率是问号。站点根目录指向是个容易被忽略的细节。这份源码的入口文件是index.php如果直接放在WWW根目录下没有子文件夹那需要把站点根目录指向WWW如果放在WWW/order里那站点根目录要指向order文件夹。常见做法是在站点配置里加一条伪静态规则把非真实文件的请求转发到index.phplocation / { if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?$1 last; } }逻辑说明这段 Nginx 伪静态配置的作用是把美观的 URL如/order/detail/5.html重写成带参数的入口请求同时保证静态文件图片、CSS、JS不被误改写。参数说明$1在重写规则里代表捕获的路径部分如果你的项目部署在子目录需要把/index.php改成/order/index.php这种带前缀的写法。3. 核心业务拆解用户下单、商户接单、配送流转的完整链路3.1 用户端点餐流程购物车到订单提交的代码落点用户端主流程是「选餐厅 - 加购物车 - 确认订单 - 提交支付 - 等待配送」。源码里对应的是index.php?mshopacart这一段。开发者在这个工程里把购物车实现做到了数据库层也就是cart表而不是用 Session 存临时数据好处是换设备不丢购物车坏处是数据库压力大。// 加入购物车的核心逻辑文件位置controller/shop.php public function addCart() { $goods_id intval($_POST[goods_id]); $num intval($_POST[num]); if ($goods_id 0 || $num 0) { $this-json(0, 参数错误); } $goods $this-db-getRow(SELECT * FROM goods WHERE id {$goods_id}); if (!$goods) { $this-json(0, 商品不存在); } $cart_data [ user_id $_SESSION[uid], shop_id $goods[shop_id], goods_id $goods_id, num $num, price $goods[price], add_time time(), ]; $this-db-insert(cart, $cart_data); $this-json(1, 已加入购物车); }逻辑说明这段代码的核心是先做参数合法性校验再验证商品是否存在最后组装数据入库。开发者用intval强制转换来防注入这是一个老 PHP 项目里很典型的防护手法。参数说明$_SESSION[uid]是用户登录后写入 Session 的用户标识如果这个值是空的说明用户没有登录但代码里没有强制跳转而是直接插入一条user_id0的脏数据——这就是一个典型的业务漏洞后面避坑部分会再提。订单提交的代码在controller/order.php里逻辑是读取购物车数据 - 计算总价 - 生成订单号 - 清空购物车。订单号的生成规则很有意思// 订单号生成规则 $order_sn date(YmdHis) . rand(1000, 9999);逻辑说明这个规则是「年月日时分秒 4 位随机数」在并发量不高的场景下基本不会重复。参数说明如果你的业务量一天超过一万单这个规则就可能撞号建议改成date(YmdHis) . mt_rand(10000, 99999)增加随机位数或者直接用uniqid()再拼接一个随机串。3.2 商户端接单与订单状态机商户端的核心是对订单状态的流转控制。这份源码里的订单状态定义很直白1 表示待接单2 表示已接单3 表示配送中4 表示已完成5 表示用户取消。整个状态机用order_status一个字段控制虽然简单但够用。// 商户端接单动作 public function accept() { $order_id intval($_POST[order_id]); $shop_id $_SESSION[shop_id]; $result $this-db-query( UPDATE orders SET order_status 2 WHERE id {$order_id} AND shop_id {$shop_id} ); if ($result) { $this-json(1, 接单成功); } else { $this-json(0, 操作失败); } }逻辑说明这条 UPDATE 语句里带上了shop_id作为条件作用是防止商户 A 操作商户 B 的订单。这是多商户系统里最基本的越权防护代码水平在这个细节上体现得很清楚。参数说明如果你的系统里同一个管理员可以管理多家店那$_SESSION[shop_id]需要改成从门店管理员关联表里去查询否则单店模式改多店时会直接踩坑。订单状态机的流转约束在源码里是靠判断条件做的没有用数据库触发器。比如用户取消订单代码里会检查order_status是否小于 2也就是只能取消待接单的订单// 用户取消订单 if ($order[order_status] 2) { $this-json(0, 商家已接单无法取消); }逻辑说明这个判断的实质是「状态小于 2 才允许取消」也就是在待接单阶段用户有主动反悔的权利一旦商户接单就只能联系商户手动处理。参数说明很多现成的外卖平台把「商户接单后 15 分钟内可无理由取消」作为规则如果你要复刻这种能力需要加一个cancel_deadline时间字段然后在取消判断里加上时间范围校验。3.3 配送员端的定位与订单绑定配送端的功能相对薄主要是查看待配送订单、抢单、送达确认。源码里没有接入地图 API用的是固定的配送范围字段delivery_range单位是公里。这一点很适合新手学习因为你不必处理高德或腾讯地图的鉴权配置。// 计算配送距离是否在范围内 $distance $this-getDistance($shop_lat, $shop_lng, $user_lat, $user_lng); if ($distance $order[delivery_range]) { $this-json(0, 超出配送范围); }逻辑说明getDistance方法内部用的是球面距离公式根据经纬度计算两点之间的距离。这个方案精度在城市级配送范围内够用但不适合做骑行路线规划因为它是直线距离不包含实际道路约束。参数说明经纬度字段在user_address表和shop表里都存在如果导入数据后没有填充坐标这段代码会拿到空值floatval转换后变成 0从而误判所有地址都在范围内。4. 部署与二次开发避坑五个把新手卡住三天的真实问题4.1 数据库连接失败但 MySQL 明明正常运行现象安装完成之后打开首页直接提示Database Connection Failed后台管理面板也打不开。原因这份源码的数据库连接配置文件在config/config.php里里面写死了localhost作为数据库主机地址。在 PHP 5.6 时代localhost走的是 MySQL 的 socket 连接而在新版 MySQL 8.0 默认是 TCP 连接Socket 路径对不上就报连接失败。解决把主机地址从localhost改成127.0.0.1同时确认配置里的端口和你的 MySQL 实际端口一致默认 3306。改完之后重启一下 PHP 服务再刷新页面。注意改config.php后不要只刷新浏览器必须重启 PHP 服务让配置重新加载否则你改的东西可能没生效。4.2 首页能开但验证码图片不显示现象登录页面加载出来了输入框和按钮都在但验证码图片的位置是一个裂开的图标。原因验证码生成依赖 GD 库这个库不是 PHP 默认启用的。在 PHPStudy 里PHP 5.6 版本的 GD 库默认可能是关闭状态需要在扩展配置里手动勾选php_gd2.dll。还有一种可能是源码里调用的是imagecreate()函数这函数在 GD 库低版本里存在但在某些编译版本里被废弃返回false。解决先在php.ini里确认extensionphp_gd2.dll是否开启然后写一个临时 PHP 文件执行?php phpinfo(); ?搜索GD Support看是否为enabled。如果已经是enabled但图片还是不显示检查验证码类文件通常在include/validate_code.php里输出的 header 头是不是在 HTML 内容输出之后才设置如果是那就把header(Content-Type:image/png)前面的所有空格和换行删掉。4.3 购物车能加入但提交订单时报「非法请求」现象用户选择商品加入购物车没有问题购物车列表也正常但点击「去结算」按钮之后跳转到一个错误页提示「非法请求」。原因源码为了防跨站请求伪造在表单里埋了一个token字段。这个 token 在生成订单时会被后端校验。如果你的站点配置了伪静态而index.php在获取 POST 参数时用了$_REQUEST那么 token 会在 URL 重写过程中被吞掉。解决找到订单提交的方法把取参方式从$_REQUEST[token]改成$_POST[token]。同时检查模板里的表单是否真的把token字段渲染出来了如果没有在提交按钮前加一个input typehidden nametoken value?php echo $_SESSION[token]; ?。4.4 管理员后台登录后跳回登录页现象输入管理员账号密码提示登录成功页面跳转到后台地址但马上又跳回登录页Session 里存的值全部丢失。原因这是典型的 Session 路径配置问题。当站点根目录和 PHP 的 session 保存路径不一致时PHP 创建的 Session 文件在另一个目录而你的代码判断 Session 存在与否用的目录和它不是一个所以每次刷新都像第一次访问。解决在config.php里增加一行session_save_path(/tmp);并确认该目录有可写权限。如果是 Windows 环境改成绝对路径比如session_save_path(D:/phpstudy_pro/Extensions/tmp);配置完重启 PHP。4.5 上传的菜品图片在商家后台不显示现象商户后台上传菜品图片成功预览时图片裂开查看图片文件确实存在于upload/goods/目录下但前端页面访问 404。原因这份源码的图片上传功能是普通的上传接口没有做防盗链和路径鉴权。如果你把站点部署在二级目录比如http://localhost/order/而数据库里存的图片路径是/upload/goods/xxx.jpg那页面访问时会从根目录去寻址自然找不到。解决把所有图片字段的存储路径改成相对路径去掉最前面的斜杠也就是存upload/goods/xxx.jpg而不是/upload/goods/xxx.jpg。改完数据库之后记得检查config.php里是否定义了UPLOAD_PATH常量如果有把它改成一个不带前导斜杠的相对路径。提示这个问题在源码自带的数据里尤其明显因为作者开发时是在根目录跑的一换环境就暴露。5. 从「跑起来」到「能用起来」三个必须做的二次开发动作5.1 把订单号从「时间随机数」升级为「业务前缀 日期 自增 ID」源码里的订单号规则date(YmdHis) . rand(1000, 9999)在小规模内测时问题不大但如果你准备拿这套源码给真实商户做演示建议改成带前缀的模式。常见做法是增加一个order_sn_prefix配置项在生成订单号时拼接业务类型和来源渠道。// 改造方案订单号 前缀 日期 当天自增序号 $prefix date(Ymd); $today_count $this-db-getOne(SELECT COUNT(*) FROM orders WHERE order_sn LIKE {$prefix}%); $order_sn $prefix . str_pad($today_count 1, 6, 0, STR_PAD_LEFT);逻辑说明这个方案的核心是用数据库查询当天已有订单数来生成序号严格说查出来之后到插入之间有一个极小的时间窗口理论上并发时可能撞号但实际业务场景单店日单量几百基本不会触发。参数说明如果你追求绝对唯一可以改成uniqid($prefix, true)这样生成的是一个带前缀和时间戳的组合串可读性差一点但绝对不重复。5.2 给商家后台补一个「营业开关」源码里商户端没有「开始营业 / 停止营业」的控制商家只要登录后台店铺在前台就一直展示。这在真实运营场景里很致命尤其是商家休息、爆单或临时外出时。-- 给 shop 表增加营业状态字段 ALTER TABLE shop ADD COLUMN is_open TINYINT(1) NOT NULL DEFAULT 1 COMMENT 1营业 0休息;// 前端餐厅列表查询时过滤掉休息店铺 $where AND is_open 1 ; $shop_list $this-db-getAll(SELECT * FROM shop WHERE 11 {$where} ORDER BY id DESC);逻辑说明这是一个典型的最小侵入改造只需加一个字段然后在查询列表处拼一个条件。商户后台的开关按钮可以复用现有的shop编辑功能加一个复选框即可。参数说明默认值设为 1 是为了兼容老数据让已有的店铺不用手动开启也能正常展示如果你希望新上线的店铺必须手动开店那就把默认值改成 0。5.3 配送费计算从固定运费升级为距离动态计价源码里的配送费是餐厅自己在后台填写的固定值用户下单时不管距离远近都是同一个价格。真实场景里超出基础距离应该加价。改造思路是在shop表增加两个字段base_distance基础公里数和base_fee基础配送费外加一个per_km_fee超出每公里加收费用然后在订单金额计算时插入一段运费计算函数。// 动态配送费计算示例 function calc_delivery_fee($distance, $shop) { if ($distance 0) return 0; $base_distance floatval($shop[base_distance]); $base_fee floatval($shop[base_fee]); $per_km_fee floatval($shop[per_km_fee]); if ($distance $base_distance) { return $base_fee; } $extra_km ceil($distance - $base_distance); return $base_fee $extra_km * $per_km_fee; }逻辑说明ceil向上取整的用法很关键因为配送距离为 2.1 公里时超出 1 公里的部分是 1.1 公里按 2 公里算加价这是外卖行业通用的计费方式避免出现 0.1 公里的零头。参数说明$shop数组里必须包含base_distance、base_fee、per_km_fee三个字段如果数据库还没加这些字段就直接调用PHP 会返回一个undefined index的警告所以务必先执行上面的 ALTER 语句。5.4 生产环境上线前强制检查这三个配置源码里的config.php在开发阶段为了方便很多调试输出是开着的。上线前我会强制把DEBUG常量改成false把数据库连接的错误提示关掉不然 SQL 语句会明文渲染到页面上等于把数据库结构直接暴露给用户。另一个检查点是后台的默认管理员密码。源码安装包里一般会有初始账号上线前必须第一步就把它改掉不然网站等于裸奔。改的方式是直接编辑数据库表里的admin字段用 MD5 加密后的新密码覆盖。最后一个容易被忽略的是upload目录的写入权限。如果你把代码部署在 Linux 服务器上upload/goods/这个目录需要给到 755 权限而且所有者必须是 PHP 运行用户通常是www或nobody。如果权限低一档商家上传图片时就会报「目录不可写」排查下来最容易卡人的就是这个。从那以后我每接手一套 PHP 源码往生产环境放都会强制走一遍「配置检查 - 密码重置 - 目录权限」三步不是不信任源码而是老项目里的默认值太容易被忽略了。希望这份外卖点餐源码能让你少走几段弯路把时间花在真正有技术含量的事情上。本文还有配套的精品资源点击获取