一、高级应用

1、计数器

计数器的原理很简单,只有两步:

第一步就是读写一个数字,第二步就是显示出来。一般CGI'大多直接写到文件系统,当然也可以利用MySQL来存储这个数字,完成第一步的操作。

第二步,除了直接写出数字之外,也可以用PHP的GD函数来试试。

(注:计数器一般都是以CGI程序做的,一般不会有人为了记这么一个数字建一个数据库,不过它很具有示范作用)

  1. //方法1:读写文件系统Filesystem
  2. <?
  3. $arr = file("counter.txt");
  4. $count = (int)$arr[];
  5. $fp = fopen("counter.txt","w");
  6. fputs($fp,++$count);
  7. fclose($fp);
  8. ?>

这个程序要能够运行前:(勿忘修改两点)

第一要先建立一个counter.txt,里面含有一个数字0;

第二它忽略了应该对counter.txt做LOCK的操作。

  1. //显示 这个数字
  2. <? echo "您是第$count位访客"; ?>

高级显示:用PHP生成一个图形

  1. //PHP 生成图形(5位数的计数器:00100)
  2. <?
  3. Header("Content-type:image/gif");
  4. //...略去读入、更改count的部分
  5. $im = ImageCreate(45,16);
  6. $white = IMageColorAllocate($im,255,255,255);
  7. $black = ImageColorAllocate($im,0,0,0);
  8. imagefill($im,1,1,$black);
  9. imagestring($im,5,0,0,sprintf("%05d",$count),$white);
  10. imagegif($im);
  11. imagedestroy($im);
  12. ?>

除了写到文件系统之外,还可以把到访次数,写到数据库的Table里,建立如下的数据库:

  1. //方法二:写到数据库Database
  2. mysql>creat table counter(
  3. id int unsigned,
  4. count int unsigned
  5. );

用Id作为不同网站/页面的区分,而Count用于记录到访次数。那么一个Select命令:

  1. select count from counter where id=3

就可以读出我们的Count值

  1. update counter set count = count+1 where id=3

也能轻易地Update数值(注意:不是count = $count +1)

这个方法如果没有做LOCK,影响层面不大,最多显示的数字差几个,而count+1的操作不会Lost掉

使用数据库的好处是:对于每一个PHTML文件,都可以一个简单的Include操作,让这个Page的到访次数被统计(不一定显示)。

2、流量统计

流量统计是计数器的高级应用:世界上有许多软件可以帮助做流量统计的工作,大多使用HTTPD的Log文件(access.log)直接作分析,可以做到相当详尽而漂亮、清楚的图形显示,甚至会在适当的时候提醒一些信息。

这里介绍的是另外一种较简单的作法。对于“流量”,一般较感兴趣的,是使用者从什么地方联机进来?进来的时间?使用什么浏览器等信息。这些在PHP里,就是PHP的环境参数。如果在记录到访次数时,同时将这些参数记录下来,就可以用来统计。至于统计的结果,当然也可以用简单的图形来表示。

  1. //第一步:建立Flow Table
  2. mysql>create table flow(
  3. id int unsigned,
  4. accdate DATE,
  5. acctime TIME,
  6. browser varCHAR(30),
  7. usrhost varCHAR(30)
  8. );
  1. //第二步:PHP记录日期、时间、浏览器信息以及使用者的Host Name等,Id一样是用来区隔不同的网站/网页的流量数据
  2. <?
  3. $str = "insert into flow values(3,CURRENT_DATE(),CURRENT_TIME(),'$HTTP_USER_AGENT,'$REMOTE_HOST')"
  4. mysql_query($str,$link);
  5. ?>

第三步:读出数据,做一些简单的统计工作。比方说,想知道有多少人是从Hinet过来

  1. select count(*) from flow where usrhost like '%hinet.net'

输出接口可以考虑用百分比长条图,直接一个ImageFilledRectangle(),就可以把算出来的一部分数据画成长条图了。、

3、留言板

利用数据库做留言板,最简单了。考虑一下需要的字段:姓名、张贴时间、Email、标题、内容、签名文件等。

第一步:建立一个数据库MSGboard(以及相关的Privileges),含有这么一个Table

  1. mysql>create table board(
  2. serial INT unsigned not null auto_inctement,
  3. id INT unsigned not null,
  4. postname CHAR(10),
  5. postemail varCHAR(30),
  6. posttime DATETIME,
  7. subject var CHAR(40),
  8. content tinyBLOB,
  9. remarks varCHAR(255),
  10. primary key(serial),
  11. index(id)
  12. );

特别的:我们使用一个Serial代表序号,Id来分别不同的留言板,另外加入了Index的概念,这样子在读取数据时会比较有效率。

第二步:写一个HTML接口让读者可以输入留言

  1. <form antion="board.phtml" method="POST">
  2. 您的大名:<input type="Text" name="postname"><br>
  3. 您的信箱:<input type="Text" name="postemail"><br>
  4. 留言标题:<input type="Text" name="subject"><br>
  5. 留言内容:<textarea name="content" cols="20" rpws="4"
  6. wrap="VIRTUAL"></textarea><br>
  7. 签名文字:<textarea name="remarks" cols="20" rows="2"
  8. wrap=“VIRTUAL”></textarea><br>
  9. <input type="Submit" name="" value="传送">
  10. <input type="reset" vlue="重写">
  11. </form>

第三步:在borad.phtml中,只要一行Insert命令,把数据写进去即可。至于读取留言,直接一次Select出来,然后显示出来就可以了。当然必要的美化画面是免不了的。

  1. <?//php读取留言
  2. $str = "select postname,postemail,
  3. dateformat('y-m-d H:i',posttime),"
  4. subject,content,remarks
  5. form board
  6. where id=3";
  7. $result = mysql_query(...);
  8. while(list($pname,$$pemail,$ptime,$subj,$content,$remk)=
  9. mysql_fetch_row($result);
  10. ?>
  11. 姓名:<a href="mailto:"<?echo $pemail;?>"<?echo $pname;?></a><br>
  12. 留言时间:<?echo $ptime;?><br>
  13. 标题:<?echo $subj;?><br>
  14. 内容:<?echo $cotent;?><br>
  15. 签名:<?echo $remk;?><br><p>
  16. <?
  17. endwhile
  18. ?>

几个可议的地方:

  • 在“留言内容”里贴上HTML代码,会怎样?直觉的看法,应该在输出的时候,原来的HTML会发生作用,例如<fontsize="+3">...</font>会真的把字放大3级;然而,由于HTML里含有双引号(“”),会造成PHP对字符串的混淆。所以结果反而可能出现Error信息。解决这个问题的方法,在输入到数据库之前,先把所有的双引号等特殊字符Escape掉(在前面加上反斜线字符\),具体参考字符串函数addslashes()与quotemeta()。
  • 至于要不要开发使用者输入HTML代码,也是依个人喜好而定,原则上来说应该开放,不过万一读者的HTML代码不小心写错了,那么辛苦做好的格式可能会走样
  • 在Textarea里面,用户也许很自然的用ENTER换行,用TAB或数个空格来达到他要的效果。记录到数据库里,不过对应到(\n),(\t)与Space字符。于是在输出的时候,HTML代码真的会有换行、TAB与空格,但是用Browser看到却完全连在一起。所以,应该事先把这些字符换掉。例如:nl2br(),很轻松的处理完换行的问题。

4、公告栏(新闻发布)

把留言板稍微变化一下,可以做到另一种效果:公告栏,也有人叫它新闻系统。一进去会看到很多新闻标题(一两句话),点进去看全文。

延续上面留言板的结构,只要在Select上下功夫就可以了。

第一步:Show标题的页面

  1. <?php
  2. $str = "select serial,subject from board where id=3 order by posttime desc limit 10";
  3. ...
  4. echo "<a href=\"show.phtml?$serial\">$subj</a>;
  5.  
  6. ?>

这样会显示出标题,点一下会Link到show.phtml:

  1. <?
  2. $str = "select .. from board where id=3 and seria = $serial";
  3. ...
  4. ?>

第二步:做一个类似留言板的Web接口,也许用一下密码保护,让客户自己去找开他们的新闻,直接插入到数据库,这样下一个浏览器的Request,显示的新闻标题立刻更新了。(这样管理许多网站的WebMaster一定会很高兴!不用再因为客户的一通电话,就去修改一堆HTML代码了)

升级1.0:加上一些管理接口,开放让客户自己去修改/删除贴过的东西,也不是什么难事。把数据读进来,放进Form的Value值当作默认值,修改完的数据用Update送回数据库即可。

升级2.0    像是SeedNet或是一些证券公司的网站,常常有一些新闻或消息,不但显示出标题,还显示出大约100字的内容,然后一个More Information...链接到全文。基本上跟上面的结构没什么两样,只不过在要Show Subject时,同时显示出Content前面固定长度的字符串而已。

  1. //显示出Content前面固定长度的字符串
  2. <?
  3. $str = "select serial,subject,left(content,100) from boar dwhere id=3 order by posttime desc limit 10";
  4. ...
  5. echo "<a href=\"show.phtml?$serial\">More...</a>"
  6. ?>

5、讨论区

讨论区一般常见的有两种:

第一种像是Matt`s Script(http://www.worldwidemart.com/scripts/)使用的是全部展开标题的树状结构,一篇Follow的文章紧跟在原来的下面,优点是层次分明,一目了然,而且可以有好几层。

第二种原则上只有两层,首先像公告栏似的列出一堆标题,然后点进去就是所有的关于这个主题的文章。优点是速度快,管理与程序结构比较单纯。

这里重点以第二种快速的讨论区说明,然后等到抓到精髓之后,应该可以设计出更个性化、方便灵活的讨论区。第一种树状结构在数据库的角度没什么太大不同,不过显示的接口比较花功夫,可以自行试试看。

第一步:规划一下Table的结构。每篇文章(每笔数据)其实内容跟“留言”或“新闻”差不多,有主题、有内容、有发布者的姓名等。

  • 关键点在“Group”跟“Order”,就是说这些一篇一篇的文章,哪些是同一个主题下的讨论,其中先后次序又应该如何。
  • 另外,假设有20,000篇文章在数据库里,也许只分属2,000个主题,因此为了空间的考虑,应该把Subject取出来独立做一个Table。
  1. create table subject(
  2. subject_id INT unsigned not null auto_increment,
  3. subject_name CHAR(20),
  4. primary key(subject_id)
  5. );
  6.  
  7. creat table content(
  8. content_id INT unsigned not null auto_increment,
  9. subject_id INT unsigned not null,
  10. post_order INT unsigned,
  11. postname CHAR(10),
  12. postemail CHAR(30),
  13. ...
  14. primary key(content_id),
  15. index(subject_id)
  16. );
  • 现在我们用了两个Tables,其中Content已经不存在Subject数据,直接用一个subject_id join到Subject Table。另外设计一个post_order,用来记录该文章到底在同一个主题的第几篇。
  • 用户张贴新的主题时,要做两个Insert操作,一个到Subject Table,另一个到Content Table,用户对某个主题Follow讨论时,则只有Insert到Content Tabel。如过要同一主题所有新的文章一律放在最后面,那post_order只要最大的加一就行。如果要插入在Follow的文章后面,还得Update同一主题的所有post_order值。

看显示的Query会更清楚一些:

  1. $str = "select subject_id,subject_name from subject";//列出所有Subject
  2. ...
  3. echo "<a href=\"show.phtml?$subject_id\">$subject_name</a>;
  1. $str = "select post_name,...from content
  2. where subject_id = $subject_id
  3. order by post_order";
  4. ...

上面的,只是原理而已,真的要运行,站在用户接口的角度,做到这样还太简单。可以多发挥想象力,例如结合后面的会员程序等,创造一个真正方便又快速的讨论区程序出来。

6、全文检索

坑:简单的想法,把所有的字放在数据库中,一搜寻就好了,问题是,第几页?第几行?怎么记录呢?总不能回答“找到”就可以把!

思路:把一整页当成一笔数据总行吧!这样可以知道找到的字符串是在第几页了。

还有问题:刚好在分页的地方的字符串怎么办?

思路:要设计全文检索,(认为)应该考虑的是,要做到什么程度。比方论文检索,也许找到哪一篇论文中有就可以了,而一本书的检索,至少应该到某一章节。

  • 两种方式:文件形式,数据库形式。
  • 可以自定义一种规则,读到某个特殊字符/字符串代表换行/换页等,然后把文件一行一行读进来。

    编号id

    章chapter 节section 段parag 内容content
    1 1 1 1 这是第一段,这是第一段,这是第一段
    1 1 1 2 这是第二段,这是第二段,这是第二段

参考:这样只要一个Select...Where ContentLike ‘%$key%’就可以了

7、会员

做一个Table记录会员数据,不是什么难事。困难的地方是,有了会员数据之后,那些要会员才能存取的网页,要如何保护?

坑:第一个直觉的想法,利用Apache本身的提供的登入限制功能就好了。通过.htaccess的设置,把这些网页放在一个目录下面,就可以达到这样的效果。

  • 第一个困扰:未来有新的用户,或者要更改密码时,都必须执行Htpasswd,要做到Web接口管理的话,可以用PHP写一个exec()做到。
  • 第二个困扰:如果会员数量庞大,速度会慢下来,当然也可以用Apache提供的DBM authentication解决。
  1. 因为Apache Authentication通过Header传送,PHP一样可以传送Header,因此可以利用这点,向Browser要求一个Aiuthentication,传回来Username跟Password自己到MySQL去做Check,不通过Apache。(注意:这个方法不要跟Apache本身的.htaccess一起用)
  2. 如下代码,读入Username和Password,配合MySQL的Member,后面就没问题了、如果在每一个需要保护的PHTML都加上这一段,就可以达到预期的效果,当然跟Apache Authentication一样,最好Realm都是同一个。
  1. <?
  2. if(!$PHP_AUTH_USER):
  3. Header("WWW-authenticate:basic realm=\"会员登入\"");
  4. Header("HTTP/1.0 401 Unauthorized");
  5. //用户按了cancel的话
  6. echo "很抱歉!您没有读取的权限!\n"
  7. exit;
  8. else:
  9. echo "嗨! $PHP_AUTH_USER.<p>";
  10. echo "您用的密码是 $PHP_AUTH_PW.<p>";
  11. endif;
  12. ?>
  • 上述两种方式,基本对Browser端而言是一模一样,只是Server运行方式不同而已。换句话说,每一次Browser激活后,只要通过一次检查,对相同的Realm的Username/Password都会被保存下来,再次进去则不必输入用户名称与密码。这也是最大的缺点:没有Logout,除非关闭Browser。

正确的做法:一般网站多半采用另一种方式:Unique ID。

原理是:不管同一个时刻有多少人进来,对每个Login指定一个暂时的、唯一的ID,存在Cookie或者用参数传递。这样只要把Cookie删除,或者把Server端相对的ID删掉,就算Logout了。

问题:这个ID要用什么比较好?又不会重复?

解决:PHP提供一个函数Uniqueid(String Prefix),以微秒为基准产生一个字符串,加上Prefix可以长到一百多个字符。更安全的作法,则是利用随机数以及编码:

  1. mt_srand((double)microtime()*1000000);
  2. $id = des(uniqid(mt_rand(1,2000)));

这样会以1~2000的数字为Prefix,产生Unique ID,再经过编码加密,让Id成为一个长32个字符的“唯一”字符串。

当然,Member Table必须也要多一个字段了:

  1. uid CHAR(32)

用这个Unique ID的方式,应该另外设计一个简单的Form,输入Username跟Password

  1. <form action="login.phtml" method="POST">
  2. 名称:<input type="Text" name="username"><br>
  3. 密码:<input type="Text" name="userpass"><br>
  4. <input type="Submit" name="" value="进入">
  5. </form>

进来之后,检查Username/Password跟在数据库里的是否一样,一样的话,产生Unique ID,存到Cookie中,也记到Member Table的Uid里。之后的Select命令,只要一个where uid=$id,就可以找出是哪一位Member。

把上述的操作,放在一个PHTML文件里,然后所有需要被保护的PTHML(没错,只有PHTML文件)最前面加上一个Enclude就能达到预期的效果。

8、个人专属网页

现在许多网站,尤其是证券的站点,都已经提供专为个人设计的画面,比如你只想看财经消息,不想看国际新闻,那么你Login之后的首页,就只显示财经消息,每个会员都可以自行设置一些选项。

用PHP怎么做到?把上述Member Tabe多加一些字段,用来存储属性,Login之后把这些属性一并抓出来,像这样:

  1. <?
  2. if($show_news&1):
  3. //001 代表显示财经信息
  4. ?>
  5.  
  6. 财经信息:...
  7.  
  8. <?
  9. endif;
  10. if($show_news&2):
  11. //010 代表显示国际消息
  12. ?>
  13.  
  14. 国际消息:...
  15.  
  16. <?
  17. endif;
  18. ?>

9、购物车

沿用Member的概念,当第一件产品加入购物车的时候,给它一个Unique ID,并且记录下来,结算的时候再把同样的Unique ID的所有产品列出来即可。

第一步:至少需要两个像这样的Tables

  1. create table product(
  2. product_id INT not null,
  3. product_name..
  4. ...
  5. );
  6.  
  7. create table cart(
  8. cart_id INT not null,
  9. uid CHAR(32),
  10. product_id INT,
  11. primary key(cart_id),
  12. index(uid)
  13. );

记录的数据会如下表所示:

cart_id uid product_id
1 ijghgdfafgsd 158
2 ijghgdfafgsd 134
3 ijghgdfafgsd 241
4 ygbfdsjdghgf 63
5 ygbfdsjdghgf 123

第二步:在PHP中一次找出来该Unique ID对应的,被选择的产品数据。当然时常要用到的“清除购物车”或是“修改”甚至“数量”,对应到Cart Table就可以了。

  1. $str = "select product.product_name,...
  2. from product,cart
  3. where product.product_id=cart.product_id
  4. and cart.uid='$id'";

购物车的另一种写法:利用联机进来的IP、Domain以及Browser信息($REMOTE_ADDR、$REMOTE_HOST、$HTTP_USER_AGENT),来确认“一辆”购物车,而不用Unique ID。

这样做的好处:不用通过Cookie或者参数的传递,对于不支持或拒绝接受Cookie的用户,也不会发生兼容的问题。


注:转载请注明出处

【前端阅读】——《活用PHP、MySQL建构Web世界》摘记之高级应用的更多相关文章

  1. 【前端阅读】——《活用PHP、MySQL建构Web世界》摘记之设计技巧

    二.设计技巧 Programming的习惯因人而异,这里只提供一些经验,可以参考. 1.利用Include模块化你的程序代码 Include函数基本上说:就像是把另一个文件(HTML或者PHP程序)读 ...

  2. 【前端阅读】——《程序员思维修炼》摘记&读后感&思维导图

    前言:这是一本介绍如何用脑的书,并从思维的角度(以程序员为例),介绍如何从新手成为专家.作者带领着读者(我)共同经历一次有关认知科学.神经学.学习和行为理论的旅程,探索人类大脑令人 惊奇的工作的机制, ...

  3. web.py+html+mysql实现web端小系统的问题汇总

    利用web.py+html(bootstrap)+mysql实现了一个小型的设备管理系统,在这个过程中遇到很多问题,将问题及解决方案总结如下,有遇到类似问题的同学,希望可以帮到你们. 1.关于中文的编 ...

  4. 个人学期总结及Python+Flask+MysqL的web建设技术过程

    一个学期即将过去,我们也迎来了2018年.这个学期,首次接触了web网站开发建设,不仅是这门课程,还有另外一门用idea的gradle框架来制作网页. 很显然,用python语言的flask框架更加简 ...

  5. Python+Flask+MysqL的web建设技术过程

    一.前言(个人学期总结) 个人总结一下这学期对于Python+Flask+MysqL的web建设技术过程的学习体会,Flask小辣椒框架相对于其他框架而言,更加稳定,不会有莫名其妙的错误,容错性强,运 ...

  6. 零基础转行web前端,如何高效的去学习web前端

    web前端开发要学的知识内容涉及的会很宽泛,虽然说主要是HTML.CSS和JavaScript这些基础知识点,但学前端开发除了要学这些基础知识外,学员还要在这之上进行延伸和深入的去学,而且互联网时代不 ...

  7. Python+Flask+MysqL的web技术建站过程

    1.个人学期总结 时间过得飞快,转眼间2017年就要过去.这一年,我学习JSP和Python,哪一门都像一样新的东西,之前从来没有学习过. 这里我就用我学习过的Python和大家分享一下,我是怎么从一 ...

  8. openresty 前端开发入门五之Mysql篇

    openresty 前端开发入门五之Mysql篇 这章主要演示怎么通过lua连接mysql,并根据用户输入的name从mysql获取数据,并返回给用户 操作mysql主要用到了lua-resty-my ...

  9. virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续)

    virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续) 第一次接触到 linux,不知道linux的确很强大,然后用virtualbox ...

随机推荐

  1. Leetcode 632.最小区间

    最小区间 你有 k 个升序排列的整数数组.找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中. 我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < ...

  2. c++中读取文件最快的方法

    https://www.byvoid.com/blog/fast-readfile 可以看看了.

  3. Codeforces Round #315 (Div. 2) B 水题强行set

    B. Inventory time limit per test 1 second memory limit per test 256 megabytes input standard input o ...

  4. 【bzoj3894】文理分科 网路流

    [bzoj3894]文理分科 2015年3月25日3,4002 Description  文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过)  小P所在的班级要进行文理分科.他的班 ...

  5. redis windows安装

    下载:https://github.com/MicrosoftArchive/redis/releases 命令行启动:redis-server.exe redis.windows.conf 以服务启 ...

  6. JAVA神操作--使用Arthas线上热更新实战

    热更不规范,同事两行泪 背景 C君是一个javaer,最近在开发用户登出接口的时候,不小心把接口参数拼错了 正确的是: /api/v1/user/logout?referrer=www.javaer. ...

  7. kernel thread vs user thread

    The most important difference is they use different memory, the kernel mode thread can access any ke ...

  8. poj 3281 Dining 拆点 最大流

    题目链接 题意 有\(N\)头牛,\(F\)个食物和\(D\)个饮料.每头牛都有自己偏好的食物和饮料列表. 问该如何分配食物和饮料,使得尽量多的牛能够既获得自己喜欢的食物又获得自己喜欢的饮料. 建图 ...

  9. c语言中的main函数讨论

    **从刚开始写C程序,相比大家便开始写main()了.虽然无数的教科书和老师告诉我们main是程序的入口.那么main函数是怎么被调用的,怎么传入参数,返回的内容到哪里了,返回的内容是什么?接下来我们 ...

  10. CF501D Misha and Permutations Summation(康托展开)

    将一个排列映射到一个数的方法就叫做康托展开.它的具体做法是这样的,对于一个给定的排列{ai}(i=1,2,3...n),对于每个ai求有多少个aj,使得j>i且ai>aj,简单来说就是求a ...