php & TP tips



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()
 返回 FALSE。换句话说,""、0、"0"、NULLFALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 TRUE
手册中对isset()的解释如下:
isset()检测变量是否设置
描述bool isset
 ( mixed var [, mixed var [, ...]] )
如果 var 存在则返回 
TRUE,否则返回 FALSE
如果已经使用 unset()
 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。同时要注意的是一个NULL 字节("\0")并不等同于 PHP 的 NULL 常数
警告: isset() 只能用于变量,因为传递任何其它参数都将造成解析错误。若想检测常量是否已设置,可使用 defined()函数。
当要 判断一个变量是否已经声明的时候 可以使用 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递归删除多级目录的代码:  

  1. function rmdirs($dir)  
  2. {  
  3. $d = dir($dir);  
  4. while (false !== ($child = $d->read())){  
  5. if($child != '.' && $child != '..'){  
  6. if(is_dir($dir.'/'.$child))  
  7. rmdirs($dir.'/'.$child);  
  8. else unlink($dir.'/'.$child);  
  9. }  
  10. }  
  11. $d->close();  
  12. 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. 事务

事务是针对数据库本身的,所以可以跨模型操作的 。
例如:

  1. //  在User模型中启动事务。 
  2. 可以在任何一个model中启动事务,启动事务的model和执行数据操作的model并没有关系。例如
  3. //$model = new Think/Model;
  4. //$model->startTrans();
  5. $User->startTrans();
  6.  // 进行相关的业务逻辑操作
  7. $Info = M("Info"); // 实例化Info对象
  8. $Info->save($User); // 保存用户信息
  9.  if (操作成功){
  10.     // 提交事务
  11.     $User->commit(); 
  12.  }else{
  13.    // 事务回滚
  14.    $User->rollback(); 
  15.  }

注意:系统提供的事务操作方法必须有数据库本身的支持,如果你的数据库或者数据表类型不支持事务,那么系统的事务操作是无效的。


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进行关联,看看关联的写法:

  1.  <?php
  2.  class NewsModel extends RelationModel {
  3.           protected $_link = array(
  4.         'detail' => array(                     //关联后,启用的数组名
  5.           'mapping_type' => HAS_ONE,      //关联类型是一对一
  6.           'mapping_key' => 'unique_id',    //第一表的关联字段  ----- mapping_key 在3.2.2的文档里都木有。
  7.           'class_name' => 'detail',        //第二个表的表名称
  8.           'foreign_key' => 'unique_id2',   //第二个表的关联字段
  9.           ),             
  10.          );
  11.  }
  12.  ?>
复制代码
复制代码

然后用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,例如:

 
 
  1. 'DEFAULT_FILTER' => 'strip_tags',

当然,我们也可以设置多个过滤方法,例如:

 
 
  1. 'DEFAULT_FILTER' => 'strip_tags,stripslashes',

2)如果是仅需要对个别数据采用特殊的过滤方法,可以在调用I函数的时候传入过滤方法,例如:

 
 
  1. I('post.id',0,'intval'); // 用intval过滤$_POST['id']
  2. I('get.title','','strip_tags'); // 用strip_tags过滤$_GET['title']


2、filter方法

如果你没有使用I函数进行数据过滤的话,还可以在模型的写入操作之前调用filter方法对数据进行安全过滤,例如:

 
 
  1. $this->data($data)->filter('strip_tags')->add();

3、create中的过滤。

create 方法从I('post.')获取数据。(http://www.thinkphp.cn/bug/2771.html 这里看到的,手册上没找到。。)

create还会调用model的自动验证,验证的时候当然也可以添加过滤。

  1. $_auto = array('content','htmlspecialchars',self::MODEL_BOTH,'function');

4、field函数对允许提交的字段的合法性进行检查。需要结合create方法使用:

  1. M('User')->field('account,password,nickname,email')->create();

除了field方法,还可以分别为新增和编辑表单设置insertFields和 updateFields属性,使用create方法创建数据对象的时候,不在定义范围内的属性将直接丢弃,避免表单提交非法数据。


5、数据库查询的连贯操作中也会对单引号等进行过滤(生成的sql中可以看到添加了转义 \',具体实现不知道哎)。




--------------------------------------------------------------

不同的数据写入、更新方法的区别。

1、create

很简单的例子:

 
 
  1. // 实例化User模型
  2. $User = M('User');
  3. // 根据表单提交的POST数据创建数据对象
  4. $User->create();

Create方法支持从其它方式创建数据对象,例如,从其它的数据对象,或者数组等

 
 
  1. $data['name'] = 'ThinkPHP';
  2. $data['email'] = 'ThinkPHP@gmail.com';
  3. $User->create($data);(这里会过滤么?直接调用create,默认从post中获取数据的时候会过滤的,但是现在呢?)

create方法所做的工作远非这么简单,在创建数据对象的同时,完成了一系列的工作,我们来看下create方法的工作流程就能明白:

步骤 说明 返回
1 获取数据源(默认是POST数组)  
2 验证数据源合法性(非数组或者对象会过滤) 失败则返回false
3 检查字段映射  
4 判断数据状态(新增或者编辑,指定或者自动判断)  
5 数据自动验证 失败则返回false
6 表单令牌验证 失败则返回false
7 表单数据赋值(过滤非法字段和字符串处理)过滤的规则是?
在哪里控制呢?
8 数据自动完成  
9 生成数据对象(保存在内存)  

因此,我们熟悉的令牌验证、自动验证自动完成功能,其实都必须通过create方法才能生效。


2、data方法创建数据

如果只是想简单创建一个数据对象,并不需要完成一些额外的功能的话,可以使用data方法简单的创建数据对象。 使用如下:

 
 
  1. // 实例化User模型
  2. $User = M('User');
  3. // 创建数据后写入到数据库
  4. $data['name'] = 'ThinkPHP';
  5. $data['email'] = 'ThinkPHP@gmail.com';
  6. $User->data($data)->add();

Data方法也支持传入数组和对象,使用data方法创建的数据对象不会进行自动验证和过滤操作,请自行处理。但在进行add或者save操作的时候,数据表中不存在的字段以及非法的数据类型(例如对象、数组等非标量数据)是会自动过滤的,不用担心非数据表字段的写入导致SQL错误的问题。

3、save add 

  1. $User->add($data);
  2. $User->save($data);



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
修改这个函数,要实现防止连续点按 while (1) { tp_dev.scan(0); if (tp_dev.sta & TP_PRES_DOWN) { //触摸屏被按下 if (tp_dev.x[0] > 0 && tp_dev.x[0] < 130 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480) { while(tp_dev.x[0] > 0 && tp_dev.x[0] < 130 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480){ tp_dev.scan(0); } if (i < 5) { password[i++] = '1'; } } else if (tp_dev.x[0] > 130 && tp_dev.x[0] < 260 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480) { while(tp_dev.x[0] > 130 && tp_dev.x[0] < 260 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480){ tp_dev.scan(0); } if (i < 5) { password[i++] = '2'; } } else if (tp_dev.x[0] > 260 && tp_dev.x[0] < 390 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480) { while(tp_dev.x[0] > 260 && tp_dev.x[0] < 390 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480){ tp_dev.scan(0); } if (i < 5) { password[i++] ='3'; } } else if (tp_dev.x[0] > 390 && tp_dev.x[0] < 520 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480) { while(tp_dev.x[0] > 390 && tp_dev.x[0] < 520 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480){ tp_dev.scan(0); } if (i < 5) { password[i++] = '4'; } } else if (tp_dev.x[0] > 520 && tp_dev.x[0] < 650 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480) { while(tp_dev.x[0] > 520 && tp_dev.x[0] < 650 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480){ tp_dev.scan(0); } if (i > 0) { password[--i] = '\0'; } } else if (tp_dev.x[0] > 650 && tp_dev.x[0] < 800 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480) { while(tp_dev.x[0] > 650 && tp_dev.x[0] < 800 && tp_dev.y[0] > 380 && tp_dev.y[0] < 480){ tp_dev.scan(0); } if (i == 4) { break; //退出密码输入循环 } else { Show_Hz16(300,250,"提示信息:用户名或密码错误",RED,WHITE); } } //显示部分 LCD_ShowString(400,150,400,24,24,password); } }
最新发布
05-22

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值