[关闭]
@artman328 2022-09-19T00:31:56.000000Z 字数 35125 阅读 3003

程序员之路 —— PHP:亲民的 Web 开发利器

php web


第一部分 WEB 应用概述与学习环境的搭建

第一章 WEB应用的概念

Web 应用是指那些人们通过浏览器(或其它基于HTTP协议的应用程序)完成诸如信息浏览、数据提交、查询、修改、更新等任务的应用程序体系。它由以下几个部分构成。

一、客户端(如:浏览器,基于HTTP协议的其它应用程序等)

客户端程序是那些在计算机或移动设备上与人直接交互的应用程序,如:浏览器、基于 HTTP 协议的其它应用程序等。这些应用程序接受用户输入,将用户的请求(Request)发送到服务器端。
最常用的客户端是各种浏览器。现代浏览器都内置了一个计算机语言编程平台——JavaScript,它包括了一个语言解释器(用于解释并执行程序指令)和常用的程序库(一些通用功能函数和对象)。在这个平台上编程,浏览器就可以和用户直接互动(如用户输入的数据验证,拖拽操作,互动特效等),必要时才将请求发往服务器。在这个平台上的编程叫客户端编程。

二、WEB 服务器(如:Apache,IIS等)

Web 服务器程序是接受来自客户端请求并给出响应(Response)的应用程序。Web服务器的主要任务是根据请求将服务器上的各种资源发送给客户端。这些资源包括各种文件,如:网页、图片、音乐、视频等。
在服务器上,根据预定规则,服务器会将一些请求的特定资源(一般为程序文件)再发送给特定的程序解释器进行处理,在处理过程中可能会和数据库服务器进行交互以便对数据库中的数据进行增、删、改、查等操作。程序解释器处理完后将结果交给 Web 服务器,Web 服务器再将其发往客户端。

三、数据库服务器(如:MySQL、SQL Server等)

数据库服务器用以存储WEB应用的数据。

第二章 WEB 应用的运作过程

一、过程描述

WEB 应用的运作过程可以下图来说明。

Created with Raphaël 2.1.2用户用户浏览器浏览器WEB服务器WEB服务器文件系统文件系统程序解释器程序解释器数据库服务器数据库服务器输入网址 或 点击链接 或 提交表单请求一般资源特定程序资源增、删、改、查数据结果业务处理结果资源响应得到结果

在web应用程序中,浏览器和服务器之间是通过 HTTP/HTTPS 协议来交互的。

HTTP 协议,称为超文本传输协议,HTTPS 协议,称为安全的 HTTP 协议。超文本传输协议定义了客户端与服务器端通信的规范。HTTP 是一种无状态协议,意思是服务器端在接受请求并给出响应的过程中,并没有记住客户端任何信息的规范和机制,客户端的每一次访问,对服务器端来说,客户端都是陌生的。

二、请求(Request)

请求由请求的资源地址(URL) 和请求数据段(请求头和请求体)构成。

1、URL

客户端向服务器端发出请求,是基于 URL 进行的,URL(Universal Resource Locator) 叫做统一资源定位器。

URL 的基本形式是:

  1. http://域名(或 IP 地址):端口/到资源/的具体/路径/资源名
  2. 如:
  3. http://www.mysite.com:80/products/images/computer.jpg
http
表明请求是以 http 协议发出的,要求对方也以 http 协议进行响应。
域名
在网络中的计算机是以 ip 地址作为唯一标识的。ip 是诸如: 123.156.210.87 的数字串,不便于记忆。域名与 ip 地址一一对应,便于人们记忆。

浏览器是以 IP 地址的形式发出请求的。人们输入的域名首先被浏览器发送到远程DNS(Domain Name Server)域名服务器,从那里得到对应的 IP 地址,再通过这个地址发出请求。事实上,系统在真正向 DNS 发出查询前,先会向操作系统中的一个特殊配置文件进行查询,如果查询到了对应的 IP ,就不再向 DNS 发出请求了。在 Windows 系统中,这个文件是 C:\Windows\System32\drivers\etc\hosts。在 Linux 和 Unix 系统中,这个文件是 /etc/hosts。
这个文件以如下形式定义了 IP 与 域名的对应关系:
ip            域名
如:
127.0.0.1             www.mysite.com
127.0.0.1             www.example.net
134.179.210.2      www.domywork.org

端口
一台计算机中一般有若干个程序正在与外界通信,从外界来的数据属于哪个程序的?为了区分数据的归属,每个程序在操作系统里都注册了一个号码,用于标明自己的通信身份。这个号码就叫端口号(形象比喻好像一台计算机上为每个程序开了一个通信端口)。从外界来的数据都有识别号,标明自己属于哪个程序,操作系统根据这个识别号将数据传递给同一编号的应用程序。Web服务器的 HTTP 协议的默认端口号是 80,HTTPS 协议的默认端口号为 443。
因此,对于http开头的网址,如果省略了端口部分,则默认为80号端口(向服务器发出的请求的网络数据包均会带上端口为80号的标记);对于https开头的网址,如果省略了端口部分,则默认为443端口(向服务器发出的请求的网络数据包均会带上端口为443号的标记)。
即:
http://www.myserver.com/http://www.myserver.com:80/ 相同,https://www.myserver.com/https://www.myserver.com:443/ 相同。
资源路径
Web服务器上的文件系统的一部分被作为一般资源的存储区域,这个区域从哪个文件夹(目录)开始,这个目录就叫 文档根 DocumentRoot。从文档根到请求的具体资源文件的路径,就是资源路径。例如:
如果把 D:\www\public 定为文档根,服务器域名是 www.mysite.com, 端口号是 8080,以 http 协议请求:
http://www.mysite.com:8080/products/images/computer.jpg
资源的 路径就是: /products/images/
资源在文件系统中的具体位置是:D:\www\public\products\images\
资源名
就是具体的资源文件名。

2、请求数据

请求数据段是请求的描述(请求头)和数据(请求体)的集合。
在请求描述中,最关键的是请求的行为。
请求的基本行为有 GET(获取)、POST(粘贴)、PUT(放置)、DELETE(删除)等。最为常用的是前面两者。

GET
主要目的是获取。可以携带请求的参数。如:
http://www.mysite.com:8080/user.html?first_name=Billy&last_name=Josh&actived=1
以上请求了文档根路径下的user.html资源,并向服务器传递了三对参数:first_name=Billy, last_name=Josh, actived=1。
POST
主要目的是上传数据,主要用于表单数据的提交。其提交的数据并不附着在 URL 后面,而是在请求体里(不可见)。

三、响应(Response)

响应由服务器给出。响应由响应头和响应数据构成。响应头用于描述响应。在响应头中,有关于响应的状态码。常用状态码是:

200
成功的请求​
403
禁止访问
404
请求的资源不存在
500
服务器内部错误

如果请求得到正常响应,响应数据就是具体的资源。

第三章 学习环境的搭建

一、XAMPP 开发套件的安装

XAMPP 是一套预先配置好的 Apache、MySQL、PHP 服务器软件,除服务器软件外,还提供了管理工具和调试工具等。

XAMPP 可以从 http://www.apachefriends.org/ 下载得到。

根据安装程序提示,一步一步安装即可。

二、服务器的配置

以下假定服务器安装在 D:\xampp 下。
安装完毕后,需要将以下几个路径加到系统级的环境变量 PATH 中。

  1. D:\xampp\php;D:\xampp\mysql\bin;

1、Apache

Apache 是著名的 WEB 服务器,主程序是 httpd.exe 。对它的配置主要在 D:\xampp\apache\conf\httpd.conf 中。以下是几个重要的配置项。

文档根路径

DocumentRoot 文件系统中的具体位置
如:
DocumentRoot D:/www/public

文档根路径的权限、规则等

<Directory 根路径>
配置项1
配置项2
...
</Directoey>

如:
<Directory D:/www/public>
    Options
    Allowoverride None
</Directory>

缺省资源

如果访问如下地址:
http://www.mysite.com/
这个地址只指定了文档根路径,并没有指定资源,即要这个路径下的哪个文件。此时服务器有两个选择,一是列出所有资源供选择,二是指定一个缺省资源提供给客户端。如果要指定一个缺省资源,其形式是:

DirectoryIndex 资源名称列表

如:

DirectoryIndex index.php index.html default.html default.htm

这样,当没有指定资源时,服务器会在指定的路径下按以上顺序找到某个资源,如果找到就送出,如果最终没能找到,可能会列出当前路径下的所有资源(由配置决定),或者报告错误。

2、MySQL/MariaDB

MySQL/MariaDB 是著名的数据库服务器,主程序是 mysqld。

3、PHP

PHP 是应用最为广泛的 WEB 应用服务器端编程语言。

第二部分 网页基础

第四章 网页内容的构建

网页是 Web 应用典型的用户界面(User Interface, UI)。网页文件是一个文本文件,即它是由可见字符构成的。网页文件从服务器传到浏览器后,浏览器根据网页内容渲染出图文并茂的网页界面。
网页的内容是用HTML,即 Hypertext Markup Language(超文本标记语言)来组织的,是用 CSS,即 Cascading Style Sheet 层叠样式表语言来进行布局及显示风格定义的。同时,网页中还可插入 JavaScript 语言程序,实现人与网页的互动。

4.1 HTML - 超文本标记语言

为了正确显示和布局网页中的不同内容,浏览器需要知道网页的内容构成。网页的内容构成是通过“标签”来标明的。这种通过标签来表明内容类型的语言,叫作标记语言,专用于网页内容标记的语言,就叫做“超文本标记语言”。

4.1.1 标记(Tag)的形式

超文本标记语言一般用以下形式来标记内容:

<标记>标记内容</标记>

如:<p>这是一个段落</p>

不带斜线的是开始标记,带斜线的是对应的结束标记。

有的标记没有标记内容,可把开始和结束标记写成同一个。如:

  1. <input type="text" value="" />
  2. 以及:
  3. <br />

4.1.2 标记的属性(Attribute)

标记可以属性。
如:

  1. <p id="mypara">这是一个段落</p>

其中,id 就是标记 p 的一个属性,用于标明这个标记的识别号。这个识别号在同一个文档中是唯一的。

4.2 CSS 层叠样式表语言

语言格式:

  1. 选择器 {
  2. 属性名:属性值;
  3. ...
  4. }

如以下把网页中的全部段落的首行统一缩进两个字宽,并把行距设定为字体高度的1.5倍:

  1. p {
  2. text-indent: 2em;
  3. line-height: 1.5em;
  4. }

4.3 JavaScript 语言

JavaScript 是一种编程语言,可实现人与网页的直接交互或网页与服务器的直接交互。本教程将不涉及 JavaScript 语言。

第五章 网页的基本结构与常用标签

5.1 基本结构

网页主要由要两大部分构成,一是头部(head),二是体部(body)。以下是一个网页的基本结构。

  1. <!-- 这个标记里的是注释内容,浏览器不会显示出来 -->
  2. <!doctype html> <!--说明这是一个 html 文档,并且采用了 html 语言的第 5 版本 -->
  3. <html> <!-- html 文档的开始标记 -->
  4. <head> <!-- 头部开始 -->
  5. ...
  6. </head> <!-- 头部结束 -->
  7. <body> <!-- 体部开始 -->
  8. ...
  9. </body> <!-- 体部结束 -->
  10. </html> <!-- html 文档结束 -->

5.2 头部

头部是关于网页的一些说明和外部资源链接,它们不会被显示在浏览器的窗口中。

5.3 体部

内容将显示在浏览器窗口中。

5.4 头部常用标签

5.4.1 meta

用于记录某些元数据(元数据:meta data,说明数据的数据)
如:

  1. <meta charset="utf-8">
  2. <meta name="description" content="Description of this page">
  3. <meta name="author" content="Bill Taut">
  4. <meta name="viewport" content="width=device-width, initial-scale=1.0">

用于链接外部文件内容到本文档。如:

  1. <link href="https://zybuluo.com/static/img/favicon.png" type="image/x-icon" rel="icon">
  2. <link href="https://zybuluo.com/static/assets/1bc053c8.base.lib.min.css" rel="stylesheet" media="screen">

5.4.3 title

用于定义文档标题,显示于浏览器窗口标题栏或标签页标题栏。如:

  1. <title>为什么要学PHP</title>

5.4.4 style

用于界定样式定义块。如:

  1. <style>
  2. body{
  3. font-size: 14px;
  4. }
  5. </style>

5.4.5 script

用于界定程序块或连接外部程序文件内容到本文档。
如定义程序块:

  1. <script>
  2. alert("这会显示一个消息框。")
  3. </script>

链接外部程序文件:

  1. <script src="main.js"></script>

5.5 体部常用标签

5.5.1 标题 (h1~h6)

h: headline (标题行)

  1. <h1>这是一级标题</h1>

5.5.2 段落 (p)

p: paragraph (段落)

  1. <p>
  2. 这是段落1。
  3. </p>
  4. <p>这是段落2。</p><p>这是段落3。</p>

这是段落1。

这是段落2。

这是段落3。

5.5.3 局部文字

span (跨度)

  1. 世界上最高的山峰是<span style="color:red;">珠穆朗玛峰</span>,这我是知道的。

世界上最高的山峰是珠穆朗玛峰,这我是知道的。

5.5.4 列表

ul: unordered list (无序列表)
ol: ordered list (有序列表)
li: list item (列表项)

  1. <ul>
  2. <li>列表项 1</li>
  3. <li>列表项 2</li>
  4. <li>列表项 3</li>
  5. </ul>
  1. <ol>
  2. <li>列表项 1</li>
  3. <li>列表项 2</li>
  4. <li>列表项 3</li>
  5. </ol>
  1. 列表项 1
  2. 列表项 2
  3. 列表项 3

5.5.5 表格

table: 表格
thead: table head, 表头
tbody: table body, 表体
tr: table row, 表格行
th: table head cell, 表头单元格
td: table data cell, 表格数据单元格

  1. <table>
  2. <thead>
  3. <tr>
  4. <th>序号</th>
  5. <th>姓名</th>
  6. <th>性别</th>
  7. <th>出生日期</th>
  8. <th>部门</th>
  9. </tr>
  10. <thead>
  11. <tbody>
  12. <tr>
  13. <td>1</td>
  14. <td>李明</td>
  15. <td></td>
  16. <td>1987-08-20</td>
  17. <td>人事</td>
  18. </tr>
  19. <tr>
  20. <td>2</td>
  21. <td>张小敏</td>
  22. <td></td>
  23. <td>1989-12-10</td>
  24. <td>公关</td>
  25. </tr>
  26. <tr>
  27. <td>3</td>
  28. <td>周娜</td>
  29. <td></td>
  30. <td>1990-02-10</td>
  31. <td>公关</td>
  32. </tr>
  33. </tbody>
  34. </table>
序号 姓名 性别 出生日期 部门
1 李明 1987-08-20 人事
2 张小敏 1989-12-10 公关
3 周娜 1990-02-10 公关

5.5.6 表单

form: 表单

  1. <form action="/add-contact.php" method="post">
  2. 标签和输入域
  3. </form>

5.5.7 标签

label: 标签

  1. <label for="">文字内容</label>

5.5.8 文本输入

input: 输入

  1. <input type="text" id="name" name="name" value="" />

5.5.9 密码输入

password: 密码

  1. <input type="passowrd" id="password" name="password" value=""/>

5.5.10 下拉框(单选)

  1. <select id="book" name="book">
  2. <option value="1">Java 面向对象程序设计</option>
  3. <option value="1">关系数据库基础</option>
  4. <option value="1">Git 应用基础</option>
  5. <option value="1">Linux 操作系统基础</option>
  6. <option value="1">Laravel 框加编程</option>
  7. </select>

5.5.11 下拉框(多选)

  1. <select id="book" name="book" multiple>
  2. <option value="1">Java 面向对象程序设计</option>
  3. <option value="1">关系数据库基础</option>
  4. <option value="1">Git 应用基础</option>
  5. <option value="1">Linux 操作系统基础</option>
  6. <option value="1">Laravel 框加编程</option>
  7. </select>

5.5.12 单选钮

  1. <input type="radio" name="gender" value="M" />
  2. <input type="radio" name="gender" value="F" />

5.5.13 多选框

  1. <input type="checkbox" name="hobbie" value="运动"> 运动
  2. <input type="checkbox" name="hobbie" value="阅读"> 阅读
  3. <input type="checkbox" name="hobbie" value="看电影"> 看电影
  4. <input type="checkbox" name="hobbie" value="听音乐"> 听音乐

5.5.14 日期输入

  1. 出生日期:<input type="date" value="" />

5.5.15 数值输入

  1. 数量:<input type="number" name="quantity">

5.5.16 选择文件

  1. <input type="file" name="uplaod_file" />

5.5.17 通用容器标签

div: division, 部分,区域

  1. <div class="important">
  2. <h2>Hello</h2>
  3. <p>...</p>
  4. </div>

5.5.18 图像

  1. <img src="/img/avatar.jpg" alt="avatar" />

第三部分 PHP 语言编程基础

第六章 PHP 语言介绍

6.1 PHP语言的发展历史

6.2 PHP语言的特点

6.3 PHP 语言用于网页的预处理

所谓预处理,是指 PHP 语言的程序代码是嵌入到 html 网页中的,当客户端浏览器向 Web 服务器请求一个扩展名为 .php 的网页文件时,它会被 Web 服务器交给一个叫做 PHP 语言解释器 的程序进行处理时,解释器会从头开始寻找并执行网页中的程序代码。执行完毕某段程序代码后,这段代码会被从网页中移除,如果这段代码有输出内容,则会把输出内容加入到这段代码的位置。整个网页处理完毕,所有 PHP 代码都会被移除,从而成为一个纯粹的 html 文档,此时才被 web 服务器作为响应传递到客户端浏览器进行显示。

Created with Raphaël 2.1.2用户用户浏览器浏览器WEB服务器WEB服务器文件系统文件系统PHP 解释器PHP 解释器数据库服务器数据库服务器输入网址回车 或 点击链接 或 提交表单等请求一般资源扩展名为 .php 的文件(包含 php 代码)增、删、改、查数据结果业务处理结果(纯粹的 html 文档内容)资源响应得到结果

6.4 将 PHP 语言嵌入网页中

PHP 语言的起始标记是 <?php,结束标记是 ?>,处于这对标记中的内容就是 php 语言的程序代码。

6.3 PHP 内置 Web 开发服务器

为便于开发及测试,PHP 解释器自带了一个内置的 Web 服务器。
启动这个服务器的方法是:

  1. php -S IP:端口 [-t 网站根目录]

如果 IP 为:

如果省略 -t 网站根目录,由默认当前目录为网站根目录。

动手实践

在 D:\mysite 目录下创建一个叫做 front.php 的文件,内容如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>My Site</title>
  7. </head>
  8. <body>
  9. <h1><?php echo "This is my site!" ?></h1>
  10. </body>
  11. </html>

然后启动 PHP 内置服务器,指定 D:\mysite 为网站根目录:

  1. php -S 127.0.0.1:80 -t d:\mysite

然后通过浏览器访问:
http://127.0.0.1/front.php
查看网页内容,并查看网页源代码,然后与 front.php 文件内容做比较。

echo, 英文是回声、回响的意思,在 php 中用于显示内容。

第七章 PHP 的变量、常量、数据类型以及运算

7.1 数据(data)

计算机处理的信息叫“数据”。 如:一首歌、一段影片、一个数字、一个名字、一个日期……

7.2 变量(variable)

为便于用程序处理数据,需要处理的数据会被“装”在被命名了的“容器”中,这些容器实际上是计算机内部的内存单元。这些容器就叫做“变量”(因为它们装的内容能够发生变化)。
变量是通过以下形式来定义的:

  1. // 变量名=值(数据);
  2. $name = "Billy";

执行以上代码后,$name 这个变量里就装着一个数据(一个字符构成的串——字符串):"Billy"。

变量名的命名规则:

7.3 常量(constant)

常量事实上是某个数据的“绰号”,以便于容易记住它。这个绰号代表的数据一经指定,就不能再改动,这就是常量的含义。
以下定义了一个叫做 PI 的常量,用它来代表圆周率 3.14。

  1. define('PI', 3.14);
  2. // 或者
  3. const PI = 3.14;

常量的命名规则:

7.4 数据类型

在计算机内部,所有信息数据都是用“0”和“1”的组合来表示的,为了正确处理数据,必须让计算机知道这些用“0”和“1”的组合表示的数据是什么类型。

7.4.1 字符串

字符串是以0 到多个字符构成的文字信息,如姓名、手机号码(尽管由数字构成,但没有数值上的含义)、地址等。
字符串数据用单引号或双引号来括住,如:
"张强"(双引号)
'13023561098' (单引号)
"I'm happy!"(双引号,内部可直接使用单引号作为普通字符)
'"I saw you last night." she said'(单引号,内部可直接使用双引号作为普通字符)
'I\'m happy!'(单引号,内部作为普通字符的单引号必须用 \ 符号来转义)
"\"I saw you last night\", she said"(双引号,内部作为普通字符的双引号必须用 \ 符号来转义)

  1. <?php
  2. $greeting="Hello!";
  3. echo is_string($greeting) . "<br>";
  4. echo gettype($greeting) . "<br>";
  5. var_dump($greeting);
  6. ?>

7.4.2 整数

整数数值信息,直接用数字表示,如:
123(十进制整数)
-238(十进制整数)
077(八进制整数)
0x3F0E(十六进制整数)
0b11011100(二进制整数)
12_652_000( 十进制整数,用下划线表示千分符,php 7.4.0 及以上)

  1. <?php
  2. $age=35;
  3. echo is_int($age) . "<br>";
  4. echo gettype($age) . "<br>";
  5. var_dump($age);
  6. ?>

7.4.3 小数

小数数值信息,直接用数字表示,如:
1.23
2.4e3 (
3e-8(
3_144.56( 用下划线表示千分符,php 7.4.0 及以上)

  1. <?php
  2. $length = 1.23;
  3. echo is_float($length) . "<br>";
  4. echo is_double($length) . "<br>";
  5. echo gettype($length) . "<br>";
  6. var_dump($length);
  7. ?>

7.4.4 逻辑数(布尔数)

代表两个极端的信息,“非黑即白”。只有两个标准值:
true(真)
false(假)

  1. <?php
  2. $logged = false;
  3. echo is_bool($logged) . "<br>";
  4. echo gettype($logged) . "<br>";
  5. var_dump($logged);
  6. ?>

7.4.5 数组

数组代表一组数据信息。表示方法:
[索引0=>数据0, 索引1=>数据1, 索引2=>数据2, ..., 索引n=>数据n]
或者:
[数据0, 数据1, 数据2, ..., 数据n], 此时的 索引0 默认为 0,索引1 默认为1,索引 n 默认为 n。相当于:
[0=>数据0, 1=>数据1, 2=>数据2, ..., n=>数据n]
如:
['name'=>"Billy", 'gender'=>"Male", 'age'=>28]
[100, 'abc', 12.34, false] 相当于:
[0=>100, 1=>'abc', 2=>12.34, 3=>false]

数组可以嵌套:
['name'=>'hat','colors'=>['blue','red','black']]

  1. <pre>
  2. <?php
  3. $data=[12,45,776,233];
  4. echo is_array($data) . "<br>";
  5. echo gettype($data) . "<br>";
  6. var_dump($data);
  7. print_r($data);
  8. ?>
  9. </pre>

数据中的数据用其索引名(也叫下标)来获取。

  1. <?php
  2. $colors = ['blue','red','black','white'];
  3. echo $colors[2]; // 'black'
  4. $school=['name'=>'YNTC','telephone'=>'0871-88769808','country'=>'China'];
  5. echo #school['telephone']; // '0871-88769808'
  6. $school['built_in'] = 1958;
  7. // ['name'=>'YNTC','telephone'=>'0871-88769808','country'=>'China','built_in'=>1958]
  8. ?>

7.4.6 对象

以后会讲到。

7.4.7 NULL (空值)

空值是一种特殊的数据类型,代表“没有数据”。

7.4.8 资源

以后会讲到。

7.5 数据类型的判断与数据类型的转换

7.6 PHP 的数据运算

7.6.1 算术运算

序号 运算符 数据类型 含义 举例
1 + 数值类型 相加 a+b
2 - 数值类型 相减 a-b
3 * 数值类型 相乘 a*b
4 / 数值类型 相除 a/b
5 % 数值类型 取除法余数 a%b
6 ++ 数值类型 增1 a++或++a 相当于 a = a + 1
7 -- 数值类型 减1 a--或--a 相当于 a = a - 1
8 +=,-=,*=,/= 数值类型 a+=b 相当于 a=a+b,依此类推
9 . 字符串类型 相加(相连) 'abc' . '123 结果为:'abc123'

7.6.2 比较运算

运算结果为真(true)和假(false)。

序号 运算符 含义 举例
1 > a>b
2 >= a>=b
3 < a
4 <= a<=b
5 == 不严格相等,自动转换到同一数据类型再比较 a==b (1=='1' 为真)
6 === 严格相等,数据类型和值都必须一致 a===b,(1==='1') 为假
7 !=, !== 不等于,分别对应不严格相等和严格相等 a!=b, a!==b

7.6.3 关系运算

将比较运算组合起来,运算结果为真(true)和假(false)。

序号 运算符 含义 举例 规则(1:真,0:假,*:与,+:或) 说明
1 &&/and (a>b) && (c>d) 或:
(a>b) and (c>d)
1*0=0;0*1=0;0*0=0;1*1=1 有假必假,全真才真
2 ||/or (x==y) || (z>0) 或:
(x==y) or (z>0)
1+0=1;0+1=1;0+0=0;1+1=1 有真必真,全假才假
3 ! !x, !(a>=b) !0=1; !1=0 取反

第八章 PHP 的基本语句

8.1 表达式、语句和语句块

8.1.1 表达式

表达式是一个算式,求得一个结果。如:
, , , ...

8.1.2 语句

语句是程序的最小执行单元,是构成程序的基本元素。一个语句用";(分号)"号结束,但以语句块结束的语句不需要用“;”结尾。

8.1.3 语句块

语句块是用一对花括号{ }括起来的零条到多条语句,语句块是封闭的,外面“看”不到它内部的数据(变量),而它可以“看”到外部的数据(变量)。

8.2 流程控制语句

8.2.1 条件判断语句

根据条件执行相应代码。
格式:

  1. // 语句一
  2. if(条件表达式){
  3. ...
  4. }
  5. // 语句二:
  6. if(条件表达式){
  7. ...
  8. }
  9. else{
  10. ...
  11. }
  12. // 语句三:
  13. if(条件表达式1){
  14. ...
  15. }
  16. else if(条件表达式2){
  17. ...
  18. }
  19. else if(条件表达式3){
  20. ...
  21. }
  22. ...
  23. else{
  24. ...
  25. }
  26. // 语句四(条件赋值):
  27. 变量 = 条件表达式 ? 1(或表达式1 : 2(或表达式2);
  28. // 语句四相当于:
  29. if(条件表达式){
  30. 变量 = 1(或表达式1);
  31. }
  32. else{
  33. 变量 = 2(或表达式2);
  34. }

动手环节
input-name.php

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>输入姓名</title>
  7. </head>
  8. <body>
  9. <form action="greeting.php" method="get">
  10. 请输入您的姓名:
  11. <input type="text" name="name">
  12. <input type="submit" value="提交">
  13. </form>
  14. </body>
  15. </html>

greeting.php

  1. <?php
  2. $timing = "";
  3. // getdate() 返回关于日期时间的数组。
  4. $hour = getdate()['hours'];
  5. if($hour>0 && $hour<=12){
  6. $timing="早上";
  7. }
  8. else if($hour>12 && $hour<=18){
  9. $timing="下午";
  10. }
  11. else{
  12. $timing="晚上";
  13. }
  14. $name = "";
  15. // $_GET, $_POST, $_REQUEST
  16. // $_GET 数组装着 get 过来的表单数据
  17. // $_POST 数组装着 post 过来的表单数据
  18. // $_REQUEST 数组装着 get 和 post 过来的表单数据
  19. // isset(变量) 函数用于判断变量是否存在
  20. if(isset($_REQUEST['name'])){
  21. $name = $_REQUEST['name'];
  22. }
  23. if($name==""){
  24. $name = "我的朋友";
  25. }
  26. ?>
  27. <!DOCTYPE html>
  28. <html lang="en">
  29. <head>
  30. <meta charset="UTF-8">
  31. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  32. <title>来自服务器的问候</title>
  33. </head>
  34. <body>
  35. <p>当前日期时间:<?php echo date("Y年m月d日 H时i分s秒") ?></p>
  36. <p><?php echo $timing ?>好, <?php echo $name ?>!</p>
  37. <a href="input-name.php">重新输入姓名</a>
  38. </body>
  39. </html>

8.2.2 switch 语句

根据变量取值执行相应代码。
格式:

  1. switch(变量){
  2. case 1// 如果变量的值==值1
  3. ...
  4. [break]; // 跳出语句块
  5. case 2
  6. ...
  7. [break];
  8. case 3
  9. ...
  10. [break];
  11. ...
  12. default:
  13. ...
  14. }

特点:
只要与某个取值相同,其后的 case 和 default 下的所有语句都会被顺序执行,除非碰到一个 break 语句而直接跳出语句块。

动手环节
input-season.php

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>输入季节</title>
  7. </head>
  8. <body>
  9. <form action="about-season.php" method="get">
  10. 请输入您喜欢的季节:
  11. <input type="text" name="season">
  12. <input type="submit" value="提交">
  13. </form>
  14. </body>
  15. </html>

about-seasion.php

  1. <?php
  2. $season_str = isset($_REQUEST['season'])? $_REQUEST['season'] : '';
  3. $season = mb_substr($season_str,0,1);
  4. $message = '';
  5. switch($season){
  6. case '春':
  7. $message = "我也喜欢{$season_str},因为此时是全年最舒服的季节!";
  8. break;
  9. case '夏':
  10. $message = "我也喜欢{$season_str},因为此时我可以去游泳了!";
  11. break;
  12. case '秋':
  13. $message = "我也喜欢{$season_str},因为此时市场上到处都是水果!";
  14. break;
  15. case '冬':
  16. $message = "我不太喜欢{$season_str},因为此时我真不想出门!";
  17. break;
  18. default:
  19. $message = "请告诉我您喜欢的季节!";
  20. }
  21. ?>
  22. <!DOCTYPE html>
  23. <html lang="en">
  24. <head>
  25. <meta charset="UTF-8">
  26. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  27. <title>关于季节</title>
  28. </head>
  29. <body>
  30. <p>您输入了:<?php echo $season_str ?></p>
  31. <p><?php echo $message ?></p>
  32. </body>
  33. </html>

训练说明
请将程序中的全部或部分 break 删除,观察程序执行效果。

8.2.3 while 语句

根据条件进行循环操作(先检测条件)。

  1. while(条件表达式){
  2. ...
  3. }

举例:

  1. php > $i=10;
  2. php > while($i>0){echo $i."\n"; $i--;}
  3. 10
  4. 9
  5. 8
  6. 7
  7. 6
  8. 5
  9. 4
  10. 3
  11. 2
  12. 1
  13. php >

8.2.4 do ... while 语句

根据条件进行循环操作(后检测条件)。

  1. do {
  2. ...
  3. } while(条件表达式);

举例:

  1. php > $i=10;
  2. php > do {echo $i . "\n"; $i--;} while($i>0);
  3. 10
  4. 9
  5. 8
  6. 7
  7. 6
  8. 5
  9. 4
  10. 3
  11. 2
  12. 1
  13. php >

比较:

  1. php > $i=0;
  2. php > do {echo $i . "\n"; $i--;} while($i>0);
  3. 0 //做了一次!
  4. php >

8.2.5 for 语句

设置初值、条件及步进,在满足条件的情况下循环操作。

  1. for(变量=初值; 条件; 步进){
  2. ...
  3. }

如:

  1. for($idx=0; $idx<100; $idx++){
  2. ...
  3. }
  4. //相当于:
  5. $idx=0;
  6. while($idx<100){
  7. ...
  8. $idx = $idx + 1; // 或:$idx ++;
  9. }

8.2.6 foreach 语句

针对数组元素进行循环操作。

  1. foreach(数组 as 键=>值){
  2. // 处理键和值
  3. }
  4. // 或:
  5. foreach(数组 as 值){
  6. // 处理值
  7. }

8.2.7 continue, break 和 return 语句

1、continue
continue 用于结束本次循环操作(语句块内的后续语句不再执行),回头进行下一次循环。
2、break
break 用于结束本次操作(语句块内的后续语句不再执行),跳出并结束循环。
3、return
用在函数中,结束函数的执行(函数中的后续语句不再执行),并返回指定的结果(不指定则返回NULL)。

8.3 PHP的错误处理

8.3.1 引发错误

语句:

  1. throw new Exception("错误信息")

8.3.1 错误的捕捉与处理

try {} catch() {} finally{} 进行异常处理(参见PHP异常处理
举例:

  1. function getSoldPrice($price,$rate){
  2. if(!is_numeric($price) || !is_numeric($rate)){
  3. throw new Exception("两个参数都必须是合法的数字!");
  4. }
  5. return $price * $rate;
  6. }
  7. try{
  8. actualPrice = getSoldPrice(1200,'1abc');
  9. }
  10. catch(Exception $e){
  11. echo $e->getMessage();
  12. }
  13. finally{
  14. echo "无论如何,此句都会被执行。";
  15. }

第九章 PHP 的字符串操作

9.1 对字符串操作的重要意义

字符串是 PHP 中处理的重要数据类型之一。

9.2 获取字符串的相关信息

9.2.1 获取字符串的长度

strlen(字符串) 返回字符串的字节数
mb_strlen(字符串,[字符编码=内部编码]) 返回特定编码的字符串的字符数

  1. php > echo strlen('IT');
  2. 2
  3. php > echo mb_strlen('IT');
  4. 2
  5. php > echo strlen('信息技术');
  6. 12
  7. php > echo mb_strlen('信息技术');
  8. 4

9.2.2 字符串与子字符串的相关操作

9.2.3 判断字符串始于或终于某个字符串

strpos(字符串1,字符串2,[开始位置=0]) 返回从开始位置(没有设置则从头开始)以后,字符串2第一次出现在字符串1中的位置(从0开始的位置序号)。可用此函数判断某个字符串是否以某些字符开头。

  1. php > echo strpos('信息技术','信息')===0? 'Yes':'No';
  2. Yes
  3. php >

9.2.4 正则表达式

9.2.5 数据校验

第十章 PHP 的数组操作

10.1 对数组操作的重要意义

数组是数据集合,是 PHP 中重要的数据类型之一。

10.2 数组结构

10.3 数组操作

10.3.1 数组元素个数

10.3.2 数组元素的添加与移除

1、头部添加

  1. array_unshift(数组,元素1,元素2,...);
  2. // 函数返回添加的元素个数

2、尾部添加

  1. array_push(数组,元素1,元素2,...);
  2. // 函数返回添加的元素个数
  3. // 如果只在数组变量$array尾部添加一个元素,最有效的方法是:
  4. $array[] = 要添加的元素;

3、内部插入
无专门函数,可用 array_slice 结合 array_merge 实现。
也可用 array_splice 函数实现,但不能保留原键名。

4、头部移除
5、尾部移除
6、内部移除

10.3.3 数组的切分与合并

10.3.4 是否在数组中

10.3.5 数组排序

数组中的每一项数据叫做数组元素,每一个数组元素由一对数据构成:“键=>值”,其中的“键”(key)用于说明值的位置序号(整数)或名称(字符串),“值”(key)是对应的数据。如果没有指明“键”,则会自动为数据指定位置序号,从“0”开始。
数组是可以嵌套的,即数组的元素本身也可以是数组。
为了查看数组的数据内容,可用 print_r(数组变量) 函数来显示数组内容。

10.4 遍历数组中的元素

可用以下两种形式遍历数组元素。

  1. // 以位置索引为键的数组
  2. for($i=0; $i<count($arrar); $i++){
  3. // 处理 $array[i]
  4. }
  5. // 或:
  6. foreach($array as $key=>$value){
  7. // 处理 $key 或 $value
  8. }
  9. // 也可以不要键
  10. foreach($array as $value){
  11. // 处理 $value
  12. }

第十一章 PHP 面向对象编程

11.1 什么是面向对象编程

在面向对象的编程中,把一切涉及的事物都看作是“活体”,它们具有自己的属性和行为。事务的管理就是通过这些“活体”的交互来完成的。比如:一张“发票”具有“开票日期”、“开票人”、“客户名称”、“所购商品列表”等属性,同时,它也具有往自己的“所购商品列表”中增加、修改和删除商品项的行为、具有说出自己的总额的行为等。

11.2 类和对象

  1. <?php
  2. //类定义
  3. class Invoice {
  4. //----- 属性 --------
  5. public $date = null;
  6. public $operator = "";
  7. public $customer = "";
  8. public $items = [];
  9. //----- 方法 --------
  10. //构造函数
  11. function __construct($date,$op,$cust){
  12. $this->date = $date;
  13. $this->operator = $op;
  14. $this->customer = $cust;
  15. }
  16. function addItem(item){
  17. $this->items[] = item;
  18. }
  19. function removeItem(id){
  20. foreach($this->items as $key=>$item){
  21. if($item['id']==id){
  22. array_split($this->items,$key,1);
  23. }
  24. }
  25. }
  26. function getSum(){
  27. foreach($this->items as $key=>$item){
  28. }
  29. }
  30. //生成对象 (调用__construct构造函数)
  31. $inv = new Invoice("2020-10-10","Ben","Tina"); // $inv 为一个 Invoice 类的对象(也叫实例)
  32. ?>

11.3 封装、继承、多态

11.3.1 封装

可使用 public、protected、private 来修饰对象的属性和方法。
使用不同修饰符的属性和方法其可被访问的权限也不同:

  1. <?php
  2. class Employee {
  3. private $id;
  4. private $name;
  5. public function __construct($id,$name){
  6. $this->id = $id;
  7. $this->name = $name;
  8. }
  9. public function getId(){
  10. return $this->id;
  11. }
  12. public function getName(){
  13. return $this->name;
  14. }
  15. }
  16. $e = new Employee(1,'Ben');
  17. echo $e->name; // 错误,无权直接读取私有属性
  18. echo $e->getName() . "\n"; // 正确,方法为公有,可访问,并得到 name
  19. ?>

11.3.2 继承

如果声明一个类继承(extend)自另一个类,这个类叫做被继承类的子类,而被继承的类叫父类。因为继承,子类不用声明和定义就具有了父类的属性和方法,子类也可有自己额外定义的属性和方法。
类的继承使用关键词extends,在子类中可使用parent访问父类的方法。在子类中可重写父类的方法。
PHP的继承为单继承,即一个类只能继承自一个父类。
一个类可以继承自:

普通类

普通类所有方法均有具体实现。

  1. <?php
  2. class Vehicle {
  3. public $name;
  4. public $brand;
  5. public function __construct($name, $brand){
  6. $this->name = $name;
  7. $this->brand = $brand;
  8. }
  9. public function description(){
  10. return "This vehicle name is: " . $this->name . " and brand is: " . $this->brand . ".";
  11. }
  12. }
  13. class Car extends Vehicle {
  14. public $seat_count;
  15. public function __construct($name, $brand, $seat_count){
  16. parent::__construct($name, $brand);
  17. $this->seat_count = $seat_count;
  18. }
  19. }
  20. $car = new Car('CRV','HONDA',5);
  21. echo $car->description() . " Seat count is: " . $car->seat_count . "\n";
抽象类

抽象类有的方法没有具体实现(抽象方法),如果子类要成为普通类,必须实现那些抽象方法,否则自己也必须是抽象类。

  1. <?php
  2. abstract class Shape {
  3. public function desc(){
  4. return "I'm a ". get_class($this) . ".";
  5. }
  6. public abstract function calcArea(); // 抽象方法没有函数体!
  7. }
  8. class Circle extends Shape {
  9. public $radius=0;
  10. public function calcArea(){
  11. return $this->radius * $this->radius * 3.14;
  12. }
  13. }
  14. $shape = new Shape(); // 错误:抽象类不能实例化,即不能产生对象
  15. $circle = new Circle();
  16. $circle->radius = 10;
  17. echo $circle->desc() . " My area is: " . $circle->calcArea();
接口

接口相当于所有方法都没有具体实现的抽象类。和类不同,接口能继承另一个和多个其它接口,一个类也可“继承”(称为实现:implements)一个或多个接口。由于声明实现了某个接口的普通类必须实现接口的所有方法,因此,接口就成为了一种“契约”。

  1. <?php
  2. interface CanFly {
  3. function fly();
  4. }
  5. interface CanWalk {
  6. function walk();
  7. }
  8. class FlyingDragon implements CanFly, CanWalk {
  9. public function fly(){
  10. // ...
  11. }
  12. public function walk(){
  13. // ...
  14. }
  15. }

11.3.3 多态

继承自相同父类并重写父类方法(或实现相同接口)的子类,相同的方法表现的行为不一样,称为多态。多态使得同一类别的对象的相同方法具有了不同的行为,使编程的灵活性大大增加。

  1. <?php
  2. interface Output {
  3. function out($content);
  4. }
  5. class Screen implements Output{
  6. public function out($content){
  7. echo $content;
  8. }
  9. }
  10. class File implements Output {
  11. public function out($content){
  12. // save to file
  13. echo "Content have saved to a file.";
  14. }
  15. }
  16. class Content {
  17. public $content;
  18. public $output
  19. // 参数 $output 为一个具有out方法的对象
  20. public function __construct($content,$output){
  21. $this->content = $content;
  22. $this->output = $output;
  23. }
  24. public function output(){
  25. $this->output->out($this->content);
  26. }
  27. }
  28. $content = new Content("Hello world!",new Screen());
  29. $content->output();
  30. $content = new Content("Hello world!",new File());
  31. $content->output();

11.4 面向对象编程举例

第十二章 PHP 的数据库操作及数据在页面的呈现

12.1 PDO 类介绍

PHP 的PDO(数据对象) 扩展为PHP访问数据库定义了一个轻量级的一致接口。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。
PDO 和所有主要的驱动作为共享扩展随 PHP 一起发布,要激活它们只需简单地编辑 php.ini 文件,并添加以下扩展:

  1. extension=php_pdo.dll

除此之外还有以下对应的各种数据库扩展:

  1. ;extension=php_pdo_firebird.dll
  2. ;extension=php_pdo_informix.dll
  3. ;extension=php_pdo_mssql.dll
  4. ;extension=php_pdo_mysql.dll
  5. ;extension=php_pdo_oci.dll
  6. ;extension=php_pdo_oci8.dll
  7. ;extension=php_pdo_odbc.dll
  8. ;extension=php_pdo_pgsql.dll
  9. ;extension=php_pdo_sqlite.dll

12.2 数据库连接

12.2.1 建立连接

PDO类的一个实例代表一个数据库连接。以下是创建一个PDO实例连接MySQL数据库的例子:

  1. <?php
  2. //Data Source Name (DSN)的PDO命名惯例为:PDO驱动程序的名称,后面为一个冒号,再后面是可选的驱动程序连接数据库变量信息,如主机名、端口和数据库名。
  3. $dsn = 'mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4';
  4. $user = 'dbuser';
  5. $password = 'dbpass';
  6. $options = [
  7. PDO::ATTR_EMULATE_PREPARES => false, // 关闭仿真模式,采用真实模式的prepare
  8. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //采用例外错误模式
  9. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 以数组方式获取记录
  10. PDO::ATTR_PERSISTENT => true, // 为相同的$user保持连接,避免每次重新连接
  11. ];
  12. try {
  13. $conn = new PDO($dsn, $user, $password, $options);
  14. } catch (Exception $e) {
  15. error_log($e->getMessage()); //将错误记录到日志,供技术人员参考
  16. exit('连接数据库时发生错误!'); //输出用户能够理解的错误信息
  17. }

12.2.2 关闭连接

将PDO实例变量设为 null(以及其它所有参照此实例的变量设为null),可关闭连接。否则,当脚本结束时会自动关闭。如果希望相同用户多次使用相同连接(脚本结束时不关闭连接),需要在建立连接时在选项中传入:PDO::ATTR_PERSISTENT => true

12.3 数据的增、删、改、查

12.3.1 使用 PDO::exec() 和 PDO::query()

执行一条非select查询语句:

  1. PDO::exec(语句)

函数返回受影响的记录数。
插入记录

  1. $name = "Printer";
  2. $brand = "Epson";
  3. $row_count = $conn->exec("insert into products(name,brand) values('$name','$brand')");
  4. $insertedId = $conn->lastInsertId(); //获取新插入的记录主键。

修改记录

  1. $increased = 10;
  2. $row_count = $conn->exec("update employees set salary=salary+$increased");

删除记录

  1. $id = 109;
  2. $row_count = $conn->exec("delete from employees where id=$id");

查询记录
格式:

  1. PDO::query(语句)

函数返回结果集(PDOStatement对象)。
如:

  1. $employees = $conn->query("select * from employees");
  2. for($row = $employees->fetch()){
  3. echo $row["id"] . "<br>";
  4. ...
  5. }

注意:使用以上语句如果不对数据做任何处理,直接将客户端输入的数据嵌入SQL
语句中,是极不安全的,可能受到 SQL注入攻击!

SQL 注入攻击:黑客将特定字符嵌入SQL语句中,实现数据的盗取或破坏。

SQL注入攻击实例1:破坏数据

  1. $id = "1 or 1=1"; // 此值来自客户端黑客的输入
  2. $conn->exec("delete from employees where id=$id");
  3. //执行的SQL: delete from employees where id=1 or 1=1; 表中记录将被全部删除!

SQL注入攻击实例2:登录系统

  1. $username = "haha"; // 此值来自客户端黑客的输入
  2. $password = "hehe' or '1=1"; // 此值来自客户端黑客的输入
  3. $user = $conn->query("select * from users where username='$username' and password='$password'")->fetch();
  4. if($user){
  5. // 登录成功
  6. }
  7. //执行的SQL: select * from users where username='haha' and password='hehe' or '1=1'; 结果会以uses表中第一个用户的身份登录成功!

12.3.2 使用 PDO::prepare() 和 PDOStatement::execute()

PDO::prepare(sql) 和 PDOStatement::execute([选项])配合使用能够提高查询效率和查询安全性(避免SQL
注入攻击)。
插入记录

  1. //使用占位符
  2. $stmt = $conn->prepare("insert into products(name,brand) values(?,?)");
  3. $stmt->execute([$_POST['name'],$_POST['brand']])
  4. // 或者,使用命名参数:
  5. $stmt = $conn->prepare("insert into products(name,brand) values(:name,:brand)");
  6. $stmt->execute([':name'=>$_POST['name'],':brand'=>$_POST['brand']]) //此句中的:name 和 :brand 前面的冒号可省略。最佳实践:保留。
  7. $insertedId = $conn->lastInsertId(); //获取新插入的记录主键。

修改记录

  1. //使用占位符
  2. $stmt = $conn->prepare("update products set price=? where id=?");
  3. $stmt->execute([$_POST['price'],$_POST['id']])
  4. // 或者,使用命名参数:
  5. $stmt = $conn->prepare("update products set price=:price where id=:id");
  6. $stmt->execute([':price'=>$_POST['price'],':id'=>$_POST['id']]) //此句中的:price 和 :id 前面的冒号可省略。最佳实践:保留。

删除记录

  1. //使用占位符
  2. $stmt = $conn->prepare("delete from products where id=?");
  3. $stmt->execute([$_POST['id'])
  4. // 或者,使用命名参数:
  5. $stmt = $conn->prepare("delete from products where id=:id");
  6. $stmt->execute([':id'=>$_POST['id']]) //此句中的 :id 前面的冒号可省略。最佳实践:保留。

查询记录

  1. //使用占位符
  2. $stmt = $conn->prepare("select * from users where username=? and password=?");
  3. $stmt->execute([$_POST['username'],$_POST['password'])
  4. // 或者,使用命名参数:
  5. $stmt = $conn->prepare(""select * from users where username=? and password=?"");
  6. $stmt->execute([':username'=>$_POST['username'],'password'=>$_POST['password']]) //此句中的 :username 和 :password 前面的冒号可省略。最佳实践:保留。

12.4 PDO的错误处理

在使用PDO处理数据时,应当对可能出现的错误进行捕获并处理。以下是一个典型的含错误处理的代码。

  1. try {
  2. $stmt = $pdo->prepare("INSERT INTO persons (name, age) VALUES (?, ?)");
  3. if(!$stmt->execute(['李明', 18])) throw new Exception('Statement Failed');
  4. $stmt = null;
  5. $stmt = $pdo->prepare("SELECT * FROM products WHERE price > ?");
  6. if(!$stmt->execute([500])) throw new Exception('Statement Failed');
  7. $arr = $stmt->fetchAll();
  8. $stmt = null;
  9. //以下操作包含在一个事务(Transaction)中
  10. try {
  11. $pdo->beginTransaction(); //开始事务
  12. $stmt1 = $pdo->prepare("INSERT INTO persons (name, province) VALUES (?, ?)");
  13. $stmt2 = $pdo->prepare("UPDATE persons SET age = ? WHERE id = ?");
  14. if(!$stmt1->execute(['王晓', '云南'])) throw new Exception('Stmt 1 Failed');
  15. else if(!$stmt2->execute([27, 139])) throw new Exception('Stmt 2 Failed');
  16. $stmt1 = null;
  17. $stmt2 = null;
  18. $pdo->commit(); //提交事务
  19. } catch(Exception $e) {
  20. $pdo->rollback(); //回滚事务
  21. throw $e; //再次抛出
  22. }
  23. } catch(Exception $e) {
  24. error_log($e);
  25. exit('数据库操作出现错误!');
  26. }

问题:
1、如何获取新插入记录的主键(自动增长型)?
2、如何获得DELETE/UPDATE/INSERT语句所影响的行数?SELECT呢?

12.5 数据在页面的呈现

12.5.1 单个数据呈现

单个数据的呈现,用<?php 产生输出的语句 ?><?php echo 变量或表达式 ?>的方式进行。
按条件呈现单个数据:

  1. ...
  2. <?php if(isset($user_name)){ ?>
  3. <div><?php echo $user_name ?></div>
  4. <?php } else { ?>
  5. <div><?php echo "未登录" ?>
  6. <?php } ?>
  7. ...

12.5.2 集合数据呈现

集合数据的呈现,结合循环与单个数据呈现进行。
以下代码在一个表格中显示数据(来自数组)。

  1. ...
  2. <table>
  3. <thead>
  4. <tr>
  5. <th>编号</th>
  6. <th>姓名</th>
  7. <th>性别</th>
  8. <th>手机</th>
  9. <th>电邮</th>
  10. </tr>
  11. </thead>
  12. <tbody>
  13. <?php foreach($contacts as $contact){ ?>
  14. <tr>
  15. <td><?php echo $contact["id"] ?></td>
  16. <td><?php echo $contact["name"] ?></td>
  17. <td><?php echo $contact["gender"] ?></td>
  18. <td><?php echo $contact["mobile"] ?></td>
  19. <td><?php echo $contact["email"] ?></td>
  20. </tr>
  21. <?php } ?>
  22. </tbody>
  23. </table>
  24. ...

[编程实例] 将联系人从数据库中按查询条件读出,并显示在页面上。并利用PDO::prepare()和PDOStatement::execute()对表中数据进行维护操作(增、删、改)。
(1)数据库脚本:

  1. drop database if exists `contact_db`;
  2. create database `contact_db` default charset utf8;
  3. use contact_db;
  4. create table `contacts`(
  5. `id` int not null auto_increment,
  6. `name` varchar(50) not null,
  7. `gender` char(1) not null,
  8. `mobile` char(11) not null,
  9. `email` varchar(100),
  10. primary key(`id`)
  11. unique key(`email`)
  12. );
  13. insert into `contacts`
  14. values
  15. (null,'王丹丹','女','13987965732','wdd@theserver.com'),
  16. (null,'李权','男','18987657899','lquan@theserver.com'),
  17. (null,'周敏敏','女','13887879412','zmmin@theserver.com'),
  18. (null,'王强生','男','13389701265','wqsh@theserver.com'),
  19. (null,'周吾','男','18987876783','zhouwu@theserver.com'),
  20. (null,'李中明','男','18997851256','lizm@theserver.com'),
  21. (null,'赵周怀','男','13089018765','zzhuai@theserver.com'),
  22. (null,'吴涵','女','18787542389','wuhan@theserver.com'),
  23. (null,'郑芸','女','18987998754','zhyun@theserver.com'),
  24. (null,'吴佳妮','女','18987658899','wujn@theserver.com')
  25. ;

(2)数据查询
根据关键字查找姓名或电话中包含关键字的记录。
(3)数据维护
添加一条记录到表中;修改符合条件的记录;删除符合条件的记录。

13.1 会话(Session)

会话是一种用于在服务器端“记住”用户的技术(因 HTTP 协议是一种无状态协议,没有记住用户的机制)。它的基本原理是:为每一个客户端连接建立一个身份编号(会话ID),以此ID为标记在服务器端记录用户的相关状态数据(如:用户身份、权限等),然后将此 ID 交给浏览器保存,每次浏览器访问服务器时自动带上此 ID 作为自己的身份标记,以便让服务器识别自己。

Cookie 是一种在浏览器中保存网站相关数据的技术。服务器可要求浏览器记住某些信息,在下次访问浏览器时将这些信息带到服务器。Session 技术就是用 Cookie 在浏览器中记住自己的 ID 的。

[编程实例] 利用 Session 记住登录用户,并利用 Cookie 在浏览器端记住用户名和密码(当用户需要时)。只有登录用户才能访问首页 index.php,否则会被导向 login.php 页面。

第十四章 PHP 标准规范与代码组织

14.1 PSR(PHP Standard Recommandation)

参阅 《PHP PSR 标准规范》

14.2 Composer

PHP的项目依赖包管理工具。访问官网

第四部分 开发案例:联系人管理

第十五章 需求与总体设计

15.1 需求说明

数据信息:

  1. drop database if exists `contact_db`;
  2. create database if not exists `contact_db` default charset utf8mb4;
  3. use `contact_db`;
  4. create table `contacts`(
  5. `id` int unsigned not null auto_increment,
  6. `name` varchar(50) not null,
  7. `gender` char(1) not null check(`gender` in ('男','女')),
  8. `birth_date` date null,
  9. `mobile` varchar(30) unique,
  10. `email` varchar(100) unique,
  11. primary key (`id`)
  12. );
  13. create table `users`(
  14. `username` varchar(30) not null,
  15. `password` char(40) not null,
  16. `real_name` varchar(50) not null,
  17. primary key (`username`)
  18. );
  19. insert into `contacts`
  20. values
  21. (1,'李会盟','男','1980-12-23','13009761265','lhm123@theserver.com'),
  22. (2,'张容湘','男','1986-09-18','18787679432','zhangrx@theserver.com'),
  23. (3,'赵睿','女','1990-01-25','13108979877','zhaomin@theserver.com'),
  24. (4,'王艳艳','女','1998-12-12','15982548799','wyy1212@theserver.com'),
  25. (5,'李想','女','1995-03-20','18087876752','lixiang@theserver.com'),
  26. (6,'张洋','男','1978-06-30','18928671113','zhangy@theserver.com'),
  27. (7,'王小小','女','1997-10-28','13031769877','wxx1028@theserver.com'),
  28. (8,'李维','男','1990-01-11','18987872266','liwei@theserver.com'),
  29. (9,'赵明','男','1980-04-12','18787092187','zhaoming@theserver.com'),
  30. (10,'王小璐','女','1999-12-31','13187465177','wangxiaolu@theserver.com')
  31. ;
  32. insert into `users`
  33. values
  34. ('xiaolu','90e5082e0e77f4e4f25877b13df17e3d4379601e','王小璐'),
  35. ('liwei','73e0ca73bc3fb8c697c9838af683decc7d7365e9','李维')
  36. ;
  37. drop user if exists contact_db_user@localhost;
  38. create user if not exists contact_db_user@localhost
  39. identified by '000000';
  40. grant all privileges on contact_db.* to contact_db_user@localhost;
  41. flush privileges;

登录用户能够增删改查联系人数据。

15.2 页面流程图

第十六章 UI设计

16.1 登录页面

login.php

  1. <?php
  2. session_start();
  3. ?>
  4. <!doctype html>
  5. <html lang="en">
  6. <head>
  7. <meta charset="UTF-8">
  8. <meta name="viewport"
  9. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  10. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  11. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  12. <title>Document</title>
  13. <style>
  14. form {
  15. width: 300px;
  16. position: absolute;
  17. top: 50%;
  18. left: 50%;
  19. transform: translate(-50%,-80%);
  20. }
  21. h1{
  22. font-size: 2rem;
  23. text-align: center;
  24. }
  25. .error{
  26. color: red;
  27. }
  28. </style>
  29. </head>
  30. <body>
  31. <div class="container">
  32. <form action="do-login.php" method="post">
  33. <h1>请登录</h1>
  34. <div class="form-group">
  35. <label for="username">用户名*</label>
  36. <input type="text" class="form-control" id="username" name="username" value="<?php echo isset($_SESSION["old"]["username"])? $_SESSION["old"]["username"]:"" ?>">
  37. <p class="error username"><?php echo isset($_SESSION["username_error"])?$_SESSION["username_error"]:"" ?></p>
  38. </div>
  39. <div class="form-group">
  40. <label for="password">密码*</label>
  41. <input type="password" class="form-control" id="password" name="password">
  42. <p class="error password"><?php echo isset($_SESSION["password_error"])?$_SESSION["password_error"]:""?></p>
  43. </div>
  44. <div class="form-group form-check">
  45. <input type="checkbox" class="form-check-input" id="remeber-me">
  46. <label class="form-check-label" for="remeber-me" style="user-select: none">记住我</label>
  47. </div>
  48. <p class="error"><?php echo isset($_SESSION["login_error"])? $_SESSION["login_error"]:"" ?></p>
  49. <button type="submit" class="btn btn-primary">登录</button>
  50. </form>
  51. </div>
  52. <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
  53. <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
  54. <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
  55. </body>
  56. </html>

do-login.php

  1. <?php
  2. session_start();
  3. require_once "db.php";
  4. $_SESSION["username_error"] = "";
  5. $_SESSION["password_error"] = "";
  6. $_SESSION["login_error"] = "";
  7. $username = isset($_POST["username"])? trim($_POST['username']):"";
  8. $password = isset($_POST["password"])? trim($_POST["password"]):"";
  9. $_SESSION["old"]["username"] = $username;
  10. $_SESSION["old"]["passowrd"] = $password;
  11. if($username==="" or $password===""){
  12. $_SESSION["username_error"] = $username===""? "用户名不能为空!":"";
  13. $_SESSION["password_error"] = $password===""? "密码不能为空!":"";
  14. header("Location: login.php");
  15. exit();
  16. }
  17. $user = null;
  18. try{
  19. $stmt = $db->prepare("select * from users where username=?");
  20. $stmt->execute([$username]);
  21. $user = $stmt->fetchObject();
  22. if($user){
  23. if(!password_verify($password,$user->password)){
  24. $user = null;
  25. }
  26. else{
  27. $_SESSION['login_user'] = $user;
  28. header("Location: index.php");
  29. exit();
  30. }
  31. }
  32. }catch (Exception $e){
  33. echo $e->getMessage();
  34. }
  35. $_SESSION["login_error"] = "用户名或密码错误!";
  36. header("Location: login.php");

logout.php

  1. <?php
  2. session_start();
  3. session_destroy();
  4. header("Location: login.php");

db.php

  1. <?php
  2. $db=null;
  3. try {
  4. $db = new PDO("mysql:host=127.0.0.1;dbname=contact_db;charset=utf8mb4", 'contact_db_user', '000000');
  5. }
  6. catch(Exception $e){
  7. echo $e->getMessage(); // 调试使用
  8. echo "连接数据库失败,请联系有关人员或稍后再试。";
  9. exit();
  10. }

16.2 联系人列表页面

index.php

  1. <?php
  2. session_start(); //打开 Session!
  3. if(!isset($_SESSION['login_user'])){
  4. header("Location: login.php");
  5. exit();
  6. }
  7. ?>
  8. <!doctype html>
  9. <html lang="en">
  10. <head>
  11. <meta charset="UTF-8">
  12. <meta name="viewport"
  13. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  14. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  15. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  16. <title>联系人列表</title>
  17. </head>
  18. <body>
  19. <div class="container">
  20. <a href="logout.php">退出登录</a>
  21. <h1>联系人列表</h1>
  22. </div>
  23. <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
  24. <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
  25. <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
  26. </body>
  27. </html>

16.3 新增联系人页面

16.4 编辑联系人页面

第十七章 功能实现:登录与退出系统

17.1 登录系统

17.2 退出系统

第十八章 功能实现:联系人列表(分页)与搜索联系人

18.1 获取联系人(分页)

18.2 将联系人展现在页面上

18.3 搜索联系人

第十九章 功能实现:新增、编辑和删除联系人

19.1 数据校验

19.2 照片处理

19.3 保存数据到数据库

19.4 删除联系人

第二十章 把应用部署到服务器

20.1 安装和配置 Web 服务器

20.2 安装和配置 PHP

20.3 安装和配置数据库服务器

20.4 部署应用

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注