WHMCS 下单 Dedicated/VPS Server 产品默认要填几个选项,包括设置主机名、密码、NS 地址,用户体验很是不好,徒增用户困扰与麻烦。研究了下如何自动填充内容,本想去掉选项验证,提交后再生成内容值。但似乎不太容易要编辑核心文件,强行去除改动太大,还是直接在页面生成好了。
创建 WHMCS 订单模板主题
先介绍 WHMCS 产品订购页面的模板文件路径:WHMCS根目录/templates/orderforms
(目录下有多个样式主题,默认使用standard_cart
),里面的模板文件所对应各个页面如下。
模板文件 | 对应页面 |
---|---|
products.tpl | 查看产品类别和所包含的产品 |
adddomain.tpl | 域名注册订单第一步骤 |
addons.tpl | 查看产品附加服务(已登录用户) |
domainrenewals.tpl | 显示用户帐户中的域名,以提供续订 |
configureproductdomain.tpl | 选择域名(附加到产品的域名) |
domainoptions.tpl | 显示域名可用性检查结果 |
configureproduct.tpl | 查看产品配置信息(未添加购物车之前) |
configuredomains.tpl | 域名配置,设置 NS 地址或自定义字段 |
ordersummary.tpl | 查看购物车内容和产品订购总额 |
viewcart.tpl | 显示订单内容开始结帐流程 |
login.tpl | 登录已注册账号 |
complete.tpl | 结账流程的最后步骤 |
注:上述模板文件为订购流程各主要页面,目录下还细分有页面加载的模块 .tpl 文件。 |
为避免后续升级程序可能丢失所做的修改,建议创建自定义主题使用(不用创建一个完整主题,要修改哪个页面就创建哪个模板文件,其它页面继承使用父模板文件)。
创建自定义主题目录,假设名称为 custom_cart。红色字符为 Web 目录路径自行修改。
mkdir /var/www/whmcs/templates/orderforms/custom_cart
接着在目录下创建 theme.yaml
配置文件指定父主题,例如继承默认主题,内容如下。
config: parent: standard_cart
拷贝要修改的模板文件到自定义主题目录下,例如要修改 configureproduct.tpl 这个模板页面。
cp /var/www/whmcs/templates/orderforms/standard_cart/configureproduct.tpl /var/www/whmcs/templates/orderforms/custom_cart/configureproduct.tpl
到 WHMCS 里启用自定义主题,在 Setup -> General Settings -> Ordering 选项卡下设置 Default Order Form Template 。或者在指定产品组里设置使用,路径 Setup -> Products/Services -> Products/Services -> 编辑产品组 -> Order Form Template。
随机生成 Host Name 选项值
主机名这里用 uniqid()
函数生成微秒级时间戳,考虑多线程和基于系统时间可能影响唯一性(实际重复可能性极低,uniqid()
时间戳精确到百万分之一秒), 在字符串前面添加两位随机数(由 mt_rand(10,99)
生成)。添加蓝色参数设置字段不可编辑和禁用浏览器自动完成功能。
<div class="col-sm-6"> <div class="form-group"> <label for="inputHostname">{$LANG.serverhostname}</label> <input type="text" name="hostname" class="form-control" id="inputHostname" value="host.{uniqid(mt_rand(10,99),false)}.com" readonly="readonly" autocomplete="off" placeholder="servername.yourdomain.com"> </div> </div>
如果想用 WHMCS 内置的 Smarty 模板系统保留变量生成随机数,可以用 {$smarty.now}
生成 UNIX 时间戳(精确到秒,配合 date_format
还可转换友好时间格式)。
如果不希望在服务器端用 PHP 生成随机数,也可以用 JS 代码生成,这里有几个简单示例。
随机生成 Root Password 选项值
由于密码需考虑不可预测性,也要尽可能随机复杂,所以不能用时间戳生成。可以通过随机+散列+截取函数生成,例如由特定范围随机数转换为 md5 字符串,再从其中截取 12 位字符。
<?php echo substr(md5(mt_rand(100000, 999999)), 0, 12); ?>
如果要生成复杂一些的(包含大写字母和特殊字符),可以用 str_shuffle()
函数随机打乱预设字符(其随机算法因 PHP 版本而有不同, PHP 7.1 开始由默认的 libc rand 改为了 Mersenne twister),再从其中截取所需长度的字符串。这种方法生成的密码每个字符只会出现一次(其中删除了容易混淆的字符),若要增加可能性可以重复添加预设字符。
<?php echo substr(str_shuffle("2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!@#$%^&*~()-_{}+="),0,12); ?>
上面两种都是比较简单的密码生成方法,可以满足一般程度的安全要求。若要追求更安全的随机值,可以使用 random_bytes()
或 openssl_random_pseudo_bytes()
函数生成。前者要求 PHP 7,后者要求 PHP 5。
修改方法和之前一样,模板文件里找到密码 input 元素,内容值里设置 PHP 密码生成函数。
<div class="col-sm-6"> <div class="form-group"> <label for="inputRootpw">{$LANG.serverrootpw}</label> <input type="password" name="rootpw" class="form-control" id="inputRootpw" value="{substr(str_shuffle('2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!@#$%^&*~()-_{}+='),0,12)}" readonly="readonly" autocomplete="off"> </div> </div>
设置 Name Server 选项值
NS 地址对一般只销售主机产品的商家来说没什么用,因此直接设置一个固定默认值就行。
<div class="col-sm-6"> <div class="form-group"> <label for="inputNs1prefix">{$LANG.serverns1prefix}</label> <input type="text" name="ns1prefix" class="form-control" id="inputNs1prefix" value="ns1.example.com" readonly="readonly" autocomplete="off" placeholder="ns1"> </div> </div> <div class="col-sm-6"> <div class="form-group"> <label for="inputNs2prefix">{$LANG.serverns2prefix}</label> <input type="text" name="ns2prefix" class="form-control" id="inputNs2prefix" value="ns2.example.com" readonly="readonly" autocomplete="off" placeholder="ns2"> </div> </div>
隐藏 Configure Server 选项内容块
完成修改后刷新页面查看工作是否正常,没问题就添加 CSS 样式隐藏页面选项内容。
<div class="sub-heading" style="display: none;"> <span>{$LANG.cartconfigserver}</span> </div> <div class="field-container" style="display: none;"> ... </div>