3.2 图形化访问计数器
恐怕很多读者有在画面上放置访问计数器的经验吧。追溯到网络技术的CGI时代,页面计数器可是典型的应用之一了。
本节利用上一节“记录每页的浏览数”中使用的access_counter表里的记录,开发出了页面使用的图形化访问计数器,如下图所示。
本例要点
access_counter表里管理的都是些数字,本节的关键是将这些数字转换成图片(<img>)后,再在画面显示出来。
当然可以将每一个统计数据都做成图片,但是统计数据在不断增加,这几乎是不可能的工作。本节准备了0到9的10个图片,对画面上统计数据,一数字对应一个数字图片的形式来进行显示。
请大家注意下面的程序中,在从access_counter表里取得访问统计数据后,对数据进行的单字节数字分解的逻辑。
目录结构
数据库的表结构
代码
将计数统计用的脚本CounterUp.php,显示计数的脚本包含过来。
showCounter函数唯一接受的参数为数字图片的文件名的固定部分,提供pic0.gif到pic9.gif的图片时,为pic。不传入参数的情况下,默认为pic。
连接数据库,与3.1节中的内容相同。
当前的URL为条件对表access_counter进行检索。
fetch函数返回False时,计数刚开始,因此统计变量$num赋值为1。
strlen函数求出统计数据的字节数,并作为循环的上限。16行到19行循环进行统计数据的字节分解。
例如统计数字为5432时,从最初的循环到结束的结果如下。
返回值保存在变量$val,最后将变量转换为对应的图片,显示在画面上。
补充
prepare方法的有效性
3.1节、3.2节中介绍了应用prepare方法进行“SQL命令准备”的概念。进行SQL命令准备有以下两重意义:
(1)性能提高
通常在程序内部,执行普通的SQL语句时,要经过“解析→编译→执行”等阶段。使用prepare方法后,事先对SQL命令进行“解析→编译”的处理,将状态保存起来,执行时,直接进行最后一步“执行”就可以了。
这样,要改变条件多次执行SQL命令时,前面的“解析→编译”两个步骤就可以省略了,能提高程序处理的性能。
(2)避免SQL注入脆弱性
SQL注入(injection)脆弱性是指通常在应用数据库的系统中,执行SQL命令时,由于疏忽对用户输入的条件数据进行相关检查,而出现的安全漏洞。
例如,需要根据输入的条件对表user进行检索,服务器端的程序中有如下的动态SQL命令:
其中变量$id由终端用户输入,如果检查存在漏洞,而用户输入的不是普通字符,而是如“hell’;UPDATE user WHERE set name =‘AAAA’”样的字符串,会出现什么样的后果呢,我们看看下面的SQL命令。
这样,用户就可以对数据进行严重地破坏了,这是非常严重的安全漏洞。
但是,如果使用了prepare方法(严格地说是执行SQL的excute方法)。在设置预留置换位(place holder)时,已经自动进行引号转换了,即将所有单引号转换为双引号。这样一来,用户输入的内容只能作为一个字符看待,再也不出现SQL注入脆弱性的问题了。
可以使用quote函数实现单双引号转换,但是如果自己事先进行转换时,不小心总会出现疏漏,怎么说也挺麻烦。因此在没有什么特殊理由的情况下,动态地生成SQL命令时请务必使用prepare函数。
无名参数与有名参数
在prepare方法中使用预留置换位时,可以使用无名参数与有名参数两种形式,分别如下。
无名参数:
有名参数:
无名参数以[?],有名参数以[:参数名]嵌入在SQL中,这两种形式都用bindValue进行实际数值的设定,不同的是,有名参数时第一参数直接使用名称,无名参数时使用序号(从1开始),形式如下:
无名参数与有名参数都可以使用,基本上没什么区别。两者分别有如表3-3所示的优点与缺点。
表3-3 无名参数与有名参数的优缺点
本书优先重视程序的可读性(即参数的易理解性),除了一部分例外,都使用有名参数的方式。
参数的默认值
本节做成的showCounter函数中使用了带默认值的参数的形式,如下:
带默认值的参数可以省略,但是在使用带默认值的参数时,该参数必须放在其他参数之后,如果像下面所示的方式定义函数时,如果省略时,将会得意想不到的结果。
只有采用如下的方式的定义,才能省略带默认值的参数:
是否可以用字符串分解函数split。
在Perl等程序中可以使用split函数将字符串分解为一个一个字节,那么在PHP是否也可以使用split进行类似的操作呢?下面是验证代码。
结论是,分解失败。Perl的情况下以空字符为间隔可以分割出字节为单位的字符,而在PHP中split函数则返回错误。