ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

PHP景区旅游小程序源码部署到联调:从环境搭建到微信支付避坑指南

PHP景区旅游小程序源码部署到联调:从环境搭建到微信支付避坑指南 简介面向景区在线服务场景的PHP旅游小程序源码包含预订、导航、信息查询与微信端能力集成适合中小型旅游业务开发者、PHP学习者研究前后端交互与小程序接口实现。包内共1952个文件以1186个php文件为主辅以136个phpt测试脚本、114个png图片、51个json配置、51个html页面、34个wxss与33个wxml小程序样式/结构文件以及yml、js、md等类型整体27.88MB。已有668人学习下载。这套代码可从中看到PHP在框架应用、数据库交互、接口设计、支付对接、安全防护等方面的实际写法并包含清晰的目录结构与文档注释可帮助读者快速理解真实旅游业务中的落地方式也可作为二次开发基础学习从需求分析到部署运维的完整路径。1. 从 .rar 到能跑通的景区小程序这包 PHP 源码到底解决了什么问题当你手里拿到这份 PHP经典源码-景区旅游小程序 V3.4.5.rar多半是要给一个景区项目做小程序。类似源码包在国内交付里很常见PHP 后端提供接口微信小程序端负责展示和下单SQL 文件初始化数据表解压后改配置就能跑。它解决的不只是线上卖门票还包括景区介绍、线路推荐、订单查询这些基础运营需求。适合三类人一是预算有限的中小景区不想为小程序单独养一个 Java 技术栈二是接单的外包开发者需要快速交付后再迭代三是想学小程序后端联调的学生和初级工程师。我的建议是先把它部署起来再读代码别一上来就研究目录结构否则很容易陷在旧框架的细节里。2. 先把压缩包变成能跑的项目环境选型、解压、数据库导入的三个关键动作2.1 用 PHP 7.4 MySQL 5.7 跑老源码能避开一半的幺蛾子V3.4.5 这个版本号一听就不是新东西它内部大概率还带着 ThinkPHP 5 或老 CI 的写法。这类源码对运行环境非常挑剔PHP 7.4 是最舒适区PHP 8.0 以上会开始报 deprecation某些函数直接被移除可能连登录接口都挂。MySQL 5.7 则能兼容老式 GROUP BY 和表引擎MySQL 8 默认的 sql_mode 更严格导 SQL 时容易卡在一条明确报错。所以不管是本机用 phpStudy/XAMPP还是服务器用宝塔或 LNMP我都先把版本锁在 PHP 7.4、MySQL 5.7 上。这套组合的好处是既能跑老代码又能装 Composer 依赖不至于完全黑匣子化。还有一点容易被忽略项目根目录里是否有 composer.json。如果有说明它依赖第三方包解压后需要执行 composer install否则访问到某些类时会 500。老 Package 通常把依赖放在 vendor/ 目录一并发给你那就不需要跑但为了保险我会先用文件搜索确认 vendor/autoload.php 是否存在。集成环境的 php.ini 也要打开 extensionmysqli 和 extensioncurl后面请求微信接口和连数据库都要用。组件建议版本原因PHP7.4兼容老框架又没有 PHP 8 的破坏性变更MySQL5.7sql_mode 宽容老 SQL 导入更稳Web 服务器Nginx 或 Apache看你想用哪种伪静态规则缓存文件或 Redis老源码默认文件缓存先保持默认这张表是基线不是必须。如果你已经有 PHP 8 环境也可以先跑起来遇到废弃函数报错再逐个处理但那样会浪费大量时间。2.2 解压、放目录、配伪静态把隐藏的入口找出来解压这一步有个坑很多 rar 包内层还套着项目文件夹。解压后先进目录找到 index.php、application 或 app 这一层作为项目根目录。如果直接放在 WWW 根目录访问时会出现两个项目路径。常见做法是新建一个 scenic 目录把解压内容放进去。放在根目录还是子目录决定你后面小程序 baseUrl 怎么写。server { listen 80; server_name scenic.demo.com; root /var/www/scenic/public; # 入口在 public 时用这个入口在根目录就去掉 /public index index.php index.html; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } } location ~ \.php$ { include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }TP5/Laravel 的入口在 public所以 root 指向 public老 TP3 或 CI 入口在根目录root 直接指向项目目录。怎么判断看根目录有没有 public 文件夹以及 index.php 是不是在根目录。伪静态规则的作用是让 URL 里不用出现 index.php?s小程序端请求更干净也避免某些路径被 Web 服务器当成真实文件去处理。Apache 则是在项目根目录放 .htaccessIfModule mod_rewrite.c RewriteEngine On Options FollowSymlinks RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php?s/$1 [QSA,PT,L] /IfModule配完重启 Web 服务器测试首页。如果还是 404优先查 root 和 pathinfo 支持。Nginx 里一般还要在 php location 中加fastcgi_param PATH_INFO $path_info;否则部分框架解析不了 URL。2.3 数据库导入与 config 修改改这几个参数前先抄下原值数据库是整个小程序的地基景区、门票、订单、用户全在库里。源码包里一般有一个 .sql 文件文件名常见为 scenic.sql、db.sql 或 install.sql。导入前先建库编码用 utf8mb4否则小程序端存不了用户昵称里的 emoji。mysql -uroot -p -e CREATE DATABASE scenic DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -uroot -p scenic /path/to/scenic.sql如果 SQL 文件里自带 CREATE DATABASE 语句建议你先打开文件把这段注释掉或改成自己要的库名避免导入时因为库已存在或字符集不一致而中断。导入完成后用SHOW TABLES;看有没有生成表至少要有 sp_admin、sp_scenic、sp_ticket、sp_order 这类表。缺表说明 SQL 导入不完整回去看屏幕上的报错。// application/database.php 对应 TP5 的配置写法 return [ type mysql, hostname 127.0.0.1, database scenic, username root, password 你的密码, hostport 3306, charset utf8mb4, prefix sp_, // 注意和 SQL 里的实际表前缀一致 ];改配置前先记录原始 hostname可能是 localhost 也可能是 127.0.0.1如果用 localhost 连不上就换成 127.0.0.1。prefix 很关键如果 SQL 里的表名是 sky_scenic而你配成 sp_系统会到处找 sp_scenic 然后报表不存在。还有一处常改的是 config.php 里的 url_domain 或 base_url它影响小程序端拼图片地址。调试时把 debug 开关打开出错能看到具体文件和行号。3. 小程序端和 PHP 接口是如何对接的从 baseUrl 到订单的一段完整请求链3.1 先找小程序端的 baseUrl接口地址一旦写错后面全是数据加载失败我拿到这种源码包一般先不读后端而是打开小程序端搜 wx.request。所有请求都指向一个公共变量通常叫 baseUrl 或 apiUrl。它在 app.js 的 globalData 里也可能在 utils/config.js 或 common/config.js。这个值决定小程序向谁要数据。// app.js 中常见的全局配置 App({ globalData: { baseUrl: http://localhost/scenic/index.php, tokenKey: scenic_token, version: v3.4.5 } })本地调试时填 ip项目路径真机预览填电脑的局域网 IP上线后填 https 域名。如果填错了最典型的现象是小程序页面一片空白、控制台出现 request:fail。还有源码里可能把 baseUrl 写死成 http://demo.xxx.com要全局搜索替换。替换后别漏了 URL 里的 index.php它对应 PHP 入口文件很多老框架不能直接去掉。小程序端还有 app.json 里的 pages 数组它能帮你确认有哪些页面。比如页面列表里有 pages/index/index、pages/order/list、pages/pay/pay对应景区首页、订单列表、支付页。后端接口则按 module/controller/action 组织。理解了对应关系你就清楚改哪个文件了。3.2 wx.login 换 openid为什么后台要自己发一个 token小程序的登录不是一个简单的表单提交。用户打开小程序wx.login 会拿到一个临时 code这个 code 只有几分钟有效小程序端不能拿它直接当身份标识。常见做法是后端拿 code 去微信的 jscode2session 接口换 openid然后自己生成一个 token 返回给小程序后续请求通过 header 带 token 识别用户。public function login() { $code input(code); if (!$code) return json([code 1, msg code不能为空]); $appid 你的小程序appid; $secret 你的小程序secret; $url https://api.weixin.qq.com/sns/jscode2session?appid{$appid}secret{$secret}js_code{$code}grant_typeauthorization_code; $res file_get_contents($url); $data json_decode($res, true); if (!isset($data[openid])) { return json([code 1, msg 登录失败请检查appid/secret]); } $token md5($data[openid] . time() . mt_rand(1000, 9999)); cache(token_ . $token, $data[openid], 7200); return json([code 0, data [token $token]]); }参数固定是 appid、secret、js_code、grant_typeauthorization_code。如果返回 errcode最常见的是 40029 code 无效说明 code 使用了两次或已过期而 40164 说明服务器 IP 不在微信后台白名单。token 的过期时间我一般设 7200 秒和微信 session_key 生命周期对齐。不要直接传 session_key 给前端后续要解手机号时后端再缓存它。3.3 统一返回 JSONcode 是 0 才算成功别放调试输出看多了这类源码会发现接口返回值基本是同一个模板code 存业务状态、msg 存提示、data 存数据。小程序端判断成功不是看 HTTP 状态而是看 code 是否为 0。所以后端控制器里每个接口都要这么返回。public function lists() { $list Db::name(scenic)-where(status, 1)-select(); return json([ code 0, msg ok, data $list, ]); }如果用 TP5 的 json 返回它会自动设置 Content-Type。但如果控制器里有 var_dump、echo、print_r或配置文件里打开了调试输出返回的字符串就不是合法 JSON小程序端 res.data 会变成字符串而不是对象页面渲染不出来。开发时可以在 PHP 入口文件加一行 catch把异常统一转成 JSON能省不少事。上线前再关闭 debug。小程序端的错误处理也有讲究遇到 code!0 时只用 wx.showToast 提示不要 console.log 一堆。这样二开时即使后台报错也不会把调试信息暴露给真实用户。4. 门票库存、订单与支付参数四个必须调对的核心位置4.1 按日期扣库存ticket_stock 才是库存表order 不是景区旅游小程序和商城小程序的本质区别在库存维度。商城只关心 sku 库存景区还得关心哪天有票、哪天已约满。所以这类源码会单独建一张库存表按日期存可售数量而不是在订单表里减库存。CREATE TABLE sp_ticket ( id int(11) NOT NULL AUTO_INCREMENT, scenic_id int(11) NOT NULL COMMENT 景区ID, name varchar(100) NOT NULL COMMENT 票种名称, price decimal(10,2) NOT NULL COMMENT 原价, stock int(11) NOT NULL DEFAULT 0 COMMENT 总库存, sale_status tinyint(1) NOT NULL DEFAULT 1 COMMENT 1上架 0下架, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE sp_ticket_stock ( id int(11) NOT NULL AUTO_INCREMENT, ticket_id int(11) NOT NULL, stock_date date NOT NULL COMMENT 游玩日期, stock int(11) NOT NULL DEFAULT 0 COMMENT 当日可售库存, sold int(11) NOT NULL DEFAULT 0 COMMENT 已售, PRIMARY KEY (id), UNIQUE KEY uk_ticket_date (ticket_id,stock_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;为什么单独用日期维度的库存表而不是在 ticket 表里放一个总库存因为景区票务按天控库存比如节假日单独限流。下单时对 sku 加锁更新 t_sold 字段这个动作要放在事务里Db::startTrans(); try { // 锁住当天库存行 $stock Db::name(ticket_stock) -where(ticket_id, $ticketId) -where(stock_date, $date) -lock(true) -find(); if (!$stock || $stock[stock] - $stock[sold] $quantity) { throw new \Exception(库存不足); } Db::name(ticket_stock) -where(id, $stock[id]) -setInc(sold, $quantity); // 写订单 Db::name(order)-insert($orderData); Db::commit(); } catch (\Exception $e) { Db::rollback(); return json([code 1, msg $e-getMessage()]); }lock(true) 是行级锁防止两个用户同时买到最后一张票。不要用“先 select 再 update”的无锁方式高并发会超卖。这是整个景区票务最值钱的一段代码。二开时有人图省事在 order 表里直接 tick 字段一旦接入多个售票渠道对账就乱。4.2 微信支付参数金额用“分”回调地址必须是公网 HTTPS支付配置通常在 application/config.php 或 wxpay.php 里老源码大概率还在用微信支付 v2 的 API 证书。参数从哪里拿作用appid小程序后台标识小程序mch_id微信商户平台商户号key商户平台设置签名密钥32位apiclient_cert.pem / apiclient_key.pem商户平台 API 证书退款、撤销等操作notify_url自己配置支付结果通知地址$config [ appid wx1234567890, mch_id 1500000000, key 你的商户密钥, notify_url https://api.yourdomain.com/index.php?/api/order/notify, ]; $order [ out_trade_no date(YmdHis) . mt_rand(1000, 9999), total_fee intval($realPrice * 100), body 景区门票, ]; $wxPay new \WechatPay($config); $payParams $wxPay-unifiedOrder($order); return json([code 0, data $payParams]);total_fee 单位是分必须转成整数。PHP 浮点计算 0.10.2 会出精度问题所以算价用分比如 99.9 * 100 再 intval或者用 BCMath 扩展。回调通知地址必须是公网 HTTPS微信支付会主动 POST 订单结果到 notify_url回调里验签成功后要返回xmlreturn_code![CDATA[SUCCESS]]/return_code/xml否则微信会重试。4.3 未支付订单超时用 cron 脚本把票放回去用户下单后不付款库存一直占着后面的游客买不到所以必须设计超时关单。老源码很多没做这步上线后容易在节假日爆库存。我的习惯是让 PHP 脚本每分钟扫一次超过 15 分钟未付款的订单置为已取消再回滚库存。*/5 * * * * /usr/bin/php /var/www/scenic/index.php /api/cron/closeExpireOrder /log/order_close.log 21脚本要加幂等条件比如只处理 status0 且 create_time NOW() - INTERVAL 15 MINUTE 的订单更新时带上 status0 条件防止并发重复执行。crontab 里路径要用绝对路径如果用的是 tp5 命令可以单独写 command 类而不是走 HTTP 接口避免接口被外部触发。5. 部署与联调避坑白屏、域名校验、支付签名失败的 5 条血泪经验5.1 白屏 500八成是 PHP 版本把函数删了现象访问首页或接口时白屏PHP 日志报Call to undefined function mcrypt_create_iv()或mysql_connect()。原因PHP 8 移除了 php 7 时的 mcrypt 和 ext/mysql 扩展老源码没做兼容。解决切换到 PHP 7.4不想切环境就全局搜代码把 mcrypt_create_iv 换成 openssl_random_pseudo_bytes 或 random_bytes。这类问题不是改一行配置能解决的别在一个函数上死磕。5.2 小程序里请求“不是合法域名”本地调试和正式环境是两套逻辑现象微信开发者工具里所有请求报url not in domain list。原因小程序正式环境只允许请求已经配置到后台的合法 HTTPS 域名而本地是 http://localhost根本不在列表。解决本地调试时在开发者工具右上角详情里勾选“不校验合法域名”上线前把 PHP 接口绑到已备案的 HTTPS 域名并在小程序后台把该域名加入 request 合法域名最多配置 20 个。这两个逻辑要分清本地能跑不代表生产环境能跑。5.3 支付回调验签失败先检查字符编码和 key 的顺序现象支付成功后订单状态不变后台日志显示验签失败。原因签名原串使用转义后的 HTML 实体或 GBK 编码参数没有按 ASCII 排序商户 key 填错。解决先打开日志输出签名原串与微信支付文档的示例对比。注意total_fee不能带小数点不会用复杂库时建议直接用微信官方 SDK。验签逻辑跑通后再测一遍退款因为退款还要用到 API 证书。5.4 图片上传后小程序显示 /uploads 路径打开是 404现象后台能传图片小程序里图片框裂开地址显示/uploads/xxx.jpg。原因上传接口只返回了相对路径前端没有域名前缀或者上传目录没有写入权限文件根本没落盘。解决统一在接口返回前拼接完整域名比如https://yourdomain.com/uploads/xxx.jpg检查 uploads/ 目录权限PHP-FPM 用户需要可写一般 chmod -R 755 属主 www-data。改完记得重跑一次上传看服务器上是否真的有文件。5.5 登录态反复失效token 存缓存别赖 cookie现象小程序每次重进都要求重新登录后台明明发了 token。原因老源码可能依赖 PHP session小程序端不持有 cookie二次请求 session_id 对不上。解决改成 token 机制登录后把 openid 存到 cache/redis小程序每次请求在 header 里带Authorization: Bearer token后端用 token 查用户$token Request::header(token); $openid cache(token_ . $token); if (!$openid) { return json([code 401, msg 登录已过期]); }这句话放到控制器基类的初始化方法里所有需要登录的接口都会自动生效。如果还是反复失效看一下 cache 用的什么驱动老源码默认文件缓存可能因为 runtime 目录没写权限而每次生成空缓存。6. 上线前的最后检查跑通一条订单闭环再交付最后一步不是写代码而是验证。我会在微信开发者工具和真机上各跑一遍完整流程首页加载景区列表 → 选择一个门票 → 提交订单 → 调起微信支付 → 支付成功回跳 → 在后台看到订单状态变更。接口日志确认每步请求的 code0响应时间低于 500ms。支付回调到微信商户平台“交易记录”看是否成功并在 PHP 日志确认 notify 被调用。数据库订单表 status 变成 1ticket_stock 的 sold 1。取消流程人工把订单置为超时确认库存回滚。这四个验证点缺一不可。二开时如果只想改某个页面先看控制器和视图的目录结构不要动框架核心文件。比如要改首页景点排序去 api/Scenic 控制器里找 order(sort desc)改字段名和排序规则即可。样式上的主题色在 app.wxss 里全局搜索 #1296db替换成景区品牌色。功能上要接新的电子票务系统重点改库存扣减处把它改成调用外部库存服务的接口事务不要跨系统。提示上线前把 config.php 中 app_debug 改为 false并把 PHP display_errors 关闭。否则一旦有报错会给用户直接输出完整路径甚至数据库密码。最后说个习惯我接手这类源码时会先复制一份原始压缩包再在代码里标注所有改动点。景区票务直接涉及钱和库存出了问题要有后悔药。遇到不明变量先全局搜索不要猜改库存逻辑一定走事务调试时多看两个日志比如 PHP 的错误日志和微信开发者工具的 Network 面板它们比控制台 print_r 靠谱。希望帮到你。本文还有配套的精品资源点击获取
返回列表