widget,英文意思为小工具,小挂件,在程序里大概也是这个意思,Yii2中叫做组件,这个示例仅仅是写一个基本的Yii2 widget,看看能不能运行。
关于widgets,他们在yii中的关系如下
system.web.widgets 系统自带最基本的widget
zii.widgets 是基本扩展
zii.widgets.grid 是基本扩展的重要分支
zii.widgets.jui 是插件扩展
一,system.web.widgets
包括:
CActiveForm
CAutoComplete
CClipWidget
CContentDecorator
CFilterWidget
CFlexWidget
CHtmlPurifier
CInputWidget
CMarkdown
CMaskedTextField
CMultiFileUpload
COutputCache
COutputProcessor
CStarRating
CTabView
CTextHighlighter
CTreeView
CWidget
看vendor/yiisoft/yii2/base/Widget.php的定义,widget需要继承这个类,begin,end,widget,run这些方法都可以在子类进行重写定义,这里我们重写run试试。
新建一个类Testwidgets.php:
namespace common\widgets;
use yii\base\Widget;
class Testwidgets extends Widget
{
public function __Construct()
{
echo 'test test ...';
}
public function run()
{
echo 'run run run ...';
}
}
在一个模板文件中这样使用:
<?php
/* @var $this yii\web\View */
use common\widgets\Testwidgets;
?>
<p>
<?php echo Testwidgets::widget();?>
</p>
页面输出:
test test …run run run …
是不是很简单,当然这只是一个最简单的Yii2 widget,只是搞清楚写widget的基本方式。
比如Yii2的表单widget,涉及到很多用法,就要定义额外的类和方法来实现需求。
<?php $model = new User();?>
<?php $form = ActiveForm::begin(['id'=>'login-form']);?>
<?= $form->field($model,'username')->label('用户名') ?>
<?= $form->field($model,'password_hash')->passwordInput()->label('密码') ?>
<?php ActiveForm::end() ;?>
这样就很方便生成一个表单,而且可以灵活设置各种属性,其实原理都是一样的。
关于Yii2的表单widget,可以好好研究一下,写的很妙。两个文件:
vendor/yiisoft/yii2/widgets/ActiveForm.php和vendor/yiisoft/yii2/widgets/ActiveField.php
使用示例
Yii2封装了一个表单widget,很方便生成各类各式的表单,试了几种表单,可以自由设置样式、类型、属性,如下代码:
<?php $model = new User();?>
<?php $form = ActiveForm::begin(['id'=>'login-form']);?>
<?= $form->field($model,'username')->label('用户名') ?>
<?= $form->field($model,'password_hash')->passwordInput()->label('密码') ?>
<?= $form->field($model,'email')->textarea(['rows'=>5]) ?>
<?= $form->field($model,'status')->checkboxList([1=>'hehe',2=>'haha',3=>'xixi',4=>'heihei'],['id'=>'dddd'])->label('多选') ?>
<?php ActiveForm::end() ;?>
如果想更全面了解如何使用,还是需要看一看源码,才能更好的灵活使用yii2的生成表单widget.
源码文件位置:vendor/yiisoft/yii2-gii/components/ActiveField.php
PHP中STDCLASS在我们开发应用中使用到的不多,但是PHP中STDCLASS作用是非常的大的,下面我们一起来看PHP中STDCLASS的用法。在WordPress中很多地方使用stdClass来定义一个对象(而通常是用数组的方式),然后使用get_object_vars来把定义的对象『转换』成数组。
如下代码所示:
PHP
$tanteng = new stdClass();
$tanteng->name = 'tanteng';
$tanteng->email = 'xxx@qq.com';
$info = get_object_vars($tanteng);
print_r($info);exit;
输出:
Array ( [name] => tanteng [email] => xxx@qq.com )
get_object_vars的作用是返回由对象属性组成的关联数组。它的效果跟这样定义数组其实是一样的:
PHP
$tanteng = array();
$tanteng['name'] = 'tanteng';
$tanteng['email'] = 'xxx@qq.com';
可以这样理解:stdClass是一个内置类,它没有成员变量,也没有成员方法的一个类。new一个stdClass就是实例化了一个『空』对象,它本身没什么意义,但是用stdClass定义有什么好处呢?
如下代码:
PHP
$user = new stdClass();
$user->name = 'gouki';
$user->hehe = 'hehe';
$myUser = $user;
$myUser->name = 'flypig';
print_r($user);
print_r($myUser);
print_r($user);
这里$myUser被赋值$user,但其实并没有新开辟一块内存存储变量,$myUser还是指的stdClass这个对象,通过$myUser改变属性页就改变了$user的属性,并不是新建一个副本,如果程序中有许多这样的操作,使用stdClass的方式可以节省内存开销。
运行结果:
PHP
stdClass Object
(
[name] => flypig
[hehe] => hehe
)
stdClass Object
(
[name] => flypig
[hehe] => hehe
)
stdClass Object
(
[name] => flypig
[hehe] => hehe
)
从结果可以看出,改变$myUser的属性确实改变了$user声明的stdClass属性。而如果$user是一个数组,赋值给$myUser,那就拷贝了一个副本给$myUser,这样增大系统开销。
当然,你也可以反过来,把一个数组转换为对象:
PHP
$hehe['he1'] = 'he1';
$hehe['he2'] = 'he2';
$hh = (object) $hehe;
print_r($hh);
打印结果:
stdClass Object ( [he1] => he1 [he2] => he2 )
函数引用与php中变量引用一样使用的是&符号了,今天我们就一起来看看函数的引用返回的一些例子,希望这些例子能够对各位有帮助.引用返回
手册里是这么写的:引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!要返回引用
当你想将函数的返回引用绑定到某个变量时,PHP允许你这么做:
function &returns_reference()
{
static $someref = 0;
$someref++;
return $someref;
}
$newref = &returns_reference();//引用返回,相当于 $newref = &$someref;
echo $newref; //1
$notref = returns_reference(); //值传递的是副本
$newref = 100;
echo $notref; //2
$newref = 100;
echo returns_reference(); //101
可见,想让函数返回引用,必须在函数申明和赋值时都带上&操作符。
对于类中方法也是如此:
class foo {
public $value = 0;
public function &getValue() {
return $this->value;
}
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue;
一些简单的例子
看下面的简单例子,尝试去理解引用返回。
<?php
function &test()
{
// 声明一个静态变量
static $b = 0;
$b = $b+1;
echo $b;
return $b;
}
$a = test(); //这条语句会输出 $b 的值为 1
$a = 5;
$a = test(); //这条语句会输出 $b 的值为2
$a = &test(); //这条语句会输出 $b 的值为3
$a = 5;
$a = test(); //这条语句会输出 $b的值 为6
?>
程序运行结果:
1
2
3
6
尽管函数声明方式是 function &test() 这样,但我们通过这种方式 $a = test() 的函数调用得到的其实不是函数的引用返回,这跟普通的函数调用没有区别。PHP 规定通过 $a = &test() 这种方式得到的才是函数的引用返回。
用上面的例子来解释就是,$a = test() 这种方式调用函数,只是将函数的值赋给 $a 而已,而$a做任何改变都不会影响到函数中的$b。
而通过 $a = &test() 方式调用函数呢,它的作用是将 return $b 中的 $b 变量的内存地址与 $a 变量的内存地址指向了同一个地方。即产生了相当于这样的效果 ($a=&$b), 所以改变 $a 的值也同时改变了 $b 的值。所以在执行了
$a = &test();
$a = 5;
以后,$b的值变为了5。
再来个程序例子加深理解:
<?php
/*
** 值传递和引用传递,值传递传递的是值的一个复本,引用传递传递的是值指向的内存地址
*/
// 函数的引用,定义时也要加上 &
function &func($a,$b){
// 这里为了更直观看到效果,定义一个静态变量
static $result = 0;
$result+=$a+$b;
echo $result.'<br />';
return $result;
}
$a = $b = 10;
// PHP里这样写函数的引用调用,和调用普通函数没有区别(只是将函数的返回值复制给$c这个变量,$c做任何改变不会影响上面函数中的$result)
// 要记住:PHP里的函数引用定义及调用都要在函数名前加上 &
$c = func($a,$b);
// 第一次执行func(),其静态变量$result的值变为 20(10+10)
// 改变$c的值,不会对下面一行语句产生影响
$c = 666;
// 第二次执行func(),其静态变量$result的值变为 40(20+10+10)
$c = func($a,$b);
echo '<hr />';
// 这样才是PHP中引用函数的调用方式
$d = &func($a,$b);
// 第三次执行func(),其静态变量$result的值变为 40(40+10+10)
$d = 888;
// 第四次执行func(),其静态变量$result的值变为 908(888+10+10)
$d = func($a,$b);
?>
防止重复提交表单的方法小编介绍过的不知道有多案了,如数据库判断,js验证,cookies验证及session验证,下面一起来看一个例子。
我们提交表单的时候,不能忽视的一个限制是防止用户重复提交表单,因为有可能用户连续点击了提交按钮或者是攻击者恶意提交数据,那么我们在提交数据后的处理如修改或添加数据到数据库时就会惹上麻烦。
那么如何规避这中重复提交表单的现象出现呢?我们可以从很多方面入手,首先从前端做限制。前端JavaScript在按钮被点击一次后禁用,即disabled,这个方法简单的防止了多次点击提交按钮,但是缺点是如果用户禁用了javascript脚本则失效。第二,我们可以在提交后做redirect页面重定向,即提交后跳转到新的页面,主要避免F5重复提交,但是也有不足之处。第三,就是数据库做唯一索引约束。第四,就是做session令牌验证。
我们现在来了解下简单的利用session token来防止表单重复提交的方法。
我们在表单中加一个input隐藏域,即type="hidden",其value值用来保存token值,当页面刷新的时候这个token值会变化,提交后判断token值是否正确,如果前台提交的token与后台不匹配,则认为是重复提交。
代码如下 | 复制代码 |
<?php /* * PHP简单利用token防止表单重复提交 */ session_start(); header("Content-Type: text/html;charset=utf-8"); function set_token() { $_SESSION['token'] = md5(microtime(true)); } function valid_token() { $return = $_REQUEST['token'] === $_SESSION['token'] ? true : false; set_token(); return $return; } //如果token为空则生成一个token if(!isset($_SESSION['token']) || $_SESSION['token']=='') { set_token(); } if(isset($_POST['web'])){ if(!valid_token()){ echo "token error,请不要重复提交!"; }else{ echo '成功提交,Value:'.$_POST['web']; } }else{ ?> <form method="post" action=""> <input type="hidden" name="token" value="<?php echo $_SESSION['token']?>"> <input type="text" class="input" name="web" value="www,111cn.net"> <input type="submit" class="btn" value="提交" /> </form> <?php } ?> |
以上是一个简单的防止重复提交表单的例子,仅供参考。那么实际项目开发中,会对表单token做更复杂的处理,即我们说的令牌验证。可能要做的处理有:验证来源域,即来路,是否为外部提交;匹配要执行的动作,是添加、修改or删除;其次最重要的是构建token,token可以采用可逆的加密算法,尽可能复杂,因为明文还是不安全的。令牌验证的具体算法可以参考各大PHP框架,如ThinkPHP提供了很好的令牌验证功能。
生成IP我们只要生成一个字符串就可以了,在指定范围的int可存储的空间中就可以生成ipv4的ip数据了,下面我们一起来来看看.有时候需要伪造IP去抓取别的网站内容,最好是国内的IP,网上找了个函数,能随机10个IP段的国内IP,我自己查了些IP数据,手动加了5段IP,一共15个IP段,这样可以随机很多个国内IP了,附代码:
function rand_ip(){
$ip_long = array(
array('607649792', '608174079'), //36.56.0.0-36.63.255.255
array('975044608', '977272831'), //58.30.0.0-58.63.255.255
array('999751680', '999784447'), //59.151.0.0-59.151.127.255
array('1019346944', '1019478015'), //60.194.0.0-60.195.255.255
array('1038614528', '1039007743'), //61.232.0.0-61.237.255.255
array('1783627776', '1784676351'), //106.80.0.0-106.95.255.255
array('1947009024', '1947074559'), //116.13.0.0-116.13.255.255
array('1987051520', '1988034559'), //118.112.0.0-118.126.255.255
array('2035023872', '2035154943'), //121.76.0.0-121.77.255.255
array('2078801920', '2079064063'), //123.232.0.0-123.235.255.255
array('-1950089216', '-1948778497'), //139.196.0.0-139.215.255.255
array('-1425539072', '-1425014785'), //171.8.0.0-171.15.255.255
array('-1236271104', '-1235419137'), //182.80.0.0-182.92.255.255
array('-770113536', '-768606209'), //210.25.0.0-210.47.255.255
array('-569376768', '-564133889'), //222.16.0.0-222.95.255.255
);
$rand_key = mt_rand(0, 14);
$huoduan_ip= long2ip(mt_rand($ip_long[$rand_key][0], $ip_long[$rand_key][1]));
return $huoduan_ip;
}
补充:long2ip函数
把存储空间降到了接近四分之一(char(15)的15个字节对整形的4个字节),计算一个特定的地址是不是在一个区段内页更简单了,而且加快了搜索和排序的速度(虽然有时仅仅是快了一点)。
例子
$ip = long2ip(3232235881);
echo $ip;//127.255.255.255