zoukankan      html  css  js  c++  java
  • 【前端阅读】——《活用PHP、MySQL建构Web世界》摘记之高级应用

    一、高级应用

    1、计数器

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    select count from counter where id=3

     就可以读出我们的Count值

    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的环境参数。如果在记录到访次数时,同时将这些参数记录下来,就可以用来统计。至于统计的结果,当然也可以用简单的图形来表示。

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

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

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

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

    3、留言板

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

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

    mysql>create table board(
         serial INT unsigned not null auto_inctement,
         id INT unsigned not null,
         postname CHAR(10),
         postemail varCHAR(30),
         posttime  DATETIME,
         subject var CHAR(40),
         content tinyBLOB,
         remarks  varCHAR(255),
         primary key(serial),
         index(id)
    );

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

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

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

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

    <?//php读取留言
    $str = "select postname,postemail,
                dateformat('y-m-d H:i',posttime),"
                subject,content,remarks
                form board
                where id=3";
    $result = mysql_query(...);
    while(list($pname,$$pemail,$ptime,$subj,$content,$remk)=
    mysql_fetch_row($result);
    ?>
    姓名:<a href="mailto:"<?echo $pemail;?>"<?echo $pname;?></a><br>
    留言时间:<?echo $ptime;?><br>
    标题:<?echo $subj;?><br>
    内容:<?echo $cotent;?><br>
    签名:<?echo $remk;?><br><p>
    <?
    endwhile
    ?>

    几个可议的地方:

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

    4、公告栏(新闻发布)

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

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

    第一步:Show标题的页面

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

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

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

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

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

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

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

    5、讨论区

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

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

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

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

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

    • 关键点在“Group”跟“Order”,就是说这些一篇一篇的文章,哪些是同一个主题下的讨论,其中先后次序又应该如何。
    • 另外,假设有20,000篇文章在数据库里,也许只分属2,000个主题,因此为了空间的考虑,应该把Subject取出来独立做一个Table。
    create table subject(
        subject_id INT unsigned not null auto_increment,
        subject_name CHAR(20),
        primary key(subject_id)
    );
    
    creat table content(
        content_id INT unsigned not null auto_increment,
        subject_id INT unsigned not null,
        post_order INT unsigned,
        postname CHAR(10),
        postemail CHAR(30),
        ...
        primary key(content_id),
        index(subject_id)
    );
    • 现在我们用了两个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会更清楚一些:

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

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

    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都是同一个。
    <?
    if(!$PHP_AUTH_USER):
        Header("WWW-authenticate:basic realm="会员登入"");
        Header("HTTP/1.0 401 Unauthorized");
       //用户按了cancel的话
       echo "很抱歉!您没有读取的权限!
    "
       exit;
    else:
       echo "嗨! $PHP_AUTH_USER.<p>";
       echo "您用的密码是 $PHP_AUTH_PW.<p>";
    endif;
    ?>
    • 上述两种方式,基本对Browser端而言是一模一样,只是Server运行方式不同而已。换句话说,每一次Browser激活后,只要通过一次检查,对相同的Realm的Username/Password都会被保存下来,再次进去则不必输入用户名称与密码。这也是最大的缺点:没有Logout,除非关闭Browser。

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

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

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

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

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

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

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

    uid CHAR(32)

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

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

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

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

    8、个人专属网页

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

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

    <?
    if($show_news&1):
        //001   代表显示财经信息
    ?>
    
    财经信息:...
    
    <?
    endif;
    if($show_news&2):
        //010   代表显示国际消息
    ?>
    
    国际消息:...
    
    <?
    endif;
    ?>

    9、购物车

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

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

    create table product(
         product_id INT not null,
         product_name..
         ...
    );
    
    create table cart(
        cart_id INT not null,
        uid   CHAR(32),
        product_id INT,
        primary key(cart_id),
        index(uid)
    );

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

    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就可以了。

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

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

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



    注:转载请注明出处 

  • 相关阅读:
    重力感应GSensor 方向介绍
    php图片保存、下载
    AJAX技术在PHP开发中的简单应用
    php 面向对象基础
    用PHP处理多个同名复选框
    去掉codeigniter地址中的index.php
    PHP中如何运用ini_set和ini_get()
    Windows 7下PHP配置环境
    zend_application 说明
    PHP写的域名查询系统whois
  • 原文地址:https://www.cnblogs.com/ljq66/p/7745708.html
Copyright © 2011-2022 走看看