前言:
后面一段时间打算学习代码审计,我之前玩ctf的时候,也会遇到一些代码审计的题目,所以对php代码略略了解一些,本文对php作一个小小的归纳小结。
基础学习:
PHP 是一门弱类型语言:PHP 会根据变量的值,自动把变量转换为正确的数据类型。
在所有函数外部定义的变量,拥有全局作用域。要在一个函数中访问一个全局变量,需要使用 global 关键字。
Static 作用域:
当一个函数完成时,它的所有变量通常都会被删除。如果希望某个局部变量不要被删除,在第一次声明变量时使用 static 关键字
类型比较:
松散比较:使用两个等号 == 比较,只比较值,不比较类型
严格比较:使用三个等号 === 比较,除了比较值,也比较类型
常量:
该值在脚本中不能改变,在整个脚本中都可以使用,常量名不需要加 $
修饰符
常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。
函数语法格式:
define ( string $name , mixed $value [, bool $case_insensitive = false ] )
name:必选参数,常量名称,即标志符。
value:必选参数,常量的值。
case_insensitive :可选参数,如果设置为 TRUE,该常量则大小写不敏感。默认是大小写敏感的。
三元运算符:
语法格式:
(expr1) ? (expr2) : (expr3)
对 expr1 求值为 TRUE 时的值为 expr2,在 expr1 求值为 FALSE 时的值为 expr3。
注意:自 PHP 5.3 起,可以省略三元运算符中间那部分。表达式 expr1 ?: expr3 在 expr1 求值为 TRUE 时返回 expr1,否则返回 expr3。
组合比较符(PHP7+):
不仅限于数值类数据的比较
语法格式:
$c = $a <=> $b;
如果
$a > $b
, 则$c
的值为 1。
如果$a == $b
, 则$c
的值为 0。
如果$a < $b
, 则$c
的值为 -1。
数组:
在 PHP 中,array() 函数用于创建数组:
在 PHP 中,有三种类型的数组:
- 数值数组 - 带有数字 ID 键的数组
- 关联数组 - 带有指定的键的数组,每个键关联一个值
- 多维数组 - 包含一个或多个数组的数组
- 数值数组:
$cars=array("Volvo","BMW","Toyota");
$cars[0]="Volvo";
$cars[1]="BMW";
$cars[2]="Toyota";
获取数组长度:
echo count($cars); # 获取数组长度
遍历数值数组:
<?php
$cars=array("Volvo","BMW","Toyota");
$arrlength=count($cars);
for($x=0;$x<$arrlength;$x++)
{
echo $cars[$x];
echo "<br>";
}
?>
- 关联数组:
使用分配给数组的指定的键的数组
$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");
# 或者
$age['Peter']="35";
$age['Ben']="37";
$age['Joe']="43";
遍历关联数组:
<?php
$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");
foreach($age as $x=>$x_value)
{
echo "Key=" . $x . ", Value=" . $x_value;
echo "<br>";
}
?>
超级全局变量:
PHP 超级全局变量列表:
$GLOBALS
$_SERVER
$_REQUEST
$_POST
$_GET
$_FILES
$_ENV
$_COOKIE
$_SESSION
- $GLOBALS
包含了全部变量的全局组合数组。变量的名字就是数组的键
- $_SERVER
包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组
所有 $_SERVER 变量中的重要元素:
元素/代码 | 描述 |
---|---|
$_SERVER['PHP_SELF'] | 当前执行脚本的文件名,与 document root 有关 |
$_SERVER['GATEWAY_INTERFACE'] | 服务器使用的 CGI 规范的版本;例如,"CGI/1.1" |
$_SERVER['REMOTE_ADDR'] | 浏览当前页面的用户的 IP 地址 |
$_SERVER['DOCUMENT_ROOT'] | 当前运行脚本所在的文档根目录。在服务器配置文件中定义。 |
$_SERVER['REMOTE_HOST'] | 浏览当前页面的用户的主机名。DNS 反向解析不依赖于用户的 REMOTE_ADDR。 |
$_SERVER['REMOTE_PORT'] | 用户机器上连接到 Web 服务器所使用的端口号。 |
$_SERVER['SERVER_ADDR'] | 当前运行脚本所在的服务器的 IP 地址。 |
$_SERVER['SERVER_NAME'] | 当前运行脚本所在的服务器的主机名。如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定。(如: www.runoob.com) |
$_SERVER['SERVER_SOFTWARE'] | 服务器标识字符串,在响应请求时的头信息中给出。 (如:Apache/2.2.24) |
$_SERVER['SERVER_PROTOCOL'] | 请求页面时通信协议的名称和版本。例如,"HTTP/1.0"。 |
$_SERVER['REQUEST_METHOD'] | 访问页面使用的请求方法;例如,"GET", "HEAD","POST","PUT"。 |
$_SERVER['REQUEST_TIME'] | 请求开始时的时间戳。从 PHP 5.1.0 起可用。 (如:1377687496) |
$_SERVER['QUERY_STRING'] | query string(查询字符串),如果有的话,通过它进行页面访问。 |
$_SERVER['HTTP_ACCEPT'] | 当前请求头中 Accept: 项的内容,如果存在的话。 |
$_SERVER['HTTP_ACCEPT_CHARSET'] | 当前请求头中 Accept-Charset: 项的内容,如果存在的话。例如:"iso-8859-1,*,utf-8"。 |
$_SERVER['HTTP_HOST'] | 当前请求头中 Host: 项的内容,如果存在的话。 |
$_SERVER['HTTP_REFERER'] | 引导用户代理到当前页的前一页的地址(如果存在)。由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改 HTTP_REFERER 的功能。简言之,该值并不可信。) |
$_SERVER['HTTPS'] | 如果脚本是通过 HTTPS 协议被访问,则被设为一个非空的值。 |
$_SERVER['SCRIPT_FILENAME'] | 当前执行脚本的绝对路径。 |
$_SERVER['SERVER_ADMIN'] | 该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上,则该值是那个虚拟主机的值。(如:someone@runoob.com) |
$_SERVER['SERVER_PORT'] | Web 服务器使用的端口。默认值为 "80"。如果使用 SSL 安全连接,则这个值为用户设置的 HTTP 端口。 |
$_SERVER['SERVER_SIGNATURE'] | 包含了服务器版本和虚拟主机名的字符串。 |
$_SERVER['PATH_TRANSLATED'] | 当前脚本所在文件系统(非文档根目录)的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。 |
$_SERVER['SCRIPT_NAME'] | 包含当前脚本的路径。这在页面需要指向自己时非常有用。FILE 常量包含当前脚本(例如包含文件)的完整路径和文件名。 |
$_SERVER['SCRIPT_URI'] | URI 用来指定要访问的页面。例如 "/index.html"。 |
- $_REQUEST
默认情况下包含了 $_GET
、$_POST
、$_COOKIE
的数组。
魔术常量:
- __LINE__:文件中的当前行号
- __FILE__:文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名
- __DIR__:文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录
- __FUNCTION__:自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)
- __CLASS__:自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)
- __TRAIT__:自 PHP 5.4.0 起,PHP 实现了代码复用的一个方法,称为 traits
- __METHOD__:返回该方法被定义时的名字(区分大小写)
- __NAMESPACE__:当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)
命名空间:
PHP 命名空间可以解决以下两类问题:
1、用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
2、为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间
类:
类定义形如:
<?php
class phpClass {
var $var1;
var $var2 = "constant string";
function myfunc ($arg1, $arg2) {
[..]
}
[..]
}
?>
注解:
类使用 class 关键字后加上类名定义。
类名后的一对大括号({})内可以定义变量和方法。
类的变量使用 var 来声明, 变量也可以初始化值。
函数定义类似 PHP 函数的定义,但函数只能通过该类及其实例化的对象访问。
实例:
<?php
class Site {
/* 成员变量 */
var $url;
var $title;
/* 成员函数 */
function setUrl($par){
$this->url = $par;
}
function getUrl(){
echo $this->url . PHP_EOL;
}
function setTitle($par){
$this->title = $par;
}
function getTitle(){
echo $this->title . PHP_EOL;
}
}
?>
变量 $this 代表自身的对象。
PHP_EOL 为换行符。
创建对象:
$taobao = new Site;
调用成员方法:
// 调用成员函数,设置标题和URL
$taobao->setTitle( "淘宝" );
$taobao->setUrl( 'www.taobao.com' );
// 调用成员函数,获取标题和URL
$taobao->getTitle();
$taobao->getUrl();
构造函数:
构造函数是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与new
运算符一起使用。
语法格式:
void __construct ([ mixed $args [, $... ]] )
添加构造函数之后的完整代码:
<?php
class Site {
/* 成员变量 */
var $url;
var $title;
function __construct( $par1, $par2 ) {
$this->url = $par1;
$this->title = $par2;
}
function getUrl(){
echo $this->url . PHP_EOL;
}
function getTitle(){
echo $this->title . PHP_EOL;
}
}
$taobao = new Site('www.taobao.com', '淘宝');
// 调用成员函数,获取标题和URL
$taobao->getTitle();
$taobao->getUrl();
?>
析构函数:
析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。
一个实例:
<?php
class MyDestructableClass {
function __construct() {
print "构造函数\n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "销毁 " . $this->name . "\n";
}
}
$obj = new MyDestructableClass();
?>
输出结果如下:
构造函数
销毁 MyDestructableClass
继承:
PHP 使用关键字 extends 来继承一个类,PHP 不支持多继承
实例中 Child_Site 类继承了 Site 类,并扩展了功能:
<?php
// 子类扩展站点类别
class Child_Site extends Site {
var $category;
function setCate($par){
$this->category = $par;
}
function getCate(){
echo $this->category . PHP_EOL;
}
}
方法重写:
如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写
function getUrl() {
echo $this->url . PHP_EOL;
return $this->url;
}
function getTitle(){
echo $this->title . PHP_EOL;
return $this->title;
}
访问控制:
PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
- public(公有):公有的类成员可以在任何地方被访问。
- protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
- private(私有):私有的类成员则只能被其定义所在的类访问。
- 属性的访问控制:
类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有。
- 方法的访问控制:
类中的方法可以被定义为公有,私有或受保护。如果没有设置这些关键字,则该方法默认为公有。
接口:
1、使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
2、接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的
3、接口中定义的所有方法都必须是公有,这是接口的特性。
4、要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。
一个实例:
<?php
// 声明一个'iTemplate'接口
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
// 实现接口
class Template implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
}
抽象类:
1、任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
2、定义为抽象的类不能被实例化。
3、被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
4、继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。
5、此外,子类方法可以包含父类抽象方法中不存在的可选参数。
Static 关键字:
1、声明类属性或方法为 static(静态),就可以不实例化类而直接访问。
2、静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
3、由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
4、静态属性不可以由对象通过 -> 操作符来访问。
5、自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
Final 关键字:
PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
调用父类构造方法:
PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。
网友评论