php start 一

1.1 PHP简介

1.1.1 概述

PHP是Hypertext Preprocessor的缩写,(超文本预处理器)是一种在服务器端运行的开源的脚本语言.
LAMP组合(Linux,Apache,Mysql,PHP),这四个产品都是公开源代码的产品.

php是一门语言,用来做业务逻辑
apache为php提供了运行环境
linux为Apache的运行提供了平台,
mysql数据库用来存储数据

多学一招:什么是wamp组合

windows+apache+mysql+php

1.1.2 五个基本概念

1.静态页面和动态页面

静态页面:服务器不执行的页面
动态页面:服务器执行的页面

2.客户端和服务器端

浏览者是客户端
服务器端:给浏览者提供服务

3.端口和端口号 端口号范围:0-65535
4. BS架构和CS架构
BS:通过浏览器去访问服务器

b:browser(浏览器)
s:server(服务器)
优点:
1.只要有浏览器就可以访问
2.开发低
缺点:
1.开发的代码都在服务器上  胖服务器-瘦客户端

所有的web都是BS架构
CS:通过客户端软件去访问服务器

c:client(客户端)
s:server(服务端)
优点:
1.开发服务端和服务器端,这时候就可以实现负载的均衡
缺点:
1.必须安装一个软件才能去访问
2.开发成本高

5.前台和后台

前台:浏览器看到的界面
后台:管理员看到的界面

1.1.3 PHP的优点

1.跨平台,既能在windows上运行,也能在linux上运行.
2.源码开放,不会涉及版权问题.
3.语法简单:php入门简单.
4.运行在服务器端,只要在服务器部署环境就可以了.

1.2 搭建web服务器

1.2.1 安装phpstudy

直接解压即可,安装路径不能含有中文和空格

1.2.2 访问服务器

在www虚拟目录下创建demo.php

<?php
phpinfo();

访问服务器

f访问规则:http://服务器ip地址/php页面
比如:
http://localhost/demo.php
http:127.0.0.1/demo.php

1.2.3 互联网通讯原理

本质一台电脑访问另一个电脑资源\寻址过程(ip地址,端口,域名,DNS)
在互联网上,ip地址是用来区分每台计算机的标识,但是ip记忆不友好,我们将ip地址取一个名字,一个ip对应一个名字,这个名字就称为域名.
步骤:
1.客户端输入域名(网址),在最近的机房做DNS解析(Domain Name Server),DNS解析就是将域名转化成ip地址
2.通过ip地址访问服务器
小结:本机 c盘下hosta文件用来做DNS解析

1.3 语法

1.3.1 注释

//单行注释
# 单行注释
/**/多行注释

1.3.2 php的输出语句

echo:输出
print:输出,输出成功返回1
print_r():输出数组
var_dump():输出数据,并且带有数据类型和数据长度
<?php
	var_dump('abc'); //string(3) "abc"
?>

1.3.3 定义常量

1.用define()函数定义常量

define(常量名,值,是否区别大小写)  true表示不区分大小写,默认false

2.常量名前没有$符
3.常量名推荐使用大写
4.定义常量可以用特殊字符,但是调用的时候必须使用constant关键字调用
5.常量一旦定义,不能再重新定义,所以在定义常量的时候要先用defined函数判断此常量是否存在.

<?php
define('NAME','tom');
echo NAME;
?>

define('&_&','tom');
echo constant('&_&');//通过constant获取特殊字符作为常量名的常量

6.判断常量是否定义,通过defined()判断常量是否已经定义.

if(!defined('NAME')){
	define('NAME','berry');
}
echo NAME;

7.还可以使用const 关键字定义常量

const NAME='tom';
echo NAME;

1.3.4 预定义常量

//php中内置的
echo PHP_VERSION,'<br>';//php版本号
echo PHP_OS,'<br>';//php操作系统
echo PHP_INT_MAX,'<br>';//php中整型的最大值

1.3.5 魔术常量

php向它运行的任何脚本提供了大量的预定义变量,不过很多常量都是由不同的扩展定义的,只有加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了.
有七个魔术常量他们的值随着它们在代码中的位置改变而改变.例如__LINE__的值就依赖于它在脚本中所处的行来决定.这些特殊的常量不区分大小写,如下:

echo __LINE__;//获取当前行号
echo __FILE__;//获取文件的完整路径和文件名
echo __DIR__;//获取文件所在的目录

1.3.6 变量

小结
1.参数的传递有两种,值传递和地址传递
2.&表示获取变量的地址
3.值传递中,一个变量变了,另一个变量没有影响,因为是两个空间
4.地址传递中,一个变量变了,另一个也变了,因为两个变量指向同一个空间.

1.3.7 销毁变量

用unset()来销毁变量,销毁的是变量名,变量值由PHP垃圾回收机制销毁

<?php
$num1=10;
$num2=&$num1;
unset($num1);//销毁的是变量名
echo $num2;//10
?>

1.4 数据类型

数据类型有两种:强类型和弱类型
PHP是弱类型

1.4.1 基本类型(标量类型)

1.整型
存整数,PHP_INT_MAX获取整形最大值.
PHP支持8,10,16进制的整数
2.浮点型
3.字符串
4.布尔型

1.4.2 复合类型

1.数组
在PHP中数组有两种形式,索引数组和关联数组
索引数组:用整数做下标,默认从0开始,后面的依次加一
关联数组:用字符串做下标,通过=>符号将下标和值关联起来
例题:数组的声明

//1.索引数组的声明
$stu=array('tom','berry','ketty');//索引数组
print_r($stu);//输出数组 Array([0]=>tom [1]=>berry [2]=>ketty)
echo '<hr>';
echo $stu[0],'<br>';//tom
echo $stu[1],'<br>';//berry 
echo $stu[2],'<br>';//ketty
//2.关联数组
$emp=array('name'=>'李白','sex'=>'男','age'=>22);
print_r($emp);//Array([name]=>李白 [sex]=>男 [age]=>22)
echo '<hr>';
echo $stu['name'],'<br>';//李白 
echo $stu['sex'],'<br>';//男
echo $stu['age'],'<br>';//22

1.5运算符

1.5.1 逻辑运算符

& 与:运算符两边的表达式都要计算
! 或:运算符两边的表达式都要计算

&& 短路与:如果前面的条件不满足,后面的条件就不用计算了
|| 短路或
! 非

例题

>?php
$a=5;
$b=10;
if($a>10&&++$a>20){
	echo '你好吗'
}
echo $a;//5
?>

1.5.2 null合并运算符(??)

<?php 
echo $name??''姓名不详;//姓名不详

多学一招:

isset():判断变量是否被设置,并且设置的不是null
empty():检查一个变量是否为空,能转成false全部是空

其他

<?php 
if(isset($_POST['button'])){
	switch($_POST['color']){
		case '1':
		$color='#FF0000';//红色
		break;
		case '1':
		$color='#009900';//绿色
		break;
		case '1':
		$color='#0000FF';//蓝色
		break;
		default:
		$color='#000000';//黑色
	}
	echo <<<str
	<script type="text/javascript">
	window.οnlοad=function(){
		document.getElementById('shi').style.color='$color';
	}
	</script>
str;
}
?>

上面代码涉及知识点
1.从服务器端php代码返回html及js
2.输出多行字符串并带变量KaTeX parse error: Expected 'EOF', got '#' at position 94: …识别. 3.颜色16进制问题,#̲后面两位代表红色中间两位代表绿…_POST获取本次post请求表单发送的内容
此外 php中的判断 多重条件判断elseif中间没有空格

1.6 循环

for ,while,do while,foreach

<?php 
for($i=1;$i<=10;$i++){
	fro($j=1;$j<=$i;$j++){
		echo $j.'&nbsp;';//变量后加.表示字符串连接符号 相当于js中的+,因为php中加减乘除等运算符只能用于数学运算
		if($j===5){
			break 2;//中断2重for循环
		}
	}
	echo '<br>';
}
?>

例题
1.如下代码循环了几次?

for($i=1;$i!=5;$i++){

}
//循环了4次

2.在循环N次循环体中,初始值执行了几次?条件执行了几次?增量执行了几次?

初始值执行了1次
条件执行了N+1次
增量执行了N

3.在循环执行完毕后,$i的值是存在的。

<?php
for($i=1;$i<=3;$i++){
}
echo $i;//4

1.6.2 while、do-while

语法

while(条件){

}
---------------------
do{

}while(条件)

小结:
1、for、while、do-while可以相互替换
2、如果明确知道循环多少次首先for循环,如果要循环到条件不成立为止选while或do-while
3、先判断再执行选while,先执行再判断选do-while
4、while循环条件不成立就不执行,do-while至少执行一次

例题
1、使用三种循环实现1加到100

<?php
//1.for循环实现
$sum=0;
for($i=1;$i<=100;$i++){
	$sum+=$i;//$sum=$sum+$i;
}
echo $sum;
//分析
/*
$i    $sum
1      1
2		1+2
3		1+2+3
4		1+2+3+4
...
100		1+2+3+...+100	
*/
----------------
//2.while循环
$i=1;
$sum=0;//保存和
while($i<=100){
	//方法一
	/*
	$sum+=$i;
	$i++;
	*/
	//方法二
	$sum+=$i++;
}
echo $sum
---------------------
//3.do-while循环
$i=1;
$sum=0;
do{
	$sum+=$i++;//++后置
}while($i<=100); 
echo $sum,'<br>';//5050
//可以做如下更改
$i=1;
$sum=0;
do{
	$sum+=$i;
}while(++$i<=100);//++前置
echo $sum,'<br>';

小结:
1、for、while、do-while可以相互替换
2、结合++前置和++后置考虑逻辑
++前置是先加再赋值 ++后置先赋值再加

1.6.3 多语句表达式

初始值、增量可以由多条语句组成
例题:数字分解

<?php
for($i=1,$j=9;$i<=$j;$i++,$j--){
	echo "10可以分成{$i}和${j}<br>";
}
//运行结果
/*
10 可以分成1和9
10 可以分成2和8
10 可以分成3和7
10 可以分成4和6
10 可以分成5和5
*/

小结:初始值、增量可以写多个表达式,但是条件一般只有一个,如果条件写多个,只有最后一个条件起作用

1.6.4 双重循环

1.打印阶梯数字

<?php
for($i=1;$i<=9;$i++){//循环行
	for($j=1;$j<=$i;$j++){//循环列
		echo $j,'&nbsp;';
	}
	echo '<br>';
}
//运行结果
1
1 2
1 2 3
...
1 2 3 4 5 6 7 8 9

2.打印九九乘法表

<style type="text/css">
table{
	width:980px;
}
table,td{
	border:solid 1px #0000FF;
	border-collapse:collapse;
}
td{
	height:40px;
}
</style>
<table>
<?php
for($i=1;$i<=9;$i++){//行
	echo '<tr>';
	for($j=1;$j<=$i;$j++){
		echo "<td>{$j}*{$i}=".($j*$i).'</td>';
	}
	echo '</tr>';
}
?>
<table>

1.6.5 return

终止脚本执行

echo '锄禾日当午<br>';
return; //终止脚本执行
echo '汗滴禾下土<br>';//不执行

提醒:return 只能中断当前页面,如果有包含文件,只能中断包含文件
例题:
6-demo.php

<?php
echo '锄禾日当午<br>';
require './test.php';//包含文件
echo '锄禾日当午<br>';

test.php

<?php
echo 'aaa<br>';
return;//只能中断test.php
echo 'bbb<br>';

如果要完全终止脚本执行,使用exit()、或者die()

echo 'aaa<br>';
exit();//die()
echo 'bbb<br>';

1.6.6 返回页面结果

test.php

<?php
return array('name'=>'tom','sex'=>'男');

6-demo.php

<?php
$stu=require './test.php';
print_r($stu); //Array([name]=>tom [sex]=>'男')

小结:在项目中引入配置文件就使用这种方法

1.6.7 函数的返回和终止

return 在函数中使用作用有二
1.终止函数执行
2.返回值

1.6.8 foreach语法

//语法一
foreach(数组 as){}
//语法二
foreach(数组 as=》值){}

例题:

<?php
$stu=['tom','berry','ketty'];
foreach($stu as $v){
	echo $v,'<br>';
}
/*
tom
berry
ketty
*/
echo '<hr>';
foreach($stu as $k=>$v){
	echo "{$k}:{$v}<br>";
}
/*
0:tom
1:berry
2:ketty
*/
?>

1.6.9 跳转语句

break:中断循环
continue:中断当前循环,进入下一个循环
switch的本质是循环了一次的循环

for($i=1;$i<=10;$i++){
	echo "{$i}:锄禾日当午<br>";
	if($i==5)
		break;
}

1.6.10 替代语法

php中除了do-while以外,其他的语法结构都有替代语法
规则:左大括号变冒号,右大括号变endxxx
if的替代语法

//if的替代语法
if():

elseif():

else:

endif;
//switch替代语法
switch():

endswitch;

//for
for():

endfor;

//while
while():

endwhile;
//foreach():
foreach():

endforeach;

例题:在混编的时候用替代语法

<body>
<?php
for($i=1;$i<=10;$i++){
	if($i%2===0):
}
?>
<?php echo $i;?>:锄禾日当午<br>
<?php
endif;

endfor;
?>
</body>
//运行结果
2:锄禾日当午
4:锄禾日当午
6:锄禾日当午
8:锄禾日当午
10:锄禾日当午

小结:可以通过替代语法证明else if 之间如果有空格是嵌套if语句。

<?php
$score=80;
if($score>=90):
	echo 'A';
elseif($score>=80)://elseif之间没有空格,如果有空格是嵌套if语句
	echo 'B';
else:
	echo 'C';
endif;

----------------------------
<?php 
$score=80;
if($score>=90):
	echo 'A';
else:
	if($score>=80):
		echo 'B';
	else:
		echo 'C';
?>

1.7 函数

1.函数就是一段代码块
2.函数可以实现模块化编程

1.7.1 函数定义

function 函数名(参数1,参数2...{
	//函数体
}

通过函数名()调用函数

//定义函数
function show(){
	echo '锄禾日当午';
}
//调用
show(); //锄禾日当午
SHOW();//锄禾日当午  //函数名不区分大小写

小结:
1.变量名区分大小写
2.关键字、函数名不区分大小写

1.7.2 可变函数

将函数名存储到变量中

function show($args){
	echo $args,'<br>';
}
$str='show';//将函数名保存到变量中
$str('锄禾日当午');

例题

<?php
function showChinse(){
	echo '锄禾日当午';
}
function showEnglish(){
	echo 'chu he ri dang wu ';
}
//测试
$fun=rand(1,10)%2?'showChinese':'showEnglish'; //可变变量
$fun();

1.7.3 匿名函数

匿名函数就是没有名字的函数

<?php
//匿名函数
$fun=function(){
	echo '锄禾日当午';
};
//匿名函数调用
$fun();

1.7.4 参数传递

函数的参数有形式参数和实际参数
形式参数是定义函数时候的参数,只起形式的作用,没有具体的值
实际参数的调用函数时候的参数,有具体的值

function fun($num1,$num2){
	echo $num1+$num2;
}
fun(10,20);//30

1.默认情况下,函数的传递是值传递
2.如果要传递地址,在参数前面加&
3.如果是地址传递,不能直接写值

function fun(&$args){
	$args=100;
}
fun(10);//报错不能直接写值
<?php
$num=10;
function fun($args){
	$args=100;
}
fun($num);
echo $num;//10
?>

地址传递

<?php
$num=10;
function fun(&$args){
	$args=100;
}
fun($num);
echo $num;//100
?>

1.7.5 参数默认值

1.在定义函数的时候给形参赋值就是参数的默认值

function fun($name,$add='地址不详'){
	echo '姓名:'.$name,'<br>';
	echo '地址:'.$add,'<hr>';
}
//测试
fun('tom','北京');
fun('berry');

2.默认值必须是值,不能用变量代替

$str="地址不详";
function fun($name,$add=$str){//错误,默认值不可以使用变量
	echo '姓名:'.$name,'<br>';
	echo '地址:'.$add,'<hr>';
}

3.默认值可以使用常量

define('ADD','地址不详');
function fun($name,$add=ADD){
	echo '姓名:'.$name,'<br>';
	echo '地址:'.$add,'<hr>';
}
//测试
fun('berry');

4.有默认值的写在后面,没有默认值的写在前面

function fun($name,$age='未知',$add='地址不详'){
	echo '姓名:'.$name,'<br>';
	echo '年龄:'.$age,'<br>';
	echo '地址:'.$add,'<hr>';
}
//测试
fun('berry');
function fun($num1,$num2){
	echo $num1,'<br>';
	echo $num2,'<br>';
}
//fun(10);//实参少于形参(报错)
fun(10,20,30);//实参多余形参,只取前面对应的值
function fun(){
	echo func_num_args();//获取参数的个数
	$args=func_get_args();//获取参数数组
	print_r($args);
}
fun(10);
fun(10,20);
fun(10,20,30);

1.7.6 参数约束

1.定义变长参数

function fun($name,$age,...$hobby){
	echo '姓名:'.$name,'<br>';
	echo '年龄:'.$age,'<br>';
	print_r($hobby);
	echo '<hr>';
}
fun('tom',22);
fun('berry',25,'读书','睡觉')

---------------------
function fun(...$args){
	print_r($args);
	echo '<br>'
}
$num=[10];
$num[]=[10,20];
echo '<pre>'
fun(...$num);//将数组中的参数展开
  1. 参数类型约束
function fun(string $name,int $age){
	echo "姓名:{$name},'<br>'";
	echo "年龄:{$age}<br>";
}
fun('tom',22);
//约束$name是字符串型,$age是整型
  1. 返回值约束
//返回值必须是整型
function fun(int $num1,int $num2):int{
	return $num1+$num2;
}
fun(10,20);//30

可以约束:string、int、float、bool、数组

//约束返回类型是数组
function fun():array{

}
//约束return 后面不能有返回值必须在7.1后的版本才支持
function fun():void{//void是空的意思
	return;
}
fun();

例题

1.求数组的和、平均值

<?php
$num=[1,20,53,23,14,12,15];
//求和
$sum=0;
for($i=0;$i<count($num);$i++){
	$sum+=$num[$i];//求和
}
echo '和是:'.$num,'<br>';
echo '平均值:'.$sum/count($num);

//改进
for($i=0$n=count($num);$i<$n;$i++){
	$sum+=$num[$i];
}
echo '平均值:'.number_format($sum/count($num),1);//精确到小数点后面1位

2.数组翻转

$stu=['tom','berry','ketty','rose','jake'];
for($i=0,$j=count($stu)-1;$i<$j;$i++,$j--){
	[$stu[$i],$stu[$j]]=[$stu[$j],$stu[$i]];//元素交换
}
print_r($stu);

3.遍历二维数组

$stu=[
	[1,2,3,4],
	[10,20,30,40] 
];
for($i=0;$i<count($stu);$i++){//循环第一列
	for($j=0;$j<count($stu[$i]);$j++){//循环第二列
		echo $stu[$i][$j],'&nbsp;';
	}
	echo '<br>';
}

4.循环输出1-100,其中3的倍数输出A,5的倍数输出B,15输出C

for($i=1;$i<=100;$i++){
	if($i%15===0) //先写%15,因为可以%15的值一定可以%3和%5
		echo 'C';
	elseif($i%3===0)
		echo 'A';
	elseif($i%5===0)
		echo 'B';
	else
		echo $i;
	echo '&nbsp;';
}

5.打印水仙花数

for($i=100;$i<=999;$i++){
	$a=(int)($i/100);  //百位数
	$b=(int)(($i%100)/10); //十位数
	$c=$i%10;		//个位数
	if($i==pow($a,3)+pow($b,3)+pow($c,3))
	echo $i,'<br>';
}
//pow($a,3) //表示a的三次方
//运行结果
153
370
371
407

6.打印100以内的斐波那契数列(迭代法)1 1 2 3 5 8 13 21…

$num1=1;//打印第一个数
$num2=1;//打印第二个数
echo $num1,'&nbsp;',$num2,'&nbsp;';
while(true){
	$num3=$num1+$num2;//第三个数是前面两个数的和
	if($num3>100)//超过100就终止循环
		break;
	echo $num3,'&nbsp;';
	$num1=$num2;//将$num2移给$num1
	$num2=$num3;//将$num3移给$num2
}
//1 1 2 3 5 8 13 21 34 55 89

2.1 作用域

2.1.1 变量作用域

1.全局变量:在函数外面
2.局部变量:在函数里面,默认情况下,函数内部是不会去访问函数外部的变量
3.超全局变量:可以在函数内部和函数外部访问
$_COOKIE
$_ENV
$_FILES
$_GET
$_POST
$_REQUEST
$_SERVER
$_SESSION

<?php
$num=10;
function fun() {
	echo $num; //Notice:Undefined variable:num  报错
}
//函数内部默认不能访问函数外部的值
------------------------
$_POST['num']=10;//将值赋给超全局变量
function fun(){
	echo $_POST['num'];//获取超全局变量的值 10
}
fun();

-----------------------------
function fun(){
	$_GET['num']=10;//将值赋给超全局变量
}
fun();
echo $_GET['num'];//打印超全局变量的值 10

-----------------

在函数内部访问全局变量

$num=10;//全局变量
function fun(){
	echo $GLOBALS['num']; //输出全局的$num
}
fun();
function fun(){
	$GLOBALS['num']=10;//将值赋给全局的$num
}
fun();
echo $num;//10
$num=10;
function fun(){
	global $num;//将全局变量的$num的地址引入到函数内部
	echo $num;//10
	$num=100;
}
fun();
echo $num;//100
$a=10;
$b=20;
function show(){
	echo '<pre>';
	var_dump($GLOBALS);//是一个数组,保存的是全局变量的所有值
}
show();

注意: 常量没有作用域的概念

define('PI',3.14);
function fun(){
	echo PI;//3.14
}
fun();
echo '<br>';
---------------------
function fun(){
	define('PI',3.14);
}
fun();
echo PI;//3.14

2.1.2 静态变量

静态变量一般指的是静态局部变量
静态变量只初始化一次

function fun(){
	$num=10;//普通变量每调用一次初始化一次,调用完毕销毁
	$num++;
	echo $num,'<br>';
}
fun();//11
fun();//11
--------------------
function fun(){
	static $num=10;//静态变量只初始化一次,调用完毕不销毁,第二次调用的时候不再初始化
	$num++;
	echo $num,'<br>';
}
fun();//11
fun();//12

常量和静态变量的区别
1.常量和静态变量都是初始化一次
2.常量不能改变值,静态变量可以改变值
3.常量没有作用域,静态变量有作用域

<?php
function fun1(){
	static $num=10;
}
function fun2(){
	echo $num;//Notice: Undefined varibale:num 因为静态变量是有作用域的
}
fun1();
fun2();

2.1.3 匿名函数use()

默认情况下,函数内部不能访问函数外部的变量,但在匿名函数中,可以通过use将外部变量引入匿名函数中。

$num=10;
$fun=function() use($num){//将$num引入到匿名函数中
	echo $num;
}
$fun();//10	

思考:如何在函数内部访问函数外部变量
1.使用超全局变量
2.$GLOBALS
3.global
4.use将函数外部变量引入到匿名函数内部

练习

$num=10;
function test(){
	$num=20;
	$fun=function() use($num){//只能引入一层
		echo $num;
	};
	$fun();
}
test();//20
$num=10;
$fun=function()use(&$num){
	$num=100;
};
$fun();
echo $num;//100

2.2递归

1.一只猴子看守一堆桃子,第一天吃了一半又多吃了1个,第二天一样,到第十天的时候就剩下一个桃子,请问原来有几个桃子?

函数内部自己调用自己
递归元素有两个元素,一个是递归点(从什么地方递归),第二递归出口
例题1:输出9 8 7 6 …

function printer($num){
	echo $num,'&nbsp;';
	if($num==1) //递归出口
	return;
	printer($num-1);//递归点
}
printer(9);

例题2:从1加到100

function cal($num){
	if($num==1)
		return 1;
	return $num+cal($num-1);
}
echo cal(10);
//分析
/*
第$i次执行     结果
cal(100)   		100+cal(99)
=				100+99+cal(98)
=				100+99+98+cal(97)
...				...
=				100+99+98+...+1
*/

打印第5个斐波那契数列

function fbnq($n){
	if($n==1||$n==2)
		return 1;
	return fbnq($n-1)+fbnq($n-2);
}
echo fnbq(5),'<br>';
/*
分析:
fbnq(5)=fbnq(4)+fbnq(3)
		=fbnq(3)*2+fbnq(2)
		=(fbnq(2)+fbnq(1))*2+fbnq(2)
		=(1+1)*2+1
		=5
*/

打印前10个斐波那契数列

for($i=1;$i<=10;$i++){
	echo fbnq($i),'&nbsp;';//1 1 2 3 5 8 13 21 34 55
}

小结:递归尽量少用,因为递归需要用到现场保护,现场保护是需要消耗资源的

2.3 包含文件

2.3.1 包含文件的方式

1、require:包含多次
2、include:包含多次
3、require_once:包含一次
4、include_once:包含一次

<?php
require './head.html';
require './head.html';
require './head.html';
//结果
锄禾日当午
锄禾日当午
锄禾日当午
<?php
include_once './head.html';
include_once'./head.html';
include_once'./head.html';
//结果
锄禾日当午

小结:
1、require遇到错误抛出error类别的错误,停止执行
2、include遇到错误抛出warning类型的错误,继续执行
3、require_once、include_once只能包含一次
4、HTML类型的包含页面中存在PHP代码,如果包含到PHP中是可以被执行的
5、包含文件相当于把包含文件中的代码拷贝到主文件中执行,魔术常量除外,魔术常量获取的是所在文件的信息。
6、包含编译时不执行、运行加载到内存、独立编译包含文件

2.3.2 包含文件的路径

 ./ 当前
 ../ 上一级目录

区分如下包含的区别

require './head.html';//在当前目录下查找
require 'head.html'; //受include_path配置影响

include_path的使用场景
如果包含文件的目录结构比较复杂,比如:在c:\aa\bb\c\aa中有多个文件需要包含,可以将包含的路径设置成include_path,这样包含就只要写文件名就可以了

<?php
set_include_path('c://aa/bb/cc/dd:d\\');//设置include_path
require 'head1.htm';   //受include_path配置影响
require 'head2.html';   

include_paht可以设置多个,路径之间用分号隔开

set_include_path('c://aa/bb/cc/dd;d:\\');

多学一招:

正斜(/) web中目录分隔用正斜
反斜(\)物理地址的分隔用反斜,(windows中物理地址正斜和反斜都可以)

2.3.3 错误处理

错误的级别

1.notice:提示
2.warning:警告
3.error:致命错误
notice和warning报错后继续执行,error报错后停止执行

错误的提示方法

方法一:显示在浏览器 上
方法二:记录在日志中

与错误处理有关的配置

在php.ini中

1.error_reporting = E_ALL;报告所有的错误
2.display_errors=On;将错误显示在浏览器上
3.log_errors=On;将错误记录在日志中
4.error_log=’地址‘:错误日志保存的地址

例题:

$debug=true  //开发模式 false正式模式
ini_set('error_reporting',E_ALL);//所有的错误有报告
if($debug){
	ini_set('display_errors','on');//错误显示是浏览器上
	ini_set('log_errors','off');//错误不显示在日志中
}else{
	ini_set('display_errors','off');
	ini_set('log_errors','on');
	ini_set('error_log','./err.log');
}
//测试
echo $num;

提示:ini_set()设置PHP的配置参数

2.3.4 自定义错误处理

通过trigger_error产生一个用户级别的error/warning/notice信息

$age=100;
if($age>80){
	//trigger_error('年龄不能超过80岁');//默认触发了notice级别的错误
	//trigger_error('年龄不能超过80岁',E_USER_NOTICE);//触发notice级别的错误
	//trigger_error('年龄不能超过80岁',E_USER_WARNING);//触发warning级别的错误
	trigger_error('年龄不能超过80岁'E_USER_ERROR);//触发ERROR级别的错误
}

3.1 文件编程

3.1.1 文件夹操作

1、创建文件夹【mkdir(路径,权限,是否递归创建)】
make:创建
directory:目录,文件夹

例题:

<?php
//1.创建目录
//mkdir('./aa');  //创建aa文件夹
//mkdir('./aa/bb'); //在aa目录下创建bb(aa目录必须存在)
mkdir('./aa/bb/cc/dd',0777,true);//递归创建

小结:
1.0777表示文件夹的权限
2.true表示递归创建,默认是false

2、删除文件夹【rmdir()】
//remove:移除
rmdir('./aa/bb/cc/dd');//删除dd文件夹

提醒:
1.删除的文件夹必须是空的
2.PHP没有提供递归删除

3、重命名文件夹【rename(旧名字,新名字)】
rename('./aa','./aaa');//将aa改为aaa
4、是否是文件夹[id_dir()]
echo is_dir('./aaa')?'是文件夹':'不是文件夹';
5、打开文件夹、读取文件夹、关闭文件夹
$folder=opendir('./');//打开目录
//var_dump($folder); //resource(3) of type (stream)
while($f=readdir($folder)){//读取文件夹
	if($f=='.'||$f=='..')
		continue;
	echo iconv('gbk','utf-8',$f),'<br>';
}
closedir($folder);//关闭文件夹
------------------------------
$folder=opendir('./');//打开目录
for(;;){
	if($f=readdir($folder)){
		if($f=='.'||$f=='..')
			continue;
		echo iconv('gbk','utf-8',$f),'<br>';//将gbk转成utf-8
	}else{
		break;
	}
}
closedir($folder);//关闭文件夹

小结:
1、opendir() 返回资源类型
2、每个文件夹中都有.和…
3、iconv()用来做字符编码转换
6、通过递归遍历整个文件夹

3.1.2 文件操作

1、将字符串写入文件
<?php
$str="床前明月光,\r\n疑是地上霜.\r\n举头望明月,\r\n低头思故乡.";
file_put_contents('.test.txt',$str);//将字符串写到文本中

小结:
1、所有的"写"操作都是清空重写
2、在文本中换行是\r\n

\r:回车  光标移动到当前行的最前面
\n:换行  将光标下移一行
按键盘的回车做了两步,第一步将光标移动到当前行的最前面,第二步下移一行.

3、\r\n是特殊字符,必须放在双引号内

2、将整个文件读入一个字符串
//方法一:
echo file_get_contents('./test.txt');//将整个文件读入一个字符串
//方法二:
readfile('./test.txt');//读取输出文件内容
//注意:echo file_grt_contents()==readfile()
3、打开文件并操作
fopen(地址,模式) 打开文件
模式:
r:读 read
w:写 write
a:追加 append

例题:

//3.1 打开文件写入
$fp=fopen('./test.txt','w');//打开文件返回文件指针(文件地址)
//var_dump($fp);// resource(3) of type (stream)
for($i=1;$i<=10;$i++)
	fputs($fp,'关关雎鸠'."\r\n");//写一行
fclose($fp);//关闭文件
----------------
//3.2 打开文件读取
$fp=fopen('./test.txt','r');//打开文件读取
while($line=fgets($fp)){
	echo $line,'<br>';
}
---------------------------------
//3.3 打开文件追加
$fp=fopen('./test.txt','a');//打开文件追加
fputs($fp,'在河之洲');//在文件末尾追加

小结:
1、打开文件返回文件指针(文件指针就是文件地址),资源类型
2、打开文件写、追加操作,如果文件不存在,就创建新的文件
3、打开文件读操作,文件不存在就报错
4、fputs()写一行,fgets()读一行,fclose()关闭文件
5、追加是在文件的末尾追加

4、是否是文件【is_file()】
echo is_file('./test.txt')?'是文件':'不是文件';
5、判断文件或文件夹是否存在【file_exists()】
echo file_exists('./test.txt')?'文件存在':'文件不存在';
6、删除文件【unlink】
$path='./test.txt';
if(file_exists($path)){//文件存在
	if(is_dir($path))//如果是文件夹用rmdir()删除
		rmdir($path);
	elseif(is_file($path))//如果是文件用unlink()删除
		unlink($path);
}else{
	echo '文件夹或文件不存在';
}
7、二进制读取【fread(文件指针,文件大小)】

文件的存储有两种:字符流和二进制流
二进制流的读取按文件大小来读的

$path='./face.jpg';
$fp=fopen($path,'r');
header('content-type:image/jpeg');//告知浏览器下面的代码通过jpg图片方式解析
echo fread($fp,filesize($path));//二进制读取

多学一招:file_get_contents()也可以进行二进制读取

header('content-type:image/jpeg');
echo file_get_contents('./face.jpg');

小结:
1、文本流有明确的结束符,二进制流没有明确的结束符,通过文件大小判断文件是否读取完毕
2、file_get_contents()既可以进行字符流读取,也可以进行二进制读取。

4.1 表单提交数据的两种方式

4.1.1 两种方式

1、get
2、post

4.1.2 区别

1、外观上看
get提交在地址上可以看到参数
post提交在地址栏上看不到参数
2、安全性
get不安全
post相对安全
3、提交原理
get提交参数是一个一个的提交
post提交是所有参数作为一个整体一起提交
4、提交数据大小
get提交一般不超过255个字节
post提交的大小取决于服务器

//在php.ini中,可以配置post提交的大小
post_max_size=8M

5、灵活性
get很灵活,只要有页面的跳转就可以传递参数
post不灵活,post提交需要有表单的参与

1.html跳转
<a href="index.php?name=tom&age=20">跳转</a>
2.js跳转
<script type="text/javascript">
	location.href='index.php?name=tom&age=20';
	location.assign('index.php?name=tom&age=20');
	location.replace('index.php?name=tom&age=20');
</script>
3.php跳转
header('location:index.php?name=tom&age=20');

小结:

GETPOST
外观上在地址上看到传递的参数和值地址栏看不到数据
提交数据的大小提交少量数据,不同的浏览器最大值不一样,IE是2K提交大量数据,可以通过更改php.ini配置文件来设置post提交数据的最大值
安全性
提交原理提交的数据和数据之前是独立的将提交的数据变成xml格式提交
灵活性很灵活,只要有页面的跳转就可以get传递数据不灵活

4.1.3 服务器接收数据的三种方式

通过名字获取名字对应的值

$_POST:只能获取POST提交的值,数组类型,保存的POST提交的值
$_GET:只能获取GET提交的值,数组类型,保存的GET提交的值
$_REQUEST:既能获取GET又能获取POST的值,数组类型,保存的GETPOST提交的值

例题:
HTML页面

<body>
<!--表单提交数据-->
<form method='get' action="./2-demo2.php">
	语文:<input type="text" name="ch"><br/>
	数学:<input type="text" name="math"><br/>
	<input type="submit" name="button" value="提交"></br>
</form>
<!--超链接提交数据-->
<a href="2-demo2.php?ch=77&math=88">跳转</a></br>
<!--js提交数据-->
<input type="button" value="点击" onclick="location.href='2-demo2.php?ch=77&math=88'">
<input type="button" value="点击" onclick="location.assign='2-demo2.php?ch=77&math=88'">
</body>

PHP页面

<?php
//post数组中不为空
if(!empty($_POST)){
	echo '这是post提交的数据<br>';
	echo '语文:'.$_POST['ch'],'<br>';
	echo '数学:'.$_POST['math'],'<br>';
}
echo '<hr>';
//获取get提交的数据
if(!empty($_GET)){
	echo '这是get提交的数据<br>';
	echo '语文:'.$_GET['ch'],'<br>';
	echo '数学:'.$_GET['math'],'<br>';
}
echo '<hr>';
//既能获取get又能获取post提交的数据
echo $_REQUEST['ch'],'<br>';
echo $REQUEST['math'];

思考题
在一个请求中,既有get又有post,get和post传递的名字是一样的.这时候通过$_REQUEST获取的数据是什么?
答:结果取决于配置文件

request_order="GP" # 先获取GET再获取POST的值

例题:

<?php
if(!empty($_POST)){
	echo '姓名:'.$_REQUEST['username'],'<br>';
}
?>
<form method='post' action="?username=berry">
	姓名:<input type="text" name="username"></br>
	<input type="submit" name="button" value="提交">
</form>
分析:先获取GET的username,再获取post的username,后面的将前面的值覆盖

小结:
1.在开发的时候,如果明确是post提交就使用$_POST获取,如果明确get提交就用$_GET获取
2.request获取效率低,尽量不要使用,除非提交的类型不确定的情况下使用.

5. 参数的传递

5.1.1 复选框值的传递

复选框的命名要注意带’[]’

<body>
<?php
if(isset($_POST['button'])){
	print_r($_POST['hobby']);
}
?>
<form method='post' action="">
	爱好:
	<input type="checkbox" name="hobby[]" value="爬山">爬山
	<input type="checkbox" name="hobby[]" value="吃肉">吃肉
	<input type="checkbox" name="hobby[]" value="喝酒">喝酒
	<input type="checkbox" name="hobby[]" value="烫头">烫头
	<input type="submit" name="button" value="提交">
</form>
</body>

5.1.2 例题

<body>
<?php
if(isset($_POST['button'])){
	echo '姓名:'.$_POST['username'].'<br>';
	echo '密码:'.$_POST['pwd'].'<br>';
	echo '性别:'.$_POST['sex'].'<br>';
	echo '爱好:',isset($_POST['hobby'])?implode(',',$_POST['hobby']):''没有爱好',<br>';
	echo '籍贯:'.$_POST['jiguan'].'<br>';
	echo '留言:'.$_POST['words'].'<br>';
}
?>
<form method='post' action="">
	姓名:<input type="text" name="username"><br/>
	密码:<input type="password" name="pwd"></br>
	性别:<input type="radio" name="sex" value='1'><input type="radio" name="sex" value='0'>女
	爱好:
	<input type="checkbox" name="hobby[]" value="爬山">爬山
	<input type="checkbox" name="hobby[]" value="吃肉">吃肉
	<input type="checkbox" name="hobby[]" value="喝酒">喝酒
	<input type="checkbox" name="hobby[]" value="烫头">烫头</br>
	籍贯:
	<select name="jiguan"
		<option value="021">上海</options>
		<option value="010">北京</options>
	</select></br>
	留言:<textarea name="words" rows="5" cols="30"></textarea></br>
	
	<input type="submit" name="button" value="提交">
</body>

6 文件上传

开发中需要上传图片、 音乐、视频等等,这种上传传递的是二进制数据.

6.1.1 客户端上传文件

文件域

<input type="file" name="image">

表单的enctype属性
默认情况下,表单传递是字符流,不能传递二进制流,通过设置表单的enctype属性传递复合数据.
enctype属性的值有:
1.application/x-www-form-urlencoded:[默认],表示传递的是带格式的文本数据.
2.multipart/form-data:复合的表单数据(字符串,文件),文件上传必须设置此值
3.text/plain:用于向服务器传递无格式的文本数据,主要用户电子邮件
单词

	multipart:复合
	form-data:表单数组

6.1.2 服务器接收文件

超全局变量$_FILES是一个二维数组,用来保存客户端上传到服务器的文件信息.二维数组的行是文件域的名称,列有5个.
1、$_FILES[][‘name’]:上传的文件名
2、$FILES[][‘type’]:上传的类型,这个类型是MIME类型(image/jpeg、image/gif、image/png)
3、$FILES[][‘size’]:文件的大小,以子节为单位
4、$FILES[][‘tmp_name’]:文件上传时的临时文件
5、$FILES[][‘error’]:错误编码(值有0、1、2、3、4、6、7)0表示正确
$_FILES[][‘error’]详解

错误描述
0正确
1文件大小超过了php.ini中允许的最大值
2文件大小超过了表单允许的最大值
3只有部分文件上传
4没有文件上传
6找不到临时文件
7文件写入失败
<form method="post" action="" enctype="multipart/form-data">
	<input type="hidden" name="MAX_FILE_SIZE" value="2">表单允许的最大值2个子节
	<input type="file" name="face">
	<input type="submit" name="button" value="上传">
</form>

注意:MAX_FILE_SIZE必须在文件域的上面.

6.1.3 将上传文件移动到指定位置

函数:

move_uploaded_file(临时地址,目标地址)

代码

<body>
<?php
if(!empty($_POST)){
	if($_FILES['face']['error']==0){
		move_uploaded_file($_FILES['face']['tmp_name'],'./'.$_FILES['face']['name']);
	}else{
		echo '上传有误';
		echo '错误码:'.$_FILES['face']['error'];
	}
}
?>
<form method='post' action="" enctype='multipart/form-data'>
	<input type="file" name="face">
	<input type="submit" name="button" value="上传">
</form>
</body>

小结:上传的同名的文件要给覆盖

6.1.4与文件上传有关的配置

post_max_size=8M:表单允许的最大值
upload_max_filesize=2M:允许上传的文件大小
upload_tmp_dir=F:\wamp\tmp:指定临时文件地址,如果不指定,操作系统自己指定
file_upoads=On:是否允许文件上传
max_file_uploads=20:允许同时上传20个文件

6.2 优化文件上传

6.2.1 更改文件名

方法一:通过时间戳做文件名

<?php
$path='face.stu.jpg';
//echo strrchr($path,'.'); //从最后一个点开始截取,一直截取到最后
echo time().rand(100,999).strrchr($path,'.');

方法二:通过uniqid()实现

$path='face.stu.jpg';
echo uniqid().strrchr($path,'.'),'<br>';//生成唯一的id
echo uniqid('goods_').strrchr($path,'.'),'<br>';//带有前缀
echo uniqid('goods_',true).strrchr($path,'.'),'<br>';//唯一id+随机数
6.2.2 验证文件格式

方法一:判断文件的扩展名(不能识别文件伪装)
操作思路:将文件的后缀和允许的后缀比对

<?php
if(!empty($_POST)){
	$allow=array('.jpg','.png','.gif');//允许的扩展名
	$ext=strrchr($_FILES['face']['name'],'.');//上传文件的扩展名
	if(in_array($ext,$allow))
		echo '允许上传';
	else 
		echo '文件不合法';
}
?>
<form method="post" action="" enctype="multipart/form-data">
	<input type="file" name="face">
	<input type="submit" name="button" value="上传">
</form>

注意:比较扩展名不能防止文件伪装.

方法二:判断$_FIELS[][‘type’]类型(不能识别文件伪装)

<?php
if(!empty($_POST)){
	$allow=array('image/jpg','image/png','image/gif');//允许的类别
	$mime=$_FILES['face']['type'];//上传文件类型
	if(in_array($mime,$allow))
		echo '允许上传';
	else 
		echo '文件不合法';
}
?>
<form method="post" action="" enctype="multipart/form-data">
	<input type="file" name="face">
	<input type="submit" name="button" value="上传">
</form>

注意:通过$_FIELS[][‘type’]不能防止文件伪装
方法三:php_fileinfo扩展(可以防止文件伪装)
在php.ini中开启fileinfo扩展

extension=php_fileinfo.dll

注意:开启fileinfo扩展以后,就可以使用info_*的函数了

<?php
if(!empty($_POST)){
	//第一步:创建finfo资源
	$info=finfo_open(FILEINFO_MIME_TYPE);
	//var_dump($info); //resuource(2) of type (file_info)
	//第二步:将finfo资源和文件做比较
	$mime=finfo_file($info,$FILES['face']['tmp_name']);
	//第三步:比较是否合法
	$allow=array('image/jpeg','image/png','image/gif');//允许的类别
	echo in_array($mime,$allow)?'合法':'不合法';
}
?>
<form method="post" action="" enctype="multipart/form-data">
	<input type="file" name="face">
	<input type="submit" name="button" value="上传">
</form>

小结:验证文件格式有三种方法
1、可以验证扩展名(不可以防止文件伪装)
2、通过$_FILES[][‘type’]验证(不可以防止文件伪装)
3、通过file_info扩展(可以防止文件伪装)

6.2.3 优化文件上传例题

步骤
第一步:验证是否有误
第二部:验证格式
第三步:验证大小
第四步:验证是否是http上传

<?php
/*
验证错误
如果有错,就返回错误,如果没错,就返回null
*/
function check($file){
	//1:验证是否有误
	if($file['error']!=0){
		switch($file['error']){
			case 1:
				return '文件大小超过了php.ini中允许的最大值,最大值是:'.ini_get('upload_max_filesize');
			case 2:
				return '文件大小超过了表单允许的最大值';
			case 3:
				return '只有部分文件上传';
			case 4:
				return '没有文件上传';
			case 6:
				return '找不到临时文件';
			case 7:
				return '文件写入失败';
			default:
				return '未知错误';
		}
	}
	//2、验证格式
	$info=finfo_open(FILEINFO_MIME_TYPE);
	$mime=finfo_file($info,$file['tmp_name']);
	$allow=array('image/jpeg','image/png','image/gif');//允许的类别
	if(!in_array($mime,$allow)){
		return  '只能上传'.implode(',',$allow).'格式';
	}
	//3、验证大小
	$size=1234;
	if($file['size']>$size){
		return '文件大小不能超过'.number_format(($size/1024),1).'k';
	}
	//4、验证是否是http上传
	if(!is_uploaded_file($file['tmp_name']))
		return '文件不是HTTP POST上传的<br>';
	return null;//没有错误
}
if(!empty($_POST)){
	//上传文件过程中有错误就显示错误
	if($error=check($_FILES['face'])){
		echo $error;
	}ele{
		//文件上传,上传的文件保存到当天的文件夹中
		$foldername=date('Y-m-d');//文件夹名称
		$folderpath="./uploads/{$foldername}";//文件夹路径
		if(!is_dir($folderpath))
			mkdir($folderpath);
		$filename=uniqid('',true).strrchr($_FILES['face']['name'],'.');//文件名
		$filepath="$folderpath/$filename";//文件路径
		if(move_uploaded_file($_FILES['face']['tmp_name'],$filepath))
			echo "上传成功,路径是:{$foldername}/{$filename}";
		else
			echo '上传失败<br>'
	}
}
?>
<form method="post" action="" enctype="multipart/form-data">
	<input type="file" name="face">
	<input type="submit" name="button" value="上传">
</form>

小结:
1、将时间戳转换格式

echo date('Y-m-d H:i:s',123126545),'<br>';//将时间戳转化成年-月-日 小时:分钟:秒
echo date('Y-m-d H:i:s'),'<br>';//将当前的时间转化成年-月-日 小时:分钟:秒

2、设置时区(php.ini)

date.timeZone=PRC //中华人民共和国

3、PHP的执行可以不需要Apache的参与

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值