ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PHP魔改私人网盘:部署、后台与IP统计实战

PHP魔改私人网盘:部署、后台与IP统计实战 简介这款魔改私人网盘源码基于PHP与MySQL技术开发专为需要私有云存储、注重数据可控性的个人用户和中小团队而设计可有效弥补公共网盘在隐私保护与容量限制上的不足。资源压缩包共48个文件涵盖16个PHP核心程序、3个SQL数据库脚本、10张演示截图与图片素材以及HTML、CSS、htaccess等前端和服务器配置文件整体约22.11MB目录结构清晰便于查阅。程序自带独立管理后台支持目录管理、系统设置、文件分享、IP访问统计和数据统计等功能压缩包内还提供安装说明文档、数据库初始化脚本及多环境配置参考可在php7.4与mysql5.7环境下快速完成部署。从后台模块来看已覆盖登录认证、文件上传下载、目录管理、消息通知等常用功能适合作为个人网盘二开或学习PHP项目架构的起点。已有105人学习/下载适合不想受限于公共网盘、希望自主掌控数据的站长和技术开发者参考。1. 魔改私人网盘PHP个人网盘开源源码带来的到底是什么很多人看到“魔改私人网盘php个人网盘开源带后台管理源码”这种文件名第一反应是解压、部署、完事。但跟商业网盘装上就漂亮不同PHP 源码网盘的真正价值在后半句“带后台管理、可分享、带 IP 统计”你可以把一个现成网盘代码改造成符合自己业务逻辑的分发工具而不是被动接受平台规则。我实际接过这类需求给团队建过内网文件分发中心也给客户搭过带访问统计的资料站。这篇文章直接从部署开始把后台权限设计、分享机制、IP 统计模块的配置和代码讲清楚最后给出真机部署里反复翻车的五个坑。适合想自己掌握数据、愿意在开源源码上动手的 PHP 开发者。2. 把zip包跑起来环境检查、配置项和首次登录三件套这类网盘 zip 最常见的部署失败原因不是源码本身有严重缺陷而是环境不一致。PHP 版本差一个大版本、缺失某个扩展、上传目录没有写权限都会导致后台白屏或功能静默失效。更麻烦的是不少源码在正式环境会关掉display_errors报错信息全被吞了你只能对着空白页面干瞪眼。所以我把部署固定拆成三步环境核对、配置导入、安全加固每一步都有明确的验证方式走完再进后台基本不会返工。2.1 环境核对PHP版本、扩展和目录权限第一步先看代码要求什么 PHP 版本。不同年代的网盘源码差别很大老项目用mysql_connect()PHP 7.0 以后这个函数就没了直接报“未定义函数”新一点的用 mysqli 或 PDO再激进点的魔改版在 PHP 8.x 下还会踩数组访问方式不兼容的雷。用下面两条命令快速摸底php -v php -m | grep -E mysqli|pdo_sqlite|curl|fileinfo|gd|mbstring第一条看主版本号第二条确认常见扩展是否齐全。个人网盘类项目里fileinfo 负责上传文件的 MIME 类型识别没有它图片附件会被当成application/octet-streammbstring 处理中文文件名和下载时的编码转换缺失的话中文文件要么乱码要么无法下载gd 生成图片缩略图少了它后台图片列表会退化成一堆空白框。如果跑在 Debian/Ubuntu 系可以用包管理器补齐sudo apt install php7.4-cli php7.4-mysql php7.4-gd php7.4-mbstring php7.4-curl php7.4-sqlite3版本号要往当前环境的 PHP 主版本靠比如机器是 PHP 8.1 就把php7.4全部换成php8.1。装完扩展之后目录权限是下一个隐形杀手。上传目录、缓存目录、日志目录都需要写权限否则前端表现为“上传失败”或者能传上去但列表页加载不出图。常见做法是分两个层次代码目录用 755属主可写数据和临时目录用 750 到 770并保证服务器运行用户是目录属主。如果一台机器只跑这一个站点直接给足也问题不大但多站点共用一台机器时我建议用“属主 用户组”的方式限制写入范围chown -R www-data:www-data /var/www/html/data chmod -R 750 /var/www/html/data上传目录的绝对路径建议写进 config并放在 web 根目录外面例如/var/www/uploads。这一步对 5.2 节分享链接的安全性影响很大先记住这个习惯。2.2 解压安装与配置三个关键字段别改错解压这步本身没有悬念但要注意 zip 里往往套着两层目录。解压后先看最外层目录再把入口文件移到站点根目录否则访问域名会 404unzip private_cloud_magic.zip -d /var/www/html/ mv /var/www/html/private_cloud/* /var/www/html/ chown -R www-data:www-data /var/www/html配置文件每个项目的位置不一样常见的是根目录下config.php或application/config.php。没有安装向导的魔改版会把数据库连接信息直接写在配置里下面几个字段无论如何都要检查// config.php 中的关键配置示例 $config[db_host] 127.0.0.1; $config[db_user] netdisk_user; $config[db_pass] 换成高强度的密码; $config[db_name] netdisk; $config[site_url] https://pan.example.com; $config[upload_root] /var/www/uploads;其中site_url最容易被忽略。不少源码在生成分享链接、拼接资源路径时直接读取这个字段如果填成localhost那前台生成的链接只在你本机有效发给别人就是死链。网盘外面还套了 Nginx 转发层时site_url必须填对外的访问地址否则页面里所有重定向都会跳到内网域名上。数据库导入前先确认字符集。zip 里附带的 SQL 文件几乎是 UTF-8 编码直接用 mysql 客户端导入时遇到中文表数据或文件路径很可能乱码。提前加一个参数能规避大部分问题mysql -u root -p --default-character-setutf8mb4然后在 MySQL 客户端里完成建库、选库、导入三步CREATE DATABASE IF NOT EXISTS netdisk DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE netdisk; SOURCE /var/www/html/install.sql;SQLite 版本则简单得多源码目录下的 data 目录内会自动生成数据库文件只要保证 PHP 进程对该目录有写权限就行。导入 SQL 后刷新首页能看到跳转登录页部署就算基本成功。2.3 首次进入后台三件加固马上做首次登录后台之前我习惯先把三件加固的事做掉每一件都用不了五分钟。第一把后台入口从默认路径改掉。很多源码后台固定在/admin或/index.php?modadmin对外不想被扫描器一眼认出就改成只有自己知道的路径。后台入口字符串在源码里通常是唯一标识做一次全局替换cp -a /var/www/html /var/www/html_backup grep -rl admin /var/www/html --include*.php | xargs sed -i s#/admin#/manage_panel#g路径改完顺手把入口文件的文件名也改掉例如admin_login.php改成manage_panel.php并同步更新引用处。这一步对安全性没有绝对保障但能挡住绝大多数的无差别扫描。第二进后台先改默认密码。这类源码默认口令常见是admin/admin或admin/123456进入后台后什么都别点先去用户管理里把密码换掉同时把表里多余的测试账号一并清理干净。第三删除安装目录。源码自带的install/或setup/目录在首次部署完成后就没有存在价值了留着等于把重新初始化数据库的入口暴露在网站下面。直接执行rm -rf /var/www/html/install做完这三件事后台这层才真正能见光。下一步进入后台管理逻辑看看权限和配额到底怎么落地。3. 后台管理源码解析权限、配额和文件管理的三根支柱后台管理是整个网盘的驾驶舱。判断一份个人网盘源码能不能投入实际运营就看它后台在这三件事上处理得是否顺手谁能用什么权限看什么文件、每个用户占用多大空间、文件管理界面是否高效。接下来逐个拆开讲并给出我实际采用过的配置和改法。3.1 权限模型管理员、上传者、只读访客的三层结构PHP 网盘项目对权限的处理通常落在一张 user 表和一张文件归属表上。user 表里常见的字段是id, username, password_hash, role, quota, used_space, statusstatus 用来做封号或审核。角色设计上我推荐用三层模型而不是无限细分admin管理全部文件和所有用户可删可改可分享后台统计仅本人可见。uploader拥有上传权限的普通用户可管理自己名下的文件和目录能创建分享链接。viewer只读访客只能浏览被授权的目录或通过收到的分享链接下载不能上传。源码里权限校验最常见的写法是每个写操作页面的开头做一次 session 检查和角色判断示意如下?php session_start(); if (empty($_SESSION[uid])) { header(Location: /login.php); exit; } $role (int)$_SESSION[role]; // role1 admin, role2 uploader, role3 viewer if ($_GET[action] delete $role 1) { exit(当前账号没有删除权限); } if ($_GET[action] upload $role 3) { exit(只读账号不能上传); }很多小网盘项目只做一层判断登录了就什么都能干剩下的权限全靠前端按钮隐藏。我认为这是后台源码里第一个要动手改的地方。前端按钮只是用户体验真正可靠的是在每个写操作上传、删除、改名、移动、分享的服务端入口都做一次权限校验。后台管理界面的按钮可以隐藏接口层的校验才是底线。目录归属同样要限制。常见做法是给每个用户分配一个唯一的根目录例如/var/www/uploads/{uid}/对用户提交的任何路径做前缀校验?php $userRoot /var/www/uploads/ . $_SESSION[uid]; $realPath realpath($targetFile); if (strpos($realPath, $userRoot) ! 0) { exit(禁止跨目录操作); }这里用realpath很关键它能过滤掉../../这种相对路径攻击。如果少了这层判断用户完全可以构造一个../别人家目录/xx.pdf的路径去读取或删除他人文件。这份源码如果还没有这层检查上线前一定要补。3.2 文件管理目录树、批量操作和分片上传的取舍个人网盘后台的文件列表功能上至少要有目录树、面包屑导航、文件多选、批量移动或删除、打包下载。目录树递归渲染其实很耗性能文件数量超过一万以后整页加载会明显变慢。我在项目里最后只展开两级第一级是用户根目录下的文件夹第二级是下一级子目录。再深层就交给文件列表页的路径跳转而不是试图用一棵树展示全部内容。批量下载是高频需求。PHP 实现批量下载的一个常用方案是把选中的文件打包成 zip 再输出。注意压缩过程极耗 CPU 和内存后台在制作压缩包时建议记录任务状态用异步任务或 cron 生成 zip而不是在 HTTP 请求里同步压缩。前端界面只轮询“压缩包是否生成好了”这样大数据量场景不会把页面卡死。?php // 小规模批量压缩可以这样写文件数多时改成任务队列 $zip new ZipArchive(); $tmpFile tempnam(sys_get_temp_dir(), netdisk_); if ($zip-open($tmpFile, ZipArchive::OVERWRITE) ! true) { exit(无法创建压缩包); } foreach ($selectedFiles as $realPath) { $zip-addFile($realPath, basename($realPath)); } $zip-close(); header(Content-Type: application/zip); header(Content-Length: . filesize($tmpFile)); readfile($tmpFile); unlink($tmpFile);这段代码处理 200 个以内的小文件没问题超过这个量级就该考虑异步方案。至于分片上传PHP 源码里最常见的实现是前端把文件切成 2MB 到 5MB 的分片循环提交后端等全部片传完后合并。实现分片合并时要注意分片文件要放在临时目录等最后一个分片到达后检查分片总数与文件头里声明的大小是否一致缺少任何一片都不允许合并。这个逻辑直接写入后台管理源码的upload模块里是稳定性相对容易翻车的区域。3.3 空间配额和限速防止小型服务器被“网盘化”网盘上线的第一天就要考虑配额不然三五个用户就能用上传脚本把一个 40GB 的 VPS 填满。配额实现不复杂在 user 表里维护used_space字段上传完成时累加文件大小删除文件时扣减上传前检查剩余空间?php $quotaLimit 10 * 1024 * 1024 * 1024; // 10GB $usedSpace (int)$_SESSION[used_space]; $fileSize (int)$_FILES[file][size]; if ($usedSpace $fileSize $quotaLimit) { exit(配额不足剩余空间 . formatSize($quotaLimit - $usedSpace)); } // 上传成功后在同一逻辑里累加配额 updateUserSpace($_SESSION[uid], $fileSize, increase);配额更新必须放在上传成功且文件校验通过之后不能在页面里只做加法而不处理失败回滚否则上传失败一次配额就被白白占掉一块。删除文件时也要同步扣减。如果源码里没有自动扣减逻辑后台管理里至少要补一个“重新统计占用空间”的按钮方便定期核对。限速这块PHP 本身不适合做带宽控制稳妥的姿势是依赖 Nginx 层做限制在站点配置中加入location /download/ { alias /var/www/uploads/; limit_rate 2m; limit_rate_after 10m; }limit_rate 2m表示单个连接下载限速 2MB/slimit_rate_after 10m表示前 10MB 不限速避免预览小文件时被限速拖慢。如果跑在 Apache 下PHP 侧没有通用的限速指令一般会靠带宽模块实现或者干脆建议换到 Nginx。个人网盘的下载速率控制在 2 到 5MB/s 比较合理内网按需提速公网按这个数字限住能显著降低出口带宽占用。4. 分享链接和IP统计从存储工具到渠道工具内网团队里把网盘只当存储工具没什么问题但如果涉及给客户发文件、给外协方放资料分享链接和访问统计就变成刚需。这类网盘源码里的分享模块本质上是给你一个受控的“门”谁的链接、访问期限、有没有提取码、被下载了几次。IP 统计则是网盘运营侧的“镜子”哪些文件是热门资源、哪个时间点是高峰期、某个外网 IP 是否在反复抓取文件都靠它回答。4.1 分享链接机制token、提取码和有效期分享链接的核心是生成一个不可猜测的 token并把 token 与文件 ID、过期时间、提取码一起存进分享表。token 生成一定要用随机来源而不是md5(time())时间戳在一天内可预测写个脚本几分钟就能遍历完?php public function createShare(int $fileId, int $expireDays 7, string $extractCode ): string { $token bin2hex(random_bytes(16)); // 32 位十六进制不可预测 $expireAt date(Y-m-d H:i:s, time() $expireDays * 86400); $stmt $pdo-prepare( INSERT INTO share (token, file_id, extract_code, expire_at, created_by) VALUES (?, ?, ?, ?, ?) ); $stmt-execute([$token, $fileId, $extractCode, $expireAt, $_SESSION[uid]]); return $token; }分享链接的典型路径是/s.php?tokenxxxxxxxx访问时的核心校验依次是token 长度、是否存在、是否过期、是否要求提取码。写代码时注意一点提取码的校验必须放在服务端不能只靠前端表单判断否则别人手动拼接参数就能绕过?php $token $_GET[token] ?? ; if (strlen($token) ! 32) { exit(链接无效); } $stmt $pdo-prepare(SELECT * FROM share WHERE token ? AND expire_at NOW()); $stmt-execute([$token]); $share $stmt-fetch(); if (!$share) { exit(分享已过期); } if ($share[extract_code] ! ) { // 提交表单验证提取码后再放行下载 }分享链接最容易忽视的一个边界是“原文件是否已被删除”。数据库里可能还留有一条分享记录但物理文件已经被管理员清理了下载处理器要做好文件存在性检查否则每次点击都会拿到一个 500 错误。更完善的实现还会在下单时顺手把分享表中的download_count加一这就是下一步 IP 统计的数据来源之一。4.2 IP统计访问日志表、写库时机与真实IP获取IP 统计的落点是日志表。这类网盘源码比较常见的表结构如下CREATE TABLE IF NOT EXISTS visit_log ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, file_id INT UNSIGNED NOT NULL, ip VARCHAR(45) NOT NULL, user_agent VARCHAR(255) DEFAULT , referer VARCHAR(255) DEFAULT , created_at DATETIME NOT NULL, KEY idx_file_time (file_id, created_at), KEY idx_ip_time (ip, created_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;每次下载都 INSERT 一条日志从写库时机来看很直观也是被吐槽最多的设计。如果高峰期同时有几百人在下载没有做任何缓冲的统计写入会先把数据库拖死网盘页面反而跟着一起变慢。一种可以接受的替代是先把统计追加到本地缓冲文件达到一定条数或时间间隔后再批量入库示意如下?php // 把访问记录追加到缓冲文件由定时任务批量导入 $line implode(|, [$fileId, $ip, date(YmdHis), $ua, $referer]); file_put_contents(/tmp/visit_buffer.log, $line . PHP_EOL, FILE_APPEND);# crontab 每 5 分钟执行一次批量导入 */5 * * * * php /var/www/netdisk/cron_import_visit.php /dev/null 21关键原则是页面下载逻辑里不要跑 INSERT只做文件追加统计模块定时解析缓冲文件后写库。对个人网盘的访问量来说文件追加的 IO 开销可以忽略不计最多丢十几秒的数据但网盘主流程永远不会被统计拖垮。获取真实 IP 也有隐藏的坑。当网盘前面还有一层 Nginx 网关或流量转发节点时$_SERVER[REMOTE_ADDR]拿到的只是网关的地址所有访客都会统计成同一个来源。如果只在纯内网用问题不大一旦对外提供服务就必须在网关那层把客户端 IP 放入转发头也就是 X-Forwarded-For。PHP 取值时按下面的顺序判断?php function clientIp(): string { if (isset($_SERVER[HTTP_X_FORWARDED_FOR])) { $ips explode(,, $_SERVER[HTTP_X_FORWARDED_FOR]); foreach ($ips as $ip) { $ip trim($ip); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { return $ip; } } } return $_SERVER[REMOTE_ADDR] ?? ; }X-Forwarded-For 是逗号分隔的链路从左到右是客户端原始地址。直接取第一个可能被篡改 IP 刷统计取最后一个又不靠谱。稳妥策略是对每个值做 IP 合法性和私网地址校验取第一个公网地址。这样拿到的数据才具备“按 IP 去重”的可信度。4.3 统计报表按天、按文件、按IP三个维度的最小实现后台统计页通常展示三块总访问量趋势、热门文件排名、来源 IP 列表。最小可用的 SQL 如下-- 按天统计访问量和独立访客 SELECT DATE_FORMAT(created_at, %Y-%m-%d) AS day, COUNT(*) AS pv, COUNT(DISTINCT ip) AS uv FROM visit_log WHERE created_at DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY day ORDER BY day DESC;-- 热门文件 TOP10 SELECT file_id, file_name, COUNT(*) AS downloads FROM visit_log JOIN file ON file.id visit_log.file_id GROUP BY file_id ORDER BY downloads DESC LIMIT 10;按 IP 明细的报表字段一般有 ip、地区、最后访问时间、累计次数业务上主要用于发现异常抓取比如同一个 IP 在几分钟内连续下载多个大文件。地区一列需要引入 IP 地址库做离线解析整体上是可选能力初期没必要做进去。先让日志有数据后面再谈分析和可视化。5. 网盘魔改避坑指南下载、路径、并发三处最常翻车这一章是我实机跑这类源码总结的踩坑记录。每一条按“现象 → 原因 → 解决”的顺序写方便你对照翻车现场直接定位。5.1 大文件下载中断PHP内存和执行超时的双重限制现象下载 200MB 以上的文件进度条走到一半就中断浏览器显示连接重置小文件偶发但也存在。原因老代码用file_get_contents($path)读整个文件再一行输出。PHP 默认memory_limit是 128M读一个 300MB 文件到内存里直接爆掉同时部分源码把max_execution_time设成 30下载稍微大点的文件就超过时限脚本被杀。解决优先使用流式读取每次只往输出缓冲区写一小块并把执行时间放宽?php $f fopen($realPath, rb); while (!feof($f)) { echo fread($f, 8192); flush(); } fclose($f);更彻底的办法是让 Nginx 直接接管下载响应PHP 只负责验证权限后返回文件地址不参与传输过程。这样无论文件多大PHP 都不会被内存和超时拖住。线上优先选择第二种PHP 流式方案只作为不支持该能力时的回退。5.2 分享链接暴露真实路径文件ID与真实路径的混淆现象收到分享链接的人把下载地址复制出来发现参数里带着path/var/www/html/data/upload/2024/realname.pdf直接改路径可以猜到其他文件名。原因分享下载模块把文件物理路径当作唯一参数没有使用文件 ID 做映射。攻击者只需要遍历路径就能把整个目录结构摸清。解决把 download 参数从路径改成fid或token。文件真实路径存数据库PHP 收到请求后先查库拿到路径再判断分享是否存在、是否过期。这样 URL 里看到的只是一个 ID物理路径永远不会出现在浏览器地址栏或访问日志中。新部署的网盘务必检查一遍所有下载入口凡是直接接受路径参数的都要改掉。5.3 IP统计写库把网盘IO卡死主流程和统计流没解耦现象下载高峰时期网盘页面响应从 100ms 跳到 5 秒以上监控里数据库 QPS 居高不下。原因统计功能的 INSERT 和下载主流程没有分离每次请求都做一次写库高峰期大量小事务把磁盘写变成了瓶颈。解决把统计写入从主流程剥离用文件缓冲或定时任务批量导入。个人网盘这个量级用文件缓冲就够了我在 4.2 节给了落盘追加的写法最多丢十几秒的明细但网盘主流程永远不被统计拖垮。等访问量真的大到文件缓冲也不够时再上 Redis 队列也不迟。5.4 中文文件名下载乱码Content-Disposition编码要统一现象Linux 服务器上文件上传和页面显示都正常但下载到 Windows 上文件名变成一串乱码部分手机浏览器直接下载失败。原因文件下载时返回的Content-Disposition头里直接放原始中文而 HTTP 头不允许非 ASCII 字符老代码用 iconv 转成 GBK又没考虑移动端浏览器的解析差异。解决按 RFC 5987 标准用filename*输出 UTF-8 编码?php $encoded rawurlencode($filename); header(Content-Disposition: attachment; filename\$encoded\; filename*UTF-8$encoded);现代浏览器会优先解析filename*的 UTF-8 内容乱码问题基本消失旧的filename字段保留兼容不支持新标准的客户端。改完记得清一下浏览器缓存再测试否则很容易误判成没改成功。5.5 后台session频繁失效上传大文件时登录状态丢现象后台登录后操作一切正常一传大文件传完再点别的页面就被弹回登录页刷新后又要重新登录。原因大文件上传期间 PHP 会话没有续期或者 session 文件所在目录被系统临时目录清理规则扫掉更常见的是源码把 session 过期时间设得太短上传耗时长完成后 session 已经失效。解决把 session 存储路径和过期时间显式配置一下?php ini_set(session.gc_maxlifetime, 7200); ini_set(session.cookie_lifetime, 0); session_save_path(/var/www/data/session); session_start();session.cookie_lifetime设为 0 表示浏览器关闭即失效配合较长的gc_maxlifetime能在“安全”和“上传不丢登录”之间取平衡。同时检查 session 保存目录是否存在且有写权限否则 PHP 会静默退回默认目录配置等于白写。多台机器共用同一套后台时还需要把 session 存到 Redis 里不过个人网盘单机部署暂时不必。6. 魔改进阶给IP统计加一个“热门下载TOP10”页面IP 统计模块上线两周后你大概率会想知道一个问题日志表里堆了几千行数据但“哪个文件最受欢迎”后台不一定有现成页面回答。这正好是动手改源码的切入点。以现有visit_log表为基础我加了一个后台菜单“下载排行”页面只做两件事运行一条聚合 SQL把近 7 天按文件维度的下载量和独立 IP 数算出来再用后台现有的表格样式渲染成列表。查询如下SELECT f.id, f.file_name, COUNT(v.id) AS downloads, COUNT(DISTINCT v.ip) AS unique_ips FROM visit_log v JOIN file f ON f.id v.file_id WHERE v.created_at DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY f.id ORDER BY downloads DESC LIMIT 20;如果文件表数据量过万注意给visit_log.file_id加上索引否则这条 SQL 每点一次都全表扫描。再套一个查询缓存结果存到临时文件里60 秒过期?php $cacheFile __DIR__ . /tmp/top_cache.php; $cacheTtl 60; if (is_file($cacheFile) (time() - filemtime($cacheFile)) $cacheTtl) { $rows include $cacheFile; } else { $rows $pdo-query($sql)-fetchAll(); file_put_contents($cacheFile, ?php return . var_export($rows, true) . ;); }页面渲染时直接在循环里对downloads做阈值判断超过 100 次的打上“高热”标签否则显示“正常”。这个判断在输出时用三行代码就能完成不需要改数据库结构。整个页面落地成本约 20 分钟但它让 IP 统计从“数据罗列”变成了“运营参考”我觉得是这类源码最典型的一次魔改。我习惯把每一次改动的文件清单和 SQL 更新记在项目根目录的 CHANGELOG 里方便后面重新部署时快速还原。魔改私人网盘这件事真正值钱的不是 zip 里原有的功能而是你亲手改过的那些小页面——每次新增一个自己真正用得上的报表或权限判断才算把这个通用开源源码变成了自己的系统。希望帮到你。本文还有配套的精品资源点击获取
返回列表