PHP面试

1:PHP怎么防止sql 注入 ?

一)使用参数化查询

参数化查询是防止 SQL 注入的最有效方法之一。在参数化查询中,SQL 语句中的变量被替换为实际的值,而不是直接将用户输入的数据嵌入到 SQL 语句中。这样可以避免攻击者通过插入恶意代码来改变 SQL 语句的语义。

以下是一个使用参数化查询的示例代码:

<?php
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT * FROM users WHERE username = :username AND password = :password";

$stmt = $pdo->prepare($sql);
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();
?>
在这个示例中,我们使用了 PDO 扩展来执行参数化查询。通过将变量绑定到参数上,避免了直接将用户输入的数据嵌入到 SQL 语句中,从而有效地防止了 SQL 注入。

(二)对用户输入进行过滤和验证

除了使用参数化查询外,我们还可以对用户输入进行过滤和验证,以确保输入的数据符合预期的格式和范围。例如,我们可以检查用户输入的用户名是否只包含字母和数字,密码是否符合一定的长度和复杂度要求等。

以下是一个对用户输入进行过滤和验证的示例代码:

<?php
$username = $_POST['username'];
$password = $_POST['password'];

// 过滤用户名,只允许字母和数字
$username = preg_replace('/[^a-zA-Z0-9]/', '', $username);

// 验证密码长度和复杂度
if (strlen($password) < 8 ||!preg_match('/[a-z]/', $password) ||!preg_match('/[A-Z]/', $password) ||!preg_match('/[0-9]/', $password)) {
   
    die('密码不符合要求');
}
?>
在这个示例中,我们通过正则表达式对用户名进行过滤,只允许字母和数字。同时,我们对密码进行了长度和复杂度的验证,确保密码符合一定的要求。

(三)使用安全的框架和库

许多 PHP 框架和库都提供了防止 SQL 注入的功能。例如,Laravel 框架提供了查询构建器和数据库迁移等功能,可以方便地执行参数化查询和防止 SQL 注入。使用这些安全的框架和库可以大大减少开发人员的工作量,同时也提高了应用的安全性。

四、实际应用中的注意事项

(一)保持警惕

即使我们已经采取了防止 SQL 注入的措施,也不能掉以轻心。攻击者可能会不断尝试新的方法来突破我们的防御,因此我们需要时刻保持警惕,及时发现和处理潜在的安全威胁。

(二)定期更新和维护

随着技术的不断发展,新的安全漏洞和威胁也会不断出现。因此,我们需要定期更新和维护我们的应用,确保应用的安全性得到持续的保障。

(三)培训和教育

开发人员是应用安全的第一道防线。因此,我们需要对开发人员进行培训和教育,提高他们的安全意识和技能,让他们能够更好地应对安全威胁。

2:在tinkphp 中怎么定义路由 ??

. 在配置文件中定义路由
在 ThinkPHP 5 和 6 中,你可以在 route 配置文件中定义路由。这个文件通常位于项目的 route 目录下。

示例:

php
// route/route.php
use think\facade\Route;

Route::get('hello/:name', 'index/hello');
Route::post('login', 'user/login');
Route::put('update', 'user/update');
Route::delete('delete', 'user/delete');

// 资源路由
Route::resource('news', 'News');
2. 使用路由控制台命令
ThinkPHP 提供了一组控制台命令来生成路由定义代码。

生成路由命令:

bash
php think route:list
php think route:create
3. 动态定义路由
你可以在应用程序的启动过程中或任何公共脚本中动态定义路由。

示例:

php
// 动态定义一个 GET 路由
Route::get('hello/:name', 'index/hello');

// 动态定义一个 POST 路由
Route::post('login', 'user/login');

// 动态定义一个路由,使用闭包
Route::get('closure', function () {
    return 'Hello, ThinkPHP!';
});

// 动态定义一个路由,带中间件
Route::get('middleware', 'user/profile')->middleware('auth');
4. 使用注解定义路由
在控制器中,你可以使用注解来定义路由,这在 ThinkPHP 6 中特别有用。

示例:

php
/**
 * @Route("hello/:name", method="get", controller="index/hello")
 */
public function myRoute()
{
    return 'Hello, ThinkPHP!';
}
5. 分组路由
你可以将一组具有共同前缀或中间件的路由分组。

示例:

php
Route::group('api', function () {
    Route::get('user', 'api/user/index');
    Route::post('login', 'api/user/login');
    Route::put('update', 'api/user/update');
    Route::delete('delete', 'api/user/delete');
});
6. 变量规则
你可以在路由定义中使用变量,并定义变量规则。

示例:

php
Route::get('user/[:id]', 'User/index');
Route::get('user/[:id]/profile', 'User/profile');
7. 路由参数
你可以在路由中定义参数,并在控制器方法中获取这些参数。

示例:

php
// 定义带参数的路由
Route::get('user/:id', 'user/read');

// 控制器中获取参数
public function read($id)
{
    // 获取用户信息
}

3:七层网络模型:

七层网络模型



七层网络模型,也称为 OSI(Open Systems Interconnection)参考模型,是国际标准化组织(ISO)制定的一个网络通信模型。这个模型将整个网络通信过程分解为七个层次,每个层次都有其特定的功能,它们从上到下依次是:

应用层 (Application Layer):

为应用软件提供网络服务,例如 HTTP、FTP、SMTP 等协议。
处理网络应用程序的具体功能。
表示层 (Presentation Layer):

确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。
负责数据格式转换、数据加密解密等。
会话层 (Session Layer):

建立、管理和终止应用程序之间的会话。
负责数据交换定界和同步功能,包括建立检查点和恢复方案。
传输层 (Transport Layer):

提供端到端的通信控制。
负责数据的完整性、错误检测和流量控制,如 TCP、UDP 协议。
网络层 (Network Layer):

负责数据包从源到目的地的传输和路由选择。
处理网络地址分配、路由和流量控制,如 IP 协议。
数据链路层 (Data Link Layer):

在相邻的网络设备之间提供数据传输。
负责帧的检测和物理地址寻址,如 Ethernet、WIFI 等。
物理层 (Physical Layer):

处理通过物理媒介传输数据的技术细节。
包括定义物理设备标准、电气特性等,确保数据可以在网络媒介上传输

4:TCP,UDP:

TCP(传输控制协议,Transmission Control Protocol)和 UDP(用户数据报协议,User Datagram Protocol)是两种网络通信协议,它们都工作在OSI模型的传输层,但它们在如何传输数据方面有着根本的不同。

TCP(传输控制协议)
TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议。它的主要特点包括:

面向连接:在数据传输开始之前,TCP 通过三次握手过程建立一个稳定的连接。

可靠的传输:TCP 确保数据无差错、不丢失、不重复、按顺序到达。它通过序列号、确认应答、重传机制、窗口控制和拥塞控制等机制来实现。

基于字节流:TCP 为应用程序提供连续的数据流,而不是分离的数据包。

流量控制:TCP 通过窗口大小来控制发送方的发送速度,以避免接收方处理不过来。

拥塞控制:TCP 动态调整发送数据的速率,以避免网络拥塞。

全双工通信:TCP 允许数据在两个方向上同时传输。

由于 TCP 保证了数据传输的可靠性,它适用于那些对数据完整性和准确性要求较高的应用,如 Web 浏览(HTTP)、文件传输(FTP)、邮件传输(SMTP)等。

UDP(用户数据报协议)
UDP 是一种无连接的、不可靠的传输层通信协议。它的主要特点包括:

无连接:UDP 不需要在数据传输前建立连接,发送方可以直接发送数据。

不可靠的传输:UDP 不保证数据的完整性、顺序或可靠性。它不进行错误检测和重传。

基于数据报:UDP 将应用程序的数据封装成数据报进行传输,每个数据报独立处理。

快速传输:由于没有复杂的控制机制,UDP 的传输速度通常比 TCP 快。

单播、多播和广播:UDP 支持单播、多播和广播传输。

低开销:UDP 的头部只有 8 字节,比 TCP 的头部开销小得多。

由于 UDP 不提供数据传输的可靠性保证,它适用于那些对传输速度要求高、可以容忍一定丢包率的应用,如实时视频会议、在线游戏、DNS 查询等。

总结
TCP 提供了连接导向、可靠的字节流服务,适合需要可靠传输的应用。
UDP 提供了无连接、尽最大努力交付的差错检测,适合对高速传输和实时性要求高的应用。
选择 TCP 还是 UDP 取决于应用程序的具体需求和网络环境。

5:TCP和UDP的区别:

TCP(传输控制协议)和 UDP(用户数据报协议)是两种常用的传输层协议,它们在实际应用中有一些主要的区别:

连接性:

TCP:面向连接的协议。在数据传输开始之前,必须与接收方建立一个连接。
UDP:无连接的协议。数据传输前不需要建立连接。
数据完整性:

TCP:提供数据包的顺序控制、重传机制、数据校验等功能,确保数据完整性。
UDP:不保证数据包的顺序、完整性或可靠性。
传输速度:

TCP:由于需要建立连接和保证数据完整性,传输速度相对较慢。
UDP:不需要建立连接,头部开销小,传输速度更快。
头部开销:

TCP:头部至少需要20字节,最大可以达到60字节。
UDP:头部固定为8字节。
流量控制和拥塞控制:

TCP:具有流量控制和拥塞控制机制。
UDP:不提供这些控制。
用途:

TCP:适用于需要可靠传输的应用,如Web浏览(HTTP)、邮件传输(SMTP)和文件传输(FTP)。
UDP:适用于对传输速度要求高、可以容忍丢包的应用,如实时视频、音频传输(RTP)、在线游戏和DNS查询。
错误恢复:

6:三次握手:


三次握手(Three-way Handshake)
三次握手是 TCP(传输控制协议)用于在两个网络实体之间建立可靠连接的过程。这个过程确保了两端的发送和接收能力都是就绪的。

第一次握手:客户端发送一个带有 SYN(同步序列编号)标志的包到服务器以发起一个新的连接,并指定客户端的初始序列号。
第二次握手:服务器接收到 SYN 包后,需要确认客户端的 SYN(ACK 确认号),同时自己也发送一个 SYN 包,即 SYN+ACK 包。
第三次握手:客户端收到服务器的 SYN+ACK 包后,发送一个确认包 ACK 到服务器端,连接建立成功。

7:四次挥手:

四次挥手(Four-way Handshake)
四次挥手是 TCP 用于终止一个连接的过程。

第一次挥手:客户端发送一个带有 FIN(结束)标志的包到服务器,请求关闭连接。
第二次挥手:服务器收到 FIN 包后,发送一个 ACK 包确认,进入半关闭状态。
第三次挥手:服务器发送一个 FIN 包给客户端请求关闭它的连接。
第四次挥手:客户端收到 FIN 包后,发送一个 ACK 包作为回应,然后双方关闭连接

8:数据库索引结构:

索引结构
在数据库中,索引是用来加快检索数据速度的数据结构。常见的索引类型包括 B+Tree 索引、B-Tree 索引和 Hash 索引等。

为什么使用 B+Tree
B+Tree 是一种自平衡的树数据结构,特别适用于数据库索引。以下是使用 B+Tree 的原因:

平衡性:B+Tree 会保持元素有序,并且自动保持平衡,使得新插入和删除操作都可以在对数时间内完成。

减少磁盘 I/O:B+Tree 由于其结构特点,可以减少查找数据时所需的磁盘 I/O 次数。

查询效率:B+Tree 可以进行范围查询,而且查询效率很高。

适合页式存储:数据库系统通常以页(page)为单位存储数据,B+Tree 的节点可以很好地对应于这些页。

高扇出性:B+Tree 每个节点可以有大量的子节点,这减少了树的高度。

B+Tree 结构
B+Tree 的每个节点包含键值和指向子节点的指针。与 B-Tree 不同的是,B+Tree 的所有键值都存在于叶子节点中,非叶子节点仅存储键值,不存储实际数据。叶子节点通常通过指针相互连接,形成链表,以优化范围查询。

退化情况
B+Tree 会在以下情况下退化:

插入顺序数据:如果插入的数据是顺序的,B+Tree 可能会退化成链表。

低度数:如果 B+Tree 的节点度(子节点数量)很低,树的高度会增加,导致查询效率降低。

频繁的删除操作:频繁删除可能导致树的某些部分变得稀疏,从而降低效率。

B+Tree 与 B-Tree 比较
存储结构:B-Tree 的数据记录可以存储在叶节点和非叶节点,而 B+Tree 的数据记录仅存储在叶节点。

查询效率:B+Tree 的查询效率通常更高,因为其叶子节点形成了一个链表,适合范围查询。

物理存储:B+Tree 比 B-Tree 更适合页式存储,因为它的非叶子节点不存储数据。

B+Tree 与 SkipList 比较
SkipList(跳表)是一种基于多级索引的链表结构,它通过构建多级索引来加快搜索速度。

实现复杂性:SkipList 的实现比 B+Tree 简单。

更新性能:SkipList 在插入和删除操作上通常比 B+Tree 快。

范围查询:B+Tree 适合范围查询,而 SkipList 则需要遍历链表。

内存消耗:SkipList 通常比 B+Tree 更消耗内存。

可预测性:B+Tree 的性能更可预测,而 SkipList 可能因随机性而波动。

总结

9:mysam和Innodb 的区别:

MyISAM 存储引擎
性能:MyISAM 通常在读取密集型的应用中表现更好,因为它对于全表扫描的速度非常快。
表级锁定:MyISAM 使用表级锁定,这意味着在任何时候,只允许一个进程可以写入数据,但可以有多个进程读取数据。
不支持事务:MyISAM 不支持事务处理,这意味着它不支持 COMMIT 和 ROLLBACK 命令。
崩溃恢复:MyISAM 没有崩溃恢复功能,这意味着如果数据库崩溃,可能会出现数据丢失。
适合场景:MyISAM 适合于那些不需要事务支持、对插入和查询速度要求较高的应用。
InnoDB 存储引擎
性能:InnoDB 在写入密集型的应用中表现更好,因为它支持事务处理和行级锁定。
行级锁定:InnoDB 使用行级锁定,这意味着在任何时候,可以有多个进程写入不同的行,大大提高了写操作的并发性。
支持事务:InnoDB 支持事务处理,包括提交(COMMIT)和回滚(ROLLBACK),提供了 ACID 兼容的事务特性。
崩溃恢复:InnoDB 具有崩溃恢复能力,即使在数据库崩溃后也能确保数据的完整性。
外键约束:InnoDB 支持外键约束,有助于保持数据的完整性。
适合场景:InnoDB 适合于需要事务支持、高并发读写操作、数据完整性要求较高的应用


锁定机制:

MyISAM:表级锁定。
InnoDB:行级锁定。
事务支持:

MyISAM:不支持事务。
InnoDB:支持事务。
崩溃恢复:

MyISAM:不支持崩溃恢复。
InnoDB:支持崩溃恢复。
外键约束:

MyISAM:不支持外键约束。
InnoDB:支持外键约束。

10:事务:

事务(Transaction)
事务是数据库管理系统中的一个核心概念,用于确保数据的完整性和一致性。它是一系列操作的集合,这些操作要么全部成功,要么全部失败。

概念
原子性(Atomicity):事务是原子工作单元,事务中的操作要么全部完成,要么全部不完成。
一致性(Consistency):事务必须确保数据库从一个一致性状态转换到另一个一致性状态。
隔离性(Isolation):事务之间的操作是隔离的,不应该互相影响。
持久性(Durability):一旦事务提交,它对数据库的改变就是永久的,即使系统发生故障也不会丢失。

11:redis:


为什么单线程也高效
Redis 是一个单线程的键值存储系统,其高效性主要来源于以下因素:

IO多路复用:Redis 使用 epoll(Linux)或 kqueue(BSD)等 IO 多路复用技术,可以高效地处理大量的并发连接和请求。

非阻塞IO:Redis 的文件事件处理器使用非阻塞 IO,这使得单个线程可以管理多个 IO 操作而不会阻塞。

内存计算:Redis 的操作主要在内存中执行,避免了磁盘IO的开销。

事件驱动模型:Redis 的请求处理是事件驱动的,减少了多线程上下文切换的损耗。

数据结构优化:Redis 的数据结构(如压缩列表quicklist、跳表等)经过优化,可以提供高效的读写性能。



数据结构
String:简单的动态字符串,支持二进制安全。
Hash:使用哈希表实现,适合存储对象或映射表。
List:最新版本使用 quicklist 实现,是一个压缩表的双向链表,支持两端的推拉操作。
Set:使用整数集合或哈希表实现,支持快速查找、添加和删除。
Sorted Set(ZSet):使用跳表(Skip List)和哈希表实现,支持排序。
Redis 主从复制过程
连接:从服务器连接到主服务器。
同步:主服务器将当前的数据快照发送给从服务器。
命令传播:主服务器将写命令发送给从服务器。
Redis Cluster 工作原理
槽(Slot):16384 个槽分布在集群中的所有主节点。
数据分片:数据被分割成多个部分,每个部分分配到不同的节点。
哈希一致性:使用哈希函数将键分布在不同的槽。
处理大Key:避免大Key带来的迁移负担,可以拆分大Key。
处理热Key:通过代码实现负载均衡来处理热Key问题。
内存淘汰策略
LRU(Least Recently Used):最近最少使用。
LFU(Least Frequently Used):最少使用频率。
Bitmap 和 HyperLogLog
Bitmap:使用位数组来存储信息,适合表示布尔值。
HyperLogLog:用于估算数据的基数,即不同元素的数量。
过期键删除
惰性删除:只有当键被访问时才检查并删除。
定期删除:定期删除一些过期键。
结合删除:结合惰性删除和定期删除。
缓存与数据库一致性
双删策略:先删除缓存,再更新数据库,然后再次删除缓存。
延时双删:在删除缓存后,等待一定时间再删除缓存,以避免缓存击穿。
缓存穿透、雪崩、击穿
缓存穿透:使用布隆过滤器来避免查询不存在的键。
缓存雪崩:均匀地设置缓存过期时间,避免大量缓存同时过期。
缓存击穿:对热点键设置互斥锁,避免同时查询数据库。
布隆过滤器原理
布隆过滤器使用位数组和多个哈希函数来测试一个元素是否在一个集合中。它允许一定的误报率,但可以高效地处理大量数据。

故障转移
Redis Sentinel 用于实现故障转移。在主节点故障时,它可以自动选举新的主节点并更新配置。

Raft 协议
Raft 是一种用于管理分布式数据系统的数据一致性协议。Redis Cluster 的故障转移机制部分基于 Raft 协议。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值