轉(zhuǎn)閑魚源碼:PHP二手交易平臺獨(dú)立后臺開發(fā)與部署實(shí)戰(zhàn))
簡介這是一套基于PHP開發(fā)的二手商品交易平臺網(wǎng)站源碼仿照58轉(zhuǎn)轉(zhuǎn)、閑魚等平臺的設(shè)計(jì)風(fēng)格附帶獨(dú)立后臺管理系統(tǒng)適合有一定PHP與MySQL基礎(chǔ)的開發(fā)者用于學(xué)習(xí)電商交易系統(tǒng)的完整實(shí)現(xiàn)。壓縮包共約2000個(gè)文件整體47.71MB其中144個(gè)php文件承載核心業(yè)務(wù)邏輯448個(gè)js與130個(gè)css、72個(gè)html構(gòu)成前后端交互與頁面布局另有542個(gè)png、194個(gè)jpg等圖片資源及2個(gè)sql數(shù)據(jù)庫腳本便于快速還原站點(diǎn)。源碼覆蓋商品發(fā)布與管理、支付接口集成、首頁展示與搜索、用戶與訂單管理等模塊后臺支持權(quán)限控制與數(shù)據(jù)統(tǒng)計(jì)可幫助讀者理解PHP與數(shù)據(jù)庫的CRUD交互、第三方支付API調(diào)用與回調(diào)處理以及前端響應(yīng)式布局和SEO優(yōu)化思路。目前已有2708人學(xué)習(xí)下載適合作為PHP Web開發(fā)、數(shù)據(jù)庫操作與后臺管理設(shè)計(jì)的綜合實(shí)踐參考使用前需自行配置支付接口并按需定制。1. 二手交易平臺源碼選型為什么 PHP 獨(dú)立后臺仍是中小團(tuán)隊(duì)的首選聊到二手商品交易平臺很多人第一反應(yīng)是「現(xiàn)在做這個(gè)還有機(jī)會(huì)嗎」。我去年幫一個(gè)做本地校園二手的小團(tuán)隊(duì)落地過一套 PHP 源碼從部署到跑通交易閉環(huán)大概用了兩周日活做到三千左右時(shí)單臺 4 核 8G 的機(jī)器還扛得住。這套「仿 58 轉(zhuǎn)轉(zhuǎn)閑魚源碼」本質(zhì)上是一個(gè)帶獨(dú)立后臺管理的 PHP 二手交易平臺系統(tǒng)前端覆蓋商品發(fā)布、搜索、下單、聊天后端覆蓋用戶、訂單、結(jié)算、內(nèi)容審核。它解決的核心問題是你不需要從零寫一套交易系統(tǒng)拿到源碼后改改配置、換換模板就能上線一個(gè)垂直品類的二手平臺。適合誰適合做本地化、垂直品類母嬰、數(shù)碼、圖書、潮玩的中小團(tuán)隊(duì)或者想快速驗(yàn)證一個(gè)二手交易想法的人。不適合誰不適合想直接對標(biāo)閑魚全品類體量、需要億級并發(fā)架構(gòu)的團(tuán)隊(duì)PHP 單體架構(gòu)在這個(gè)量級會(huì)先撞到數(shù)據(jù)庫瓶頸。2. 仿 58 轉(zhuǎn)轉(zhuǎn)閑魚源碼的技術(shù)棧拆解與選型理由2.1 一套典型 PHP 二手交易源碼里到底有什么拿到一套「仿 58 轉(zhuǎn)轉(zhuǎn)閑魚源碼」先別急著裝。我一般會(huì)花半小時(shí)把目錄結(jié)構(gòu)和依賴摸清楚因?yàn)椴煌瑏碓吹脑创a在分層上差異很大。典型結(jié)構(gòu)大致是這樣application/放業(yè)務(wù)邏輯用戶、商品、訂單、支付、消息public/是入口和靜態(tài)資源config/放數(shù)據(jù)庫和第三方密鑰extend/放支付、短信、推送的 SDKruntime/是緩存和日志。數(shù)據(jù)庫一般分幾十張表核心是user、goods、order、order_item、chat_message、wallet_log、admin_user。選型上要盯三件事。第一框架版本。ThinkPHP 5.x 和 6.x 的寫法差異不小5.x 里Db::name()和 6.x 的查詢構(gòu)造器在鏈?zhǔn)秸{(diào)用上有區(qū)別改代碼前先確認(rèn)版本否則你照著 6.x 文檔改 5.x 項(xiàng)目會(huì)一直報(bào)方法不存在。第二PHP 版本。源碼如果寫的是 PHP 7.2你直接上 PHP 8.1 大概率會(huì)碰到each()已移除、create_function廢棄這類致命錯(cuò)誤。第三擴(kuò)展依賴。二手交易平臺幾乎必然用到fileinfo圖片類型校驗(yàn)、redis會(huì)話和隊(duì)列、gd或imagick縮略圖、openssl支付簽名。缺一個(gè)后臺可能白屏但日志里只寫一句「Class not found」。提示先跑php -m看擴(kuò)展再跑composer check-platform-reqs如果項(xiàng)目帶 composer.json比裝完再排錯(cuò)省事得多。2.2 獨(dú)立后臺管理和前臺為什么要分開部署「獨(dú)立后臺管理」是這套源碼的一個(gè)賣點(diǎn)但很多人把它理解成「后臺只是多幾個(gè)菜單」。實(shí)際落地時(shí)獨(dú)立后臺的價(jià)值在于權(quán)限隔離和部署隔離。前臺面向公網(wǎng)、允許匿名訪問、要扛住爬蟲和刷接口后臺只對運(yùn)營開放、必須登錄、最好再套一層 IP 白名單或獨(dú)立域名。我一般會(huì)把后臺單獨(dú)綁一個(gè)子域名比如admin.xxx.comNginx 里單獨(dú)配 server 塊和前臺共用同一套數(shù)據(jù)庫但走不同的入口文件。這樣做的好處是后臺被爆破時(shí)不會(huì)直接影響前臺可用性后臺的慢查詢比如導(dǎo)出全量訂單不會(huì)拖垮前臺接口后續(xù)給運(yùn)營加權(quán)限、加操作日志改動(dòng)范圍可控。代價(jià)是要維護(hù)兩套入口配置部署腳本里得寫清楚哪個(gè)目錄對應(yīng)哪個(gè)域名。如果團(tuán)隊(duì)只有一兩個(gè)人也可以先合并部署但至少要在應(yīng)用層做角色校驗(yàn)別讓普通用戶 token 能調(diào)后臺接口——這是我在真實(shí)項(xiàng)目里見過最多的翻車點(diǎn)前臺登錄態(tài)和后臺登錄態(tài)用了同一個(gè) session key結(jié)果普通用戶改個(gè) cookie 就能進(jìn)后臺。2.3 環(huán)境準(zhǔn)備從零到能打開安裝頁的最小步驟下面這套命令是我在 Ubuntu 22.04 上反復(fù)用過的PHP 7.4 MySQL 5.7 Redis Nginx。PHP 7.4 是因?yàn)槎鄶?shù)這類源碼在這個(gè)版本上兼容性最好PHP 8 的坑后面避坑章節(jié)會(huì)講。# 1. 裝 PHP 7.4 及二手交易平臺常用擴(kuò)展 sudo apt install -y php7.4-fpm php7.4-mysql php7.4-redis \ php7.4-gd php7.4-mbstring php7.4-curl php7.4-xml \ php7.4-fileinfo php7.4-openssl php7.4-zip # 2. 裝 MySQL 5.7 和 Redis sudo apt install -y mysql-server-5.7 redis-server # 3. 建庫字符集必須 utf8mb4否則 emoji 和部分生僻字會(huì)亂碼 mysql -uroot -p -e CREATE DATABASE ershou DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 4. 拉代碼目錄權(quán)限給 www-data cd /var/www git clone 你的源碼地址 ershou sudo chown -R www-data:www-data /var/www/ershou sudo chmod -R 755 /var/www/ershou sudo chmod -R 777 /var/www/ershou/runtime /var/www/ershou/public/uploads邏輯說明前三步把運(yùn)行環(huán)境鋪好第四步的關(guān)鍵是runtime和uploads必須可寫否則安裝頁會(huì)卡在「目錄不可寫」或者上傳商品圖直接 500。參數(shù)上utf8mb4不能省二手平臺商品標(biāo)題里 emoji 很常見用utf8存進(jìn)去會(huì)變成問號。chmod 777只給這兩個(gè)目錄別圖省事給整個(gè)項(xiàng)目 777那是給后面留后門。2.4 安裝向?qū)c數(shù)據(jù)庫初始化三個(gè)必須核對的參數(shù)瀏覽器打開http://你的域名/install后安裝向?qū)б话銜?huì)讓你填數(shù)據(jù)庫地址、庫名、賬號密碼、管理員賬號。這里有三個(gè)參數(shù)最容易填錯(cuò)。第一數(shù)據(jù)庫主機(jī)。如果 MySQL 和 PHP 在同一臺機(jī)器填127.0.0.1而不是localhost因?yàn)閘ocalhost會(huì)走 socket而 PHP-FPM 的 socket 路徑可能和 MySQL 默認(rèn)路徑不一致報(bào)「Connection refused」時(shí)你會(huì)以為是密碼錯(cuò)。第二表前綴。源碼默認(rèn)可能是tp_或eb_如果你之前裝過一次沒清庫第二次裝會(huì)因表已存在而失敗裝之前先DROP DATABASE重建。第三管理員密碼。安裝向?qū)傻墓芾韱T賬號密碼要立刻改掉很多源碼的默認(rèn)后臺路徑是/admin或/manage默認(rèn)賬號是admin/123456不改等于把后臺掛在公網(wǎng)上裸奔。裝完后先別急著配支付。我一般會(huì)先跑一遍最小閉環(huán)注冊一個(gè)普通用戶 → 發(fā)布一件商品 → 用另一個(gè)賬號下單 → 后臺看到訂單。這一步能過說明數(shù)據(jù)庫、路由、模板、權(quán)限基本通了再去接支付和短信排錯(cuò)范圍小很多。3. 商品發(fā)布、訂單與錢包二手交易閉環(huán)的核心代碼怎么改3.1 商品發(fā)布接口圖片上傳和敏感詞過濾商品發(fā)布是二手平臺最高頻的寫操作也是最容易出問題的地方。核心邏輯是接收表單 → 校驗(yàn)參數(shù) → 處理圖片 → 敏感詞過濾 → 寫庫。下面這段是 ThinkPHP 風(fēng)格的發(fā)布邏輯我做了簡化但保留了關(guān)鍵校驗(yàn)。public function publish() { $data input(post.); // 必填校驗(yàn)標(biāo)題、價(jià)格、分類、至少一張圖 $validate $this-validate($data, [ title require|max:60, price require|float|egt:0, cat_id require|number, ]); if (true ! $validate) { return json([code 400, msg $validate]); } // 圖片處理限制數(shù)量、大小、真實(shí)類型 $images []; foreach ($_FILES[images][tmp_name] as $k $tmp) { if ($_FILES[images][size][$k] 5 * 1024 * 1024) { return json([code 400, msg 單圖不能超過5M]); } $info getimagesize($tmp); // 用真實(shí)內(nèi)容判斷類型別信擴(kuò)展名 if (!$info || !in_array($info[2], [IMAGETYPE_JPEG, IMAGETYPE_PNG])) { return json([code 400, msg 只支持 JPG/PNG]); } $images[] $this-saveImage($tmp); } // 敏感詞過濾詞庫放 Redis 里避免每次查庫 $badWords Redis::sMembers(bad_words); foreach ($badWords as $w) { if (mb_strpos($data[title], $w) ! false) { return json([code 400, msg 標(biāo)題含違規(guī)詞]); } } $data[images] json_encode($images); $data[user_id] $this-uid; $data[status] 1; // 1待審核 $data[create_at] time(); Db::name(goods)-insert($data); return json([code 0, msg 發(fā)布成功等待審核]); }邏輯說明先做參數(shù)校驗(yàn)再做圖片校驗(yàn)最后做內(nèi)容過濾順序不能反——先過濾再校驗(yàn)圖片用戶傳個(gè)超大圖就把敏感詞邏輯白跑了。參數(shù)上5 * 1024 * 1024是單圖上限二手平臺用戶常傳手機(jī)原圖動(dòng)輒 8M 以上前端最好先壓縮再傳。getimagesize比看擴(kuò)展名可靠改后綴的偽裝文件在這里會(huì)被攔下。敏感詞放 Redis 的 Set 里sMembers一次取回比循環(huán)查 MySQL 快一個(gè)數(shù)量級詞庫更新時(shí)重新sAdd即可。3.2 下單與庫存扣減別讓同一件二手商品被賣兩次二手商品和普通電商最大的區(qū)別是庫存通常是 1賣一件少一件超賣就是事故。常見做法有兩種一是數(shù)據(jù)庫行鎖二是 Redis 預(yù)扣加隊(duì)列落庫。小團(tuán)隊(duì)我建議先用行鎖簡單可靠。public function createOrder() { $goodsId input(post.goods_id); $buyerId $this-uid; Db::startTrans(); try { // FOR UPDATE 鎖住這一行防止并發(fā)下單 $goods Db::name(goods) -where(id, $goodsId) -lock(true) -find(); if (!$goods || $goods[status] ! 2) { // 2在售 throw new \Exception(商品已下架或已售出); } if ($goods[user_id] $buyerId) { throw new \Exception(不能購買自己的商品); } // 扣庫存并改狀態(tài) Db::name(goods)-where(id, $goodsId)-update([ status 3, // 3已售 buyer_id $buyerId, sold_at time(), ]); // 生成訂單 $orderNo date(YmdHis) . mt_rand(1000, 9999); Db::name(order)-insert([ order_no $orderNo, goods_id $goodsId, buyer_id $buyerId, seller_id $goods[user_id], amount $goods[price], status 1, // 1待付款 create_at time(), ]); Db::commit(); return json([code 0, order_no $orderNo]); } catch (\Exception $e) { Db::rollback(); return json([code 400, msg $e-getMessage()]); } }邏輯說明lock(true)生成SELECT ... FOR UPDATE在事務(wù)里鎖住商品行第二個(gè)并發(fā)請求會(huì)等第一個(gè)提交后再讀讀到status3就拋異常超賣被擋住。參數(shù)上status的取值要在全項(xiàng)目統(tǒng)一1 待審核、2 在售、3 已售、4 下架改代碼時(shí)全局搜一遍別漏。order_no用時(shí)間戳加隨機(jī)數(shù)夠用但不絕對唯一量大時(shí)建議換成uniqid或雪花算法。事務(wù)范圍要盡量小鎖行到提交之間別做發(fā)短信、推消息這類慢操作否則鎖持有時(shí)間變長并發(fā)直接掉。3.3 錢包與資金流水每一分錢都要有日志二手平臺涉及買家付款、平臺抽傭、賣家提現(xiàn)資金鏈路必須可追溯。核心原則是余額字段和流水表在同一個(gè)事務(wù)里更新且流水只增不改。// 賣家余額增加同時(shí)寫流水 public function addBalance($userId, $amount, $type, $refId) { Db::startTrans(); try { // 用 inc 原子自增避免讀-改-寫丟更新 Db::name(user)-where(id, $userId)-inc(balance, $amount)-update(); Db::name(wallet_log)-insert([ user_id $userId, amount $amount, type $type, // 1訂單收入 2提現(xiàn) 3退款 ref_id $refId, // 關(guān)聯(lián)訂單號 balance_after Db::name(user)-where(id, $userId)-value(balance), create_at time(), ]); Db::commit(); } catch (\Exception $e) { Db::rollback(); throw $e; } }邏輯說明inc是原子操作比「先查余額再算再寫」安全后者在并發(fā)下會(huì)丟更新。balance_after記錄變動(dòng)后余額對賬時(shí)一眼能看出哪筆流水對不上。參數(shù)上type要和前端展示文案對應(yīng)退款走負(fù)數(shù)金額還是單獨(dú)類型要提前定混用會(huì)讓對賬腳本很難寫。提現(xiàn)一定要走人工審核或至少加風(fēng)控我見過源碼里提現(xiàn)接口沒做金額校驗(yàn)用戶傳負(fù)數(shù)直接把余額加上去的。4. 獨(dú)立后臺管理權(quán)限、審核與運(yùn)營功能的落地細(xì)節(jié)4.1 后臺權(quán)限模型RBAC 最小實(shí)現(xiàn)獨(dú)立后臺的核心不是菜單多而是權(quán)限分得清。最小可用的 RBAC 三張表admin_user、admin_role、admin_rule再加一張admin_role_rule關(guān)聯(lián)。登錄后把該角色的規(guī)則 ID 存 session每次請求校驗(yàn)當(dāng)前控制器和方法是否在允許列表里。// 后臺基類控制器里的權(quán)限校驗(yàn) protected function checkAuth() { $uid session(admin_uid); if (!$uid) { $this-redirect(/admin/login); } // 超管跳過校驗(yàn) if (session(admin_is_super) 1) { return true; } $rule strtolower(request()-controller() . / . request()-action()); $allow session(admin_rules); // 登錄時(shí)查好的規(guī)則數(shù)組 if (!in_array($rule, $allow)) { throw new \Exception(無權(quán)限訪問); } }邏輯說明把權(quán)限判斷放在基類構(gòu)造函數(shù)里所有后臺控制器繼承它就不會(huì)漏。參數(shù)上admin_rules在登錄時(shí)一次性查好存 session避免每次請求查庫但角色權(quán)限變更后要讓相關(guān)管理員重新登錄或者加一個(gè)版本號比對。常見誤用是把權(quán)限判斷寫在每個(gè)方法里改一個(gè)漏一個(gè)最后變成「菜單藏了但接口還能調(diào)」。4.2 商品審核與違規(guī)處理運(yùn)營每天要用的三個(gè)動(dòng)作后臺運(yùn)營最高頻的三個(gè)動(dòng)作是審核新商品、下架違規(guī)商品、處理舉報(bào)。審核列表要支持按狀態(tài)篩選、批量通過、批量拒絕并填原因。拒絕原因要存下來并推送給發(fā)布者否則用戶不知道哪里違規(guī)會(huì)反復(fù)發(fā)。功能關(guān)鍵字段注意點(diǎn)商品審核status、audit_admin、audit_at批量操作要逐條寫日志別只更新狀態(tài)違規(guī)下架status、off_reason下架要同時(shí)凍結(jié)關(guān)聯(lián)訂單避免已下單商品被下架舉報(bào)處理report 表、handle_result舉報(bào)和商品狀態(tài)要聯(lián)動(dòng)處理完回寫舉報(bào)單審核接口我一般會(huì)加一個(gè)操作日志表admin_log記錄誰在什么時(shí)間對哪條數(shù)據(jù)做了什么。出問題時(shí)這是唯一的后悔藥尤其是資金相關(guān)的操作。4.3 數(shù)據(jù)統(tǒng)計(jì)與導(dǎo)出別讓后臺導(dǎo)出拖垮前臺后臺的訂單導(dǎo)出、用戶導(dǎo)出是典型的慢操作。常見做法是同步導(dǎo)出數(shù)據(jù)量一大就超時(shí)還會(huì)占著數(shù)據(jù)庫連接影響前臺。我一般改成異步點(diǎn)導(dǎo)出后寫一條任務(wù)記錄后臺隊(duì)列慢慢生成 CSV生成完給運(yùn)營一個(gè)下載鏈接。// 導(dǎo)出任務(wù)入隊(duì)不直接查全量 public function exportOrders() { $taskId Db::name(export_task)-insertGetId([ admin_id session(admin_uid), type order, status 0, // 0排隊(duì)中 create_at time(), ]); // 推入 Redis 隊(duì)列由常駐腳本消費(fèi) Redis::lPush(export_queue, json_encode([task_id $taskId])); return json([code 0, msg 導(dǎo)出任務(wù)已提交稍后到下載中心查看]); }邏輯說明接口只寫任務(wù)和入隊(duì)立刻返回運(yùn)營不會(huì)看到轉(zhuǎn)圈。消費(fèi)腳本分批查、分批寫文件每批 1000 條避免一次性把內(nèi)存打滿。參數(shù)上status要有 0 排隊(duì)、1 生成中、2 完成、3 失敗四個(gè)狀態(tài)失敗要記原因。下載鏈接最好帶過期時(shí)間別讓導(dǎo)出文件長期裸放在公網(wǎng)目錄。5. 部署上線與性能排查PHP 二手平臺最容易翻車的地方5.1 Nginx 與 PHP-FPM 配置三個(gè)影響吞吐的參數(shù)源碼跑通不等于能上線。Nginx 和 PHP-FPM 的默認(rèn)配置面向低并發(fā)二手平臺一搞活動(dòng)就容易 502。我一般會(huì)調(diào)這三個(gè)地方。# Nginx靜態(tài)資源和上傳目錄直接返回別走 PHP location ~* \.(jpg|jpeg|png|gif|css|js|ico)$ { expires 7d; access_log off; } location /uploads/ { alias /var/www/ershou/public/uploads/; }; php-fpm.conf / www.conf pm dynamic pm.max_children 50 ; 按內(nèi)存算每個(gè) PHP 進(jìn)程約 30-50M pm.start_servers 10 pm.min_spare_servers 5 pm.max_spare_servers 20 pm.max_requests 500 ; 防止內(nèi)存泄漏累積邏輯說明圖片走 Nginx 直接返回能省掉大量 PHP 進(jìn)程。pm.max_children不是越大越好4G 內(nèi)存的機(jī)器給 50 已經(jīng)接近上限給 200 會(huì)因內(nèi)存不足觸發(fā) OOM。pm.max_requests讓進(jìn)程處理一定請求后重啟規(guī)避第三方 SDK 的內(nèi)存泄漏。參數(shù)要按機(jī)器實(shí)際內(nèi)存調(diào)調(diào)完用ab或wrk壓一下商品列表接口看 QPS 和錯(cuò)誤率。5.2 慢查詢與索引二手平臺最該加索引的四張表二手平臺數(shù)據(jù)量漲得最快的是goods、order、chat_message、wallet_log。這四張表如果沒有合適索引幾千條數(shù)據(jù)時(shí)就開始卡。我一般會(huì)確認(rèn)這幾個(gè)索引存在。表建議索引對應(yīng)查詢goods(status, cat_id, create_at)分類下在售商品列表goods(user_id, status)我的發(fā)布o(jì)rder(buyer_id, status)我的購買order(seller_id, status)我的賣出chat_message(from_id, to_id, create_at)聊天記錄分頁wallet_log(user_id, create_at)錢包流水加索引前先用EXPLAIN看現(xiàn)有查詢走沒走索引別盲目加。chat_message這類表增長極快量大了要考慮按時(shí)間分表或定期歸檔否則單表幾千萬行時(shí)加索引本身就會(huì)鎖表很久。5.3 緩存策略哪些數(shù)據(jù)能緩存哪些絕對不能能緩存的商品分類、首頁推薦位、敏感詞庫、地區(qū)數(shù)據(jù)。這些變更頻率低緩存幾分鐘到幾小時(shí)都行。不能緩存的商品庫存狀態(tài)、訂單狀態(tài)、用戶余額。這些一旦緩存就會(huì)出現(xiàn)「頁面顯示在售但下單提示已售」的玄學(xué)問題。// 分類緩存10 分鐘過期 public function getCats() { $cats Redis::get(cat_list); if (!$cats) { $cats Db::name(category)-where(status, 1)-select(); Redis::setex(cat_list, 600, json_encode($cats)); } return json_decode($cats, true); }邏輯說明setex第二個(gè)參數(shù)是秒600 即 10 分鐘。緩存更新有兩種策略一是等過期二是數(shù)據(jù)變更時(shí)主動(dòng)del。分類這種低頻數(shù)據(jù)等過期就行商品狀態(tài)這種高頻變更的別緩存。參數(shù)上緩存 key 要帶業(yè)務(wù)前綴避免和會(huì)話等其他 key 沖突。6. 避坑與排查仿閑魚源碼落地時(shí)最常見的五個(gè)翻車點(diǎn)6.1 安裝頁 500 但日志空白現(xiàn)象打開/install直接 500runtime/log里沒有當(dāng)天日志。原因PHP 錯(cuò)誤沒寫到項(xiàng)目日志而是進(jìn)了 PHP-FPM 的錯(cuò)誤日志或者display_errors關(guān)了。解決先看/var/log/php7.4-fpm.log和 Nginx 的error.log再臨時(shí)在入口文件加ini_set(display_errors, 1); error_reporting(E_ALL);定位到具體行后改完記得關(guān)掉別把報(bào)錯(cuò)暴露到公網(wǎng)。6.2 上傳商品圖提示成功但圖片是破圖現(xiàn)象發(fā)布成功列表里圖片顯示裂開。原因uploads目錄沒寫權(quán)限或者 Nginx 的alias路徑配錯(cuò)文件實(shí)際沒落盤或訪問不到。解決ls -l看目錄里有沒有文件有文件就是 Nginx 路徑問題沒文件就是權(quán)限問題。權(quán)限只給uploads和runtime別整個(gè)項(xiàng)目放開。6.3 支付回調(diào)一直驗(yàn)簽失敗現(xiàn)象用戶付了錢訂單還是待付款。原因回調(diào)地址被 Nginx 重寫規(guī)則攔截或者密鑰里有多余空格或者回調(diào)參數(shù)被框架的全局過濾改了。解決先把回調(diào)原始數(shù)據(jù)file_put_contents到日志對比簽名串再確認(rèn)回調(diào)路由在 Nginx 里try_files之前放行密鑰從配置讀時(shí)trim一下。這類問題沒有捷徑就是打日志比對。6.4 后臺能登錄但所有菜單點(diǎn)進(jìn)去 404現(xiàn)象登錄成功點(diǎn)任何菜單都是 404。原因Nginx 沒配 PATH_INFO或者try_files把/admin/user/list當(dāng)成靜態(tài)文件找了。解決Nginx 里加try_files $uri $uri/ /index.php?$query_string;并確認(rèn)fastcgi_param PATH_INFO有傳。ThinkPHP 的兼容模式也可以臨時(shí)打開但根治還是配好重寫。6.5 PHP 8 下源碼大面積報(bào)錯(cuò)現(xiàn)象換到 PHP 8.1 后登錄頁都打不開日志里全是each() removed、create_function廢棄。原因源碼按 PHP 7.x 寫用了 PHP 8 移除的函數(shù)。解決最省事是退回 PHP 7.4非要上 8就全局搜each(、create_function、money_format逐個(gè)替換each用foreach改寫工作量取決于源碼規(guī)模。我一般建議先用 7.4 跑通業(yè)務(wù)再評估升級別一上來就跟版本較勁。7. 從能跑到能運(yùn)營二手平臺源碼的二開邊界與驗(yàn)證習(xí)慣源碼能跑通只是起點(diǎn)真正決定這套東西值不值得投入的是二開邊界清不清楚。我的經(jīng)驗(yàn)是交易主鏈路發(fā)布、下單、支付、退款盡量少動(dòng)動(dòng)之前先寫測試用例或者至少手動(dòng)跑一遍全流程運(yùn)營功能審核、統(tǒng)計(jì)、消息推送可以大膽改改壞了不影響成交。判斷一套仿 58 轉(zhuǎn)轉(zhuǎn)閑魚源碼值不值得長期用我會(huì)看三點(diǎn)數(shù)據(jù)庫表設(shè)計(jì)有沒有留擴(kuò)展字段、支付和消息有沒有抽象成獨(dú)立模塊、后臺權(quán)限是不是 RBAC 而不是寫死的。三點(diǎn)都占二開成本低只占一點(diǎn)后面每加一個(gè)功能都要?jiǎng)雍诵拇a遲早推倒重來。驗(yàn)證習(xí)慣上我給自己定了一條任何涉及資金的改動(dòng)上線前必須用兩個(gè)賬號跑一遍「下單 → 付款 → 賣家收款 → 提現(xiàn)」全鏈路并在wallet_log里核對每一筆流水的balance_after是否連續(xù)。這條習(xí)慣幫我攔下過至少兩次對賬不平的事故。二手交易平臺的錢是用戶的錢寧可上線慢一天也別讓流水對不上。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取