1. php中删除数组的特定元素
unset() 或者 array_splice(). unset()删除后不会重排索引。array_splice()只能删除数字索引的。
2.empty() & isset()
要说它们的联系,其共同点就是empty()和isset()都是变量处理函数,作用是判断变量是否已经配置,正是由于它们在处理变量过程中有很大的相似性,才导致对它们的关系认识不足。单从empty()和isset()这两个函数本身来考虑的话会把人弄得更糊涂,换一个角度来它。empty()和isset()的处理对象无外乎未定义变量,0,空字符串。
如果变量为0,则empty()会返回TRUE,isset()会返回TRUE;
如果变量为空字符串,则empty()会返回TRUE,isset()会返回TRUE;
如果变量未定义,则empty()会返回TRUE,isset()会返回FLASE;
手册中对empty()的解释如下:
描述bool empty( mixed var )
如果 var 是非空或非零的值,则 empty()
手册中对isset()的解释如下:
isset()检测变量是否设置
描述bool isset
如果 var 存在则返回
如果已经使用 unset()
当要 判断一个变量是否已经声明的时候 可以使用 isset 函数
当要 判断一个变量是否已经赋予数据且不为空 可以用 empty 函数
当要 判断 一个变量 存在且不为空 先isset 函数 再用 empty 函数
Note:
empty() only checks variables as anythingelse will result in a parse error. In other words, the following will not work:empty(trim($name)).
创建多级目录
其实使用mkdir是可以创建多级目录的,不过必须在PHP5下才可以使用该函数创建多级目录。因为PHP5对创建目录函数 mkdir 增加了一个新的参数 recursive ,通过设置 recursive 为 true 可以实现递归创建目录的目的,但是这个在PHP4环境下是行不通的。
mkdir($path,0777,true); //-----------
第一个参数:必须,代表要创建的多级目录的路径;
第二个参数:设定目录的权限,默认是 0777,意味着最大可能的访问权;
第三个参数:true表示允许创建多级目录。
举例代码(支持创建中文目录):
<?php
header("Content-type:text/html;charset=utf-8");
//要创建的多级目录
$path="dai/php/php学习";
//判断目录存在否,存在给出提示,不存在则创建目录
if (is_dir($path)){
echo "对不起!目录 " . $path . " 已经存在!";
}else{
//第三个参数是“true”表示能创建多级目录,iconv防止中文目录乱码
$res=mkdir(iconv("UTF-8", "GBK", $path),0777,true);
if ($res){
echo "目录 $path 创建成功";
}else{
echo "目录 $path 创建失败";
}
}
?>
//问题是,这个方法在俺的环境下怎么尝试都不成功。。或者递归生成:
function mkdirs($dir)
{
if(!is_dir($dir))
{
if(!mkdirs(dirname($dir))){
return false;
}
if(!mkdir($dir,0777)){
return false;
}
}
return true;
}
同样的思路,php用rmdir和unlink递归删除多级目录的代码:
- function rmdirs($dir)
- {
- $d = dir($dir);
- while (false !== ($child = $d->read())){
- if($child != '.' && $child != '..'){
- if(is_dir($dir.'/'.$child))
- rmdirs($dir.'/'.$child);
- else unlink($dir.'/'.$child);
- }
- }
- $d->close();
- rmdir($dir);
- }
php向mysql写入时间时的考虑。
数据库中关于时间的字段可以存成int或者datetime类型。
使用int型的话存的就是unix时间戳形式。对于datetime,MySQL 以 'YYYY-MM-DD HH:MM:SS' 格式检索与显示 DATETIME 类型。php中插入数据则是"Y-m-d H:i:s"形式的字符串:
$data['input_time'] = date("Y-m-d H:i:s");
M('table_name')->add($data);
php提供了好多函数可以方便的在时间戳和字符串之间转化。
如果存的是datetime形式,读取之后,可以使用strtotime函数将字符串转换为unix时间戳,然后再使用getdate() date()等函数转换为任意需要的形式。
$time2 = date('Y年m月d日 H时i分s秒',$time);
如果直接存储的是整数的时间戳形式,那么可以省掉strtotime的转换。
但是使用datetime有着很多的好处,比如时区的处理上。
而且datetime类型是也是直接可以比较的,例如:
select * from `table` where `input_time` >= 1999-9-9 8:8:8.
php数组操作
array_combine() 函数通过合并两个数组来创建一个新数组,其中的一个数组是键名,另一个数组的值为键值。
如果其中一个数组为空,或者两个数组的元素个数不同,则该函数返回 false。
语法
array_combine(array1,array2)
参数 描述
array1 必需。规定键名。
array2 必需。规定值。
提示和注释
注释:两个参数必须有相同数目的元素。
例子
<?php
$a1=array("a","b","c","d");
$a2=array("Cat","Dog","Horse","Cow");
print_r(array_combine($a1,$a2));
?>
输出:
Array ( [a] => Cat [b] => Dog [c] => Horse [d] => Cow )
------------------------------------------------------------------------------------------------------------------
如果要自动生成学号,自动生成某某编号,就像这样的形式“d0000009”、“d0000027”时,那么就会面临一个问题,怎么把左边用0补齐成这样8位数的编码呢?我想到了两种方法实现这个功能。
方法一:
先构造一个数字10000000,千万,也就是一个1,7个0,然后加上当前的编号(比如是3),那么就得到 10000003,用字符串截取 substr('10000003',1,7)后就得到0000003,最后在与“d”拼接,就得到了最终的编号d0000003。
源码如下:
<?php
$num = 3;
$temp_num = 10000000;
$new_num = $num + $temp_num;
$real_num = "d".substr($new_num,1,7); //即截取掉最前面的“1”
echo $real_num;
?>
----------------------------------------------------------------------------------------------------------
php中的虚函数功能
学过C++的人都应该知道C++中有个虚函数的概念。而在php5中如何实现这个虚函数呢?
请看下面的代码:
<?php
class A {
public function x() {
echo "A::x() was called.\n";
}
public function y() {
self::x();
echo "A::y() was called.\n";
}
public function z() {
$this->x();
echo "A::z() was called.\n";
}
}
class B extends A {
public function x() {
echo "B::x() was called.\n";
}
}
$b = new B();
$b->y();
echo "--\n";
$b->z();
?>
该例中,A::y()调用了A::x(),而B::x()覆盖了A::x(),那么当调用B::y()时,B::y()应该调用A::x()还是 B::x()呢?在C++中,如果A::x()未被定义为虚函数,那么B::y()(也就是A::y())将调用A::x(),而如果A::x()使用 virtual关键字定义成虚函数,那么B::y()将调用B::x()。然而,在PHP5中,虚函数的功能是由 self 和 $this 关键字实现的。如果父类中A::y()中使用 self::x() 的方式调用了 A::x(),那么在子类中不论A::x()是否被覆盖,A::y()调用的都是A::x();而如果父类中A::y()使用 $this->x() 的方式调用了 A::x(),那么如果在子类中A::x()被B::x()覆盖,A::y()将会调用B::x()。
上例的运行结果如下:
A::x() was called. A::y() was called. --
B::x() was called. A::z() was called.
需要注意的是,这里的覆盖的函数,不管是A中的还是B中的,都是public的。如果A中是protected的,而重写的时候还是protected的话,那么调用的还是A中的函数。如果改成public的,则会调用子类B中的函数。
-----------------------------------------------------------------------------------------------------------
容易犯的小错误:
echo 'result'; // 向着页面上echo不会结束当前线程,echo还会继续执行。
die(); //
foreach 循环的问题
foreach( $vals as $val )
{
$val = 'new_val';//不会起作用,$vals数组里还是原来的值。foreach 循环貌似是复制了数组中的值。
}
可以很容易地通过在 $value 之前加上 & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // 最后取消掉引用
?>
php中每次访问都是开启和结束一个新的线程。两次访问之间,私有成员变量啥的不会保存数据,每次访问都是重新初始化(感觉这让私有变量,不是私有函数,木有存在的意义了)。保存只能是session cookei 临时文件 或者 数据库。
类内部调用自己的函数也要放上 $this->.
-----------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------
php str_replace 单引号 双引号 区别
出处:http://www.cnblogs.com/zcy_soft/archive/2011/01/13/1934620.html
linux "\n"
php 中 str_replace()函数的具体概况
str_replace($search, $replace, $subject)
例如
1
str_replace("\n", "<br/>", '465s4d6f5s4ad1as65d4fa6s\n54df65sdafgsdf\n65g4sd65g4hdf6\n54ghd6fbghdfgh'); //注意引号
输出:465s4d6f5s4ad1as65d4fa6s\n54df65sdafgsdf\n65g4sd65g4hdf6\n54ghd6fbghdfgh
2
str_replace("\n", "<br/>", "465s4d6f5s4ad1as65d4fa6s\n54df65sdafgsdf\n65g4sd65g4hdf6\n54ghd6fbghdfgh"); //注意引号
输出:
465s4d6f5s4ad1as65d4fa6s
54df65sdafgsdf
65g4sd65g4hdf6
54ghd6fbghdfgh
3
str_replace('\n', '<br/>', "465s4d6f5s4ad1as65d4fa6s\n54df65sdafgsdf\n65g4sd65g4hdf6\n54ghd6fbghdfgh"); //注意引号
输出:
465s4d6f5s4ad1as65d4fa6s 54df65sdafgsdf 65g4sd65g4hdf6 54ghd6fbghdfgh
注意:单引号只是表示纯粹的字符串
而双引号是要经过编译器编译的
也就是说在'\n'与"\n"有区别,前者是指字符串\n,而后者是经过编译器的\n,是转移字符的意思
所以当只有$search和$subject变量同时为单引号或者双引号的时候才会有效果。
从文本框或取出来的值都是转移的,也就是说存在着转移后的\n,所以用'\n'是没有用的,一定要用"\n"
做过滤的时候,比如json字符串生成json对象之前的过滤,要注意。
-----------------------------------------------------------------------------------------------------------
tp:
1. 事务
事务是针对数据库本身的,所以可以跨模型操作的 。
例如:
- // 在User模型中启动事务。
- 可以在任何一个model中启动事务,启动事务的model和执行数据操作的model并没有关系。例如
- //$model = new Think/Model;
- //$model->startTrans();
- $User->startTrans();
- // 进行相关的业务逻辑操作
- $Info = M("Info"); // 实例化Info对象
- $Info->save($User); // 保存用户信息
- if (操作成功){
- // 提交事务
- $User->commit();
- }else{
- // 事务回滚
- $User->rollback();
- }
注意:系统提供的事务操作方法必须有数据库本身的支持,如果你的数据库或者数据表类型不支持事务,那么系统的事务操作是无效的。
2. log
tp带一个log系统,开启方式看手册:)
log文件的默认输出位置在runtime文件夹下面的logs下。
log的时候如果是ajax的操作,尽量使用Think\Log::write函数。Think\Log::record貌似有时候记录不到。
3. tp的关联模型. tp的关联模型是个很奇葩的东东。
from:http://www.thinkphp.cn/topic/7802.html
光看个最简单的HAS_ONE都难以看明白,而且搞了很久。
实际上,关联模型的关系并不复杂,也就是两个表,第一表和第二表,通过第一表的某个字段值等于第二表的某个字段值,建立结合关系,但说明文档过于简化,很不好理解。
在不简化的情况下就好理解关联了,特别是关联的字段并不是主键的时候,例如:
第一表news表,有字段id,title, 第二表detail有字段id,detail 这时,两个表都有主键id,有的时候,关联并不是使用主键作为关联字段的。例如:
第一表news有字段id,unique_id,title,
第二表detai有字段id,unique_id2,detail,remark
现在用第一表的unique_id和第二表的unique_id2进行关联,看看关联的写法:
- <?php
- class NewsModel extends RelationModel {
- protected $_link = array(
- 'detail' => array( //关联后,启用的数组名
- 'mapping_type' => HAS_ONE, //关联类型是一对一
- 'mapping_key' => 'unique_id', //第一表的关联字段 ----- mapping_key 在3.2.2的文档里都木有。
- 'class_name' => 'detail', //第二个表的表名称
- 'foreign_key' => 'unique_id2', //第二个表的关联字段
- ),
- );
- }
- ?>
然后用D函数实例化这个model,查询就行了。
$model = D('News');
$model->relation(true)->select();
问题是,这里的关联的实现不是连接查询,而是通过多次查询实现的(:))。看日志就会发现,先查询主表,然后是一堆的针对从表的查询。然后如果条件查询的话:
$model->where($map)->relation(true)->select();那么 $map 只能是针对主表来说的。各种和条件查询有关的,如limit啥的,都是针对主表来说的,cache函数也是。
所以,如果要实现真正的连接查询,还是乖乖的使用连接查询吧。比如:
$bookinfo = $Book->table('t_book a') ->field('a.id,a.cid,a.bookname,b.catename') ->join('t_book_cate b ON a.cid = b.id') ->where('a.id = ' . $bid) ->find();
或者使用视图模型。
网上的评论:
查询自己组合sql或用视图,至于增删改操作,还是用关联来得方便(注意,不是容易)。
关联模型是专用于 关联 的增删改操作的么。。
-----------------------------------------------------------------
数据过滤:
1、I方法
使用系统内置的I函数
是避免输入数据出现安全隐患的重要手段,I函数默认的过滤方法是htmlspecialchars
,如果我们需要采用其他的方法进行安全过滤,有两种方式:
(htmlspecialchars默认不过滤单引号,想过滤单引号得加参数,怎样在配置文件中添加参数呢?)
1)如果是全局的过滤方法,那么可以设置DEFAULT_FILTER,例如:
'DEFAULT_FILTER' => 'strip_tags',
当然,我们也可以设置多个过滤方法,例如:
'DEFAULT_FILTER' => 'strip_tags,stripslashes',
2)如果是仅需要对个别数据采用特殊的过滤方法,可以在调用I函数的时候传入过滤方法,例如:
I('post.id',0,'intval'); // 用intval过滤$_POST['id']
I('get.title','','strip_tags'); // 用strip_tags过滤$_GET['title']
2、filter方法
如果你没有使用I函数进行数据过滤的话,还可以在模型的写入操作之前调用filter方法对数据进行安全过滤,例如:
$this->data($data)->filter('strip_tags')->add();
3、create中的过滤。
create 方法从I('post.')获取数据。(http://www.thinkphp.cn/bug/2771.html 这里看到的,手册上没找到。。)
create还会调用model的自动验证,验证的时候当然也可以添加过滤。
- $_auto = array('content','htmlspecialchars',self::MODEL_BOTH,'function');
4、field函数对允许提交的字段的合法性进行检查。需要结合create方法使用:
-
M('User')->field('account,password,nickname,email')->create();
insertFields
和 updateFields
属性,使用create方法创建数据对象的时候,不在定义范围内的属性将直接丢弃,避免表单提交非法数据。
5、数据库查询的连贯操作中也会对单引号等进行过滤(生成的sql中可以看到添加了转义 \',具体实现不知道哎)。
--------------------------------------------------------------
不同的数据写入、更新方法的区别。
1、create
很简单的例子:
// 实例化User模型
$User = M('User');
// 根据表单提交的POST数据创建数据对象
$User->create();
Create方法支持从其它方式创建数据对象,例如,从其它的数据对象,或者数组等
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->create($data);(这里会过滤么?直接调用create,默认从post中获取数据的时候会过滤的,但是现在呢?)
create方法所做的工作远非这么简单,在创建数据对象的同时,完成了一系列的工作,我们来看下create方法的工作流程就能明白:
步骤 | 说明 | 返回 |
---|---|---|
1 | 获取数据源(默认是POST数组) | |
2 | 验证数据源合法性(非数组或者对象会过滤) | 失败则返回false |
3 | 检查字段映射 | |
4 | 判断数据状态(新增或者编辑,指定或者自动判断) | |
5 | 数据自动验证 | 失败则返回false |
6 | 表单令牌验证 | 失败则返回false |
7 | 表单数据赋值(过滤非法字段和字符串处理) | (过滤的规则是? 在哪里控制呢?) |
8 | 数据自动完成 | |
9 | 生成数据对象(保存在内存) |
因此,我们熟悉的令牌验证、自动验证和自动完成功能,其实都必须通过create方法才能生效。
2、data方法创建数据
如果只是想简单创建一个数据对象,并不需要完成一些额外的功能的话,可以使用data方法简单的创建数据对象。 使用如下:
// 实例化User模型
$User = M('User');
// 创建数据后写入到数据库
$data['name'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$User->data($data)->add();
Data方法也支持传入数组和对象,使用data方法创建的数据对象不会进行自动验证和过滤操作,请自行处理。但在进行add或者save操作的时候,数据表中不存在的字段以及非法的数据类型(例如对象、数组等非标量数据)是会自动过滤的,不用担心非数据表字段的写入导致SQL错误的问题。
3、save add
-
$User->add($data);
- $User->save($data);