web侠客行(十六)--PHP开发步骤教学

大致思路

要做前后端通讯的系统,首先要有需求和设计,包括前端UI,前后端通讯使用技术,后端架构与数据库。做好这些工作以后开始开发。

前端

虽然流行用vue,但是从模板网站上很容易得到类似模板,稍微改动一下即可使用。

搭建HBuilder工作环境

从模板之家下载四款登录页,挑一款开始工作。
选择 cpts_1121_brc 这一款。HBuilder建项目,名为EIS,把包中的内容拷贝到HBuilder项目目录下。

访问测试,能通了以后,开始改造。

企业网站meta的用例

meta标签的作用。

metadata 中文名叫做元数据,是用于描述数据的数据,他不会显示在页面上,但是机器可以识别,常用于定义页面的说明,关键字,最后修改日期,和其他信息,这些信息存储于浏览器,如何布局或者重新加载页面。搜索引擎和其他服务。

logo和title

改logo和title

1
2
<title>恒生软件EIS系统</title>
<link rel="shortcut icon" href="images/恒生软件logo.jpg" type="image/x-icon" />

html页面中文

英文改中文

1
<html lang="zh-cmn-Hans">

某些浏览器不支持,直接用 zh

1
<html lang="zh">

字符格式

设置字符编码

1
<meta charset="UTF-8">

组成meta标签共有两个属性,分别是http-equiv属性和name属性。

name属性

name属性主要用于描述网页,比如网页的关键词,叙述等。与之对应的属性值为content,content中的内容是对name填入类型的具体描述,便于搜索引擎抓取。

keywords(关键字)

说明:用于告诉搜索引擎,你网页的关键字。举例:

1
<meta name="keywords" content="恒生软件,建站,软件开发,小程序开发,APP开发">

description(网站内容的描述)

说明:用于告诉搜索引擎,网站的主要内容。举例:

1
<meta name="description" content="恒生软件EIS系统">

viewport(移动端的窗口)

说明:这个属性常用于设计移动端网页。在用bootstrap,AmazeUI等框架时候都有用过viewport。

举例(常用范例):

1
<meta name="viewport" content="width=device-width, initial-scale=1">

robots(定义搜索引擎爬虫的索引方式)

说明:robots用来告诉爬虫哪些页面需要索引,哪些页面不需要索引。content的参数有all,none,index,noindex,follow,nofollow。默认是all。

举例:

1
<meta name="robots" content="none">

具体参数如下:

  1. none : 搜索引擎将忽略此网页,等价于noindex,nofollow。
  2. noindex : 搜索引擎不索引此网页。
  3. nofollow: 搜索引擎不继续通过此网页的链接索引搜索其它的网页。
  4. all : 搜索引擎将索引此网页与继续通过此网页的链接索引,等价于index,follow。
  5. index : 搜索引擎索引此网页。
  6. follow : 搜索引擎继续通过此网页的链接索引搜索其它的网页。

author(作者)

说明:用于标注网页作者举例:

1
<meta name="author" content="恒生软件,hundsunsoft@126.com">

generator(网页制作软件)

说明:用于标明网页是什么软件做的举例:

1
<meta name="generator" content="html5 css3 js">

说明:用于标注版权信息举例:

1
<meta name="copyright" content="粤ICP备18013766号">

revisit-after(搜索引擎爬虫重访时间)

说明:如果页面不是经常更新,为了减轻搜索引擎爬虫对服务器带来的压力,可以设置一个爬虫的重访时间。如果重访时间过短,爬虫将按它们定义的默认时间来访问。举例:

1
<meta name="revisit-after" content="30 days" >

renderer(双核浏览器渲染方式)

说明:renderer是为双核浏览器准备的,用于指定双核浏览器默认以何种方式渲染页面。比如说360浏览器。举例:

1
2
3
<meta name="renderer" content="webkit"> //默认webkit内核
<meta name="renderer" content="ie-comp"> //默认IE兼容模式
<meta name="renderer" content="ie-stand"> //默认IE标准模式

http-equiv属性

http-equiv顾名思义,相当于http的文件头作用。

content-Type(设定网页字符集)(推荐使用HTML5的方式)

说明:用于设定网页字符集,便于浏览器解析与渲染页面举例:

1
2
3
4
5
//旧的HTML,不推荐
<meta http-equiv="content-Type" content="text/html;charset=utf-8">

//HTML5设定网页字符集的方式,推荐使用UTF-8
<meta charset="utf-8">

X-UA-Compatible(浏览器采取何种版本渲染当前页面)

说明:用于告知浏览器以何种版本来渲染页面。(一般都设置为最新模式,在各大框架中这个设置也很常见。)举例:

1
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> //指定IE和Chrome使用最新版本渲染当前页面

cache-control(指定请求和响应遵循的缓存机制)

用法1.
说明:指导浏览器如何缓存某个响应以及缓存多长时间。
举例:

1
<meta http-equiv="cache-control" content="no-cache">

共有以下几种用法:

  1. no-cache: 先发送请求,与服务器确认该资源是否被更改,如果未被更改,则使用缓存。
  2. no-store: 不允许缓存,每次都要去服务器上,下载完整的响应。(安全措施)
  3. public : 缓存所有响应,但并非必须。因为max-age也可以做到相同效果
  4. private : 只为单个用户缓存,因此不允许任何中继进行缓存。(比如说CDN就不允许缓存private的响应)
  5. maxage : 表示当前请求开始,该响应在多久内能被缓存和重用,而不去服务器重新请求。例如:max-age=60表示响应可以再缓存和重用 60 秒。

用法2.(禁止百度自动转码)
说明:用于禁止当前页面在移动端浏览时,被百度自动转码。虽然百度的本意是好的,但是转码效果很多时候却不尽人意。所以可以在head中加入例子中的那句话,就可以避免百度自动转码了。举例:

1
<meta http-equiv="Cache-Control" content="no-siteapp" />

expires(网页到期时间)

说明:用于设定网页的到期时间,过期后网页必须到服务器上重新传输。举例:

1
<meta http-equiv="expires" content="Sunday 26 October 2016 01:00 GMT" />

refresh(自动刷新并指向某页面)

说明:网页将在设定的时间内,自动刷新并调向设定的网址。举例:

1
<meta http-equiv="refresh" content="2;URL=https://www.baidu.com/"> //意思是2秒后跳转

说明:如果网页过期。那么这个网页存在本地的cookies也会被自动删除。

1
2
3
<meta http-equiv="Set-Cookie" content="name, date"> //格式

<meta http-equiv="Set-Cookie" content="User=Lxxyx; path=/; expires=Sunday, 10-Jan-16 10:00:00 GMT"> //具体范例

企业网站实例

1
2
3
4
5
6
7
8
9
10
11
12
13
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="恒生软件EIS系统">
<meta name="keywords" content="恒生软件,建站,软件开发,小程序开发,APP开发">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="author" content="恒生软件,hundsunsoft@126.com">
<meta name="copyright" content="粤ICP备18013766号">
<title>恒生软件EIS系统</title>
<meta name="renderer" content="webkit">
<meta http-equiv="Pragma" content="no-cache" />
<link rel="shortcut icon" href="images/恒生软件logo.jpg" type="image/x-icon" />
</head>

页面主体

再找一个模板做页面主体。twts_153_MaterialAdmin

改head

包括编码,设备,关键字,描述,标题,作者,图标

1
2
3
4
5
6
7
8
9
10
11
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="恒生软件EIS系统">
<meta name="keywords" content="恒生软件,建站,软件开发,小程序开发,APP开发">
<meta name="author" content="恒生软件,hundsunsoft@126.com">
<meta name="copyright" content="粤ICP备18013766号">
<title>恒生软件EIS系统</title>
<meta name="renderer" content="webkit">
<meta http-equiv="Pragma" content="no-cache" />
<link rel="shortcut icon" href="images/恒生软件logo.ico" type="image/x-icon" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

阻止网页复制及F12

1
2
3
4
5
6
7
8
9
10
11
12
13
<script language="Javascript">
document.oncontextmenu=new Function("event.returnValue=false");
document.onselectstart=new Function("event.returnValue=false");
</script>
<script type="text/javascript">
document.onkeydown = function () {
if (window.event && window.event.keyCode == 123) {
event.keyCode = 0;
event.returnValue = false;
return false;
}
};
</script>

改UI及其form表单

action=””代表调用自己,即访问本页面不跳转,主要是改form表单,把表单内容用form括起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<form method="post" action="">										  
<section class="mdc-card__primary">
<h1 class="mdc-card__title mdc-card__title--large">选择产品</h1>
</section>
<section class="mdc-card__supporting-text" >
<div class="template-demo">
<div id="hero-js-select" class="mdc-select" role="listbox" >
<div class="mdc-select__surface" tabindex="0">
<div class="mdc-select__label">选择一款产品</div>
<div class="mdc-select__selected-text"></div>
<div class="mdc-select__bottom-line"></div>
</div>
<div class="mdc-simple-menu mdc-select__menu">
<ul class="mdc-list mdc-simple-menu__items">
<li class="mdc-list-item" role="option" tabindex="0">
手机壳
</li>
<li class="mdc-list-item" role="option" tabindex="0">
尾插
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fruit
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Milk, Yogurt, and Cheese
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fats, Oils, and Sweets
</li>
</ul>
</div>
</div>
</div>
</section>
<section class="mdc-card__supporting-text">
<div class="mdc-layout-grid__inner">
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-4-desktop">
<div class="template-demo">
<div id="demo-tf-box-wrapper">
<div id="tf-box-example" class="mdc-text-field mdc-text-field--box w-100">
<input type="text" id="tf-box" class="mdc-text-field__input" aria-controls="name-validation-message" name="prodtype">
<label for="tf-box" class="mdc-text-field__label">产品型号</label>
<div class="mdc-text-field__bottom-line"></div>
</div>
</div>
</div>
</div>
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-4-desktop">
<div class="template-demo">
<div id="demo-tf-box-leading-wrapper">
<div id="tf-box-leading-example" class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon w-100">
<i class="material-icons mdc-text-field__icon" tabindex="0">event</i>
<input type="text" id="tf-box-leading" class="mdc-text-field__input">
<label for="tf-box-leading" class="mdc-text-field__label">查询起始日期</label>
<div class="mdc-text-field__bottom-line"></div>
</div>
</div>
</div>
</div>
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-4-desktop">
<div class="template-demo">
<div id="demo-tf-box-leading-wrapper">
<div id="tf-box-leading-example" class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon w-100">
<i class="material-icons mdc-text-field__icon" tabindex="0">event</i>
<input type="text" id="tf-box-leading" class="mdc-text-field__input">
<label for="tf-box-leading" class="mdc-text-field__label">查询截止日期</label>
<div class="mdc-text-field__bottom-line"></div>
</div>
</div>
</div>
</div>
<!-- 第二排 -->
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-4-desktop">
<div class="template-demo">
<div id="demo-tf-box-wrapper">
<div id="tf-box-example" class="mdc-text-field mdc-text-field--box w-100">
<input type="text" id="tf-box" class="mdc-text-field__input" aria-controls="name-validation-message">
<label for="tf-box" class="mdc-text-field__label">库存</label>
<div class="mdc-text-field__bottom-line"></div>
</div>
<!-- <p class="mdc-text-field-helper-text mdc-text-field-helper-text--validation-msg" id="name-validation-msg">
Must be at least 8 characters
</p> -->
</div>
</div>
</div>
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-4-desktop">
<div class="template-demo">
<input class="mdc-button mdc-button--raised" name="select" type="submit" value="查询">
</div>
</div>
</div>
</section>
</form>

PHP部分

启动apache和mysql

直接双击 Wampserver64 启动即可。

php默认端口80,默认应用路径 www 。

mysql默认端口3306,默认用户 root,默认密码 空 。

mysql建库

建库默认编码为utf8

1
CREATE DATABASE eisdb character set utf8;

mysql建用户并给予权限

1
2
GRANT ALL ON eisdb.* TO 'eisuser'@'localhost' IDENTIFIED BY 'Difficult_password1234';
GRANT ALL ON eisdb.* TO 'eisuser'@'%' IDENTIFIED BY 'Difficult_password1234';

mysql建表

利用工具MySql Workbench建表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CREATE TABLE `cust_info` (
`cust_id` INT AUTO_INCREMENT NOT NULL COMMENT '客户ID',
`cust_name` VARCHAR(45) NOT NULL COMMENT '客户姓名',
`cust_cname` VARCHAR(45) NULL COMMENT '别名',
`unit_name` VARCHAR(60) NULL COMMENT '工作单位',
`busi_type` VARCHAR(40) NULL COMMENT '客户所属行业',
`addr` VARCHAR(200) NULL COMMENT '地址',
`phone` VARCHAR(11) NULL COMMENT '联系电话',
`open_date` VARCHAR(20) NULL COMMENT '登记日期',
`cust_state` VARCHAR(20) NULL COMMENT '客户状态:\nactive - 活跃\nno-active - 非活跃\nno-contract - 失联',
`last_tran_date` VARCHAR(20) NULL COMMENT '最后交易日期',
`last_tran_amt` DECIMAL(16,2) NULL COMMENT '最后交易金额',
`last_tran_order` VARCHAR(40) NULL COMMENT '最后交易订单',
`last_tran_info` VARCHAR(200) NULL COMMENT '最后交易信息',
`contract` VARCHAR(45) NULL COMMENT '其他联系方式',
`info` VARCHAR(200) NULL COMMENT '说明',
`remark1` VARCHAR(45) NULL COMMENT '备注1',
`remakr2` VARCHAR(45) NULL COMMENT '备注2',
PRIMARY KEY (`cust_id`));

测试数据库中文可用性

1
2
insert into cust_info (cust_name) values ('小明');
select * from cust_info;

数据库部分结束。

改写html为php

首先,把html格式改名为php结尾。

先测试一个最简单的php,看服务可用性

welcome.php

1
2
3
<?php
echo "hello world";
?>

再来个稍微复杂的php
welcome.php

1
2
3
4
5
6
7
8
<?php
echo "hello world";
?>

<br>

欢迎<?php echo $_POST["fname"]; ?>!<br>
你的年龄是 <?php echo $_POST["age"]; ?> 岁。

写静态php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
function insert() {
$x = 100.00;
echo '<tr>';
echo '<td class="text-left">热干面</td>';
echo '<td>';
echo $x;
echo '</td>';
echo '<td>haha</td>';
echo '<td>haha</td>';
echo '<td>haha</td>';
echo '<td>haha</td>';
echo '<td>haha</td>';
echo '<td>haha</td>';
echo '<td>haha</td>';
}
if(isset($_POST['prodtype'])){
insert();
}
?>

写MYSQL查询部分

数据库连接,写在最开始,并且指定数据库不可用时,跳转404。

特别关注设置数据库编码。

这里不关闭数据库,mysqli_close($conn); 为了避免一会还需要重连数据库查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
$servername = "localhost";
$username = "eisuser";
$password = "Difficult_password1234";
$dbname = "eisdb";

// 创建连接
$conn = mysqli_connect($servername, $username, $password, $dbname);
mysqli_query($conn, "set names 'utf8'");//这就是指定数据库字符集,一般放在连接数据库后面就系了

// 检测连接
if (!$conn) {
// 连接数据库失败跳404
header("Location: ./pages/samples/404.html");
//确保重定向后,后续代码不会被执行
exit;
} else {
echo "连接成功";
}

?>

测试查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$sql = "SELECT cust_id, cust_name FROM cust_info";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
// 输出数据
while($row = mysqli_fetch_assoc($result)) {
echo "id: " . $row["cust_id"]. " - Name: " . $row["cust_name"]. "<br>";
}
} else {
echo "0 结果";
}

mysqli_close($conn);
?>

顺便建一张产品表,还是用mysql workbench

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE TABLE `eisdb`.`product_info` (
`product_id` INT NOT NULL AUTO_INCREMENT COMMENT '产品ID',
`product_name` VARCHAR(45) NOT NULL COMMENT '产品名称',
`product_type` VARCHAR(45) NULL COMMENT '产品类型',
`product_belong` VARCHAR(45) NULL COMMENT '产品所属',
`cust_id` VARCHAR(45) NULL COMMENT '关联客户ID',
`product_credate` DATETIME NULL COMMENT '产品创建日期',
`product_desc` VARCHAR(200) NULL COMMENT '产品描述',
`unit` VARCHAR(20) NULL COMMENT '产品单位',
`price` DECIMAL(16,2) NULL COMMENT '产品售价',
`cost` DECIMAL(16,2) NULL COMMENT '产品成本',
`transport_cost` DECIMAL(16,2) NULL COMMENT '产品运费',
`tax_rate` DECIMAL(16,2) NULL COMMENT '税率',
`valid_date` DATETIME NULL COMMENT '有效期至',
`product_state` VARCHAR(45) NULL COMMENT '产品状态:online-在产; offline-停产;',
`info` VARCHAR(200) NULL COMMENT '产品信息',
`remark1` VARCHAR(45) NULL COMMENT '备注1',
`remark2` VARCHAR(45) NULL COMMENT '备注2',
PRIMARY KEY (`product_id`))
COMMENT = '产品信息表';

插入数据:

产品信息表

1
2
INSERT INTO `eisdb`.`product_info` (`product_id`, `product_name`, `product_type`, `product_belong`, `cust_id`, `product_credate`, `product_desc`, `unit`, `price`, `cost`, `transport_cost`, `tax_rate`, `valid_date`, `product_state`) VALUES ('1', '手机壳', '小米', '恒生软件', '1', '2019-01-01 12:00:00', '磨砂', '个', '10.00', '2.00', '1.00', '0.00', '2999-12-31', 'ONLINE');
INSERT INTO `eisdb`.`product_info` (`product_id`, `product_name`, `product_type`, `product_belong`, `cust_id`, `product_credate`, `product_desc`, `unit`, `price`, `cost`, `transport_cost`, `tax_rate`, `valid_date`, `product_state`) VALUES ('2', '尾插', '苹果', '恒生电子', '2', '2019-06-08 14:00:00', 'IPHONE 4', '箱', '10000.00', '200.00', '10.00', '0.00', '3999-12-31', 'ONLINE');

产品库存表

1
2
INSERT INTO `eisdb`.`product_inven` (`product_id`, `product_name`, `unit`, `num`, `sold_num`, `transport_fee`, `profit`) VALUES ('1', '手机壳', '个', '100', '20', '10.00', '500.00');
INSERT INTO `eisdb`.`product_inven` (`product_id`, `product_name`, `unit`, `num`, `sold_num`, `transport_fee`, `profit`) VALUES ('2', '尾插', '袋', '10', '2', '20.00', '20000.00');

改写动态php

静态php改为动态php,查询数据库返回列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$sql = "select a.product_name, a.cost, b.sold_num, b.transport_fee, b.profit, 0, b.num, 0 as ret from product_info a left join product_inven b on a.product_id = b.product_id";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
// 输出数据
while($row = mysqli_fetch_assoc($result)) {
echo '<tr>';
echo '<td class="text-left">'.$row["product_name"].'</td>';
echo '<td>'.$row["cost"].'</td>';
echo '<td>'.$row["sold_num"].'</td>';
echo '<td>'.$row["transport_fee"].'</td>';
echo '<td>'.$row["sold_num"].'</td>';
echo '<td>'.$row["profit"].'</td>';
echo '<td>'.$row["num"].'</td>';
echo '<td>'.$row["ret"].'</td>';
echo '<td><div class="col mdc-button" data-mdc-auto-init="MDCRipple"><i class="mdi mdi-heart text-blue"></i></div><div class="col mdc-button" data-mdc-auto-init="MDCRipple"><i class="mdi mdi-forum text-yellow"></i></div><div class="col mdc-button" data-mdc-auto-init="MDCRipple"><i class="mdi mdi-delete text-red"></i></div></td>';
echo '</tr>';
}
} else {
}

mysqli_close($conn);
?>

php图片上传

action不写,默认服务器自身

1
2
3
4
5
6
<form enctype="multipart/form-data" method="post" name="upform">
上传文件:
<input name="upfile" type="file">
<input type="submit" value="上传"><br>
允许上传的文件类型为:<?=implode(', ',$uptypes)?>
</form>

服务器的 PHP 临时文件夹中创建了一个被上传文件的临时副本。这个临时的副本文件会在脚本结束时消失。要保存被上传的文件,我们需要把它拷贝到另外的位置。

1
2


安装gd库

1
yum install php-gd

验证安装

1
var_dump(gd_info());
-->