做过后台的,应该都知道,经常要用到iframe来处理导航,如果按一般的思路来做这个功能,还是挺简单的
可是当我用smarty的时候,就发现了问题,比如,一个iframeset分成了:头部top,左边menu,右边main,
正常情况,用smarty来处理的话,一般是这样:
如果3个页面仅仅只是静态页面的话,就是如下处理
iframe.html代码:
<frame src="/blog_article/top.html" name="topFrame" id="topFrame" scrolling="no">
<frameset cols="180,*" name="btFrame" id="btFrame" frameborder="NO" border="0" framespacing="0">
<frame src="/blog_article/menu.html" id="leftbar" noresize name="menu" scrolling="yes">
<frame src="/blog_article/main.html" id="rightbar" noresize name="main" scrolling="yes">
</frameset>
假设iframe里面的内容页都要应用到一些特殊处理,如:
top.html需要显示后台登陆用户名
menu.html中menu都是动态获取
main.html中需要读取服务器的信息
这样的话,我们会给3个内容页分别用3个后台处理页
//top.php:
$smarty->assign('user', $names );
smarty_Output('top.php')
//menu.php:
$arr=array();
$arr=GetMenu();
$smarty->assign('menu', $arr);
smarty_Output('menu.php');
//main.php
$smarty->assign('serverInfo', $serverInfoArr);
smarty_Output('main.php');
//显示iframe页
smarty_Output('iframe.html')
上面的处理方法,完全能达到要求
iframe.html代码:
<frame src="/blog_article/top.html" name="topFrame" id="topFrame" scrolling="no">
<frameset cols="180,*" name="btFrame" id="btFrame" frameborder="NO" border="0" framespacing="0">
<frame src="/blog_article/menu.html" id="leftbar" noresize name="menu" scrolling="yes">
<frame src="/blog_article/main.html" id="rightbar" noresize name="main" scrolling="yes">
</frameset>
现在我们假设,我们现在要对这3个内容页分别进行分角色处理,不同角色,3个页面需要显示不同的效果
按上面的处理方法,我们就需要对3个页面分别处理,这样就自然的就多了冗余的处理,而且以后的维护也麻烦
于是我想到了下面的方法,独立出一个专门的处理程序iframe.php,通过条件来模拟出上面3个页面
直接贴代码了:
iframe.php 后台代码:
/*此处放共用处理代码*/
switch($src)
{
case "top":
/*此处放处理代码*/
smarty_Output('top.html');
break;
case "menu":
/*此处放处理代码*/
smarty_Output('menu.html');
break;
case "main":
/*此处放处理代码*/
smarty_Output('main.html');
break;
default:
break;
}
iframe.html:
<frame src="/blog_article/iframe/src/top.html" name="topFrame" id="topFrame" scrolling="no">
<frameset cols="180,*" name="btFrame" id="btFrame" frameborder="NO" border="0" framespacing="0">
<frame src="/blog_article/iframe/src/menu.html" id="leftbar" noresize name="menu" scrolling="yes">
<frame src="/blog_article/iframe/src/main.html" id="rightbar" noresize name="main" scrolling="yes">
</frameset>
通过这样处理,我感觉方便多了
操作符
操作符是用来对数组和变量进行某种操作运算的符号。
1、算术操作符
操作符
名称
示例
+
加
$a+$b
-
减
$a-$b
*
乘
$a*$b
/
除
$a/$b
%
取余
$a%$b
2、复合赋值操作符
操作符
使用方法
等价于
+=
$a+=$b
$a=$a+$b
-=
$a-=$b
$a=$a-$b
*=
$a*=$b
$a=$a*$b
/=
$a/=$b
$a=$a/$b
%=
$a%=$b
$a=$a%$b
.=
$a.=$b
$a=$a.$b
前置递增递减和后置递增递减运算符:
$a=++$b;
$a=$b++;
$a=--$b;
$a=$b--;
3、比较运算符
操作符
名称
使用方法
= =
等于
$a= =$b
= = =
恒等
$a= = =$b
!=
不等
$a!=$b
!= =
不恒等
$a!= =$b
<>
不等
$a<>$b
<
小于
$a<$b
>
大于
$a>$b
<=
小于等于
$a<=$b
>=
大于等于
$a>=$b
注:恒等表示只有两边操作数相等并且数据类型也相当才返回true;
例如:0= ="0" 这个返回为true ,因为操作数相等
0= = ="0" 这个返回为false,因为数据类型不同
4、逻辑运算符
操作符
使用方法
使用方法
说明
!
非
!$b
如果$b是false,则返回true;否则相反
&&
与
$a&&$b
如果$a和$b都是true,则结果为true;否则为false
||
或
$a||$b
如果$a和$b中有一个为true或者都为true时,其结果为true;否则为false
and
与
$a and $b
与&&相同,但其优先级较低
or
或
$a or $b
与||相同,但其优先级较低
操作符"and"和"or"比&&和||的优先级要低。
5、三元操作符
Condition ? value if true : value if false
示例:($grade>=50 ? "Passed" : "Failed")
6、错误抑制操作符:
$a=@(57/0);
除数不能为0,会出错,所以加上@避免出现错误警告。
7、数组操作符
操作符
使用方法
使用方法
说明
+
联合
!$b
返回一个包含了$a和$b中所有元素的数组
= =
等价
$a&&$b
如果$a和$b具有相同的元素,返回true
= = =
恒等
$a||$b
如果$a和$b具有相同的元素以及相同的顺序,返回true
!=
非等价
$a and $b
如果$a和$b不是等价的,返回true
<>
非等价
如果$a和$b不是等价的,返回true
!= =
非恒等
$a or $b
如果$a和$b不是恒等的,返回true
操作符的优先级和结合性:
一般地说,操作符具有一组优先级,也就是执行他们的顺序。
操作符还具有结合性,也就是同一优先级的操作符的执行顺序。这种顺序通常有从左到右,从右到左或者不相关。
下面给出操作符优先级的表。最上面的操作符优先级最低,按着表的由上而下的顺序,优先级递增。
操作符优先级
结合性
操作符
左
,
左
Or
左
Xor
左
And
右
左
= += -= *= /= .= %= &= |= ^= ~= <<= >>=
左
?:
左
||
左
&&
左
|
左
^
左
&
不相关
= = != = = = = != =
不相关
<<= >>=
左
<< >>
左
+ - .
左
* / %
右
! ~ ++ -- (int)(double)(string)(array)(object) @
右
[]
不相关
New
不相关
()
为了避免优先级混乱,可以使用括号避开优先级。
控制结构
如果我们希望有效地相应用户的输入,代码就需要具有判断能力。能够让程序进行判断的结构称为条件。
1、if..else循环有三种结构
第一种是只有用到if条件,当作单纯的判断。解释成“若发生了某事则怎样处理”。语法如下:
if (expr) { statement }
其中的expr为判断的条件,通常都是用逻辑运算符号当判断的条件。而statement为符合条件的执行部分程序,若程序只有一行,可以省略大括号 {}。
范例:本例省略大括号。
<?php
if ($state==1)echo "哈哈" ;
?>
这里特别注意的是,判断是否相等是==而不是=,ASP程序员可能常犯这个错误,=是赋值。
范例:本例的执行部分有三行,不可省略大括号。
<?php
if ($state==1) {
echo "哈哈 ;
echo "<br>" ;
}
?>
第二种是除了if之外,加上了else的条件,可解释成“若发生了某事则怎样处理,否则该如何解决”。语法如下:
if (expr) { statement1 } else { statement2 }
范例:上面的例子来修改成更完整的处理。其中的else由于只有一行执行的指令,因此不用加上大括号。
<?php
if ($state==1) {
echo "哈哈" ;
echo "<br>";
}
else{
echo "呵呵";
echo "<br>";
}
?>
第三种就是递归的if..else循环,通常用在多种决策判断时。它将数个if..else拿来合并运用处理。
直接看下面的例子:
<?php
if ( $a > $b ) {
echo "a 比 b 大" ;
} elseif ( $a == $b ) {
echo "a 等于 b" ;
} else {
echo "a 比 b 小" ;
}
?>
上例只用二层的if..else循环,用来比较a和b两个变量。实际要使用这种递归if..else循环时,请小心使用,因为太多层的循环容易使设计的逻辑出问题,或者少打了大括号等,都会造成程序出现莫名其妙的问题。
2、for循环就单纯只有一种,没有变化,它的语法如下:
for (expr1; expr2; expr3) { statement }
其中的expr1为条件的初始值。expr2为判断的条件,通常都是用逻辑运算符号(logical operators)当判断的条件。expr3为执行statement后要执行的部份,用来改变条件,供下次的循环判断,如加一..等等。而statement为符合条件的执行部分程序,若程序只有一行,可以省略大括号 {}。
下例是用for循环写的的例子:
<?php
for ( $i = 1 ; $i <= 10 ; $i ++) {
echo "这是第".$i."次循环<br>" ;
}
?>
3、switch循环,通常处理复合式的条件判断,每个子条件,都是case指令部分。在实作上若使用许多类似的if指令,可以将它综合成switch循环。
语法如下:
switch (expr) { case expr1: statement1; break; case expr2: statement2; break; default: statementN; break; }
其中的expr条件,通常为变量名称。而case后的exprN,通常表示变量值。冒号后则为符合该条件要执行的部分。注意要用break跳离循环。
<?php
switch ( date ( "D" )) {
case "Mon" :
echo "今天星期一" ;
break;
case "Tue" :
echo "今天星期二" ;
break;
case "Wed" :
echo "今天星期三" ;
break;
case "Thu" :
echo "今天星期四" ;
break;
case "Fri" :
echo "今天星期五" ;
break;
default:
echo "今天放假" ;
break;
}
?>
这里需要注意的是break;别遗漏了,default,省略是可以的。
很明显的,上述的例子用if循环就很麻烦了。当然在设计时,要将出现机率最大的条件放在最前面,最少出现的条件放在最后面,可以增加程序的执行效率。上例由于每天出现的机率相同,所以不用注意条件的顺序。
早在Sql注入横行的前几年,字符串转化为整数就已经被列为每个web程序必备的操作了。web程序将get或post来的id、整数等值强制经过转化函数转化为整数,过滤掉危险字符,尽可能降低系统本身被Sql注入的可能性。
现如今,虽然Sql注入已经逐渐淡出历史舞台,但是,为了保证web程序的正常运行,减少出错概率,更好的保证用的满意度,我们同样需要将用户的不正确输入转化为我们所需要的。
转化方式
在PHP中,我们可以使用3种方式将字符串转化为整数。
1.强制类型转换方式
强制类型转换方式,就是“在要转换的变量之前加上用括号括起来的目标类型”(摘自PHP手册“类型戏法”节)的方式。
<?php
$foo = "1"; // $foo 是字符串类型
$bar = (int)$foo; // $bar 是整型
?>
对于整型来说,强制转换类型名称为int或者integer。
2.内置函数方式
内置函数方式,就是使用PHP的内置函数intval进行变量的转换操作。
<?php
$foo = "1"; // $foo 是字符串类型
$bar = intval($foo); // $bar 是整型
?>
intval函数的格式为:
int intval(mixed $var [, int $base]); (摘自PHP手册)
虽然PHP手册中明确指出,intval()不能用于array和object的转换。但是经过我测试,转换array的时候不会出任何问题,转换值为1,而不是想象中的0。恐怕是因为在PHP内部,array类型的变量也被认为是非零值得缘故吧。转换object的时候,PHP会给出如下的 notice:
Object of class xxxx could not be converted to int in xxxxx.php on line xx
转换值同样为1。
3.格式化字符串方式
格式化字符串方式,是利用sprintf的%d格式化指定的变量,以达到类型转换的目的。
<?php
$foo = "1"; // $foo 是字符串类型
$bar = sprintf("%d", $foo); // $bar 是字符串类型
?>
严格意义上讲sprintf的转换结果还是string型,因此它不应该算是字符串转化为整数的方式。但是经过他处理之后的字符串值确实已经成为了“被强制转化为字符串类型的整数”。
实际测试
上面介绍了PHP中,将字符串转化为整数的3种方式。对于一般的程序员来说,看到这里就算结束了,下面的部分是针对变态程序员的。
1.基本功能测试
设定以下数组:
<?php
$a[] = "1";
$a[] = "a1";
$a[] = "1a";
$a[] = "1a2";
$a[] = "0";
$a[] = array('4',2);
$a[] = "2.3";
$a[] = "-1";
$a[] = new Directory();
?>
使用三种方式依次转化上面给出的数组中的元素,查看转换情况。程序源代码如下:
<?php
$a[] = "1";
$a[] = "a1";
$a[] = "1a";
$a[] = "1a2";
$a[] = "0";
$a[] = array('4',2);
$a[] = "2.3";
$a[] = "-1";
$a[] = new Directory();
// int
print "(int)<br />";
foreach($a as $v)
{
var_dump((int)$v);
print "<br />";
}
// intval
print "intval();<br />";
foreach($a as $v)
{
var_dump(intval($v));
print "<br />";
}
// sprintf
print "sprintf();<br />";
foreach($a as $v)
{
var_dump(sprintf("%d", $v));
print "<br />";
}
?>
程序的最终运行结果如下(已经去掉转换object时出现的notice):
(int)
int(1)
int(0)
int(1)
int(1)
int(0)
int(1)
int(2)
int(-1)
int(1)
intval();
int(1)
int(0)
int(1)
int(1)
int(0)
int(1)
int(2)
int(-1)
int(1)
sprintf();
string(1) "1"
string(1) "0"
string(1) "1"
string(1) "1"
string(1) "0"
string(1) "1"
string(1) "2"
string(2) "-1"
string(1) "1"
由此可以看出,三种转换的结果是完全一样的。那么从功能上讲,3种方式都可以胜任转换工作,那么接下来的工作就是看哪一种效率更高了。
2.性能测试
被测试字符串是我们在注入工作中可能会使用到的一种:
<?php
$foo = "1';Select * ...";
?>
获取时间点的函数如下(用于获取测试起始点和结束点,以计算消耗时间):
<?php
**
* Simple function to replicate PHP 5 behaviour
*/
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
?>
(摘自PHP手册microtime()函数节)
测试过程是使用每种方式转换变量$foo 1000000次(100万次),并将各自的消耗时间输出,总共进行三组测试,尽可能降低误差。测试程序如下:
<?php
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
$foo = "1';Select * ...";
// (int)
$fStart = microtime_float();
for($i=0;$i<1000000;$i++)
{
$bar = (int)$foo;
}
$fEnd = microtime_float();
print "(int):" . ($fEnd - $fStart) . "s<br />";
// intval()
$fStart = microtime_float();
for($i=0;$i<1000000;$i++)
{
$bar = intval($foo);
}
$fEnd = microtime_float();
print "intval():" . ($fEnd - $fStart) . "s<br />";
// sprintf()
$fStart = microtime_float();
for($i=0;$i<1000000;$i++)
{
$bar = sprintf("%d", $foo);
}
$fEnd = microtime_float();
print "sprintf():" . ($fEnd - $fStart) . "s<br />";
?>
最终的测试结果:
(int):0.67205619812012s
intval():1.1603000164032s
sprintf():2.1068270206451s
(int):0.66051411628723s
intval():1.1493890285492s
sprintf():2.1008238792419s
(int):0.66878795623779s
intval():1.1613430976868s
sprintf():2.0976209640503s
虽然这个测试有点变态(谁会连续转换100w次的整数?),但是由此可以看出,使用强制类型转换将字符串转化为整数速度是最快的。
总结
使用强制类型转换方式将字符串转化为整数是最直接的转化方式之一(可以直接获得整型的变量值)。从代码可读性角度上讲,sprintf方式代码比较长,而且其结果有可能还需要再次进行强制类型转换,而intval函数是典型的面向过程式转换,强制类型转换则比较直接的将“我要转化”这个思想传递给阅读者。从效率上讲,强制类型转换方式也是最快速的转化方式。因此,对于经常进行转化工作的程序员,我推荐使用这种方式。