删除数组中的元素,第一想法是使用unset函数,它确实可以删除,但是可能会在后面操作该数组的时候出现问题。通过下面的例子来说明:
$arr = array(0, 1, 2, 3, 4);
$index = 2;
unset($arr[$index]);
echo count($arr);
if (empty($arr[$index])) {
echo "arr[$index] is empty";
}
print_r($arr);
输出为:
4
arr[2] is empty
Array([0] => 0 [1] => 1 [3] => 3 [4] => 4)
从上面的输出结果可以看到数组的长度是正常的,但是下标还是保持原来的,所以按照下标去获取元素就会出问题。另外此方法对key-value形式的数组是安全的。
如何安全的删除元素呢?可以使用array_splice函数。array_splice()的用途是删除原始数组中指定的一系列元素,并用其他值代替(如果指定),返回值是被删除的元素。更多信息可以参考官方文档:http://php.net/manual/zh/function.array-splice.php。例如:
$arr = array(0, 1, 2, 3, 4);
$rtn = array_splice($arr, 2, 1);
echo count($arr);
print_r($arr);
print_r($rtn);
输出为:
4
Array
([0] => 0 [1] => 1 [2] => 3 [3] => 4)
Array([0] => 2)
如果想获取删除首位元素后的数组,则可以有两种方法:
1、
$arr = array(0, 1, 2, 3, 4);
array_splice($arr, 0, 1);
2、
$arr = array(0, 1, 2, 3, 4);
$arr = array_splice($arr, 1);
最近浏览器提示flash有新版本,需要升级,按提示提示去adobe的官网下载安装包,注意这个安装包大小不到1M,只是一个壳,它会去下载最新版所需要的文件,但是每次通过它安装都是失败(下载文件进度条在50%左右的时候),也没有给任何错误提示,很是郁闷。后来查了一下,有人说要先卸载老版本的,卸载程序在:应用程序 –> 使用工具中,卸载后安装还是失败,这下麻烦了,新的安装不了,老的又卸载了。进过一番折腾最后终于安装上最新版的flash了。下面介绍详细步骤。
首先进入 http://get.adobe.com/cn/flashplayer/ 点击“立即下载”转到 http://get.adobe.com/cn/flashplayer/download/?installer=Flash_Player_11_for_Mac_OS_X_10.6_-_10.9&os=OSX&browser_type=Gecko&browser_dist=Firefox&d=Adobe_Photoshop_Lightroom_for_Macintosh&dualoffer=false这个页面,此时会提示保存下载文件,选择取消,在此页面的左下角找到“单击此处*以查看疑难解答信息”,点击“单击此处”去到页面 http://helpx.adobe.com/flash-player/kb/installation-problems-flash-player-mac.html,这个页面都是一些无用的帮助信息,不过上面提供了一个离线安装包到是最有用的,查找”Download from the direct link“,在其下面一行有”Click here to download Flash Player“,点击”here“就会开始下载离线安装包。通过这个离线安装包,顺利安装最新版flash。
sort是array对象自带的方法,可以对array中的元素按升序的方式进行排列。如果sort方法没有指定参数,那么array的元素会按照字符的编码数据进行排序。如果想对其他类型的元素进行排序,就需要自己实现一个比较函数作为参数传递给sort,此函数有两个参数a和b,当 a 大于 b 返回大于0的数,a 等于 b 返回0,否则返回一个小于0的值。
需要注意的是排序是在原array上进行的,不会生成副本。
例如一个array为[20,17,15,30,100],默认排序后的结果为100,15,17,20,30。可以看到并不是按照数值的大小排序,如果想要按照数值的大小排序,可以自己实现一个function,如:
function intSort(a, b) {
return a - b;
}
var arr = [20,17,15,30,100];
arr.sort(intSort);
//或通过匿名函数的方式
arr.sort(
function(a, b) {
return a - b;
}
);
//倒序排序
arr.sort(intSort).reverse();
另外如果想按照倒序排列,可以先对array进行sort,然后调用reverse方法即可。
有两种方法可以在命令行下执行sql命令。第一种是使用“-e“参数来指定需要执行的sql语句;第二种是通过管道的方式。语法及例子如下:
1、
MYSQL_HOME/bin/mysql -u用户名 -p密码 -D数据库名 -e"sql 语句"
/usr/local/mysql/bin/mysql -uroot -p123456 -Dmysql -e"select host,user from user";
2、
echo "sql 语句" | MYSQL_HOME/bin/mysql -u用户名 -p密码 -D数据库名
echo "select host,user from user" | /usr/local/mysql/bin/mysql -uroot -p123456 -Dmysql
上面命令执行的结果如下图。从图中可以看到二者的显示结果有些不一样。
使用场景多用在脚本中,例如定期执行存储过程、load data infile以及删除老数据等。
借助于强大的jquery库,通过一些简单的js代码来实现对table数据列进行排序。排序是通过调整table的tr的顺序重新显示,全部在客户端上完成,不需要和服务器交互,因此减轻了服务器的压力。查看Demo请猛点这里。
实现排序的js代码如下:
function tableSort(jqTableObj) {
jqTableObj.find('thead th').click(
function(){
var dataType = $(this).attr('dataType') || 'text';
var index = jqTableObj.find('thead th').index(this) + 1;
var arr = [];
var row = jqTableObj.find('tbody tr');
$.each(row, function(i){arr[i] = row[i]});
if($(this).hasClass('current')){
arr.reverse();
} else {
arr.sort(Utils.sortStr(index, dataType))
jqTableObj.find('thead th').removeClass('current');
$(this).addClass('current');
}
var fragment = document.createDocumentFragment();
$.each(arr, function(i){
fragment.appendChild(arr[i]);
});
jqTableObj.find('tbody').append(fragment);
}
);
var Utils = (function() {
function sortStr(index, dataType){
return function(a, b){
var aText=$(a).find('td:nth-child(' + index + ')').attr('_order') || $(a).find('td:nth-child(' + index + ')').text();
var bText=$(b).find('td:nth-child(' + index + ')').attr('_order') || $(b).find('td:nth-child(' + index + ')').text();
if(dataType != 'text'){
aText=parseNonText(aText, dataType);
bText=parseNonText(bText, dataType);
return aText > bText ? -1 : bText > aText ? 1 : 0;
} else {
return aText.localeCompare(bText)
}
}
}
function parseNonText(data, dataType){
switch(dataType){
case 'int':
return parseInt(data) || 0
case 'float':
return parseFloat(data) || 0
default :
return filterStr(data)
}
}
//过滤中文字符和$
function filterStr(data){
if (!data) {
return 0;
}
return parseFloat(data.replace(/^[\$a-zA-z\u4e00-\u9fa5 ]*(.*?)[a-zA-z\u4e00-\u9fa5 ]*$/,'$1'));
}
return {'sortStr' : sortStr};
})();
}
要想让上面的代码工作,需要在原有的table中注意几点。
1、表头的tr其父元素为thead,另外表头列使用th,同时要使用dataType属性名来标示数据的类型,类型可以为text(默认),int和float;
2、显示table数据的tr父元素为tbody,显示数据的列用td,可以使用_order属性指定该字段的真实值。
table 示例如下:
<table>
<thead>
<tr>
<th datatype="int">ID</th>
<th datatype="text">Username</th>
<th datatype="float" class="current">Revenue</th>
</tr>
</thead>
<tbody>
<tr>
<td>1032</td>
<td>Zhang</td>
<td _order="127579">$ 127,579.00</td>
</tr>
<tr>
<td>1074</td>
<td>gm1</td>
<td _order="37331">$ 37,331.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2">Summary</th>
<th>$ 164,910.00
</tr>
</tfoot>
</table>
要禁止某个或一类资源,只需要增加一个location,然后在其中使用deny all即可。
禁止访问扩展名为bat的文件,配置如下:
location ~* /\.bat {
deny all;
}
禁止访问configs目录,以及其下所有子目录或文件,配置如下:
location ^~ /configs/ {
deny all;
}
注意上述configs后面的斜杠不能少,否则所有以configs开头的目录或文件都将禁止访问。
location指令是server段中的一个指令,可以对不同路径或不同文件类型进行特殊处理。例如用的比较多的就是针对网站的静态内容设置缓存。由于一个server段中可以有多个location,而http请求最终只能使用其中的一个,所以有必要弄清nginx是如何选择location的。
location 指令语法如下:
location [=|^~|~|!~|~*|!~*] uri {
}
上述配置中[]内为可选配置,但只能使用其中一个。关于具体含义,可以参考:nginx 匹配操作符。uri可以是普通字符串或正则表达式。
匹配的顺序是先匹配普通字符串,然后再匹配正则表达式。另外普通字符串匹配顺序是根据配置中字符长度从长到短,也就是说使用普通字符串配置的location顺序是无关紧要的,反正最后nginx会根据配置的长短来进行匹配,但是需要注意的是正则表达式按照配置文件里的顺序测试。找到第一个比配的正则表达式将停止搜索。
一般情况下,匹配成功了普通字符串location后还会进行正则表达式location匹配。有两种方法改变这种行为,其一就是使用“=”前缀,这时执行的是严格匹配,并且匹配成功后立即停止其他匹配,同时处理这个请求;另外一种就是使用“^~”前缀,如果把这个前缀用于一个常规字符串那么告诉nginx 如果路径匹配那么不测试正则表达式。
总结下来location指令的匹配顺序为:
1、“=”前缀指令匹配,如果匹配成功,停止其他匹配
2、普通字符串指令匹配,顺序是从长到短,匹配成功的location如果使用“^~”前缀,则停止其他匹配。
3、正则表达式指令匹配,按配置文件里的顺序,成功就停止其他匹配。
4、如果第3步中有匹配成功,则使用该结果,否则使用第二步中的匹配结果。
这里说的异步执行是让php脚本在后台挂起一个执行具体操作的脚本,主脚本退出后,挂起的脚本还能继续执行。比如执行某些耗时操作或可以并行执行的操作,可以采用php异步执行的方式。主脚本和子脚本的通讯可以采用外部文件或memcached的方式。原理就是通过exec或system来执行一个外部命令。注意:本文所述的是针对Linux环境。
在Linux下要让一个脚本挂在后台执行可以在命令的结尾加上一个 “&” 符号,有时候这还不够,需要借助nohup命令,关于nohup,可以参考http://www.netingcn.com/linux-nohup.html。
CLI环境和Web环境执行的操作还不太一样。先来说CLI环境,这里需要用上nohup和&,同时还要把指定输出,如果不想要输出结果,可以把输出定向到/dev/null中。现在来做一个测试,假设在一个目录中有main.php、sub1.php和sub2.php,其中sub1和sub2内容一样都让sleep函数暂停一段时间。代码如下:
//main.php
<?php
$cmd = 'nohup php ./sub.php >./tmp.log &';
exec($cmd);
$cmd = 'nohup php ./sub1.php >/dev/null &';
exec($cmd);
?>
//sub1.php sub2.php
<?php
sleep(100000);
?>
上述文件中main.php是作为主脚本,在命令行中执行php main.php,可以看到main.php脚本很快就执行完并退出。在使用ps aux | grep sub命令搜索进程,应该可以在后台看到上述的两个子脚本,说明成功挂起了子脚本。
在Web环境下,执行php脚本都是Web服务器开启的cgi进程来处理,只要脚本不退出,就会一直占有该cgi进程,当启动的所有cgi进程都被占用完后就不能在处理新的请求。所以对那些可能会很费时的脚本,可以采用异步的方式。启动子脚本的方式和CLI差不多,必须要使用&和指定输出(只好是定向到/dev/null),但是不能使用nohup。例如:
<?php
$cmd = 'php PATH_TO_SUB1/sub1.php >/dev/null &';
exec($cmd);
$cmd = 'php PATH_TO_SUB1/sub2.php >/dev/null &';
exec($cmd);
?>
当在浏览器中访问该脚本文件,可以看到浏览器里面响应完成,同时使用ps命令查看后台可以看到sub1和sub2脚本。
注意上述例子中如果php命令不在PATH中,需要指定命令完整的路径。推荐使用完整路径,特别是在Web下。
自mysql 5.1.3起开始支持分区功能。mysql表中存储的记录和表对应的索引信息,最后都是以文件的方式存储在计算机的硬盘上的,有了分区功能,就可以按照一定的分区规则把这些记录分布到不同的数据文件上,目前分区规则有四种,分别是RANGE、LIST、HASH和KEY,另外通过DATA DIRECTORY和INDEX DIRECTORY选项可以把不同的分区数据文件分散到不同的磁盘上,从而进步一提高系统的IO吞吐量。因此按照业务逻辑设计好了分区,可以大大提高查询效率,而且删除数据可能也会很容易。但是分区也有一些限制:1、主键或者唯一索引必须包含分区字段;2、只能通过int类型的字段或者返回int类型的表达式来分区;3、单表最多只能有1024个分区。
默认mysql是开启了分区功能的,可以通过下述查询查看结果:
show variables like '%partition%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| have_partitioning | YES |
+-------------------+-------+
//YES 表示开启
下面也range规则为例介绍一下分区常用的命令。
1、创建分区。可以在创建表的同时创建,也可以在表创建后追加分区。
drop table if exists `netingcn_com`;
create table `netingcn_com` (
`id` int(11) unsigned not null auto_increment,
`day` int(11) not null default 0,
primary key (`id`, `day`)
) engine=innodb default charset=utf8 auto_increment=1;
alter table `netingcn_com` partition by range(`day`) (
partition p_2012 values less than (20130000),
partition p_2013 values less than (20140000)
);
或
drop table if exists `netingcn_com`;
create table `netingcn_com` (
`id` int(11) unsigned not null auto_increment,
`day` int(11) not null default 0,
primary key (`id`, `day`)
) engine=innodb default charset=utf8 auto_increment=1
partition by range(`day`) (
partition p_2012 values less than (20130000),
partition p_2013 values less than (20140000)
);
可以explain命令查看分区是否创建成功
explain partitions select * from netingcn_com where day = 20130412;
+----+-------------+--------------+------------+-------+
| id | select_type | table | partitions | type |
+----+-------------+--------------+------------+-------+
| 1 | SIMPLE | netingcn_com | p_2013 | index |
+----+-------------+--------------+------------+-------+
2、增加或删除分区。注意:删除分区的同时,该分区的所有数据也会别删除。
增加分区
alter table netingcn_com add partition (
partition p_2014 values less than (20150000)
);
删除分区
alter table netingcn_com drop partition p_2012;
3、重新分区。注意:hash和key分区规则不能用REORGANIZE来重新分区
alter table netingcn_com reorganize partition p_2013,p_2014 into (partition p_2014 values less than (20150000));
更多关于mysql 分区功能可以参考:http://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html
php中使用内置的reset函数可以获取array的第一个元素的值。例如:
$arr = array('one', 'two', 'three');
echo reset($arr); // 输出的结果为 one
对于下述代码,如果php开启了“Strict Standards”,将会看到“Strict Standards: Only variables should be passed by reference in”的提示。
$str = 'netingcn.com';
echo reset(explode('.', $str));
为什么会这样呢?可以先看看reset函数的定义:
function reset (array &$array) {}
从定义中可以看到,reset接受的参数是一个array的引用。而上述代码中explode返回值不是任何array的引用,所以在“Strict Standards”下会有上述提示。解决办法很简单,只需要把reset(explode(‘.’, $str))分两步写即可。第一步先把explode的返回值赋给一个变量,第二步把这个变量作为reset参数。
出现上面的提示的不只是reset函数,只要参数接受的是对象引用,而传值直接使用function返回值都会看到那样的提示。例如内置的array_pop、shuffle、curent、next、prev、next等等。