暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PHPMySQL 搭建网站

yBmZlQzJ 2023-12-14
311

Cover

Table of Contents

前言

第 2 章 准备工作

第 3 章 主页&数据库连接

第 4 章 图片显示和 Page 页面

第 5 章 管理页面

第 6 章 文章编辑、图片上传

第 7 章 图片上传、故事删除

第 8 章 文章的 publish

第 9 章 关键字和搜索

前言

PHP 是一种易于学习和使用的后台开发技术,用户只需具备很少的编程知识,就可以使用 PHP 建立一个具有交互功能的 Web 站点。PHP 同样也是一种嵌入式 HTML 脚本语言,大多数语法来源于 C 语言,也有一部分 PHP 特性借鉴于 Java 和 Perl 语言。

PHP 最大的特色是简单并与 MySQL 天生的结合性。从目前市场情况看,大约有 2200 万家网站采用 PHP 技术,而且数量还在持续增加中。PHP 技术也受到计算机工业巨头的支持,像 IBM 和 Oracle 都致力于开发支持 PHP 软件以顺利读取其下数据库的程序,支持 PHP 的发展。

本教程主要介绍了如何利用 PHP+MySQL 搭建网站,从开始的域名申领、数据库的建立到网站基本功能的开发。让读者能够根据教程,了解并搭建自己的网站。

适用人群

高级 PHP 网站开发人员,特别适合于有编程基础,希望全面学习 PHP 技术,提高实际应用能力的读者群体。

学习前提

  • 比较熟悉 PHP 语言。
  • 对 MySQL 数据库有一定了解,能够简单的操作数据库配置并做些增删改查的操作。

鸣谢

作者:kaka

出处:【转载】http://blog.csdn.net/u011156012/article/category/3254867

作者简介

作者: kaka

作者简介:移动客户端工程师,多年从事移动 APP 开发工作,具有丰富的项目经验。

联系方式: CSDN 博客地址:http://my.csdn.net/u011156012

更新日期:2015-05-26

2

准备工作

本教程讲如何用 PHP+MySQL 搭建网站。

之前一直有想过搭建自己的个人网站,然后上周通过阿里云申请的域名和空间都通过审核了,于是就开始研究如何用 PHP+MYSQL 搭建网站,研究了差不多两周,总算搞定了一个小型的 blog 类的网站。当然,整个过程是通过学习《PHP and MySQL web development》下来的,这篇教程中的例子是在原书中的 Chapter 28: Building a Content Manager System 章节的基础上,修改完成的。所有的源代码可以在这里找到,本来想买中文版的书来看,但是看评论说翻译的不行,然后就直接看的原版第 3 版的英文 PDF,有想要的同学可以自行 Google 或者给我留言。

我是从 0 开始学习PHP+MySQL的,基本上网站搭建下来花了不到两周;当然,这里需要你有一定的 HTML 和 SQL 的基础,很基本的就行了。PHP 其实就是个脚本语言,在原来的 HTML 中,把需要动态计算的部分用 PHP 完成,其实最后输出出来的还是 HTML 的格式。

所以不用觉得很困难,当然我在学习的过程中还是经历的很多痛苦的,因为书本资料比较久远,而且阿里的云主机也不知道怎么连数据库,所以很有必要记录下来。

按照惯例,我们来看下需要完成哪些准备工作吧。

首先你需要有一个自己的域名和主机。

这个我是通过阿里云注册的(www.net.cn)里面有域名申请,我申请了一个.cn
的,一年 29 块钱。域名申请很简单,掏钱就可以了。主要是之后还要申请主机,这样可以把你的域名解析成你的主机 ip 地址,然后用户访问你的域名以后就能跳转到你的主机上去,找到相应的网页文件了。

整个主机申请的过程可以参照网站上面的介绍,里面有特别详细的过程,包括填写资料,上传省份证、到指定地点拍照、邮寄资料,然后就等待审核吧。我之前的所有步骤,就是拍照、邮寄资料这些的都是两天就搞定了,但是最后资料审核特别慢,基本上两周才审核通过。你也可以申请国外的主机,好像不用审核,但是需要收费。国内阿里会免费提供你一个主机,但是就是需要审核。

pm.png

这个是我在阿里的主机界面,在下面的新手必读里面,写的比较清楚,按照这个步骤来,你的主机申请是没啥问题的。

数据库操作

这个步骤我研究了好久才弄明白在哪里操作。本来按照上图里面的 3 步骤来,本地下了个 Mysql 然后无论如何也连接不到远程去。后来无意间发现可以在网页上管理数据库。

就是上图里面的,在你的主机目录后面,点击“管理”,然后就跳转到这个页面:

pm1.png

然后点击顶端的“数据库信息”

pm2.png

点击右边的“管理”

pm3.png

然后就到了登录界面,登录以后,在命令行页面就可以操作数据库了,建表、插入、删除等等操作,写完了以后 Ctrl+Enter 就执行了

pm4.png

然后就可以执行 bookmarks.sql 里面的响应的 sql 语句,建好我们这个程序需要用到的几个表

代码如下:

pm5.png

然后我们需要插入一些测试数据,直接用教材里面的吧:

insert into writers (username, password, full_name)
values ('bob', SHA1('password'), 'Robert Bobbins');
 
insert into writers (username, password, full_name)
values ('bill', SHA1('password'), 'William Billings');
 
 
insert into pages (code, description)
values ('news', 'The Top News Stories From Around the World');
 
insert into pages (code, description)
values ('sport', 'Sports Latest - All The Winners and Losers');
 
insert into pages (code, description)
values ('weather', 'Up To The Minute Weather Reports and Forecasts');
 
 
insert into writer_permissions (writer, page) values ('bob', 'news');
insert into writer_permissions (writer, page) values ('bob', 'sport');
 
insert into writer_permissions (writer, page) values ('bill', 'news');
insert into writer_permissions (writer, page) values ('bill', 'weather');
 
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (1, 'bill', 'news', 'Man gives birth', 976573221, 976580154, 976570230,
'A man today gave birth in a hospital on Staten Island, NY. The baby boy weighed in at just over eight pounds and is doing well. The parents were naturally overjoyed at the birth of their first son, and have have said they hope to have a large family. <br /><br />Father Ted, 34, conceived using a new method known as paternatility whereby the fertilised embryo is transferred to the father\'s body at an early stage. It is believed that this method reduces many of the risks of childbirth.', 'images/1.jpg');
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (2, 'bill', 'news', 'Fire!', 976562355, 976572203, 976570230,
'Breaking news: Reports are coming in of a fire in a barn somewhere in Arizona. Our sources say the barn is very likely to burn to the ground and will not be economically viable to repair.<br /><br />A bystander is reputed to have said "There was quite a lot of smoke"', 'images/2.jpg');
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (3, 'bill', 'news', 'SFON Launch Party report', 976542355, 976542503, 976555650,
'Yesterday has already gone down in history as the day the best news site on the web first hit the Internet. Just to prove the point, there was a star-studded party last night at a secret location in Seattle.<br /><br />Joining our team for a boogie were several A-list celebs who wish to remain anonymous.', 'images/3.jpg');
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (4, 'bob', 'sport', 'World Crossword Championship Preview', 976531355, 976532503, 976533320,
'It\'s now just three days to the start of the prestigious annual World Crossword Championship to be held this year for the first time live on the Internet. The new media format will allow many more competitors than ever before to take part from the comfort of their own home, or from one of 126 regional centers.<br /><br />Last year\' champion is not keen on the new format. She said "Crosswords should be done on paper, not online".', 'images/4.jpg');
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (5, 'bob', 'sport', 'Basketball is bad for you', 976542355, 976542503, 976555650,
'Scientists believe that basketball can be bad for you. Research has suggested that both watching and playing the game can have detrimental effects on your health. The scientific evidence supporting this claim is currently being verified by our expert team and we will bring you updates as soon as we can.<br /><br />An NBA spokesperson said "That is complete rubbish".', 'images/5.jpg');
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (6, 'bill', 'weather', 'Storms to come', 976542355, 976542503,
976555650, 'It never rains but it pours. When the rain comes in November there\'s gonna be a storm.<br /><br /> Meterologists predict rain, thunder, lightening and all the usual displeasures that you get during a period of inclement weather. No word on a hurricane yet, but don\'t be surprised if we get one!', 'images/6.jpg');
 
insert into stories
(id, writer, page, headline, created, modified, published,
story_text, picture)
values (7, 'bill', 'weather', 'Sun is shining, weather is sweet', 976451129, 976458734, 976458754,
'The forecast for this weekend is good, with long spells of sunshine predicted in most areas. The high temperature will be 96F and no rain is expected until November', '');

HTML编辑器

首选 Komodo edit,该有的功能都有了,左边可以看到目录,然后语法支持的也比较好,写起代码来很舒服

pm6.png

还可以用 Sublime Text2 这个也还不错,我之前用了好久。

总结

代码下载:http://yun.baidu.com/share/link?shareid=3242370915&uk=2953066218 然后我做好的这个示例网站的地址是 www.jiyuanhuida.cn/28 大家可以先去体验一下。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议) 中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

3

主页&数据库连接

这一章节我们来看用户输入网页后的主界面。

一般来说,默认主页都是 index 点 xxx,比如 index.php, index.html , index.jsp 等等。我们来看一下我们的 index.php 吧。

index.php

pm7.png

提醒: 在的两端,不要出现任何空格或者其他字符,也就是不要在<?php
的前面加上空格这样的字符,然后?>
后面也不要出现其余的字符,不然的话可能会出现这样的提示:

pm8.png

我之前出现过这样的情况,Google 了之后是说 header 必须放在最开始的时候执行,不能先有输出然后再 header。

再次强调一遍,stackoverflow 真的是太强大了,基本上所有的问题都能在上面找到答案。

接下来,我们看两个 include_once() 相当于 import 进来的文件,在整个 index.php 中我们移动 include 了 3 个文件,分别是 db_fns.php, header.php 和 footer.php。

我们分别来看吧。

db_fns.php

pm9.png

这个阶段我们只需要用到这个 db_connect() 函数就好了,不要忘记在结尾加上?>

这个函数是用来连接数据库的,mysql_connect() 函数里面的3个参数,分别是 数据库的地址、数据库的用户名称、该用户的密码。

友情提醒下,上一篇里面可以下载到源代码,那里面的密码我是改成了‘password’的,真实的密码不一样哦。 然后用 mysql_select_db() 函数来选择我们的数据库。

这样就可以连接到我们之前建好的数据库了。

header.php 和 footer.php 其实就相当于独立出来的框架,在不同的页面里面,我们只需要修改里面的内容,而外围的这个框架是不变的,所以单独把它们摘出来。

header.php

pm10.png

可以看到,header.php 里面其实没有 php 的代码,都是纯的 HTML 的代码,这里就不多做讲解了,都很简单的标签、链接地址、CSS等等

footer.php

pm11.png

footer 也一样,都是纯的 HTML 标签。这两部分结合起来看,就是一个完整的框架,然后我们需要做的,就是修改中间的部分,让它们在不同的页面展示不同的内容。

让我们把注意力集中在 index.php 中间的 php 代码块部分。我们慢点来,刚开始总会有点困难:

我再帖一遍代码:

pm12.png

代码的第 12 行,我们写了我们工程中的第一个 sql 语句,我们从 page 表中把所有的内容筛选出来,如果在数据库里面是这样的:

pm13.png

我们看到 page 表里面存了所有文章的类型,用 code 来表示;每种类型的描述也都相应地存储了下来。 然后我们通过 mysql_query 函数把 select 的结果保存到一个变量 pages_result 里面:

$pages_result = mysql_query($pages_sql);

然后,看代码的第 17 行,在 while 语句中,我们用到了一个函数 mysql_fetch_assoc 来把搜索出来的结果存到一个字典里面。

如果你 Google 一下这个函数,会发现在 Mysql 的函数中,一共有 3 个:

mysql_fetch_row , mysql_fetch_array 和mysql_fetch_assoc

row 的话只能用下标 0,1,2 来选取不同列的内容,而 assoc 可以通过数据库的列名来选取,array 即可以用数字,也可以用 key 来找。

所以在第一次执行 while 语句是变量 pages 里面其实是一个 key 和 value 的键值对,key 是 code 和 description ,value 分别是 news 和 'The top news stories from around the world';

所以,我们就能理解 18,19 行的 select 语句是如何组成了的吧?不懂的可以留言,大家一起学习!

通过 while 语句循环,我们依次得到 3 个 select 语句,从 stories 表里面选取出按照 page 做分类的所有 stories

pm14.png

这样,我们以此显示出不同 page 的第一个 story(因为是 if 不是 while,仅显示第一个 story 的相关内容); 然后我们通过 resize_image.php 显示出来对应的图片,这个我们放到下个章节来介绍,包括数据库里面的一些小 tips 和 header 里面的几个链接,我们都放到以后介绍。

这样代码写下来,在浏览器里就能显示出来相应的内容了。当然,如果你点击上面的链接是会提示错误的,我们慢慢来完善吧。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议)中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

4

图片显示和 Page 页面

接着上一章节的看,我们现在的程序有了第一个主页面,但是我们会发现几个问题,一个是主页上的图片没法显示,二是点击 read more ... 之后的链接没有内容。

这两个页面的入口分别是下图里面的两个框出来的内容。

pm15.png

我们先来看图片显示的页面;

Resize_image.php

我们注意到其实这个链接的完整 URL 是: resize_image.php?image=...&max_width=...&max_height=...; 也就是说这个链接有 3 个参数: image 是图片的名称,max_width 和 height 分别对应图片的宽和高。 那么我们在这个页面我们该如何处理呢?

pm16.png

这是 resize_image.php 的完整代码,将原始的图片大小根据我们页面输入的 width 和 height 来进行压缩或者放大,然后重新生成一张新的图片,用于显示在页面上。

接下来我们来看 page.php 页面

page.php

pm17.png

因为点击 page 页面其实相当于打开了 3 个不同类型的 blog 内容的详细页面,所以我们肯定是需要到数据库里面进行 select 操作的。

上一篇里面有讲解过,我们只需要改变中间的显示内容,所以在第 10 行和第 47 行,我们分别引入了 header.php 和 footer.php ,中间的内容我们通过数据库查询以后再显示出来。

我们展示 page 页面的时候,可能有时候是用户点击了某一条 story,这时候参数里面会有 story,传入的是故事的 id;或者可能是某一类的只有 page 字段,所以根据参数中有没有 story,我们来决定我们的 select 该怎么写。

但是无论如何,我们最后得到的都是这样的表结构:

pm18.png

我们再来回顾下 stories 表的建立过程:

pm19.png

注意看到 id 字段不仅仅是 primary key,而且它还是 auto_increment 属性,在 MySQL 里面,auto_increment 就是自增字段,每次插入数据时,会自动查询当前序列的最大值,然后加 1,

pmsql.png

大家看我的 stories 表中存的所有内容,1-7 都是我们通过教材手动 insert 进去的,然后会发现接下来就是 11 了,而并没有 8,9 和 10 ,是因为我在开发过程中进行了插入和删除操作,我把 id 为 8,9,10 的记录删除了,所以在表中没有显示,但是即便这时候你的表里面最大的 id 是 7,他的记录也会插进去 11,也就是说这个自增的序列是独立于当前的表的,和 oracle 的自增序列一样,但是我不太清楚 mysql 里面的自增序列和 oracle 有哪些区别。

oracle 中的自增序列的建立方法是:

CREATE SEQUENCE "SEQ_ID" MINVALUE 1 MAXVALUE 999999999999 INCREMENT BY 1 START WITH 1 CACHE 10 NOORDER NOCYCLE;

然后使用的时候就直接 insert .... values(seq_id.nextval)就相当与插入了下一个自增序列的下一个值,所以在 oracle 里面可以有好几个自增序列,但是不太清楚 MySQL 里面自增序列这块是怎样的,目测是只有一个公用的自增序列。

好了我们回归正题,在 while 循环体内,我们能看到每个故事是由 4 部分组成的,

27 行:

显示每篇 story 的 headline,

29-35 行:

根据存储的 picture 名称来显示出图片,使用的方法仍然是我们上面提到的 resize_image.php

36-41 行:

这里我们需要用到 db_fns.php 中的新的函数:

把下面的函数添加进 db_fns.php 中,这个函数很简单,就是把当前 sotry 的 writer 信息找到。

pms1.png

然后显示文章修改的时间:

这里在数据库里面存储的是 10 位的时间戳形式的,显示的时候 根据格式做一下转换就好了:

date('M d, H: i', $story['modified']);

44 行

显示故事的主题内容。

好了,这样我们就能看到界面上的图片,然后也能点击主界面上的大部分按钮了。

下一章节我们来进行用户登录,然后新增文章等操作。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议)中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

5

管理页面

先来看一下本篇将要介绍的内容。

我们的主页面已经搭建完成了,然后左边的 navigation 里面的大部分内容也都能点击了,只剩下“search” 和“I'm a writer”两个链接了。

本篇教程过后,我们将能完成下面的功能:

这是我们的主界面

mm.png

点击“I'm a writer” :

mm1.png

点击任意一个链接:

mm2.png

Writers 登录之后的页面:

mm3.png

好了,我们一步一步来吧:

我们可以看到在主界面的表单项里面,点击 I'm a writer 之后的链接是这样的:

mm4.png

“admin/index.php”,所以我们需要在主机上新建一个文件夹,命名为 admin,然后编辑 index.php,就是我们今天要搞定的用于作者登录的页面了。

为了便于讲解,从现在开始,如果不加特殊的说明,所有的文件都是在 admin 这个文件夹下新建的,我们再来回顾一下目录结构:

mm5.png

接下来,我们就来开始作者页面的开发吧!

index.php

mm6.png

这个页面很简单,从开始的图片里面也看到了,就是两行表单的内容,一个链接指向本篇要讲解的 writer.php,另一个链接指向 publish.php。

接下来我们来看

writer.php

mm7.png

我们先来整体看一下 writer.php 是如何完成我们想要的内容的,然后里面出现的一些函数我们在后面再详细讲解 第4行

include 了一个新的文件 include_fns.php,注意,这个也是在 admin 文件夹里面的哦,writer.php 中会用到一些函数,而这些函数,都是从这个 include_fns.php 中所包含的。

第6行

判断了一下当前时候有用户登录,这个函数将会在之前引用的文件里面包含。如果没有用户登录,那么就执行 login_form() 函数,显示出用户登录的表单,否则的话,就会显示出当前登录用户的文章信息了

第13行

get_writer_record 函数用来返回用户的相关信息,然后在 15-19 行,结合用户的信息,显示出这一行内容:

21-23行

这个 select 语句应该很简单了吧,就是把当前用户发表过的文章都找出来,按照创建的时间做倒叙排序

25-28 行

根据用户的记录,显示用户一共有几篇文章,然后再附带一个新的连接到添加文章的页面 story.php,这个我们在下一篇 blog 中讲解

30-59 行

这里面的内容应该我们也不难理解了,之前有类似的内容,就是按照搜索出来的文章信息,展示给用户,同时提供几个链接可以进行更多的操作:edit(story.php),delete(delete_story.php)和keywords(keyword.php)等等

好了,这里整体的框架我们已经清楚了,接下来我们就单独来看几个新用到的函数吧。

我们来看下

include_fns.php

mm8.png

其实很简单对吧,这里还是引入了两个新的 php 文件,一个是上一级目录下的 db_fns.php,这个我们在之前的文章里面已经很熟悉了,是用于数据库链接和操作的各个函数,注意引入的格式是:../db_fns.php
; 另一个是我们关于用户的一系列函数user_auth_fns.php

check_auth_user()函数

这个函数出现在 user_auth_fns.php 文件中:

mm9.png

很简单,就不多介绍了。

login_form()函数

依旧是 user_auth_fns.php 文件中:

mm10.png

这个函数依旧不难,也是之前出现过的内容,就是一个表单的输入,然后点解 login 按钮以后,请求的是 login.php 页面,发送的方式是 post。

login.php 页面依旧很简单,我们来看下吧:

login.php

mm11.png

这里两个关键点:

1 个是 login 函数,这个函数依旧是来自 user_auth_fns.php 文件中:

mm12.png

我们根据传入的两个参数 username 和 password,都是之前用户输入的内容,然后去数据库里面和 writers 表里面做对比,如果找到了,就表示用户输入的用户名和密码是合法的,返回 1;否则就返回 0。

是我们看到 header('Location: '.$_SERVER['HTTP_REFERER']);函数的作用是返回到之前的页面,并刷新登录; 之前的页面是 writer.php,因为用户已经登录过了,所以在 writer.php 的第一个 if 判断时,得到的结论就是已经有登录的用户,所以就跳转到 11 行,进行用户文章的展示页面了。

好我们接着来看 :

get_writer_record()函数

因为是数据库层面的操作,所以这个函数存放在 db_fns.php 中,注意,这个文件在上一层目录中

mm13.png

基本上也就这些内容了。到这里,我们一共完成了用户的登录、显示文章等页面的操作,这节内容还是有点多的,大家好好消化下吧。有不同的可以留言一起讨论。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议) 中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

6

文章编辑、图片上传

本篇我们将来重点看文章编辑页面 story.php,因为这个页面说实话代码量是挺多的,还涉及到了图片的上传。

从页面上来直观的体验:

a.png

add new 和 edit 都是打开的 story.php 页面,所以我们应该能提前想到,这个页面会先检测下是哪种请求。 首先我们来搞定比较简单的 logout.php 页面

a1.png

这个页面其实很简单了,主要是几个函数

unset 函数其实就是将一些特定的变量置为空;

session_destroy 函数是销毁当前的 session,当然,当前 session 中的数据也随着一并销毁了;

接下来再执行 header 函数,也就是 writer.php,当然就会执行到这个代码块中去了:

a2.png

Menu 和 Public Site 都很简单,一个是返回到 admin 文件夹下的 index 页面,另一个是返回当上级目录,默认是 index.php,就是我们整个网站的主页面。

接下来看重头戏,

story.php

因为这部分的代码算是比较长的,我们还是先把代码贴出来,先整体讲解下,然后再就个别细节进行深入讲解。

<?php
# Script User to Create or Edit a Story
include_once('include_fns.php');
 
if (isset($_REQUEST['story'])) {
$story = get_story_record($_REQUEST['story']);
}
?>
 
<form action = "story_submit.php" method = "POST" enctype="multipart/form-data">
<input type = "hidden" name="story" value = "<?php echo $_REQUEST['story'];?>">
<input type = "hidden" name = "destination"
value = "<?php echo $_SERVER['HTTP_REFERER']; ?>">
 
<table>
<tr>
<td>Headline</td>
</tr>
 
<tr>
<td><input size="80" name="headline"
value ="<?php echo $story['headline'];?>" ></td>
</tr>
 
<tr>
<td>Page</td>
</tr>
 
<tr>
<td>
<?php
if (isset($_REQUEST['story'])) {
# code...
$query = "select p.code, p.description
from pages p, writer_permissions wp, stories s
where p.code = wp.page
and wp.writer = s.writer
and s.id = ".$_REQUEST['story'];
}else{
$query = "select p.code, p.description
from pages p, writer_permissions wp
where p.code = wp.page
and wp.writer = '{$_SESSION['auth_user']}'";
}
echo query_select('page', $query , $story['page']);
?>
</td>
</tr>
 
<tr>
<td>Story text (can contain HTML tags)</td>
</tr>
 
<tr>
<td>
<textarea cols = "80" rows="7" name="story_text" wrap="virtual">
<?php echo $story['story_text'];?>
</textarea>
</td>
</tr>
 
<tr>
<td>
Or upload HTML file
</td>
</tr>
 
<tr>
<td>
<input type = "file" name = "html" size="40">
</td>
</tr>
 
<tr>
<td>Picture</td>
</tr>
<tr>
<td><input type="file" name= "picture" size="40"></td>
</tr>
 
<?php
if ($story[picture]) {
$size = getimagesize('../'.$story['picture']);
$width = $size[0];
$height = $size[1];
?>
 
<tr>
<td>
<img src="<?php echo '../'.$story['picture'];?>"
width="<?php echo $width;?>" height="<?php echo $height;?>">
</td>
</tr>
<?php
}
?>
 
<tr>
<td algin="center"><input type="submit" value="Submit"></td>
</tr>
</table>
</form>

因为代码比较长,所以就不整个截图了,然后我们来走一遍代码:

第 5 行

我们之前有提到过,无论点击 add new 还是 edit,显示的都是 story.php 页面,所以,这里就是根据 request 中有没有 story 这个变量来决定到底是 add new 还是 edit 了。当然,我们很容易能够想到,如果没有参数 story,那就是 add new,如果有 story 参数,那一定是 edit 了。

这也可以从 writer.php 的代码中看出来。

第 6 行

我们用 get_story_record 函数来获取当前 story 的各个详细信息,包括 id,作者,主体内容,创建时间,修改时间,发布时间,图片内容等等。

接下去的整个代码构造出来的是一个表单内容 form

a3.png

看到表单 submit 的请求页面是 story_submit.php,请求方式是 POST,关于 enctype,我们来看一下stackoverflow 上面大神的解答吧:

a4.png

因为我们这个页面可能会传文件上去,所以enctype要是 multipart/form-data。

接下来,页面输入了两个属性为 hidden 的参数,一个是 story,一个是 destination。story 不用多解释,如果是新建的话,那 story 是空的;而 destination 是为了在 story_submit.php 页面可以直接返回到当前页面的前一个页面(其实准确的说法,这里并不是前一个页面,而是The address of the page (if any) which referred the user agent to the current page. This is set by the user agent
,也就是 writer.php 页面,其实这里 _SERVER['HTTP_REFERER']
里面其实就是 writer.php 页面。

关于更多 _SERVER 的内容,参见: http://php.net/manual/en/reserved.variables.server.php

16-23 行

是 headline 的表单行,这部分比较简单

25-48 行

是 page 类别的下拉选择项

这里依旧是根据参数中有无 story 来判断,如果有,则根据当前 story 的 id 号来找到属于哪一类别的,并且显示出来;如果没有,则查看当前用户有发表那几种文章的权限,例如当前我登陆的用户,只有两个权限:

a5.png

当然,这个权限是存储在 writer_permissions 表中的,

然后 select 语句写好了之后,我们就通过 query_select 函数来显示下拉框

50-60 行

这部分用来显示 story 的主体部分,和 headline 类似。

62-80 行

是用来上传文件的部分,第一部分是上传 html 格式的文件,第2部分是上传图片

81-96 行

这部分 php 代码用来显示已经存储于服务器上的图片,当然前提是要能从 story 表中获取到 picture 字段的内容

好了,整个代码走完了一遍,我们来看具体用到的几个函数吧:

get_story_record 函数

这个函数存在于 db_fns.php,你知道它是存放在根目录的对吧?

a6.png

query_select 函数

依旧是在 db_fns.php 中

a7.png

这部分组合成了最终要显示的HTML格式的内容,我们可以查看下源代码:

<select name = 'page'>
<option value="" selected>-- Choose --</option>
<option value='news'>[news] The Top News Stories From Around the World</option>
<option value='sport'>[sport] Sports Latest - All The Winners and Losers</option>
</select>

好了,这部分的内容就到此为止,我们下一章章节来看我们新输入的内容是如何上传到服务器上的。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议) 中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

7

图片上传、故事删除

上篇文章中讲到,story.php 中的表单提交之后的页面是 story_submit.php,我们就看一下 story_submit.php 是如何完成文章的发表的 老样子,先上代码:

<?php
# add / modify story record
include_once('include_fns.php');
 
$handle = db_connect();
 
$headline = $_REQUEST['headline'];
$page = $_REQUEST['page'];
$time = time();
 
if ((isset($_FILES['html']['name']) &&
(dirname($_FILES['html']['type']) == 'text') &&
is_uploaded_file($_FILES['html']['tmp_name']) )) {
// if user upload some files, then set the content of the files as the story_text
$story_text = file_get_contents($_FILES['html']['tmp_name']);
}else{
$story_text = $_REQUEST['story_text'];
}
 
$story_text = addslashes($story_text);
 
if (isset($_REQUEST['story']) && $_REQUEST['story']!='') {
# it's an update
$story = $_REQUEST['story'];
 
$query = "update stories
set headline = '$headline',
story_text = '$story_text',
page = '$page',
modified = $time
where id = $story";
}else{
// it's a new story
$query = "insert into stories
(headline,story_text,page,writer,created,modified)
values
('$headline','$story_text','$page','".$_SESSION['auth_user']."',
$time,$time)";
}
 
$result = mysql_query($query);
 
if (!$result) {
# code...
echo "There was a database error when executing <pre>$query</pre>";
echo mysql_error();
exit;
}
 
if ((isset($_FILES['picture']['name']) &&
is_uploaded_file($_FILES['picture']['tmp_name']))) {
# there is uploaded picture
if (!isset($_REQUEST['story']) || $_REQUEST['story']=='') {
$story = mysql_insert_id($handle);
// mysql_insert_id return the auto generated id used in the last query
}
$type = basename($_FILES['picture']['type']);
 
switch ($type) {
case 'jpeg':
case 'pjpeg':
case 'png':
case 'jpg':
$filename = "images/$story.jpg";
move_uploaded_file($_FILES['picture']['tmp_name'], '../'.$filename);
$query = "update stories
set picture = '$filename'
where id = $story";
$result = mysql_query($query);
break;
 
default:
echo 'Invalid picture format:'.$_FILES['picture']['type'];
break;
}
}else{
// there is no image file to upload or didn't get the file's info
echo 'Possible file upload attack:';
echo "filename '".$_FILES['picture']['tmp_name']."'.";
}
 
header('Location: '.$_REQUEST['destination']);
?>

我们还是先从整体捋一遍代码:

$headline = $_REQUEST['headline'];
$page = $_REQUEST['page'];

这两个变量都是从上一个页面 story.php 提交表单中获取的参数。

$time = time();

time 函数返回的是时间戳。

if ((isset($_FILES['html']['name']) &&
(dirname($_FILES['html']['type']) == 'text') &&
is_uploaded_file($_FILES['html']['tmp_name']) )) {
// if user upload some files, then set the content of the files as the story_text
$story_text = file_get_contents($_FILES['html']['tmp_name']);
}else{
$story_text = $_REQUEST['story_text'];
}

这部分代码返回的是上传的 html 文件的内容。

$story_text = addslashes($story_text);

这里用到了 php 中发送 text 内容到数据库的一个函数:addslashes,作用是在一些特定的符号前面加上/
符号,特定的符号有'
, ''
, nul
, \
等,

例如:

a8.png

然后我在搜索这个函数是,发现了另外的方法 mysql_escape_string,

a9.png

if (isset($_REQUEST['story']) && $_REQUEST['story']!='') {
# it's an update
$story = $_REQUEST['story'];
 
$query = "update stories
set headline = '$headline',
story_text = '$story_text',
page = '$page',
modified = $time
where id = $story";
}else{
// it's a new story
$query = "insert into stories
(headline,story_text,page,writer,created,modified)
values
('$headline','$story_text','$page','".$_SESSION['auth_user']."',
$time,$time)";
}

根据传入的参数中有没有 story 来判断是更新还是新添加的 story,这里之前我们也有提到了。

if ((isset($_FILES['picture']['name']) &&
is_uploaded_file($_FILES['picture']['tmp_name']))) {
# there is uploaded picture
if (!isset($_REQUEST['story']) || $_REQUEST['story']=='') {
$story = mysql_insert_id($handle);
// mysql_insert_id return the auto generated id used in the last query
}
$type = basename($_FILES['picture']['type']);
 
switch ($type) {
case 'jpeg':
case 'pjpeg':
case 'png':
case 'jpg':
$filename = "images/$story.jpg";
move_uploaded_file($_FILES['picture']['tmp_name'], '../'.$filename);
$query = "update stories
set picture = '$filename'
where id = $story";
$result = mysql_query($query);
break;
 
default:
echo 'Invalid picture format:'.$_FILES['picture']['type'];
break;
}

上段代码是标准的 php 上传文件的步骤,可以试着记一下

注意这行$story = mysql_insert_id($handle);
,是得到自增序列的下一个字段

header('Location: '.$_REQUEST['destination']);

我们上一篇里面有提到过,在 form 提交了两个 hidden 的参数,其中一个是 destination,其实就是 writer.php 页面了。

好了,基本上这个页面没有什么特别难的地方。

我们在来看更简单的 delete_story.php

a10.png

通过 check_permission 函数来确定当前用户是否有修改的权限,如果有,就把当前的文章删除。 check_permission 是在 user_auth_fns.php 文件中

a11.png

好了,文章的修改和新建部分我们都全部介绍完了,下一篇,我们来介绍 publish 相关的 3 个文件。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议) 中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

8

文章的 publish

本篇我们来看和 publish 相关的 3 个页面: publish.php, unpublish_story.php 和 publish_story.php

我们回到 admin 的主页面,index.php

p1.png

我们点击下面的链接,跳转到的是

publish.php

p2.png

整体过一遍代码,这里面应该没有多少新的内容了,我们重点看一下结构:

4-6 行

和 editer 一样,如果当前用户还未已经登录,就显示登录的界面

9-13 行

显示当前登录作者的名字,以及 3 个链接,logout,主菜单和返回主页面

15-18 行

这个select语句是找出当前作者发表的故事

25-40 行

类似于 story.php 页面,这里我们也是列出来作者发表和未发表的文章列表。

并且如果当前的 published 列不是 null,则显示 unpublish 链接,否则显示 publish 和 delete 链接,像这样:

接下来我们来看

publish_story.php

p3.png

其实这个页面很简单,就是更新下记录,把原本 published 列设置成当前的时间。

注意到在这里并没有执行 commit 操作,后来我查了一下:

Mysql 之所以不需要显示提交 commit,是因为 mysql 里面的 autocommit 是 on,也就是说是自动提交的。

了解更多请点击:

关于 Mysql 的 commit 和 rollback

接下来同样的,

unpublish_story也很简单了:

p4.png

只需要把当前记录中的 published 字段设置成 null 就好了。

到这里,关于 publish 的相关网页我们都搞定了,最后一项,关键字和查找,我们下一篇中讲解。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议) 中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

9

关键字和搜索

本篇是这系列教程的最后一篇了。

我们看到还有几个页面没有讲到,分别是

keywords 相关页面

k1.png

和 search 相关页面

k2.png

将这两部分放在一起是因为 search 是搜索的关键字找到文章的。因为这本教材是比较老的教材了,所以里面的架构设计可能也比较老。

截止到目前,基本上没有新的知识点要讲解了,看一下如何来构建网页和后台的逻辑吧:

keywords.php

k3.png

第 10 行 get_story_record
和get_writer_record
功能类似,是在db_fns.php
中的一个函数:

k4.png

keyword_add.php

k5.png

keyword_delete.php

k6.png

这部分的内容比较简单,和之前的操作都是类似的,所以就不细讲了,有不懂的可以留言。

接下来我们完成了 keyword 相关的页面,我们就回到主页面上,进行 search 的页面编辑吧!

我们点击 search 链接后,链接的地址是

search_form.php

这个页面很简单,就是这样的:

k7.png

代码当然也很简单:

k8.png

接下来我们看 search.php 页面:

k9.png

基本上也没什么难懂的地方,根绝关键字搜索,搜索到了就显示出来,没搜索到的话就显示没找到。

好了,到这里,一个完整的网站已经搭建起来了。当然这个是比较基础的功能性的网站,关于页面的优化,CSS 什么都没有做特别细致的处理。但是我们知道了如何用 PHP 和 MySQL 链接操作显示,剩下的工作就很简单了。

本文由 kaka 创作,采用 知识共享署名-相同方式 3.0 (CC协议) 中国大陆许可协议 进行许可。 转载、引用前需联系作者,并署名作者且注明文章出处。

jk_book.png

jk_weixin.png

更多信息请访问 book_view.png

http://wiki.jikexueyuan.com/project/php-and-mysql-web/

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论