代码审计

php代码基础入门

2020-10-22  本文已影响0人  book4yi

前言:


后面一段时间打算学习代码审计,我之前玩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

包含了全部变量的全局组合数组。变量的名字就是数组的键

包含了诸如头信息(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"。

默认情况下包含了 $_GET$_POST$_COOKIE 的数组。

魔术常量:

命名空间:
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() 。

参考如下:


PHP 教程 | 菜鸟教程

上一篇下一篇

猜你喜欢

热点阅读