分享一下,工作中遇见值得分享的Code,这些代码往往比较有趣、有意义、或者少见(有意义),在此我统称为:酷代码。

IP 白名单检测

场景描述:我司的一个子项目,用来处理全部的支付业务,为了安全,所有的内部请求必须经过 IP 检测(这只是其中一环),分享一下基于我老大(涛哥)思想,利用位运算完成,IP白名单检测方法,以下是核心代码

定义检测函数checkRemoteAddr()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 验证 IP 白名单
* @param $ip string 待验证IP地址
* @param $AllowRemoteIps array 允许的IP白名单
* @return bool
*/
function checkRemoteAddr($ip,$AllowRemoteIps)
{
$ipNum = ip2long($ip);
foreach ($AllowRemoteIps as $mask)
{
@list($maskIp, $maskStep) = explode("/", $mask);
$maskIpNum = ip2long($maskIp);
$maskStep = !isset($maskStep) ? 0 : 32 - intval($maskStep);
if( ($ipNum >> $maskStep) === ($maskIpNum >> $maskStep) ) return true;
}
return false;
}

调用

config.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$allowRemoteIp = [
"58.246.60.40", // 开放指定 IP
"192.168.10.0/24", // 验证前3段
"10.0.1.0/24", // 验证前3段
'172.19.2.2/32', // 验证4段 写法等同于 172.19.2.2
// '0.0.0.0/0', // 允许所有 IP
];

$r1 = checkRemoteAddr('58.246.60.40',$allowRemoteIp);
var_dump($r1);
$r2 = checkRemoteAddr('58.246.60.41',$allowRemoteIp);
var_dump($r2);
$r3 = checkRemoteAddr('10.0.1.120',$allowRemoteIp);
var_dump($r3);
$r4 = checkRemoteAddr('10.0.2.120',$allowRemoteIp);
var_dump($r4);

结果

1
2
3
4
bool(true)
bool(false)
bool(true)
bool(false)

一个闭包写法

定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A
{
public function test($num){
$this->run(function ($m) use ($num){
if ($num == $m) echo '存在 Num '. $num . PHP_EOL;
});
echo 'End '. date('Y/m/d H:i:s') . PHP_EOL;
}

public function run(callable $callback){
for ($i=0; $i<=5; $i++){
// to-do
$callback($i);
}
}
}

调用

1
2
$a = new A;
$a->test(5);

结果

1
2
存在 Num 5
End 2019/05/30 17:48:52

有趣的复数

近日在Yii2框架中写reset api,发现资源类控制定义后的访问形式必须为复数,这个复数呢,不是简单加个s的方式,而是遵循英语的复数规则,感觉很是有意思,带着好奇找了一下Yii2是怎么实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
// vendor/yiisoft/yii2/rest/UrlRule.php

public function init()
{
$controllers = [];
foreach ((array) $this->controller as $urlName => $controller) {
if (is_int($urlName)) {
$urlName = $this->pluralize ? Inflector::pluralize($controller) : $controller;
}
$controllers[$urlName] = $controller;
}
...
}

继续查看puluralize()方法,在/vendor/yiisoft/yii2/helpers/BaseInflector.php文件中看到了真面目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Converts a word to its plural form.
* Note that this is for English only!
* For example, 'apple' will become 'apples', and 'child' will become 'children'.
* @param string $word the word to be pluralized
* @return string the pluralized word
*/
public static function pluralize($word)
{
if (isset(static::$specials[$word])) {
return static::$specials[$word];
}
foreach (static::$plurals as $rule => $replacement) {
if (preg_match($rule, $word)) {
return preg_replace($rule, $replacement, $word);
}
}

return $word;
}

从方法中可以看出,如果$word存在于静态属性$specials定义,则返回其对应的value,否则从静态数组$plurals中循环匹配复数规则,命中时根据preg_replace函数翻译成复数,这个两个数组的定义比较大,这里仅贴出部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static $specials = [
'atlas' => 'atlases',
'beef' => 'beefs',
'brother' => 'brothers',
'cafe' => 'cafes',
'child' => 'children',
'cookie' => 'cookies',
'corpus' => 'corpuses',
'cow' => 'cows',
'curve' => 'curves',
'foe' => 'foes',
...
...
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static $plurals = [
'/([nrlm]ese|deer|fish|sheep|measles|ois|pox|media)$/i' => '\1',
'/^(sea[- ]bass)$/i' => '\1',
'/(m)ove$/i' => '\1oves',
'/(f)oot$/i' => '\1eet',
'/(h)uman$/i' => '\1umans',
'/(s)tatus$/i' => '\1tatuses',
'/(s)taff$/i' => '\1taff',
'/(t)ooth$/i' => '\1eeth',
'/(quiz)$/i' => '\1zes',
'/^(ox)$/i' => '\1\2en',
'/([m|l])ouse$/i' => '\1ice',
'/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
'/(x|ch|ss|sh)$/i' => '\1es',
'/([^aeiouy]|qu)y$/i' => '\1ies',
'/(hive)$/i' => '\1s',
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
'/sis$/i' => 'ses',
'/([ti])um$/i' => '\1a',
'/(p)erson$/i' => '\1eople',
'/(m)an$/i' => '\1en',
'/(c)hild$/i' => '\1hildren',
'/(buffal|tomat|potat|ech|her|vet)o$/i' => '\1oes',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
'/us$/i' => 'uses',
'/(alias)$/i' => '\1es',
'/(ax|cris|test)is$/i' => '\1es',
'/(currenc)y$/' => '\1ies',
'/s$/' => 's',
'/^$/' => '',
'/$/' => 's',
];

END :)