php面试题
php中error_reporting函数作用
设置 PHP 的报错级别并返回当前级别
E_NOTICE 表示一般情形不记录,只有程序有错误情形时才用到
E_WARNING 通常都会显示出来,但不会中断程序的执行。这对除错很有效。
E_ERROR 通常会显示出来,亦会中断程序执行。
E_PARSE 从语法中解析错误。
E_CORE_ERROR 类似 E_ERROR,但不包括 PHP 核心造成的错误。
E_CORE_WARNING 类似 E_WARNING,但不包括 PHP 核心错误警告
error_reporting = E_ALL & ~E_NOTICE ; 显示所有的错误,除了提醒
PHP中include和require的区别
- 当文件不存在的时候, require会终止进程, 而include不会。
- include()是有条件包含函数,而 require()则是无条件包含函数。
php转义特殊字符函数
1、addslashes() 在预定义的字符前添加反斜杠。单引号('),双引号("),反斜杠(),NULL。
2、mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。\x00,\n,\r,\,',",\x1a。
3、htmlspecialchars()把HTML中的几个特殊字符转义成HTML Entity(格式:&xxxx;)形式。包括(&),(‘),(“),(<),(>)五个字符。
什么是面向对象,面向对象的特性
面向对象是一种开发模式
特性:1、封装,2、继承,3、多态
mysql MyIASM和InnoDB区别
- 数据的存储结构不同。
- MyISAM在磁盘上存储成三个文件,它们以表的名字开头来命名。.frm文件存储表定义。.MYD(MYD)存储数据文件。.MYI(MYIndex)存储索引文件。
- InnoDB在磁盘上保存为两个文件。.frm文件同样存储为表结构文件,.ibd文件存储的是数据和索引文件。
- InnoDB 是聚集索引,MyISAM 是非聚集索引。
- InnoDB 支持事务,MyISAM 不支持事务。
- InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。
- InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
- InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM 会失败;
mysql 事务
1. 四个特性
- 原子性(Atomicity):指事务是一个不可分割的最小工作单位,事务中的操作只有都发生和都不发生两种情况。
- 一致性(Consistency):事务必须使数据库从一个一致状态变换到另外一个一致状态。举一个栗子,李二给王五转账50元,其事务就是让李二账户上减去50元,王五账户上加上50元;一致性是指其他事务看到的情况是要么李二还没有给王五转账的状态,要么王五已经成功接收到李二的50元转账。而对于李二少了50元,王五还没加上50元这个中间状态是不可见的。
- 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability):一个事务一旦提交成功,它对数据库中数据的改变将是永久性的,接下来的其他操作或故障不应对其有任何影响。
2. 事务并发时出现的问题
- 脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的。
- 不可重复读 :对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段之后,T1在读取同一个字段,值就不同了。
- 幻读:对于两个事务T1,T2,T1在A表中读取了一个字段,然后T2又在A表中插入了一些新的数据时,T1再读取该表时,就会发现神不知鬼不觉的多出几行了…
MySQL事务隔离级别
mysql 行锁和表锁
表锁
- 特点:偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行锁
- 特点:偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
- 锁定没有索引数据时会升级为表锁。
mysql 共享锁(读锁)和排他锁(写锁)
共享锁
- 事务对某数据上了共享锁,其他事务可以继续读,也允许加共享读锁(共享锁转移给其他事务,锁是只有一把),但是不能写。
- select * from table where id = 1 lock in share mode;
排他锁
- 当事务对某数据加上了排他锁,只有当前事务能够对这数据执行修改或删除操作。其他事务,不能读,不能写 ,不能再加排他锁。
- select * from table where id =1 for update;
- insert,delete,update自动加排他锁
mysql 性能优化
- 建表时字段指定为not null。
- 合理建立索引,尽量使用唯一索引,每个表索引最好不要超过5个
- 指定查询字段,不要select *,尽量能用到索引覆盖。
- 非必要不使用子查询,使用join连接查询代替子查询。
- innodb count() 统计查询时count(*)比count(id)性能好
mysql索引失效的情况有哪些
1、like查询以“%”开头。
2、使用or时没有注意。
- 没有同时使用索引
- where code = '001' or height = 8; 改为 (select * from test1 where code = '001')
union (select * from test1 where height = 8);
3、组合索引中不是使用第一列索引。
4、在索引列上使用“IS NULL”或“IS NOT NULL”操作。
5、在索引字段上使用“not”,“!=”。
6、使用了表达式或者函数,如:where id + 1 = 2。
7、字符类型没加引号,如:where user_name = 123456。
mysql主从复制
一、原理
- Master的更新事件(update、insert、delete)会按照顺序写入bin-log中。当Slave连接到Master的后,Master机器会为Slave开启binlog dump线程,该线程会去读取bin-log日志。
- Slave连接到Master后,Slave库有一个I/O线程 通过请求binlog dump thread读取bin-log日志,然后写入从库的relay log日志中。
- Slave还有一个 SQL线程,实时监控 relay-log日志内容是否有更新,解析文件中的SQL语句,在Slave数据库中去执行。
二、总结
- Master必须开启bin-log功能。
- 整个Mysql主从复制一共开启了3个线程。Master开启 dump线程,Slave开启 IO线程 和 SQL线程。
- Master和Slave交互的时候,是Slave去请求Master,而不是Master主动推给Slave。Slave通过IO线程连接Master后发起请求,Master服务器收到Slave IO线程发来的日志请求信息,io线程去将bin-log内容返回给slave IO线程。
三、异步复制
MySQL主从同步默认是异步复制的。就是上面原理三步中,只有第一步是同步的(也就是Mater写入bin log日志),就是主库写入binlog日志后即可成功返回客户端,无须等待binlog日志传递给从库的过程。Master 不关心 Slave 的数据有没有写入成功。因此如果Master和Slave之间有网络延迟,就会造成暂时的数据不一致的现象;如果Master出故障,而数据还没有复制过去,则会造成数据丢失;但也有好处,效率较其他两种复制方式最高。
四、同步复制
Master主机将事件发送给Slave主机后会触发一个等待,直到所有Slave节点(如果有多个Slave)返回数据复制成功的信息给Master。这种复制方式最安全,但是同时,效率也是最差的。
五、半同步复制
Master主机将事件发送给Slave主机后会触发一个等待,直到其中一个Slave节点(如果有多个Slave)返回数据复制成功的信息给Master。由此增强了数据的一致性,但是因为Master主机的确认开销,会损耗一部分的性能;另外,半同步复制除了不需要等待所有Slave主机确认事件的接收外,半同步数据复制并不要求那些事件完全地执行,因此,仍有可能看到在Slave主机上数据复制延迟的发生,如果因为网络延迟等原因造成Slave迟迟没有返回复制成功的信息,超过了Master设置的超时时长,半同步复制就降级为异步复制方式,而后继续数据复制。
六、主从延时的来源
- 从库性能太差。
- 从库的压力较大,即从库承受了大量的请求。
- 执行大事务。因为主库上必须等事务执行完成才会写入 binlog,再传给备库。如果一个主库上语句执行 10 分钟,那么这个事务可能会导致从库延迟 10 分钟。
- 从库不支持并行复制,只有一个线程消费relay log,速度跟不上。
七、主从延时解决办法
- 强制走主库方案(强一致性)。
- 使用缓存,缓解从库压力。
redis数据类型
- string(字符串)。
- hash(哈希)。
- list(列表)。
- set(集合)。
- sorted set (有序集合)。
redis持久化策略
Redis提供了两种持久化机制:RDB快照(snapshot)和AOF(append-only file)日志。
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
redis过期策略
定期删除+惰性删除
- redis默认是每隔100ms就随机抽取一些设置了过期时间的key进行检查,如果过期了就会删除。
- 在读取某个key的时候,redis会先检查一个该key是否过期,如果过期了,就会在此时删除,然后不会给你返回任何东西。
redis内存淘汰机制 (maxmemory-policy)
- noeviction: (默认策略) 当内存不足以容纳新写入数据时,新写入操作会报错。
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key。
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key。
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。
redis为什么这么快
- 数据存在内存中,避免了磁盘IO的开销。
- 数据结构简单,对数据操作也简单。Redis中的数据结构是专门进行设计的,每种数据结构都有一种或多种数据结构来支持。
- 采用单线程,省去了很多上下文切换的时间以及CPU消耗,不存在竞争条件,不用去考虑各种锁的问题,不存在加锁释放锁操作,也不会出现死锁而导致的性能消耗。
- 使用基于IO多路复用机制的线程模型,可以处理并发的链接。
Redis缓存和MySQL数据一致性的问题
缓存双淘汰法
- 先淘汰缓存
- 再写数据库
- 往队列发送淘汰消息,1秒后消费消息,删除缓存
缓存穿透、缓存击穿、缓存雪崩问题及解决方案
缓存穿透:指的是缓存中不存在key的数据,导致请 求打到数据库上,导致数据库压力过大。
解决方案:
- 做好参数校验,无效的请求直接返回。例如user_id <= 0。
- 对缓存中找不到的key,需要去数据库查找的key,缓存到Redis中,但是可能会导致Redis中缓存大量无效的key,可以设置一个很短的过期时间,例如1分钟。
- 也可以使用布隆过滤器,将所有可能的存在的数据通过去hash值的方式存入到一个足够大的bitmap中去,处理请求时,通过在bitmap中查找,可以将不存在的数据拦截掉。
缓存击穿:主要指的是某个热点key失效,导致大量请求全部转向数据库,导致数据库压力过大。
解决方案:
- 对热点key设置永不过期。
- 加互斥锁,缓存中没有热点key对应的数据时,等待100ms,由获得锁的线程去读取数据库然后设置缓存。
缓存雪崩:主要指的是短时间内大量key失效,导致所有请求全部转向数据库,导致数据库压力过大。
解决方案:
- 在给缓存设置失效时间时加一个随机值,避免集体失效。
- 双缓存机制,缓存A的失效时间为20分钟,缓存B的失效时间会比A长一些,从缓存A读取数据,缓存A中没有时,去缓存B中读取数据,并且启动一个异步线程来更新缓存A(如果已经有异步线程正在更新了,就不用重复更新了)。以及更新缓存B,以便延迟B的过期时间。
Redis和 memecache 有什么区别
- Redis相比memecache,拥有更多的数据结构和支持更丰富的数据操作。
- 内存使用率对比,Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于memecache。
- 性能对比:Redis只使用单核,memecache使用多核。
- Redis支持磁盘持久化,memecache不支持。
- Redis支持分布式集群,memecache不支持。
http协议状态码的含义
200 : 成功,表示访问成功,正常状态。
301 : 永久移动,表示本网页已经永久性的移动到一个新的地址,在客户端自动将请求地址改为服务器返回的新地址。
302 : 临时重定向,表示网页暂时性的转移到一的新的地址,客户端在以后可以继续向本地址发起请求。
303 : 表示必须临时重定向,并且必须使用GET方式请求。
304 : 重定向至浏览器本身,当浏览器多次发起同一请求,且内容未更改时,使用浏览器缓存,这样可以减少网络开销。
401 : 表示用户没有访问权限,需要进行身份认证。
403 : 表示没有权限,服务器拒绝访问请求。
404 : 这是最常见的错误,表示找不到系统资源,但是只是暂时性地。
500 : 表示服务器程序错误,一个通用的错误信息。
503 : 表示服务器繁忙,或者服务器负载,通常这只是一个临时状态。
CSRF和xss攻击及预防
CSRF:跨站点请求伪造,攻击者盗用了你的身份,以你的名义发送恶意请求
原理:
- 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
- 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
- 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
- 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
- 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
防御:
- 验证 HTTP Referer 字段。HTTP头中的Referer字段记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,而如果黑客要对其实施 CSRF攻击,他一般只能在他自己的网站构造请求。因此,可以通过验证Referer值来防御CSRF 攻击。
- 使用验证码。关键操作页面加上验证码,后台收到请求后通过判断验证码可以防御CSRF。但这种方法对用户不太友好。
- 在请求中添加防伪token并验证。客户端请求包含表单的HTML页面,服务器在响应中包含防伪token,隐藏在表单字段中,提交时需要带上防伪token。
XSS:跨站点脚本攻击,由用户输入一些数据到你的网站,其中包括客户端脚本(通常JavaScript)。如果你没有过滤就输出数据到另一个web页面,这个脚本将被执行。XSS攻击常出现在提交表单中,如博客的评论区等,用户可以通过提交评论:,那么只要访问该页面的用户都会弹窗,有些人利用XSS攻击窃取用户名密码,调用黑客的工程,将用户名和密码发送过去,也可以伪装成钓鱼网站。例如在表单中注入: 那么页面会跳转到xxx.com,还可以根据js获取本地浏览器的cookie信息,根据cookie信息完全可以模拟用户。
预防:使用PHP的htmlentities()函数过滤再输出到浏览器。
PHP 数组排序函数
- sort() - 以升序对数组排序
- rsort() - 以降序对数组排序
- asort() - 根据值,以升序对关联数组进行排序
- ksort() - 根据键,以升序对关联数组进行排序
- arsort() - 根据值,以降序对关联数组进行排序
- krsort() - 根据键,以降序对关联数组进行排序
rabbitmq常用的五种模式
- 简单模式HelloWorld:一个生产者、一个消费者,不需要设置交换机(使用 默认的交换机)。
- 工作队列模式 Work Queue:一个生产者、多个消费者(竞争关系),不需要设置交换机(使用默认 的交换机)
- 路由模式 Routing:需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列。
- 发布订阅模式 Publish/subscribe:需要设置类型为fanout的交换机,并且交换机和队列进行绑定, 当发送消息到交换机后,交换机会将消息发送到绑定的队列。
- 通配符模式 Topic:需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的 routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列。
rabbitmq如何避免消息丢失
- 生产者发送消息时使用事务,或者使用confirm模式。
- 消息持久化:Exchange 设置持久化,Queue 设置持久化,发送消息设置发送模式deliveryMode=2。
- 消费者使用ack应答机制,使用手动应答机制。