CSS3 为不同媒介设置样式的方法(CSS3 Media Queries)

随着智能手机、平板电脑越来越流行,许多网站都开始考虑为这些移动设备开发一套专属布局和样式。幸好 CSS3 提供了针对不同设备的查询规则,让这一目的变得非常容易实现。

<style type="text/css">
/*
	说明:CSS3 为不同媒介设置样式的方式(CSS3 Media Queries)
	来源:http://www.stuffandnonsense.co.uk/blog/about/hardboiled_css3_media_queries/
	整理:CodeBit.cn [ http://www.codebit.cn ]
*/

/* 智能手机 (纵向 和 横向) ----------- */
@media only screen 
and (min-device-width : 320px) 
and (max-device-width : 480px) {
/* Styles */
}

/* 智能手机 (横向) ----------- */
@media only screen 
and (min-width : 321px) {
/* Styles */
}

/* 智能手机 (纵向) ----------- */
@media only screen 
and (max-width : 320px) {
/* Styles */
}

/* iPad 系列 (纵向 和 横向) ----------- */
@media only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) {
/* Styles */
}

/* iPad 系列 (横向) ----------- */
@media only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) 
and (orientation : landscape) {
/* Styles */
}

/* iPad 系列 (纵向) ----------- */
@media only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) 
and (orientation : portrait) {
/* Styles */
}

/* 台式机 和 笔记本 ----------- */
@media only screen 
and (min-width : 1224px) {
/* Styles */
}

/* 大屏幕 ----------- */
@media only screen 
and (min-width : 1824px) {
/* Styles */
}

/* iPhone 4 ----------- */
@media
only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5) {
/* Styles */
}
</style>

当然,将所有样式放在一起不是一个好主意,你可以将不同设备特定的 CSS 放到不同文件中,然后再通过 link 节点的 media 属性来加载:

<head>

<link rel="stylesheet" href="smartphone.css" 
media="only screen and (min-device-width : 320px) 
and (max-device-width : 480px)">

<link rel="stylesheet" href="smartphone-landscape.css" 
media="only screen and (min-width : 321px)">

<link rel="stylesheet" href="smartphone-portrait.css" 
media="only screen and (max-width : 320px)">

<link rel="stylesheet" href="ipad.css" 
media="only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px)">

<link rel="stylesheet" href="ipad-landscape.css" 
media="only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) 
and (orientation : landscape)">

<link rel="stylesheet" href="ipad-portrait.css" 
media="only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) 
and (orientation : portrait)">

<link rel="stylesheet" href="widescreen.css" 
media="only screen and (min-width : 1824px)">

<link rel="stylesheet" href="iphone4.css" 
media="only screen 
and (-webkit-min-device-pixel-ratio : 1.5), 
only screen and (min-device-pixel-ratio : 1.5)">

</head>

纯 CSS3 制作的页面卷曲阴影效果

虽然 CSS3 还没有完全定稿,但目前已知的一些功能足以让所有的前端开发攻城师激动不已,灵活的背景图片设置、轻松实现的阴影及边框,还有之前只能靠 Javascript 才能实现的动画效果,在 CSS3 中都能由前端攻城师自己来定义。

虽然 IE 系列浏览器对 CSS3 还不能很好的支持,但 CSS3 毕竟是趋势,所以本站会开始介绍一些 CSS3 的效果。更多精彩,敬请期待 :) 如果你有好的点子,也欢迎和网友们分享,点此了解如何发布文章

本文介绍的是使用纯 CSS3 制作的页面卷曲阴影效果,先看图和示例:

纯 CSS3 制作的页面卷曲阴影效果

纯 CSS3 制作的页面卷曲阴影效果 – 示例

<style type="text/css">
/*
	说明:纯 CSS3 制作的页面卷曲阴影效果
	来源:Matt Hamm [ http://matthamm.com/box-shadow-curl.html ]
	整理:CodeBit.cn [ http://www.codebit.cn ]
*/
ul.box {
	position: relative;
	z-index: 1; /* prevent shadows falling behind containers with backgrounds */
	overflow: hidden;
	list-style: none;
	margin: 0;
	padding: 0;
}

ul.box li {
	position: relative;
	float: left;
	width: 250px;
	height: 150px;
	padding: 0;
	border: 1px solid #efefef;
	margin: 0 30px 30px 0;
	background: #fff;
	-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset;
	-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset;
}

ul.box li:before,
ul.box li:after {
	content: '';
	z-index: -1;
	position: absolute;
	left: 10px;
	bottom: 10px;
	width: 70%;
	max-width: 300px; /* avoid rotation causing ugly appearance at large container widths */
	max-height: 100px;
	height: 55%;
	-webkit-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
	-moz-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
	box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
	-webkit-transform: skew(-15deg) rotate(-6deg);
	-moz-transform: skew(-15deg) rotate(-6deg);
	-ms-transform: skew(-15deg) rotate(-6deg);
	-o-transform: skew(-15deg) rotate(-6deg);
	transform: skew(-15deg) rotate(-6deg);
}

ul.box li:after {
	left: auto;
	right: 10px;
	-webkit-transform: skew(15deg) rotate(6deg);
	-moz-transform: skew(15deg) rotate(6deg);
	-ms-transform: skew(15deg) rotate(6deg);
	-o-transform: skew(15deg) rotate(6deg);
	transform: skew(15deg) rotate(6deg);
}
</style>
<ul class="box">
	<li></li>
	<li></li>
	<li></li>
	<li></li>
	<li></li>
	<li></li>
</ul>

注意:如果有父节点,需要给父节点设置 position: relative; z-index: 99; 否则,阴影可能不会正常显示。

解决 PHP 中 usort 在值相同时改变原始位置的问题

从 PHP 4.1.0 后,usort 在比较的值相同时,原始位置可能会改变,文档中是这样说的:

If two members compare as equal, their order in the sorted array is undefined.

也就是说,如果比较的2个值相同,则它们在排序结果中的顺序是随机的。如果你需要保持相同值的原始位置,可以参考本文的方法。

演示数据:

<?php
/*
解决 PHP 中 usort 在值相同时改变原始位置的问题
作者:Artlover    http://www.CodeBit.cn
*/
$arr = array(
	array('a' => 5, 'b' => 3),
	array('a' => 5, 'b' => 1),
	array('a' => 5, 'b' => 4),
	array('a' => 5, 'b' => 2),
);
?>

数组中第一个元素的值是相同的,期望的结果是保持现有的位置不变,即 b 的顺序为 3,1,4,2

用 usort 排序,当比较字段的值相同时,原始顺序可能会改变

<?php
/*
解决 PHP 中 usort 在值相同时改变原始位置的问题
作者:Artlover    http://www.CodeBit.cn
*/
$callback = create_function('$a,$b', 'return ($a["a"] == $b["a"])?0:(($a["a"] > $b["a"]) ? 1 : -1);');
usort($arr, $callback);
?>

结果:


Array
(
    [0] => Array
        (
            [a] => 5
            [b] => 2
        )
 
    [1] => Array
        (
            [a] => 5
            [b] => 4
        )
 
    [2] => Array
        (
            [a] => 5
            [b] => 1
        )
 
    [3] => Array
        (
            [a] => 5
            [b] => 3
        )
 
)

虽然排序字段的值相同,但是 usort 却将整个数组的顺序打乱了。

如果要在比较的值相同时保持原始位置,可以用 array_multisort :

<?php

/*
解决 PHP 中 usort 在值相同时改变原始位置的问题
作者:Artlover    http://www.CodeBit.cn
*/

// 索引计数器
$i = 0;

// 创建2个空数组,第一个保存要排序的字段,第二个保存原始索引信息
$a = $index = array();

foreach ($arr as $key => $data) {
	$a[$key] = $data['a'];
	$index[] = $i++;
}

// 第一个数组先排,接着按原始索引排
array_multisort($a, SORT_ASC, $index, SORT_ASC, $arr);

?>

结果:


Array
(
    [0] => Array
        (
            [a] => 5
            [b] => 3
        )
 
    [1] => Array
        (
            [a] => 5
            [b] => 1
        )
 
    [2] => Array
        (
            [a] => 5
            [b] => 4
        )
 
    [3] => Array
        (
            [a] => 5
            [b] => 2
        )
 
)

MySQL 数据库中删除重复记录的方法总结

演示数据

表结构:

mysql> desc demo;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| site  | varchar(100)     | NO   | MUL |         |                |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

数据:

mysql> select * from demo order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  2 | http://YITU.org        |
|  3 | http://www.ShuoWen.org |
|  4 | http://www.CodeBit.cn  |
|  5 | http://www.ShuoWen.org |
+----+------------------------+
5 rows in set (0.00 sec)

当没有创建表或创建索引权限的时候,可以用下面的方法:

如果你要删除较旧的重复记录,可以使用下面的语句:

mysql> delete from a 
    -> using demo as a, demo as b
    -> where (a.id > b.id)
    -> and (a.site = b.site);
Query OK, 2 rows affected (0.12 sec)

mysql> select * from demo order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  2 | http://YITU.org        |
|  3 | http://www.ShuoWen.org |
+----+------------------------+
3 rows in set (0.00 sec)

如果你要删除较新的重复记录,可以使用下面的语句:

mysql> delete from a 
    -> using demo as a, demo as b
    -> where (a.id < b.id)
    -> and (a.site = b.site);
Query OK, 2 rows affected (0.12 sec)

mysql> select * from demo order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  2 | http://YITU.org        |
|  4 | http://www.CodeBit.cn  |
|  5 | http://www.ShuoWen.org |
+----+------------------------+
3 rows in set (0.00 sec)

你可以用下面的语句先确认将被删除的重复记录:

mysql> SELECT a.* 
    -> FROM demo a, demo b
    -> WHERE a.id > b.id
    -> AND (a.site = b.site);
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  3 | http://www.ShuoWen.org |
+----+------------------------+
2 rows in set (0.00 sec)

如果有创建索引的权限,可以用下面的方法:

在表上创建唯一键索引:

mysql> alter ignore table demo add unique index ukey (site);
Query OK, 5 rows affected (0.46 sec)
Records: 5  Duplicates: 2  Warnings: 0

mysql> select * from demo order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  2 | http://YITU.org        |
|  3 | http://www.ShuoWen.org |
+----+------------------------+
3 rows in set (0.00 sec)

重复记录被删除后,如果需要,可以删除索引:

mysql> alter table demo drop index ukey;
Query OK, 3 rows affected (0.37 sec)
Records: 3  Duplicates: 0  Warnings: 0

如果有创建表的权限,可以用下面的方法:

创建一个新表,然后将原表中不重复的数据插入新表:

mysql> create table demo_new as select * from demo group by site;
Query OK, 3 rows affected (0.19 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| demo           |
| demo_new       |
+----------------+
2 rows in set (0.00 sec)

mysql> select * from demo order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  2 | http://YITU.org        |
|  3 | http://www.ShuoWen.org |
|  4 | http://www.CodeBit.cn  |
|  5 | http://www.ShuoWen.org |
+----+------------------------+
5 rows in set (0.00 sec)

mysql> select * from demo_new order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  2 | http://YITU.org        |
|  3 | http://www.ShuoWen.org |
+----+------------------------+
3 rows in set (0.00 sec)

然后将原表备份,将新表重命名为当前表:

mysql> rename table demo to demo_old, demo_new to demo;
Query OK, 0 rows affected (0.04 sec)

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| demo           |
| demo_old       |
+----------------+
2 rows in set (0.00 sec)

mysql> select * from demo order by id;
+----+------------------------+
| id | site                   |
+----+------------------------+
|  1 | http://www.CodeBit.cn  |
|  2 | http://YITU.org        |
|  3 | http://www.ShuoWen.org |
+----+------------------------+
3 rows in set (0.00 sec)

注意:使用这种方式创建的表会丢失原表的索引信息!

mysql> desc demo;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(11) unsigned | NO   |     | 0       |       |
| site  | varchar(100)     | NO   |     |         |       |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

如果要保持和原表信息一致,你可以使用 show create table demo; 来查看原表的创建语句,然后使用原表的创建语句创建新表,接着使用 insert … select 语句插入数据,再重命名表即可。

当然,如果要避免重复记录,最好的办法还是不要插入重复数据,可以参考本站另外一篇文章:MySQL 当记录不存在时插入(insert if not exists)

PHP 中检查或过滤 IP 地址

网络环境异常复杂,有时候我们不得不禁止一些恶意用户访问,禁止的方式有很多种,其中一种就是通过 IP 来限制,本文提供的方法允许你通过 IP 区间、CIDR (Classless Inter-Domain Routing)及单个 IP 格式来检查或过滤 IP 地址。

你可以通过增加一个配置文件,然后将需要禁止的一些 IP 地址通过一定规则添加到配置文件中,在程序初始化的时候,读取配置文件中的每个规则,然后通过本文提供的方法去检查当前访问的客户端 IP 地址是否存在于这些规则中,如果存在,则拒绝提供服务。

<?php
/**
 * PHP 中检查或过滤 IP 地址
 * 
 * 支持 IP 区间、CIDR(Classless Inter-Domain Routing)及单个 IP 格式
 * 整理:http://www.CodeBit.cn
 * 参考:
 *   - {@link http://us2.php.net/manual/zh/function.ip2long.php#70055}
 *   - {@link http://us2.php.net/manual/zh/function.ip2long.php#82397}
 * 
 * @param string $network 网段,支持 IP 区间、CIDR及单个 IP 格式
 * @param string $ip 要检查的 IP 地址
 * @return boolean
 */
function netMatch($network, $ip) {

    $network = trim($network);
    $ip = trim($ip);
    
    $result = false;
    
    // IP range : 174.129.0.0 - 174.129.255.255
    if (false !== ($pos = strpos($network, "-"))) {
        $from = ip2long(trim(substr($network, 0, $pos)));
        $to = ip2long(trim(substr($network, $pos+1)));
        
        $ip = ip2long($ip);
        
        $result = ($ip >= $from and $ip <= $to);

    // CIDR : 174.129.0.0/16
    } else if (false !== strpos($network,"/")) {
        list ($net, $mask) = explode ('/', $network);
        $result = (ip2long($ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($net); 

    // single IP
    } else {
        $result = $network === $ip;
    
    }
    
    return $result;
}

// 174.129.0.0 - 174.129.255.255
var_dump(netMatch(' 174.129.0.0  -  174.129.255.255 ', '174.129.1.31')); // True
var_dump(netMatch(' 174.129.0.0/16 ', '174.139.1.31')); // False
var_dump(netMatch(' 174.129.1.32 ', '174.129.1.31')); // False
?>

由于中国使用的大多数都是动态 IP 地址,所以通过 IP 地址限制访问具有一定的局限性,使用的时候需要谨慎,但是对于应急限制访问来说,还是非常有用的。

正则表达式:匹配至少有一个非空白字符并且不超过指定长度

最近需要用到一个验证,规则为:至少有一个非空白字符并且不超过指定长度,想用正则表达式来处理,上网搜了一下,发现其他人也有和我一样的需求,并且有高手给了几个很精彩的解决方案,现将网上的解决方案整理一下,以备其他有相同需求的人参考。

chinmo 逆向思维解决方案

<script type="text/javascript">
/**
 * 至少有一个非空白字符并且不超过6个字符的正则表达式
 * 
 * 作者:chinmo
 * 整理:http://www.CodeBit.cn
 * 来源:http://topic.csdn.net/u/20090207/18/ffa003ed-ecd4-40e0-b81f-36aa1fe46d85.html#r_55136904
 */
var pattern = /^[s]{0,}$|^[ws]{7,}$/g;
var str = "";
var str1 = " ";
var str2 = "a";
var str3 = "abcdefgabcdefgabcdefgabcdefgg";
var str4 = " a ";

document.write(!pattern.test(str))
document.write(!pattern.test(str1))
document.write(!pattern.test(str2))
document.write(!pattern.test(str3))
document.write(!pattern.test(str4))
</script>

正则表达式规则分析:

  • ^[s]{0,}$ :整个字符串为空或者都是空白字符
  • ^[ws]{7,}$ : 整个字符串长度大于6

作者采用逆向思维,通过匹配不符合条件的情况,再通过取反(注意每个 document.write 中的感叹号)来实现要求达到的效果。

JK_10000 逆向思维解决方案简化版

<script type="text/javascript">
/**
 * 至少有一个非空白字符并且不超过6个字符的正则表达式
 * 
 * 作者:JK_10000
 * 整理:http://www.CodeBit.cn
 * 来源:http://topic.csdn.net/u/20090207/18/ffa003ed-ecd4-40e0-b81f-36aa1fe46d85.html#rt_55145516
 */
var pattern = /.{7}|^s*$/g;
var str = "";
var str1 = " ";
var str2 = "a";
var str3 = "www.CodeBit.cn";
var str4 = " a ";

document.write(!pattern.test(str))
document.write(!pattern.test(str1))
document.write(!pattern.test(str2))
document.write(!pattern.test(str3))
document.write(!pattern.test(str4))
</script>

正则表达式规则分析:

  • .{7} : 整个字符串长度大于6,注意:这里的 . 匹配任意字符
  • ^s*$ :整个字符串为空或者都是空白字符

JK_10000 正向思维解决方案

<script type="text/javascript">
/**
 * 至少有一个非空白字符并且不超过6个字符的正则表达式
 * 
 * 作者:JK_10000
 * 整理:http://www.CodeBit.cn
 * 来源:http://hi.baidu.com/jkisjk/blog/item/b54a7a3d1c7ce3c09f3d629b.html
 * 来源:http://topic.csdn.net/u/20090207/18/ffa003ed-ecd4-40e0-b81f-36aa1fe46d85.html#rt_55145611
 */
var pattern = /^(?!.{7}|^s*$)/g;
var str = "";
var str1 = " ";
var str2 = "a";
var str3 = "www.CodeBit.cn";
var str4 = " a ";

document.write(pattern.test(str))
document.write(pattern.test(str1))
document.write(pattern.test(str2))
document.write(pattern.test(str3))
document.write(pattern.test(str4))
</script>

正则表达式规则分析:

  • .{7} : 整个字符串长度大于6,注意:这里的 . 匹配任意字符
  • ^s*$ :整个字符串为空或者都是空白字符

作者使用了正则表达式的顺序否定环视 ,指明开始(^)后面不能有7个及以上字符,或者整个字符串为空(s 没有的情况下,^$表示内容为空),或者全部都是空白字符 (s*)。

不过,该正则表达式可以将环视条件中的 ^ 去掉,即 /^(?!.{7}|s*$)/g , 因为规则一开始就已经有了一个 ^ 。

<script type="text/javascript">
/**
 * 至少有一个非空白字符并且不超过6个字符的正则表达式
 * 
 * 作者:JK_10000
 * 整理:http://www.CodeBit.cn
 * 来源:http://hi.baidu.com/jkisjk/blog/item/b54a7a3d1c7ce3c09f3d629b.html
 * 来源:http://topic.csdn.net/u/20090207/18/ffa003ed-ecd4-40e0-b81f-36aa1fe46d85.html#rt_55145611
 */
var pattern = /^(?!.{7}|s*$)/g;
var str = "";
var str1 = " ";
var str2 = "a";
var str3 = "www.CodeBit.cn";
var str4 = " a ";

document.write(pattern.test(str))
document.write(pattern.test(str1))
document.write(pattern.test(str2))
document.write(pattern.test(str3))
document.write(pattern.test(str4))
</script>

wc 发布在 JK 博客评论中的方案

<script type="text/javascript">
/**
 * 至少有一个非空白字符并且不超过6个字符的正则表达式
 * 
 * 作者:wc
 * 整理:http://www.CodeBit.cn
 * 来源:http://hi.baidu.com/jkisjk/blog/item/b54a7a3d1c7ce3c09f3d629b.html
 */
var pattern = /^(?=.*?S)[sS]{0,6}$/g;
var str = "";
var str1 = " ";
var str2 = "a";
var str3 = "www.CodeBit.cn";
var str4 = " a ";

document.write(pattern.test(str))
document.write(pattern.test(str1))
document.write(pattern.test(str2))
document.write(pattern.test(str3))
document.write(pattern.test(str4))
</script>

正则表达式规则分析:

  • (?=.*?S) :肯定顺序环视,指定任意多个任意字符后面有个非空白字符
  • [sS]{0,6} : 6个以内的空白或者非空白字符

在 Javascript 中使用全局匹配修饰符 g 的时候要特别注意,可参考本站的另外一篇文章:Javascript 中使用 exec 进行正则表达式全局匹配时的注意事项

PHP 的 array_diff() 函数在处理大数组时的效率问题

PHP 5.2.6 以上版本的 array_diff() 函数在处理大数组时,需要花费超长时间,这个 bug 已经被官方确认;在这个问题被修复之前或者在我们不能控制 PHP 版本的时候,可以使用本文提供的方法。

cisa 提交到 PHP 官方 BUG 页面上的方法

<?php
/**
 * 解决 php 5.2.6 以上版本 array_diff() 函数在处理
 * 大数组时的需要花费超长时间的问题
 * 
 * 整理:http://www.CodeBit.cn
 * 来源:http://bugs.php.net/47643
 */
function array_diff_fast($data1, $data2) {
    $data1 = array_flip($data1);
    $data2 = array_flip($data2);

    foreach($data2 as $hash => $key) {
       if (isset($data1[$hash])) unset($data1[$hash]);
    }

    return array_flip($data1);
}
?>

根据 ChinaUnix 论坛版主 hightman 思路重写的方法

<?php
/**
 * 解决 php 5.2.6 以上版本 array_diff() 函数在处理大数组时的效率问题
 * 根据 ChinaUnix 论坛版主 hightman 思路写的方法
 * 
 * 整理:http://www.CodeBit.cn
 * 参考:http://bbs.chinaunix.net/viewthread.php?tid=938096&rpid=6817036&ordertype=0&page=1#pid6817036
 */
function array_diff_fast($firstArray, $secondArray) {

    // 转换第二个数组的键值关系
    $secondArray = array_flip($secondArray);

    // 循环第一个数组
    foreach($firstArray as $key => $value) { 

        // 如果第二个数组中存在第一个数组的值
        if (isset($secondArray[$value])) {

            // 移除第一个数组中对应的元素
            unset($firstArray[$key]); 
        } 
    }

    return $firstArray; 
}
?>

此方法只交换了第二个数组的 key 和 value,所以效率更高。

注意:PHP 内置的 array_diff() 函数可以处理多个数组,而本文提供的方法只处理了两个数组的比较。

Javascript 中使用 exec 进行正则表达式全局匹配时的注意事项

在 Javascript 中使用 exec 进行正则表达式全局匹配时,有一个非常容易犯的错误,这是因为 exec() 在全局模式下的行为稍微有点复杂。本文就是介绍在使用 Javascript 中使用 exec 进行正则表达式全局匹配时的注意事项。

先看一下常见的用法:

 
<script type="text/javascript">
 
var pattern = /http://([^/s]+)/;
alert(pattern.exec('http://www.codebit.cn')); // http://www.codebit.cn,www.codebit.cn
alert(pattern.exec('http://YITU.org')); // http://YITU.org,YITU.org
 
// 也可以直接写成 /http://([^/]+)/.exec('http://www.codebit.cn');
 
</script>

接下来看一下全局模式下的诡异事件:

 
<script type="text/javascript">
 
var pattern = /http://([^/s]+)/g;   // 使用了 g 修饰符
alert(pattern.exec('http://www.codebit.cn')); // http://www.codebit.cn,www.codebit.cn
alert(pattern.exec('http://YITU.org')); // 并没有返回期望的 http://YITU.org,YITU.org ,而是返回了 null
 
</script>

第二个语句并没有返回期望的结果,而是返回了 null ,这是因为:


在全局模式下,当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把正则表达式对象的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。

下面是正常的全局模式下的匹配方式:

 
<script type="text/javascript">
 
var pattern = /http://([^/s]+)/g;
var str = "CodeBit.cn : http://www.codebit.cn | YITU.org : http://YITU.org"; 
var result;
while ((result = pattern.exec(str)) != null)  {
	alert("Result : " + result + "  LastIndex : " + pattern.lastIndex);
}
 
//Result : http://www.codebit.cn,www.codebit.cn  LastIndex : 34
//Result : http://YITU.org,YITU.org  LastIndex : 67
 
</script>

从上面的代码我们可以看到,之所以出现第二段代码中的问题,影响因素是 lastIndex ,所以我们可以通过将 lastIndex 手动置 0 的方式来解决这个问题。

 
<script type="text/javascript">
 
var pattern = /http://([^/s]+)/g;   // 使用了 g 修饰符
alert(pattern.exec('http://www.codebit.cn')); // http://www.codebit.cn,www.codebit.cn
pattern.lastIndex = 0;
alert(pattern.exec('http://YITU.org')); // http://YITU.org,YITU.org 
 
</script>

总结:

在全局模式下,如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串,就必须手动地把 lastIndex 属性重置为 0。

在 XSLTProcessor 中 registerPHPFunctions 后无法调用 php 函数

XSLT 是一个非常方便的转换 XML 的工具,PHP 里面是通过 XSLTProcessor 来实现;XSLT 中内置了许多有用的函数,同时,只需要调用 XSLTProcessor 实例的 registerPHPFunctions 方法,我们就可以在 XSLT 中直接使用 PHP 的函数,这大大增强了 XSLT 的处理能力。

但是,在 XSLT 中使用 PHP 函数时,很多人会遇到如下两种错误:

(1) Warning: XSLTProcessor::transformToXml(): xmlXPathCompiledEval: 1 objects left o
n the stack.
(2)PHP Warning: XSLTProcessor::transformToXml(): xmlXPathCompOpEval: function func
tion bound to undefined prefix php in ….

示例代码:

 
<?php
$xml = <<<EOB
<allusers>
 <user>
  <uid>bob</uid>
 </user>
 <user>
  <uid>joe</uid>
 </user>
</allusers>
EOB;
$xsl = <<<EOB
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8" indent="yes"/>
 <xsl:template match="allusers">
  <html><body>
    <h2>Users</h2>
    <table>
    <xsl:for-each select="user">
      <tr><td>
        <xsl:value-of
             select="php:function('ucfirst',string(uid))"/>
      </td></tr>
    </xsl:for-each>
    </table>
  </body></html>
 </xsl:template>
</xsl:stylesheet>
EOB;
$xmldoc = DOMDocument::loadXML($xml);
$xsldoc = DOMDocument::loadXML($xsl);
 
$proc = new XSLTProcessor();
$proc->registerPHPFunctions();
$proc->importStyleSheet($xsldoc);
echo $proc->transformToXML($xmldoc);
?>

其实,出现这种错误,是因为我们没有定义 PHP namespace ,只需要在

 
<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

中增加 xmlns:php="http://php.net/xsl" 就能解决此问题, 即

 
<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:php="http://php.net/xsl">

在 Zend Framework MVC 下禁用 view 或者 layout

在 Zend_Controller 中禁用 view

在 Action 级别禁用 view:

 
<?php
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
         $this->_helper->viewRenderer->setNoRender();
    }
}
?>

在执行当前 action 的时候会不会展示 view .

在 Controller 级别禁用 view:

 
<?php
class FooController extends Zend_Controller_Action
{
    public function init()
    {
         $this->_helper->viewRenderer->setNoRender();
    }
}
?>

在执行当前 controller 下的所有 action 的时候都不会展示 view .

全局级别禁用 view:

 
<?php
Zend_Controller_Front::getInstance()->setParam('noViewRenderer', true);
?>

在整个程序的执行过程中都不会展示 view .

在 Controller 中禁用或改变 layout

禁用 layout

 
<?php
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        $this->_helper->layout->disableLayout();
    }
}
?>

在此 action 执行的时候将不会使用 Zend_Layout 。

改变 layout

 
<?php
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        $this->_helper->layout->setLayout('other');
    }
}
?>

在此 action 执行的时候将使用名为 other 的 layout 。