代码审计基础
1. php中的类(class)
- 定义了一件事物的抽象特点
- 类的定义包含了数据的形式以及对数据的操作
(1)类的定义和调用
- 类的定义
<?php
class Animal{
public $name = "小猫仔";
public function eat(){
echo "在吃饭.";
}
}
?>
- 类的调用
new实例化对象
$cat = new Animal;
echo $cat->name;
$cat->eat();
(2)类方法和属性
- 类方法(函数)
<?php
class Animal{
public $name = "小猫仔";
public function eat(){
echo "在吃饭.";
}
public function say(){
echo "在说话.";
}
}
?>
- $this
代表自身的对象
<?php
class Animal{
public $name = "小猫仔";
public function eat(){
echo $this->name."在吃饭.";
}
}
$cat = new Animal;
$cat->eat();
$dog = new Animal;
$dog->name = "小狗仔";
$dog->eat();
?>
(3)类的访问控制
关键字:public,protected,private
- public(公有):公有的类成员可以在任何地方被访问
<?php
class Permissions{
public $name = "公有";
}
$way = new Permissions;
echo $way->name;
?>
- protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问(自家的)
直接调用会报错
<?php
class Permissions{
protected $name = "受保护";
}
$way = new Permissions;
echo $way->name;
?>
可通过内部定义get和set方法来实现调用和修改
<?php
class Permissions{
protected $name = "受保护";
public function getName(){
return $this->name;
}
public function setName($newname){
$this->name = $newname;
}
}
$way = new Permissions;
echo $way->getName();
$way->setName(" 新受保护");
echo $way->getName();
?>
- private(私有):私有的类成员则只能被其定义所在的类访问(自己的)
直接调用会报错
<?php
class Permissions{
private $name = "私有";
}
$way = new Permissions;
echo $way->name;
?>
可通过内部定义get和set方法来实现调用和修改
<?php
class Permissions{
private $name = "私有";
public function getName(){
return $this->name;
}
public function setName($newname){
$this->name = $newname;
}
}
$way = new Permissions;
echo $way->getName();
$way->setName("新私有");
echo $way->getName();
?>
注:
私有和受保护显著区别为私有的只有自己内部可调用,而受保护的不仅自己内部可调用,自己的子类和父类也可以调用,上面演示的get及set方法即类似于内部调用
(4)类的构造函数(__construct)
- 构造函数是一种特殊的方法,在创建一个新对象时,它会被自动调用
- 它可以用来初始化对象的属性或执行其他必要操作
- 没有返回值
- 无参的情况
<?php
class Animal{
private $name;
public function __construct(){
$this->name = "小猫";
}
public function eat(){
echo $this->name . "在吃饭.";
}
}
$cat = new Animal;
$cat->eat();
?>
- 有参的情况
若在初始化的时候不进行传参则会报错
错误写法:
<?php
class Animal{
private $name;
public function __construct($name){
$this->name = $name;
}
public function eat(){
echo $this->name . "在吃饭.";
}
}
$cat = new Animal;
$cat->eat();
?>
正确写法:
<?php
class Animal{
private $name;
public function __construct($name){
$this->name = $name;
}
public function eat(){
echo $this->name . "在吃饭.";
}
}
$cat = new Animal("小猫");
$cat->eat();
?>
实际应用
<?php
class Animal{
private $name;
private $birth;
private $age;
// 构造方法,用来初始化动物对象的名字和出生日期
public function __construct($name, $birth){
$this->name = $name;
$this->birth = $birth;
$this->age = floor((time() - strtotime($birth)) / 3600 / 24);
}
public function getInfo(){
echo "$this->name 的年龄是 $this->age 天,出生日期是 $this->birth";
}
}
$cat = new Animal("小猫","2025-03-01");
$cat->getInfo();
?>
floor((time() - strtotime($birth)) / 3600 / 24);
这段代码的作用是计算从 $birth
(出生日期)到当前时间的天数,并返回一个整数。
time()
获取当前时间的 Unix 时间戳,即当前时间自 1970 年 1 月 1 日以来的秒数。strtotime($birth)
将出生日期转换为 Unix 时间戳,即出生日期自 1970 年 1 月 1 日以来的秒数。time() - strtotime($birth)
计算出这两个时间点之间的秒数,接着除以 3600 转换为小时,再除以 24 转换为天数。floor()
函数将结果向下取整,得到一个整数天数。
运行日期:
(5)类的析构函数(__destruct)
- 析构函数是一种特殊的方法,它在对象被销毁时自动调用
- 它可以用来执行一些清理操作,例如释放资源或关闭数据库连接
- 当对象不再被引用或脚本执行结束时,析构函数会自动调用
<?php
class Myclass{
public function say($i){
echo "saying".$i."\n";
}
public function __destruct(){
echo "析构函数被调用";
}
}
$obj = new Myclass;
for($i=0;$i<4;$i++){
if($i==3){
unset($obj);
}
if($obj){
$obj->say($i);
}
}
?>
- unset()函数:
- 用于销毁指定的变量。
- 它的主要作用是释放变量所占用的内存空间,使其不再可用。
unset
可以用于销毁单个变量、数组中的某个元素,或者同时销毁多个变量。
(6)类的静态变量(static)
- [静态]指的是无需对类进行实例化,就可以直接调用这些属性和方法
- 所有对静态变量进行的操作都会对所有对象起作用
- 举例:"小猫小狗听到指令来吃饭",指令变化,全部都要听从
调用方法:
- 使用 类名:: 调用
<?php
class Animal{
public static $name = "猫仔";
public function eat(){
echo Animal::$name."在吃饭";
}
}
$cat = new Animal;
$cat->eat();
?>
- 使用 self:: 调用
<?php
class Animal{
public static $name = "猫仔";
public function eat(){
echo self::$name."在吃饭";
}
}
$cat = new Animal;
$cat->eat();
?>
- 使用 $this:: 调用
<?php
class Animal{
public static $name = "猫仔";
public function eat(){
echo $this::$name."在吃饭";
}
}
$cat = new Animal;
$cat->eat();
?>
所有对静态变量进行的操作都会对所有对象起作用:
<?php
class Animal{
public static $name = "猫仔";
public function eat(){
echo self::$name."在吃饭";
}
}
$cat = new Animal;
Animal::$name = "不是猫";
$cat->eat();
$dog = new Animal;
$cat->eat();
?>
注:修改静态变量的值时只能使用类名来调用
(7)类的类常量(const)
- 使用场景:所有的对象共用一个属性
- 静态变量与类常量相似,唯一的区分是类常量不可以更改,静态变量可以更改
- 类常量命名时一般使用大写字母,且不能使用"$"符号
调用方法:
- 使用 Animal:: 调用
<?php
class Animal{
public const NAME = "猫仔";
public function eat(){
echo Animal::NAME."在吃饭";
}
}
$cat = new Animal;
$cat->eat();
?>
- 使用 self:: 调用
<?php
class Animal{
public const NAME = "猫仔";
public function eat(){
echo self::NAME."在吃饭";
}
}
$cat = new Animal;
$cat->eat();
?>
- 使用 $this:: 调用
<?php
class Animal{
public const NAME = "猫仔";
public function eat(){
echo $this::NAME."在吃饭";
}
}
$cat = new Animal;
$cat->eat();
?>
2.nodejs服务端语言
(1)什么是Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。它 使用事件驱动、非阻塞I/O模型,使其轻量且高效,非常适合数据密 集型实时应用。
(2)环境配置
安装Node.js
- 访问 Node.js 官方网站 下载适合你操作系统的安装包。
- 按照安装向导完成安装。
- 打开命令行,输入 node -v 和 npm -v 检查是否安装成功。
安装编辑器
推荐使用 Visual Studio Code,并安装以下插件:
- Node.js Extension Pack
- ESLint
- Prettier
初始化项目
mkdir my-node-app
cd my-node-app
npm init -y
(3)基础知识
Hello World
创建一个名为 app.js 的文件,内容如下:
// 输出 'Hello, World!','你好!' 到控制台
console.log('Hello, World!');
console.log('你好,世界!');
点击运行或在终端输入:
node app.js
注:
- 若运行失败,先退出vscode,重新以管理员身份运行,目前先这 样解决,在npm包的使用时进行彻底解决这个问题;
注:若任然运行不了,在开始中搜索"powershell",以管理员身份运行,执行"Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass"
- 若中文出现乱码,将vscode右下角的编码方式改为"UTF-8"即可解 决问题。
全局对象
global
:类似于浏览器中的 window 对象。process
:提供有关当前 Node.js 进程的信息和控制。console
:用于输出日志。
(4)模块系统
内置模块
Node.js 提供了许多内置模块,如 fs、path、http、url 等。
自定义模块
创建一个名为 module.js 的文件,内容如下:
// 定义一个函数 'greet',接受一个参数 'name'
function greet(name){
// 在控制台输出一个问候消息,模版字符串用反引号(``)
console.log(`Hello, ${name}!`);
}
// 将 'greet' 函数导出,使其在其他文件中可以使用
module.exports = greet;
在app.js
中使用:
// 导入模块中的 'greet' 函数
const greet = require('./module');
// 调用 'greet' 函数,并传入 'Alice' 作为参数
greet('Alice');
npm包
使用 npm 安装第三方模块:
npm install lodash
注:若在vscode终端无法安装成功(确保已经配置了环境变量,类似 ——NODE_HOME:E:\ProgramFiles\node-v22.13.1-x64),
**1.若错误是类似没有node/npm命令,**其一可能是说明环境变量配置错误,修改配置即可;其二可能是node.exe默认只有管理员才有权限,到node文件夹处,如我的是node-v22.13.1-x64,单击右键-属 性-安全-编辑,给Authenticated Users和Users用户添加 “完全控 制、修改” 权限即可);
**2.若错误类似不允许运行脚本,**说明系统ExecutionPolicy(执行策 略)的问题,将ExecutionPolicy修改为RemoteSigned(远程签名)即 可,修改方法:点击开始-输入"PowerShell"-点击""以管理身份运 行""-输入"set-ExecutionPolicy RemoteSigned"-可以输入"get-ExecutionPolicy"查看是否修改成功,修改完成即可正常使用。
注:Lodash 是一个非常流行的 JavaScript 工具库,它提供了一组 强大且高效的实用函数,用来简化常见的编程任务。它涵盖了很多 常见的功能,比如数组、对象、函数和字符串的操作,使得 JavaScript 编程更加高效和便捷。
在代码中使用:
// 引入 lodash 模块
const _ = require('lodash');
// 使用 lodash 的 chunk 函数将数组 [1, 2, 3, 4] 按每组 2个元素进行分块
console.log(_.chunk([1, 2, 3, 4], 2));
// 输出 [[1, 2], [3, 4]]
(5)异步编程
回调函数
// 定义一个异步函数,接收一个回调函数作为参数
function asyncFunction(callback) {
// 使用 setTimeout 模拟异步操作,1秒后调用回调函数
setTimeout(() => {
callback(' Async Hello!'); // 回调函数传递消息
}, 1000);
}
// 调用 asyncFunction,并传入一个回调函数来处理异步返回的消
息
asyncFunction((message) => {
console.log(message); // 打印收到的消息
});
注:
() => 是 JavaScript 中的 箭头函数(Arrow Function) 语法,它 是一种简洁的函数定义方式,主要有以下特点:
简洁的语法:箭头函数提供了比传统函数表达式更简短的写法。 传统函数定义:
jsfunction add(a, b) { return a + b; }
箭头函数:
jsconst add = (a, b) => a + b;
- () => 的含义:
()
:表示函数的参数列表。如果没有参数,可以是空括号 (); 如果有多个参数,参数会放在括号内。=>
:是箭头函数的标志,表示函数体的开始。如果箭头函数只有一个表达式,那么可以省略大括号 {},并且 该表达式的结果会自动作为函数的返回值。
注:
callback
是传入的回调函数。Async Hello!
是传递给回调函数的参数。callback(' Async Hello!')
就是调用回调函数并传递' Async Hello!' 给它。
Promise
// 定义一个返回 Promise 的异步函数 asyncFunction
function asyncFunction() {
// 返回一个新的 Promise 对象
return new Promise((resolve, reject) => {
// 模拟一个异步操作(比如:setTimeout,表示等待 1 秒
后执行)
setTimeout(() => {
// 在 1 秒后调用 resolve,将 'Async Hello!' 作
为结果传递
resolve('Async Hello!');
}, 1000);
});
}
// 调用 asyncFunction 函数,并使用 then 处理 Promise
返回的结果
asyncFunction().then((message) => {
// 在 Promise 被 resolve 后,打印传递过来的 message
(即 'Async Hello!')
console.log(message); // 输出:'Async Hello!'
});
注:
在 JavaScript 的 Promise 中,reject 是一个用于表示操作失败的 函数,它会被用来“拒绝”一个 Promise,并且可以传递一个错误信 息或其他任何你想要的值,通常用于表示异步操作出现问题时的情 况。
reject 的作用:
- 当 Promise 被 reject 时,Promise 的状态变为 rejected, 并且会触发 catch 方法或 then 中的第二个回调函数(如果有 的话)。
- reject 会将错误或者失败的原因传递给后续的错误处理逻辑。 如:
// 定义一个异步函数,返回一个 Promise 对象
function asyncFunction() {
return new Promise((resolve, reject) => {
// 使用 setTimeout 模拟一个异步操作(例如网络请求)
setTimeout(() => {
const success = false; // 设置 success 为
false 来模拟操作失败
if (success) {
// 如果 success 为 true,表示操作成功,调用
resolve
resolve('Async Hello!'); // 返回成功信息
} else {
// 如果 success 为 false,表示操作失败,调用
reject
reject('Something went wrong!'); // 返回失败
信息
}
}, 1000); // 延时 1 秒后执行
});
}
// 调用 asyncFunction,并处理其返回的 Promise
asyncFunction()
.then((message) => {
// 如果 Promise 被 resolve,表示成功,执行此回调
console.log(message); // 打印成功信息:'Async
Hello!'(如果操作成功)
})
.catch((error) => {
// 如果 Promise 被 reject,表示失败,执行此回调
console.log('Error:', error); // 打印错误信
息:'Error: Something went wrong!'(如果操作失败)
});
async/await
// 定义一个异步函数 asyncFunction,返回一个 Promise 对象
async function asyncFunction() {
return new Promise((resolve, reject) => {
// 使用 setTimeout 模拟一个异步操作(例如网络请求)
setTimeout(() => {
resolve('Async Hello!'); // 1秒后返回成功信息
'Async Hello!'
}, 1000); // 延时 1 秒后执行
});
}
// 定义一个异步函数 run,用于调用 asyncFunction 并处理其
返回结果
async function run() {
// 使用 await 等待 asyncFunction 执行完毕,并将其结果
赋值给 message
const message = await asyncFunction();
// 打印 asyncFunction 返回的消息
console.log(message); // 输出 'Async
Hello!'(asyncFunction 返回的结果)
}
// 调用 run 函数
run();
(6)文件系统
读取文件
// 引入 Node.js 的文件系统模块 fs
const fs = require('fs');
// 使用 fs.readFile 异步读取 'example.txt' 文件的内容
fs.readFile('example.txt', 'utf8', (err, data) => {
// 如果在读取过程中发生错误,抛出错误
if (err) throw err;
// 如果文件读取成功,打印读取到的内容
console.log(data); // 输出文件内容(如果文件读取成功)
});
注:
先创建'example.txt'文件,随便写入任意内容。
fs.readFile('example.txt', 'utf8', (err, data) => {...})
fs.readFile 是一个异步函数,用于读取文件。
第一个参数 'example.txt' 是要读取的文件的路径。
第二个参数 'utf8' 是指定读取文件时使用的编码格式,表示文 件内容是以 UTF-8 编码的文本。
第三个参数是回调函数,它接受两个参数:
err:如果文件读取过程中发生错误(如文件不存在),它 将包含错误信息。
data:如果文件读取成功,它包含文件的内容。
if (err) throw err;
如果在文件读取过程中发生错误,抛出错误并终止程序。
写入文件
// 引入 Node.js 的文件系统模块 fs
const fs = require('fs');
// 使用 fs.writeFile 异步写入数据到 'example.txt' 文件
fs.writeFile('example.txt', 'Hello, World!', (err)
=> {
// 如果在写入过程中发生错误,抛出错误
if (err) throw err;
// 如果文件写入成功,打印消息 '文件已保存'
console.log('文件已保存'); // 输出:文件已保存
});
注:
fs.writeFile('example.txt', 'Hello, World!', (err) => {...})
fs.writeFile 是一个异步函数,用于将数据写入指定文件。如 果文件不存在,它会自动创建该文件。
第一个参数 'example.txt' 是要写入的目标文件的路径。
第二个参数 'Hello, World!' 是要写入文件的内容。在本例 中,它是一个简单的字符串。
第三个参数是回调函数,它接受一个参数err: 如果在写入过程中发生错误,err 会包含错误信息。 如果写入操作成功,则 err 为 null。
if (err) throw err;:
如果发生错误,抛出错误并终止程序执行。
3.以上方式会覆盖原文件内容。 不覆盖的方式:追加
const fs = require('fs');
// 使用 fs.appendFile 异步追加内容到 'example.txt' 文件
fs.appendFile('example.txt', 'Hello, World!\n',
(err) => {
// 如果在写入过程中发生错误,抛出错误
if (err) throw err;
// 如果文件内容成功追加,打印消息 '文件内容已追加'
console.log('文件内容已追加');
});
(7)HTTP模块
创建服务器
// 引入 Node.js 的 http 模块,用于创建 HTTP 服务器
const http = require('http');
// 创建一个 HTTP 服务器
const server = http.createServer((req, res) => {
// 设置响应的状态码为 200,表示请求成功
res.statusCode = 200;
// 设置响应头,指定返回内容的类型为纯文本(text/plain)
res.setHeader('Content-Type', 'text/plain');
// 结束响应并发送内容 'Hello, World!' 给客户端
res.end('Hello, World!\n');
});
// 让服务器监听 3000 端口,IP 地址为 '127.0.0.1'(本地地
址)
// 当服务器成功启动时,打印 '服务器正在运行'
server.listen(3000, '127.0.0.1', () => {
console.log('服务器正在运行'); // 输出:服务器正在运行
});
浏览器访问url:http://localhost:3000/app.js
或http://127.0.0.1:3000/app.js
(假设文件名是app.js),localhost与127.0.0.1同理,不 再赘述。
注:
在 Node.js 的 HTTP 服务器中,(req, res) 是回调函数的两个参 数,它们分别代表请求对象(req)和响应对象(res)。它们用 于处理客户端请求和返回响应。
req (请求对象):
全称:Request(请求)
作用:表示客户端(通常是浏览器)发送的 HTTP 请求。通过 req 对象,服务器可以获取到请求的详细信息,如请求的 URL、请求方法、请求头、查询参数、请求体等。
常用属性:
req.url:请求的 URL(路径)。
req.method:请求方法(如 GET、POST)。 req.headers:请求头,包含客户端发送的所有头信息。 req.query:查询参数,用于 GET 请求时获取 URL 中的查 询字符串(例如 ?name=John)。
req.body:请求体,用于 POST 请求时获取客户端发送的数 据(需要配合中间件处理)。
res (响应对象):
- 全称:Response(响应)
作用:表示服务器向客户端返回的 HTTP 响应。通过 res 对 象,服务器可以设置响应的状态码、响应头,并发送响应内容 (如 HTML、JSON、文本等)。
常用方法:
res.statusCode:设置响应的状态码(如 200、404)。 res.setHeader():设置响应头,告诉客户端如何处理响应 内容。
res.end():结束响应并发送数据,通常用于简单的文本响 应。 res.json():将 JavaScript 对象转换为 JSON 格式并发送给 客户端(如果是 JSON 响应)。
res.send():用于发送响应,可以是字符串、对象、缓冲 区等。
处理路由
// 引入 http 模块用于创建 HTTP 服务器
const http = require('http');
// 引入 url 模块用于解析请求的 URL
const url = require('url');
// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
// 使用 url.parse 解析请求的 URL,并获取其路径部分
const parseUrl = url.parse(req.url, true);
const path = parseUrl.pathname;
// 判断请求的路径,如果是根路径 '/'
if (path === '/') {
// 设置响应状态码为 200 (成功)
res.statusCode = 200;
// 设置响应的内容类型为纯文本
res.setHeader('Content-Type', 'text/plain');
// 返回 'Home Page' 的内容
res.end('Home Page\n');
}
// 判断请求的路径是否为 '/about'
else if (path === '/about') {
// 设置响应状态码为 200 (成功)
res.statusCode = 200;
// 设置响应的内容类型为纯文本
res.setHeader('Content-Type', 'text/plain');
// 返回 'About Page' 的内容
res.end('About Page\n');
}
// 如果路径不匹配以上任何情况,则返回 404 (页面未找到)
else {
res.statusCode = 404;
// 设置响应的内容类型为纯文本
res.setHeader('Content-Type', 'text/plain');
// 返回 'Page Not Found' 的内容
res.end('Page Not Found\n');
}
});
// 让服务器监听 3000 端口并在本地 127.0.0.1 地址启动
server.listen(3000, '127.0.0.1', () => {
// 输出服务器启动信息
console.log('服务器正在运行');
});
浏览器分别访问url:
http://127.0.0.1:3000/(匹配根目录,返回"Home Page"页面) http://127.0.0.1:3000/about(匹配about路由,返回"About Page"页面)
http://127.0.0.1:3000/other (无此页面,返回"Page Not Found"页面)
(8)Express框架
安装Express
npm install express
创建Express应用
// 引入 express 模块
const express = require('express');
// 创建一个 express 应用实例
const app = express();
// 设置路由:当访问根路径 (/) 时,返回 "Hello, World!" 字
符串
app.get('/', (req, res) => {
res.send('Hello, World!');
});
// 启动服务器,监听 3000 端口
app.listen(3000, () => {
console.log('服务器正在运行'); // 在控制台输出消息,表示
服务器已启动
});
浏览器访问url:http://127.0.0.1:3000/
路由和中间件
// 引入 express 模块
const express = require('express');
// 创建一个 express 应用实例
const app = express();
// 使用中间件:每次请求都会执行此函数
app.use((req, res, next) => {
// 在控制台输出请求的 HTTP 方法和 URL
console.log(`${req.method} ${req.url}`);
// 调用 next(),继续处理请求
next();
});
// 定义根路由,当访问根路径时返回 "Home Page"
app.get('/', (req, res) => {
res.send('Home Page');
});
// 定义/about 路由,当访问 /about 路径时返回 "About Page"
app.get('/about', (req, res) => {
res.send('About Page');
});
// 启动服务器,监听 3000 端口
app.listen(3000, () => {
console.log('服务器正在运行'); // 在控制台输出消息,表示
服务器已启动
});
浏览器访问:
进行观察,观察到请求方式及请求路由被记录到vscode输出面板上
(9)数据库连接
MySQL
安装 mysql:
npm install mysql
连接MySQL:
// 引入 mysql 模块
const mysql = require('mysql');
// 创建与数据库的连接
const connection = mysql.createConnection({
host: 'localhost', // 数据库服务器地址,通常是
localhost(本地)或远程 IP 地址
user: 'root', // 连接数据库的用户名
password: 'root', // 用户密码
database: 'mydatabase', // 需要连接的数据库名称
});
// 连接数据库
connection.connect((err) => {
// 如果连接发生错误,抛出错误信息
if (err) throw err;
// 连接成功后,在控制台输出提示信息
console.log('连接到数据库');
});
注:修改为自己数据库所对应的信息。