ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

PHP名片系统源码实战:从环境部署到二维码生成与二次开发

PHP名片系统源码实战:从环境部署到二维码生成与二次开发 简介这是一个基于PHP开发的名片管理系统完整源码包内置前端展示、后端业务逻辑与数据库脚本适合PHP初学者、Web开发者以及需要快速搭建名片管理功能的项目参考。源码包共146个文件体积约1.79MB以PHP、JavaScript、CSS文件为主体其中20个PHP文件负责路由与业务处理46个JS和23个CSS构建前端交互与界面样式另含less/scss源文件、字体图标及SQL初始数据等目录结构清晰便于按模块查阅。已有540人学习下载。通过阅读该源码可系统理解PHP项目分层架构、用户登录验证、名片数据的增删改查实现以及针对SQL注入和XSS攻击的常见防护手法同时还可参考部署配置与功能扩展思路如加入搜索、缓存或社交分享是一份能快速提升PHP实战能力的实用样例。1. 为什么一个 PHP 名片系统源码值得占你一个晚上拿到这份PHP名片系统源码.zip的时候我第一反应是“就一个名片管理能有多少东西”。真正解压跑起来才意识到这个小项目把 PHP 后端、数据库表设计、二维码生成、文件上传、登录会话全串起来了非常适合两类人一是刚把语法学完、想找个完整项目练手的 PHP 初学者二是公司预算有限、想用现成源码改一个内部客户管理工具的从业者。它解决的痛点很具体——纸质名片随手一塞就丢客户信息散在微信和通讯录里等要联系人的时候翻半天。这类系统通常不复杂但麻雀虽小五脏俱全拿它做二次开发起点比从零写省时间得多。本文后面所有内容都以这份源码里的实际结构为例展开。2. 把项目跑起来环境选型与目录结构拆解2.1 PHP 版本与扩展检查7.4 是底线8.x 要改兼容老 PHP 项目最常见的坑就是环境不匹配。这份名片系统源码我打开看了一遍代码风格属于典型的中期 PHP 写法——没用框架直接面向过程加少量类封装数据库用的是 mysqli。这种项目选 PHP 7.4 是最稳的8.0 以上能跑但会有不少Deprecated警告个别老函数在 8.0 直接被移除比如create_function()、each()如果源码里恰好用了页面会直接白屏。建议部署前先跑一遍下面这条命令确认当前 PHP 版本和已加载的扩展php -v php -m输出结果里重点看mysqli、pdo_mysql、gd、mbstring、openssl这几项。二维码生成依赖gd没有它后面第三章的二维码会输出一片空白mbstring管中文截断和编码转换名片里带中文姓名和公司名这个扩展不能缺。Windows 环境用 phpStudy 或小皮面板自带这些扩展Linux 下直接用 apt 或 yum 装对应包比如 Debian 系是apt install php7.4-mysql php7.4-gd php7.4-mbstring。装完记得重启 PHP-FPM 再验证一次。2.2 目录结构拆解入口文件、配置文件、上传目录解压后先把目录结构过一遍不要上来就拖进 Web 根目录。这套名片系统的标准布局大概是这样的目录/文件职责/admin/后台管理页面登录后的名片增删改查都在这里/api/前端调用的接口返回 JSON 数据/config/config.php数据库连接、站点 URL、上传路径等全局配置/includes/公共函数库、数据库连接类、Session 校验/uploads/名片照片与二维码图片的存放目录/sql/数据库初始化脚本一般是.sql文件index.php前台入口展示名片墙或名片详情有几个位置要特别留意。config.php是全局配置的黑匣子入口改数据库密码、改站点 URL 都在这里uploads目录必须保证 Web 服务进程可写否则上传头像和生成二维码都会报权限错误sql目录里通常只有一个建表脚本执行它就能把数据库结构拉起来。建议先把config.php里注释掉的配置项全部读一遍很多环境差异问题出在这个文件的默认值上。2.3 数据库初始化命令行导入和 phpMyAdmin 导入数据库脚本一般是sql/system.sql或者sql/card.sql这样的名字里面包含建库、建表、插入初始管理员账号的语句。导入方式三种我习惯用命令行干净利落mysql -u root -p source /path/to/sql/system.sql;执行完以后用show tables;确认表已经建出来。如果用 phpMyAdmin 导入注意导入前先创建好空数据库再选择目标数据库、点击导入按钮编码格式选utf8mb4。这里要说一个血的教训不要看 SQL 文件里有DROP TABLE IF EXISTS就直接执行在已有数据的生产库上这么干等于一键清空。导入前先打开 SQL 文件搜一下DROP确认这个表名和自己环境里没有冲突。初始化完成后还要核对config.php里的连接参数$db_host 127.0.0.1; $db_user root; $db_pass 你的密码; $db_name card_system; $db_charset utf8mb4;参数说明db_charset必须是utf8mb4不是utf8否则中文和 emoji 符号在存取时可能变问号。db_host在本地用127.0.0.1就行如果用localhost且 PHP 版本较老可能走 socket 连接导致连不上这时候换 IP 写法更省事。3. 名片管理核心模块增删改查与二维码生成3.1 名片数据表设计字段冗余与索引取舍看这套源码的建表语句核心表就是一张card表加一张category分类表。card表的字段设计非常有代表性几乎是名片系统的标准答案字段名类型说明idint(11) 主键自增名片唯一标识category_idint(11)所属分类namevarchar(50)姓名companyvarchar(100)公司/单位positionvarchar(50)职位phonevarchar(30)手机号emailvarchar(80)邮箱addressvarchar(200)地址avatarvarchar(200)头像图片路径qrcodevarchar(200)二维码图片路径statustinyint(1)启用状态 1/0created_atdatetime创建时间索引部分源码里给得比较保守只有主键。我自己的习惯是把category_id加一个普通索引因为列表页最常见的查询就是按分类筛选company字段如果要支持搜索加个普通索引能明显提升查询速度但也别加太多索引名片表数据量几千条时索引收益有限写操作反而变慢。字段冗余这一点avatar和qrcode存的是相对路径而不是图片二进制这是正确取舍数据库只存路径文件落磁盘查询压力小很多。3.2 新增和编辑名片PDO 预处理与防 XSS老源码多数用 mysqli 拼 SQL 字符串我拿到手后会统一改成 PDO 预处理这步改动不算大但能挡住大部分注入风险。新增名片的代码核心段落长这样$pdo new PDO( mysql:host$db_host;dbname$db_name;charset$db_charset, $db_user, $db_pass ); $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sql INSERT INTO card (category_id, name, company, position, phone, email, address, status, created_at) VALUES (:category_id, :name, :company, :position, :phone, :email, :address, :status, NOW()); $stmt $pdo-prepare($sql); $stmt-execute([ :category_id $_POST[category_id], :name htmlspecialchars($_POST[name], ENT_QUOTES, UTF-8), :company htmlspecialchars($_POST[company], ENT_QUOTES, UTF-8), :position htmlspecialchars($_POST[position], ENT_QUOTES, UTF-8), :phone htmlspecialchars($_POST[phone], ENT_QUOTES, UTF-8), :email htmlspecialchars($_POST[email], ENT_QUOTES, UTF-8), :address htmlspecialchars($_POST[address], ENT_QUOTES, UTF-8), :status isset($_POST[status]) ? 1 : 0 ]); $lastId $pdo-lastInsertId();逻辑说明bindValue和execute传参的效果一样我这里直接在execute里传关联数组:category_id这种命名占位符比?问号占位符可读性好得多。NOW()由数据库生成时间避免 PHP 时间函数和数据库时区不一致。htmlspecialchars是必须的名片数据最终要回显到 HTML 页面上不转义的话别人在姓名栏填一段script就能在你后台弹恶意脚本这是最基础的 XSS 防线。参数说明ENT_QUOTES表示单引号双引号都转义UTF-8要和数据库字符集保持一致。编辑操作就是把INSERT换成UPDATE ... WHERE id :id预处理方式完全一样这里不重复贴。3.3 二维码生成用 phpqrcode 类库还是手写 API名片系统的核心卖点之一是把名片信息生成二维码手机扫码直接存通讯录。源码里用的是phpqrcode类库这是一个很成熟的本地生成方案不依赖外部 API内网也能用。调用方式很简单require_once /path/to/phpqrcode/qrlib.php; $content BEGIN:VCARD . \n . VERSION:3.0 . \n . N: . $name . \n . ORG: . $company . \n . TITLE: . $position . \n . TEL: . $phone . \n . EMAIL: . $email . \n . ADR: . $address . \n . END:VCARD; QRcode::png($content, /uploads/qrcode/card_.$lastId..png, QR_ECLEVEL_M, 6);逻辑说明二维码里装的是 vCard 3.0 格式的字符串手机相机扫码后能直接识别成联系人这是名片场景的标准做法。QRcode::png()的第二个参数传了具体路径二维码图片直接落盘后面列表页只需要用img src引用路径不用每次请求都动态生成性能压力小很多。参数说明第三个参数是容错率QR_ECLEVEL_M表示中等容错二维码有 15% 区域被遮挡也能扫出来第四个参数 6 是放大倍数数字越大图片越清晰。如果发现扫码识别率低优先提高容错率到QR_ECLEVEL_H而不是盲目放大图片尺寸。3.4 列表分页与搜索SQL 拼接的正确姿势前台名片列表和后台管理列表都绕不开分页和搜索。分页的 SQL 模型是标准的$page max(1, (int)$_GET[page]); $pageSize 12; $offset ($page - 1) * $pageSize; $sql SELECT * FROM card WHERE status 1; $params [:status 1]; if (!empty($_GET[keyword])) { $sql . AND (name LIKE :kw1 OR company LIKE :kw2); $params[:kw1] % . $_GET[keyword] . %; $params[:kw2] % . $_GET[keyword] . %; } $sql . ORDER BY created_at DESC LIMIT $offset, $pageSize; $stmt $pdo-prepare($sql); $stmt-execute($params); $list $stmt-fetchAll(PDO::FETCH_ASSOC);逻辑说明$offset和$pageSize是整数强转过的不会引入注入面所以直接拼进 SQL 没有问题keyword部分用了预处理占位符LIKE里的%是拼在参数值里的不是拼在 SQL 模板里这点很关键——如果把%写进模板绑定参数就失效了。ORDER BY created_at DESC让最新添加的名片排前面符合使用习惯。参数说明max(1, (int)$_GET[page])防止用户把 page 号改成负数或非数字这是分页最容易忽略的边界。LIKE :kw1和LIKE :kw2不能共用一个参数名PDO 在部分驱动下复用命名占位符可能报错所以复制成两个参数。3.5 给前端返回 JSON数组转对象的正确姿势前台页面如果需要异步加载名片数据源码里通常有独立的 API 入口返回 JSON 格式。这里有个高频踩坑点就是 PHP 数组转 JSON 的中文编码问题$data [ code 0, msg success, data $list ]; echo json_encode($data, JSON_UNESCAPED_UNICODE);逻辑说明JSON_UNESCAPED_UNICODE参数让中文原样输出不加这个参数的话姓名和公司名会被转成\u5f20\u4e09这种 unicode 转义序列浏览器能解析但人眼没法排查问题。code字段用 0 表示成功非 0 表示各种错误码这是前后端接口的常见约定。配合前端fetch或 jQuery 的$.ajax就能完成页面局部刷新不需要整页跳转。如果后续要支持跨域调用再在响应头加Access-Control-Allow-Origin名片系统作为内部工具一般用不到但接移动端页面时要注意。4. 部署与排错避坑本地能跑不代表线上能活4.1 遇到mysql_connect()未定义错误现象页面直接白屏PHP 报Fatal error: Uncaught Error: Call to undefined function mysql_connect()。原因源码里用了 PHP 5 时代的mysql_*函数族这类函数在 PHP 7.0 被彻底移除换到 7.4 或 8.x 环境必然报错。解决把mysql_connect、mysql_query、mysql_fetch_array这系列函数统一改成mysqli或 PDO改动量大约一小时或者省事一点直接装 PHP 5.6 环境跑但我不推荐老版本漏洞太多内网用勉强可以对外提供服务风险太大。从这以后我看任何老项目第一步永远是搜代码里有没有mysql_开头的老函数。4.2 中文乱码显示成问号或方块现象前台页面和后台列表的中文都是???或乱码但数据库表里直接查是好的。原因三处字符集不一致——页面meta charset、PHP 连接数据库的字符集、数据库表本身的排序规则只要有一处是latin1或gbk就会乱。解决统一成utf8mb4数据库表和字段的排序规则改成utf8mb4_general_ciPHP 连接串加charsetutf8mb4页面头部写成meta charsetutf-8三处全部对齐。注意已存在的表要执行ALTER TABLE card CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;才能把存量数据捞回来。4.3 二维码生成一片空白或直接报 500现象点击生成二维码图片区域是碎的或空白后台日志报GD library extension not available。原因PHP 的gd扩展没装phpqrcode类库依赖 GD 库输出 PNG 图片。解决Windows 环境在 php.ini 里去掉extensiongd前的分号并重启 Web 服务Linux 用包管理器安装后重启 PHP-FPM。验证方式是在命令行执行php -m | grep gd有输出就表示加载成功。再补充一个冷门坑phpqrcode类库文件本身如果是从网上下载的注意类库版本要支持当前 PHP 版本老版本在 PHP 8 下可能因为each()函数报错直接下载新版类库替换即可。4.4 登录后台后 Session 频繁失效现象后台登录成功操作两分钟就跳回登录页刷新页面偶尔又好了。原因这个现象在 Linux 服务器上最常见本质是session.save_path指向的目录不存在或 Web 服务用户没有写权限PHP 无法正常读写 session 文件另一种可能是后台代码里手动设置了 session 超时时间。解决在config.php或入口文件里设置一个稳定的 session 保存路径并检查目录权限代码如下。session_save_path(/var/lib/php/sessions); if (!is_dir(/var/lib/php/sessions)) { mkdir(/var/lib/php/sessions, 0777, true); } ini_set(session.cookie_lifetime, 7200); ini_set(session.gc_maxlifetime, 7200); session_start();逻辑说明session_save_path必须指向 Web 服务进程有权限读写的目录否则 PHP 的 session 机制直接降级为无法保存状态。session.cookie_lifetime和session.gc_maxlifetime一起设为 7200 秒这是两个不同概念——前者是浏览器端 cookie 存活时间后者是服务器端 session 文件保留时间只设一个会造成“浏览器还在服务器已经删了 session”这种灵异现象。4.5 下载的 zip 解压后文件不完整或提示密码现象从网盘或论坛下载的PHP名片系统源码.zip用 Windows 自带解压工具解压到一半报错“文件损坏”或者解压出来的文件夹里少了sql目录再或者解压就要求输密码但压缩包介绍里没说有密码。原因压缩包可能带了伪加密标记——文件头里的加密标志位被动过手脚实际上没有加密但普通解压工具不认也可能是压缩包在传输过程中被下载工具“提前结束”导致索引区残缺。解决换工具Windows 上优先用 7-Zip它能识别一部分伪加密命令行用户用unzip -t先测试完整性再加-O处理编码。对于伪加密文件7-Zip 打开后如果能看到文件列表且能预览内容直接“提取”往往能跳过那个多余的加密标志如果确认伪加密但工具解不开可以尝试把文件头部第 7 到第 8 字节的加密标志位从01 00改成00 00再解但这是玄学操作成功率看运气更聪明的办法是找原发布人确认。这类问题在网上下老项目时极易翻车我现在的习惯是解压后先检查目录完整性重点看sql和config目录在不在再决定要不要往环境里拖。5. 二次开发的三个落地点把名片系统改成你自己的5.1 批量导出 CSVExcel 打开不乱码的关键一步名片系统上线跑一阵后最频繁的新需求是把名片导成表格交给销售或财务。源码里如果没带导出功能自己加一个不难。核心代码就是把查询结果拼成 CSV 输出header(Content-Type: text/csv; charsetutf-8); header(Content-Disposition: attachment; filenamecards_ . date(Ymd) . .csv); $fp fopen(php://output, w); fwrite($fp, \xEF\xBB\xBF); fputcsv($fp, [姓名, 公司, 职位, 手机, 邮箱]); foreach ($list as $row) { fputcsv($fp, [$row[name], $row[company], $row[position], $row[phone], $row[email]]); } fclose($fp);逻辑说明fwrite($fp, \xEF\xBB\xBF)这一行是关键它输出 UTF-8 BOM。Excel 默认用 ANSI 编码打开 CSV没有 BOM 时中文直接乱成一团加上 BOM 后 Excel 才能正确识别为 UTF-8。php://output把文件流直接写到响应里不产生临时文件数据量大时也更省磁盘。注意fputcsv默认用逗号分隔名片地址里有逗号时会自动加引号不用担心字段错位。5.2 手机端分页加载与微信内打开场景名片系统做完桌面端下一步常见需求是手机能访问。源码里的列表页如果是整页刷新的 PHP 渲染在手机上体验一般改造方式是把列表接口和数据渲染剥离开。一个省事的过渡方案是保留服务端渲染但做 UA 判断给手机单独输出窄版页面$ua $_SERVER[HTTP_USER_AGENT] ?? ; if (preg_match(/Mobile|Android|iPhone/i, $ua)) { $template templates/mobile_list.php; } else { $template templates/desktop_list.php; } include $template;逻辑说明这个方案不用动接口层只换模板工作量小适合名片系统这种页面结构简单的项目。如果后续要把名片页分享到微信里还需要做一件事确认页面标题、缩略图、描述能被微信的爬虫正确抓取也就是加og开头的 meta 标签否则分享出去只有光秃秃的链接没有卡片预览。另外注意微信内置浏览器对不带 SSL 证书的 HTTP 页面会拦截涉及到手机端访问尽早把站点切到 HTTPS。最后说一个我自己的习惯。每次拿到这种老 PHP 项目我先不急着往服务器上拖第一步永远是在本地跑通然后把config.php全量读一遍再搜索代码里有没有mysql_、create_function、eval这三个关键词任何项目只要中了其中一个后面必然有坑等着。这套动作做多了以后踩坑次数明显下降。这份名片系统源码在我手里跑通加二次改造差不多用了半个工作日希望帮到你。本文还有配套的精品资源点击获取
返回列表