PHP中register_globals = On的问题

本文介绍在PHP中如何正确配置全局变量以避免潜在的命名冲突问题,尤其是在启用了register_globals选项时。建议使用特定前缀来区分不同的数据来源,并提供了一个关于如何在URL参数和会话变量间保持一致性的示例。

在php.ini中配置了register_globals = On后,

_GET, _POST, _SESSION最好起不同的变量名;如url.php?city=beijing时,url中最好取gcity=beijing;

通过$city = $_GET['gcity']; $_SESSION['scity'] =  $_GET['gcity']; 

也就是说$city最好别和$_GET或$_POST时的city=重名.

否则有时候会出现莫名其妙的问题(php默认把url中的city赋值给$city,即使你没使用$city = $_GET['city']),而_SESSION的命名最好改为数组,如$_SESSION['item']['city'].

<?php /** * 鸿宇多用户商城 在线客服聊天系统-前台 * ============================================================================ * 版权所有 2015-2018 鸿宇多用户商城科技有限公司,并保留所有权利。 * 网站地址: http://bbs.hongyuvip.com; * ---------------------------------------------------------------------------- * 仅供学习交流使用,如需商用请购买正版版权。鸿宇不承担任何法律责任。 * 踏踏实实做事,堂堂正正做人。 * ============================================================================ * $Author: 鸿宇多用户商城 $ * $Id: category.php 17217 2015-02-10 06:29:08Z 鸿宇多用户商城 $ */ define('IN_ECS', true); require ('includes/init.php'); require ('includes/lib_chat.php'); /* 载入语言文件 */ require_once (ROOT_PATH . 'languages/' . $_CFG['lang'] . '/user.php'); $action = isset($_REQUEST['act']) ? trim($_REQUEST['act']) : 'chat'; /* 检查用户是否已登录 */ if(empty($_SESSION['user_id']) && $action != 'act_login' && $action != 'check_login') { // $captcha = intval($_CFG['captcha']); // if(($captcha & CAPTCHA_LOGIN) && (! ($captcha & CAPTCHA_LOGIN_FAIL) || (($captcha & CAPTCHA_LOGIN_FAIL) && $_SESSION['login_fail'] > 2)) && gd_version() > 0) // { // $GLOBALS['smarty']->assign('enabled_captcha', 1); // $GLOBALS['smarty']->assign('rand', mt_rand()); // } // 如果未登录跳转到登录页面 /** $smarty->assign('lang', $_LANG); $smarty->assign('back_act', ''); $smarty->assign('action', 'login'); $smarty->display('chat_passport.dwt'); **/ show_message('您还未登录系统,请先登录!', array('登录', '返回上一页'), array('user.php?act=login', 'index.php'), 'info'); return; } //路由 $function_name = 'action_' . $action; if(function_exists($function_name)) { call_user_func($function_name); } else { exit('函数' . $function_name . '不存在'); } /** * 检查用户是否登录 */ function action_check_login() { $is_login = empty($_SESSION['user_id']) ? 'false' : 'true'; exit($is_login); } /** * 处理会员登录 */ function action_act_login () { $user_id = $_SESSION['user_id']; $smarty = get_smarty(); $ecs = get_ecs(); $db = get_database(); /* 处理会员的登录 */ $username = isset($_POST['username']) ? trim($_POST['username']) : ''; $password = isset($_POST['password']) ? trim($_POST['password']) : ''; $back_act = isset($_POST['back_act']) ? trim($_POST['back_act']) : ''; $captcha = intval($_CFG['captcha']); if(($captcha & CAPTCHA_LOGIN) && (! ($captcha & CAPTCHA_LOGIN_FAIL) || (($captcha & CAPTCHA_LOGIN_FAIL) && $_SESSION['login_fail'] > 2)) && gd_version() > 0) { if(empty($_POST['captcha'])) { $smarty->assign('lang', $_LANG); $smarty->assign('action', 'login'); $smarty->assign('error', $_LANG['invalid_captcha']); $smarty->display('chat_passport.dwt'); return; } /* 检查验证码 */ include_once ('includes/cls_captcha.php'); $validator = new captcha(); $validator->session_word = 'captcha_login'; if(! $validator->check_word($_POST['captcha'])) { $smarty->assign('lang', $_LANG); $smarty->assign('action', 'login'); $smarty->assign('error', $_LANG['invalid_captcha']); $smarty->display('chat_passport.dwt'); return; } } if(is_email($username)) { $sql = "select user_name from " . $ecs->table('users') . " where email='" . $username . "'"; $username_e = $db->getOne($sql); if($username_e) $username = $username_e; } if(is_telephone($username)) { $sql = "select user_name from " . $ecs->table('users') . " where mobile_phone='" . $username . "'"; $username_res = $db->query($sql); $kkk = 0; while($username_row = $db->fetchRow($username_res)) { $username_e = $username_row['user_name']; $kkk = $kkk + 1; } if($kkk > 1) { $smarty->assign('lang', $_LANG); $smarty->assign('action', 'login'); $smarty->assign('error', '本网站有多个会员ID绑定了和您相同的手机号,请使用其他登录方式,如:邮箱或用户名。'); $smarty->display('chat_passport.dwt'); return; } if($username_e) { $username = $username_e; } } if($GLOBALS['user']->login($username, $password, isset($_POST['remember']))) { update_user_info(); recalculate_price(); // 登录成功 $ucdata = isset($user->ucdata) ? $user->ucdata : ''; // show_message($_LANG['login_success'] . $ucdata , // array($_LANG['back_up_page'], $_LANG['profile_lnk']), // array($back_act,'user.php'), 'info'); // 刷新user_id $user_id = $_SESSION['user_id']; header('Location: chat.php?act=chat'); } else { $_SESSION['login_fail'] ++; $smarty->assign('lang', $_LANG); $smarty->assign('action', 'login'); $smarty->assign('error', $_LANG['login_failure']); $smarty->display('chat_passport.dwt'); return; } } /* ------------------------------------------------------ */ // -- 在线客服聊天 --> 请求聊天 // 聊天窗口右侧默认展示最近订单,如果想要展示商品、订单、店铺则需要在当前页面中设置隐藏域,name必须为 chat_goods_id, // chat_order_id, chat_supp_id /* ------------------------------------------------------ */ function action_chat () { $user_id = $_SESSION['user_id']; $smarty = get_smarty(); $ecs = get_ecs(); $db = get_database(); /** * 判断当前用户是为聊天系统的注册用户 */ $exist = check_of_username_exist($user_id); // 获取用户头像 if(! empty($user_id)) { $sql = "select password, headimg from " . $ecs->table('users') . " where user_id = '$user_id'"; $row = $db->getRow($sql); $headimg = $row['headimg']; $password = $row['password']; $smarty->assign('headimg', $headimg); } if(! $exist) { // 查询ECShop内用户信息 $sql = 'select a.user_id, a.password, a.email, a.user_name from ' . $ecs->table('users') . ' AS a where a.user_id = "' . $user_id . '"'; $user = $GLOBALS['db']->getRow($sql); if(empty($user)) { // 根据user_id未查找到任何用户信息 } // 用户不存在,创建用户信息 $username = $user_id; $password = $user['password']; $name = $user['user_name']; $email = $user['email']; $type = 10; $shop_id = - 1; // $result = create_of_user($username, $password, $name, $email, $type, $shop_id);(修改前)) $of_password = md5($password); $result = create_of_user($username, $of_password, $name, $email, $type, $shop_id); if($result) { // 创建成功 } else { // 创建失败 } } // 获取前端传来的商品编号、订单编号、店铺编号等 // 商品编号则显示商品信息 // 订单编号则显示订单信息 // 店铺编号则显示店铺信息 $goods_id = null; $supp_id = - 1; $order_id = null; $customers = null; // 获取客服信息 $tab_items = array(); // 客服类型 $cus_types = CUSTOMER_SERVICE; // 记录需要发给客服的URL if(! empty($_REQUEST['chat_goods_id'])) { /* 咨询商品信息 */ $goods_id = $_REQUEST['chat_goods_id']; $goods = goods_info($goods_id); $smarty->assign('chat_goods', $goods); $smarty->assign('chat_goods_id', $goods_id); $tab_items[] = array( "id" => "chat_goods","name" => "咨询商品" ); // 客服+售前 $cus_types = CUSTOMER_SERVICE . ',' . CUSTOMER_PRE; } if(! empty($_REQUEST['chat_order_id'])) { /* 咨询订单信息 */ require ('includes/lib_order.php'); $order_id = $_REQUEST['chat_order_id']; // 获取商品和店铺信息 $goods_id = null; $order = order_info($order_id); $supp_id = $order['supplier_id']; $order['order_status_text'] = $GLOBALS['_LANG']['os'][$order['order_status']] . ',' . $GLOBALS['_LANG']['ps'][$order['pay_status']] . ',' . $GLOBALS['_LANG']['ss'][$order['shipping_status']]; $order['goods_list'] = order_goods($order_id); $smarty->assign('chat_order', $order); $smarty->assign('chat_order_id', $order_id); $smarty->assign('chat_order_sn', $order['order_sn']); $tab_items[] = array( "id" => "chat_order","name" => "咨询订单" ); // 客服+售后 $cus_types = CUSTOMER_SERVICE . ',' . CUSTOMER_AFTER; } if(! empty($_REQUEST['chat_supp_id']) && $_REQUEST['chat_supp_id'] != 0) { /* 店铺信息 */ $supp_id = $_REQUEST['chat_supp_id']; $supp_info = get_dianpu_baseinfo($supp_id); $smarty->assign('supp_info', $supp_info); $smarty->assign('chat_supp_id', $supp_id); $tab_items[] = array( "id" => "chat_supp", "name" => "店铺信息" ); // 客服+售前 $cus_types = CUSTOMER_SERVICE . ',' . CUSTOMER_PRE; } if(true) { /* 最近订单列表 */ require ('includes/lib_transaction_1.php'); // 获取用户最近的5条订单列表 $order_list = get_user_orders_1($user_id, 5, 0); // 所有客服忙碌状态,提示web端 $smarty->assign('order_list', $order_list); $smarty->assign('order_count', count($order_list)); $tab_items[] = array( "id" => "chat_order_list","name" => "最近订单" ); // 客服 $cus_types = CUSTOMER_SERVICE; } // 获取客服信息 $customers = get_customers($cus_types, $supp_id); // 转换为JSON数据 $smarty->assign('tab_items', json_encode($tab_items)); $to = null; // 客服获取策略:0-顺序、1-随机、2-竞争 if(! empty($customers)) { // 暂时采用随机策略 $poliy = 1; if($poliy == 0) { foreach($customers as $customer) { $status = $customer['status']; if($status == '在线' || $status == '空闲') { $to = $customer; break; // if(isset($customer['cus_status']) && count($customers) > 1) // { // if(time() - $customer['chat_time'] > 5*60) // { // set_customer_status($customer['cus_id'], 0); // $customer['cus_status'] = 0; // } // if($customer['cus_status'] == 0) // { // $to = $customer; // break; // } // } // else // { // $to = $customer; // break; // } } } } else if($poliy == 1) { /* 随进策略 */ $onlines = array(); foreach($customers as $customer) { $status = $customer['status']; if($status == '在线' || $status == '空闲') { $onlines[] = $customer; } } if(count($onlines) > 0) { $min = 1; $max = count($onlines); $i = mt_rand($min, $max); $to = $onlines[$i - 1]; } } else { } if(empty($to)) { if($supp_id == -1){ // 所有客服忙碌状态,提示web端 $smarty->assign('system_notice', '当前客服忙碌,请稍后联系!'); }else{ // 所有客服忙碌状态,提示web端 $smarty->assign('system_notice', '当前店铺客服忙碌,请稍后联系!'); } } else { $xmpp_domain = get_xmpp_domain(); $_SESSION['OF_FROM'] = $user_id . '@' . $xmpp_domain; $_SESSION['OF_TO'] = $to['of_username'] . '@' . $xmpp_domain; $smarty->assign('from', $_SESSION['OF_FROM']); $smarty->assign('password', $password); // $smarty->assign('password', "123456"); // $smarty->assign('to', '==to=='); // 传递正确的客服JID给前端 $smarty->assign('to', $_SESSION['OF_TO']); $smarty->assign('username', $_SESSION['user_name']); $smarty->assign('customername', $to['cus_name']); // 存储在Session中方便其他地方使用 // 所有客服忙碌状态,提示web端 $smarty->assign('system_notice', '客服<span class="kf_name">' . $to['cus_name'] . '</span>已加入会话!'); } } else { // 所有客服忙碌状态,提示web端 $smarty->assign('system_notice', '当前客服忙碌,请稍后联系!'); } // 打开聊天页面 $smarty->display('chat.dwt'); } /* ------------------------------------------------------ */ // -- 在线客服聊天 --> 认证失败,重新设置聊天系统的用户密码 // 聊天窗口右侧默认展示最近订单,如果想要展示商品、订单、店铺则需要在当前页面中设置隐藏域,name必须为 chat_goods_id, // chat_order_id, chat_supp_id /* ------------------------------------------------------ */ function action_authfail () { $user_id = $_SESSION['user_id']; $sql = "select user_name, password, email from " . $GLOBALS['ecs']->table('users') . " where user_id = '$user_id'"; $row = $db->getRow($sql); $success = create_of_user($user_id, $row['password'], $row['user_name'], $row['email'], 10, - 1); if($success) { $result = array( 'error' => 1,'message' => '可能由于网络原因,发生错误!请点击 <a href="chat.php?act=chat"><strong>重试</strong></a> ,重新连接...','content' => '' ); } else { $result = array( 'error' => 1,'message' => '由于网络原因,发生错误!请点击 <a href="chat.php?act=chat"><strong>重试</strong></a> ,重新连接...','content' => '' ); } $result = json_encode($result); exit($result); } /** * 用户离线 */ function action_off_line() { // 用户超过5分钟未发言则视为自动离线,更新客服状态 } function is_telephone ($phone) { $chars = "/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$/"; if(preg_match($chars, $phone)) { return true; } } /** * 获取db对象 * * @return unknown */ function get_database () { return $GLOBALS['db']; } /** * 获取smarty对象 * * @return unknown */ function get_smarty () { return $GLOBALS[smarty]; } /** * 获取ecs对象 * * @return unknown */ function get_ecs () { return $GLOBALS['ecs']; } /* * 获取商品所对应店铺的店铺基本信息 * @param int $suppid 店铺id * @param int $suppinfo 入驻商的信息 */ function get_dianpu_baseinfo ($suppid = 0) { if(intval($suppid) <= 0) { return; } $sql_supplier = "SELECT s.supplier_id,s.supplier_name,s.add_time,sr.rank_name FROM " . $GLOBALS['ecs']->table("supplier") . " as s left join " . $GLOBALS['ecs']->table("supplier_rank") . " as sr ON s.rank_id=sr.rank_id WHERE s.supplier_id=" . $suppid . " AND s.status=1"; $supp_info = $GLOBALS['db']->getRow($sql_supplier); $sql = "SELECT * FROM " . $GLOBALS['ecs']->table('supplier_shop_config') . " WHERE supplier_id = " . $suppid; $shopinfo = $GLOBALS['db']->getAll($sql); $config = array(); foreach($shopinfo as $value) { $config[$value['code']] = $value['value']; } $shop_info = array(); $shop_info['ghs_css_path'] = 'themes/' . $config['template'] . '/images/ghs/css/ghs_style.css'; // 入驻商所选模板样式路径 $shoplogo = empty($config['shop_logo']) ? 'themes/' . $config['template'] . '/images/dianpu.jpg' : $config['shop_logo']; $shop_info['shoplogo'] = $shoplogo; // 商家logo $shop_info['shopname'] = htmlspecialchars($config['shop_name']); // 店铺名称 $shop_info['suppid'] = $suppid; // 商家名称 $shop_info['suppliername'] = htmlspecialchars($supp_info['supplier_name']); // 商家名称 $shop_info['userrank'] = htmlspecialchars($supp_info['rank_name']); // 商家等级 $shop_info['region'] = get_province_city($config['shop_province'], $config['shop_city']); $shop_info['address'] = $config['shop_address']; $shop_info['serviceqq'] = $config['qq']; $shop_info['serviceww'] = $config['ww']; $shop_info['serviceemail'] = $config['service_email']; $shop_info['servicephone'] = $config['service_phone']; $shop_info['createtime'] = gmdate('Y-m-d', $config['add_time']); // 商家创建时间 $suppid = (intval($suppid) > 0) ? intval($suppid) : intval($_GET['suppId']); return $shop_info; function get_xmpp_domain() { return 'yfw.szrengjing.com'; // 替换为你的Openfire服务器域名 } } ?>
最新发布
11-11
你提供的是一个 **鸿宇多用户商城系统(基于 ECShop)的在线客服聊天模块 PHP 后端代码**,它实现了: - 用户登录检查 - 自动创建 XMPP 聊天账号(如 Openfire 或 Prosody 用户) - 获取订单、商品、店铺信息用于会话上下文 - 客服分配策略(随机/顺序) - 与前端 JSXC 或自定义 WebIM 客户端通信 --- ## ✅ 当前目标分析 你已经: 1. ✅ 部署了 `JSXC` 并构建成功 2. ✅ 运行了 `Prosody`,BOSH 可用 (`https://szrengjing.com:5281/http-bind/`) 3. ✅ 提供了一个完整的商城系统 `chat.php` 路由逻辑 现在你需要: ➡️ **将这个商城系统的 `chat.php` 页面连接到 Prosody XMPP 服务器,实现 Web 在线客服功能** --- ## 🧩 第一步:修复并完善你的 PHP 代码问题 ### ❌ 问题 1:`get_xmpp_domain()` 函数定义在错误位置 你在 `get_dianpu_baseinfo()` 函数内部定义了 `get_xmpp_domain()`,这是语法错误! #### 🔧 修复方法: 将该函数移出,并放在文件顶层或合适位置: ```php /** * 获取XMPP服务器域名 */ function get_xmpp_domain() { return 'szrengjing.com'; // 改为你的实际域名(必须和 Prosody VirtualHost 一致) } ``` > ⚠️ 注意:不要写成 `yfw.szrengjing.com` 除非你在 Prosody 中配置了这个虚拟主机。 --- ### ❌ 问题 2:密码加密方式不匹配 你用了: ```php $of_password = md5($password); $result = create_of_user($username, $of_password, $name, $email, $type, $shop_id); ``` 但大多数 XMPP 服务(包括 Prosody)默认使用 **SHA-1 + salt** 或明文存储。MD5 不一定被支持。 #### ✅ 解决方案一:使用明文密码(推荐调试阶段) Prosody 支持明文密码,你可以直接传原始密码(即数据库中的 `$row['password']`): ```php // 假设 ECShop 密码是 MD5 加密的 $raw_password = $_POST['password']; // 登录时获取原始输入密码 // 或者从 session 记录原始密码(注意安全) ``` > 更佳做法是在用户登录后保存一份加密后的版本给 XMPP 使用。 #### ✅ 解决方案二:让 Prosody 支持 MD5(不推荐) 修改 `/etc/prosody/prosody.cfg.lua`: ```lua authentication = "internal_hashed" ``` 然后手动插入用户时使用 MD5 存储(需自定义脚本)。 --- ### ✅ 补充建议:确保 `create_of_user()` 实际可用 你调用了 `create_of_user(...)`,但它没有出现在代码中。 这应该是你自己的库函数,位于 `includes/lib_chat.php` 中。 请确认其内容类似如下: ```php // includes/lib_chat.php function create_of_user($username, $password, $name, $email, $type, $shop_id) { // 示例:调用 Openfire REST API 或直接写入 Prosody 数据库 $url = "http://localhost:9090/plugins/restapi/v1/users"; // Openfire REST API $headers = [ 'Authorization: Bearer YOUR_API_TOKEN', 'Content-Type: application/json' ]; $data = json_encode([ 'username' => $username, 'password' => $password, 'name' => $name, 'email' => $email ]); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $http_code == 201 || $http_code == 409; // 409 已存在也算成功 } ``` ⚠️ 如果你用的是 **Prosody**,可以用 Lua 脚本或 CLI 创建用户: ```bash prosodyctl register user szrengjing.com yourpassword ``` 或者通过 PHP 执行命令(慎用): ```php exec("sudo -u prosody prosodyctl register {$username} szrengjing.com '{$password}'", $output, $ret); return $ret === 0; ``` --- ## 🚀 第二步:修改 `chat.dwt` 模板文件以集成 JSXC 你现在只提供了 PHP 后端,还需要修改前端模板 `chat.dwt` 来加载 JSXC。 ### 编辑:`themes/your_theme/chat.dwt` ```html <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <title>在线客服</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <link rel="stylesheet" href="/jsxc/css/jsxc.bundle.css" /> <style> body { font-family: Arial, sans-serif; } #jsxc_root { position: fixed; bottom: 0; right: 0; z-index: 9999; width: 350px; height: 500px; } .sidebar { margin-top: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; background: #f9f9f9; } </style> </head> <body> <h2>欢迎来到在线客服中心</h2> <div class="sidebar"> {if $system_notice} <p>{$system_notice}</p> {/if} {if $chat_goods} <h3>咨询商品:<a href="goods.php?id={$chat_goods.goods_id}">{$chat_goods.goods_name}</a></h3> <img src="{$chat_goods.goods_thumb}" width="80" /> {/if} {if $chat_order} <h3>订单号:{$chat_order_sn}</h3> <p>状态:{$chat_order.order_status_text}</p> {/if} {if $order_list} <h3>最近订单</h3> <ul> {foreach from=$order_list item=order} <li><a href="user.php?act=order_detail&order_id={$order.order_id}">{$order.order_sn}</a></li> {/foreach} </ul> {/if} </div> <!-- JSXC 容器 --> <div id="jsxc_root"></div> <!-- 加载 JSXC --> <script src="/jsxc/js/jsxc.bundle.min.js"></script> <script> $(function() { const from = '{$from}'; // e.g., user123@szrengjing.com const to = '{$to}'; // e.g., kefu1@szrengjing.com const password = '{$password}'; const domain = 'szrengjing.com'; JSXC.init({ loginForm: { enabled: false }, xmpp: { url: 'https://szrengjing.com/http-bind/', // Nginx 代理后的地址 domain: domain, resource: 'web', overwrite: true }, root: '/jsxc', ui: { enableNotifications: false, hideOfflineContacts: true, allowContactAddition: false, allowContactDelete: false, allowSettingsSave: false }, onReady: function() { console.log('JSXC ready, starting session...'); JSXC.start(from, password); } }); // 监听连接事件 $(document).on('connected.jsxc', function() { console.log('Connected as:', from); // 发送一条欢迎消息给客服 setTimeout(() => { JSXC.postMessage(to, '您好,我想咨询一下订单或商品相关问题。'); }, 2000); }); }); </script> </body> </html> ``` --- ## 🔐 第三步:确保 HTTPS 和证书正确 由于你在使用 `https://szrengjing.com/http-bind/`,必须满足: 1. ✅ 网站全站启用 HTTPS 2. ✅ Nginx 正确代理 `/http-bind` 到 Prosody 的 `5281` 端口 3. ✅ 浏览器信任证书(不能是自签名) ### 推荐 Nginx 配置(再次强调): ```nginx server { listen 443 ssl; server_name szrengjing.com; ssl_certificate /www/server/panel/vhost/cert/szrengjing.com/fullchain.pem; ssl_certificate_key /www/server/panel/vhost/cert/szrengjing.com/privkey.pem; location /http-bind { proxy_pass http://127.0.0.1:5281/http-bind; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location / { root /www/wwwroot/szrengjing.com; index index.php; } location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/var/run/php/php74-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } ``` 重启 Nginx: ```bash systemctl restart nginx ``` --- ## 👤 第四步:创建测试客服账号 运行: ```bash sudo prosodyctl register kefu1 szrengjing.com 123456 sudo prosodyctl register kefu2 szrengjing.com 123456 ``` 并在数据库中添加对应的客服记录,确保 `get_customers()` 能查到这些 JID。 例如,在你的客服表中插入: | cus_id | cus_name | of_username | status | |--------|----------|-------------|--------| | 1 | 张客服 | kefu1 | 在线 | | 2 | 李客服 | kefu2 | 空闲 | 这样 `action_chat()` 才能正确分配。 --- ## ✅ 最终流程验证 1. 用户登录商城 → 进入 `chat.php` 2. PHP 检查是否已在 XMPP 注册,若无则调用 `create_of_user(...)` 3. 分配一位“在线”的客服(JID) 4. Smarty 渲染 `chat.dwt`,注入 `from`, `to`, `password` 5. JSXC 初始化并自动登录 6. 成功连接 Prosody,建立聊天会话 --- ## 💡 进阶优化建议 | 功能 | 实现方式 | |------|---------| | 自动发送订单链接 | 在 `onReady` 后发送 `<a href="...">订单详情</a>` | | 客服离线转留言 | 检测 `status != 在线` 时弹出留言表单 | | 消息持久化 | 启用 Prosody 的 `mod_mam` 模块 | | 多租户隔离 | 用 `supp_id@szrengjing.com` 作为房间名 | | 移动端适配 | 使用 [Converse.js](https://conversejs.org) 替代 JSXC | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值