2012年10月31日星期三

PHP 5 中图片验证码的制作

一、应用场景

    在 WEB 网站中,图片验证码经常被用来防止恶意地用户注册、发帖等场景。在 PHP 中,图片验证码主要是通过 GD 库提供的 API 来完成的。

二、实现的方法

    验证码一般都是随机的数字和字母组合的,可以通过随机函数,十六进制函数 dechex 简单实现。最关键的问题还是怎样生成图片。

<?php
//生成随机数-》创建图片-》随机数写进图片 -》输出到浏览器

for($i=0;$i<4;$i++{
  $rand .= dechex(rand(1,15));
}
  
$im imagecreatetruecolor(100,30);// 新建一个真彩色图像  x就是宽 ,y就是高

//设置颜色

// 为一幅图像分配颜色(相当于 PhotoShop 的调色板)

// imagecolorallocate ( resource image, int red, int green, int blue )  返回一个标识符,代表了由给定的 RGB 成分组成的颜色。

$bg imagecolorallocate($im,0,0,0);//第一次对 imagecolorallocate() 的调用会给基于调色板的图像填充背景色。代表了由给定的 RGB 成分组成的颜色
  
$te imagecolorallocate($im,225,225,225);


//把字符串写在图像左上角

//绘图函数  imagestring ( resource image, font, int x, int y, string s, int col ) 

//用 col 颜色将字符串 s 画到 image 所代表的图像的 x,y 坐标处(这是字符串左上角坐标,整幅图像的左上角为 0,0)。如果 font 是 1,2,3,4 或 5,则使用内置字体。  

imagestring($im,5,rand(3,70),rand(0,16),$rand,$te);

//直接输出图像到浏览器
header("Content-type: image/jpeg");

// imagejpeg ( resource image [, string filename [, int quality]] )  filename 参数为可选,如果省略,则原始图像流将被直接输出。要省略 filename 参数而提供 quality 参数,使用空字符串('')。通过 header() 发送 Content-type: image/jpeg 可以使 PHP 脚本直接输出 JPEG 图像。

imagejpeg($im);
?>

三、制作复杂的图片验证码

     有时验证码为了防止被一些图片识别工具识别,必须设置一些干扰。例如在图片上随机加上一些线条或者点。这主要通过 imageline() 和 imagesetpixel() 函数来实现。甚至制作中文验证码。

<?php

for($i=0;$i<4;$i++{
  $rand .= dechex(rand(1,15));
}
  
$im imagecreatetruecolor(100,30);

$bg imagecolorallocate($im,0,0,0);
  
$te imagecolorallocate($im,225,225,225);

//画线条
for($i=0$i<3$i++){
  $te2 imagecolorallocate($im,rand(0,225),rand(0,225),rand(0,225));
//imageline ( resource image, int x1, int y1, int x2, int y2, int color )  用 color 颜色在图像 image 中从坐标 x1,y1 到 x2,y2(图像左上角为 0, 0)画一条线段。 
  imageline($im,rand(0,100),0,rand(0,100),rand(0,30),$te2);
}
//画点
for($i 0$i 100$i++){
  //imagesetpixel ( resource image, int x, int y, int color ) 在 image 图像中用 color 颜色在 x,y 坐标(图像左上角为 0,0)上画一个点。 
  imagesetpixel($im,rand()%100,rand()%30,$te2);
}
  
$str iconv("gbk","UTF-8","验证码");//把gbk编码转换成UTF-8,如果文件的编码是 UTF-8,则不需要这一步。因为我们的系统(Windows)自带的字体默认是用国际通用编码(UTF-8)模式来识别的,所以如果不做编码转换,可能无法正常显示。
imagettftext($im,12,rand(0,10),20,20,$te,'msyh.ttf',$str);//rand(3,10)倾斜度。msyh.ttf 是微软雅黑字体,可在 C:\Windows\Fonts (Windows XP、Windows 7)找到。然后拷贝到该文件的目录。Windows 下之所以能够显示中文,是因为系统安装了中文字体

header("Content-type: image/jpeg");

imagejpeg($im);
?>


2012年10月26日星期五

PHP中用 htmlspecialchars() 对特殊字符进行编码的弊端

    当对表单传递过来的参数用 htmlspecialchars 对特殊字符(& ,' ," ,< ,> )进行编码时(由于插入数据库安全过滤的需要),会出现如下问题。
   
    如果用户上传了一个文件是带有特殊字符的,如 ' ,文件名保存到数据库就会发生以下问题。

    如果你服务器端的 PHP 代码是通过 $_GET['id'] 间接来获取它的文件名,然后以名称传输到客户端。

<?php    
$name mysql_query('SELECT name FROM accessories');//通过 ID 获取文件名
//......获取文件......
$file_path ROOT_PATH '/uploads/accessories/'$name;
header 'Content-Disposition: attachment; filename=' urlencode $name );
header 'Content-type: application/octet-stream;' );
header 'Content-Length: ' filesize $file_path );
readfile $file_path );
exit ();
?>

   那么下载的时候就会出现如下文件名错误。



2012年10月23日星期二

JavaScript 匿名函数的作用

    在 WEB 开发中有时候有这样的需求:用 JavaScript 技术,我们要在一个函数 fun 中传递一个类型为函数的参数 b ,并且函数 b 又要带参数,该怎么办呢?且看下面的例子。

<script>
function func(a,b{
 alert(a);//你的业务逻辑
 b();//运行函数 b
}
var 5;
func(1,function(c{
  c=c+5
  alert(c);
});
</script>


   运行上面的例子可以知道,第二个 alert 打印出来的是 NaN 。及无法通过上面的方法传参。这时匿名函数就派上用场了。

<script>
function func(a,b{
 alert(a);//你的业务逻辑
 b();//运行函数 b
}
var 5;
func(1,(function(c{
  return function({//返回一个匿名函数作为参数
      c=c+5
      alert(c);
  }
})(c));
</script>

   这时就会2个弹窗提示,第一个是1,第二个是10。也许你会感到奇怪,为什么要在匿名函数再次返回一个函数。

<script>
function func(a,b{
 alert(a);//你的业务逻辑
 b();//运行函数 b
}
var 5;
func(1,(function(c{
  c=c+5
  alert(c);
})(c));
</script>


    可以看到会有2个弹窗提示,但第一个是 10,第二个是 1 。并且用 google chrome 的开发人员工具的控制台可以看到有如下错误:


开发人员工具的控制台



(function(c{
  c=c+5
  alert(c);
})(c)

   在 func 函数中,在第一个括号内,是一个匿名函数;第二个括号,表示立即执行。

关于匿名函数可以参考这里

2012年10月12日星期五

MySQL 5.5 复制配置

这里以 Windows 7 平台下 wamp  2.1 为例说明怎样配置 MySQL 的主从复制。

第一步:编辑主服务器 MySQL 的 my.ini 文件。


# Replication Master Server (default)
# binary logging is required for replication

log-bin=mysql-bin
# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted

server-id  = 1​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​


注意,上面的编辑应该是在 [wampmysqld] 节点下面进行编辑,如下图,然后按照下面的方式重启MySQL。


[wampmysqld] 节点
[wampmysqld] 节点



shell> mysqladmin -u root -p shutdown   #关闭MySQL
shell> mysqld --remove wampmysqld   #移除
wampmysqld 服务


shell> mysqld --install wampmysqld --binlog-do-db=test  #添加 wampmysqld 服务,并只对数据库 test 进行日志的操作。然后需手动在 控制面板\系统和安全\管理工具\服务 中启动 mysql

服务


第二步:编辑服务器 MySQL 的 my.ini 文件。


# required unique id between 2 and 2^32 - 1
# (and different from the master)
# defaults to 2 if master-host is set
# but will not function as a slave if omitted

server-id       = 2​​​​​​​​​​​​​​​​​​​​

同样的,上面的编辑也是在 [wampmysqld] 节点下面进行编辑,如下图,然后按照下面的方式安装 MySQL 服务。


shell> mysqladmin -u root -p shutdown   #关闭MySQL
shell> mysqld --remove wampmysqld   #移除
wampmysqld 服务
shell> mysqld --install wampmysqld   #安装为服务

第三步:专门为从服务器创建一个用户(可选)

打开主服务器MySQL客户端,输入以下命令:



mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'slavepass';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

第四步:获取主服务器二进制日志的坐标

1.打开主服务器MySQL客户端,执行下面的SQL语句来防止MySQL的写操作

mysql> FLUSH TABLES WITH READ LOCK;

2.获取主服务器的二进制文件名和位置

mysql > SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 73       | test         | manual,mysql     |
+------------------+----------+--------------+------------------+

    在主服务器,我们能够通过 --binlog-do-db and --binlog-ignore-db 选项来控制哪些数据库被记录入二进制日志。详情见:Binary Log Options and Variables

第五步:使用 mysqldump 创建数据快照

1.打开主服务器 MySQL 客户端

mysql> FLUSH TABLES WITH READ LOCK;

2.打开一个新的 DOS 窗口,用 mysqldump 创建转储,可以是你要复制的所有数据库,也可以是单个数据库

shell> mysqldump --all-databases --lock-all-tables >dbdump.db

   还有一种方法是用裸转储,用 --master-data 选项,在从服务器启动复制进程的时候会自动添加 CHANGE MASTER TO 语句。

shell> mysqldump --all-databases --master-data >dbdump.db

3.在第1步的 MySQL 客户端输入以下命令来解锁

mysql> UNLOCK TABLES;


第六步:使用复制原始文件创建数据快照

   如果你的数据库很大,复制数据库的原始文件会比用 mysqldump 的效率高。
   
   如果你主从服务器的系统变量 ft_stopword_file, ft_min_word_len 或者 ft_max_word_len 有差异,在复制那些有全文索引的表也会出现问题。



第七步:在已经有数据的从服务器上启动复制


a. 用 --skip-slave-start 选项启动从服务器的MySQL,确保复制还没开始

shell> mysqld --skip-slave-start    #然后需手动在 控制面板\系统和安全\管理工具\服务 中启动 mysql


b. 导入转储文件

shell> mysql < fulldb.dump

6.设定从服务器复制相关配置

mysql> CHANGE MASTER TO
    ->     MASTER_HOST='master_host_name',
    ->     MASTER_USER='replication_user_name',
    ->     MASTER_PASSWORD='replication_password',
    ->     MASTER_LOG_FILE='recorded_log_file_name',
    ->     MASTER_LOG_POS=recorded_log_position;


7.启动从服务器的线程

mysql> START SLAVE;