这是一个非常常见的需求,尤其是在移动端或者追求极致用户体验的场景下,用户无需注册或登录,直接填写收货信息和订单备注即可完成下单。

(图片来源网络,侵删)
核心思路
免登录提交订单的本质是 “临时创建用户”,流程如下:
- 用户进入提交订单页面:系统判断用户是否登录,如果未登录,则显示一个简化的注册/登录表单,或者直接显示一个纯订单信息填写表单。
- 填写订单信息:用户填写收货人、电话、地址、商品信息等。
- 创建临时用户:在后端处理逻辑中,系统会根据用户填写的手机号或邮箱,自动在
dede_member表中创建一个新用户,为了区分,这个用户的mtype字段可以设置为一个特殊值('temp'),userid和pwd字段可以设置为手机号或邮箱的哈希值,或者一个随机字符串。 - 关联订单与临时用户:在创建订单时,将这个临时用户的
uid关联到订单记录中。 - 完成下单:订单创建成功后,可以提示用户“下单成功,请使用手机号登录查看订单详情”,并引导其完善个人信息或进行支付。
详细实现步骤
我们将分步实现这个功能,主要涉及修改模板文件和修改PHP处理文件。
第一步:准备订单提交页面模板
订单提交页面是 plus/cartridge.php,我们需要修改这个文件,使其在用户未登录时也能显示订单信息表单。
-
修改
plus/cartridge.php文件:
(图片来源网络,侵删)在文件开头,找到检查登录状态的代码,并将其注释掉或修改,在包含订单表单的模板之前,加入我们自己的逻辑。
<?php require_once(dirname(__FILE__)."/../include/config_base.php"); require_once(DEDEINC."/membermodel.cls.php"); require_once(DEDEINC.'/shopcar.class.php'); require_once(DEDEINC.'/dedetemplate.class.php'); // 检查用户是否登录,如果未登录,我们不直接跳转,而是继续执行下面的逻辑 // if($cfg_ml->IsLogin()) { // // 已登录用户逻辑... // } else { // // 未登录用户逻辑... // } $cart = new MemberShopsCart(); if(empty($cart->fields)) { ShowMsg("您的购物车是空的,请先去购物!", 'javascript:;'); exit(); } // 获取收货地址列表(这里可以修改,只获取已登录用户的地址,或者显示一个公共地址列表) // $addrs = $cart->GetAddressList(); $dsql = new DedeSql(false); $row = $dsql->GetOne("SELECT * FROM #@shop_config"); unset($dsql); $templet = $cfg_basedir.$cfg_templets_dir."/plus/cartridge.htm"; $dtp = new DedeTemplate(); $dtp->LoadTemplate($templet); $dtp->Display(); ?> -
修改订单提交模板
templets/plus/cartridge.htm:在这个模板中,我们需要确保即使没有登录,也能正常显示订单信息,关键在于传递
mid(用户ID) 给后续的处理页面。在模板中找到处理订单的表单,确保它存在并正确。
(图片来源网络,侵删)<form name='orderform' action='cartridge.php?dopost=send' method='post'> <!-- 这里是购物车商品列表 --> <!-- ... --> <!-- 收货人信息 --> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td height="30" colspan="2" style="font-weight:bold;">收货人信息</td> </tr> <tr> <td width="20%" height="28">收货人姓名:</td> <td> <input type='text' name='usernames' id='usernames' size='30' class='intxt' style='width:250px' /> </td> </tr> <tr> <td height="28">联系电话:</td> <td> <input type='text' name='user tel' id='user tel' size='30' class='intxt' style='width:250px' /> </td> </tr> <tr> <td height="28">电子邮箱:</td> <td> <input type='text' name='email' id='email' size='30' class='intxt' style='width:250px' /> </td> </tr> <tr> <td height="28">收货地址:</td> <td> <textarea name='address' id='address' rows='3' cols='60' style='width:400px;'></textarea> </td> </tr> <tr> <td height="28">订单备注:</td> <td> <textarea name='message' id='message' rows='3' cols='60' style='width:400px;'></textarea> </td> </tr> </table> <!-- 关键:传递用户ID,如果未登录,则留空,由后端处理 --> <input type="hidden" name="mid" value="<?php echo $cfg_ml->M_ID; ?>" /> <div style="margin-top:20px; text-align:center;"> <button type="submit" name="submit" class="btn btn-primary">提交订单</button> </div> </form>
第二步:修改订单处理逻辑
这是最关键的一步,我们需要修改 plus/cartridge.php 中处理 dopost=send 的部分。
-
在
plus/cartridge.php中找到send处理分支:这个分支通常在文件末尾,我们将重写这部分代码。
-
编写核心处理逻辑:
逻辑是:检查
mid是否为空,如果为空,则根据手机号或邮箱创建一个临时用户,然后获取其uid,再继续创建订单。// ... 文件前面的代码 ... // 处理订单提交 if($dopost == 'send') { // 1. 获取表单数据 $usernames = trim($_POST['usernames']); $usertel = trim($_POST['usertel']); $email = trim($_POST['email']); $address = trim($_POST['address']); $message = trim($_POST['message']); $mid = isset($_POST['mid']) ? intval($_POST['mid']) : 0; // 基本验证 if(empty($usernames) || empty($usertel) || empty($address)) { ShowMsg("请填写完整的收货人信息!", '-1'); exit(); } // 2. 核心逻辑:如果用户未登录,则创建临时用户 if(empty($mid) || !$cfg_ml->IsLogin()) { // 检查手机号是否已注册 $dsql->SetQuery("SELECT uid FROM `#@__member` WHERE mobilephone = '$usertel' OR userid = '$usertel'"); $dsql->Execute(); if($row = $dsql->GetArray()) { // 如果手机号已存在,直接使用该用户 $mid = $row['uid']; } else { // 手机号不存在,创建一个新用户 $pwd = md5($usertel); // 密码设为手机号MD5值,用户可后续修改 $uname = $usertel; // 用户名也设为手机号 $mtype = 'temp'; // 标记为临时用户 $inQuery = "INSERT INTO `#@__member`(`mtype`, `userid`, `pwd`, `uname`, `email`, `mobilephone`, `jointime`, `joinip`) VALUES ('$mtype', '$uname', '$pwd', '$usernames', '$email', '$usertel', '".time()."', '".GetIP()."')"; $dsql->ExecuteNoneQuery($inQuery); if($dsql->GetErrorNum() > 0) { ShowMsg("创建用户失败,请联系管理员!", '-1'); exit(); } $mid = $dsql->GetLastID(); // 获取新创建用户的ID } } // 3. 创建订单 (这部分代码可以参考原DedeCMS的订单创建逻辑,通常在member/shops_action.php等文件里) // 这里简化了订单创建过程,你需要根据你的实际订单表结构和创建逻辑来完善 $money = $cart->GetPriceCount(); // 获取订单总金额 $order_sn = 'DD'.date('YmdHis').rand(1000, 9999); // 生成唯一订单号 $orderQuery = "INSERT INTO `#@__member_shops_order`(`order_sn`, `mid`, `usernames`, `email`, `tel`, `address`, `money`, `dtime`, `ptotal`, `message`) VALUES ('$order_sn', '$mid', '$usernames', '$email', '$usertel', '$address', '$money', '".time()."', '0', '$message')"; $dsql->ExecuteNoneQuery($orderQuery); if($dsql->GetErrorNum() > 0) { ShowMsg("创建订单失败,请联系管理员!", '-1'); exit(); } $oid = $dsql->GetLastID(); // 4. 清空购物车 $cart->ClearCart(); // 5. 跳转到支付或成功页面 ShowMsg("订单提交成功!订单号:".$order_sn.",请使用手机号 ".$usertel." 登录并支付。", '/member/index.php?uid='.$mid); // 跳转到用户中心 exit(); }
第三步:安全性与用户体验优化
-
安全性:
- 数据过滤:所有从表单获取的数据(
$_POST)都必须经过trim()和htmlspecialchars()等函数处理,防止XSS攻击。 - SQL注入:DedeCMS 的
$dsql类已经做了基本的防注入处理,但使用SetQuery时,如果涉及变量拼接,最好使用$dsql->SetQuery("SELECT ... WHERE id = {$id}")这种方式,让Dede自行处理。 - 密码安全:临时用户的密码使用了
md5加密,虽然md5已不推荐用于密码存储,但对于临时用户来说,这已经足够,你可以使用password_hash和password_verify来增强安全性,但这需要修改会员登录验证逻辑。
- 数据过滤:所有从表单获取的数据(
-
用户体验:
- 提示信息:下单成功后,明确告知用户订单号,并告知其如何登录(使用手机号/邮箱)。
- 自动登录:在创建临时用户后,可以尝试模拟登录,让用户直接进入登录状态,这需要调用
cfg_ml->PutLoginInfo()等方法,逻辑稍复杂,但体验更好。 - 支付集成:订单创建成功后,应立即跳转到支付页面(如支付宝、微信支付),而不是仅仅显示一个成功消息,这需要你集成相应的支付SDK或调用DedeCMS自带的支付接口。
实现 DedeCMS 免登录提交订单的核心步骤可以概括为:
- 修改模板:让订单提交页面在未登录时也能显示,并传递一个空的
mid。 - 修改PHP逻辑:在订单处理的后端代码中,判断
mid是否为空,如果为空,则根据用户填写的手机号/邮箱自动创建一个mtype='temp'的临时用户,并获取其uid。 - 关联订单:将这个新用户的
uid作为mid存入订单表中,完成订单与用户的关联。 - 优化与安全:完善数据验证、错误处理,并考虑如何提升用户体验(如提示登录、引导支付)。
这个方案提供了一个完整的实现思路,你可以根据自己网站的具体情况进行调整和扩展。
