PHP面试的相关知识点

时间:2021-06-22 14:27:49

1. php数组函数常见的那些?array_merge、in_array的作用

数组的常用函数有

简单的数组排序
sort() rsort()
根据元素的键值对数组排序
ksort() krsort()

拆分、合并、分解、接合的数组函数

array_splice()//返回值和array_slice()相同,返回截取后的字符串不同之处在于前者影响源数据(源数据=源数据-array_splice()返回值), 后者不改变源数据.
array_merge();//合并

数组与数据结构的函数

array_push() array_pop() 入栈和出栈

array_merge

array_merge() 将一个或多个数组的单元合并起来,一个数组中的值附加在前一个数组的后面。返回作为结果的数组。

如果输入的数组中有相同的字符串键名,则该键名后面的值将覆盖前一个值。然而,如果数组包含数字键名,后面的值将不会覆盖原来的值,而是附加到后面。

in_array

— 检查数组中是否存在某个值, 默认是区分大小写
第三个参数如果为true 则会根据具体类型向数组中进项查找’

<?php
$a = array('1.10', 12.4, 1.13);
if (in_array('12.4', $a, true)) {
echo "'12.4' found with strict check\n";
}
if (in_array(1.13, $a, true)) {
echo "1.13 found with strict check\n";
}
?>

结果是: 1.13 found with strict check
如果第一个if语句改成false, 则会输出’12.4’ found with strict check

PHP中的数组其实就是一个有序图,图是一种把value映射到keys的类型,此类型做了很多的优化, 因此可以把它当成是数组使用,列表(矢量),散列表(图的一种实现),字典,集合,栈,队列,以及更过的可能性. 因此可以用一个PHP数组作为值, 也可以很容易的的实现树.

参考地址: http://php.net/manual/zh/book.array.php

2. 二分查找(折半查找)的原理和时间复杂度?

前提:线性表中记录必须是有序的,线性表采用顺序存储.

原理:在有序表中,取中间记录作为比较对象,若给定的值和中间记录的关键字相同,则查找成功;如果查找对象小于中间记录的关键字,则在中间记录的左半部分继续查找;否则在右半区查找.

时间复杂度: O(log(n))

3. 常见的设计模式,实现一个?

php常用的设计模式有: 工厂模式 , 策略模式 , 单例模式 , 观察者模式 , 命令链模式. (推荐大家看一下 <大话设计模式>)
单例模式(Singleton)最好实现 (可以参考<剑指offer>第31页), 用于 保证系统中一个类只有一个实例而且该实例易于外界访问, 从而方便对实例个数的控制并节约系统资源.

public class SingletonClass{
private static SingletonClass instance=new SingletonClass();
public static SingletonClass getInstance()
{
return instance;
}
private SingletonClass(){
}
}

php中的单例模式(Single) 实现连接数据库

class Mysql{
private static $instance = null;
private static $conn = null;
private function __construct(){
self::$conn = mysql_connect('localhost', 'root', 'mysql');
}
public static function getInstance(){
if(! self::$instance instanceof self){
echo '---', "\n";
self::$instance = new self;
}
return self::$instance;
}
public function get_conn(){
return self::$conn;
}
//禁止克隆
private function __clone(){}
}
$db = Mysql::getInstance(); //输出 -----
$db = Mysql::getInstance(); //不会输出
$db = Mysql::getInstance(); //不会输出
//$temp = clone $db; //克隆$db 则会报错,, 因为 __clone 是private类型的
var_dump($db->get_conn()); //resource(5) of type (mysql link)

单例模式应该返回的是一个对象.

注 : 如果直接这样写 private static $conn = mysql_connect(‘localhost’, ‘root’,’mysql’); 则会报错的.

4. 数据库的索引有啥?

索引是对数据库中一个或多个列的值进行排序的结构
索引分为: 唯一索引, 主键索引, 聚簇索引
唯一索引:

不允许其中任何两行具有相同索引值的索引

主键索引:

数据库表经常有一列或列组合,其值唯一标识表中的每一行。

在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。

聚集索引 :

表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引,聚簇索引的叶节点对应着数据页,从中间级的索引页的索引行直接对应着数据页。

如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度

5. 联合索引和主键的区别?

主键也相当于索引,不允许有重复的值,主键不能不能为空.
联合索引

查询条件中出现联合索引第一列,或者全部,则能利用联合索引
查询条件中没有出现联合索引的第一列,而出现联合索引的其它列,都不会利用联合索引查询

6. 数据库表的优化方法?建表注意事项和原则

优化方法:索引(数据库),缓存,分表,分库,sql优化

分表:针对每个时间周期产生大量的数据,可以考虑采用一定的策略将数据存到多个数据表中。
分库:就是将系统按照模块相关的特征分布到不同的数据中,以提高系统整体负载能力。
sql优化:

1. in 和 not in 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据

2. 尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描
SELECT * FROM T1 WHERE F1/2=100
应改为:
SELECT * FROM T1 WHERE F1=100*2

3. 充分利用连接条件,在某种情况下,两个表之间可能不只一个的连接条件,这时在 WHERE 子句中将 连接条件完整的写上,有可能大大提高查询速度。
例: SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO 改成
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO

4. 把表的一个子集进行排序并创建视图,有时能加速查询。
参考 http://blog.csdn.net/hguisu/article/details/5731629

建表的注意事项
1. 为每个表创建一个自增的id
2. 创建主键和外键
3. 根据需求建立索引
4. 尽量字段设置为NOT NULL
5. 建表要遵循范式

第一范式:每一个分量是不能再分的数据项
第二范式:在1NF的基础上,非码属性必须完全依赖于码 要求数据库表中的每个实例或记录必须可以被唯一的区分,选取一个能区分每个实体的属性或属性组,作为实体的唯一标识
第三范式: 在1NF基础上,任何非主属性不依赖于其它非主属性[在2NF基础上消除传递依赖] 即要求一个关系中不包含已在其它关系已包含的非主关键字信息

建表是字段的类型的选取和数据库引擎的选择和具体的需求有关系.
如果实现一个查询需要连接很多的表, 时间效率慢,可以适当的进行数据表字段的冗余性, 用空间换取时间.

7. PHP缓存技术有哪些?tp是局部还是完全缓存?

1. 全页面静态化缓存

也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程

2. 页面部分缓存

将一个页面中不经常变的部分进行静态缓存,而经常变化的块不缓存,最后组装在一起显示

3. 数据缓存

通过一个id进行请求的数据,将数据缓存到一个php文件中,id和文件是对应的,下次通过这个id进行请求时 直接读php文件

4. 查询缓存

和数据缓存差不多,根据查询语句进行缓存;


  1. 常用的缓存技术有

redis和memcache
个人认为tp应该是全局缓存 因为:tp缓存实在本地生成一个php文件来存储数据库中读取出来的数据

8. nginx,apache的作用?apache的rewrite的作用?

nginx和apache的作用:

都是常见的webserver服务器,将浏览器用户过来的http请求,交给脚本语言处理(比如php),然后把结果反应给浏览器

apache的rewrite作用:

主要的功能就是实现URL的跳转,可基于服务器级的(httpd.conf)和目录级的(.htaccess)两种方式,如果想使用该模块必须加载该模块
比如在虚拟主机(httpd-vhosts.conf)中进行设置

NameVirtualHost 192.168.100.8:80
<VirtualHost 192.168.100.8:80>
ServerAdmin webmaster@colorme.com.cn
DocumentRoot "/web/webapp"
ServerName www.colorme.com.cn
ServerName colorme.com.cn
RewriteEngine on #打开rewirte功能
RewriteCond %{HTTP_HOST} !^www.colorme.com.cn [NC] #声明Client请求的主机中前缀不是www.colorme.com.cn,[NC]的意思是忽略大小写
RewriteCond %{HTTP_HOST} !^203.81.23.202 [NC] #声明Client请求的主机中前缀不是203.81.23.202,[NC]的意思是忽略大小写
RewriteCond %{HTTP_HOST} !^$ #声明Client请求的主机中前缀不为空,[NC]的意思是忽略大小写
RewriteRule ^/(.*) http://www.colorme.com.cn/ [L] #含义是如果Client请求的主机中的前缀符合上述条件,则直接进行跳转到http://www.colorme.com.cn/, [L]意味着立即停止重写操作,并不再应用其他重写规则。这里的.*是指匹配所有URL中不包含换行字符,()括号的功能是把所有的字符做一个标记,以便 于后面的应用.就是引用前面里的(.*)字符。

9. 索引的最左前缀原则?

就是最左优先, 比如 为name,age,city三个列建立多列索引,相当于创建了name单列索引和name,age组合索引,和name,age,city组合查询,如果where条件选择的是age and city 或 age,或 city 这些字段来查, 则不会使用到索引,会遍历全表进行查找.

一般情况下, where子句中使用最频繁的一列放在最左边.

10. 使用tp框架和使用php编写代码的优缺点?

使用tp框架 代码编写效率高,节约时间,让开发者专注于功能的实现上. 由于tp的mvc模式[ 模型(model)-视图(view)-控制器(controller)] 使业务 逻辑.数据处理, 界面展示分离的方法组织代码,使人员分工更加明确.

tp的优点非常多,比如:缓存机制, 扩展机制,url模式,查询语言,动态模型,ajax支持,分页,多语言支持,自动完成和验证,验证码等.
用原生态的php语言进行编写代码, 效率比框架低, 其实框架的优点也就是缺点, 当程序员经常使用框架, 会造成一种依赖, 编码人员未必明白框架其中的原理. 如果自己将框架的特点自己用php实现一下,这个过程,会对自己有很大的提高.

总的来说使用框架是为了节约 时间,节约人力和财力资源, 现在web项目一般都是短平快的节奏, 编码往往都是使用框架的.

11. tp中的hook机制?

钩子其实就是起到一个挂载点的作用,这个钩子挂在哪里,就可以在哪里执行,内容或功能就是挂载插件或类库的具体实现。这样实现的代码就有很大的灵活性,挂载点不变,挂的东西变量,功能也就相应的变化

12. 什么是rest ful?

restful架构: 是一种软件架构风格,提供了一组设计原则和约束条件.

1. 每一个URI代表一种资源
2. 客户端和服务器之间,传递这种资源的某种表现层, 客户端和服务器之间交互在请求之间是无状态的.
3. 客户端通过四个HTTP动词(get获取资源,post新建资源或更新资源,put更新资源,delete删除资源),对服务资源则进行操作,实现”表现层状态转化”

可以参考 http://www.ruanyifeng.com/blog/2011/09/restful.html

13. 共享模式?

共享有效的大量细粒度对象,来提供应用程序的性能, 节约系统重复创建对象实例的性能消耗. 是给出内存资源节省的一个方案.

14. php的namespace?

什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子,文件 foo.txt 可以同时在目录/home/greg 和 /home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。另外,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以及目录分隔符放在文件名之前得到 /home/greg/foo.txt。这个原理应用到程序设计领域就是命名空间的概念。

在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

  1. 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
  2. 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

PHP 命名空间(5.3后才有)提供了一种将相关的类、函数和常量组合到一起的途径。

15. php spl

spl更多的被看做是一种是object模仿array行为的接口和类.
php标准库spl 主要包含预定义常量,数据结构,迭代器(核心),接口,异常,文件处理,spl函数.
迭代器(Iterator) 能够使许多不同的数据结构,都能有统一的操作界面,比如一个数据库的结果集同一个目录中的文件集,或者一个文本中每一行构成的集合.
参考: http://www.ruanyifeng.com/blog/2008/07/php_spl_notes.html

16. autoload

尝试加载未定义的类,可以使用autoload这个魔术方法中实现include(),从而 用户创建对象的时候没有引入文件也不会报错.因为autoload自动加载了该文件

定义一个ClassA类  在ClassA.php中
<?php
class ClassA{
public function __construct(){
echo "ClassA load success!";
}
}
?>
在index.php创建ClassA的一个对象
<?php
function __autoload($classname) {
$filename = "./". $classname .".php";
include_once($filename);
}

$obj = new ClassA();
?>
结果是 ClassA load success!

17. 二叉树遍历,非递归实现

1.前序

对于任一结点T:

1)访问结点T,并将结点T入栈;

2)判断结点T的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点T,循环至1);若不为空,则将T的左孩子置为当前的结点T;

3)直到T为NULL并且栈为空,则遍历结束。

//前序遍历 -- 非递归实现 -- 利用栈实现 
void preOrderTraverse2 (BiTree T){
stack<BiTree> s; //初始化栈, 此时s 不为空的...
while(T != NULL || !s.empty()){ //栈为null并且当前结点也为null 退出循环
while(T != NULL){
cout << T->data << " ";
s.push(T);
T = T->lchild;
}
T = s.top();
s.pop();
T = T->rchild;
}
}
2.中序

对于任一结点P,

1)若其左孩子不为空,则将T入栈并将P的左孩子置为当前的T,然后对当前结点T再进行相同的处理;

2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的T置为栈顶结点的右孩子;

3)直到T为NULL并且栈为空则遍历结束

//中序遍历 -- 非递归遍历 -- 用栈实现 -- 和前序遍历的顺序略有调整 
void inOrderTraverse2 (BiTree T){
stack<BiTree> s;
while(T != NULL || !s.empty()){ //当前结点为null 并且 栈为null时 退出循环
while(T != NULL) {
s.push(T);
T = T->lchild;
}
T = s.top();
cout << T->data << " ";
s.pop();
T = T->rchild;
}
}
3.后序遍历

要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点T,先将其入栈。如果T不存在左孩子和右孩子,则可以直接访问它;或者T存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将T的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

//后序遍历(post order traverse) -- 先入右结点,后入左结点 
void postOrderTraverse2(BiTree T){
stack<BiTree> s;
s.push(T);
BiTree cur; //当前访问的结点
BiTree pre = NULL; //前一个访问的结点
while(!s.empty()){
cur = s.top();
//当前结点没有左右结点 或者 孩子结点都已经被访问过了 -- 输出当前的值
if((cur->lchild == NULL && cur->rchild == NULL)|| (pre != NULL && (pre == cur->lchild || pre == cur->rchild))) {
cout << cur->data << " " ;
s.pop();
pre = cur;
}else{
//先入右结点
if(cur->rchild != NULL){
s.push(cur->rchild) ;
}
if(cur->lchild != NULL){
s.push(cur->lchild);
}
}
}
}

18. php接口,通信方式,socket,http通信实现

socket 相当于进行网络通信两端的插座, 只要对方的socket和自己的socket有通信联接, 双方就可以发送和接受数据了.

服务器端:

  1. 先调用socket()创建一个套接字
  2. 调用bind()绑定ip地址和端口
  3. 启动一个for循环, 循环中使用accept()进行监听连接请求, 接收到连接返回通信套接字.
  4. 使用getOutStream()和getInputStream()获取输出流和输入流, 调用send()和recv()发送和接受数据
  5. 关闭套接字 close()

客户端

  1. 调用socket()创建套接字, 并连接到服务器端connect()(连接),
  2. 使用getOutStream()和getInputStream()获取输出流和输入流, 调用send()和recv()发送和接受数据
  3. 关闭套接字 close()

19. json数据格式有哪些特点?

JSON的两种结构

  1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。

  2. 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

对于所有语言都是统一的key-value处理规范 eg { “name”: “wangming” }
可读性比较高
如果要处理大量 JavaScript 对象,那么 JSON 几乎肯定是一个好选择,这样就可以轻松地将数据转换为可以在请求中发送给服务器端程序的格式。

20. 验证码安全,实现原理?

验证码实现原理

  1. 产生随机字符或数字,
  2. 生成一个png图片,
  3. 将每个随机值调整角度和位置到png图片中,
  4. 加入噪点和干扰线来防止机器分析图片 ,
  5. 在将随机产生的字符或数字存到服务器端的session中,并设置有效期
  6. 输出图片
  7. 释放图片和内存

验证码的安全

  1. 一般验证码生成后,会在服务器中的session中进行保存,并且设置了有效期.
  2. 客户端,将验证码的值通过请求发送到服务器中,服务器,进行session的有效期是否过期和验证session值是否和客户端发送来的是否一致,若一致,返回true,进行下一个用户的操作否则返回false则重新生成一个验证码,并将新的验证码值覆盖之前的session值.

21. 请求量比较大时应从哪方面优化提高性能?

1. 页面静态化
2. 使用缓存机制
3. sql优化 数据库读写分离,优化数据表
4. 数据的水平分割和垂直分割(根据具体的应用场景来使用)
5. 控制大文件的下载
6. HTTP重定向,dns重定向 分流

增加N台内部服务器,组成一个局域网,将程序复制N份放到内部服务器中,原来的服务器作为与因特网通信的接口。当原服务器收到客户端请求后,服务器选择一个负载最小的内部服务器,将客户端的请求重定向到该服务器

22. javascript和jquery区别


  1. jQuery其实是一个轻量级的JavaScript库或者说是框架,是对JavaScript的一个扩展,封装, jQuery简化了的JavaScript编程
  2. JavaScript是个脚本语言,是浏览器的一部分,用于客户端的脚本语言,最早在html网页上使用,给html网页增加动态功能.
    由于jQuery是对JavaScript的一个封装,所以 在代码书写中是有区别的.

1 加载dom的区别

javascript:
function first(){}
function second(){}
window.onload = first;
window.onload = second;
只会执行第二个window.onload;
可以通过这个进行改进 window.onload = function(){ first(); second();}
jQuery : 美元符(document).reday() { first(); }
美元符(document).reday(){ second(); } 这两个函数都会执行
2. 获取id
javascript: document.getElementById(‘idName’) ;
jQuery : $(‘#idName’);
等等….

23. core文件是什么?有什么用?

core是unix系统的内核。当你的程序出现内存越界的时候,操作系统会中止你的进程,并将当前内存状态导出到core文件中,以便进一步分析。

bug和操作系统或硬件的保护机制都会导致程序异常终止,操作系统会kill掉这些进程并产生core文件,程序员可以通过core文件来找出问题所在。 它记录了程序挂掉时详细的状态描述

24. fork后,子进程保留父进程的什么?

fork()会产生一个和父进程完全相同的子进程

fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间

25. 共享内存除了文件映射还有什么方式?

原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,进程对其可以直接访问,避免了数据的复制过程。内存映射文件是一个共享的资源,多个进程读写必然存在同步的问题
另一种方式 对象映射[ 不太确定 ]

26. tcp是怎样实现流量控制的

所谓流量控制就是让发送发送速率不要过快,让接收方来得及接收。利用滑动窗口机制就可以实施流量控制。
发送方的发送窗口不可以大于接收方发回的窗口大小
窗口大小在ACK的报文里。

27. 一个超长字符串表示的十进制数(大于2^32),转化为十六进制的字符串

<?php
$number = 123456; //十进制的被除数
$div = 16; //除数
$remainder = []; //余数
while(1){
if($number >= 16){
array_push($remainder,$number % $div); //余数入栈
$number = (int)($number / $div); //重新生成被除数
}else{
array_push($remainder,$number); //将最后的值入栈;
break;
}
}

while(1){
$temp = array_pop($remainder);
if($temp !== null){
switch($temp){
case 10:
echo 'A ';
break;
case 11:
echo 'B ';
break;
case 12:
echo 'C ';
break;
case 13:
echo 'D ';
break;
case 14:
echo 'E ';
break;
case 15:
echo 'F ';
break;
default:
echo $temp, ' ';
}
}else{
break;
}
}
?>

28. https和http的区别?https的安全性

区别:
总的来说,http效率更高,https安全性更高。
HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议

它基于HTTP开发,用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换
HTTPS使用端口443
HTTPS协议需要到ca申请证书,一般免费证书很少,需要交费。
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议 要比http协议安全
https 则是具有安全性的ssl加密传输协议, 信息是密文

http: 超文本传输协议

http使用端口号是80
http的连接很简单,是无状态的
http是超文本传输协议,信息是明文传输

https的安全性
https使用非对称加密的方式加密一个密钥,然后双方使用这个密钥对传输的明文数据进行对称加密。非对称常用的是RSA,对称常用D­ES等

1.客户端发起连接,向服务器发送ClientHello报文,主要内容包括自己支持的各种算法列表,比如非对称加密的支持哪些,对称加密的支持哪些等等。
2.服务器收到消息之后,和自己支持的加密算法对比,找出双方都支持的算法,然后服务器把自己的证书,常见的是X509证书,发送给客户端,ServerH­ello报文,包含被选中的加密算法,X509证书等内容,证书中包含服务器的公钥等内容。
3.客户端接受到了证书之后获取服务器的公钥,随即生成一个字符串,使用服务器的公钥加密,发送给服务端。
4.服务端用自己的私钥解开这个加密串,得到明文。
5.然后服务器和客户端之间就使用这个串作为密钥,来作对称加密。这样https回话就建立了.

29. 数据库连接池原理,什么是数据结构实现的?

数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需要从缓冲池中取出一个了,使用完毕后再放回去。我们可以通过设定连接池最大数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库连接使用数量,使用情况,为系统开发,测试以及性能调整提供依据。
连接池的工作原理主要由三部分组成,分别为连接池的建立,连接池中连接的使用管理连接池的关闭

可以用队列实现

30. hashtable和hashmap的区别.

1.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
2.hashMap键和值都是对象,并且不能包含重复键,允许空键值,而hashTable不允许。
3.HashTable中hash数组默认大小是11,增加的方式是old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

31. 对于静态页面文件,是放在nginx端,还是Server端?

放在nginx端, ngnix处理静态页面性能比apache要*倍以上,所以直接放在ngnix

32. 用php做客户端接口应注意什么问题

数据加密
数据验证
使用json传参

33. 建立数据库应该注意哪些?

  1. 根据应用场景选取合适的数据库搜索引擎
  2. 表名和字段名称要有意义,
  3. 字段选取合适的类型, 添加注释
  4. 可以使用前缀给出表和视图内容之外的其它信息
  5. 为表建立主键,外键,索引,约束
  6. 建表可以依据范式进行创建.

34. 数据库事务是什么?

事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
事务通常是以BEGIN TRANSACTION开始,以COMMITROLLBACK结束。
事务的四个基本要素:ACID 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

原子性: 事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。
一致性: 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。(例如 一个字段建立的约束条件是a+b=10, 如果事务改变了a的值,则b的值也会相应的改变)
隔离性: 一个事务的执行不能被其他事务干扰。
持久性: 一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

35. sql注入有哪些,如何有效防止?

sql注入: 通过把SQL命令插入到Web表单提交或输入域名页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
注入

1. 使用特殊的字符: 不同的SQL数据库有许多不同是特殊字符和变量,通过某些配置不安全或过滤不细致的应用系统能够取得某些有用的信息,从而对进一步攻击提供方向。
2. 使用条件语句: 此方式具体可分为基于内容、基于时间、基于错误三种形式。一般在经过常规访问后加上条件语句,根据信息反馈来判定被攻击的目标。
3. 利用存储过程: 通过某些标准存储过程,数据库厂商对数据库的功能进行扩展的同时,系统也可与进行交互。部分存储过程可以让用户自行定义。通过其他类型的攻击收集到数据库的类型、结构等信息后,便能够建构执行存储过程的命令。
4. 采用非主流通道技术: 除HTTP响应外,能通过通道获取数据,然而,通道大都依赖与数据库支持的功能而存在. E-mail、DNS以及数据库连接,基本思想为:先对SQL查询打包,然后借助非主流通道将信息反馈至攻击者。

防范

1. 输入验证: 检查用户输入的合法性,确信输入的内容只包含合法的数据。数据检查应当在客户端和服务器端都执行之所以要执行服务器端验证,是为了弥补客户端验证机制脆弱的安全性。
2. 错误消息处理: 防范SQL注入,还要避免出现一些详细的错误消息,因为黑客们可以利用这些消息。要使用一种标准的输入确认机制来验证所有的输入数据的长度、类型、语句、企业规则等。
3. 加密处理: 将用户登录名称、密码等数据加密保存。加密用户输入的数据,然后再将它与数据库中保存的数据比较
4. 存储过程来执行所有的查询: *SQL参数的传递方式将防止攻击者利用单引号和连字符实施攻击。此外,它还使得数据库权限可以限制到只允许特定的存储过程执行*,所有的用户输入必须遵从被调用的存储过程的安全上下文
5. 确保数据库安全: 锁定你的数据库的安全,只给访问数据库的web应用功能所需的最低的权限,撤销不必要的公共许可,如果web应用不需要访问某些表,那么确认它没有访问这些表的权限。如果web应用只需要只读的权限,那么就禁止它对此表的 drop 、insert、update、delete 的权限

36. Cookie和Session区别?

cookie机制采用的是在客户端保持状态的方案。它是在用户端的会话状态的存贮机制,他需要用户打开客户端的cookie支持。cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力

session机制采用的是一种在客户端与服务器之间保持状态的解决方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的。而session提供了方便管理全局变量的方式

session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器

就安全性来说:当你访问一个使用session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些.因为它不会任意读取客户存储的信息。

Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。

session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个 session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。

关闭浏览器后这个 session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。

http是无状态的协议,客户每次读取web页面时,服务器都打开新的会话,而且服务器也不会自动维护客户的上下文信息,那么要怎么才能实现网上商店中的购物车呢

session是以cookie或URL重写为基础的,默认使用cookie来实现,系统会创造一个名为JSESSIONID的输出cookie,我们叫做**session cookie,以区别persistent cookies,也就是我们通常所说的cookie

当我们把浏览器的cookie禁止后,*web服务器会采用URL重写*的方式传递Sessionid,我们就可以在地址栏看到sessionid=KWJHUG6JJM65HS2K6之类的字符串。

session cookie针对某一次会话而言,会话结束session cookie也就随着消失了,而persistent cookie只是存在于客户端硬盘上的一段文本(通常是加密的),而且可能会遭到cookie欺骗以及针对cookie的跨站脚本攻击,自然不如session cookie安全了。

通常session cookie是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的sessionid,这样我们信息共享的目的就达不到了,此时我们可以先把sessionid保存在persistent cookie中,然后在新窗口中读出来,就可以得到上一个窗口SessionID了,这样通过session cookie和persistent cookie的结合我们就实现了跨窗口的session tracking(会话跟踪)。

cookie的清除操作有浏览器执行.

cookie的总大小和浏览器有关联,一般是4k, 每个域名可以设置20个
session没有限制大小, 上限是你的内存上限

session共享的几种方式

1. 基于NFS的Session共享
2. 基于数据库的Session共享
3. 基于Cookie的Session共享
4. 基于缓存(Memcache)的Session共享
参考: http://blog.csdn.net/it_man/article/details/38368795

参考 http://blog.sina.com.cn/s/blog_59e16a4d0100q3yn.html
参考 http://laiguowei2004.blog.163.com/blog/static/3682900020107302248722/
参考: http://blog.csdn.net/u013927110/article/details/47019215

37. 禁用Cookie后,Session还可以用吗,有什么解决方案?

可以 采用URL重写的方式传递Sessionid
也可以通过隐藏表单传递sessionid

38. 解释一下php中的fastcgi,那cgi是什么,cgi和fastcgi的区别

CGI工作原理:每当客户请求CGI的时候,WEB服务器就请求操作系统生成一个新的CGI解释器进程(如php-cgi.exe),CGI 的一个进程则处理完一个请求后退出,下一个请求来时再创建新进程。
FastCGI是语言无关的、可伸缩架构的CGI开放扩展,其主要行 为是将CGI解释器进程保持在内存中并因此获得较高的性能
参考http://blog.csdn.net/u010187139/article/details/46840469

39. get与post提交方法的区别

GET是发送请求HTTP协议通过URL参数传递进行接收数据, URL地址存在最大长度问题,一般是2k 所以GET传送的数据量小, 并且用户能通过URL看到,所以不安全

POST可以通过表单提交大量信息,POST将表单中的内容放在html的header中,发送给URL, 用户看不到这个过程, 所以相对安全. post传送的数据量比较大, php.ini默认是8M

40. PHP打印出前一天的时间格式

date(‘Y-m-d H:i:s’, strtotime(‘-1 days’));

41. echo(),print(),print_r()的区别

echo和print是语句,没有返回值

print_r()是函数, 又返回值

千万不要被()给迷惑了, ()有时候是个预算符.

可以通过function_exists("函数名称")进行测试
var_dump(function_exists('print'));
var_dump(function_exists('echo'));
var_dump(function_exists('print_r'));

结果是:
bool(false)
bool(false)
bool(true)

42. MYSQL取得当前时间的函数是?,格式化日期的函数是?

日期函数:now(), curdate(), curtime()
格式化: date_format() FROM_UNIXTIME(time, format)

select curdate();       //当前的日期 y-m-d
select curtime(); //当前时间 h:i:s
select now(); //当前的日期和时间 y-m-d h:i:s
select date_format(now(),'%Y-%m-%d') ; //格式化
FROM_UNIXTIME(create_time, '%Y-%m-%d %H:%i:%s')

43. 用PHP写出 显示客户端和服务器端ip的代码

通过本地apache测试

header("Content-type:text/html; charset=utf-8");
echo '<pre>客户端ip:', $_SERVER['REMOTE_ADDR'], '</pre>';
echo '<pre>服务器端ip:', $_SERVER['SERVER_ADDR'], '</pre>';
echo '<pre>通过域名解析ip:',gethostbyname("baidu.com"), '</pre>';

结果:
客户端ip:127.0.0.1
服务器端ip:127.0.0.1
通过域名解析ip:220.181.57.217

44. include和require的区别

  1. include()语句, 执行文件时, 都要进行读取和评估,而 require()只执行一次
  2. include在用到时加载, require在一开始加载(一般放在顶部)
  3. include遇到错误,会给出提示,并继续执行, require也会给出提示,并停止运行下面的代码.
    _once后缀的表示 已经加载的不再加载

45. 修改session的生存周期

  1. 修改 php.ini 中的session.gc_maxlifetime 默认是1440(单位是秒)

  2. savePath = “./session_save_dir/”;
    lifeTime = 小时 * 秒;
    session_save_path(savePath);
    session_set_cookie_params(lifeTime);
    session_start();

  3. setcookie() and session_set_cookie_params($lifeTime);

46. 给定一个用php开发的主页: http://www.abc.com/index.html,如何获取它的内容

//第一种方式:
$readcontents = fopen("http://www.abc.com/index.html", "rb");
$contents = stream_get_contents($readcontents); //将一个流的剩余部分读入一个字符串中
fclose($readcontents);
echo $contents;
//第二种方式
//直接用file_get_contents()
echo file_get_contents("http://www.abc.com/index.html");

47. PHP中,heredoc

heredoc的语法是用”<<<”加上自己定义成对的标签,在标签范围內的文字视为一个字符串

<?php
$str = <<< SHOW //开始标示符
my name is wangming!
SHOW; //结束标示符 必须定格
echo $str;
//结果是 my name is wangming!
?>

48. PHP中error_reporting()作用

设置php的错误报告级别

49. 获取当前执行脚本路径和参数

1. 如果脚本路径全路径则用$_SERVER全局变量获取或_FILE_

echo $_SERVER['SCRIPT_FILENAME'], "\n<br/>";

结果: F:/Apache/www/temp/php_demo/demo/demo.php

echo __FILE__, "\n<br/>";
//str_replace('\\', '/', __FILE__);

结果: F:\Apache\www\temp\php_demo\demo\demo.php

这是在window下, 用FILE路径是用 \ 分割 魔术常量不区分大小写
可以使用 str_replace();进行处理之后结果和第一个就一样了.

  1. 获取参数
echo $_SERVER['QUERY_STRING'], "\n<br/>";

比如URL中有 ?sfs=sfds&sdf=sfds
结果: 则输出?之后的 即: ?sfs=sfds&sdf=sfds
3. 题目的意思如果是获取的文件名称
需要利用FILE魔术常量

$script_name = basename(__FILE__);
print_r($script_name);

结果是: demo.php

50. foo()和@foo()之间有什么区别

php@可是控制错误的输出, 加上@之后语句有错误则屏蔽掉.

51. mysql_fetch_row() 和mysql_fetch_array之间有什么区别?

mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得

举例:

<?php
$connect = mysql_connect('localhost','root','mysql');
if(!$connect){
die("数据库连接失败</br>".mysql_error());
}
$db_select = mysql_select_db('cangku');
if(!$db_select){
die("没有这个数据库</br>".mysql_error());
}
$sql = 'select * from user_info limit 1';
$res = mysql_query($sql);

//使用mysql_fetch_array遍历结果
while($row = mysql_fetch_array($res)){
$result[] = $row;
}
print_r($result);
$res = mysql_query($sql);
mysql_close();

//使用mysql_fetch_row遍历结果
while($row = mysql_fetch_row($res)){
$result1[] = $row;
}
print_r($result1);
?>

结果是:

Array
(
[0] => Array
(
[0] => 1
[id] => 1
[1] => admin
[user_ident] => admin
.....
[9] => 1418721886
[create_time] => 1418721886
)
.......
)
Array
(
[0] => Array
(
[0] => 1
[1] => admin
.....
[9] => 1418721886
)
......
)

52. 从一个标准url中取出扩展名

<?php
//给定一个标准的url 从中去除扩展名

//第一种方式
function getExt1($url){
$arr = parse_url($url);
print_r($arr);
$path = $arr['path'];
$res = explode('.', $path);
var_dump('文件扩展名是: ' . $res[1]);
}
//第二种方式
function getExt2($url){
$file = basename($url);
var_dump('basename is; ' . $file);
$pos1 = strpos($file, '.'); //字符.在$file中第一次出现的位置
$pos2 = strpos($file, '?');
if(strstr($file,"?"))
{
var_dump('文件扩展名是: ' . substr($file,$pos1 + 1,$pos2 - $pos1 - 1));
}else{
var_dump('文件扩展名是: ' . substr($file,$pos1 + 1));
}
}
$url = 'http://www.sina.com.cn/abc/de/fg.php?id=12';
//$url = 'http://www.sina.com.cn/abc/de/fg.php';
echo 'url 是: ',$url, "\n";
getExt1($url);
echo "\n\n";
getExt2($url);
?>

结果是:

url 是: http://www.sina.com.cn/abc/de/fg.php?id=12
Array
(
[scheme] => http
[host] => www.sina.com.cn
[path] => /abc/de/fg.php
[query] => id=12
)
string(23) "文件扩展名是: php"


string(26) "basename is; fg.php?id=12"
string(23) "文件扩展名是: php"

53. 判断链表是否存在环

定义两个指针, 都指向头结点, 一个走的快,一个走的慢, 如果是环, 若干步之后, 快的会超过慢的一圈.
为什么是一圈而不是相遇呢, 个人理解: 单链表中,这两个指针会在最后一个结点相遇.

参考: http://blog.csdn.net/thefutureisour/article/details/8174313

54. 如何计算环的长度

首先它是环,才能从第一次相遇开始计数
当快指针和慢指针相遇的时候开始计数, 当他们再次相遇的时候, 就是环的长度

55. 判断两个不带环的链表是否相交

设定 第一个链表为L1 第二个链表为L2
1.将L1的头部和尾部相连构成一个环, 如果L2也是环 则 L1和L2相交

2.将L1和L2的头尾相连, 判断新组成的链表是否为环, 如果是则相交

原因: 大家通过画图 便可明白, 原理就是只要有环,并且环上有个入口(就是连接点)则可以通过这个入口进入到环中.

56. Memcache内存分配机制

1.page(页)为内存分配的最小单位
2.Slabs(层)划分数据空间
3.Chunk(块)才是存放缓存数据的单位。

4. Slab的内存分配

Memcached在启动时通过-m指定最大使用内存,但是这个不会一启动就占用,是随着需要逐步分配给各slab的。

如果一个新的缓存数据要被存放,memcached首先选择一个合适的slab,然后查看该slab是否还有空闲的chunk,如果有则直接存放进去;如果没有则要进行申请slab申请内存时以page为单位,所以在放入第一个数据,无论大小为多少,都会有1M大小的page被分配给该slab。申请到 page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk的数组,在从chunk数组中选择一个用于存储数据。

这里有几个特点要注意

1. Memcached分配出去的page不会被回收或者重新分配
2. Memcached申请的内存不会被释放
3. slab空闲的chunk不会借给任何其他slab使用

详情请参考: http://blog.csdn.net/u010187139/article/details/47010405

57. 索引如何存储

索引文件在存储器上分为两个区:索引区和数据区。索引区存放索引表,数据区存放主文件
索引表分由关键字该关键字所在记录的物理地址组成, 统称为索引项

分类
如果每个节点在索引表中都有一个索引项,则该索引表就被称为稠密索引
若一组节点在索引表中只对应于一个索引项,则该索引表就成为稀疏索引又称分块索引

把数据集的记录分成了若干块,并且这些块需要满足两个条件:

1. 块内无序: 每一块的记录不需要有序. 当然有序查找的会更快
2. 块间有序: 要求第二块所有的记录均要大于第一快的所有的额记录的关键字, 因为只有块间有序,才有可能在查找是带来效率.

搜索引擎中,需要按某些关键字的值来查找记录,为此可以按关键字建立索引,这种索引就叫做倒排索引

原理: 事先生成一个单词表表(有序的), 表中主要存储 次关键码和记录号(即地址)
当用户输入关键字的时候, 先对关键字按照某种算法进行 拆分成次关键码, 然后通过查单词表,能迅速得到用户想要的数据和记录数(因为单词表是有序的,查找效率很高的) , 在文章数是海量的时候,这样的做法只是理论上可行的.现实中没有人愿意使用的.

参考: 大话数据结构:306页
http://baike.baidu.com/link?url=W7z0TwKBRvFEW9vPQOWMNy2sm2dghAUVdNezzq5eTVjDJPMsLNu3SY01wdTQBTImIfZ4rY1bUBAtubPyTyPPOK

58. js面向对象

  1. js对象: 是无序属性的集合, 属性可以包含 基本值, 对象 或函数.
  2. js中的每个方法就可以理解为一个对象.可以基于Object创建对象,可以基于对象字面量方式
  3. 在方法中定义的变量和方法可以理解为对象的私有属性和方法
  4. 通过 对象名.prototype关键字添加对象的共有的属性和共有方法
  5. 通过 类名.属性和类名.方法 可以添加静态静态成员属性和方法
  6. 可以使用.操作符扩展属性,可以使用delete将属性设置为undefined

参考http://blog.csdn.net/u010187139/article/details/47017543

59. js中的闭包

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

参考 http://segmentfault.com/a/1190000000652891

闭包的三个特性: 1. 作用域链,2. 垃圾(内存)回收机制,3. 函数嵌套

1.作用域链:

函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查找,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续.如果找到最后也没找到需要的变量,则解释器返回undefined.

2.垃圾(内存)回收机制

一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.下次再执行此函数的时候,所有的变量又回到最初的状态,重新赋值使用.但是如果这个函数内部又嵌套了另一个函数,而这个函数是有可能在外部被调用到的.并且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.如果在外部函数返回后,又直接调用了内部函数,那么内部函数就无法读取到他所需要的外部函数中变量的值了.所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(*变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包

有了闭包,嵌套的函数结构才可以运作

var result=[];
function foo(){
var i= 0;
for (;i<3;i=i+1){
result[i]=function(){
console.log(i);
}
}
}
foo();
result[0](); // 3
result[1](); // 3
result[2](); // 3

这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的*变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变

解决的方法之一,是让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值

var result1=[];
function foo1(){
var i= 0;
for (;i<3;i=i+1){
result1[i]=(function(j){
return function(){
console.log(j);
};
})(i);
}
}
foo1();
result1[0](); // 0
result1[1](); // 1
result1[2](); // 2

这里用到了另外2个技术,立即调用的匿名函数返回函数.也是初学者比较难以理解的部分
参考: http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html

>

60. 数据库读写分离

读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。能有效地减轻数据库压力,也能减轻io压力, 数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

其实在很多系统中,主要是读的操作。当主数据库进行写操作时,数据要同步到从的数据库,这样才能有效保证数据库完整性

对于这类读大于写并且数据量增加不是很明显的数据库,推荐采用读写分离+缓存的模式,试想一下一个用户注册、修改用户信息、记录用户登录时间、记录用户登录IP、修改登录密码,这些是写操作。但是以上这些操作次数都是很小的,所以整个数据库的写压力是很小的。唯一一个比较大的就是记录用户登录时间、记录用户登录IP这类信息,只要把这些经常变动的信息排除在外,那么写操作可以忽略不计。所以读写分离首要解决的就是经常变化的数据的拆分,比如:用户登录时间、记录用户登录IP。这类信息可以单独独立出来,记录在持久化类的缓存中(可靠性要求并不高,登陆时间、IP丢了就丢了,下次来了就又来了)

以oracle为例,主库负责写数据、读数据。读库仅负责读数据。每次有写库操作,同步更新cache,每次读取先读cache在读DB。写库就一个,读库可以有多个,采用dataguard(备库)来负责主库和多个读库的数据同步。

PHP面试的相关知识点

参考: http://blog.csdn.net/kobejayandy/article/details/8775255

mysql也有自己的同步数据技术。mysql只要是通过二进制日志来复制数据。这个复制比较好的就是通过异步方法,把数据同步到从数据库

主数据库同步到从数据库后,从数据库一般由多台数据库组成这样才能达到减轻压力的目的。读的操作怎么样分配到从数据库上?应该**根据服务器的压力把读的操作分配到服务器,而不是简单的随机分配。**mysql提供了MySQL-Proxy实现读写分离操作

PHP面试的相关知识点
PHP面试的相关知识点

上面说的数据库同步复制,都是在从同一种数据库中
参考: http://www.cnblogs.com/qlee/archive/2011/04/08/2009738.html

61. 设计模式的好处

设计模式是在某一背景下某个问题的解决方案.

1.复用解决方案

通过复用已经公认的设计,我能够在解决问题时取得先发优势,而且避免重蹈前人覆辙。我可以从学习他人的经验中获益,用不着为那些总是会重复出现的问题再次设计解决方案了。

2.确立通用术语

开发中的交流和协作都需要共同的词汇基础和对问题的共识。设计模式在项目的分析和设计阶段提供了共同的基准点。

3.提高观察高度

模式还为我们提供了观察问题、设计过程和面向对象的更高层次的视角,这将使我们从“过早处理细节”的桎梏中解放出来。

4.使软件更容易修改和维护

原因在于,它们都是久经考验的解决方案。所以,它们的结构都是经过长期发展形成的,比新构思的解决方案更善于应对变化。而且,这些模式所用代码往往更易于理解——从而使代码更易维护。

62. 前端性能优化

  1. 减少http请求
  2. 用Gzip压缩并优化js/css/image
  3. 代码规范
  4. 异步加载 ajax
  5. 延迟加载
  6. 预加载

PHP面试的相关知识点

参考: http://www.cnblogs.com/lei2007/archive/2013/08/16/3262897.html

63. PHP strlen()和mb_strlen()的区别

两个函数都是返回字符串的长度
strlen() 使用单字符集计算字符串的长度
mb_strlen() 可以指定字符集进行计算字符串的长度

<?php
$str1 = 'wangming is a good boy!';
echo 'str1 strlen length is', strlen($str1), "\n";
echo 'str1 mb_strlen length is', mb_strlen($str1,'utf-8'), "\n";
$str2 = '王明是一个好人';
echo 'str2 strlen length is', strlen($str2), "\n";
echo 'str2 mb_strlen length is', mb_strlen($str2,'utf-8'), "\n";
?>

结果是:

str1 strlen length is23
str1 mb_strlen length is23
str2 strlen length is21
str2 mb_strlen length is7

注意 使用mb_strlen()需要制定字符集, 如果不指定默认返回的和strlen()相同

64. PHP 翻转字符串(含中文)

1.没有中文的 直接使用php的内部方法: strrev()便可

$str4 = 'www.baidu.com';
echo strrev($str4), "\n";

结果: moc.udiab.www

2.含有中文

原理: 1. 将字符串分解数组, 2. 用数组的array_reverse()函数翻转 3. 用join()在链接起来.

$str3 = '中国2北333京欢迎你';
function utf8_strrev($str){
preg_match_all('/./us', $str, $ar);
return join('',array_reverse($ar[0]));
}
function strrev_utf8($str){
return join('', array_reverse(preg_split('//u', $str)));
}
var_dump(utf8_strrev($str3));
var_dump(strrev_utf8($str3));

结果是:
string(25) “你迎欢京333北2国中”
string(25) “你迎欢京333北2国中”

注: preg_split()返回的是一维数组
preg_match_all()返回二维数组

65. PHP 什么是可变变量

一个普通变量的值作为这个可变变量的变量名

举例:

<?php
$a = 'hello'; //定义了一个普通变量
?>
<?php
$$a = 'world'; //定义了一个可变量, 相当于$hello = 'world'
?>
<?php
//第一个输出和第二个输出是一样的
echo "$a ${$a}"; //hello world
echo "$a $hello";
?>

看下这个例子:

<?php
$Bar = "a";
$Foo = "Bar";
$World = "Foo";
$Hello = "World";
$a = "Hello";

$a; //Returns Hello
$$a; //Returns World
$$$a; //Returns Foo
$$$$a; //Returns Bar
$$$$$a; //Returns a

$$$$$$a; //Returns Hello
$$$$$$$a; //Returns World
?>

注: 在 PHP 的函数和类的方法中,超全局变量不能用作可变变量$this 变量也是一个特殊变量,不能被动态引用。

eg:

$wanming = 'cc';
$$wanming = $this; //会报错误的

66. apche动态加载php模块和解析php脚本处理 如何在配置文件中配置

//以模块的方式再装php, 在http.conf中配置如下, 即可动态装载PHP模块
LoadModule php5_module "f:/php5.4.16/php5apache2_4.dll"
//下面的配置可以是: apache下所有的php文件都作为php脚本处理
AddType application/x-httpd-php .php

67. 计算字符串中的某个字符的个数

利用php内部函数substr_count()

//计算字符串的额长度
$text = 'asfkasfjasfasfwerwefss';
echo substr_count($text, 's'); //结果是: 6

68. 接口和抽象类的区别

  1. 抽象类是一种不能被实例化的类, 只能用于其他类的父类来使用, 抽象类通过关键字abstract 来声明.
  2. 抽象类和普通的类相似, 都包含成员属性和成员方法, 两者的区别是: 抽象类至少要有一个抽象方法.
    抽象方法没有方法体, 需要子类重写.
    抽象方法的格式为: abstract function abstractMethod();
  3. 接口是抽象方法的集合,如果一个类继承了这个接口,就要使用所有的抽象方法
  4. 接口可以继承一个或多个其他的接口, 抽象方法只能继承一个类
  5. 子类继承抽象类使用extends, 子类实现接口使用implements
  6. 抽象类中方法可以是public, protected这些修饰符, 接口默认的修饰符是public, 不能使用其他的修饰符

69. mysql中varchar的大小

1. 存储限制

varchar字段第一个字节通常是是: 0xef, 用1到2个字节存储实际的长度(长度超过255时用2个字节), 所以最大的长度不能超过65535-1-2个长度

2. 编码长度限制

字符类型若为Latinl,每个字符占1个字节,最大长度不能超过65532;
字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766;
字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845。

3. 行长度限制

Mysql中要求一个行定义的长度不能超过65535,如果超过这个值, 会报错的.

计算例子

若一个表只有一个varchar类型,如定义为 create table t4(c varchar(N)) charset=gbk;

则此处N的最大值为(65535-1-2)/2= 32766。

减1的原因是实际行存储从第二个字节开始’;
减2的原因是varchar头部的2个字节表示长度;
除2的原因是字符编码是gbk。

若一个表定义为 create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;

则此处N的最大值为 (65535-1-2-4-30*3)/3=21812
减1和减2与上例相同;
减4的原因是int类型的c占4个字节;
减30*3的原因是char(30)占用90个字节,编码是utf8。

70. php 访问数据库的步骤

  1. 链接数据库: mysql_connect(‘host’, ‘user’, ‘passwd’);
  2. 选择数据库: mysql_select_db(数据库名);
  3. 设置字符集: mysql_query(‘set names utf8’);
  4. 执行sql语句: mysql_query(sql语句);
  5. 处理结果集
  6. 关闭结果集, 释放资源: mysql_free_result($result);
  7. 关闭连接: mysql_close($conn);

71. php final

1.final只能修饰类和方法,不能修饰成员属性

2.final修饰的方法不能在子类中进行重写

3.final修饰的类不能被继承

final class ClassF{
public static $name = 'wangming';
public static function test(){
var_dump('this is test static function');
}
final function test1(){
var_dump('this is final function');
}
const aa = 'wangming';
}
class A extends ClassF{ //提示错误PHP Fatal error: Class A may not inherit from final class 
public function test1(){ //提示错误Cannot override final method ClassF::test1()

}
}

注: 当一个类不让子类进行扩展 使用final定义此类

72. memcache工作原理

Memcahce是把所有的数据保存在内存当中,采用hash表的方式,每条数据又key和value组成,每个key是独一无二的,当要访问某个值的时候先按照找到值,然后返回结果。Memcahce采用LRU(最近最久未使用)算法来逐渐把过期数据清除掉.

73. 搜索引擎包含哪些技术

爬虫(采集)、切词(分词)、索引(存储)、查询以及其他相关技术

74. 假设给你5台服务器,请大致的描述一下,如何使用你所熟悉的开源软件,搭建一个日PV 300万左右的中型网站

台Web服务器,两台MySQL数据库服务器,采用Master/Slave同步的方式减轻数据库负载,Web服务器可以结合Memcahe缓存来减少负载,同时三台Web服务器内容一致,可以采用DNS轮训的方式来进行负载平衡

75. http一次请求的全过程

  1. 建立TCP连接
  2. Web浏览器向Web服务器发送请求命令
  3. Web浏览器发送请求头信息
  4. Web服务器应答
  5. Web服务器发送应答头信息
  6. Web服务器向浏览器发送数据
  7. Web服务器关闭TCP连接
    中间的每一个实现过程可以参考 http://blog.csdn.net/wdzxl198/article/details/11265475

76. session的工作原理

当客户端访问服务器时,服务器根据需求设置session,将会话信息保存在服务器上,同时将标示session的session_id传递给客户端浏览器,
浏览器将这个session_id保存在内存中(还有其他的存储方式,例如写在url中),我们称之为无过期时间的cookie。浏览器关闭后,这个cookie就清掉了,它不会存在用户的cookie临时文件。

以后浏览器每次请求都会额外加上这个参数值,再服务器根据这个session_id,就能取得客户端的数据状态。

如果客户端浏览器意外关闭,服务器保存的session数据不是立即释放,此时数据还会存在,只要我们知道那个session_id,就可以继续通过请求获得此session的信息;但是这个时候后台的session还存在,但是session的保存有一个过期
时间,一旦超过规定时间没有客户端请求时,他就会清除这个session。

77. 设计模式的6大原则

  1. 单一职责 就是一个类只负责一项职责
  2. 里氏替换 子类可以扩展父类的功能,但不能改变父类原有的功能
  3. 依赖倒转 具体依赖于抽象, 抽象不应该依赖具体
  4. 接口隔离原则 不要建立臃肿的接口
  5. 迪米特法则 只与直接朋友通信
  6. 开闭原则 对扩展开放, 对修改关闭

78. 开发环境、生产环境、测试环境的基本理解和区别

开发环境:开发环境是程序猿们专门用于开发的服务器,配置可以比较随意, 为了开发调试方便,一般打开全部错误报告。

测试环境:一般是克隆一份生产环境的配置,一个程序在测试环境工作不正常,那么肯定不能把它发布到生产机上。

生产环境:是指正式提供对外服务的,一般会关掉错误报告,打开错误日志。

79. 代理服务器与反向代理服务器的区别

代理服务器通常分为两类,即转发代理(forward proxy)服务器和反向代理(reverse proxy)服务器。转发代理服务器又通常简称为代理服务器,我们常提到的代理服务器就指的是转发代理服务器。

转发代理服务器

普通的转发代理服务器是客户端与原始服务器之间的一个中间服务器。为了从原始服务器获取内容,客户端发送请求到代理服务器,然后代理服务器从原始服务器中获取内容再返回给客户端。客户端必须专门地配置转发代理来访问其他站点,如在浏览器中配置代理服务器地址及端口号等。

转发代理服务器的一个典型应用就是为处于防火墙后的内部客户端提供访问外部Internet网,比如校园网用户通过代理访问国外网站,公司内网用户通过公司的统一代理访问外部Internet网站等。转发代理服务器也能够使用缓存来缓解原始服务器负载,提供响应速度。

反向代理服务器

而反向代理服务器则相反,在客户端来看它就像一个普通的Web服务器。客户端不要做任何特殊的配置。客户端发送普通的请求来获取反向代理所属空间的内容。反向代理决定将这些请求发往何处,然后就好像它本身就是原始服务器一样将请求内容返回。

反向代理服务器的一个典型应用就是为处于防火墙后的服务器提供外部Internet用户的访问。反向代理能够用于在多个后端服务器提供负载均衡,或者为较慢的后端服务器提供缓存。此外,反向代理还能够简单地将多个服务器映射到同一个URL空间。

两者区别

两者的相同点在于都是用户和服务器之间的中介,完成用户请求和结果的转发。主要的不同在于:

(1)转发代理的内部是客户端,而反向代理的内部是服务器。即内网的客户端通过转发代理服务器访问外部网络,而外部的用户通过反向代理访问内部的服务器。

(2)转发代理通常接受客户端发送的任何请求,而反向代理通常只接受到指定服务器的请求。如校园网内部用户可以通过转发代理访问国外的任何站点(如果不加限制的话),而只有特定的请求才发往反向代理,然后又反向代理发往内部服务器。

80. XSS攻击和CSRF

攻击手段和目的

a. 盗用 cookie ,获取敏感信息。

b.利用植入 Flash ,通过 crossdomain 权限设置进一步获取更高权限;或者利用Java等得到类似的操作。

c.利用 iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。

d.利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。

e.在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果。

漏洞的防御和利用:

将用户所提供的内容进行过滤
PHP的htmlentities()或是htmlspecialchars()

使用HTTP头指定类型:
很多时候可以使用HTTP头指定内容的类型,使得输出的内容避免被作为HTML解析。如在PHP语言中使用以下代码:

header(‘Content-Type: text/javascript; charset=utf-8’);

CSRF

CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。

要完成一次CSRF攻击,受害者必须依次完成两个步骤:

1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。

如何防御?

请求令牌

参考地址: http://www.freebuf.com/articles/web/39234.html

81. PHP安全函数解析

1. mysql_real_escape_string()

这个函数对于在PHP中防止SQL注入攻击很有帮助,它对特殊的字符,像单引号和双引号,加上了“反斜杠”,确保用户的输入在用它去查询以前已经是安全的了。但你要注意你是在连接着数据库的情况下使用这个函数。

但现在mysql_real_escape_string()这个函数基本不用了,所有新的应用开发都应该使用像PDO这样的库对数据库进行操作,也就是说,我们可以使用现成的语句防止SQL注入攻击。

2. addslashes()

这个函数和上面的mysql_real_escape_string()很相似。但要注意当设置文件php.ini中的magic_quotes_gpc 的值为“on”时,不要使用这个函数。默认情况下, magic_quotes_gpc 为 on,对所有的 GET、POST 和 COOKIE 数据 自动运行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致 双层转义。你可以通过PHP中get_magic_quotes_gpc()函数检查这个变量的值。

3. htmlentities()

这个函数对过滤用户输入数据非常有用,它可以把字符转换为 HTML 实体。比如,当用户输入字符“<”时,就会被该函数转化为HTML实体<,因此防止了XSS和SQL注入攻击。

4. htmlspecialchars()

HTML中的一些字符有着特殊的含义,如果要体现这样的含义,就要被转换为HTML实体,这个函数会返回转换后的字符串,比如,‘&’amp会转为‘&’。

5. strip_tags()

这个函数可以去除字符串中所有的HTML,JavaScript和PHP标签,当然你也可以通过设置该函数的第二个参数,让一些特定的标签出现。

6. md5()

一些开发者存储的密码非常简单,这从安全的角度上看是不好的,md5()函数可以产生给定字符串的32个字符的md5散列,而且这个过程不可逆,即你不能从md5()的结果得到原始字符串。

7. sha1()

这个函数和上面的md5()相似,但是它使用了不同的算法,产生的是40个字符的SHA-1散列(md5产生的是32个字符的散列)。

8. intval()

不要笑,我知道这不是一个和安全相关的函数,它是在将变量转成整数类型。但是,你可以用这个函数让你的PHP代码更安全,特别是当你在解析id,年龄这样的数据时

82. 为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

83. 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
参考地址: http://blog.csdn.net/whuslei/article/details/6667471

文章中如有错误, 请大家指出.

其它PHP相关例子参考: http://blog.csdn.net/u010187139/article/details/46787671
http://janephp.blog.51cto.com/4439680/1316012