PHP7-和-MySQL8-实践指南-六-

61 阅读32分钟

PHP7 和 MySQL8 实践指南(六)

原文:Practical PHP 7, MySQL 8, and MariaDB Website Databases

协议:CC BY-NC-SA 4.0

九、连接多个表和其他增强功能

数据库驱动的网站可以从本章描述的三个实用的改进中获益。例如,多个表可以给出更具体的搜索结果,并且对于论坛和电子商务网站的管理是必不可少的,会员费可以通过支票以及使用 PayPal 和信用卡/借记卡来支付,支票付款可以附带可打印的申请表。

完成本章后,您将能够

  • 使用 phpMyAdmin 创建多个表

  • 理解内部连接和外部连接的区别

  • 使用 phpMyAdmin 连接多个表

  • 使用程序代码连接多个表

  • 提供可打印的在线表格

多表介绍

前面的章节一次显示一个表中的信息。有时数据库使用几个可以相互关联的表。这些数据库被称为关系数据库。可以将每个表中的数据连接(组合)起来,形成可以在浏览器中显示的虚拟表。在本教程中,我们将完全专注于连接表的过程。为了简单明了,这些教程的网站将去掉几个功能,比如登录和管理。这些功能的按钮将出现在标题上,但它们将是死链接。

你可能想知道为什么我们需要不止一张桌子。为什么不把所有数据放在一个表中?我们可以用一张大桌子,但这会带来无穷无尽的麻烦。大量的信息将被多次输入,导致数据库效率低下,并且管理将是耗时和乏味的。

举个例子,假设我们有一个销售电话和对讲机的电子商务网站。我们可以有一组记录,如表 9-1 所示。

表 9-1

有许多重复条目的表

|

订单 id

|

用户姓名

|

地址

|

产品

|

股票

| | --- | --- | --- | --- | --- | | One thousand and six | 查理·史密斯 | 汤斯维尔公园路 3 号 TV77 99JP | 电话 123 | one | | One thousand and seven | 查理·史密斯 | 汤斯维尔公园路 3 号 TV77 99JP | 对讲机 456 | four | | One thousand and eight | 罗伯特·布鲁斯 | 4 林登街城市 UT88 66XY | 对讲机 456 | five | | One thousand and nine | 内莉·迪恩 | 密尔沃基市榆树大道 7 号,邮编:78 88WZ | 电话 456 | six | | One thousand and ten | 罗伯特·布鲁斯 | 4 林登街城市 UT88 66XY | 电话 678 | one | | One thousand and eleven | 内莉·迪恩 | 米尔敦镇榆树大道 7 号 MT78 88WZ | 对讲机 396 | three | | One thousand and twelve | 查理·史密斯 | 汤斯维尔公园路 3 号 TV77 99JP | 电话基座 A2 | four |

这个包含最新订单的单个表有许多问题。

在不同的日期,查理·史密斯点了三样东西,他的地址重复了三次。如果他改变了地址,我们就需要修改表中的三行。查理的名字和地址应该保存在一个单独的表中;这将允许我们只更改他的地址一次。库存水平通常会变化。我们目前必须滚动浏览记录,以确定特定商品的最低库存水平。库存水平和产品描述应该保存在另一个表中,这样当库存水平改变时,只需要更新一个表。当显示产品时,用户和管理员可以容易地看到库存水平的准确数字。

正常化

消除重复和其他维护问题的过程称为规范化。表 9-1 包含了说明非常不良做法的项目。名字和姓氏应该在不同的列中。地址应该按照街道、城镇和邮政编码分成单独的列。这个过程被称为“原子性”这个相当笨拙的名字,因为像原子一样,数据被分成最小的成分。于是原子不可分

规范化是通过应用严格的原子性并将数据拆分成几个表来实现的,而不是只使用一个表,这样每个表都有一个特定的单一用途。此外,每个表中的信息必须有密切相关的数据,如名字、姓氏和电子邮件地址;如果客户更改了他或她的电子邮件地址,您只需修改一条记录。规范化允许数据库被容易地扩展,以便它能保存更多类型的信息。例如,可以添加一个表来保存手机的颜色,或者可以有一个表来保存发货日期。

开始时规范化可能很难理解,但是如果应用原子性,然后将密切相关的数据分组到单独的表中,您将自动规范化您的表。通过将数据分解到最低级别,您可以考虑未来的增长和更好的数据控制,并在未来为自己留下更多修改和操作数据的选项。能够在多个表上建立一对多的关系可以减少数据冗余。

注意

在大多数情况下,正确设计的数据库表(至少)是第三范式(3NF)。

当一个表具有由以下要求定义的关系时,它被认为是第一范式(1NF)。

  • 每个单元格保存一个值。

  • 所有列值都属于同一类型。

  • 每个列都是唯一标识的(列名)。

  • 这些列可以按任何顺序排列。

  • 这些行可以按任何顺序排列。

  • 每行都包含唯一的数据。

如果一个表是 1NF 格式的,并且包含唯一标识每一行的主键,那么这个表就是第二范式(2NF)。如果一个表在 2NF 中,并且没有定义(依赖)于其他列的列,则该表为第三范式。数据是原子的或 ?? 的不可见的。另外,表可以被分类为第四范式(4NF)和第五范式(5NF)。然而,这些分类超出了本书的范围。

在某些情况下,数据库管理员可能会降低规范化程度,并跨表复制数据。这可以提高频繁使用的数据库中的数据检索效率,例如大型百货商店的库存数据库。

现在让我们创建一个包含两个表的数据库。

创建数据库和表

对于本教程的第一部分,我们将创建一个包含两个小表的数据库。在 phpMyAdmin 中,创建一个名为 birdsdb 的数据库,然后设置一个用户和密码,如下所示:

  1. 在 XAMPP 的 htdocs 文件夹或 EasyPHP 文件夹 eds_www 中,新建一个名为 birds 的文件夹。

  2. 出版社的页面下载第 9 章的文件。并将它们解压到新的鸟类文件夹中。

  3. 启动 XAMPP 或 EasyPHP,在浏览器的地址栏输入 localhost/phpmyadmin/ 访问 phpmyadmin。

  4. 单击 Databases 选项卡并创建一个名为 birdsdb 的数据库。从下拉排序规则列表中,选择 utf8_general_ci,然后单击创建。

  5. 单击权限选项卡,然后向下滚动并单击添加新用户。

  6. 输入这些详细信息:

    • 用户名:法拉第

    • 密码 : Dynam01831

    • 主机:本地主机

    • 数据库名称:birdsdb

  7. 单击开始。

查看连接文件

文件 mysqli_connect.php 的代码如下:

<?php
// Create a connection to the migrate database and to MySQL
// Set the encoding to utf-8
// Set the database access details as constants
define ('DB_USER', 'faraday');
define ('DB_PASSWORD', 'Dynam01831');
define ('DB_HOST', 'localhost');
define ('DB_NAME', 'birdsdb');
// Make the connection:
$dbcon = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Set the encoding...optional but recommended
mysqli_set_charset($dbcon, 'utf8');

我们没有为 birds、location 和 rsvinfo 表提供转储文件。因此,您必须手动创建和填充这些表。这不会很乏味,因为表很小。

单击 phpMyAdmin 左侧面板中的数据库 birdsdb,手动创建一个名为 birds 的表,该表有四列,属性如表 9-2 所示。

表 9-2

鸟桌

|

列名

|

类型

|

长度/值

|

默认

|

属性

|

|

索引

|

A_I

| | --- | --- | --- | --- | --- | --- | --- | --- | | 伯德 _id | 中位 | four | 没有人 | 无符号的 | -是吗 | 主要的 | ·······················。 | | 鸟名 | 微小文本 | Sixty | 没有人 |   | -是吗 |   | -是吗 | | 稀薄 | 微小文本 | 60` | 没有人 |   | -是吗 |   | -是吗 | | 最佳时间 | 微小文本 | Sixty | 没有人 |   | -是吗 |   | -是吗 |

birds 表包含一个名为 bird_id 的列。该列被配置为主键。

你会看到如图 9-1 所示的弹出对话框;记住不要输入大小,因为您已经在列描述中定义了它。

img/314857_2_En_9_Fig1_HTML.jpg

图 9-1

设置主索引

我们现在需要创建名为 location 的附加表。

创建第二个表

单击 phpMyAdmin 左侧面板中的数据库 birdsdb,手动创建一个名为 location 的表,该表有四列,属性如表 9-3 所示。将显示一个弹出窗口(如图 9-1 )让您确认 location_id 是主键。只需点击 Go 确认信息。

表 9-3

位置表的属性

|

列名

|

类型

|

长度/值

|

默认

|

属性

|

|

索引

|

A_I

| | --- | --- | --- | --- | --- | --- | --- | --- | | 位置标识 | 中位 | four | 没有人 | 无符号的 | -是吗 | 主要的 | ·······················。 | | 位置 | 微小文本 | Sixty | 没有人 |   | -是吗 |   | -是吗 | | 位置类型 | 微小文本 | 60` | 没有人 |   | -是吗 |   | -是吗 | | 伯德 _id | 中位 | four | 没有人 | 无符号的 | -是吗 |   | -是吗 |

重要的

在位置表中,确保项目 bird_id 与 birds 表中的 bird_id 具有相同的名称、长度和类型。在我们的例子中,它们具有相同的名称(bird_id)、相同的长度(4)和相同的类型(MEDIUMINT)。这对于连接和显示多个表中的数据至关重要。

外键

在正常情况下,您不会期望在位置详细信息表中看到名为 bird_id 的项目。位置表中的 bird_id 项被称为外键。通过在两个表中包含 bird_id 列,我们将能够组合并显示从两个表中选择的数据;我们通过一个 JOIN 语句来实现这一点,稍后我们将对此进行解释。

警告

不要在表格中输入数据。当表准备好进行连接时,我们将稍后执行此操作。

同时,我们必须开始做一些准备。

准备用于连接的表格

现在需要为位置表设置索引。列 location_id 已经被索引,因为它是主键。location 表中名为 bird_id 的外键将被索引。在 phpMyAdmin 中,单击左侧面板中的位置表。选择 Structure 选项卡,并在右侧面板中选中 bird_id 列旁边的框。向下滚动到 Indexes 按钮,您将看到一条消息,表明定义了主索引,但没有定义外键。

向上滚动,然后点击图 9-2 右下角的索引(显示为圆圈)。如果您选中了 bird_id 左侧的框,那么将自动为您创建索引。向下滚动到索引区域。现在您应该可以看到主键和 bird_id 索引。

img/314857_2_En_9_Fig2_HTML.jpg

图 9-2

为外键创建索引

推广两个表

如前所述,因为我们没有用于注册鸟类或位置的页面,所以我们需要使用 phpMyAdmin 手动填充它们。这不会很乏味,因为表中包含的条目很少。此外,对于您自己对该书网站的改编,您将不会获得鸟类和位置表的 SQL 转储文件。因此,学习如何使用 phpMyAdmin 填充表是必不可少的。

要填充 birds 表,在 phpMyAdmin 中,单击左栏中的数据库 birdsdb(图 9-3 中的圆圈),然后单击 Structure 选项卡。您将在右窗格中看到这两个表。

img/314857_2_En_9_Fig3_HTML.jpg

图 9-3

使用 phpMyAdmin 填充 birds 表

选中 birds 表旁边的框(在图 9-3 中圈出),然后在 birds 记录(行)中点击插入图标(在图 9-3 中圈出)。现在将出现插入页面,如图 9-4 所示。

img/314857_2_En_9_Fig4_HTML.jpg

图 9-4

“插入”选项卡显示为黄金眼鸭插入的详细信息

在左侧,您会看到表格列有:鸟名、稀有度和最佳时间。在右侧的文本字段中,您可以填充这些项目。例如,你将在图 9-3 中看到,我们已经进入黄金眼、普通和冬季。

使用表 9-4 中的数据对其他鸟重复该程序。

表 9-4

鸟桌

|

伯德 _id

|

鸟名

|

稀薄

|

最佳时间

| | --- | --- | --- | --- | | one | 黄金眼 | 普通 | 冬天的 | | Two | 歪脖 | 罕见的 | 夏天 | | three | Avocet | 普通 | 冬天的 | | four | 黑水鸡 | 普通 | 随时 |

现在继续使用 phpMyAdmin 并单击左侧面板中的位置表。使用 phpMyAdmin 填充位置表;该过程与您刚才用来填充 birds 表的过程相同。使用表 9-5 中所示的数据。

表 9-5

位置表

|

位置标识

|

位置

|

位置类型

|

伯德 _id

| | --- | --- | --- | --- | | one | 南方公园 | 池塘 | four | | Two | 湿地(wetlands) | 河口 | three | | three | 莱克兰 | 湖 | one | | four | 摩尔菲尔德 | 沼地 | Two | | five | 希斯维尔 | 灌木丛生的荒地 | Two |

现在这两个表都被填充和索引了,我们可以学习如何连接它们,以便数据可以被组合并显示在屏幕上。

注意

位置表中的 bird_id 值必须与 birds 表中现有的 bird_id 值相匹配,才能正确检索数据。如果您在 birds 表中为 bird_id 自动增加的数字与表 9-4 中的不同,请在 location 表中的 bird_id 列中进行调整以匹配您的值。bird_id 列是根据鸟类的栖息地填充的。黑水鸡栖息在池塘中,白鳍豚喜欢在河口生活,黄金眼鸭主要生活在湖泊中,而黄喉拟水鸭生活在高沼地和荒野中。

连接两个表中的数据

phpMyAdmin 应用为连接两个或多个表中的数据提供了一个简洁的过程。尝试以下步骤:

img/314857_2_En_9_Fig6_HTML.jpg

图 9-6

用于指定关系类型的弹出对话框

  1. 打开 phpMyAdmin 并在左侧面板中单击 birdsdb。

  2. 单击设计器选项卡;如果没有看到设计器选项卡,请单击更多下拉选项卡,然后单击设计器。

  3. 您应该看到这两个表;使用鼠标拖动它们,使它们大致处于图 9-5 所示的位置。

    img/314857_2_En_9_Fig5_HTML.jpg

    图 9-5

    放置桌子准备接合

  4. 在垂直工具栏上,单击创建关系图标,该图标在图 9-5 中用圆圈表示。

  5. 单击鸟类表中的 bird_id,然后单击位置表中的 bird_id。如果您以错误的顺序执行此操作(即,首先单击位置),您将会看到一条错误消息。

  6. 你会看到一个弹出面板,如图 9-6 所示。

从下拉菜单中,在两个字段中选择限制,然后单击确定。

注意

MySQL 和 MariaDB 在创建表之间的关系时允许几个选项。这些选项基于父表(birds)发生更新或删除时该做什么,以及这会如何影响子表(locations)。读取数据时(选择),实际关系并不重要。如何从表中提取信息的实际决定是由 SQL 语句本身决定的。

以下选项可用:

  • 级联:根据需要,所有表格都会发生变化。例如,如果 birds 表中的 bird_id 值被更改,它也会更改 locations 表中相应的 id。根据外键关系,这些更改可以通过多个表级联。如果从 birds 表中删除 bird_id 值,locations 表中的相应记录也将被删除。

  • Set NULL :对父表 birds 的任何更改都会导致在子表 locations 的相关主键中放置一个 NULL 值。如果 birds 表中的 bird_id 值被更改或删除,locations 表中相应的 bird_id 值将被更改为 NULL。

  • Restrict:DMBS 不会进行更新或删除,除非同一个 SQL 语句同时处理父表 birds 和子表 locations。如果 SQL 语句试图只更改父表的外键值,而不同时更改子表中的相关主键,该语句将被拒绝。此外,如果 SQL 语句试图删除父表记录或外键,而没有从子表中删除(或更改)相关记录(或主键),该语句将被拒绝。

我们的示例将 delete 和 update 值都设置为 restrict,如果 birds 表发生了变化,而 locations 表没有发生相应的变化,这将为管理员提供反馈。虽然本章介绍了如何从多个表中读取数据,但是您可以通过在 phpMyAdmin 中更改表并尝试更新或删除记录来测试这些关系如何影响表。

  1. 你会看到这些表格被链接(相关),如图 9-7 所示。

    img/314857_2_En_9_Fig7_HTML.jpg

    图 9-7

    这些表现在是相关的

  2. 点击图 9-7 中圈出的保存图标保存链接。

我们现在将使用 phpMyAdmin 创建第三个名为 reserves_info 的表;该表将包含有关保护区的信息,如进入鸟笼(庇护所)和门票(如有)。

创建第三个表

单击 phpMyAdmin 左侧面板中的数据库 birdsdb,手动创建一个名为 reserves_info 的表,该表包含五列以及表 9-6 中的属性。如上所示,验证主键。

表 9-6

reserves_info 表的结构和属性

|

列名

|

类型

|

长度/值

|

默认

|

属性

|

|

索引

|

A_I

| | --- | --- | --- | --- | --- | --- | --- | --- | | reserses _ id | 中位 | four | 没有人 | 无符号的 | -是吗 | 主要的 | ·······················。 | | 鸟皮 | ENUM | 是','否' | 没有人 |   | -是吗 |   | -是吗 | | 入口 _ 成员 | 微小文本 | 60` | 没有人 |   | -是吗 |   | -是吗 | | 条目 _ 非成员 | 微小文本 | Sixty | 没有人 |   | -是吗 |   | -是吗 | | 位置标识 | 中位 | four | 没有人 | 无符号的 | -是吗 | 指数 | -是吗 |

重要的

遵循与前面位置表中 bird_id 相同的过程,将 location_id 作为索引。

使用 phpMyAdmin 中的 Insert 选项卡,用表 9-7 中给出的数据填充 reserves_info 表。

表 9-7

reserves_info 表的数据(门票是指门票)

|

储量 _id

|

鸟皮

|

入口 _ 成员

|

条目 _ 非成员

|

位置标识

| | --- | --- | --- | --- | --- | | one | 是 | 自由的 | one | one | | Two | 是 | one | £2 | Two | | three | 是 | 自由的 | one | three | | four | 不 | 自由的 | 自由的 | four | | five | 不 | 自由的 | 自由的 | five |

注意

reserves_info 表中的 location_id 值必须与 location 表中的 location_id 值相匹配。如果您的值与表 9-5 和表 9-7 中显示的不同,进行必要的调整,使值匹配。

创建并填充 reserves_info 表后,在 phpMyAdmin 中单击页面左侧的 birdsdb 数据库名称。然后单击 Designer 选项卡显示表之间的当前关系。您将看到前两个表及其链接,但可能看不到第三个表。

在这种情况下,单击垂直工具栏上最顶端的图标(图 9-8 中的圆圈),表格列表将出现在右侧的新面板中。将列出第三个表,但不会选中其复选框。选中第三个表格的框以显示该表格。将第三个工作台左右滑动,使其大致位于另外两个工作台的左上方,如图 9-8 所示。

img/314857_2_En_9_Fig8_HTML.jpg

图 9-8

在设计器视图中显示和定位第三个表

第三个表不会被链接,如图 9-8 所示。

我们现在需要在 location 表和 reserves_info 表之间创建一个关系。

  1. 在垂直工具栏中,单击创建关系图标(在图 9-9 中用圆圈显示)。

  2. 单击位置表中的位置标识,然后单击储量信息表中的位置标识。如果您以错误的顺序执行此操作(即,如果您首先在 reserves_info 表中单击 location_id),您将会看到一条错误消息。

  3. 当外键弹出窗口出现时,在两个字段中选择限制,然后单击开始。

现在你应该看到这些表格被链接起来,如图 9-9 所示。

img/314857_2_En_9_Fig9_HTML.jpg

图 9-9

创建并保存第二个和第三个表之间的关系

创建页面以显示连接表中的数据

连接的表是数据库管理系统(DBMS)中的虚拟表,公众看不到。

我们现在将创建一些页面,以便您的表格可以在公共浏览器中显示。除了主页之外,我们还将创建页面来显示鸟类表、保护区的位置、两个连接表和三个连接表。这些页面包含在章节 9 的可下载文件中。

主页

图 9-10 显示了我们网站的主页。

img/314857_2_En_9_Fig10_HTML.jpg

图 9-10

主页

清单 9-10 显示了主页的代码。

<!DOCTYPE html>
<html lang="en">
<head>
<title>Birds Home Page</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,
       shrink-to-fit=no">
<!-- Bootstrap CSS File -->
<link rel="stylesheet"
  href=
"https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
  integrity=
"sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
  crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="birds.css">
</head>
<body>
<div class="container" style="margin-top:30px;border: 3px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
        style="margin-bottom:2px; padding:20px;background-color:#CCFF99;">
               <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<!-- Left-side Column Menu Section -->
  <nav class="col-sm-2">
      <ul class="nav nav-pills flex-column">
               <?php include('includes/nav.php'); ?>
      </ul>
  </nav>
<!-- Center Column Content Section -->
<div class="col-sm-8 row" style="padding-left: 30px;">
<h2 style="padding-left: 50px; padding-top: 20px;">
         Help Save Our Devon Birds From Extinction</h2>
<div class="col-sm-8 text-left">
<p>The Devon bird reserves were established in an effort to combat the massive decline in the bird population. Farmers (the self proclaimed Guardians of the Countryside!) spray insecticides, weed killers and pesticides that kill the birds' main source of food. They also rip out the hedges that provide the birds with nesting sites and their means of travelling safely from field to field. Any birds that survive will probably be shot to satisfy a blood lust for living targets</p>
</div>
<div class="col-sm-4">
<h4 class="text-center"><strong>
         Become a member and support our cause</strong></h4>
<p class="text-left">
         The annual membership fee includes free or reduced entrance fees to the reserves, a free quarterly magazine, news updates and more.
</p>
</div>
</div>
<!-- Right-side Column Content Section -->
       <aside class="col-sm-2" style="padding-top: 20px;
               padding-right: 0px;">
               <?php include('includes/info-col.php'); ?>
        </aside>
</div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
style="padding-bottom:1px; padding-top:8px;
        background-color:#CCFF99;">
        <?php include('includes/footer.php'); ?>
</footer>
</div>
</body>
</html>

Listing 9-10The Code for the Home Page (index.php)

这段代码类似于我们讨论过的其他索引页面。因此,我们在这里没有提供额外的解释。

清单 9-10a 显示了网站的 CSS 样式表。

body {text-align:center; background-color:#CCFF99; color:green;
font-family: "times new roman";
font-size: 120%; margin: auto; }
#container {margin:auto; border:5px black solid; }

header {color:white; background-color:#CCFF99;}
}
label { color: black; }
#submit {margin: 0px; background:#559a55; border: 5px
    outset #559a55; width: 140px;}
#includemenu {padding-top: 10px; padding-bottom: 10px;
    padding-right: 0px;}
#includefooter {background:#68CE53; padding-top: 5px;
    padding-bottom: 5px; margin: 0px;}
#includeheader { height:auto; background:#95b522;
    margin-bottom: 0px; padding:0px;
    background:url('img/header3.jpg');
    background-repeat:no-repeat;}
#contents {background-color:transparent ;margin-top: -7px;
    color: black; margin: 0px; padding: 0px;}
   #buttons {background:#559a55; border: 5px outset #559a55;}

Listing 9-10aThe Code for the Style Sheet (birds.css)

页面的主菜单

主菜单上的按钮将使公众能够查看单个表和连接的表。图 9-10 显示了该菜单。菜单存储在包含文件夹中,清单 9-10b 给出代码。

<div style="padding-top: 10px; padding-bottom: 10px; padding-right: 15px;">
          <nav class="float-left navbar navbar-expand-md navbar-dark">
          <button class="navbar-toggler" type="button"
                  data-toggle="collapse" data-target="#collapsibleMenu1">
                  <span class="navbar-toggler-icon"></span>
          </button>
<div class="btn-group-vertical btn-group-sm collapse navbar-collapse"
          id="collapsibleMenu1"  role="group" aria-label="Button Group">
          <ul class="navbar-nav flex-column" style="width: 140px;">
                   <li class="nav-item">
                             <a class="btn btn-primary" id="buttons"
                             title="Page Two" href="#" role="button">
                             About Us</a>
                   </li>
                   <li class="nav-item">
                             <a class="btn btn-primary" id="buttons"
                             title="The Birds" href="birds.php"
                             role="button">The Birds</a>
                   </li>
                   <li class="nav-item">
                             <a class="btn btn-primary" id="buttons"
                             title="The Reserves" href="reserves.php"
                             role="button">The Reserves</a>
                   </li>
                   <li class="nav-item">
                             <a class="btn btn-primary" id="buttons"
                             title="Page Five" href="join-2.php"
                             role="button">Join 2 Tables</a>
                   </li>
                   <li class="nav-item">
                             <a class="btn btn-primary" id="buttons"
                             title="Page Six" href="join-3.php"
                             role="button">Join 3 Tables</a>
                   </li>
                   <li class="nav-item">
                             <a class="btn btn-primary" id="buttons"
                             title="Return to Home Page" href="index.php"
                             role="button">Home Page</a>
                   </li>
          </div>
    </nav>
</div>

Listing 9-10bThe Main Menu (nav.php)

所有页面的页眉

所有页面的标题都包含两个菜单按钮。你可以在图 9-10 中看到这个标题。

清单 9-10c 给出了标题的代码。

<meta name="viewport" content="width=device-width, initial-scale=1">
       <script src=
       "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
       </script>
       <script src=
"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js">
       </script>
       <script src=
"https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js">
       </script>
<div class="col-sm-8" style="color: white; padding-top: 5%;">
 <div class="h1 display-4 text-left" >The Devon Bird Reserves</div>
</div>
<div class="col-sm-4" style="padding-top: 10px; padding-bottom: 10px;">
     <nav class="float-right navbar navbar-expand-md navbar-dark">
               <button class="navbar-toggler" type="button"
               data-toggle="collapse" data-target="#collapsibleMenu">
                       <span class="navbar-toggler-icon"></span>
               </button>
<div class="btn-group-vertical btn-group-sm collapse navbar-collapse"
        id="collapsibleMenu" role="group" aria-label="Button Group">
        <ul class="navbar-nav flex-column" style="width: 140px;">
               <li class="nav-item">
        <a class="btn btn-primary" id="buttons" href="#"
                          role="button">Login</a>
        </li>
        <li class="nav-item">
                  <a class="btn btn-primary" id="buttons"
                           href="member_reg.php" role="button">Register</a>
        </li>
</ul>
</div>
</nav>
</div>

Listing 9-10cThe Code for the Header (includes/header.php)

现在让我们看一些鸟。

查看鸟类的页面

图 9-11 显示了查看鸟表的显示。

img/314857_2_En_9_Fig11_HTML.jpg

图 9-11

鸟的桌子

清单 9-11 给出了鸟表显示的代码。

<?php
        define('ERROR_LOG','errorlog.log');
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Birds Home Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content=
               "width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
                  href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                  integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                  crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="birds1.css">
</head>
<body>
<div class="container" style="margin-top:30px;border: 3px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
style="margin-bottom:2px; padding:20px;background-color:#CCFF99;">
        <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<!-- Left-side Column Menu Section -->
  <nav class="col-sm-2">
      <ul class="nav nav-pills flex-column">
                  <?php include('includes/nav.php'); ?>
      </ul>
  </nav>
<!-- Center Column Content Section -->
<div class="col-sm-8 row" style="padding-left: 30px;">
           <h2>The Birds that can be seen on our Reserves</h2>
           <?php
           try
           {
           // This script retrieves all the records from the birds table
           require ('mysqli_connect.php'); // Connect to the database
           // Make the query:
           $q = "SELECT bird_name, rarity, best_time FROM birds ORDER BY bird_name ASC";
           $result = mysqli_query ($dbcon, $q); // Run the query
           if ($result) { // If it ran OK, display the records
                     // Table header
                     ?>
                     <table class="table table-striped" style=
                              "background: white;color:black;">
                     <tr>
                              <th scope="col">Birds Name</th>
                              <th scope="col">Rarity</th>
                              <th scope="col">Best Time</th>
                     </tr>
<?php
           // Fetch and print all the records
           while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                    $bird_name = htmlspecialchars($row['bird_name'], ENT_QUOTES);
                    $rarity = htmlspecialchars($row['rarity'], ENT_QUOTES);
                    $best_time = htmlspecialchars($row['best_time'], ENT_QUOTES);
                    echo '<tr>
                             <td scope="row">' . $bird_name . '</td>
                             <td scope="row">' . $rarity . '</td>
                             <td scope="row">' . $best_time . '</td>
                    </tr>';
           }
           echo '</table>'; // Close the table
           mysqli_free_result ($result); // Free up the resources
           } else { // If it did not run OK
                    // Message
                    echo '<p class="text-center">
                    The current birds could not be retrieved. ';
                    echo 'We apologize for any inconvenience.</p>';
                    // Debugging message
                    //echo '<p>' . mysqli_error($dbcon) . '<br><br />Query: ' .
                             $q . '</p>';
           } // End of if ($result)
           mysqli_close($dbcon); // Close the database connection.
}
catch(Exception $e) // We finally handle any problems here
{
           // print "An Exception occurred. Message: " . $e->getMessage();
           print "The system is busy please try later";
           //  $date = date('m.d.y h:i:s');
           //  $errormessage = $e->getMessage();
           //  $eMessage = $date . " | Exception Error | " , $errormessage . |\n";
           //   error_log($eMessage,3,ERROR_LOG);
           // e-mail support person to alert there is a problem
           //  error_log("Date/Time: $date – Exception Error,
           // Check error log for details", 1, noone@helpme.com,
           // "Subject: Exception Error \nFrom: Error Log
           // <errorlog@helpme.com>" . "\r\n");
   }
   catch(Error $e)
   {
           // print "An Error occurred. Message: " . $e->getMessage();
           print "The system is busy please try later";
           // $date = date('m.d.y h:i:s');
           // $errormessage = $e->getMessage();
           // $eMessage = $date . " | Error | " , $errormessage . |\n";
           // error_log($eMessage,3,ERROR_LOG);
           // e-mail support person to alert there is a problem
           //  error_log("Date/Time: $date – Error, Check error log for
           //details", 1, noone@helpme.com, "Subject: Error \nFrom:
           // Error Log <errorlog@helpme.com>" . "\r\n");
   }
?>
</div><!-- End of the view birds page content. -->
<!-- Right-side Column Content Section -->
           <aside class="col-sm-2" style=
                    "padding-top: 20px; padding-right: 0px;">
                    <?php include('includes/info-col.php'); ?>
           </aside>
</div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
           style="padding-bottom:1px;
           padding-top:8px;background-color:#CCFF99;">
           <?php include('includes/footer.php'); ?>
</footer>
</div>
</div>
</body>
</html>

Listing 9-11Creating a Display for the Birds Table (birds.php)

点击主页上的鸟类菜单按钮可以查看此页面。

代码的解释

您已经在前面的章节中看到了所有这些代码。因此,我们在这里不提供任何额外的解释。

我们现在将检查 locations 表,这是本教程的第二个表。可以通过点击菜单按钮 reservations 来查看。

用于查看保护区位置和栖息地的页面

图 9-12 显示了查看保护区位置表的画面。

img/314857_2_En_9_Fig12_HTML.jpg

图 9-12

显示保护区的位置和类型

列表 9-12 给出了显示保护区位置和栖息地的代码。

<?php
    define('ERROR_LOG','errorlog.log');
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Reserves Page</title>
  <meta charset="utf-8">
  <meta name="viewport" content=
            "width=device-width, initial-scale=1, shrink-to-fit=no">
  <!-- Bootstrap CSS File -->
  <link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
            integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
            crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="birds1.css">
</head>
<body>
<div class="container" style="margin-top:30px;border: 3px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
    style="margin-bottom:2px; padding:20px;
            background-color:#CCFF99;">
    <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<!-- Left-side Column Menu Section -->
  <nav class="col-sm-2">
        <ul class="nav nav-pills flex-column">
                  <?php include('includes/nav.php'); ?>
        </ul>
  </nav>
<!-- Center Column Content Section -->
<div class="col-sm-8 row" style="padding-left: 30px;">
<h2>The location and habitat of the Devon Bird Reserves</h2>
<?php
    try {
    // This script retrieves all the records from the users table
              require ('mysqli_connect.php'); // Connect to the database
              // Make the query:
              $q = "SELECT location, location_type FROM location ORDER BY ";
              $q .= "location_id ASC";
              $result = mysqli_query ($dbcon, $q); // Run the query
              if ($result) { // If it ran OK, display the records
              // Table header
    ?>
        <table class="table table-striped"
            style="background: white;color:black;">
            <tr>
                     <th scope="col">Location</th>
                     <th scope="col">Location Type</th>
            </tr>
    <?php
    // Fetch and print all the records
             while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                      $location = htmlspecialchars($row['location'], ENT_QUOTES);
                      $location_type = htmlspecialchars($row['location_type'], ENT_QUOTES);
                      echo '<tr>
                      <td scope="row">' . $location . '</td>
                      <td scope="row">' . $location_type . '</td>
                      </tr>';
             }
             echo '</table>'; // Close the table
             mysqli_free_result ($result); // Free up the resources
    } else { // If it did not run OK
             // Message
             echo '<p class="text-center">
                      The current locations could not be retrieved. ';
             echo 'We apologize for any inconvenience.</p>';
             // Debugging message
             //echo '<p>' . mysqli_error($dbcon) . '<br><br />Query: ' .
                      // $q . '</p>';
    } // End of if ($result)
    mysqli_close($dbcon); // Close the database connection.
}
catch(Exception $e) // We finally handle any problems here
{
    // print "An Exception occurred. Message: " . $e->getMessage();
    print "The system is busy please try later";
    //  $date = date('m.d.y h:i:s');
    //  $errormessage = $e->getMessage();
    //  $eMessage = $date . " | Exception Error | " , $errormessage .
//|\n";
    // error_log($eMessage,3,ERROR_LOG);
    // e-mail support person to alert there is a problem
    // error_log("Date/Time: $date – Exception Error, Check error log for
    //details", 1, noone@helpme.com, "Subject: Exception Error
    //\nFrom: Error Log <errorlog@helpme.com>" . "\r\n");

}
catch(Error $e)
{
    // print "An Error occurred. Message: " . $e->getMessage();
    print "The system is busy please try later";
    // $date = date('m.d.y h:i:s');
    // $errormessage = $e->getMessage();
    // $eMessage = $date . " | Error | " , $errormessage . |\n";
    // error_log($eMessage,3,ERROR_LOG);
    // // e-mail support person to alert there is a problem
    //  error_log("Date/Time: $date – Error, Check error log for
    //details", 1, noone@helpme.com, "Subject: Error \nFrom:
    // Error Log <errorlog@helpme.com>" . "\r\n");
}
?>
</div><!-- End of the view birds page content. -->
<!-- Right-side Column Content Section -->
     <aside class="col-sm-2" style="padding-top: 20px;
              padding-right: 0px;">
     <?php include('includes/info-col.php'); ?>
     </aside>
</div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
    style="padding-bottom:1px; padding-top:8px;
            background-color:#CCFF99;">
            <?php include('includes/footer.php'); ?>
</footer>
</div>
</div>
</body>
</html>

Listing 9-12Creating the Page for Displaying the Locations and Habitats of the Reserves (reserves.php)

我们现在将显示两个连接表的显示。在本章的后面,我们将更深入地讨论如何连接表。

显示连接表中的数据

当这两个表连接在一起时,将显示每个表 birds 和 location 的一些数据,如图 9-13 所示。

img/314857_2_En_9_Fig13_HTML.jpg

图 9-13

显示两个连接的表

清单 9-13 显示了显示从两个连接的表中选择的数据的代码。

<?php
       define('ERROR_LOG','errorlog.log');
?>
 <!DOCTYPE html>
<html lang="en">
<head>
       <title>Two Tables Page</title>
       <meta charset="utf-8">
       <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
       <!-- Bootstrap CSS File -->
       <link rel="stylesheet"
       ref="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
              integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
              crossorigin="anonymous">
       <link rel="stylesheet" type="text/css" href="birds1.css">
</head>
<body>
       <div class="container" style="margin-top:30px;border: 3px black solid;">
       <!-- Header Section -->
       <header class="jumbotron text-center row" id="includeheader"
               style="margin-bottom:2px; padding:20px;background-color:#CCFF99;">
                        <?php include('includes/header.php'); ?>
       </header>
       <!-- Body Section -->
       <div class="content mx-auto" id="contents">
       <div class="row mx-auto" style="padding-left: 0px; height: auto;">
       <!-- Left-side Column Menu Section -->
       <nav class="col-sm-2">
               <ul class="nav nav-pills flex-column">
                       <?php include('includes/nav.php'); ?>
               </ul>
       </nav>
       <!-- Center Column Content Section -->
       <div class="col-sm-8 row" style="padding-left: 30px;">
               <h2>The location and habitat of the Devon Bird Reserves</h2>
       <?php
       try {
       // This script retrieves all the records from the birds table
               require ('mysqli_connect.php'); // Connect to the database
               // Make the query:
               $q = "SELECT location.location, birds.bird_name, birds.rarity, birds.best_time
                       FROM location INNER JOIN birds ON location.bird_id=birds.bird_id";
               $result = mysqli_query ($dbcon, $q); // Run the query
               if ($result) { // If it ran OK, display the records
                       // Table header
                       ?>
                       <table class="table table-striped" style="background: white;color:black;">
                       <tr>
                                 <th scope="col">Location</th>
                                 <th scope="col">Bird Name</th>
                                 <th scope="col">Rarity</th>
                                 <th scope="col">Best Time</th>
                       </tr>
               <?php
               // Fetch and print all the records
               while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                       $location = htmlspecialchars($row['location'], ENT_QUOTES);
                       $bird_name = htmlspecialchars($row['bird_name'], ENT_QUOTES);
                       $rarity = htmlspecialchars($row['rarity'], ENT_QUOTES);
                       $best_time = htmlspecialchars($row['best_time'], ENT_QUOTES);
                       echo '<tr>
                              <td scope="row">' . $location . '</td>
                              <td scope="row">' . $bird_name . '</td>
                              <td scope="row">' . $rarity . '</td>
                              <td scope="row">' . $best_time . '</td>
                       </tr>';
               }
               echo '</table>'; // Close the table
               mysqli_free_result ($result); // Free up the resources
       } else { // If it did not run OK
                // Message
                echo '<p class="text-center">The current birds or locations could not be retrieved. ';
                echo 'We apologize for any inconvenience.</p>';
                // Debugging message
       //echo '<p>' . mysqli_error($dbcon) . '<br><br />Query: ' . $q . '</p>';
       } // End of if ($result)
       mysqli_close($dbcon); // Close the database connection
}
catch(Exception $e) // We finally handle any problems here
{
       // print "An Exception occurred. Message: " . $e->getMessage();
       print "The system is busy please try later";
       //  $date = date('m.d.y h:i:s');
       //  $errormessage = $e->getMessage();
       //  $eMessage = $date . " | Exception Error | " , $errormessage . |\n";
       //   error_log($eMessage,3,ERROR_LOG);
       // e-mail support person to alert there is a problem
       //  error_log("Date/Time: $date – Exception Error, Check error log for
       //details", 1, noone@helpme.com, "Subject: Exception Error \nFrom: Error Log
       // <errorlog@helpme.com>" . "\r\n");
}
catch(Error $e)
{
       // print "An Error occurred. Message: " . $e->getMessage();
       print "The system is busy please try later";
       // $date = date('m.d.y h:i:s');
       // $errormessage = $e->getMessage();
       // $eMessage = $date . " | Error | " , $errormessage . |\n";
       // error_log($eMessage,3,ERROR_LOG);
       // e-mail support person to alert there is a problem
       //  error_log("Date/Time: $date – Error, Check error log for
       //details", 1, noone@helpme.com, "Subject: Error \nFrom:
       // Error Log <errorlog@helpme.com>" . "\r\n");
   }
?>
</div><!-- End of the view birds page content. -->
<!-- Right-side Column Content Section -->
        <aside class="col-sm-2" style="padding-top: 20px; padding-right: 0px;">
                <?php include('includes/info-col.php'); ?>
        </aside>
</div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
        style="padding-bottom:1px; padding-top:8px;background-color:#CCFF99;">
                <?php include('includes/footer.php'); ?>
</footer>
</div>
</div>
</body>
</html>

Listing 9-13Creating the Page for Displaying Selected Data from Two Joined Tables (join-2.php)

请注意,ON 单词后面的项目顺序可以颠倒,您将获得相同的结果。例如,以下内容:

   ON location.bird_id=birds.bird_id)" ;

可以写成如下:

   ON birds.bird_id=location.bird_id";

您可以通过单击“连接两个表”菜单按钮来查看这两个连接的表。您将能够看到该表包含来自两个表的数据,如图 9-13 所示。

SQL ON 关键字通过将相关的 bird_id 字段链接在一起来连接这两个表。让我们花点时间来讨论一下如何以及为什么将表连接在一起。

我们现在将创建一个显示三个虚拟连接表的环境。这些页面可通过主页中的菜单按钮访问。

注意

如前所述,连接表是虚拟表。只有在浏览器中显示后才能看到它们。本教程中的页面专门用于演示连接表的结果。通过单击菜单上的按钮来选择表格显示。真实世界的网站不会有标记为“连接 2 个表”和“连接 3 个表”的按钮。这些标签只是为了您的方便。

创建一个页面来显示三个连接的表

之前我们使用 myPhpAdmin 创建了数据库中三个表的连接关系,如图 9-14 所示。

img/314857_2_En_9_Fig14_HTML.jpg

图 9-14

创建并保存第二个和第三个表之间的关系

我们现在将创建一个页面来选择和显示这三个表中的数据。其原理非常符合逻辑:首先连接两个表以产生一个虚拟表,然后将它连接到第三个表。用于连接和选择三个表中的数据的查询的语法如下:

$q= "SELECT some column, some other column, another column
       FROM table1
               INNER JOIN table2 USING (the key that links table1 and table2)
               INNER JOIN table3 USING (the key that links table2 and table3) ";

让我们从三个连接的表中选择一些数据显示在 web 页面上。

$q = "SELECT bird_name, best_time, location, bird_hides, entrance_member,
        entr_non_member FROM birds
                INNER JOIN location USING (bird_id)
                INNER JOIN reserves_info USING (location_id) ";

执行该 SQL 语句的结果如图 9-15 所示。

img/314857_2_En_9_Fig15_HTML.jpg

图 9-15

浏览器中连接和显示的三个表

显示此表的页面可以通过单击索引页面中的 Join 3 Tables 菜单按钮来查看。

清单 9-15 显示了这个页面的代码。

<?php
        define('ERROR_LOG','errorlog.log');
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Three Tables Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
        href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="birds1.css">
</head>
<body>
<div class="container" style="margin-top:30px;border: 3px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
        style="margin-bottom:2px; padding:20px;background-color:#CCFF99;">
        <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<!-- Left-side Column Menu Section -->
        <nav class="col-sm-2">
               <ul class="nav nav-pills flex-column">
                       <?php include('includes/nav.php'); ?>
               </ul>
        </nav>
<!-- Center Column Content Section -->
<div class="col-sm-8 row" style="padding-left: 30px;">
        <h2>The location and habitat of the Devon Bird Reserves</h2>
<?php
        try {
               require ('mysqli_connect.php'); // Connect to the database
               // Make the query:
               $q = "SELECT bird_name, best_time, location, bird_hides,
                       entrance_member, entr_non_member FROM birds
                       INNER JOIN location USING (bird_id)
                       INNER JOIN reserves_info USING (location_id)";
               $result = mysqli_query ($dbcon, $q); // Run the query
               if ($result) { // If it ran OK, display the records
               // Table header
                       ?>
                       <table class="table table-responsive table-striped"
                               style="background: white;color:black;">
                               <tr>
                                       <th scope="col">Birds Name</th>
                                       <th scope="col">Best Time</th>
                                       <th scope="col">Location</th>
                                       <th scope="col">Bird Hides</th>
                                       <th scope="col">Entrance Member</th>
                                       <th scope="col">Entrance Non-Member</th>
                               </tr>
                       <?php
                       // Fetch and print all the records
                       while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                              $bird_name = htmlspecialchars($row['bird_name'], ENT_QUOTES);
                              $best_time = htmlspecialchars($row['best_time'], ENT_QUOTES);
                              $location = htmlspecialchars($row['location'], ENT_QUOTES);
                              $bird_hides = htmlspecialchars($row['bird_hides'], ENT_QUOTES);
                              $entrance_member = htmlspecialchars($row['entrance_member'], ENT_QUOTES);
                              $entrance_non_member = htmlspecialchars($row['entr_non_member'], ENT_QUOTES);
                              echo '<tr>
                              <td scope="row">' . $bird_name . '</td>
                              <td scope="row">' . $best_time . '</td>
                              <td scope="row">' . $location . '</td>
                              <td scope="row">' . $bird_hides . '</td>
                              <td scope="row">' . $entrance_member . '</td>
                              <td scope="row">' . $entrance_non_member . '</td>
                       </tr>';
                       }
               echo '</table>'; // Close the table
               mysqli_free_result ($result); // Free up the resources
       } else { // If it did not run OK
               // Message
               echo '<p class="error">The current data could not be retrieved. ';
               echo 'We apologize for any inconvenience.</p>';
               // Debugging message
               echo '<p>' . mysqli_error($dbcon) . '<br><br />Query: ' . $q . '</p>';
       } // End of if ($result)
       mysqli_close($dbcon); // Close the database connection
}
catch(Error $e)
{
       // print "An Error occurred. Message: " . $e->getMessage();
       print "The system is busy please try later";
       // $date = date('m.d.y h:i:s');
       // $errormessage = $e->getMessage();
       // $eMessage = $date . " | Error | " , $errormessage . |\n";
       // error_log($eMessage,3,ERROR_LOG);
       // e-mail support person to alert there is a problem
       //  error_log("Date/Time: $date – Error, Check error log for
       //details", 1, noone@helpme.com, "Subject: Error \nFrom: Error Log <errorlog@helpme.com>" .
       //"\r\n");
  }
?>
</div><!-- End of the view birds page content. -->
<!-- Right-side Column Content Section -->
        <aside class="col-sm-2" style="padding-top: 20px; padding-right: 0px;">
                <?php include('includes/info-col.php'); ?>
        </aside>
  </div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
style="padding-bottom:1px; padding-top:8px;background-color:#CCFF99;">
  <?php include('includes/footer.php'); ?>
</footer>
</div>
</div>
</body>
</html>

Listing 9-15Creating the Page for Displaying Three Joined Tables (join-3.php).

代码的解释

本节解释代码。

$q = "SELECT bird_name, best_time, location, bird_hides,
        entrance_member,
        entr_non_member FROM birds
                INNER JOIN location USING (bird_id)
                INNER JOIN reserve_info USING (location_id)";

该代码类似于两个表的代码,只是多了一个 INNER JOIN 语句。

我们从三个连接的表中选择了一些数据(但不是全部)。使用 SELECT 查询从三个表中选择了六个项目。

我们现在将学习如何添加使用支票而不是 PayPal 或借记卡/信用卡支付商品或会员费的替代方法。

支票支付

仍然有顾客喜欢用支票支付,因为他们没有 PayPal 账户,或者他们不喜欢在网上透露他们的借记卡/信用卡信息。支票付款通常需要附有打印的表格,其中包含解释付款原因的信息。该表单通常包含客户的姓名、地址、电子邮件地址、电话号码和其他相关信息,如付款号码。

本教程为需要在线注册的组织使用了简化的可打印表单;该表单需要用户的完整信息,以及支付方式的选择。这对于需要会员注册的网站来说非常理想。

让我们假设德文郡鸟类保护区需要一个在线登记表,如图 9-16 所示。

img/314857_2_En_9_Fig16_HTML.jpg

图 9-16

注册页面

您可以通过单击主页标题上的注册按钮来查看注册页面。

注意

SQL 文件成员已包含在章节文件中。该文件包含为注册页面创建所需表格的代码。在尝试运行以下任何代码之前,必须使用 phpMyAdmin 导入该代码。

注册页面和相关表格与第七章中使用的基本相同。大部分代码来自第七章,嵌入到 birds 模板中,保存为 member_reg.php 。因为代码是相似的,所以这里不包括它,但是包含在章节文件中。

当用户注册成功后,注册按钮会将他们重定向到一个“谢谢”页面,该页面包含支付会员费的替代方法。

支付方式的选择

填写完会员注册表格后,点击注册按钮会将用户带到一个页面,让用户选择三种支付方式,如图 9-17 所示。

img/314857_2_En_9_Fig17_HTML.jpg

图 9-17

为用户提供支付方式的选择

PayPal 徽标的显示特意在页面上复制,以表明您可以选择垂直或水平徽标。为了避免页面混乱,您应该只选择一个。清单 9-17 给出了创建如图 9-17 所示页面的代码。

<?php
        define("ERROR_LOG","errorlog.log");
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Register Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
        href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
        integrity=
"sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
        crossorigin="anonymous">
        <script src="verify.js"></script>
        <script src='https://www.google.com/recaptcha/api.js'></script>
        <link rel="stylesheet" type="text/css" href="birds1.css">
</head>
<body>
        <div class="container" style="margin-top:30px;border: 3px black solid;">
        <!-- Header Section -->
        <header class="jumbotron text-center row" id="includeheader"
                style="margin-bottom:2px; padding:20px;background-color:#CCFF99;">
                <?php include('includes/header.php'); ?>
        </header>
        <!-- Body Section -->
        <div class="content mx-auto" id="contents">
        <div class="row mx-auto" style="padding-left: 0px; height: auto;">
        <!-- Left-side Column Menu Section -->
                 <nav class="col-sm-2">
                        <ul class="nav nav-pills flex-column">
                                <?php include('includes/nav.php'); ?>
                        </ul>
                 </nav>
        <!-- Center Column Content Section -->
        <div class="col-sm-8">
        <h3 class="h2 text-center" >Thank you for registering</h2>
        <h6 class="text-center">
        To confirm your registration please verify membership class and
        pay the membership fee now.</h6>
        <h6 class="text-center">You can use PayPal, a check or a credit/debit card.</h6>
        <p class="text-center" >When you have completed your registration you will be
        able to login to the member's only pages.</p>
<?php
try {
        require ("mysqli_connect.php");
        $query = "SELECT * FROM prices";
        $result = mysqli_query ($dbcon, $query); // Run the query.
        if ($result) { // If it ran OK, display the records.
                $row = mysqli_fetch_array($result, MYSQLI_NUM);
                $yearsarray = array(
        "Standard one year:", "Standard five year:", "Military one year:", "Under 21 one year:",
        "Other - Give what you can. Maybe:" );
               echo '<h6 class="text-center text-danger">Membership classes:</h6>' ;
               echo '<h6 class="text-center text-danger small"> ';
               for ($j = 0, $i = 0; $j < 5; $j++, $i = $i + 2) {
                       echo $yearsarray[$j] . " &pound; " .
                       htmlspecialchars($row[$i], ENT_QUOTES)  .
                       " GB, &dollar; " .
                       htmlspecialchars($row[$i + 1], ENT_QUOTES) .
                       " US";
               if ($j != 4) {
                       if ($j % 2 == 0) { echo "</h6><h6 class='text-center text-danger small'>"; }
                       else { echo " , "; }
               }
        }
        echo "</h6>";
}
?>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
        <input type="hidden" name="cmd" value="_s-xclick">
        <input type="hidden" name="hosted_button_id" value="XXXXXXXXXXXXX">
        <div class="form-group row">
        <label for="level" class="col-sm-4 col-form-label text-right">*Membership Class</label>
        <div class="col-sm-8">
                <select id="level" name="level" class="form-control" required>
                <option value="0" >-Select-</option>
        <?php
                $class = htmlspecialchars($_GET['class'], ENT_QUOTES);
                for ($j = 0, $i = 0; $j < 5; $j++, $i = $i + 2) {
                        echo '<option value="' .
                        htmlspecialchars($row[$i], ENT_QUOTES) . '" ';
                        if ((isset($class)) && ( $class == $row[$i]))
                        {
                               echo ' selected ';
                        }
                echo ">" . $yearsarray[$j] . " " .
                htmlspecialchars($row[$i], ENT_QUOTES) .
                " &pound; GB, " .
                htmlspecialchars($row[$i + 1], ENT_QUOTES) .
                "&dollar; US</option>";
                }
        ?>
        </select>
</div>
</div>
<div class="form-group row">
<div class="col-sm-6 col-form-label">
        <nav class="float-right navbar navbar-expand-md navbar-dark">
                <button class="navbar-toggler" type="button" data-toggle="collapse"
                        data-target="#collapsibleMenu">
                        <span class="navbar-toggler-icon"></span>
                </button>
<div class="btn-group-vertical btn-group-sm collapse navbar-collapse" id="collapsibleMenu"
        role="group" aria-label="Button Group">
                <ul class="navbar-nav flex-column" style="width: 140px;">
                       <li class="nav-item">
                               <a class="btn btn-primary" id="buttons"
                               href="pay-with-check.php" role="button">Pay By Check</a>
                       </li>
                </ul>
</div>
</nav>
</div>
<div class="col-sm-6">
<!-- Replace the code below with code provided by PayPal once you obtain a Merchant ID -->
        <input type="hidden" name="currency_code" value="GBP">
                <input style="margin:10px 0 0 40px" type="image"
                src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif"
                name="submit" alt="PayPal  The safer, easier way to pay online.">
        <img alt="" src=
                "https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
<!-- Replace code above with PayPal provided code -->
</div>
</div>
</form>
</div>
<!-- Right-side Column Content Section -->
        <aside class="col-sm-2">
               <?php include('includes/info-col-cards.php'); ?>
        </aside>
</div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
        style="padding-bottom:1px; padding-top:8px;background-color:#CCFF99;">
        <?php include('includes/footer.php'); ?>
</footer>
<?php
} // end try
catch(Exception $e) // We finally handle any problems here
{
        // print "An Exception occurred. Message: " . $e->getMessage();
        print "The system is busy please try later";
        //  $date = date('m.d.y h:i:s');
        //  $errormessage = $e->getMessage();
        //  $eMessage = $date . " | Exception Error | " , $errormessage . |\n";
        //   error_log($eMessage,3,ERROR_LOG);
        // e-mail support person to alert there is a problem
        //  error_log("Date/Time: $date – Exception Error, Check error log for
        //details", 1, noone@helpme.com, "Subject: Exception Error \nFrom: Error Log
                <errorlog@helpme.com>" . "\r\n");
}
catch(Error $e)
{
        // print "An Error occurred. Message: " . $e->getMessage();
        print "The system is busy please try later";
        // $date = date('m.d.y h:i:s');
        // $errormessage = $e->getMessage();
        // $eMessage = $date . " | Error | " , $errormessage . |\n";
        // error_log($eMessage,3,ERROR_LOG);
        // e-mail support person to alert there is a problem
        //  error_log("Date/Time: $date – Error, Check error log for
        //details", 1, noone@helpme.com, "Subject: Error \nFrom: Error Log
        // <errorlog@helpme.com>" . "\r\n");
   }
?>
</body>
</html>

Listing 9-17Creating a Page for Alternative Methods of Payment (register-thanks.php)

当点击 PayPal Pay Now 按钮时,用户会被带到通常的 PayPal 页面进行支付。或者,用户现在可以单击“用支票支付”按钮,填写并打印一个表格,与他们的支票一起发送。这段代码类似于第七章中的 register_thanks 程序。

支票付款

当用户点击 Pay By Check 按钮时,他们将被带到一个包含可打印表格的页面,如图 9-18 所示。

img/314857_2_En_9_Fig18_HTML.jpg

图 9-18

可打印的表格可以在屏幕上填写,除了签名和日期(pay-with-check.php)

清单 9-18 给出了创建可打印表单的代码。

该表格设计为在屏幕上填写,然后打印。

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Register Page</title>
  <meta charset="utf-8">
  <meta name="viewport" content=
            "width=device-width, initial-scale=1, shrink-to-fit=no">
  <!-- Bootstrap CSS File -->
  <link rel="stylesheet"
  href=
"https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
  integrity=
"sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
  crossorigin="anonymous">
<script src="verify.js"></script>
<script src='https://www.google.com/recaptcha/api.js'></script>

<link rel="stylesheet" type="text/css" href="birds1.css" media="screen">
<link rel="stylesheet" type="text/css" href="print.css" media="print">

<style type="text/css">
    label { margin-bottom:5px; }
    label { width:570px; float:left; text-align:right; }
    .sign { font-weight:bold;}
</style>
</head>
<body>
<div class="container" style="margin-top:30px;border: 3px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
    style="margin-bottom:2px; padding:20px;background-color:#CCFF99;">
            <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<!-- Left-side Column Menu Section -->
     <nav class="col-sm-2">
     <ul class="nav nav-pills flex-column">
                      <?php include('includes/nav.php'); ?>
     </ul>
     </nav>
<!-- Center Column Content Section -->
<div class="col-sm-8">
     <h4>Complete your Registration by Paying with a Check</h4>
     <p>Thank you for registering online, now please fill out this
     form. Asterisks indicate essential fields. When you
     have filled out the form please print two copies by clicking
     the "Print This Form" button. Sign one copy and keep one for
     reference sign a check payable to &quot;The Devon Bird
     Reserves&quot;. </p><p>Mail the signed form and check to:
     <br>The Treasurer, The Devon Bird Reserves, 99 The Street,
     The Village, EX99 99ZZ </p>
<form>
<div id="fields">
     <label class="label" for="title">Title<span
              class="large-red">*</span>
     <input id="title" name="title" size="35" type="text" required>
     </label>
     <br><br><label class="label" for="firstname">First Name
<span>*</span>
     <input id="firstname" name="firstname" size="35" type="text"
              required></label><br>
<br><label class="label" for="lastname">Last Name
<span>*</span>
<input id="lastname" name="lastname" size="35" type="text"
       required></label><br>
<br><label class="label" for="useremail">Your Email Address
<span>*</span>
<input id="useremail" name="useremail" type="email" size="35"
       required></label><br>
</div>
</form>
<br><br>
<p class="sign">
 Signed___________________________________________&nbsp;Date_________________
</p>
<br>
<div id="button">
     <input type="button" value=
     "Click to automatically print the form in black and white"
               onclick="window.print()" title="Print this Form"><br>
</div>
<!--End of content.-->
</div>
<!-- Right-side Column Content Section -->
     <aside class="col-sm-2">
     <?php include('includes/info-col-cards.php'); ?>
     </aside>
</div>
<!-- Footer Content Section -->
<footer class="jumbotron text-center row"
    style="padding-bottom:1px; padding-top:8px;
            background-color:#CCFF99;">
            <?php include('includes/footer.php'); ?>
</footer>
</div>
</div>
</body>
</html>

Listing 9-18Creating the Printable Form

(pay-with-check.php)

代码的解释

本节解释代码。

<link rel="stylesheet" type="text/css" href="birds.css" media="screen">
<link rel="stylesheet" type="text/css" href="print.css" media="print">

使用 PHP 打印表单是不可能的,因为 PHP 是一个服务器端脚本。但是,表单是由浏览器显示的,我们可以从浏览器显示的屏幕打印。我们通过使用媒体属性 media="print "链接到一个单独的条件样式表来实现这一点。

第一行链接到主样式表 birds.css ,它使用媒体属性 media="screen "在屏幕上显示页面。第二行将页面链接到页面的打印版本。当显示内容发送到打印机或打印预览时,会自动调用此功能。打印的表单不需要页眉、菜单或页脚。此外,使用 CSS 样式表,我们可以使它只使用黑色墨水打印,这样用户就不必使用更昂贵的彩色墨盒。

<div id="button">
         <input type="button" value=
                  "Click to automatically print the form in black and white"
                  onclick="window.print()" title="Print this Form"><br>
</div>

这是页面上用于将浏览器显示设置为打印机的按钮的代码。

打印在线表格

图 9-19 显示打印页面。

img/314857_2_En_9_Fig19_HTML.jpg

图 9-19

用黑色墨水打印的页面的上半部分包含了所有重要的信息

为了生成图 9-19 所示的打印输出,在用户屏幕上填写表格,然后点击打印按钮。结果使用了最少的墨水并且没有彩色墨水;然而,它包含了成为德文郡鸟类保护区成员的所有必要条件。用户在表单上签名,然后将它和支票一起寄出。当用户填写注册页面时,他们的地址被输入数据库;因此,这不需要在印刷表格中重复。

样式表 print.css 是生成可打印表单的关键。清单 9-19 显示了这个样式表的代码。

/*PRINT.CSS: style amendments for printing only*/
/*SELECT ITEMS THAT YOU DO NOT WANT TO PRINT, e.g.,
header, menu, print-this-page button, and footer*/
#header, #nav, #leftcol, #button, #rightcol, #footer,
#info-col, ul { display:none; }
input { border:1px black solid; }
h2 { font-size:16pt; color:black; text-align:center; }
h3 { text-align:center; font-size:11pt;}
/*REVEAL OUTGOING URL links on printed page*/
a[href^="http://":after {content: "(" attr(href)")"; }

Listing 9-19Creating the Style Sheet for Printing Forms

(print.css)

CSS 语句{ display:none;}告诉打印机哪些项目不应该打印。为了避免在测试打印页面的外观时浪费纸张和墨水,请使用浏览器的打印预览功能。将页面加载到浏览器中,选择文件,然后选择打印预览,查看可打印页面的外观。如果可打印页面包含分页符,请单击打印预览屏幕的向右箭头查看后续页面。

按 Esc 键退出打印预览模式。

h2 { font-size:16pt; text-align:center; }
h3 { text-align:center; font-size:11pt;}

要为打印机选择正确的字体大小,请使用磅值(如 16 磅。和 12 磅。)并使用试错法来优化尺寸。你可能有文字在里面

tags, so be sure to include a style for the paragraph font size.

/*REVEAL OUTGOING URL links on the printed page*/
a[href^="http://]:after {content: "(" attr(href)")"; }

如果页面包含您的网站的 URL,您可能希望它以对用户有用的格式出现在打印的页面上(假设他们打印并保留了表单的副本)。注意三种类型的括号的使用。在表单中,HTML 看起来像这样:

<p>Click for
<a title="Click to visit the Devon Bird Reserves web site"
href="http://www.the devonbirdreserves.co.uk">The Devon Bird Reserves</a></p>

该 URL 将在浏览器中显示如下:

点击访问德文郡鸟类保护区网站。

使用前面的代码,打印的表单将如下所示:

点击访问德文郡鸟类保护区网站( www.devonbirdreserves.co.uk )。

摘要

在本章中,我们介绍了使用多个表的理论和实践。您了解了这种表是虚拟表,只存在于服务器的易失性内存中,可以在 MySQL 或 MariaDB 等 DBMS 中查看。描述了各种连接方法之间的差异。然后,我们演示了通过使用 SQL 查询和 PHP 可以使虚拟表在 web 页面中可见。一个教程向您展示了如何通过支票实现会员付费。除此之外,还演示了经济的表格打印,以便向该组织发送申请表和支票。在下一章,我们将向你介绍一个在线留言板。

十、创建一个留言板

留言板可以是一个独立的功能,也可以是论坛中的一个重要组件。一个基本论坛至少有四个表,分别用于消息、会员注册、主题和回复。然而,为了节省空间并遵从本书的副标题简化的方法,本章描述了一个简单的留言板,其中有一个消息表和一个成员表。我们希望对这个留言板的原则的理解能启发你扩展它的功能并探索更复杂的解决方案。为了让你感兴趣,在本章的最后,我们添加了一个图表,展示了如何增强留言板来创建一个论坛。

留言板的功能比论坛少;一般来说,它们缺乏以允许它们作为线索被收集的方式接受回复的能力。在论坛中,回复与原始发帖 ID 相关联,并按日期升序显示。我们的留言板旨在收集明智和滑稽的报价,然后将它们插入一个可搜索的数据库。

完成本章后,您将能够

  • 创建一个带有数据库和表格的留言板

  • 创建注册页面

  • 创建登录和注销页面

  • 创建留言板类别的网关

  • 创建页面以显示报价

  • 创建搜索工具

警告

为了防止不愉快内容的显示,留言板需要持续的监控(调节)。在你的潜在客户承诺与你签订设计合同之前,应该提醒他们这一点。2018 年,美国实施了将公共留言板和其他公共论坛的内容责任置于论坛提供商的法律。这与以前的强制措施相反,以前的强制措施解除了论坛提供商对公共内容的责任。

计划

为了简化本章中的留言板,用户只有在注册并登录后才能查看消息。然而,一些信息会显示在主页上,以吸引用户注册。在我们的例子中,消息是报价,目的是建立一个有用的报价数据库。主页上的登录按钮会将注册用户重定向到一个页面,在那里他们可以选择查看哪种类型的报价,滑稽报价或明智报价。

当访问留言板时,注册会员将能够提供报价。因为该成员提供了报价,所以我们在教程中将线程称为报价。为了进一步简化,表中的列数被减少到实际的最小值。

用于登录的用户名将是用户选择的唯一的假名,因为留言板和论坛应该保护用户的个人信息。当会员发布新报价时,他们的假名是留言板上显示的唯一名称。但是,在注册时,他们可能还会被要求提供其他信息,例如他们的电子邮件地址,以便站点管理员在必要时可以与他们联系。他们的电子邮件地址从未在留言板上公开过。

我们现在将为留言板创建数据库和表格。

创建数据库

从本书的页面下载本章的文件。并将它们放在一个名为 msgboard 的新文件夹中,该文件夹位于 htdocseds-www 文件夹中。

启动 XAMPP 或 EasyPHP,在 phpMyAdmin 中创建名为 msgboarddb 的数据库。将编码设置为 utf8_general_ci。向下滚动并单击添加新用户。然后选择 Databases 选项卡,选择 msgboarddb 旁边的框,并单击 privileges。添加具有以下详细信息的新用户:

  • 用户名:布鲁内尔

  • 主机:本地主机

  • 密码:介于 1lblac 3r 之间

向下滚动到全局权限并选中全部选中框。单击保存(或在某些版本中单击继续)。

数据库连接文件 mysqli_connect.php 包含在可下载文件中。一定要把它添加到你的 htdocseds-www 文件夹中。如果要手动创建文件,请使用以下代码:

<?php
// Create a connection to the msgboarddb database and to MySQL
// Set the encoding to utf-8
// Set the database access details as constants
define ('DB_USER', 'brunel');
define ('DB_PASSWORD', 'tra1lblaz3r');
define ('DB_HOST', 'localhost');
define ('DB_NAME', 'msgboarddb');
// Make the connection:
$dbcon = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Set the encoding...optional but recommended
mysqli_set_charset($dbcon, 'utf8');

创建表

使用可下载的导入表格。sql 文件或手动创建它们。

如果您想从头开始创建表,在 phpMyAdmin 的左侧面板中,单击单词 msgboarddb 。然后创建第一个包含六列的表,并将表成员命名为。

使用表 10-1 中的属性,并为将接受排序规则的列选择排序规则 utf8 _ general _ ci(reg _ date 和 member_level 没有排序规则)。创建列时,将出现 member_id 和 user_name 索引的弹出对话框。对于 member_id 弹出窗口,这两个字段都将是主字段。在用户名索引弹出窗口中,在第一个字段中输入用户名,在第二个字段中输入唯一用户名

表 10-1

成员表

|

列名

|

类型

|

长度/值

|

默认

|

属性

|

|

索引

|   |

A_I

| | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 成员 id | (同 Internationalorganizations)国际组织 | eight | 没有人 | 无符号的 | -是吗 | 主要的 |   | ·······················。 | | 用户名 | 可变长字符串 | Twelve | 没有人 |   | -是吗 | 独一无二的 |   | -是吗 | | 电子邮件 | 可变长字符串 | Sixty | 没有人 |   | -是吗 |   |   | -是吗 | | 密码 | 茶 | Sixty | 没有人 |   | -是吗 |   |   | -是吗 | | reg_date | DATETIME |   | 没有人 |   | -是吗 |   |   | -是吗 | | 成员级别 | 蒂尼因特 | Two | 没有人 |   | -是吗 |   |   | -是吗 |

member_id 列是主键,user_name 列有一个唯一的索引以防止重复条目。向下滚动并单击保存。

创建第二个表

您可以从可下载的 SQL 文件中导入论坛表,或者手动创建包含五列的论坛表。它包含一个名为 post_id 的列,该列被配置为主键。我们的项目将使用户能够从引文中搜索短语或单词;因此,提供了全文搜索。给消息列一个全文索引。

表 10-2 显示了表的细节。

表 10-2

论坛表的属性

|

列名

|

类型

|

长度/值

|

默认

|

属性

|

|

索引

|   |

A_I

| | --- | --- | --- | --- | --- | --- | --- | --- | --- | | post_id | (同 Internationalorganizations)国际组织 | eight | 没有人 | 无符号的 | -是吗 | 主要的 |   | ·······················。 | | 用户名 | 可变长字符串 | Twelve | 没有人 |   | -是吗 |   |   | -是吗 | | 科目 | 可变长字符串 | Sixty | 没有人 |   | -是吗 |   |   | -是吗 | | 消息 | 文本 |   | 没有人 |   | -是吗 | 全面测试 |   | -是吗 | | 发布日期 | DATETIME |   | 没有人 |   | -是吗 |   |   | -是吗 |

当您在论坛表中创建 post_id 列时,您将看到一个弹出对话框。对于 post_id 列,两个字段都应该包含单词 PRIMARY 。单击开始。当你在论坛表中创建消息栏时,你会看到如图 10-1 所示的弹出对话框。

img/314857_2_En_10_Fig1_HTML.jpg

图 10-1

添加索引对话框

接下来,我们将检查网站的一些页面。

为留言板创建主页

主页上显示了一些例子来鼓励人们注册。注册并登录后,他们将能够查看更多报价,还可以向收藏中添加报价。如果您喜欢从头开始创建表格,则在填充消息表格之前,主页上不会显示报价(消息)。

图 10-2 显示了填充表格后的主页。

img/314857_2_En_10_Fig2_HTML.jpg

图 10-2

表格被填充,因此主页显示四个引号

清单 10-2a 显示了生成主页的代码。

<?php // Start the session.
session_start() ;
     if ( isset( $_SESSION[ 'member_id' ] ) )
                 { $menu = 1;}
     else { $menu = 5; }
?>
<!DOCTYPE html>
<html lang="en">
<head>
     <title>Message Board Home Page</title>
     <meta charset="utf-8">
     <meta name="viewport" content=
                 "width=device-width, initial-scale=1, shrink-to-fit=no">
     <!-- Bootstrap CSS File -->
     <link rel="stylesheet"
                 href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                 integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                 crossorigin="anonymous">
     <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
     <div class="container"
              style="margin-top:30px;border: 2px black solid;">
     <!-- Header Section -->
     <header class="jumbotron text-center row" id="includeheader"
         style="margin-bottom:2px;
         background:linear-gradient(#0073e6, white); padding:10px;">
             <?php include('includes/header.php'); ?>
     </header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<div class="col-sm-12">
     <h4 class="text-center">
         This home page shows a selection from our large collection
             of quotations.</h4>
         <h4 class="text-center">To view the whole collection,
             please register. </h4>
         <h5 class="text-center">You will then be able to contribute to
             this message board by adding quotations.</h5>
     <?php
     // Connect to the database
     require ( 'mysqli_connect.php' ) ;
     // Make the query
     $query =
     "SELECT user_name,post_date, subject, message FROM forum LIMIT 4" ;
     $result = mysqli_query( $dbcon, $query ) ;
     if ( mysqli_num_rows( $result ) > 0 )
     {
             ?>
             <table class="table table-responsive table-striped col-sm-12"
             style="background: white;color:black; padding-left: 80px;">
                    <tr>
                                 <th scope="col">Posted By</th>
                                 <th scope="col">Subject</th>
                                 <th scope="col">Message</th>
                    </tr>
             <?php
             while ( $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ))
             {
                    $user_name =
                    htmlspecialchars($row['user_name'], ENT_QUOTES);
                    $post_date =
                    htmlspecialchars($row['post_date'], ENT_QUOTES);
                    $message =
                    htmlspecialchars($row['message'], ENT_QUOTES);
                    echo '<tr>
                                 <td scope="row">' . $user_name . '</td>
                                 <td scope="row">' . $post_date . '</td>
                                 <td scope="row">' . $message . '</td>
                    </tr>';
             }
             echo '</table>' ;
     }
     else { echo '<p class="text-center">
               There are currently no messages.</p>' ; }
     mysqli_close( $dbcon ) ;
?>
</div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
     style="padding-bottom:1px; margin: 0px; padding-top:8px;
             background-color:white;">
     <div class="col-sm-12 text-center">
             <?php include('includes/footer.php'); ?>
  </div>
</footer>
</div>
</div>
</body>
</html>

Listing 10-2aCreating the Home Page for the Forums Website (index.php)

标题使用了一个 case 语句,其中包含了本章所要求的每个水平菜单按钮,但是不同的按钮将被禁用以适应每个页面。

清单 10-2b 给出了索引页面的主页标题代码段的代码。

<meta name="viewport" content="width=device-width, initial-scale=1">
<script src=
"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>
<script src=
"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js">
    </script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js">
    </script>
<div class="col-sm-8">
    <h1 class="mb-4 font-bold float-left" style="color:white">
             <?php
             if (!empty($_GET['name'])) {
                        $name =
                        filter_var( $_GET['name'], FILTER_SANITIZE_STRING);
                        echo $name;
             }
             else { echo "Quick Quotes"; }
             ?>
    </h1>
</div>
    <nav class="float-left navbar navbar-expand-xl navbar-trans navbar-light">
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleMenu">
    <span class="navbar-toggler-icon"></span>
  </button>
      <div class="btn-group btn-group-md collapse navbar-collapse navbar" id="collapsibleMenu"  role="group" aria-label="Button Group">   <?php
              switch ($menu) {
                      case 1: //index.php
                      ?>
                               <button type="button" style="width: 110px;"
                               class="btn btn-secondary bg-primary disabled"
                               onclick="location.href = "">Home Page
                               </button>

                               <button type="button" style="width: 110px;"
                               class="btn btn-secondary bg-primary disabled"
                               onclick="location.href = "" >Login
                               </button>

                               <button type="button" style="width: 110px;"
                               class="btn btn-secondary bg-primary"
                               onclick="location.href =
                               'logout.php?name=Logout'">Logout
                               </button>

                               <button type="button" style="width: 110px;"
                               class="btn btn-secondary bg-primary disabled"
                               onclick="location.href = "" >Register
                               </button>

                               <button type="button" style="width: 120px;"
                               class="btn btn-secondary bg-primary"
                               onclick="location.href =
                               'view_posts.php?name=Your Quotes'" >
                               Your Quotes
                               </button>

                               <button type="button" style="width: 120px;"
                               class="btn btn-secondary bg-primary"
                               onclick="location.href =
                               'post.php?name=Add A Quote'">Add A Quote
                               </button>

                               <button type="button" style="width: 120px;"
                               class="btn btn-secondary bg-primary"
                               onclick="location.href =
                               'forum_c.php?name=Comic Quotes'" >
                               Comic Quotes
                               </button>

                               <button type="button" style="width: 120px;"
                               class="btn btn-secondary bg-primary"
                               onclick="location.href =
                               'forum_w.php?name=Wise Quotes'">
                               Wise Quotes
                               </button>

                               <button type="button" style="width: 120px;" class=
                               "btn btn-secondary bg-primary"
                               onclick="location.href =
                               'search.php?name=Search Quotes'" >
                               Search Quotes
                               </button>
              <?php
              break;

Listing 10-2bCreating the Header for the Home Page (includes/header.php)

标题使用一个水平菜单,在页面上为成员的发帖和回复提供最大的空间。清单 10-2b 中显示的代码段包括引导代码,用于在较小的设备(手机)中将菜单更改为“煎饼菜单”。case 语句的第一段(case 1)演示了用户登录时索引页面菜单的状态。除了“登录”和“注册”按钮之外,所有按钮都已启用。如果用户未登录,不同的按钮块(情况 5,未显示)将仅显示登录和注册按钮为活动状态(如图 10-2 所示)。

<?php // Start the session.
session_start() ;
     if ( isset( $_SESSION[ 'member_id' ] ) )
                 { $menu = 1;}
     else { $menu = 5; }
?>

索引页面代码的顶部(清单 10-2a )包含了前一段。该段通过搜索 member_id 值来确定显示哪个菜单。如果存在,则用户已经登录。变量menu设置为1,这将激活除登录和注册之外的所有按钮。如果memberid值不存在,则用户尚未登录。变量menu 设置为 1,这将激活除登录和注册之外的所有按钮。如果 member_id 值不存在,则用户尚未登录。变量menu 设置为 5。案例 5 的菜单块(在 header.php 文件的中)仅激活登录和注册按钮。

注意

目前,很少有按钮工作,因为我们还没有创建其他页面。这将在我们创建一些数据后得到纠正。

下一步将是创建注册页面,以便我们可以注册一些成员数据。

创建注册表单

登记表是第七章中表格的简化版。形式如图 10-3 所示。

img/314857_2_En_10_Fig3_HTML.jpg

图 10-3

注册页面

如前所述,用户名不是成员的真实姓名,而是匿名登录网站的假名。

清单 10-3a 显示了注册表单的代码,并将一条记录插入到成员表中,清单 10-3b 给出了 PHP 代码。

<?php
$menu = 2;
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
//require("cap.php");
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Register Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content=
"width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
href=
"https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity=
"sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
   <script src="verify.js"></script>
   <script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<div class="container" style="margin-top:30px;border: 2px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
style="margin-bottom:2px;
background:linear-gradient(#0073e6, white); padding:10px;
padding-right: 5px;">
                <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<div class="col-sm-12">
<h4 class="text-center">Registration</h4>
<h4 class="text-center">Items marked with an asterisk *
are required</h4>
<h6 class="text-center"><strong>IMPORTANT:</strong> Do NOT
use your real name for the username.</h6>
<h6 class="text-center"><strong>Terms and conditions:</strong>
Your registration and all your messages
will be immediately deleted </h6>
<h6 class="text-center">if you post unpleasant, obscene or
defamatory messages to the message board.</h6>
<?php
try {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
                require('process-register-page.php');
} // End of the main Submit conditional.
?>
<div class="col-sm-10">
<form action="safer-register-page.php" method="post"
onsubmit="return checked();" name="regform" id="regform">
<div class="form-group row">
   <label for="user_name" class="col-sm-4 col-form-label text-right">
User Name*:</label>
    <div class="col-sm-8">
<input type="text" class="form-control" id="user_name"
        name="user_name"
                        pattern="[a-zA-Z][a-zA-Z0-9\s]*" title=
"Alphabetic, numeric and space only max of 30 characters"
                        placeholder="User Name" maxlength="30" required
                        value=
                                "<?php if (isset($_POST['user_name']))
                        echo htmlspecialchars($_POST['user_name'], ENT_QUOTES);
                        ?>" >
    </div>
</div>
<div class="form-group row">
<label for="email" class="col-sm-4 col-form-label text-right">
E-mail*:</label>
<div class="col-sm-8">
        <input type="email" class="form-control" id="email"
name="email" placeholder="E-mail" maxlength="60"
required
                        value=
                                "<?php if (isset($_POST['email']))
                        echo htmlspecialchars($_POST['email'], ENT_QUOTES);
?>" >
    </div>
</div>
<div class="form-group row">
<label for="password1" class="col-sm-4 col-form-label
text-right">Password*:</label>
<div class="col-sm-8">
      <input type="password" class="form-control" id="password1"
                        name="password1"
                        pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,12}"
                        title=
"One number, one upper, one lower, one special, with 8 to 12 characters"
                placeholder="Password" minlength="8" maxlength="12" required
                        value=
                            "<?php if (isset($_POST['password1']))
                echo htmlspecialchars($_POST['password1'], ENT_QUOTES); ?>" >
                        <span id="message">Between 8 and 12 characters.</span>
    </div>
</div>
<div class="form-group row">
<label for="password2" class="col-sm-4 col-form-label text-right">
Confirm Password*:</label>
<div class="col-sm-8">
      <input type="password" class="form-control" id="password2"
        name="password2"
              pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,12}"
                        title=
"One number, one uppercase, one lowercase letter, with 8 to 12 characters"
                        placeholder=
"Confirm Password" minlength="8" maxlength="12" required
                        value=
                                "<?php if (isset($_POST['password2']))
                echo htmlspecialchars($_POST['password2'], ENT_QUOTES); ?>" >
    </div>
</div>
<div class="form-group row">
<label for="question" class="col-sm-4 col-form-label text-right">
          Secret Question*:</label>
<div class="col-sm-8">
          <select id="question" class="form-control">
                        <option selected value="">- Select -</option>
<option value="Maiden">Mother's Maiden Name</option>
                        <option value="Pet">Pet's Name</option>
                        <option value="School">High School</option>
                        <option value="Vacation">Favorite Vacation Spot</option>
                </select>
        </div>
</div>
<div class="form-group row">
<label for="secret" class="col-sm-4 col-form-label
text-right">Answer*:</label>
<div class="col-sm-8">
      <input type="text" class="form-control" id="secret" name="secret"
                pattern="[a-zA-Z][a-zA-Z\s\.\,\-]*"
                title="Alphabetic, period, comma, dash and space only max of 30
                        characters"
                placeholder="Secret Answer" maxlength="30" required
                value=
                        "<?php if (isset($_POST['secret']))
                        echo htmlspecialchars($_POST['secret'], ENT_QUOTES); ?>" >
  </div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label"></label>
<div class="col-sm-8" style="padding-left: 80px;">
<div class="float-left g-recaptcha"
data-sitekey=
"6LcrQ1wUAAAAAPxlrAkLuPdpY5qwS9rXF1j46fhq"></div>
</div>
</div>
<div class="form-group row">
<label for="" class="col-sm-3 col-form-label"></label>
<div class="col-sm-8 text-center">
        <input id="submit" class="btn btn-primary" type="submit" name="submit"
        value="Register">
</div>
</div>
</form>
</div>
</div>
</div>
<!-- Footer Section -->
<footer class="jumbotron row mx-auto" id="includefooter"
style="padding-bottom:1px; margin: 0px; padding-top:8px;
padding-left: 0px; background-color:white;">
<div class="col-sm-12 text-center">
                <?php include('includes/footer.php'); ?>
  </div>
</footer>
</div>
</div>
<?php
}
catch(Exception $e) // We finally handle any problems here
 {
// print "An Exception occurred. Message: " . $e->getMessage();
        print "The system is busy please try later";
        //  $date = date('m.d.y h:i:s');
        //  $errormessage = $e->getMessage();
        //  $eMessage = $date . " | Exception Error | " , $errormessage . |\n";
        //   error_log($eMessage,3,ERROR_LOG);
// e-mail support person to alert there is a problem
        //  error_log("Date/Time: $date – Exception Error, Check error log for
//details", 1, noone@helpme.com, "Subject: Exception Error \nFrom:
// Error Log <errorlog@helpme.com>" . "\r\n");
 }
catch(Error $e)
 {
   // print "An Error occurred. Message: " . $e->getMessage();
   print "The system is busy please try later";
   // $date = date('m.d.y h:i:s');
   // $errormessage = $e->getMessage();
   // $eMessage = $date . " | Error | " , $errormessage . |\n";
   // error_log($eMessage,3,ERROR_LOG);
   // e-mail support person to alert there is a problem
        //  error_log("Date/Time: $date – Error, Check error log for
//details", 1, noone@helpme.com, "Subject: Error \nFrom: Error Log
// <errorlog@helpme.com>" . "\r\n");
 }
 ?>
</body>
</html>

Listing 10-3aCreating the Registration Page (safer-register-page.php)

<?php
define("ERROR_LOG","errors.log");
// Has the form been submitted?
try {
require ('mysqli_connect.php'); // Connect to the database
$errors = array(); // Initialize an error array.
// --------------------check the entries-------------
// Trim the first name
        $user_name = filter_var( $_POST['user_name'], FILTER_SANITIZE_STRING);
if ((!empty($user_name)) && (preg_match('/[a-z0-9\s]/i',$user_name)) &&
                (strlen($user_name) <= 30)) {
                //Save the trimmed first name
        $user_nametrim = $user_name;
        }else{
                $errors[] =
'First name missing or not alphabetic, numeric and space characters.
        Max 30';
        }
// Check that an email address has been entered
        $emailtrim = filter_var( $_POST['email'], FILTER_SANITIZE_EMAIL);
        if  ((empty($emailtrim)) ||
(!filter_var($emailtrim, FILTER_VALIDATE_EMAIL))
                        || (strlen($emailtrim > 60))) {
                $errors[] = 'You forgot to enter your email address';
                $errors[] = ' or the e-mail format is incorrect.';
        }
// Check for a password and match against the confirmed password:
$password1trim = filter_var( $_POST['password1'], FILTER_SANITIZE_STRING);
if (empty($password1trim)){   //
$errors[] ='Please enter a valid password';
}
else {
if(!preg_match(
'/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])
[A-Za-z\d#$@!%&*?]{8,12}$/',
$password1trim)) {  //
$errors[] =
'Invalid password, 8 to 12 chars, one upper, one lower,
one number, one special.';
} else
{
$password2trim =
filter_var( $_POST['password2'], FILTER_SANITIZE_STRING);
if($password1trim === $password2trim) { //
$password = $password1trim;
}else{
$errors[] = 'Your two passwords do not match.';
$errors[] = 'Please try again';
}
}
}
//Is the secret present? If it is, sanitize it
$secret = filter_var( $_POST['secret'], FILTER_SANITIZE_STRING);
if ((!empty($secret)) && (preg_match('/[a-z\.\s\,\-]/i', $secret)) &&
        (strlen($secret) <= 30)) {
        //Sanitize the trimmed city
        $secrettrim = $secret;
}else{
        $errors[] =
'Missing city. Only alphabetic, period, comma, dash and space. Max 30.';
}
if (empty($errors)) { // If everything's OK.
// If no problems encountered, register user in the database
//Determine whether the email address has already been registered
$query = "SELECT user_name FROM members WHERE email = ? ";
$q = mysqli_stmt_init($dbcon);
mysqli_stmt_prepare($q, $query);
mysqli_stmt_bind_param($q,'s', $emailtrim);
mysqli_stmt_execute($q);
$result = mysqli_stmt_get_result($q);

if (mysqli_num_rows($result) == 0){
//The email address has not been registered
//already therefore register the user in the users table
                        //-------------Valid Entries - Save to database -----
                //Start of the SUCCESSFUL SECTION. i.e.
//all the required fields were filled out
                $hashed_password = password_hash($password, PASSWORD_DEFAULT);
                // Register the user in the database...
                // Register the user in the database...
                $query =
"INSERT INTO members (member_id, user_name, email,
        passcode, secret, reg_date) ";
        $query .= "VALUES(' ', ?, ?, ?, ?, NOW() )";
$q = mysqli_stmt_init($dbcon);
mysqli_stmt_prepare($q, $query);
// use prepared statement to ensure that only text is inserted
// bind fields to SQL Statement
mysqli_stmt_bind_param($q, 'ssss', $user_nametrim, $emailtrim,
        $hashed_password, $secrettrim);
// execute query
mysqli_stmt_execute($q);
if (mysqli_stmt_affected_rows($q) == 1) {
                        header ("location: register-thanks.php");
                } else {
                        // echo 'Invalid query:' . $dbcon->error;
                $errorstring = "System is busy, please try later";
echo "<p class=' text-center col-sm-2' style='color:red'>$errorstring</p>";
                }
        }else{//The email address is already registered
        $errorstring = 'The email address is already registered.';
echo "<p class=' text-center col-sm-2'
style='color:red'>$errorstring</p>";
}
} else {//End of SUCCESSFUL SECTION
// ---------------Process User Errors---------------
// Display the users entry errors
$errorstring = 'Error! The following error(s) occurred: ';
foreach ($errors as $msg) { // Print each error.
$errorstring .= " - $msg<br>\n";
    }
$errorstring .= 'Please try again.';
echo "<p class=' text-center col-sm-2'
        style='color:red'>$errorstring</p>";
}// End of if (empty($errors)) IF.
}
catch(Exception $e) // We finally handle any problems here
{
// print "An Exception occurred. Message: " . $e->getMessage();
print "The system is busy please try later";
//  $date = date('m.d.y h:i:s');
//  $errormessage = $e->getMessage();
//  $eMessage = $date . " | Exception Error | " , $errormessage . |\n";
//   error_log($eMessage,3,ERROR_LOG);
// e-mail support person to alert there is a problem
//  error_log("Date/Time: $date – Exception Error, Check error log for
//details", 1, noone@helpme.com, "Subject: Exception Error \nFrom:
//Error Log <errorlog@helpme.com>" . "\r\n");
}
catch(Error $e)
{
// print "An Error occurred. Message: " . $e->getMessage();
print "The system is busy please try later";
// $date = date('m.d.y h:i:s');
// $errormessage = $e->getMessage();
// $eMessage = $date . " | Error | " , $errormessage . |\n";
// error_log($eMessage,3,ERROR_LOG);
// e-mail support person to alert there is a problem
//  error_log("Date/Time: $date – Error, Check error log for
//details", 1, noone@helpme.com, "Subject: Error \nFrom:
//Error Log <errorlog@helpme.com>" . "\r\n");
}
?>

Listing 10-3bChecking the Registration Page (process-register-page.php)

不需要对代码进行解释,因为它类似于第七章中的登记表。

注意

大多数菜单项都被禁用,只有主页按钮处于活动状态。主页标题上的注册按钮现在可以工作了,因为它可以链接到我们新创建的注册页面。

“谢谢”页面

如果注册成功,显示“谢谢”,如图 10-4 所示。

img/314857_2_En_10_Fig4_HTML.jpg

图 10-4

“谢谢”页面

注意

safer-register-page.php中使用的按钮块(情况 2)在“谢谢”文件中使用。只有主页是活动的。

清单 10-4 显示了“谢谢”页面的代码。

<?php
        $menu = 2;
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Thank You Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
                href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity=
        "sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
<div class="container" style="margin-top:30px;border: 2px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
        style="margin-bottom:2px; background:linear-gradient(#0073e6, white); padding:10px;">
        <?php include('includes/header.php'); ?>
</header>
<!-- Body Section -->
<div class="content mx-auto" id="contents">
<div class="row mx-auto" style="padding-left: 0px; height: auto;">
<div class="col-sm-12">
        <h4 class="text-center">Thank you for registering</h4>
        <h5 class="text-center">On the Home Page, you will now be able to login</h5>
        <h5 class="text-center">and add new quotes to the message board.</h5>
</div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
        style="padding-bottom:1px; margin: 0px; padding-top:8px; background-color:white;">
        <div class="col-sm-12 text-center">
                <?php include('includes/footer.php'); ?>
        </div>
</footer>
</div>
</div>
</body>

Listing 10-4Creating theThank YouPage (register-thanks.php)

推广成员表

现在您已经有了一个注册表单,您可以使用标题中的 Register 按钮来注册表 10-3 中给出的成员,或者您可以导入可下载的 SQL 文件。

表 10-3

成员表的属性

|

用户名

|

电子邮件地址

|

密码

| | --- | --- | --- | | 粉红色的百合 | jsmith@myisp.co.uk | 砰砰砰!3b33 | | 巨人台阶 12 | ndean@myisp.co.uk | 第三季第 1 集 | | 机械 7 | jdoe@myisp.co.uk | -= ytet-伊甸园字幕组=-翻译:粒粒粒尘紫月猫姐 scenery 校对 | | 内衣 | jsmith@outcook.com | D0gs0dy!2 | | 神话之王 | 亚瑟@myisp.net | Cam@10t4 |

成员将自动拥有默认的 member_level 值零。为了节省空间,在本教程中,我们没有包括管理设施。如果要添加此功能,请将成员注册为管理员,member_level 值为 1。然后为他们提供管理页面,如前几章所述。如果没有这个特性,网站管理员将需要监控最新的帖子,并使用 phpMyAdmin 删除任何攻击性的帖子。

现在我们有了一些注册会员,他们可以登录了。

登录页面

图 10-5 显示登录页面。

img/314857_2_En_10_Fig5_HTML.jpg

图 10-5

登录页面

清单 10-5a 给出了登录页面的代码。

标题块(情况 3)禁用除注册和主页之外的所有按钮。这段代码处理来自登录表单的提交。

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
      //require("cap.php");
}
$menu = 3;
?>
<!DOCTYPE html>
<html lang="en">
<head>
      <title>Login Page</title>
      <meta charset="utf-8">
      <meta name="viewport"
              content="width=device-width, initial-scale=1, shrink-to-fit=no">
      <!-- Bootstrap CSS File -->
      <link rel="stylesheet"
              href=
"https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
              integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
              crossorigin="anonymous">
      <script src='https://www.google.com/recaptcha/api.js'></script>
      <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
      <div class="container"
              style="margin-top:30px;border: 2px black solid;">
      <!-- Header Section -->
      <header class="jumbotron text-center row" id="includeheader"
              style="margin-bottom:2px;
              background:linear-gradient(#0073e6,whit1); padding:20px;">
              <?php include('includes/header.php'); ?>
      </header>
      <!-- Body Section -->
      <div class="content mx-auto" id="contents">
      <div class="row mx-auto" style="padding-left: 0px; height: auto;">
      <div class="col-sm-12">
      <?php
      if ($_SERVER['REQUEST_METHOD'] == 'POST') {                                       //#1
               require('process-login.php');
      }
      ?>
      <!-- Display the login form fields -->
      <div class="col-sm-10">
                <h3 class="h3 text-center">
                         <?php if(empty($errorstring)) { echo "Login"; }
                                  else { echo $errorstring; }
                         ?>
                </h3>
      <form action="login.php" method="post" name="loginform" id="loginform">
                <div class="form-group row">
      <label for="user_name" class="col-sm-4 col-form-label text-right">
                User ID:</label>
      <div class="col-sm-6">
        <input type="user_name" class="form-control" id="user_name"
                         name="user_name"
                         placeholder="User ID" maxlength="30" size="30" required
                         value=
                         "<?php if (isset($_POST['user_name']))
              echo htmlspecialchars($_POST['user_name'], ENT_QUOTES); ?>" >
    </div>
</div>
<div class="form-group row">
    <label for="passcode" class="col-sm-4 col-form-label
                text-right">Password:</label>
    <div class="col-sm-6">
                <input type="password" class="form-control" id="passcode"
                         name="passcode"
                         pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,12}"
                         title="One number, one upper, one lower, one special,
                                 with 8 to 12 characters"
                         placeholder="Password" minlength="8" maxlength="12"
                         required
                         value=
                         "<?php if (isset($_POST['passcode']))
                echo htmlspecialchars($_POST['passcode'], ENT_QUOTES); ?>" >
                         <span id="message">Between 8 and 12 characters.</span>
    </div>
</div>
<div class="form-group row">
     <label class="col-sm-4 col-form-label"></label>
<div class="col-sm-8" style="padding-left: 80px;">
<div class="float-left g-recaptcha" data-sitekey=
              "6LcrQ1wUAAAAAPxlrAkLuPdpY5qwS9rXF1j46fhq"></div>
</div>
</div>
<div class="form-group row">
     <label for="" class="col-sm-3 col-form-label"></label>
<div class="col-sm-8 text-center">
     <input id="submit" class="btn btn-primary" type="submit" name="submit"
             value="Login">
     </div>
   </div>
</form>
</div>
</div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
     style="padding-bottom:1px; margin: 0px; padding-left: 0px;
     padding-top:8px; background-color:white;">
     <div class="col-sm-12 text-center">
          <?php include('includes/footer.php'); ?>
     </div>
</footer>
</div>
</div>
</body>
</html>

Listing 10-5aCreating the Login Page (login.php)

代码的解释

您之前已经看到了所有的代码,但是编号为#1 的行引用了一个需要解释的文件。

if ($_SERVER['REQUEST_METHOD'] == 'POST') {                                             //#1
         require('process-login.php');
}

名为process-login.php的文件启动登录过程。清单 10-5b 中给出了代码。

<?php
        define('ERROR_LOG',"errors.log");
        // This section processes submissions from the login form
        // Check if the form has been submitted:
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        //connect to database
        try {
                require ('mysqli_connect.php');
                // Check that user name has been entered
                $user_name = filter_var( $_POST['user_name'], FILTER_SANITIZE_STRING);
                if  ((empty($user_name))
                        || (strlen($user_name > 30))) {
                        $errors[] = 'You forgot to enter your User ID';
                        $errors[] = ' or the User ID format is incorrect.';
                }
        // Check for a password and match against the confirmed password:
        $password = filter_var( $_POST['passcode'], FILTER_SANITIZE_STRING);
        //$string_length = strlen($password);
        if (empty($password)){
                $errors[] ='Please enter a valid password';
        }
        else {
                if(!preg_match(
                '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,12}$/',
                        $password)) {
                $errors[] = 'Invalid password, 8 to 12 chars, one upper, one lower, one number, one special.';
        }
}
  if (empty($errors)) { // If everything's OK.
        // Retrieve the user_id, psword, first_name and user_level for that
        // email/password combination
        $query = "SELECT member_id, passcode, user_name FROM members ";
        $query .= "WHERE user_name=?";
        $q = mysqli_stmt_init($dbcon);
        mysqli_stmt_prepare($q, $query);
                // bind $user_name to SQL Statement
        mysqli_stmt_bind_param($q, "s", $user_name);
        // execute query
        mysqli_stmt_execute($q);
        $result = mysqli_stmt_get_result($q);
        $row = mysqli_fetch_array($result, MYSQLI_NUM);
        if (mysqli_num_rows($result) == 1) {
                //if one database row (record) matches the input:-
                // Start the session, fetch the record and insert the
                // values in an array
                if (password_verify($password, $row[1])) {
                        session_start();
                        $_SESSION[ 'member_id' ] = $row[0];
                        $_SESSION[ 'user_name' ] = $row[2] ;
                        header ( 'Location: forum.php' ) ;
                } else { // No password match was made.
                        $errors[] = 'User ID/Password entered does not match our records. ';
                        $errors[] = 'Perhaps you need to register, just click the Register ';
                        $errors[] = 'button on the header menu';
                }
        } else { // No e-mail match was made.
                $errors[] = 'User ID/Password entered does not match our records. ';
                $errors[] = 'Perhaps you need to register, just click the Register ';
                $errors[] = 'button on the header menu';
        }
}
if (!empty($errors)) {
                $errorstring = "Error! <br /> The following error(s) occurred:<br>";
                foreach ($errors as $msg) { // Print each error.
                        $errorstring .= " $msg<br>\n";
                }
                $errorstring .= "Please try again.<br>";
                }// End of if (!empty($errors)) IF.

}
catch(Exception $e) // We finally handle any problems here
   {
        // print "An Exception occurred. Message: " . $e->getMessage();
        print "The system is busy please try later";
        //  $date = date('m.d.y h:i:s');
        //  $errormessage = $e->getMessage();
        //  $eMessage = $date . " | Exception Error | " , $errormessage . |\n";
        //   error_log($eMessage,3,ERROR_LOG);
        // e-mail support person to alert there is a problem
        //  error_log("Date/Time: $date – Exception Error, Check error log for
        //details", 1, noone@helpme.com, "Subject: Exception Error \nFrom:
        // Error Log <errorlog@helpme.com>" . "\r\n");
   }
catch(Error $e)
   {
        // print "An Error occurred. Message: " . $e->getMessage();
        print "The system is busy please try later";
        // $date = date('m.d.y h:i:s');
        // $errormessage = $e->getMessage();
        // $eMessage = $date . " | Error | " , $errormessage . |\n";
        // error_log($eMessage,3,ERROR_LOG);
        // e-mail support person to alert there is a problem
        //  error_log("Date/Time: $date – Error, Check error log for
        //details", 1, noone@helpme.com, "Subject: Error \nFrom:
        // Error Log <errorlog@helpme.com>" . "\r\n");
   }
}
?>

Listing 10-5bCreating the Code for Processing the Login (process_login.php)

验证与前几章相同。如果登录失败,它会显示错误消息。

注销

注销是一项重要的安全功能。除非用户注销(或关闭浏览器),否则会话仍然是活动的,并且有人可以访问和更改信息。清单 10-5c 显示了注销页面的代码。

<?php
session_start();//access the current session.
// if no session variable exists then redirect the user
if (!isset($_SESSION['member_id'])) {
header("location:index.php");
exit();
//cancel the session and redirect the user:
}else{ //cancel the session
    $_SESSION = array(); // Destroy the variables
        $params = session_get_cookie_params();
        // Destroy the cookie
        setcookie(session_name(), ", time()-42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]);
if (session_status() == PHP_SESSION_ACTIVE) {
session_destroy(); } // Destroy the session itself
header("location:index.php");
        }

Listing 10-5cCreating the Logout File (logout.php)

用户注销后,只能访问登录或注册页面以及主页。前面描述的登录页面将注册用户重定向到论坛页面,在那里他们可以选择查看哪个论坛。接下来描述论坛页面。

创建选择报价的途径

门户页面允许成员选择要查看的类别,如图 10-6 所示。

img/314857_2_En_10_Fig6_HTML.jpg

图 10-6

forum.php 页面允许用户选择要查看的报价类别

清单 10-6 给出了网关页面的代码。

标题块(header.php的情况 4)激活除登录和注册之外的所有按钮,因为用户现在已经登录。

<?php
// Start the session.
session_start() ;
//Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
       { header("Location: login.php");
                exit(); }
$menu = 4;
?>
<!DOCTYPE html>
<html lang="en">
<head>
       <title>Thank You Page</title>
       <meta charset="utf-8">
       <meta name="viewport" content="width=device-width,
                initial-scale=1, shrink-to-fit=no">
       <!-- Bootstrap CSS File -->
       <link rel="stylesheet"
                 href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                 integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                 crossorigin="anonymous">
       <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
       <div class="container" style="margin-top:30px;border:
                2px black solid;">
       <!-- Header Section -->
       <header class="jumbotron text-center row" id="includeheader"
               style="margin-bottom:2px;
               background:linear-gradient(#0073e6,white); padding:10px;">
               <?php include('includes/header.php'); ?>
       </header>
       <!-- Body Section -->
       <div class="content mx-auto" id="contents">
       <div class="row mx-auto" style="padding-left: 0px; height: auto;">
       <div class="col-sm-12">
            <h4 class="text-center">Thanks for logging in.
               Choose a forum from the menu above.</h4>
       </div>
       </div>
       <footer class="jumbotron row mx-auto" id="includefooter"
            style="padding-bottom:1px; margin: 0px; padding-top:8px;
               background-color:white;">
               <div class="col-sm-12 text-center">
                         <?php include('includes/footer.php'); ?>
               </div>
       </footer>
    </div>
    </div>
</body>
</html>

Listing 10-6Creating a Gateway to the Two Categories (forum.php)

在我们创建两个论坛页面之前,我们需要在论坛页面中显示一些报价。我们现在将创建一个表单,以便我们可以输入一些报价。

用于发布报价的表单

图 10-7 显示了过账表单。

img/314857_2_En_10_Fig7_HTML.jpg

图 10-7

用于发布报价的表单

你可以用这个词主语或者,如果你愿意,你可以用类别来代替。在本教程中,它们是同义词。主题使用下拉菜单有两个原因。

  • 我们假设留言板所有者想要限制主题(类别)的数量,因为所有者不希望成员创建新的主题。成员们将会在“滑稽语录”主题或“智慧语录”主题中添加新的语录。

  • 拼写需要一致。下拉菜单保证了这一点。当然,所有者可以在下拉菜单中添加新的主题(类别)。

清单 10-7a 给出了发布页面的代码。

包含的标题块(header.php的案例 8)激活除登录、注销和添加报价之外的所有按钮。

<?php
// Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
    { header("Location: login.php");
exit(); }
$menu = 8;
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    //require("cap.php");
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Post A Quote Page</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS File -->
    <link rel="stylesheet"
            href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
            integrity=
"sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
    crossorigin="anonymous">
    <script src='https://www.google.com/recaptcha/api.js'></script>
    <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
    <div class="container" style="margin-top:30px;border: 2px black solid;">
    <!-- Header Section -->
    <header class="jumbotron text-center row" id="includeheader"
            style="margin-bottom:2px; background:linear-gradient(#0073e6,white); padding:10px;">
            <?php include('includes/header.php'); ?>
    </header>
    <!-- Body Section -->
    <div class="content mx-auto" id="contents">
    <div class="row mx-auto" style="padding-left: 0px; height: auto;">
    <div class="col-sm-10" style="padding-top: 20px;">
            <h4 class="text-center">Post a Quotation</h4>
    <!-- Display the form fields-->
    <form id="post_form" action="process_post.php" method="post" accept-charset="utf-8"  >
            <div class="form-group row">
                    <label for="question" class="col-sm-4 col-form-label text-right">
            Choose the Subject*:</label>
            <div class="col-sm-8">
                    <select id="subject" name="subject" class="form-control">
                    <option selected value="">- Select -</option>
                    <option value="Comic Quotes">Comic Quotes</option>
                    <option value="Wise Quotes">Wise Quotes</option>
                    </select>
            </div>
            </div>
    <div class="form-group row">
            <label for="" class="col-sm-4 col-form-label text-right"></label>
    <div class="col-sm-8 text-center">
                    <label for="message">Please enter your quote below</label>
                    <textarea class="form-control" id="message" name="message" rows="5" cols="50"
                    value=
                            "<?php if (isset($_POST['message']))
                    echo htmlspecialchars($_POST['message'], ENT_QUOTES); ?>" >
            </textarea>
    </div>
    <div>
    <div class="form-group row">
    <label class="col-sm-4 col-form-label"></label>
    <div class="col-sm-8">
    <div class="g-recaptcha" style="margin-left: 90px;"
            data-sitekey="6LcrQ1wUAAAAAPxlrAkLuPdpY5qwS9rXF1j46fhq"></div>
    </div>
    </div>
    <div class="form-group row">
            <label for="" class="col-sm-3 col-form-label"></label>
    <div class="col-sm-8 text-center" style="padding-left: 40px;">
            <input id="submit" class="btn btn-primary" type="submit" name="submit" value="Submit">
    </div>
    </div>
</form>
</div>
<!--posting an entry into the database table automatically sends a message to the forum moderator                                                                                 #1
// Assign the subject-->
<!--<?php
    $subject = "Posting added to message board";
    $member = isset($_SESSION['user_name']) ? $_SESSION['user_name'] : "";
    $body = "Posting added by " . $member;
    mail("admin@myisp.co.uk", $subject, $body, "From:admin@myisp.co.uk\r\n");
    ?>-->
</div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
    style="padding-bottom:1px; margin: 0px; padding-top:8px; background-color:white;">
    <div class="col-sm-12 text-center">
        <?php include('includes/footer.php'); ?>
    </div>
</footer>
</div>
</body>
</html>

Listing 10-7aCreating the Form for Posting New Quotations (post.php)

代码的解释

本节解释代码。

<!--posting an entry into the database table automaticlally sends a message to the forum moderator                                                                                 #1
// Assign the subject-->
<!--<?php
    $subject = "Posting added to message board";
    $member = isset($_SESSION['user_name']) ? $_SESSION['user_name'] : "";
    $body = "Posting added by " . $member;
    mail("admin@myisp.co.uk", $subject, $body, "From:admin@myisp.co.uk\r\n");
?>-->

每当论坛中添加新报价时,都会向管理员发送一封电子邮件。然后,管理员应该检查公告,以确保它是适当的。如前所述,论坛提供商对论坛的内容负责。在这个例子中,这个电子邮件部分被注释掉了,因为只有当论坛被加载到提供 PHP 电子邮件服务的 web 服务器上时,这个代码才起作用。

本例中的电子邮件保持可用。PHP 函数 mail()的格式如下:mail (to,subject,body,from)。

收件人和发件人必须是电子邮件地址。变量可以是基本的,比如本例中的$subject,也可以是复杂的。在这个清单中,发布消息的人的用户名从会话中提取,然后与一些文本连接在一起,形成电子邮件的正文。“主题”、“收件人”和“发件人”项创建了电子邮件的标题。标题是电子邮件的顶部;正文是页眉下面的窗口。生成的电子邮件将类似于表 10-4 。

表 10-4

电子邮件的外观

| 来自: | admin@myisp.co.uk | | 日期: | 2018 年 08 月 02 日 17 时 26 分 | | 致: | admin@myisp.co.uk | | 主题: | 张贴添加到快速报价留言板 | | 粉红百合添加的帖子 |

当然,您必须用自己的电子邮件地址替换这些假电子邮件地址。请注意,给自己发送电子邮件时,两个电子邮件地址是相同的。

当然,数据库可以由熟悉 phpMyAdmin 的管理员管理;然而,为不熟悉 phpMyAdmin 的人创建一个用户友好的管理工具是很好的。(查看前面的章节,尤其是第三章,了解创建管理页面的说明。)用户友好的管理页面允许管理员查看最新帖子的表格。该表将有删除和编辑链接,如第三章所述。或者,可以在论坛表中添加一个额外的字段,以指示批准了哪些帖子。则只能显示批准的报价。这将不允许显示任何未批准的帖子。

注意

除非提供 PHP 电子邮件服务,否则不会使用您的计算机发送和接收电子邮件。购买主机环境时,确保包含 PHP 电子邮件。

处理过帐

清单 10-7b 给出了 process_post.php 的代码。

<?php
// Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
        { header("Location: login.php");
        exit(); }
//Connect to the database
require ( 'mysqli_connect.php' ) ;
// Has the form been submitted?
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
        // Check that the user has entered a subject and a message                        #1
        $subject = filter_var( $_POST['subject'], FILTER_SANITIZE_STRING);
         if ( empty($subject ) ) { echo 'You forgot to select a subject.'; }

        $comment = filter_var( $_POST['message'], FILTER_SANITIZE_STRING);
        if ((!empty($comment)) && (strlen($comment) <= 480)) {
                // remove ability to create link in email
                $patterns = array("/http/", "/https/", "/\:/","/\/\//","/www./");
                $commenttrim = preg_replace($patterns," ", $comment);
        }else{ // if comment not valid display error page
                echo "You forgot to enter a message";
        }
        // If successful insert the post into the database table
        if( !empty($commenttrim) && !empty($subject) )
        {
                //Make the insert query                                                   #2
                $query = "INSERT INTO forum (post_id, user_name, subject, message, post_date) ";
                $query .= "VALUES( ' ', ?, ?, ?, NOW() )";
                $q = mysqli_stmt_init($dbcon);
                mysqli_stmt_prepare($q, $query);
                // use prepared statement to ensure that only text is inserted
                // bind fields to SQL Statement
                $user_name = filter_var( $_SESSION['user_name'], FILTER_SANITIZE_STRING);
                mysqli_stmt_bind_param($q, 'sss', $user_name, $subject, $commenttrim);
                // execute query
                mysqli_stmt_execute($q);
                if (mysqli_stmt_affected_rows($q) == 1) {
                        header ("Location: post_thanks.php");
        }
        else
        {
                echo "An Error has occurred in loading your posting";
        }
// Close the database connection
mysqli_close( $dbcon ) ;
}
 }
?>

Listing 10-7bCreating the File for Processing the Postings (process_post.php)

代码的解释

本节解释代码。

// Check that the user has entered a subject and a message                           #1
$subject = filter_var( $_POST['subject'], FILTER_SANITIZE_STRING);
if ( empty($subject ) ) { echo 'You forgot to select a subject.'; }

$comment = filter_var( $_POST['message'], FILTER_SANITIZE_STRING);
if ((!empty($comment)) && (strlen($comment) <= 480)) {
        // remove ability to create link in email
        $patterns = array("/http/", "/https/", "/\:/","/\/\//","/www./");
        $commenttrim = preg_replace($patterns," ", $comment);

消息的文本区域(以及来自用户的所有信息)吸引了那些想要插入危险脚本的恶意用户。因此,必须在代码中内置特殊的安全过滤器。使用带有 FILTER_SANITIZE_STRING 参数的 filter_var 函数清理 textarea(和 subject)中的消息。这使得条目无害。使用预准备语句还可以确保传递的字符串作为文本传递,并且不会造成伤害。

之前已经多次遇到 filter_var 和 FILTER_SANITIZE_STRING。它将删除任何不需要的字符,包括撇号。

//Make the insert query                                                             #2
$query = "INSERT INTO forum (post_id, user_name, subject, message, post_date) ";
$query .= "VALUES( ' ', ?, ?, ?, NOW() )";
$q = mysqli_stmt_init($dbcon);
mysqli_stmt_prepare($q, $query);
// use prepared statement to ensure that only text is inserted
// bind fields to SQL Statement
$user_name = filter_var( $_SESSION['user_name'], FILTER_SANITIZE_STRING);
mysqli_stmt_bind_param($q, 'sss', $user_name, $subject, $commenttrim);
// execute query
mysqli_stmt_execute($q);
if (mysqli_stmt_affected_rows($q) == 1) {
        header ("Location: post_thanks.php");

准备好的 insert 语句使用筛选过的会话用户名、先前筛选过的主题和先前筛选过的引号($commenttrim)。如果由于某种原因,变量仍然包含有害数据,则准备好的语句会将它们用作文本,并且不会执行任何代码。尽管从安全角度来看,这些条目现在是无害的,但它们可能仍然包含不适合留言板的字符或信息。管理员可以更正数据或删除公告。

张贴一些报价

现在我们有了一个将帖子插入论坛表的表单,我们将发布表 10-5 中显示的引用。您还可以使用 phpMyAdmin 从下载文件一章中导入 SQL 文件。当每个报价发布后,您将被重定向到论坛页面。但是,您还不能查看报价,因为我们还没有创建显示报价的两个页面。

表 10-5

贴一些语录

|

以…身份登录

|

主题(又名论坛)

|

消息

| | --- | --- | --- | | 粉红色的百合 | 明智的报价 | "逆境使一些人崩溃,另一些人打破记录."威廉·阿瑟·沃德 | | 机械 7 | 滑稽的引语 | “我喜欢最后期限。我喜欢它们飞过时发出的嗖嗖声。”道格拉斯·亚当斯 | | 粉红色的百合 | 滑稽的引语 | "打高尔夫球是一种很好的散步方式."[人名]马克·吐温(美国幽默大师、小说家、作家、演说家) | | 粉红色的百合 | 滑稽的引语 | "生活是一件接一件糟糕的事情。"[人名]马克·吐温(美国幽默大师、小说家、作家、演说家) | | 巨人台阶 12 | 滑稽的引语 | “给我高尔夫球杆,新鲜空气和一个漂亮的伴侣,你可以保留高尔夫球杆和新鲜空气”杰克·本尼 | | 神话之王 | 明智的报价 | "没有巨大的热情,就不会有伟大的成就。"拉尔夫·瓦尔多·爱默生 | | 神话之王 | 明智的报价 | "至理名言往往落在贫瘠的土地上,但一句友善的话绝不会被丢弃."亚瑟帮忙 | | 神话之王 | 滑稽的引语 | "许多小事情因为正确的广告而变得很大."[人名]马克·吐温(美国幽默大师、小说家、作家、演说家) | | 神话之王 | 明智的报价 | "同时做两件事等于什么都不做。"Publilius Syrus | | 巨人台阶 12 | 明智的报价 | "从未犯过错误的人从未尝试过新事物."[人名]阿尔伯特·爱因斯坦(犹太裔理论物理学家) | | 巨人台阶 12 | 滑稽的引语 | "经验只是我们给自己的错误起的名字."奥斯卡·王尔德 | | 巨人台阶 12 | 滑稽的引语 | "如果你想重获青春,就砍掉他的零花钱."阿尔·贝恩斯坦 | | 机械 7 | 滑稽的引语 | "技术进步只是为我们提供了一种更有效的倒退手段."阿尔多斯·赫胥黎 | | 粉红色的百合 | 明智的报价 | "真正的知识是知道自己无知的程度."孔子 | | 机械 7 | 明智的报价 | "如果你不在乎谁得到了荣誉,你会取得惊人的成就."哈里·S·杜鲁门 |

纪念

将自动添加发布的日期和时间。

当你有一些报价要显示时,它们会出现在主页上(如图 10-2 所示)。

滑稽的报价页面

图 10-8 显示了滑稽的报价页面。

img/314857_2_En_10_Fig8_HTML.jpg

图 10-8

滑稽的报价页面

清单 10-8 中给出的代码只从数据库论坛表中选择滑稽的引文。

<?php // Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
        { header("Location: login.php");
        exit(); }
$menu = 9;
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Message Board Home Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
                href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity=
        "sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
        <div class="container" style="margin-top:30px;border: 2px black solid;">
        <!-- Header Section -->
        <header class="jumbotron text-center row" id="includeheader"
                style="margin-bottom:2px; background:linear-gradient(#0073e6,white); padding:10px;">
                <?php include('includes/header.php'); ?>
        </header>
        <!-- Body Section -->
        <div class="content mx-auto" id="contents">
        <div class="row mx-auto" style="padding-left: 0px; height: auto;">
        <div class="col-sm-12">
                <h4 class="text-center">Comic Quotes</h4>
                <?php
                // Connect to the database
                require ( 'mysqli_connect.php' ) ;
                // Make the query                                                         #1
                $query = "SELECT user_name,post_date,subject,message FROM forum WHERE  ";
                $query .=  "subject = 'Comical Quotes' ORDER BY 'post_date' ASC";
                $result = mysqli_query( $dbcon, $query ) ;
                if ( mysqli_num_rows( $result ) > 0 )
                {
                        ?>
                        <table class="table table-responsive table-striped col-sm-12"
                                style="background: white;color:black; padding-left: 20px;">
                                <tr>
                                        <th scope="col">Posted By</th>
                                        <th scope="col">Forum</th>
                                        <th scope="col">Quotation</th>
                                </tr>
                        <?php
                        while ( $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ))
                        {
                                $user_name = htmlspecialchars($row['user_name'], ENT_QUOTES);
                                $post_date = htmlspecialchars($row['post_date'], ENT_QUOTES);
                                $message = htmlspecialchars($row['message'], ENT_QUOTES);
                                echo '<tr>
                                        <td scope="row">' . $user_name . '</td>
                                        <td scope="row">' . $post_date . '</td>
                                        <td scope="row">' . $message . '</td>
                                </tr>';
                        }
                        echo '</table>' ;
                }
                else { echo 'There are currently no messages.' ; }
        mysqli_close( $dbcon ) ;
?>
</div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
        style="padding-bottom:1px; margin: 0px; padding-top:8px; background-color:white;">
        <div class="col-sm-12 text-center">
                <?php include('includes/footer.php'); ?>
        </div>
</footer>
</div>
</div>
</body>
</html>

Listing 10-8Creating the Comical Quotes Page (forum_c.php)

代码的解释

清单 10-8 中的大部分代码大家都会很熟悉,清单中还有注释提醒你重要的代码行。

我们现在将检查第 1 行:

// Make the query                                                                      #1
$query = "SELECT user_name,post_date,subject,message FROM forum WHERE  ";
$query .=  "subject = 'Comical Quotes' ORDER BY 'post_date' ASC";

该查询只从论坛表中选择滑稽的引文。报价将按发布的升序排序,即最早的先排序。

滑稽引用页面的标题

在查看滑稽报价页面后,用户可能还想查看明智报价页面或插入他们自己的报价。为了让用户能够做到这一点,下面显示的标题块(header.php的第 9 种情况)激活了除登录、注册和漫画引用之外的所有按钮。目前,这些按钮中有几个是无效的,因为我们还没有设计相关的页面。

要显示的按钮在来自header.php的代码片段中显示如下:

case 9: //forum_c.php
        ?>
             <button type="button" style="width: 110px;"
                     class="btn btn-secondary bg-primary"
                     onclick="location.href =
                     'index.php?name=Quick Quotes'">
                     Home Page
             </button>

             <button type="button" style="width: 110px;" class=
                     btn btn-secondary bg-primary disabled"
                     onclick="location.href = "" >Login
             </button>

             <button type="button" style="width: 110px;"
                     class="btn btn-secondary bg-primary"
                     onclick="location.href =
                     'logout.php?name=Logout'">Logout
             </button>

             <button type="button" style="width: 110px;" class=
                     "btn btn-secondary bg-primary disabled"
                     onclick="location.href = "" >Register
             </button>

             <button type="button" style="width: 120px;"
                     class="btn btn-secondary bg-primary"
                     onclick="location.href =
                     'view_posts.php?name=Your Quotes'" >Your Quotes
             </button>

             <button type="button" style="width: 120px;"
                     class="btn btn-secondary bg-primary"
                     onclick="location.href = 'post.php?name=Add A Quote'">
                     Add A Quote
             </button>

             <button type="button" style="width: 120px;" class=
                     "btn btn-secondary bg-primary disabled"
                     onclick="location.href = "" >Comic Quotes
             </button>

             <button type="button" style="width: 120px;"
                     class="btn btn-secondary bg-primary"
                     onclick="location.href =
                     'forum_w.php?name=Wise Quotes'">Wise Quotes
             </button>

             <button type="button" style="width: 120px;"
                     class="btn btn-secondary bg-primary"
                     onclick="location.href =
                     'search.php?name=Search Quotes'" >Search Quotes
             </button>
      <?php
    break;

明智的报价页面

除了 SQL 查询之外,这个页面几乎与滑稽的报价页面相同。此外,明智的报价按钮被禁用,而滑稽的报价按钮被启用。图 10-9 显示了 Wise 报价页面。

img/314857_2_En_10_Fig9_HTML.jpg

图 10-9

明智引语的展示

该页面仅显示明智的报价。清单 10-9 给出了 Wise 报价页面的代码。

<?php // Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
        { header("Location: login.php");
        exit(); }
$menu = 10;
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Message Board Home Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
                href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
        <div class="container" style="margin-top:30px;border: 2px black solid;">
        <!-- Header Section -->
        <header class="jumbotron text-center row" id="includeheader"
                style="margin-bottom:2px; background:linear-gradient(#0073e6,white); padding:10px;">
                <?php include('includes/header.php'); ?>
        </header>
        <!-- Body Section -->
        <div class="content mx-auto" id="contents">
        <div class="row mx-auto" style="padding-left: 0px; height: auto;">
        <div class="col-sm-12">
                <h4 class="text-center">Wise Quotes</h4>
                <?php
                // Connect to the database
                require ( 'mysqli_connect.php' ) ;
                // Make the query                                                       #1
                $query = "SELECT user_name,post_date,subject,message FROM forum ";
                $query .= "WHERE subject = 'Wise Quotes' ORDER BY 'post_date' ASC";
                $result = mysqli_query( $dbcon, $query ) ;
                if ( mysqli_num_rows( $result ) > 0 )
                {
                        ?>
                        <table class="table table-responsive table-striped col-sm-12"
                                style="background: white;color:black; padding-left: 50px;">
                                <tr>
                                        <th scope="col">Posted By</th>
                                        <th scope="col">Forum</th>
                                        <th scope="col">Quotation</th>
                                </tr>
                        <?php
                        while ( $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ))
                        {
                                $user_name = htmlspecialchars($row['user_name'], ENT_QUOTES);
                                $post_date = htmlspecialchars($row['post_date'], ENT_QUOTES);
                                $message = htmlspecialchars($row['message'], ENT_QUOTES);
                                echo '<tr>
                                        <td scope="row">' . $user_name . '</td>
                                        <td scope="row">' . $post_date . '</td>
                                        <td scope="row">' . $message . '</td>
                                </tr>';
                        }
                echo '</table>' ;
                }
                else { echo 'There are currently no messages.' ; }
                mysqli_close( $dbcon ) ;
        ?>
        </div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
        style="padding-bottom:1px; margin: 0px; padding-top:8px; background-color:white;">
        <div class="col-sm-12 text-center">
                <?php include('includes/footer.php'); ?>
        </div>
</footer>
</div>
</div>
</body>
</html>

Listing 10-9Creating the Wise Quotes Page (forum_w.php)

代码的解释

代码几乎与 Comical Quotes 论坛页面的列表相同,除了此处显示的项目:

// Make the query                                                                         #1
$query = "SELECT user_name,post_date,subject,message FROM forum ";
$query .= "WHERE subject = 'Wise Quotes' ORDER BY 'post_date' ASC";

该查询只选择主题为“Wise Quotes”的记录报价将按发布的升序排序,即最早的先排序。

与滑稽报价页面一样,一个新的标题块(header.php的案例 10)将允许用户重定向到滑稽报价页面。

明智报价页面的标题

标题块与“滑稽引用”页面的标题块相同,只是“明智引用”按钮被禁用,而“滑稽引用”按钮被激活。请注意,“查看您的帖子”和“搜索”按钮将不起作用,因为相关页面尚未创建。

   case 10: //forum_w.php
            ?>
                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'index.php?name=Quick Quotes'">
                        Home Page
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "" >Login
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'logout.php?name=Logout'">Logout
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "" >Register
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'view_posts.php?name=Your Quotes'" >
                        Your Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'post.php?name=Add A Quotes'">
                        Add A Quote
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'forum_c.php?name=Comic Quotes'" >
                        Comic Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "">Wise Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'search.php?name=Search Quotes'" >
                        Search Quotes
                </button>
        <?php
        break;

添加搜索工具

最可能的搜索原因如下:

  • 成员可能想要查看他们自己的帖子或其他贡献者的帖子的列表。

  • 成员可能希望在邮件中搜索特定作者的特定单词或短语或引文。

在实现这些搜索之前,我们必须创建显示搜索结果的页面。

图 10-10 显示了查看单个成员帖子的显示。

img/314857_2_En_10_Fig10_HTML.jpg

图 10-10

显示一个成员的帖子

清单 10-10 给出了显示成员帖子的页面代码。

<?php
// Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
{ header("Location: login.php");
exit(); }
$menu = 7;
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>View Postings Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content=
"width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
                href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="birds.css">
</head>
<body>
<div class="container" style=
"margin-top:30px;border: 2px black solid;">
<!-- Header Section -->
<header class="jumbotron text-center row" id="includeheader"
style="margin-bottom:2px;
background:linear-gradient(#0073e6,white); padding:10px;">
                        <?php include('includes/header.php'); ?>
</header>
<div id="content"><!--Start of the quotes found page content-->
<?php
// Connect to the database
require ( 'mysqli_connect.php' ) ;                                                      //#1
                $user_name =
filter_var( $_SESSION['user_name'], FILTER_SANITIZE_STRING);
                // Make the full text query
                $query = "SELECT user_name,post_date,subject,message FROM ";
$query .= "forum WHERE user_name = ? ";
                $query .= "ORDER BY post_date ASC";
        $q = mysqli_stmt_init($dbcon);
        mysqli_stmt_prepare($q, $query);
        // bind $id to SQL Statement
                mysqli_stmt_bind_param($q, "s", $user_name);
        // execute query
        mysqli_stmt_execute($q);
        $result = mysqli_stmt_get_result($q);
                if (mysqli_num_rows($result) > 0) {
                        echo '<h4 class="text-center">Your Postings</h4>';
                        ?>
                        <table class=
"table table-responsive table-striped col-sm-12"
                                style="background: white;color:black;
padding-left: 40px;">
                                <tr>
                                        <th scope="col">Posted By</th>
                                        <th scope="col">Forum</th>
                                        <th scope="col">Quotation</th>
                                </tr>
                        <?php
                        while ( $row =
mysqli_fetch_array( $result, MYSQLI_ASSOC ))
                        {
                                $user_name =
htmlspecialchars($row['user_name'], ENT_QUOTES);
                                $post_date =
htmlspecialchars($row['post_date'], ENT_QUOTES);
                                $subject =
htmlspecialchars($row['subject'], ENT_QUOTES);
                                $message =
htmlspecialchars($row['message'], ENT_QUOTES);
                                echo '<tr>
                                        <td scope="row">' . $user_name . " " .
 $post_date . '</td>
                                        <td scope="row">' . $subject . '</td>
                                        <td scope="row">' . $message . '</td>
                                </tr>';
                        }
                        echo '</table>' ;
                }
else { echo '<p class="text-center">
There are currently no messages.</p>' ; }
mysqli_close( $dbcon ) ;
?>
</div><!--End of the quotes found page content.-->
<footer class="jumbotron row mx-auto" id="includefooter"
style="padding-bottom:1px; margin: 0px; padding-top:8px;
background-color:white;">
<div class="col-sm-12 text-center">
                        <?php include('includes/footer.php'); ?>
                </div>
</footer>
</div>
</body>
</html>

Listing 10-10Creating a Page to Display an Individual Members Postings (view_posts.php)

代码的解释

您之前已经看到了大部分代码,但是查询需要一些解释。

require ( 'mysqli_connect.php' ) ;                                                      //#1
                $user_name =
filter_var( $_SESSION['user_name'], FILTER_SANITIZE_STRING);
                // Make the full text query
                $query = "SELECT user_name,post_date,subject,message FROM ";
$query .= "forum WHERE user_name = ? ";
                $query .= "ORDER BY post_date ASC";
        $q = mysqli_stmt_init($dbcon);
        mysqli_stmt_prepare($q, $query);
        // bind $id to SQL Statement
                mysqli_stmt_bind_param($q, "s", $user_name);
        // execute query
        mysqli_stmt_execute($q);

该查询选择要显示的项目,并指定两个条件:只显示在会话中指定的用户名($user_name)的过帐,并按过帐日期的升序对表行显示进行排序。

ViewPosts.php 的头球

标题块将激活除登录、注册和报价之外的所有按钮。下面的代码片段显示了来自header.php的代码:

case 8: //post.php
            ?>
                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'index.php?name=Quick Quotes'">
                        Home Page
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "" >Login
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'logout.php?name=Logout'">
                        Logout
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "" >Register
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'view_posts.php?name=Your Quotes'" >
                        Your Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "">Add A Quote
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'forum_c.php?name=Comic Quotes'" >
                        Comic Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'forum_w.php?name=Wise Quotes'">
                        Wise Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'search.php?name=Search Quotes'" >
                        Search Quotes
                </button>
        <?php
        break;

我们现在将启用成员进行全文搜索的能力。

搜索特定的单词或短语

成员们可能希望看到马克·吐温的语录表或关于高尔夫的语录列表;因此,成员将搜索特定的单词或短语。这将需要在标题中的搜索按钮。作为一种替代方案,可以在论坛页面中加入一个搜索字段;然而,为了简单起见,我们将使用更简单的方法:使用一个链接到搜索表单的按钮。

全文搜索将在每封邮件中查找单词。名为 messages 的列必须作为全文索引,如本章开头所示。

全文搜索可用于 VARCHAR 和 text 列。全文搜索不区分大小写,将忽略以下内容:

  • 偏旁的话。如果你想搜索被宠坏的,你得搜索完整的单词。只搜索不会返回你要找的东西。

  • 包含少于四个字符的单词。

  • 别说了。这些都是极为常见的词语,如中的中的中的中的中的中的中的中的中的等。

  • 被搜索列中超过 50%的行中包含的单词或短语。在这种情况下,该单词或短语被视为停用词。这通常可以通过在一个表中有四个或更多记录来避免。

全文搜索表单

我们现在将创建一个在消息(引用)中搜索特定单词或短语的表单。

图 10-11 显示了搜索表单。

img/314857_2_En_10_Fig11_HTML.jpg

图 10-11

搜索表单

清单 10-11 给出了搜索表单的代码。

<?php
// Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
        { header("Location: login.php");
        exit(); }
$menu = 6;
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Search Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
        href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
        integrity=
        "sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
        crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
        <div class="container" style="margin-top:30px;border: 2px black solid;">
        <!-- Header Section -->
        <header class="jumbotron text-center row" id="includeheader"
                style="margin-bottom:2px; background:linear-gradient(#0073e6,white); padding:10px;">
                <?php include('includes/header.php'); ?>
        </header>
        <!-- Body Section -->
        <div class="content mx-auto" id="contents">
        <div class="row mx-auto" style="padding-left: 0px; height: auto;">
        <div class="col-sm-12">
                <h3 class="text-center">Search for a word or phrase in the quotes</h3>
                <form id="search" action="quotes_found.php" method="post">
                <div class="form-group row">
                <label for="target" class="col-sm-4 col-form-label text-right">Enter a word or phrase:</label>
                <div class="col-sm-4">
                        <input type="text" class="form-control" id="target" name="target"
                                placeholder="Word or Phrase" maxlength="60" size="40" required
                                value=
                                        "<?php if (isset($_POST['target']))
                                echo htmlspecialchars($_POST['target'], ENT_QUOTES); ?>" >
                </div>
                 </div>
                <div class="form-group row">
                        <label for="" class="col-sm-2 col-form-label"></label>
                <div class="col-sm-8 text-center">
                        <input id="submit" class="btn btn-primary" type="submit"
                                name="submit" value="Search">
                </div>
        </div>
</form>
</div>
</div>
<footer class="jumbotron row mx-auto" id="includefooter"
        style="padding-bottom:1px; margin: 0px; padding-top:8px; background-color:white;">
        <div class="col-sm-12 text-center">
                <?php include('includes/footer.php'); ?>
  </div>
</footer>
</div>
</div>
</body>
</html>

Listing 10-11Creating the Search Form (search.php)

搜索表单将搜索词传递给显示搜索结果的页面。

显示搜索结果

图 10-12 显示了全文搜索如何显示结果。

img/314857_2_En_10_Fig12_HTML.jpg

图 10-12

显示对单词 Mark Twain 进行全文搜索的结果

请注意,马克·吐温的引用次数不到我们论坛表中所有引用次数的 50%。如果引用马克·吐温的次数超过引用次数的 50%,就不会显示任何结果。在我们的示例数据库表中,有 23 个报价。马克·吐温被引用了三次;因此,他占总数的 13%。因为这不到总数的 50 %,他将被找到并展示。如果表中只有六条引文,马克·吐温将被引用 50%,因此他将找不到。换句话说,组词马克·吐温将被视为停用词,如他的她的以及你的。如果您知道某个词或短语存在于数据库表中,但全文搜索未能找到它,则可能是表中没有足够的引号,或者至少 50%的引号包含要搜索的词或短语。清单 10-12a 给出了 quotes_found 页面的代码。

<?php
// Start the session.
session_start() ;
// Redirect if not logged in.
if ( !isset( $_SESSION[ 'member_id' ] ) )
        { header("Location: login.php");
        exit(); }
$menu = 4;
?>
<!DOCTYPE html>
<html lang="en">
<head>
        <title>Search Page</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS File -->
        <link rel="stylesheet"
                href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
                integrity=
"sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
                crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="msgboard.css">
</head>
<body>
<div class="container" style="margin-top:30px;border: 2px black solid;">
<!-- Header Section -->
        <header class="jumbotron text-center row" id="includeheader"
                style="margin-bottom:2px; background:linear-gradient(#0073e6,white); padding:10px;">
                        <?php include('includes/header.php'); ?>
        </header>
<div id="content"><!--Start of the quotes found page content-->
<?php
        // Connect to the database
        require ( 'mysqli_connect.php' ) ;
        //if POST is set                                                                 #1
        if($_SERVER['REQUEST_METHOD'] == 'POST' ) {
                $target = filter_var( $_POST['target'], FILTER_SANITIZE_STRING);
                // Make the full text query                                              #2
                $query = "SELECT user_name,post_date,subject,message FROM forum WHERE ";
                $query .= "MATCH (message) AGAINST ( ? ) ORDER BY post_date ASC";
                $q = mysqli_stmt_init($dbcon);
                mysqli_stmt_prepare($q, $query);
                // bind $id to SQL Statement
                mysqli_stmt_bind_param($q, "s", $target);
                // execute query
                mysqli_stmt_execute($q);
                $result = mysqli_stmt_get_result($q);
                if (mysqli_num_rows($result) > 0) {
                        echo '<h4 class="text-center">Full Text Search Results</h2>';
                        ?>
                        <table class="table table-responsive table-striped col-sm-12"
                                style="background: white;color:black; padding-left: 50px;">
                                <tr>
                                        <th scope="col">Posted By</th>
                                        <th scope="col">Forum</th>
                                        <th scope="col">Quotation</th>
                                </tr>
                        <?php
                        while ( $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ))
                        {
                                $user_name = htmlspecialchars($row['user_name'], ENT_QUOTES);
                                $subject = htmlspecialchars($row['subject'], ENT_QUOTES);
                                $message = htmlspecialchars($row['message'], ENT_QUOTES);
                                echo '<tr>
                                        <td scope="row">' . $user_name . '</td>
                                        <td scope="row">' . $subject . '</td>
                                        <td scope="row">' . $message . '</td>
                                </tr>';
                        }
                        echo '</table>' ;
                }
                else { echo '<p class="text-center">There are currently no messages.</p>' ; }
        mysqli_close( $dbcon ) ;
        }
?>
</div><!--End of the quotes found page content.-->
<footer class="jumbotron row mx-auto" id="includefooter"
        style="padding-bottom:1px; margin: 0px; padding-top:8px; background-color:white;">
        <div class="col-sm-12 text-center">
                <?php include('includes/footer.php'); ?>
        </div>
</footer>
</div>
</body>
</html>

Listing 10-12aCreating the Search Results Page (quotes_found.php)

注意

如果您运行该文件并看到错误消息“警告:mysqli_num_rows()期望参数 1 是 mysqli_result,布尔值在…中给定”,您可能忘记选择全文作为表中消息列的索引。

代码的解释

本节解释代码。

//if POST is set                                                                          #1
if($_SERVER['REQUEST_METHOD'] == 'POST' ) {
        $target = filter_var( $_POST['target'], FILTER_SANITIZE_STRING);

搜索表单将目标单词或短语(例如马克·吐温)发送到这个页面,在这里它被赋给变量$target。

// Make the full text query                                                               #2
$query = "SELECT user_name,post_date,subject,message FROM forum WHERE ";
$query .= "MATCH (message) AGAINST ( ? ) ORDER BY post_date ASC";
$q = mysqli_stmt_init($dbcon);
mysqli_stmt_prepare($q, $query);
// bind $id to SQL Statement
mysqli_stmt_bind_param($q, "s", $target);

全文查询在 forum 表中搜索包含存储在变量$target 中的单词 Mark Twain 的消息(引文),该变量绑定到 prepare 语句。注意括号、逗号、双引号和单引号;它们很重要。全文搜索查询的格式如下:

SELECT list of items FROM some table WHERE MATCH (the column) AGAINST(the search words) ;

关键字 MATCH 和 AGAINST 是标准选择查询和全文搜索查询之间的主要区别。

quotes_found 页面的标题

清单 10-12b 给出了头部的代码块。这也是 forum.php 使用的相同标题。

case 4: //forum.php //quotes_found.php
            ?>
                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'index.php?name=Quick Quotes'">
                        Home Page
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "" >Login
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'logout.php?name=Logout'">
Logout
                </button>

                <button type="button" style="width: 110px;" class="btn btn-secondary bg-primary disabled"
                        onclick="location.href = "" >Register
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'view_posts.php?name=Your Quotes'" >
                        Your Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'post.php?name=Add A Quote'">
                        Add A Quote
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'forum_c.php?name=Comic Quotes'" >
                        Comic Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'forum_w.php?name=Wise Quotes'">
                        Wise Quotes
                </button>

                <button type="button" style="width: 120px;" class="btn btn-secondary bg-primary"
                        onclick="location.href = 'search.php?name=Search Quotes'" >Search Quotes
                </button>
        <?php
        break;

Listing 10-12bCreating the Header Block for the Quotes Found Page (header.php)

增强留言板

为了不熟悉数据库的读者的利益,本章中的留言板被大大简化了。通过使用您从前面章节中获得的知识,可以添加如下增强功能:

  • 用于显示两类报价的页面可以显示分页的结果。(查看第章第五章和第章第八章,了解如何完成此操作。)

  • 成员可能想要更改他们的密码。(查看第三章了解详情。)

  • 成员可能忘记了他们的密码;可以向他们发送新密码。这包括在第十一章中。

将留言板转换为论坛

在这一章的开始,我们说过我们将简要描述一个将留言板转换成论坛的结构。一个论坛需要最大的规范化和原子性。(参见第九章,提醒您这些术语的定义。)需要更多的表,其中几个将通过包含关键字 JOIN 的查询来链接。

论坛需要额外的表格来放置主题和回复。留言板由管理员审核,结果是自动发送一封包含发帖人姓名和日期的电子邮件。当报价被提交时,它被立即插入到数据库表中;更好的解决方案是创建一个额外的列(approved ),该列必须由管理员设置,以允许向成员显示报价。

如果管理员能够在不使用 phpMyAdmin 的情况下删除或编辑报价,那将会很有帮助。管理页面可以显示包含编辑和删除链接的最近帖子的表格,如第三章所述。

一个论坛最少需要四张桌子,如图 10-13 所示。

img/314857_2_En_10_Fig13_HTML.jpg

图 10-13

一个非常基本的论坛的表格

摘要

在这一章中,我们学习了基本留言板的计划和结构。我们创建了一个注册页面和登录表单。我们开发了一个两页报价的网关,然后创建了这些页面。我们学习了如何创建发布消息的表单。我们创建了两个搜索表单:一个允许成员搜索他们自己的帖子列表,另一个用于进行全文搜索。建议对基本留言板进行一些改进,最后提供了一个基本论坛的简要概述。下一章描述一个基本的电子商务网站。