php面试题

4-19 1,900 views

php魔术方法

__get( $property )       当调用一个未定义的属性时访问此方法
__set( $property, $value )    给一个未定义的属性赋值时调用
__isset( $property ) 当在一个未定义的属性上调用isset()函数时调用此方法
__unset( $property ) 当在一个未定义的属性上调用unset()函数时调用此方法
__call( $method, $arg_array ) 当调用一个未定义(包括没有权限访问)的方法是调用此方法
__autoload 函数,使用尚未被定义的类时自动调用。通过此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
注意: 在 __autoload 函数中抛出的异常不能被 catch 语句块捕获并导致致命错误。
__construct 构造方法,当一个对象被创建时调用此方法,好处是可以使构造方法有一个独一无二的名称,无论它所在的类的名称是什么,这样你在改变类的名称时,就不需要改变构造方法的名称
__destruct 析构方法,PHP将在对象被销毁前(即从内存中清除前)调用这个方法
PHP5中的对象赋值是使用的引用赋值,使用clone方法复制一个对象时,对象会自动调用__clone魔术方法,如果在对象复制需要执行某些初始化操作,可以在__clone方法实现。
__toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时,如果类没有实现此方法,则无法通过echo打印对象,否则会显示:Catchable fatal error: Object of class test could not be converted to string in,此方法必须返回一个字符串。

在PHP 5.2.0之前,__toString方法只有结合使用echo() 或 print()时 才能生效。PHP 5.2.0之后,则可以在任何字符串环境生效(例如通过printf(),使用%s修饰符),但 不能用于非字符串环境(如使用%d修饰符)。从PHP 5.2.0,如果将一个未定义__toString方法的对象 转换为字符串,会报出一个E_RECOVERABLE_ERROR错误。

_sleep 串行化的时候用
__wakeup 反串行化的时候调用
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。

使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。

相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

它的工作方式类似于 __call() 魔术方法,__callStatic() 是为了处理静态方法调用,PHP5.3.0以上版本有效,PHP 确实加强了对 __callStatic() 方法的定义;它必须是公共的,并且必须被声明为静态的。同样,__call() 魔术方法必须被定义为公共的,所有其他魔术方法都必须如此。

7层网络传输协议

1 应用层:
为应用程序提供服务并规定应用程序中通信相关的细节;包括的协议如下:
①:超文本传输协议HTTP:这是一种最基本的客户机/服务器的访问协议;浏览器向服务器发送请求,而服务器回应相应的网页
②:文件传送协议FTP:提供交互式的访问,基于客户服务器模式,面向连接 使用TCP可靠的运输服务
   主要功能:减少/消除不同操作系统下文件的不兼容性 
③:远程登录协议TELNET:客户服务器模式,能适应许多计算机和操作系统的差异,网络虚拟终端NVT的意义
④:简单邮件传送协议SMTP:Client/Server模式,面向连接 
   基本功能:写信、传送、报告传送情况、显示信件、接收方处理信件 
⑤:DNS域名解析协议:DNS是一种用以将域名转换为IP地址的Internet服务
⑥:简单文件传送协议TFTP:客户服务器模式,使用UDP数据报,只支持文件传输,不支持交互,TFTP代码占内存小 
⑦:简单网络管理协议(SNMP): SNMP模型的4个组件:被管理结点、管理站、管理信息、管理协议
   SNMP代理:运行SNMP管理进程的被管理结点
   对象:描述设备的变量
   管理信息库(MIB):保存所有对象的数据结构
⑧DHCP动态主机配置协议: 发现协议中的引导文件名、空终止符、属名或者空,DHCP供应协议中的受限目录路径名 Options –可选参数字段,参考定义选择列表中的选择文件

2 表示层:
将应用处理的信息转换为适合网络传输的格式,或将来自下一层的数据转换为上层能够处理的格式;主要负责数据格式的转换,确保一个系统的应用层信息可被另一个系统应用层读取
具体来说,就是将设备固有的数据格式转换为网络标准传输格式,不同设备对同一比特流解释的结果可能会不同;因此,主要负责使它们保持一致
3 会话层:
负责建立和断开通信连接(数据流动的逻辑通路),记忆数据的分隔等数据传输相关的管理
PS:其实在应用层、表示层、会话层这三层,协议可以共用:
4 传输层:
只在通信双方的节点上(比如计算机终端)进行处理,而无需在路由器上处理,传输层是OSI中最重要、最关键的一层,是唯一负责总体的数据传输和数据控制的一层;
传输层提供端到端的交换数据的机制,检查分组编号与次序,传输层对其上三层如会话层等,提供可靠的传输服务,对网络层提供可靠的目的地站点信息主要功能
在这一层,数据的单位称为数据段(segment)
主要功能:
①:为端到端连接提供传输服务
②:这种传输服务分为可靠和不可靠的,其中Tcp是典型的可靠传输,而Udp则是不可靠传输
③:为端到端连接提供流量控制,差错控制,服务质量(Quality of Service,QoS)等管理服务
包括的协议如下:
TCP:传输控制协议,传输效率低,可靠性强
UDP:用户数据报协议,适用于传输可靠性要求不高,数据量小的数据(比如QQ)
DCCP、SCTP、RTP、RSVP、PPTP等协议
具体的内容可参考这篇文章:http://book.51cto.com/art/200807/81191.htm
5 网络层:
将数据传输到目标地址;目标地址可以使多个网络通过路由器连接而成的某一个地址,主要负责寻找地址和路由选择,网络层还可以实现拥塞控制、网际互连等功能
在这一层,数据的单位称为数据包(packet)
网络层协议的代表包括:IP、IPX、RIP、OSPF等
6 数据链路层:
负责物理层面上的互联的、节点间的通信传输(例如一个以太网项链的2个节点之间的通信);该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。
在这一层,数据的单位称为帧(frame)
数据链路层协议的代表包括:ARP、RARP、SDLC、HDLC、PPP、STP、帧中继等
7 物理层:
负责0、1 比特流(0/1序列)与电压的高低、逛的闪灭之间的转换
规定了激活、维持、关闭通信端点之间的机械特性、电气特性、功能特性以及过程特性;该层为上层协议提供了一个传输数据的物理媒体。只是说明标准
在这一层,数据的单位称为比特(bit)
属于物理层定义的典型规范代表包括:EIA/TIA RS-232、EIA/TIA RS-449、V.35、RJ-45、fddi令牌环网等

nignx跟php的通信协议

FastCGI原理

  FastCGI是一个运用于Http Server和动态脚本语言间通信的接口,多数流行的Http Server都支持FastCGI,包括Apache、Nginx和lighttpd等。同时,FastCGI也被许多脚本语言支持,其中就有PHP。 FastCGI接口方式采用C/S结构,可以将HttP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HttP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给客户端。这种方式可以让HttP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。
  
Nginx+php-fpm实现原理
 Nginx本身不会对PHP进行解析,终端对PHP页面的请求将会被Nginx交给FastCGI进程监听的IP地址及端口,由php-fpm作为动态解析服务器处理,最后将处理结果再返回给nginx。其实,Nginx就是一个反向代理服务器。Nginx通过反向代理功能将动态请求转向后端php-fpm,从而实现对PHP的解析支持,这就是Nginx实现PHP动态解析的原理。
  Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端。

什么是composer?以及composer是干什么用的?工作原理

Composer 是 PHP 的一个依赖管理工具,简单的说就是我们的项目通常会使用其它代码库,这时仅仅是在项目中申明依赖哪些代码库,默认情况下它不会在全局安装任何东西。
对于现代语言而言,依赖管理工具基本上是标配。Java 有 Maven,Python 有 pip,Ruby 有 gem,Nodejs 有 npm。PHP 的则是 PEAR,不过 PEAR 坑不少:依赖处理容易出问题,配置非常复杂,难用的命令行接口等等。
Composer又是如何工作的呢,举个例子当我们去安装一个软件的时候,一般是通过app store 去安装。当我们开发PHP项目的时候,也会面临同样的问题。比如我们需要一个工具记录业务log,那这样我们是不是可以通过一个php的应用商店来下载我们需要的工具。
my-app <-> packagist <-> github

PHP如何实现静态化

    PHP站点开发过程中,因为搜索引擎对PHP页面搜鹿和html页面的收录有一定的区别,为了站点的推广或者SEO的须要,要对站点进行一定的静态化。静态化并非页面中没有动画等元素,而是指网页的html代码都在页面中,不须要再去执行PHP脚本等server端的语言,我们能够直接訪问到的网页。这就是静态网页。

   有一种方式是改写訪问地址,能够通过URL的PATHINFO模式来改动它。让它看上去更像一个静态页面。从而有更大的几率被搜索引擎抓取和收录,仅是对搜索引擎比較友好,伪静态化。

   第二种就是站点能够在用户訪问站点之前就通过一定的程序来进行静态化。生成静态页面。当用户去訪问该页面的时候。因为訪问的是静态页面,因此,訪问速度会比訪问动态页面的速度快了非常多倍,前台的表现是页面载入速度变快,在后台的表现是降低了数据库的连接。降低了数据库的压力,唯一的缺点就是相对占的硬盘多一些,硬盘相对便宜的多。

     纯静态化,就是生成HTML文件的方式,我们须要开启PHP自带的缓存机制,即ob_start来开启缓存。而且在ob_start之前不能有不论什么输出,否则运行失败,然后我们用ob_get_contents函数来获取缓存中的内容,该函数会返回一个字符串。第三个函数就是ob_end_clean,它用来清空缓存中的内容而且关闭,成功返回True,失败返回False。

mysql事务隔离级别

一、事务的基本要素(ACID)

  1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

   2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

   3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

   4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
二、事务的并发问题

  1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

  2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

  3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

三、MySQL事务隔离级别

事务隔离级别                  脏读  不可重复读   幻读
读未提交(read-uncommitted)   是   是           是
不可重复读(read-committed)   否    是          是
可重复读(repeatable-read)    否   否           是
串行化(serializable)         否   否             否

mysql默认的事务隔离级别为repeatable-read

mysql分库分表

数据库设计经验,为什么进行分表?分库?一般多少数据量开始分表?分库?分库分表的目的?什么是数据库垂直拆分?水平拆分?分区等等

一:为什么要分表
当一张表的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表。这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕。分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率。数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;另外,由于无法进行分布式式部署,而一台服务器的资源(CPU、磁盘、内存、IO 等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。

二:分表的方案

1,做 mysql 集群,有人会问 mysql 集群,根分表有什么关系吗?虽然它不是实际意义上的分表,但是它启到了分表的作用,做集群的意义是什么呢?为一个数据库减轻负担,说白了就是减少 sql 排队队列中的 sql 的数量,举个例子:有 10 个 sql 请求,如果放在一个数据库服务器的排队队列中,他要等很长时间,如果把这 10 个 sql 请求,分配到 5 个数据库服务器的排队队列中,一个数据库服务器的队列中只有 2 个,这样等待时间是不是大大的缩短了呢?

linux mysql proxy 的安装,配置,以及读写分离

mysql replication 互为主从的安装及配置,以及数据同步

优点:扩展性好,没有多个分表后的复杂操作(php 代码)

缺点:单个表的数据量还是没有变,一次操作所花的时间还是那么多,硬件开销大。

2. 垂直分割就是按字段分。水平分割。就是按记录分

数据库优化有哪些?分别需要注意什么?

SQL 优化的原则是:将一次操作需要读取的 BLOCK 数减到最低,即在最短的时间达到最大的数据吞吐量。

调整不良 SQL 通常可以从以下几点切入:

检查不良的 SQL,考虑其写法是否还有可优化内容

检查子查询 考虑 SQL 子查询是否可以用简单连接的方式进行重新书写

检查优化索引的使用

考虑数据库的优化器

避免出现 SELECT * FROM table 语句,要明确查出的字段。

在一个 SQL 语句中,如果一个 where 条件过滤的数据库记录越多,定位越准确,则该 where 条件越应该前移。

查询时尽可能使用索引覆盖。即对 SELECT 的字段建立复合索引,这样查询时只进行索引扫描,不读取数据块。

在判断有无符合条件的记录时建议不要用 SELECT COUNT ()和 select top 1 语句。

使用内层限定原则,在拼写 SQL 语句时,将查询条件分解、分类,并尽量在 SQL 语句的最里层进行限定,以减少数据的处理量。

应绝对避免在 order by 子句中使用表达式。

如果需要从关联表读数据,关联的表一般不要超过 7 个。

小心使用 IN 和 OR,需要注意 In 集合中的数据量。建议集合中的数据不超过 200 个。

<> 用 < 、> 代替,> 用 >= 代替,< 用 <= 代替,这样可以有效的利用索引。

在查询时尽量减少对多余数据的读取包括多余的列与多余的行。

对于复合索引要注意,例如在建立复合索引时列的顺序是 F1,F2,F3,则在 where 或 order by 子句中这些字段出现的顺序要与建立索引时的字段顺序一致,且必须包含第一列。只能是 F1 或 F1,F2 或 F1,F2,F3。否则不会用到该索引。

多表关联查询时,写法必须遵循以下原则,这样做有利于建立索引,提高查询效率。格式如下

select sum(table1.je) from table1 table1, table2 table2, table3 table3 where (table1的等值条件(=)) and(table1的非等值条件) and (table2与table1的关联条件) and (table2的等值条件) and (table2的非等值条件) and(table3与table2的关联条件) and (table3的等值条件) and (table3的非等值条件)。

注:关于多表查询时 from 后面表的出现顺序对效率的影响还有待研究。

子查询问题。对于能用连接方式或者视图方式实现的功能,不要用子查询

在 WHERE 子句中,避免对列的四则运算,特别是 where 条件的左边,严禁使用运算与函数对列进行处理。比如有些地方 substring 可以用 like 代替。

如果在语句中有 not in(in)操作,应考虑用 not exists(exists)来重写,最好的办法是使用外连接实现。

对一个业务过程的处理,应该使事物的开始与结束之间的时间间隔越短越好,原则上做到数据库的读操作在前面完成,数据库写操作在后面完成,避免交叉。

请小心不要对过多的列使用列函数和 order by,group by 等,谨慎使用 disti 软件开发 t。

用 union all 代替 union,数据库执行 union 操作,首先先分别执行 union 两端的查询,将其放在临时表中,然后在对其进行排序,过滤重复的记录。

当已知的业务逻辑决定 query A 和 query B 中不会有重复记录时,应该用 union all 代替 union,以提高查询效率。

选取最适用的字段属性 ,MySQL 可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。

例如,在定义邮政编码这个字段时,如果将其设置为 CHAR (255), 显然给数据库增加了不必要的空间,甚至使用 VARCHAR 这种类型也是多余的,因为 CHAR (6) 就可以很好的完成任务了。同样的,如果可以的话,我们应该使用 MEDIUMINT 而不是 BIGIN 来定义整型字段。

另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为 NOTNULL,这样在将来执行查询的时候,数据库不用去比较 NULL 值。

对于某些文本字段,例如 “省份” 或者 “性别”,我们可以将它们定义为 ENUM 类型。因为在 MySQL 中,ENUM 类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。

给你 256M 的内存,统计 10G 文件每个关键字出现的次数如何实现?

# 考察php逐行读取
$handle = fopen("/tmp/uploadfile.txt","r") or die("Couldn't get handle");
if($handle){
    while(!feof($handle)){
        $buffer=fgets($handle,4096);
    }
    fclose($handle);
}

PHP 的生命周期 / 启动流程

完整的生命周期为模块初始化、请求初始化、请求处理、请求关闭、模块关闭五大阶段。

cli 模式下,每个脚本都会完整的执行上面的五大阶段;对于 fastcgi 模式而言,只在启动时会执行模块初始化,之后的请求都走了请求初始化、处理请求、请求关闭三大阶段,在 fastcgi 关闭时执行模块关闭阶段。各个扩展的加载也是在模块初始化阶段完成的。

分布式事务

1.XA事务与MySQL
XA事务就是两阶段提交的一种实现方式

XA规范主要定义了事务管理器TM,和资源管理器RM之间的接口

根据2PC的规范,将一次事务分割成两个阶段

1. prepare阶段

TM向所有RM发送prepare指令,RM接受到指令后执行数据修改和日志记录等操作,然后返回 可以提交/不可提交 给TM

(按照我的理解应该类似于MySQL在开启一个事务之后,只差最后的COMMIT或者ROLLBACK的状态)

2. commit阶段

TM接受到所有RM的prepare结果

如果有RM返回是 不可提交 或者超时,那么向所有RM发送ROLLBACK命令

如果所有RM都返回可以提交,那么向所有RM发送COMMIT命令

中文分词解决方案

1.sphinx分布式配置+中文分词
2.ElasticSearch中文分词,ik分词器

分表主键id解决方案

1. 通过MySQL表生成ID
2.UUID,虽然可以做到全局唯一性,但还是不推荐使用它作为主键,因为我们的实际业务中不管是 user_id 还是 order_id 主键多为整型,而 UUID 生成的是个 32 位的字符串
3.SNOWFLAKE(雪花算法),生成一个 64bit的长整型(Long)数据。
sharding-jdbc 中雪花算法生成的主键主要由 4部分组成,1bit符号位、41bit时间戳位、10bit工作进程位以及 12bit 序列号位。了解了雪花算法的主键 ID 组成后不难发现,这是一种严重依赖于服务器时间的算法,而依赖服务器时间的就会遇到一个棘手的问题:时钟回拨。

redis数据结构

1.String 字符串类型
是redis中最基本的数据类型,一个key对应一个value。

String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。

使用:get 、 set 、 del 、 incr、 decr 等

2.Hash (哈希)
是一个Mapmap,指值本身又是一种键值对结构,如 value={{field1,value1},......fieldN,valueN}}
使用:所有hash的命令都是  h   开头的     hget  、hset 、  hdel 等

3.链表 
List 说白了就是链表(redis 使用双端链表实现的 List),是有序的,value可以重复,可以通过下标取出对应的value值,左右两边都能进行插入和删除数据。

4.Set   集合
集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中  1. 不允许有重复的元素,2.集合中的元素是无序的,不能通过索引下标获取元素,3.支持集合间的操作,可以取多个集合取交集、并集、差集。

5.zset  有序集合
有序集合和集合有着必然的联系,保留了集合不能有重复成员的特性,区别是,有序集合中的元素是可以排序的,它给每个元素设置一个分数,作为排序的依据。

(有序集合中的元素不可以重复,但是score 分数 可以重复,就和一个班里的同学学号不能重复,但考试成绩可以相同)。

设计模式

工厂模式

建立一个工厂(一个函数或一个类方法)来制造新的对象

工厂模式 是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。

单例模式

某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。

单元素模式可以满足此要求。

PHP 中的单例模式(singleton pattern):指的是在 PHP 的应用程序的范围内只对指定的类创建一个实例。

在 PHP 中使用单例模式的类通常拥有一个私有构造函数和一个私有克隆函数,以防 止用户通过创建对象或者克隆对其进行实例化。还有一个静态私有成员变量 $instance 与静态方法 getInstance。getInstance 负责对其本身实例化,然后将这个对象存储在 $instance 静态成员变量中,以确保只有一个实例被创建。

观察者模式

命令链模式

策略模式

用PHP打印出前一天的时间

$a= date("Y-m-d H:i:s", strtotime("-1 days")); 

对于大流量的网站,你会采用什么方法来解决访问量?

(1)首先确认服务器硬件是否满足支持当前的流量;

(2)优化数据库的访问;

(3)禁止外部盗链;

(4)控制大文件下载;

(5)使用不同的主机分流;

(6)使用流量分析统计;

mysql b+tree怎么实现

谈谈你对 mysql 引擎中的MyISAM与InnoDB的区别理解?

MyISAM与InnoDB的区别是什么?

1、 存储结构

MyISAM:每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。

InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

2、 存储空间

MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。

InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

3、 可移植性、备份及恢复

MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。

InnoDB:免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

4、 事务支持

MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。

InnoDB:提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

5、 AUTO_INCREMENT

MyISAM:可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,他可以根据前面几列进行排序后递增。

InnoDB:InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。

6、 表锁差异

MyISAM:只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。

InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

7、 全文索引

MyISAM:支持 FULLTEXT类型的全文索引

InnoDB:不支持FULLTEXT类型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。

8、 表主键

MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。

InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。

9、 表的具体行数

MyISAM:保存有表的总行数,如果select count(*) from table;会直接取出出该值。

InnoDB:没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。

10、 CURD操作

MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。

InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令。

11、 外键

MyISAM:不支持

InnoDB:支持

通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、存储 过程、视图、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外,任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。如果不是很复杂的Web应用,非关键应用,还是可以继续考虑MyISAM的,这个具体情况可以自己斟酌。

redis 和 memache 缓存的区别

总结一:
1.数据类型
Redis数据类型丰富,支持set list等类型
memcache支持简单数据类型,需要客户端自己处理复杂对象
2.持久性
redis支持数据落地持久化存储
memcache不支持数据持久存储
3.分布式存储
redis支持master-slave复制模式
memcache可以使用一致性hash做分布式
value大小不同
memcache是一个内存缓存,key的长度小于250字符,单个item存储要小于1M,不适合虚拟机使用
4.数据一致性不同

redis使用的是单线程模型,保证了数据按顺序提交。

memcache需要使用cas保证数据一致性。CAS(Check and Set)是一个确保并发一致性的机制,属于“乐观锁”范畴;原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作

5.cpu利用
redis单线程模型只能使用一个cpu,可以开启多个redis进程
总结二:

1.Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcached相比一个最大的区别。

2.Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。

3.Redis支持数据的备份,即master-slave模式的数据备份。

4.Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

我个人认为最本质的不同是Redis在很多方面具备数据库的特征,或者说就是一个数据库系统,而Memcached只是简单的K/V缓存
总结三:
redis和memecache的不同在于:
1、存储方式:

memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小

redis有部份存在硬盘上,这样能保证数据的持久性。

2、数据支持类型:

redis在数据支持上要比memecache多的多。

3、使用底层模型不同:

新版本的redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

4、运行环境不同:

redis目前官方只支持Linux 上去行,从而省去了对于其它系统的支持,这样的话可以更好的把精力用于本系统 环境上的优化,虽然后来微软有一个小组为其写了补丁。但是没有放到主干上

memcache只能当做缓存,cache

redis的内容是可以落地的,就是说跟MongoDB有些类似,然后redis也可以作为缓存,并且可以设置master-slave

表中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列

drop table table1  create table table1(  

    a int,  

    b int,  

    c int  )  insert into table1 values(22,24,23)  

  select * from table1  

  select (case when a>b then a else b end),(case when b>c then b else c end)  from table1  

  select (case when a>b then a  

             when a>c then a  

             when b>c then b else c  

             end)  from table1

php 的垃圾回收机制

PHP 可以自动进行内存管理,清除不需要的对象。

PHP 使用了引用计数 (reference counting) GC 机制。

每个对象都内含一个引用计数器 refcount,每个 reference 连接到对象,计数器加 1。当 reference 离开生存空间或被设为 NULL,计数器减 1。当某个对象的引用计数器为零时,PHP 知道你将不再需要使用这个对象,释放其所占的内存空间。

每一个变量对应一个 zval 数据结构,在该结构内还有一个 val 结构体,该结构体内有一个引用计数(php7 而言,对于 php5,这个引用计数是保存在 zval 结构中的),标识该对象的引用数,当对象的引用计数为 0 时代表这个对象可被回收。

对象的 refcount 减少的时机:修改变量、函数返回(释放局部变量)、unset 变量

对于数组和对象而言,可能存在变量中的成员引用变量本身的情况,也就是循环引用,这样会造成这个变量永远不会被内存回收,而成为垃圾。

PHP 里对于这种情况给出了垃圾回收机制:如果数组、对象的引用计数减少而且不为零,则认为他们可能是垃圾,把他们放到垃圾收集器里。等垃圾收集器到了一定的数量之后,进行垃圾处理:对所有可能的垃圾 refcount 减 1,如果为 1,说明是垃圾,则进行内存回收;如果不为 1,说明还有其他变量在使用,refcount 重新加 1;这种对象复用以及垃圾回收机制在其他语言中也有体现:redis 中也使用了引用计数表示每个对象的引用数量。

session 与 cookie 的区别和联系

区别:

1. 存放位置:Session 保存在服务器,Cookie 保存在客户端。

2. 存放的形式:Session 是以对象的形式保存在服务器,Cookie 以字符串的形式保存在客户端。

3. 用途:Cookies 适合做保存用户的个人设置,爱好等,Session 适合做客户的身份验证

4. 路径:Session 不能区分路径,同一个用户在访问一个网站期间,所有的 Session 在任何一个地方都可以访问到。而 Cookie 中如果设置了路径参数,那么同一个网站中不同路径下的 Cookie 互相是访问不到的。

5. 安全性:Cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗,考虑到安全应当使用 session

6. 大小以及数量限制:每个域名所包含的 cookie 数:IE7/8,FireFox:50 个,Opera30 个; Cookie 总大小:Firefox 和 Safari 允许 cookie 多达 4097 个字节,Opera 允许 cookie 多达 4096 个字 节,InternetExplorer 允许 cookie 多达 4095 个字节;一般认为 Session 没有大小和数量限制。

关系:

Session 需要借助 Cookie 才能正常工作。如果客户端完全禁止 Cookie,Session 将失效!因为 Session 是由应用服务器维持的一个 服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的 SessionID, 用该 SessionID 为标识符来存取服务器端的 Session 存储空间。而 SessionID 这一数据则是保存到客户端,用 Cookie 保存的,用户提交页面时,会将这一 SessionID 提交到服务器端,来存取 Session 数据。这一过程,是不用开发人员干预的。所以一旦客户端禁用 Cookie,那么 Session 也会失效。

PHP7 与 PHP5 的区别

改进的性能 - 将 PHPNG 代码合并到 PHP7 中,速度是 PHP 5 的两倍。

降低内存消耗 - 优化的 PHP 7 使用较少的资源。

标量类型声明 - 现在可以强制执行参数和返回类型。

一致的 64 位支持 - 对 64 位体系结构机器的一致支持。

改进了异常层次 - 异常层次得到了改进

许多致命的错误转换为例外 - 例外范围增加,涵盖许多致命的错误转换为例外。

安全随机数发生器 - 增加新的安全随机数发生器 API。

已弃用的 SAPI 和扩展已删除 - 各种旧的和不受支持的 SAPI 和扩展从最新版本中删除。

空合并运算符(?) - 添加了新的空合并运算符。

返回和标量类型声明 - 支持所添加的返回类型和参数类型。

匿名类 - 支持匿名添加。

零成本断言 - 支持零成本断言增加。

MongoDB 应用场景

mongodb 支持副本集、索引、自动分片,可以保证较高的性能和可用性。

更高的写入负载

默认情况下,MongoDB 更侧重高数据写入性能,而非事务安全,MongoDB 很适合业务系统中有大量 “低价值” 数据的场景。但是应当避免在高事务安全性的系统中使用 MongoDB,除非能从架构设计上保证事务安全。

高可用性

MongoDB 的复副集 (Master-Slave) 配置非常简洁方便,此外,MongoDB 可以快速响应的处理单节点故障,自动、安全的完成故障转移。这些特性使得 MongoDB 能在一个相对不稳定(如云主机)的环境中,保持高可用性。

数据量很大或者未来会变得很大

依赖数据库 (MySQL) 自身的特性,完成数据的扩展是较困难的事,在 MySQL 中,当一个单达表到 5-10GB 时会出现明显的性能降级,此时需要通过数据的水平和垂直拆分、库的拆分完成扩展,使用 MySQL 通常需要借助驱动层或代理层完成这类需求。而 MongoDB 内建了多种数据分片的特性,可以很好的适应大数据量的需求。

基于位置的数据查询

MongoDB 支持二维空间索引,因此可以快速及精确的从指定位置获取数据。

表结构不明确

在一些传统 RDBMS 中,增加一个字段会锁住整个数据库 / 表,或者在执行一个重负载的请求时会明显造成其它请求的性能降级。通常发生在数据表大于 1G 的时候(当大于 1TB 时更甚)。 因 MongoDB 是文档型数据库,为非结构货的文档增加一个新字段是很快速的操作,并且不会影响到已有数据。另外一个好处当业务数据发生变化时,是将不在需要由 DBA 修改表结构。

如何修改 SESSION 的生存时间

设置浏览器保存的 sessionid 失效时间 setcookie (session_name (), session_id (), time () + $lifeTime, "/");
可以使用 SESSION 自带的 session_set_cookie_params (86400); 来设置 Session 的生存期
通过修改 php.ini 中的 session.gc_maxlifetime 参数的值就可以改变 session 的生存时间

PHP 短信验证码防刷机制

1、时间限制:60 秒后才能再次发送

从发送验证码开始,前端(客户端)会进行一个 60 秒的倒数,在这一分钟之内,用户是无法提交多次发送信息的请求的。这种方法虽然使用得比较普遍,但是却不是非常有用,技术稍微好点的人完全可以绕过这个限制,直接发送短信验证码。

2、手机号限制:同一个手机号,24 小时之内不能够超过 5 条

对使用同一个手机号码进行注册或者其他发送短信验证码的操作的时候,系统可以对这个手机号码进行限制,例如,24 小时只能发送 5 条短信验证码,超出限制则进行报错(如:系统繁忙,请稍后再试)。然而,这也只能够避免人工手动刷短信而已,对于批量使用不同手机号码来刷短信的机器,这种方法也是无可奈何的。

3、短信验证码限制:30 分钟之内发送同一个验证码

网上还有一种方法说:30 分钟之内,所有的请求,所发送的短信验证码都是同一个验证码。第一次请求短信接口,然后缓存短信验证码结果,30 分钟之内再次请求,则直接返回缓存的内容。对于这种方式,不是很清楚短信接口商会不会对发送缓存信息收取费用,如果有兴趣可以了解了解。

4、前后端校验:提交 Token 参数校验

这种方式比较少人说到,个人觉得可以这种方法值得一试。前端(客户端)在请求发送短信的时候,同时向服务端提交一个 Token 参数,服务端对这个 Token 参数进行校验,校验通过之后,再向请求发送短信的接口向用户手机发送短信。

5、唯一性限制:微信产品,限制同一个微信 ID 用户的请求数量

如果是微信的产品的话,可以通过微信 ID 来进行识别,然后对同一个微信 ID 的用户限制,24 小时之内最多只能够发送一定量的短信。

6、产品流程限制:分步骤进行

例如注册的短信验证码使用场景,我们将注册的步骤分成 2 步,用户在输入手机号码并设置了密码之后,下一步才进入验证码的验证步骤。

7、图形验证码限制:图形验证通过后再请求接口

用户输入图形验证码并通过之后,再请求短信接口获取验证码。为了有更好的用户体验,也可以设计成:一开始不需要输入图形验证码,在操作达到一定量之后,才需要输入图形验证码。具体情况请根据具体场景来进行设计。

8、IP 及 Cookie 限制:限制相同的 IP/Cookie 信息最大数量

使用 Cookie 或者 IP,能够简单识别同一个用户,然后对相同的用户进行限制(如:24 小时内最多只能够发送 20 条短信)。然而,Cookie 能够清理、IP 能够模拟,而且 IP 还会出现局域网相同 IP 的情况,因此,在使用此方法的时候,应该根据具体情况来思考。

9、短信预警机制,做好出问题之后的防护

以上的方法并不一定能够完全杜绝短信被刷,因此,我们也应该做好短信的预警机制,即当短信的使用量达到一定量之后,向管理员发送预警信息,管理员可以立刻对短信的接口情况进行监控和防护。

PHP 的控制反转 (IOC) 和依赖注入 (DI) 概念

IOC(inversion of control)控制反转模式;控制反转是将组件间的依赖关系从程序内部提到外部来管理;

DI(dependency injection)依赖注入模式;依赖注入是指将组件的依赖通过外部以参数或其他形式注入;

mySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据

相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6 种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db [i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db [i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db [i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db [i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db [i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据

HTTP 协议详解、应用

http(超文本传输协议)是一个基于请求与响应模式的、无状态的、短连接、灵活、应用层的协议,常基于 TCP 的连接方式。

参考 http://blog.csdn.net/gueter/article/detail… (http 协议详解)

(HTTP 响应状态码)

HTTP 响应状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

1xx:指示信息 — 表示请求已接收,继续处理

2xx:成功 — 表示请求已被成功接收、理解、接受

3xx:重定向 — 要完成请求必须进行更进一步的操作

4xx:客户端错误 — 请求有语法错误或请求无法实现

5xx:服务器端错误 — 服务器未能实现合法的请求

常见状态代码、状态描述、说明:

200 OK // 客户端请求成功

400 Bad Request // 客户端请求有语法错误,不能被服务器所理解

401 Unauthorized // 请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用 403 Forbidden // 服务器收到请求,但是拒绝提供服务

404 Not Found // 请求资源不存在,eg:输入了错误的 URL

500 Internal Server Error // 服务器发生不可预期的错误

503 Server Unavailable // 服务器超时 // 可能恢复正常

304 Not Modifed // 自从上次请求后,请求的网页未修改过。

// 服务器返回此响应时,不会返回网页内容。

socket 连接步骤

Socket(套接字)概念

套接字(socket)是通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的 IP 地址,本地进程的协议端口,远地主机的 IP 地址,远地进程的协议端口。

Socket 连接过程

建立 Socket 连接至少需要一对套接字,其中一个运行于客户端,称为 ClientSocket ,另一个运行于服务器端,称为 ServerSocket

套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。

客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端

套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

TCP 协议,三次握手、四次挥手

TCP 协议 (Transmission Control Protocol) 是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接,四次挥手断开连接。

位码即 tcp 标志位,有 6 种标示:

SYN (synchronous 建立联机) 同步

ACK (acknowledgement 确认)

PSH (push 传送)

FIN (finish 结束)

RST (reset 重置)

URG (urgent 紧急)

预定义变量、魔术变量、魔术方法比较,及作用举例

预定义变量(超级全局变量)

$GLOBALS

$_SERVER

$_GET

$_POST

$_COOKIE

$_SESSION

$_REQUEST

$_ENV

construct 和 destruct

__autoload

get 和 set

isset 和 unset

call 和 callStatic

__clone

__toString

sleep 和 wakeup

__invoke

魔术变量 http://apps.hi.baidu.com/share/detail/17851228

LINE

FILE

DIR

CLASS

FUNCTION

METHOD

NAMESPACE

如何优化前端性能

1) 页面内容的优化

a) 降低请求数

合并 css、js 文件,集成 CSS 图片

b) 减少交互通信量

压缩技术:压缩 css、js 文件,优化图像,减少 cookie 体积;

合理利用缓存:使用外部 js/css 文件,缓存 ajax;

减少不必要的通信量:剔除无用脚本和样式、推迟加载内容、使用 GET 请求

c) 合理利用 “并行” 尽量避免重定向

慎用 Iframe 样式表置于顶部 脚本放到样式后面加载

d) 节约系统消耗

避免 CSS 表达式、滤镜

2) 服务器的优化

a) b)

c)

d)

## yahoo 的 34 条前端优化法则
减少 HTTP 请求、利用 CDN 技术、 设置头文件过期或者静态缓存、Gzip 压缩、把 CSS 放顶部、 把 JS 放底部、避免 CSS 表达式、将 JS 和 CSS 外链、减少 DNS 查找、减小 JS 和 CSS 的体积、 避免重定向、删除重复脚本、 配置 ETags、缓存 Ajax、尽早的释放缓冲、

用 GET 方式进行 AJAX 请求、延迟加载组件、 预加载组件、减少 DOM 元素数量、跨域分离组件、

减少 iframe 数量、不要出现 404 页面、减小 Cookie、 对组件使用无 Cookie 的域名、减少 DOM 的访问次数、开发灵活的事件处理句柄、使用 <link> 而非 @import、避免过滤器的使用、优化图片、优化 CSS Sprites、 不要在 HTML 中缩放图片、缩小 favicon. ico 的大小并缓存它、保证组件在 25K 以下、将组件打包进一个多部分的文档中

PHP 安全模式

php 安全模式:safe_mode=on|off

启用 safe_mode 指令将对在共享环境中使用 PHP 时可能有危险的语言特性有所限制。可以将 safe_mode 是指为布尔值 on 来启用,或者设置为 off 和脚本尝试访问的文件的 UID,以此作为限制机制的基础。如果 UID 相同,则执行脚本;否则,脚本失败。

当启用安全模式时,一些限制将生效

1、 所有输入输出函数(例如 fopen ()、file () 和 require ())的适用会受到限制,只能用于与调用这些函数的

脚本有相同拥有者的文件

2、 如果试图通过函数 popen ()、system () 或 exec () 等执行脚本,只有当脚本位于 safe_mode_exec_dir

配置指令指定的目录才可能

3、HTTP 验证得到进一步加强,因为验证脚本用于者的 UID 划入验证领域范围内。此外,当启用安

全模式时,不会设置 PHP_AUTH。

4、如果适用 MySQL 数据库服务器,链接 MySQL 服务器所用的用户名必须与调用 mysql_connect ()

的文件拥有者用户名相同。

以下是一些和安全模式相关的配置选项

safe_mode_gid=on|off

safe_mode_include_dir=string

safe_mode_env_vars=string

safe_mode_exec_dir=string

safe_mode_protected_env_vars=string

常见的 web 攻击方式

常见攻击

XSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往 Web 页面里插入恶意 html 代码,当用户浏览该页之时,嵌入的恶意 html 代码会被执行,从而达到恶意用户的特殊 目的。XSS 属于被动式的攻击,因为其被动且不好利用,所以许多人常呼略其危害性。但是随着前端技术的不断进步富客户端的应用越来越多,这方面的问题越来 越受关注。举个简单例子 : 假如你现在是 sns 站点上一个用户,发布信息的功能存在漏洞可以执行 js 你在 此刻输入一个 恶意脚本,那么当前所有看到你新信息的人的浏览器都会执行这个脚本弹出提示框 (很爽吧 弹出广告 :)),如果你做一些更为激进行为呢 后果难以想象。

CSRF (Cross Site Request Forgery),跨站点伪造请求。顾名思义就是 通过伪造连接请求在用户不知情的情况下,让用户以自己的身份来完成攻击者需要达到的一些目的。csrf 的攻击不同于 xss csrf 需要被攻击者的主动行为触发。这样听来似乎是有 “被钓鱼” 的嫌疑。

多窗口浏览器这这方面似乎是有助纣为虐的嫌疑,因为打开的新窗口是具有当前所有 会话的,如果是单浏览器窗口类似 ie6 就不会存在这样的问题,因为每个窗口都是一个独立的进程。举个简单例子 : 你正在玩白社会, 看到有人发了一个连接,你点击过去,然后这个连接里面伪造了一个送礼物的表单,这仅仅是一个简单的例子,问题可见一般。

cookie 劫持。通过获取页面的权限,在页面中写一个简单的到恶意站点的请 求,并携带用户的 cookie 获取 cookie 后通过 cookie 就可以直以被盗用户的身份登录站点。这就是 cookie 劫持。举个简单例子: 某人写了一篇很有意思的日志,然后分享给大家,很多人都点击查看并且分享了该日志,一切似乎都很正常,然而写日志的人却另有用心,在日志中偷偷隐藏了一个 对站外的请求,那么所有看过这片日志的人都会在不知情的情况下把自己的 cookie 发送给了 某人,那么他可以通过任意一个人的 cookie 来登录这个人的账户。

SQL 注入攻击

在 SQL 注入攻击 中,用户通过操纵表单或 GET 查询字符串,将信息添加到数据库查询中。

DNS 攻击

拒绝服务攻击

拒绝服务攻击即攻击者想办法让目标机器停止提供服务,是黑客常用的攻击手段之。

攻击者进行拒绝服务攻击,实际上让服务器实现两种效果:一是迫使服务器的缓冲区满,不接收新的请求;二是使用 IP 欺骗,迫使服务器把合法用户的连接复位,影响合法用户的连接

PHP 做好防盗链的基本思想 防盗链

什么是盗链?

盗链是指服务提供商自己不提供服务的内容,通过技术手段绕过其它有利益的最终用户界面 (如广告),直接在自己的网站上向最终用户提供其它服务提供商的服务内容,骗取最终用户的浏览和点击率。受益者不提供资源或提供很少的资源,而真正的服务提供商却得不到任何的收益。

网站盗链会大量消耗被盗链网站的带宽,而真正的点击率也许会很小,严重损害了被盗链网站的利益。 如何做防盗链?

不定期更名文件或者目录

限制引用页

原理是,服务器获取用户提交信息的网站地址,然后和真正的服务端的地址相比较, 如果一致则表明是站内提交,或者为自己信任的站点提交,否则视为盗链。实现时可以使用 HTTP_REFERER1 和 htaccess 文件 (需要启用 mod_Rewrite),结合正则表达式去匹配用户的每一个访问请求。

文件伪装

文件伪装是目前用得最多的一种反盗链技术,一般会结合服务器端动态脚本 (PHP/JSP/ASP)。实际上用户请求的文件地址,只是一个经过伪装的脚本文件,这个脚本文件会对用户的请求作认证,一般会检查 Session,Cookie 或 HTTP_REFERER 作为判断是否为盗链的依据。而真实的文件实际隐藏在用户不能够访问的地方,只有用户通过验证以后才会返回给用户

加密认证

这种反盗链方式,先从客户端获取用户信息,然后根据这个信息和用户请求的文件名 字一起加密成字符串 (Session ID) 作为身份验证。只有当认证成功以后,服务端才会把用户需要的文件传送给客户。一般我们会把加密的 Session ID 作为 URL 参数的一部分传递给服务器,由于这个 Session ID 和用户的信息挂钩,所以别人就算是盗取了链接,该 Session ID 也无法通过身份认证,从而达到反盗链的目的。这种方式对于分布式盗链非常有效。

随机附加码

每次,在页面里生成一个附加码,并存在数据库里,和对应的图片相关,访问图片时和此附加码对比,相同则输出图片,否则输出 404 图片

加入水印

Redis

1.简介

Redis 是一个支持持久化的内存数据库[1],通过持久化机制把内存中的数据同步到硬盘文件来 保证数据持久化。当 Redis 重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目 的。 实现:单独创建 fork()一个子进程,将当前父进程的数据库数据复制到子进程的内存中,然 后由子进程写入到临时文件中,持久化的过程结束了,再用这个临时文件替换上次的快照文 件,然后子进程退出,内存释放。
RDB 是 Redis 默认的持久化方式。按照一定的时间周期策略把内存的数据以快照的形式保存 到硬盘的二进制文件。即 Snapshot 快照存储,对应产生的数据文件为 dump.rdb,通过配置 文件中的 save 参数来定义快照的周期。( 快照可以是其所表示的数据的一个副本,也可以 是数据的一个复制品。) AOF:Redis 会将每一个收到的写命令都通过 Write 函数追加到文件最后,类似于 MySQL 的 binlog。当 Redis 重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的 内容。 当两种方式同时开启时,数据恢复 Redis 会优先选择 AOF 恢复。

缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间 (例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有 原本应该访问缓存的请求都去查询数据库了,而对数据库 CPU 和内存造成巨大压力,严重 的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。 解决办法: 大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证不会有大量 的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还

2.缓存穿透

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询 的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次 无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。 
解决办法; 最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一 个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。 另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还 是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分 钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继 续访问数据库,这种办法最简单粗暴。 5TB 的硬盘上放满了数据,请写一个算法将这些数据进行排重。如果这些数据是一些 32bit 大小的数据该如何解决?如果是 64bit 的呢?

对于空间的利用到达了一种极致,那就是 Bitmap 和布隆过滤器(BloomFilter)。 Bitmap: 典型的就是哈希表 缺点是,Bitmap 对于每个元素只能记录 1bit 信息,如果还想完成额外的功能,恐怕只能靠 牺牲更多的空间、时间来完成了。
布隆过滤器(推荐) 就是引入了 k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素 判重的过程。 它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困 难。 Bloom-Filter 算法的核心思想就是利用多个不同的 Hash 函数来解决“冲突”。 Hash 存在一个冲突(碰撞)的问题,用同一个 Hash 得到的两个 URL 的值有可能相同。为了 减少冲突,我们可以多引入几个 Hash,如果通过其中的一个 Hash 值我们得出某元素不在集 合中,那么该元素肯定不在集合中。只有在所有的 Hash 函数告诉我们该元素在集合中时, 才能确定该元素存在于集合中。这便是 Bloom-Filter 的基本思想。 Bloom-Filter 一般用于在大数据量的集合中判定某元素是否存在。

3.缓存预热

缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解,缓存 预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求 的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据! 解决思路: 1、直接写个缓存刷新页面,上线时手工操作下; 2、数据量不大,可以在项目启动的时候自动进行加载; 3、定时刷新缓存;

4.缓存更新

除了缓存服务器自带的缓存失效策略之外(Redis 默认的有 6 中策略可供选择),我们还可

以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种: (
1)定时去清理过期的缓存; 
(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系 统得到新数据并更新缓存。 
两者各有优劣,第一种的缺点是维护大量缓存的 key 是比较麻烦的,
第二种的缺点就是每次 用户请求过来都要判断缓存失效,逻辑相对比较复杂!
具体用哪种方案,大家可以根据自己 的应用场景来权衡。 

5.缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性 能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自 动降级,也可以配置开关实现人工降级。 降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入 购物车、结算)。 以参考日志级别设置预案: 
(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级; 
(2)警告:有些服务在一段时间内成功率有波动(如在 95~100%之间),可以自动降级或 人工降级,并发送告警; 
(3)错误:比如可用率低于 90%,或者数据库连接池被打爆了,或者访问量突然猛增到系 统能承受的最大阀值,此时可以根据情况自动降级或者人工降级; 
(4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

服务降级的目的,是为了防止 Redis 服务故障,导致数据库跟着一起发生雪崩问题。因此, 对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis 出 现问题,不去数据库查询,而是直接返回默认值给用户。

热点数据和冷数据是什么 热点数据,缓存才有价值 对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而 且价值不大。频繁修改的数据,看情况考虑使用缓存 对于上面两个例子,寿星列表、导航信息都存在一个特点,就是信息修改频率不高,读取通 常非常高的场景。 对于热点数据,比如我们的某 IM 产品,生日祝福模块,当天的寿星列表,缓存以后可能读 取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。 **数据更新前至少读取两次,**缓存才有意义。这个是最基本的策略,如果缓存还没有起作 用就失效了,那就没有太大价值了。 那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个读取接口对 数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的 压力,比如我们的某助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是 又不断变化,此时就需要将数据同步保存到 Redis 缓存,减少数据库压力。

6.单线程的 redis 为什么这么快

(一)纯内存操作 
(二)单线程操作,避免了频繁的上下文切换 
(三)采用了非阻塞 I/O 多路复用机制

7.redis 的数据类型

一共五种 
(一)String 这个其实没啥好说的,最常规的 set/get 操作,value 可以是 String 也可以是数字。一般做一 些复杂的计数功能的缓存。 
(二)hash 这里 value 存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登 录的时候,就是用这种数据结构存储用户信息,以 cookieId 作为 key,设置 30 分钟为缓存 过期时间,能很好的模拟出类似 session 的效果。 
(三)list 使用 List 的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用 lrange 命令,做基于 redis 的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适—取 行情信息。就也是个生产者和消费者的场景。LIST 可以很好的完成排队,先进先出的原则。 
(四)set 因为 set 堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用 JVM 自带 的 Set 进行去重?因为我们的系统一般都是集群部署,使用 JVM 自带的 Set,比较麻烦,难 道为了一个做一个全局去重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜 好等功能。
(五)sortedset sortedset多了一个权重参数 score,集合中的元素能够按 score进行排列。可以做排行榜应用, 取 TOPN 操作。

写出一个能创建多级目录的PHP函数(新浪网技术部)

<?php

    /**

     * 创建多级目录

     * @param $path string 要创建的目录

     * @param $mode int 创建目录的模式,在windows下可忽略

     */

    function create_dir($path,$mode = 0777)

    {

        if (is_dir($path)) {

            # 如果目录已经存在,则不创建

            echo "该目录已经存在";

        } else {

            # 不存在,创建

            if (mkdir($path,$mode,true)) {

                echo "创建目录成功";

            } else {

                echo "创建目录失败";

            }

        }

    }

?>

写出smarty模板的特点

速度快,编译型,缓存技术,插件机制,强大的表现逻辑

打开php.ini中的safe_mode,会影响哪些函数?至少说出6个。

safe_mode,PHP安全模式,它提供一个基本安全的共享环境,在一个有多个用户账户存在的php开发的web服务器上。当安全模式打开的时候,一些函数将被完全的禁止,而另一些函数的功能将会受到限制,如:chdir,move_uploaded_file,chgrp,parse_ini_file,chown,rmdir,copy,rename,fopen,require,mkdir,unlink等。
注意,在php5.3以上版本,safe_mode被弃用,在php5.4以上版本,则将此特性完全去除了。

请写一段PHP代码,确保多个进程同时写入同一个文件成功(加锁)

<?php

    $fp = fopen("lock.txt","w+");

    if (flock($fp,LOCK_EX)) {

        //获得写锁,写数据

        fwrite($fp, "write something");

        // 解除锁定

        flock($fp, LOCK_UN);

    } else {

        echo "file is locking...";

    }

    fclose($fp);

?>

写一个函数,尽可能高效的,从一个标准url里取出文件的扩展名

<?php

    // 方案一

    function getExt1($url){

        $arr = parse_url($url);

        //Array ( [scheme] => http [host] => www.sina.com.cn [path] => /abc/de/fg.php [query] => id=1 )

        $file = basename($arr['path']);

        $ext = explode('.', $file);

        return $ext[count($ext)-1];

    }

    // 方案二

    function getExt2($url){

        $url = basename($url);

        $pos1 = strpos($url,'.');

        $pos2 = strpos($url,'?');

        if (strstr($url,'?')) {

            return substr($url,$pos1+1,$pos2-$pos1-1);

        } else {

            return substr($url,$pos1);

        }

    }

    $path = "http://www.sina.com.cn/abc/de/fg.php?id=1";

    echo getExt1($path);

    echo "<br />";

    echo getExt2($path);

?>

写一个函数,能够遍历一个文件夹下的所有文件和子文件夹。

<?php

    function my_scandir($dir){

        $files = array();

        if(is_dir($dir)){

            if ($handle = opendir($dir)) {

                while (($flie = readdir($handle))!== false) {

                    if ($flie!="." && $file!="..") {

                        if (is_dir($dir."/".$file)) {

                            $files[$file] = my_scandir($dir."/".$file);

                        } else {

                            $files[] = $dir."/".$file;

                        }

                    }

                }

                closedir($handle);

                return $files;

            }

        }

    }

?>

请写一个函数验证电子邮件的格式是否正确(要求使用正则)

preg_match('/^[\w\-\.]+@[\w\-]+(\.\w+)+$/',$email);

编写函数取得上一月的最后一天

<?php

 date_default_timezone_set('PRC');

    /**

     * 获取给定月份的上一月最后一天

     * @param $date string 给定日期

     * @return string 上一月最后一天

     */

    function get_last_month_last_day($date = ''){

        if ($date != '') {

            $time = strtotime($date);

        } else {

            $time = time();

        }

        $day = date('j',$time);//获取该日期是当前月的第几天

        return date('Y-m-d',strtotime("-{$day} days",$time));

    }

    // 测试

    echo get_last_month_last_day();

    echo "<br />";

    echo get_last_month_last_day("2013-3-21");

在url中用get传值的时候,若中文出现乱码,应该用哪个函数对中文进行编码

urlencode()

解决 laravel-admin between datetime 假如数据库是时间戳int类型无法筛选。

laravel-admin默认的between->datetime(),查询默认是datetime类型,但是假如数据库是时间戳类型就会报错,又不想改底层文件的话可以试试加自定义筛选功能...

阅读全文

php解析英文语句,自动分解。

参考:https://www.php.net/manual/en/function.str-split.php 最近碰到一个问题,客户的英文地址太长,超出接口api字段长度,所以需要解析下语句分解发送。 ...

阅读全文

记录一个laravel-excel导出表格值为0导出excel显示空的解决方法。

最近在使用laravel-excel导出表格的时候,发现假如字段值为0的情况下,导出的excel中直接显示为空,找到一个方法解决,如下. 在laravel-excel的config配置中...

阅读全文

欢迎留言