美高梅6s娱乐官方网址:用PHP达成的抢红包小程序,PHP数学生运动算函数大汇总_php本事_脚本之家

那二日多少懒,不怎么更新,经常事务比超多,加之周日要去练习打球赛所以才拖了那么久。闲话休说,上干货!!首先那个程序已经不是何等新鲜的东西了,早在Wechat出抢红包作用的时候就有了,但是让本身想写那篇小说的原因是前几天付加物出了个需求,大约是要贯彻分享商品的链接进行拼单这么三个成效,前提条件已经设定好,设计了多少个变量参数,三个是商品的总价值(这里能够引申为红包总额),叁个是分享的人头(引申为抢红包的总人数),最终的规范是种种人的拼单金额大小(抢到的红包金额大小)是不管三七二十大器晚成的,不过总额要小于等于商品总的价值。通过以上的解析,那么就足以主导分明那是一个天下第一的抢红包程序。在写程序早前,笔者想分享一点资历和经历,以往的文章都会有打点的编制程序小本领分享。切记一点:不要急于,写程序避讳一步到位!先达成四个小demo,然后再逐级扩张你的各个标准和巡回,做项目也是同等,都以从各种细微的模块渐渐拼凑成大模块最终才拼成一个完完全全的品类。先拆分须求,比方这里面须要用到随机数,那就先写个转换0.01到10.00间距的自由浮点数的主次。以下是代码。

mt_srand() 和 mt_rand()

mt_srand()
: 为mt_rand(卡塔尔国函数播种的函数

php manual 的解释是:

mt_srand : 播下叁个越来越好的任性数产生器种子,用 seed
来给自由数发生器播种。 未有设定 seed 参数时,会被设为任何时候数。

Note: 自 PHP 4.2.0 起,不再供给用 srand(卡塔尔 或 mt_srand()给自由数发生器播种 ,因为明日是由系统自动实现的。

mt_rand()
: 生成随机数的函数

php manual的演说为:生成越来越好的即兴数,超级多老的 libc
的人身自由数爆发器械备部分不分明和茫然的天性而且相当的慢。PHP 的 rand(卡塔尔(قطر‎函数暗中认可使用 libc 随机数发生器。mt_rand(State of Qatar函数是业余用来替换它的。该函数用了 » Mersenne Twister
中已知的天性作为自由数发生器,它可以产生随机数值的平均速度比 libc 提供的 rand() 快四倍。

若果未有提供可选参数 min 和 max,mt_rand() 返回 0 到 mt_getrandmax(卡塔尔之间的伪随机数。

mt_rand(卡塔尔(قطر‎函数的二种适用处景

  • 内定范围参数,比方mt_rand(1,1000)
  • 不点名范围,让系统自动生成

万生龙活虎大家同舟共济钦命范围的话,如若过小则超级轻便被爆破出来的,由此非常多实际运用中都以不点名范围,
mt_美高梅6s娱乐官方网址,rand(卡塔尔国函数默许范围是0到 mt_getrandmax(卡塔尔国之间的伪随机数

我们来看下mt_getrandmax(卡塔尔函数的最大值是某些

php > echo mt_getrandmax();
2147483647
php > echo 2**31-1;
2147483647

发现mt_getrandmax(State of Qatar的最大值是2**31-1的分寸,也正是说随机数的范围在0x00000000~0xffffffff
之间, 在这里个约束内大家是足以爆破的,大家得以爆破在0x00000000~0xffffffff
之间的种子值,相称生成的随机数是或不是和大家爆破的即兴数相等,
爆破的工具已经有大牌用c写了php_mt_seed的几个工具

http://www.openwall.com/php\_mt\_seed/

正文汇总深入分析了PHP数学运算函数。分享给大家供我们参考,具体如下:

$min = 0.01;$max = 10.00;$random = rand($min,$max);echo $random ;

php_mt_seed

笔者们来看下该工具爆破0x00000000~0xffffffff爆破的经过,爆破完也就几分钟的时刻

比方多个十分轻易的次序:

<?php

mt_srand(20);
echo mt_rand();

>>>
873212871

我们用php_mt_seed去爆破我们的种子,假诺种子值获得小,差不离是秒破的

lj@lj /d/T/C/M/C/p/php_mt_seed-4.0> ./php_mt_seed 873212871
Pattern: EXACT
Version: 3.0.7 to 5.2.0
Found 0, trying 0x30000000 - 0x33ffffff, speed 5033.2 Mseeds/s 
seed = 0x32524e6c = 844254828 (PHP 3.0.7 to 5.2.0)
seed = 0x32524e6d = 844254829 (PHP 3.0.7 to 5.2.0)
Found 2, trying 0xfc000000 - 0xffffffff, speed 5219.6 Mseeds/s 
Version: 5.2.1+
Found 2, trying 0x00000000 - 0x01ffffff, speed 0.0 Mseeds/s 
seed = 0x00000014 = 20 (PHP 5.2.1 to 7.0.x; HHVM)
Found 3, trying 0x04000000 - 0x05ffffff, speed 37.3 Mseeds/s ^C

php_mt_rand 工具只可以用来爆破mt_rand(State of Qatar函数发生的随便数的种子值,
无论是不是显式调用mt_srand(卡塔尔函数播种,但不能够用于mt_rand(1,1000State of Qatar这种内定范围的和rand函数的爆破

大范围的两种用mt_srand(卡塔尔(قطر‎ 播种的事态

  • 稳固种子: 比如mt_srand(1000)

这种气象如若是调用mt_rand()函数用php_mt_seed工具差不多秒破

  • 动态种子

1. mt_srand(mt_rand(0,1000));

// 如果动态种子的值不是很大,我们可以可以去写一个脚去生成所有种子值生成的随机数序列,l类似彩虹表, 然后一一对比即可

2. mt_srand(time());
// 这种动态种子其实和比静态种子还危险,因为time()函数生成的种子是已知的,每个人生成的time()的值都是一样的
  • 前后相继自动播种
    这种气象也得以分为三种意况
  1. 用mt_srand(卡塔尔国函数,种子值随机
  2. 次第隐式调用mt_srand(卡塔尔函数,不再要求客户来调用mt_srand()函数

这种情状就比较复杂,也正如相符实况

,
但难点来了,到底系统活动完毕播种是怎么时候,因为是隐式调用的,借使是历次调用mt_rand(State of Qatar函数都会自动播种,那么破解seed也就不曾意思了,那样就能够化为真随机数了

咱俩来找对应php源码来解析下:

PHPAPI void php_mt_srand(uint32_t seed)
{
    /* Seed the generator with a simple uint32 */
    php_mt_initialize(seed, BG(state));
    php_mt_reload();

    /* Seed only once */
    BG(mt_rand_is_seeded) = 1;
}
/* }}} */

/* {{{ php_mt_rand
 */
PHPAPI uint32_t php_mt_rand(void)
{
    /* Pull a 32-bit integer from the generator state
       Every other access function simply transforms the numbers extracted here */

    register uint32_t s1;

    if (UNEXPECTED(!BG(mt_rand_is_seeded))) {
        php_mt_srand(GENERATE_SEED());
    }

    if (BG(left) == 0) {
        php_mt_reload();
    }
    --BG(left);

    s1 = *BG(next)++;
    s1 ^= (s1 >> 11);
    s1 ^= (s1 <<  7) & 0x9d2c5680U;
    s1 ^= (s1 << 15) & 0xefc60000U;
    return ( s1 ^ (s1 >> 18) );
}

php_mt_srand
是播种函数,依照注释我们我们清楚该程序的光景效能是先起先化一个seed,
然后调用php_mt_reload
生成N个的自由数,并赋值标识位:mt_rand_is_seeded为1,
表示早就播种的意思

php_mt_rand是转换随机数函数, 大家看出如此意气风发段

if (UNEXPECTED(!BG(mt_rand_is_seeded))) {
    php_mt_srand(GENERATE_SEED());
}

if (BG(left) == 0) {
    php_mt_reload();
}
--BG(left);

若无播种,就调用php_mt_srand函数播种,那么下二次调用mt_rand(卡塔尔(قطر‎函数时就能够跳过这步

所以,其实能够精晓,mt_rand(卡塔尔国函数并非每三回调用都会都会自由播种,那么什么样时候会再度播种呢?
即几时mt_rand_is_seeded 标记位会被起头化为0呢?
那步赋值0的操作在源码basic_functions.c中有定义, 这里不精心贴了,
即在每一个新历程始起的时候会开头化叁次mt_rand_is_seeded

大器晚成、常用函数表明:

是因为一条结果很难显现效果,那么再加个循环

rand()

rand(卡塔尔(قطر‎ 函数在发生随机数的时候未有调用
srand(卡塔尔,则发出的专断数是有规律可询的.

发出的随机数能够用上边这一个公式预测 : state[i] = state[i-3] +
state[i-31] (平常预测值或者比实际值要差1卡塔尔国

<?php
$randstr = array();
for ($i = 0; $i <= 50; $i++) {
    $randstr[$i] = rand(0, 30);
    if ($i >= 31) {
        echo "第" . $i . "个随机数:";
        echo "$randstr[$i]=(" . $randstr[$i - 31] . "+" . $randstr[$i - 3] . ") mod 32 +1\n";
    } else {
        echo "第" . $i . "个随机数:" . $randstr[$i] . "\n";
    }
}

>>>

第0个随机数:2
第1个随机数:0
第2个随机数:1
第3个随机数:26
第4个随机数:24
第5个随机数:10
第6个随机数:17
第7个随机数:27
第8个随机数:23
第9个随机数:2
第10个随机数:6
第11个随机数:18
第12个随机数:25
第13个随机数:17
第14个随机数:14
第15个随机数:2
第16个随机数:14
第17个随机数:26
第18个随机数:20
第19个随机数:14
第20个随机数:17
第21个随机数:6
第22个随机数:15
第23个随机数:0
第24个随机数:23
第25个随机数:1
第26个随机数:17
第27个随机数:2
第28个随机数:17
第29个随机数:25
第30个随机数:27
第31个随机数:19=(2+17) mod 32 +1
第32个随机数:25=(0+25) mod 32 +1
第33个随机数:29=(1+27) mod 32 +1
第34个随机数:15=(26+19) mod 32 +1
第35个随机数:19=(24+25) mod 32 +1
第36个随机数:8=(10+29) mod 32 +1
第37个随机数:1=(17+15) mod 32 +1
第38个随机数:15=(27+19) mod 32 +1
第39个随机数:0=(23+8) mod 32 +1
第40个随机数:4=(2+1) mod 32 +1
第41个随机数:21=(6+15) mod 32 +1
第42个随机数:19=(18+0) mod 32 +1
第43个随机数:29=(25+4) mod 32 +1
第44个随机数:7=(17+21) mod 32 +1
第45个随机数:3=(14+19) mod 32 +1
第46个随机数:0=(2+29) mod 32 +1
第47个随机数:22=(14+7) mod 32 +1
第48个随机数:29=(26+3) mod 32 +1
第49个随机数:21=(20+0) mod 32 +1
第50个随机数:6=(14+22) mod 32 +1

能够看见只供给发出前38个随机数,后边的32-四16个随机数大家都能够用后面包车型客车妄动数去预测后边的妄动数值

咱俩来看几道题, 叁个是EIS 上的后生可畏道随机数的题,源码为:

<?php
include "flag.php";
session_start();
if (isset($_GET['code']) && intval($_GET['code']) === $_SESSION['code']) {
    die($flag);
} else {echo "wrong answer!";}
srand(rand(0, MAX_NUM));
for ($i = 0; $i < 3; $i++) {
    echo "<h3>randnum$i:" . rand(0, MAX_NUM) . "</h3><br>";
}
echo 'sessionid: ' . session_id();
var_dump($_SESSION);
$_SESSION['code'] = rand(0, MAX_NUM);
var_dump($_SESSION);
?>
<form action="" method="get">
the next random num is:<input type="text" name="code"/>
<input type="submit"/>
</form>

srand(卡塔尔的种子值是动态, 而MAX_NUM
的值也是未知,不太好分明种子的节制和rand随机数的限定,
通过观看发掘随机数值基本都以3位数和2位数的,未有超越4位数的,
见到有大佬们一贯推测MAX_NUM位1000, 然后去爆破就能够

<?php

for ($i = 0; $i < 1001; $i++) {
    srand($i);
    echo 'srand:' . $i . ':' . rand(1, 1000) . ' ' . rand(1, 1000) . ' ' . rand(1, 1000) . ' ' . rand(1, 1000);
    echo "\n";
}

那样写三个php脚本然后生成多少个相像彩虹表的事物,
每便改换前八个随机数,对照以下虹彩表就足以预测出来第七个随机数了,
平时绝对误差在+1左右,

这种做法就算有几许估摸的做法,但也是合理的, 真正MAX_NUM 确实是1000,
如若出题人改成999,那么用于转移的词典会大大扩充,假诺是爆破900-1100的MAX_NUM值,大约供给200*1000=二零零二0那样大小的词典

本子如下:

<?php

$max_num = 1000;
for ($k = 900; $k <= 1100; $k++) {
    $max_num = $k;
    for ($i = 0; $i <= 1000; $i++) {
        srand($i);
        echo 'srand:' . $i . ':' . rand(1, $max_num) . ' ' . rand(1, $max_num) . ' ' . rand(1, $max_num) . ' ' . rand(1, $max_num);
        echo "\n";
    }
}

第三种做法是写三个py脚本直接去爆破随机数,因为随便数的范围都是自愧弗如1000的,由此那么些一向爆破0,1000即可

import requests

url = 'http://0.0.0.0:91/index.php'
s = requests.session()

# headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
# html = s.get(url,headers=headers)

for i in range(1000):
    #s = requests.session()

    url2 = url+'?code='+str(i)
    res = s.get(url2)
    print res.content
    if 'flag' in res.content:
        print res.content 
        break

大概每种session 能够爆出2,3次就不可能再次爆破了,也可以有少数随机性在内部的

ps: 其实session(卡塔尔这些函数有一些像随机数播种,
程序每一趟运维叁次session函数,都会分配三个永世的sessionid,
下面那么些顺序把session放在眼前,那么循环部分的sessionid都以生机勃勃律的,和大家浏览器访谈并从未非常的大差异,
但假使是把session(卡塔尔(قطر‎函数放到循环体里面,那么每趟访谈的sessionid的值都会变卦,约等于1000私有同有的时候间做客壹回站点,
前边相当于壹个人寻访了1000次站点

上面来看后生可畏到湖湘杯的标题:

<?php
error_reporting(0);
$flag = "*********************";
echo "please input a rand_num !";
function create_password($pw_length = 10) {
    $randpwd = "";
    for ($i = 0; $i < $pw_length; $i++) {
        $randpwd .= chr(mt_rand(100, 200));
    }
    return $randpwd;
}

session_start();
var_dump($_SESSION);

mt_srand(time());

$pwd = create_password();
var_dump(($_SESSION['userLogin'] == $_GET['login']));

echo $pwd . '||';

if ($pwd == $_GET['pwd']) {
    echo "first";
    if ($_SESSION['userLogin'] == $_GET['login']) {
        echo "Nice , you get the flag it is " . $flag;
    }

} else {
    echo "Wrong!";
}

$_SESSION['userLogin'] = create_password(32) . rand();

?>

mt_srand(卡塔尔函数用time(State of Qatar做种子值, 约等于已知的,
我们能够本地用time(卡塔尔那个种子值去预测pwd的值, 这第风流倜傥层判定超轻便绕过,
第二层的判别就有一些迷了

察觉那一个第二层的判别为if ($_SESSION['userLogin'] == $_GET['login']),
只是简短的推断了下是不是等于,而并未有看清$_GET[‘login’] 那个值是或不是为空,
因为程序大器晚成旦第二回加载,那么那个时候$_SESSION还从未赋值,$_SESSION[‘login’]
的内容自然是空, NULL===NULL, 超轻便就绕过了第二层,
由此那题第二层剖断形如虚设:

<?php

function create_password($pw_length = 10) {
    $randpwd = "";
    for ($i = 0; $i < $pw_length; $i++) {
        $randpwd .= chr(mt_rand(100, 200));
    }
    return $randpwd;
}

mt_srand(time());
$pass = create_password();
echo $pass . "\n";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://114.215.138.89:10080/?pwd=' . $pass);
$output = curl_exec($curl);
print_r($output);
curl_close($curl);

如若你的时日和服务器上面的时日不联合,即time(State of Qatar的值不相通话,供给去偏移一个大要范围去爆破

只要那题是改成如下

<?php
error_reporting(0);
$flag = "*********************";
echo "please input a rand_num !";
function create_password($pw_length = 10) {
    $randpwd = "";
    for ($i = 0; $i < $pw_length; $i++) {
        $randpwd .= chr(mt_rand(100, 200));
    }
    return $randpwd;
}

session_start();
var_dump($_SESSION);

mt_srand(time());

$pwd = create_password();
var_dump(($_SESSION['userLogin'] == $_GET['login']));

echo $pwd . '||';

if ($pwd == $_GET['pwd']) {
    echo "first";
    if (isset($_GET['login']) && $_SESSION['userLogin'] == $_GET['login']) {
        echo "Nice , you get the flag it is " . $flag;
    }

} else {
    echo "Wrong!";
}

$_SESSION['userLogin'] = create_password(32) . rand();

?>

那正是说又该如何来解呢? 笔者才那一个标题标愿意应该也是想这么考的,
这样的话难度大大进步

rand(卡塔尔国函数在未曾调用srand(卡塔尔国的时候产生的即兴数值是足以猜测的,
须要通过那一个毛病去赢得$_SESSION[‘userLogin’]的值,
具体得以落成之后一时间会在写意气风发篇小说来剖判

参考大佬们的博客:

http://mp.weixin.qq.com/s/3TgBKXHw3MC61qIYELanJg

http://wonderkun.cc/index.html/index.php/2017/03/16/php%E7%9A%84%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%9A%84%E5%AE%89%E5%85%A8%E6%80%A7%E5%88%86%E6%9E%90/

Abs: 得到相对值。

$min = 0.01;$max = 10.00;for ($i=0;$i<10;$i++){ $random = mt_rand($min,$max); echo "第 $i 个随机数为:"; echo $random ; echo "<br />";//输出html换行标签}

Acos: 获得反余弦值。

结果如下图

Asin: 获得反正弦值。

美高梅6s娱乐官方网址 1随机数.png

Atan: 得到反正切值。

由于mt_rand(卡塔尔国的重回值是整型,不是大家最后想要的结果,所以得独出机杼,在须要涉及到金额这一块的时候都要特别仔细商量。

Atan2: 计算二数的左右切值。

$min = 0.01;$max = 10.00;for ($i=0;$i<10;$i++){ $random = $min + mt_rand() / mt_getrandmax() * ($max - $min); echo "第 $i 个随机数为:"; echo $random ; echo "<br />";//输出html换行标签}

base_convert: 调换数字的进位情势。

那边用到三个函数mt_getrandmax(卡塔尔(قطر‎,关于那几个函数是那般的种类日常会有最大能产生的随便数值LIMIT_RAND_MAX,比如2^31-1,而mt_getrandmax(State of Qatar重回的正是系统默许的那些值。使用情境应该是如此的:1、使用mt_getrandmax(卡塔尔(قطر‎函数获取系统能爆发的最大随机数值LIMIT_RAND_MAX2、根据LIMIT_RAND_MAX来推断自身所需的随机数是不是在此个范围3、使用mt_rand(State of Qatar产生随机数一句话来讲,mt_getrandmax(卡塔尔国仅仅是用来做约束衡量功效。结果如下

BinDec: 二进位转成十进位。

美高梅6s娱乐官方网址 2随机数1.png

Ceil: 总计大于内定数的纤维整数。

那回临近多了,剩下的正是取小数点后2位。很简短,正是先乘上100取整,最终用php中的bc函数举办相除,取后两位,就得到大家想要的结果。

DecBin: 十进位转二进位。

$min = 0.01;$max = 10.00;for ($i=0;$i<10;$i++){ $random = $min + mt_rand() / mt_getrandmax() * ($max - $min); $rward = bcdiv(floor($random*100),100,2); echo "第 $i 个随机数为:"; echo $rward ; echo "<br />";//输出html换行标签}

DecHex: 十进位转十八进位。

结果如下

DecOct: 十进位转八进位。

美高梅6s娱乐官方网址 3随便浮点数.png

Exp: 自然对数 e 的次方值。

接下去是大旨部分,抢红包的机制,首先各样人抢到的红包金额总和不能够超越红包的总和,并且每一种人的红包金额大小是自便的。那么能够依靠设定抢红包的人头来写多个for循环。
这里可以先把发生随机数封装成二个函数。

Floor: 计算小于钦命数的最大整数。

//取随机浮点数function random_float($min = 0.01, $max = 10.00) { return $min + mt_rand() / mt_getrandmax() * ($max - $min);}$total_price = 20.00;//红包总额$overage = $total_price;//红包余额$num = 5;//设置抢红包的人数$reward = array;//每个人获得的红包for ($i=1;$i<=$num;$i++){ $random = random_float(0.01,$overage); $reward[$i] = bcdiv(floor($random*100),100,2); $overage = bcsub($overage,$reward[$i],2); echo "第 $i 个人抢到的红包金额:";print_r($reward[$i]);echo "剩余红包总额为: $overage"; echo "<br />";//输出html换行标签}

getrandmax: 随机数的最大值。

结果如下

HexDec: 十四进位转十进位。

美高梅6s娱乐官方网址 4抢红包.png那么到这里抢红包的作用基本上完成了,但是还少了几样东西,我想大家都开掘了,为何第后生可畏私房抢到的红包金额那么大,而别的的人金额普及相当的低,又或许5个人内部三个抢到的红包数远远超越其余人的红包金额的总和,是因为大家在变化随机数的时候从不做节制,引致区间一点都不小,说起此地就必须要说二个叫二倍均值法的东西,轻巧的话便是把每一回爆发随机数的右区间也等于美高梅6s娱乐官方网址 5num,然后再乘上2。做完那件事还要加一个标准手艺算实现,最终一个人抢到的红包金额就是尾数首轮余下的红包总额。

Log: 自然对数值。

//取随机浮点数function random_float($min = 0.01, $max = 10.00) { return $min + mt_rand() / mt_getrandmax() * ($max - $min);}$total_price = 20.00;//红包总额$overage = $total_price;//红包余额$num = 5;//设置抢红包的人数$reward = array;//每个人获得的红包for ($i=1;$i<=$num;$i++){ if { $reward[$i] = $overage; $overage = 0; }else{ $random = random_float(0.01,$overage/$num*2); $reward[$i] = bcdiv(floor($random*100),100,2); $overage = bcsub($overage,$reward[$i],2); } echo "第 $i 个人抢到的红包金额:";print_r($reward[$i]);echo "剩余红包总额为: $overage"; echo "<br />";//输出html换行标签}

Log10: 10 基底的对数值。

出口结果

max: 得到最大值。

美高梅6s娱乐官方网址 6抢红包2.png

min: 得到最小值。

那般算是是水到渠成了,那么贰个付加物的须求也就宗旨到位,那是最优秀的抢红包程序了,能够根据产物的活灵活现供给实行更动,变出越来越多花样。所以编制程序正是贰个消除某些实际难题的进程,那也是从代码到作用达成的进程,希望对您有协助!如有不得法之处招待私信小编!迎接商讨提议越多优化的地点!多谢!

mt_rand: 拿到自由数值。

mt_srand: 配置随机数种子。

mt_getrandmax: 随机数的最大值。

发表评论

电子邮件地址不会被公开。 必填项已用*标注