ThinkPHP6 多应用模式调用其他控制器时需要填写$app参数,报错Required parameter ‘$app’ missing

如图所示,在多应用情况下,我调用User() 控制器,提示需要填写$app参数,

因为我所有的控制器都是 extends BaseController 的,所以查看BaseController的源码,发现如下

/**
 * 构造方法
 * @access public
 * @param  App  $app  应用对象
 */
public function __construct(App $app)
{
    $this->app     = $app;
    $this->request = $this->app->request;

    // 控制器初始化
    $this->initialize();
}

调用时需要传入一个App对象。

在网上和文档里查了半天都没结果,自己猜出解决方案。

传入参数如下:

(new App())->initialize()

完整的也就是

$user = new User((new App())->initialize());

你学废了吗?

 

By the way,TP6的文档写的乱七八糟,我真特么是服了,遇到问题看文档屁用没有。

 

河南宗教知识竞赛加密算法分析

开头

我的博客因宗教插件而火,故在1400多人的强烈要求下今年还是更新了。这个东西确实没法说,要求满分不给题库,40分钟搜个锤子呢,这不是找着让大学生都去找代刷呢,能学了吗,达的到目的吗?

我的群一直讲究技术交流为主,资源分享为辅,和谐交流环境,禁商禁推广发现就踢。所以这次也算造福一下同学们了。

起因

2021年11月23日早上群友发现插件全部失效了,上班前看了一眼,发现题目结构和开始时间都被加密了,导致老的数据全部失效,因此今天晚上下班回来简单分析了一下,发现并不是那么难,下面把分析过程写在这篇文章里,以作为技术交流。

分析

首先看一下加密后的代码结构:

可观察到大部分的重复以及最后面那显眼的0000000

起初我并没看出这是什么算法,但因为知道之前没加密的时候是一串数字,如1000055这类的,可以看出编码算法应该是个通用算法。

首先想到的就是Base64,经过测试,发现和图中数据不一致,如下面所示

原文:1000143

Base64:MTAwMDE0Mw==

图中加密的:M1T0A0w8M6D0E001M3w2O0O0O0O0

可观察出有很多相似的地方。

尝试对比后,发现如下规律(图中是另一个用户下测试的)

发现被插入的数字是 1004901214 在网页源码中查找此数字,发现正是memberusercode的值

也就是说算法其实很简单,就是把原先的数据经过Base64编码,然后每隔一位将memberusercode的一位数插入进去,最后把 == 替换成那一堆O0,如果没有 == 则直接在后面加上 O0

至此,分析完毕。

算法实现

我用js来实现这个算法,非常简单,拿来直接可以用。以下是代码实现:

function encrypt(content) {
    let code = memberusercode;
    content = window.btoa(content);
    for (let i = 0; i < 10; i++) {
        content = content.slice(0, 2 * i + 1) + code.slice(i, i + 1) + content.slice(2 * i + 1);
    }
    if (content.indexOf('==') == -1) {
        content += 'O0O0OO0O0O';
    } else {
        content = content.replace('==', 'O0O0OO0O0O');
    }
    return content;
}

就不再写注释了,各位同学可以度读一下代码看看是如何实现的,非常简单。

需要注意的是,我们需要在中间插入,要考虑到插入后的文本长度,如下所示

原文:A B C D

1次插入:A X B C D

2次插入:A X B X C D

3次插入:A X B X C X D

……

所以我们插入的索引位置是1 3 5 7 9 ……

因此,for循环内的slice的长度使用的是等差数列公式2i + 1

帮一下官方

我非常明白官方想防作弊的决心,但是说句实话,这样的算法难不倒广大高材生,我并不是第一个解出来的。我愿意在此祝官方一臂之力!

下面我给官方提供一套我在用的自定义算法,非常好用,我用它来生成用户TOKEN。

密钥不泄露几乎不存在被反解密的情况。语言是PHP的。

function encryption($string, $operation)
{
    $key = md5(config('encryption_key')); // 这是密钥,可以写在数据库或配置文件内
    $key_length = strlen($key);
    $string = str_replace('_', '/', $string);
    $string = str_replace("-", '\\', $string);
    $string = str_replace("*", '+', $string);
    $string = $operation == 'D' ? base64_decode($string) : substr(md5($string . $key), 0, 8) . $string;
    $string_length = strlen($string);
    $rndkey = $box = array();
    $result = '';
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($key[$i % $key_length]);
        $box[$i] = $i;
    }
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'D') {
        if (substr($result, 0, 8) == substr(md5(substr($result, 8) . $key), 0, 8)) {
            $result = substr($result, 8);
            return $result;
        } else {
            return '';
        }
    } else {
        $result = str_replace('=', '', base64_encode($result));
        $result = str_replace('/', '_', $result);
        $result = str_replace("\\", '-', $result);
        $result = str_replace("+", '*', $result);
        // 正斜杠 / 改为下划线 _ ; 反斜杠 \ 改为减号 - 。
        return $result;
    }
}

使用方法:

加密时:encryption(要加密的字符串, “E”)

解密时:encryption(要解密的字符串, “D”)

结语

希望官方可以改进让学生学习的措施办法,做好加密防护,给学生们个题库,他们真的会认真搜题学习,我群里已有很多将题库背下来的同学,他们不就达到了官方的目的了吗。

自用ThinkPHP的common.php 包含各种常用函数封装

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 紫旭 <zixutech@gmail.com> <https://www.zixutech.cn>
// +----------------------------------------------------------------------

// 应用公共文件
function assembleJson($code, $status, $message, $data)
{
    return json_encode(['code' => $code, 'status' => $status, 'message' => $message, 'data' => $data]);
}

function assembleTableJson($code, $status, $message, $totalCount, $data)
{
    return json_encode(['code' => $code, 'status' => $status, 'msg' => $message, 'totalCount' => $totalCount, 'data' => $data]);
}

function generateToken($tokenArray)
{
    $token = base64_encode(json_encode($tokenArray));
    $token = encryption($token, 'E');
    return $token;
}

function decryptToken($token)
{
    $tokenArray = encryption($token, 'D');
    $tokenArray = base64_decode($tokenArray);
    $tokenArray = json_decode($tokenArray, true);
    return $tokenArray;
}

// 第二个参数 E加密 D解密
function encryption($string, $operation)
{
    $key = md5(config('encryption_key'));
    $key_length = strlen($key);
    $string = str_replace('_', '/', $string);
    $string = str_replace("-", '\\', $string);
    $string = str_replace("*", '+', $string);
    $string = $operation == 'D' ? base64_decode($string) : substr(md5($string . $key), 0, 8) . $string;
    $string_length = strlen($string);
    $rndkey = $box = array();
    $result = '';
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($key[$i % $key_length]);
        $box[$i] = $i;
    }
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'D') {
        if (substr($result, 0, 8) == substr(md5(substr($result, 8) . $key), 0, 8)) {
            $result = substr($result, 8);
            return $result;
        } else {
            return '';
        }
    } else {
        $result = str_replace('=', '', base64_encode($result));
        $result = str_replace('/', '_', $result);
        $result = str_replace("\\", '-', $result);
        $result = str_replace("+", '*', $result);
        // 正斜杠 / 改为下划线 _ ; 反斜杠 \ 改为减号 - 。
        return $result;
    }
}

//获取用户真实IP
function getIp()
{
    if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
        $ip = getenv("HTTP_CLIENT_IP");
    else
        if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
            $ip = getenv("HTTP_X_FORWARDED_FOR");
        else
            if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
                $ip = getenv("REMOTE_ADDR");
            else
                if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
                    $ip = $_SERVER['REMOTE_ADDR'];
                else
                    $ip = "unknown";
    return ($ip);
}

//Remove the exploer'bug XSS
function RemoveXSS($val)
{
    // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
    // this prevents some character re-spacing such as <java\0script>
    // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
    $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);
    // straight replacements, the user should never need these since they're normal characters
    // this prevents like <IMG SRC=@avascript:alert('XSS')>
    $search = 'abcdefghijklmnopqrstuvwxyz';
    $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $search .= '1234567890!@#$%^&*()';
    $search .= '~`";:?+/={}[]-_|\'\\';
    for ($i = 0; $i < strlen($search); $i++) {
        // ;? matches the ;, which is optional
        // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars

        // @ @ search for the hex values
        $val = preg_replace('/(&#[xX]0{0,8}' . dechex(ord($search[$i])) . ';?)/i', $search[$i], $val); // with a ;
        // @ @ 0{0,7} matches '0' zero to seven times
        $val = preg_replace('/(�{0,8}' . ord($search[$i]) . ';?)/', $search[$i], $val); // with a ;
    }

    // now the only remaining whitespace attacks are \t, \n, and \r
    $ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
    $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
    $ra = array_merge($ra1, $ra2);

    $found = true; // keep replacing as long as the previous round replaced something
    while ($found == true) {
        $val_before = $val;
        for ($i = 0; $i < sizeof($ra); $i++) {
            $pattern = '/';
            for ($j = 0; $j < strlen($ra[$i]); $j++) {
                if ($j > 0) {
                    $pattern .= '(';
                    $pattern .= '(&#[xX]0{0,8}([9ab]);)';
                    $pattern .= '|';
                    $pattern .= '|(�{0,8}([9|10|13]);)';
                    $pattern .= ')*';
                }
                $pattern .= $ra[$i][$j];
            }
            $pattern .= '/i';
            $replacement = substr($ra[$i], 0, 2) . '<x>' . substr($ra[$i], 2); // add in <> to nerf the tag
            $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
            if ($val_before == $val) {
                // no replacements were made, so exit the loop
                $found = false;
            }
        }
    }
    return $val;
}

//防注入
function abacaAddslashes($var)
{
    if (!get_magic_quotes_gpc()) {
        if (is_array($var)) {
            foreach ($var as $key => $val) {
                $var [$key] = abacaAddslashes($val);
            }
        } else {
            $var = addslashes($var);
        }
    }
    return $var;
}

//检查各项过期时间,过期返回true 没过期返回false
function checkExpire($expiretime)
{
    if (!strtotime($expiretime)) {
        //不是时间
        return true;
    }
    $expiretime = number_format(strtotime($expiretime) - time());
    if ($expiretime <= 0) {
        return true;
    } else {
        return false;
    }
}

//取中间文本
function get_between($input, $start, $end)
{
    $substr = substr($input, strlen($start) + strpos($input, $start), (strlen($input) - strpos($input, $end)) * (-1));
    return $substr;
}

// 生成随机密码
function randomkeys($length, $pureNumber = false)
{
    // 生成字母和数字组成的6位字符串

    if ($pureNumber) {
        $arr = range(0, 9);
    } else {
        $str = range('A', 'Z');

        // 去除大写的O,以防止与0混淆

        unset($str[array_search('O', $str)]);
        $arr = array_merge(range(0, 9), $str);
    }

    shuffle($arr);

    $invitecode = '';

    $arr_len = count($arr);

    for ($i = 0; $i < $length; $i++) {

        $rand = mt_rand(0, $arr_len - 1);

        $invitecode .= $arr[$rand];

    }

    return $invitecode;
}

function getThisWeek()
{

//当前日期
    $sdefaultDate = date('Y-m-d');
//$first =1 表示每周星期一为开始日期 0表示每周日为开始日期
    $first = 0;
//获取当前周的第几天 周日是 0 周一到周六是 1 - 6
    $w = date('w', strtotime($sdefaultDate));
//获取本周开始日期,如果$w是0,则表示周日,减去 6 天
    $week_start = date('Y-m-d', strtotime("$sdefaultDate -" . ($w ? $w - $first : 6) . ' days'));
//本周结束日期
    $week_end = date('Y-m-d', strtotime("$week_start +6 days"));
    return [$week_start, $week_end];
}

function array_sort($array, $keys, $type = 'asc')
{
    $keysvalue = $new_array = array();
    foreach ($array as $k => $v) {
        $keysvalue[$k] = $v[$keys];
    }
    if ($type == 'asc') {
        asort($keysvalue);
    } else {
        arsort($keysvalue);
    }
    reset($keysvalue);
    foreach ($keysvalue as $k => $v) {
        $new_array[$k] = $array[$k];
    }
    return $new_array;
}

/**
 * 系统邮件发送函数
 * @param string $tomail 接收邮件者邮箱
 * @param string $name 接收邮件者名称
 * @param string $subject 邮件主题
 * @param string $body 邮件内容
 * @param string $attachment 附件列表
 * @return boolean
 * @throws \PHPMailer\PHPMailer\Exception
 */
function send_mail($tomail, $name, $subject = '', $body = '', $attachment = null)
{
    $mail = new PHPMailer\PHPMailer\PHPMailer();           //实例化PHPMailer对象
    $mail->CharSet = 'UTF-8';           //设定邮件编码,默认ISO-8859-1,如果发中文此项必须设置,否则乱码
    $mail->IsSMTP();                    // 设定使用SMTP服务
    $mail->SMTPDebug = 3;               // SMTP调试功能 0=关闭 1 = 错误和消息 2 = 消息
    $mail->SMTPAuth = true;             // 启用 SMTP 验证功能
    $mail->SMTPSecure = 'ssl';          // 使用安全协议
    $mail->Host = "smtp.qq.com"; // SMTP 服务器
    $mail->Port = 465;                  // SMTP服务器的端口号
    $mail->Username = "";    // SMTP服务器用户名
    $mail->Password = "";     // SMTP服务器密码
    $mail->SetFrom('发信地址', '邮件标题');
    $replyEmail = '';                   //留空则为发件人EMAIL
    $replyName = '请勿回复本邮件';                    //回复名称(留空则为发件人名称)
    $mail->AddReplyTo($replyEmail, $replyName);
    $mail->Subject = $subject;
    $mail->MsgHTML($body);
    $mail->AddAddress($tomail, $name);
    if (is_array($attachment)) { // 添加附件
        foreach ($attachment as $file) {
            is_file($file) && $mail->AddAttachment($file);
        }
    }
    return $mail->Send() ? true : $mail->ErrorInfo;
}

/**
 * http请求
 * @param string $url 请求地址
 * @param boolean|string|array $params 请求数据
 * @param integer $ispost 0/1,是否post
 * @param array $header
 * @param bool $verify 是否验证ssl
 * return string|boolean          出错时返回false
 * @param bool|array $proxy 代理数组
 * @return bool|mixed
 */
function http_request($url, $params = false, $ispost = 0, $header = [], $verify = false, $proxy = false)
{
    $httpInfo = array();
    $ch = curl_init();
    $ua = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36';
    if (!empty($header)) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    }
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_USERAGENT, $ua);

    if ($proxy) {
        curl_setopt($ch, CURLOPT_PROXY, $proxy['ip']); //代理服务器地址
        curl_setopt($ch, CURLOPT_PROXYPORT, $proxy['port']); //代理服务器端口
    }
    //忽略ssl证书
    if ($verify === true) {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    } else {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    }
    if ($ispost) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        curl_setopt($ch, CURLOPT_URL, $url);
    } else {
        if (is_array($params)) {
            $params = http_build_query($params);
        }
        if ($params) {
            curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
        } else {
            curl_setopt($ch, CURLOPT_URL, $url);
        }
    }
    $response = curl_exec($ch);
    if ($response === FALSE) {
        trace("cURL Error: " . curl_errno($ch) . ',' . curl_error($ch), 'error');
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo, curl_getinfo($ch));
        trace($httpInfo, 'error');
        return false;
    }
    curl_close($ch);
    return $response;
}


/**
 * 检查是否是手机访问
 * @return bool
 */
function is_mobile()
{
    $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
    $is_pc = (strpos($agent, 'windows nt')) ? true : false;
    $is_mac = (strpos($agent, 'mac os')) ? true : false;
    $is_iphone = (strpos($agent, 'iphone')) ? true : false;
    $is_android = (strpos($agent, 'android')) ? true : false;
    $is_ipad = (strpos($agent, 'ipad')) ? true : false;


    if ($is_pc) {
        return false;
    }

    if ($is_mac) {
        return false;
    }

    if ($is_iphone) {
        return true;
    }

    if ($is_android) {
        return true;
    }

    if ($is_ipad) {
        return false;
    }
}

 

ElementUI的select组件的option的label slot里的错位问题

标题很拗口,但是就是这个意思。

问题

本问题实际描述是,当使用select组件,并且为option使用了插槽之后,像官方里的那样使用style=”float: right;” 后 导致错位,如下图所示

右边的tag贴顶了,但是返回去看官方文档里的代码,却没有问题。

仔细看官方的例子,官方在插槽里用的是纯文本<span></span>,而el-tag也会自动转为span,但依然是样式错误。

在此省略一系列尝试之后,终于发现解决办法,特此记录,以便自己和其他有相同问题的朋友查阅。

解决

在el-tag的外层加一个空格即可解决问题,注意不是键盘上的space,而是

&nbsp;

此时错位问题完美解决!

elementUI MessageBox prompt模式下异步提交问题

问题

最近写项目发现,使用elementUI的MessageBox的prompt 异步提交数据时,存在点了确定弹窗关闭并且不再执行then下面的指令,自然也就没办法继续执行。

经过一番测试,解决办法为:使用callback方法来代替Promise,示例代码如下

this.$prompt('请输入密码', '管理员登录', {
        confirmButtonText: '确定',
        inputPlaceholder: '密码必须包含大小写字母和数字的组合',
        cancelButtonText: '取消',
        inputPattern: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,16}$/,
        inputErrorMessage: '密码格式不正确',
        callback: function (action, instance) {
          if (action === 'confirm') {
            self.$axios({
              url: self.$serverUrl + '/index/Server/RconLogin',
              method: 'POST',
              data: {你要提交的数据}
            }).then(function (res) {
              if (res.data.status === 'success') {
                self.$message({
                  type: 'success',
                  message: '成功进入管理员模式!'
                })
                self.ServerInfoDialog.adminMode = true
              }
            }).catch(function (error) {
              self.$message({
                type: 'danger',
                message: error.response.data
              })
            })
          }
        }
      })

这样就可以在窗口关闭之后继续执行回调内的代码了。请注意 instance.inputValue 的值就是prompt内输入的信息

ThinkPHP5错误解析之variable type error:array

在TP5的post提交方式中,有一个坑爹的bug就是post提交数据不能提交数组。
请注意是不能提交数组形式的数据,而不是单纯的数据。举个例子:注意以下2种格式数据的比较:
第一种:普通的数据提交,这种格式的数据在TP5中用post提交,$request->post(‘参数’);可以接受数据。

//js,
{
    'data':123,
    'id':1,
    'name':'user'
}

下面看坑爹的第二种:

{
'data':[1,2,3,4,5],
'id':1,
'name':'user'
}

这种形式的数据同过POST提交数据在TP5框架内通过$request->post(‘参数’);去接收就会报错。
variable type error:array
这是因为tp5不能用post去接收数组‘data’:[1,2,3,4,5]这种数据。在通过request的post方法取获取时,post方法不能分辨它是否是数组。
所以在想不改变post提交方式的情况下,解决办法之一就是用/a。(这里的/a就相当于告诉解析器我要获取一个数组。)
将原来的接收方式参数修改为:

$data = $request->post('data/a');
// $data是任意定义的变量。

同时,如果是表单直接提交,也需要把name的值改为数组,也就是加个[]

<select name="sid[]" id="sid" placeholder="必须选择适用产品" data-am-selected="{searchBox: 1}" multiple required>
//部分属性是AmazeUI框架带的,各位读者只需要注意name属性即可

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3hoxr13jt4g0o

php生成唯一订单号的5种方法

这篇文章主要介绍了关于php生成唯一订单号的方法,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

第一种

private function doCreateOrderNumber($time){

          $i=1;

          $dd = date('Ymd',$time);

          $aa = 'OH'.$dd;

          $res = $this->orderModel->query("select sn from sr_order_list where sn like '$aa%' order by id limit 1");

          if(!isset($res[0]['sn'])){

                $i = 1;

          }else{

                $i = (int)substr($res[0]['sn'],9,10) + 1;

          }

          while(true){

                $nsn = 'OH'.$dd.$i;

                $exist = $this->orderModel->query("select id from sr_order_list where sn = '$nsn' ");

                if($exist){

                      $i++;

                }else{

                      return $nsn;

                }

          }

    }

第二种

$osn = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);

echo $osn; //2018070462577

第三种

$osn = date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);

echo $osn; //2018070499495653

第四种

$order_id_main = date('YmdHis') . rand(10000000,99999999);

  $order_id_len = strlen($order_id_main);

  $order_id_sum = 0;

  for($i=0; $i<$order_id_len; $i++){

  $order_id_sum += (int)(substr($order_id_main,$i,1));

  }

  $osn = $order_id_main . str_pad((100 - $order_id_sum % 100) % 100,2,'0',STR_PAD_LEFT);

echo $osn; //201807041332258742313727

第五种

$code = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');

$osn = $code[intval(date('Y')) - 2011] . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));

echo $osn; //H704764673624352

 

ThinkPHP5 另类方法实现分页功能

前言

当然是自己需要这个功能啦。。。

准备

我所用的前端框架是老外用BootStrap4二开的主题,叫MaterialPro(以下简称MP),我会在本文末附上压缩包。非常好用哦。

传统的分页是使用ul li来做,但是最大的问题就是如果没有正好的样式,那么你还得费大半天时间去写样式,烦得很。所以我这次使用的是MP的按钮组,美观也好看。

实现方法

分页实现是用的TP5自带的paginate方法,在Model里查询数据的时候直接使用该方法进行分页。然后将对象返回过来就好。

注意:官方文档写的是使用render方法来分页,但是在这里我们不用这个方法,因为他在我这有各种BUG。

将数据对象返回过来之后,var_dump之后结构是这样的(这里只发出来跟分页有关的数据结构)

protected 'currentPage' => int 1
  protected 'lastPage' => int 1
  protected 'total' => int 4
  protected 'listRows' => int 10
  protected 'hasMore' => boolean false
  protected 'options' =>
    array (size=6)
      'var_page' => string 'page' (length=4)
      'path' => string '/index/index/charge' (length=19)
      'query' =>
        array (size=0)
          empty
      'fragment' => string '' (length=0)
      'type' => string 'bootstrap' (length=9)
      'list_rows' => int 15
  protected 'nextItem' => null

提示:这里很多人会误认为total是总页数,其实是错误的,total是数据总条数。

接下来就是前端了,很easy,我直接把代码贴上来你们读一下就懂了

<div class="float-right">
{if $record->currentPage()>1}
<button id="pre" type="button" class="btn btn-secondary" data-page="/index/index/charge?page={$record->currentPage()-1}">上一页</button>
{/if}
<div class="btn-group" role="group">
{for start="1" end="$record->lastPage()+1" name="page"}
<button type="button" class="pages btn {if $page==$record->currentPage()}btn-info{else /}btn-secondary{/if}" data-page="/index/index/charge?page={$page}">{$page}</button>
{/for}
</div>
{if $record->currentPage()<$record->lastPage()}
<button id="af" type="button" class="btn btn-secondary" data-page="/index/index/charge?page={$record->currentPage()+1}">下一页</button>
{/if}
</div>
<!--这里写分页代码-->

以及js代码

$('#pre').on('click',function () {
window.location.href = $(this).attr('data-page');
});
$('#af').on('click',function () {
window.location.href = $(this).attr('data-page');
});
$('.pages').on('click',function () {
window.location.href = $(this).attr('data-page');
});

最终效果图:

第一页的时候上一页会隐藏,最后一页的时候下一页会隐藏。很NICE

结尾

怎么样,是不是非常easy……

【干货】TP5第三方类库引用报Class not found 办法

这篇文章我实在懒得排版了,就这样发吧。。

1、TP5第三方类库全部放在Extend目录内,如果是放在Extend目录下,则不需要再类库里声明namespace。直接 new \YourClass() 即可

2、如果你的类库在Extend的子目录下,则需要命名空间,命名空间要与目录名保持一致。

假如我有一个 Network.php 类,我放在了 Extend/Net/里面,真实地址就是:

extend/Net/Netword.php , 则命名空间就要为 

[php]namespace Net;[/php]

3、类名必须和文件名保持一致!!首字母必须大写!!!!

接着第2条的例子来说,文件名叫Network,则类名也必须叫Network,如下所示

[php]class Network{}[/php]

遵循以上,就不会再出错了。我本人已经被这个问题烦死了。。。。所以写下来以后提醒自己。。。