首页 > 代码库 > 转载 遇到过的一些php笔试题
转载 遇到过的一些php笔试题
遇到过的一些php笔试题
1、linux的多线程和多进程有什么区别?什么时候使用多线程,什么时候使用多进程?
答:(1)进程资源调度的最小单位,线程是cpu调度的最小单位;多进程开销大,多线程开销小,这是最基本的区别;一个进程里面可能有很多线程,把进程分解为线程之后就可以有效利用cpu和内存
(2)当需要频繁创建和销毁时优先选用多线程;
需要进行大量计算的优先使用线程;
强相关的处理用线程,弱相关的处理用进程;
可能要扩展到多机分布的用进程,多核分布的用线程;
都满足需求的情况下用最熟悉最拿手的方式
2、现有的nosql数据库都有哪些?
答:NoSQL,指的是非关系型的数据库,Redis,Tokyo Cabinet,Cassandra,Voldemort,MongoDB,Dynomite,HBase,CouchDB,Hypertable, Riak,Tin, Flare, Lightcloud, KiokuDB,Scalaris, Kai, ThruDB等等都是非关系型数据库
3、javascript实现跨域的几种方法?
答:(1)document.domain+iframe的设置
对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。 具体的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别加上 document.domain = ‘a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以 “交互”了。当然这种办法只能解决主域相同而二级域名不同的情况,如果你异想天开的把script.a.com的domian设为alibaba.com 那显然是会报错地!代码如下:
www.a.com上的a.html
document.domain = ‘a.com‘;var ifr = document.createElement(‘iframe‘);ifr.src = http://www.mamicode.com/‘http://script.a.com/b.html‘;"h1")[0].childNodes[0].nodeValue);};
script.a.com上的b.html
document.domain = ‘a.com‘;
这种方式适用于{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何页面相互通信。
备注:某一页面的domain默认等于window.location.hostname。主域名是不带www的域名,例如a.com,主域名前面 带前缀的通常都为二级域名或多级域名,例如www.a.com其实是二级域名。 domain只能设置为主域名,不可以在b.a.com中将domain设置为c.a.com。
- 问题:
- 1、安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞。
- 2、如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。
(2)动态创建script
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。具体的做法可以参考YUI的Get Utility
这里判断script节点加载完毕还是蛮有意思的:ie只能通过script的readystatechange属性,其它浏览器是script的load事件。以下是部分判断script加载完毕的方法。
js.onload = js.onreadystatechange = function() { if (!this.readyState || this.readyState === ‘loaded‘ || this.readyState === ‘complete‘) { // callback在此处执行 js.onload = js.onreadystatechange = null; }};
(3)利用iframe和location.hash
这个办法比较绕,但是可以解决完全跨域情况下的脚步置换问题。原理是利用location.hash来进行传值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash,改变hash并不会导致页面刷新,所以可 以利用hash值来进行数据传递,当然数据容量是有限的。假设域名a.com下的文件cs1.html要和cnblogs.com域名下的 cs2.html传递信息,cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的 cs2.html页面,这时的hash值可以做参数传递用。cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe;Firefox可以修改)。同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一点有变化则获取获取hash值。代码如下:
先是a.com下的文件cs1.html文件:
function startRequest(){ var ifr = document.createElement(‘iframe‘); ifr.style.display = ‘none‘; ifr.src = http://www.mamicode.com/‘http://www.cnblogs.com/lab/cscript/cs2.html#paramdo‘;>
cnblogs.com域名下的cs2.html:
//模拟一个简单的参数处理操作switch(location.hash){ case ‘#paramdo‘: callBack(); break; case ‘#paramset‘: //do something…… break;}function callBack(){ try { parent.location.hash = ‘somedata‘; } catch (e) { // ie、chrome的安全机制无法修改parent.location.hash, // 所以要利用一个中间的cnblogs域下的代理iframe var ifrproxy = document.createElement(‘iframe‘); ifrproxy.style.display = ‘none‘; ifrproxy.src = http://www.mamicode.com/‘http://a.com/test/cscript/cs3.html#somedata‘; // 注意该文件在"a.com"域下 document.body.appendChild(ifrproxy); }}
a.com下的域名cs3.html
//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值parent.parent.location.hash = self.location.hash.substring(1);
当然这样做也存在很多缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等……
(4)window.name实现的跨域数据传输
有三个页面:
a.com/app.html:应用页面。
a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。
b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。
实现起来基本步骤如下:
在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:
<script type="text/javascript">
window.name = ‘I was there!‘; // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右 //格式可以自定义,如json、字符串
</script>
在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,所以可以相互通信)。app.html部分代码如下:
<script type="text/javascript">
var state = 0,
iframe = document.createElement(‘iframe‘),
loadfn = function() {
if (state === 1) {
var data = http://www.mamicode.com/iframe.contentWindow.name; // 读取数据
alert(data); //弹出‘I was there!‘
} else if (state === 0) {
state = 1;
iframe.contentWindow.location = "http://a.com/proxy.html";// 设置的代理文件
}
};
iframe.src = http://www.mamicode.com/‘http://b.com/data.html‘;
if (iframe.attachEvent) {
iframe.attachEvent(‘onload‘, loadfn);
} else {
iframe.onload = loadfn;
}
document.body.appendChild(iframe);
</script>
获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)。
<script type="text/javascript">
iframe.contentWindow.document.write(‘‘);
iframe.contentWindow.close();
document.body.removeChild(iframe);
</script>
总结起来即:iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
(5)使用HTML5 postMessage
HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。 下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。
- otherWindow.postMessage(message, targetOrigin);
- otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制
a.com/index.html中的代码:
<iframe id="ifr" src="http://www.mamicode.com/b.com/index.html"></iframe><script type="text/javascript">window.onload = function() { var ifr = document.getElementById(‘ifr‘); var targetOrigin = ‘http://b.com‘; // 若写成‘http://b.com/c/proxy.html‘效果一样 // 若写成‘http://c.com‘就不会执行postMessage了 ifr.contentWindow.postMessage(‘I was there!‘, targetOrigin);};</script>
b.com/index.html中的代码:
<script type="text/javascript"> window.addEventListener(‘message‘, function(event){ // 通过origin属性判断消息来源地址 if (event.origin == ‘http://a.com‘) { alert(event.data); // 弹出"I was there!" alert(event.source); // 对a.com、index.html中window对象的引用 // 但由于同源策略,这里event.source不可以访问window对象 } }, false);</script>
(6)利用flash
这是从YUI3的IO组件中看到的办法,具体可见http://developer.yahoo.com/yui/3/io/。
可以看在Adobe Developer Connection看到更多的跨域代理文件规范:ross-Domain Policy File Specifications、HTTP Headers Blacklist。
4、Jquery最核心的部分是什么?
答:Jquery选择器
5、冒泡排序、快速排序、选择排序、堆排序、插入排序各写一例?说说冒泡排序和快速排序的核心思想
答:假设以下都是从小到大排序:
1、冒泡排序(稳定排序)
个人理解:冒泡排序就是两个循环,大循环套小循环,从头或者尾部开始比较连续的两个元素的大小,如果不符合自己的排序标准(由小到大,或由大到小),则交换其值。
function bubble_sort($array){
$count=count($array);
for($i=0;$i<$count;$i++){
for($j=$count-1;$j>$i;$j--){
if($array[$j]<$array[$j-1]){//如果后面的值小于前面的元素,则交换值
$temp=$array[$j];
$array[$j]=$array[$j-1];
$array[$j-1]=$temp;
}
}
}
}
2、快速排序(又称数组排序)(不稳定排序)
个人理解:在要排序的数组中找一个关键数据(标准值),通常把数组的第一个元素当成关键数据,然后循环数组,从第二个元素开始依次将元素值与关键数据进行比较,如果小于关键数据,就把该元素放在关键值左边,如果答应关键数据,就把该元素放在关键数据右边,将关键值左边元素存成数组,右边元素也存成数组,再分别进行以上排序,得到的数组与关键数据合并数组后就排序成功
function quick_sort($array){
$count=count($array);
if($count<=1) retrun $array; //如果数组只有一个元素或为空,则直接返回数组,不用排序了
$key=$array[0]; //将数组第一个元素设置为关键数据
$left_arr=array();
$right_ar=array();
for($i=1;$i<$count;$i++){
if($array[$i]<=$key)
$left_arr[]=$array[$i];
else
$right_arr[]=$array[$i];
}
$left_arr=quick_sort($left_arr);
$right_arr=quick_sort($right_arr);
//返回合并后的数组
return array_merge($left_arr,array($key),$right_arr);
}
3、选择排序(不稳定排序)
个人理解:选择排序就是在要排序的数组中选出最小值与第一个元素交换值,然后再剩下的元素中选出最小值与第二个元素交换值,如此循环到倒数第二个元素和最后一个元素比较为止。
function select_sort($array){
$count=count($array);
if($count<=1) return $array;
for($i=0;$i<$count-1;$i++){
$min=$array[$i]; //假设当前元素为数最小,比较后再调整
for($j=$i+1;$j<$count;$j++){
if($array[$j]<$min){
$min=$array[$j];
$key=$j; //将此时值最小的元素的键名记下,
}
}
if($min!=$array[$i]){ //如果min在循环中改变了,就需要交换数据
$temp=$array[$i];
$array[$i]=$array[$key];
$array[$key]=$temp;
}
}
}其他的排序以后再说吧
略
6、当前的web应用程序的网络协议都有哪些?
答:HTTP(超文本传输协议)、TCP/IP(传输控制协议/网络互联协议)、SMTP(邮件传输协议)、POP3(邮局协议第三版)、FTP(文件传输协议)等等
7、谈谈session和cookie的概念?并说说其各自的实现原理
8、nginx是什么?与linux的区别?
答:nginx(发音同 engine x)一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少,并发能力强,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。linux是一种操作系统,两个根本不属同一类
9、jsonp和json有什么区别
答:JSON(JavaScript Object Notation)是Douglas Crockford提出的。他是一个轻量级的数据交换格式,基于JavaScript对象字面量。
使用JSON的优点在于:
(1) 比XML轻了很多,没有那么多冗余的东西
(2)JSON也是具有很好的可读性的,但是通常返回的都是压缩过后的。不像XML这样的浏览器可以直接显示,浏览器对于JSON的格式化的显示就需要借助一些插件了
(3)在JavaScript中处理JSON很简单
(4)其他语言例如PHP对于JSON的支持也不错
JSON也有一些劣势:
(1) JSON在服务端语言的支持不像XML那么广泛,不过JSON.org上提供很多语言的库
(2) 如果你使用eval()来解析的话,会容易出现安全问题
尽管如此,JSON的优点还是很明显的。他是Ajax数据交互的很理想的数据格式。
JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问
区别:JSON没有实现跨域,JSONP可以实现跨域
10、谈谈tinyint int smallint mediumint的 字节数 和长度范围
答:类型 字节 最小值(带符号/无符号) 最大值(带符号/无符号)
TINYINT 1 -128 / 0 127 / 255
SMALLINT 2 -32768 / 0 32767 / 65535
MEDIUMINT 3 -8388608 / 0 8388607 / 16777215
int 4 -2147483648 / 0 2147483647 / 4294967295
11、说说对面向对象的理解?
答:面对对象就是: 把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。
面向对象有三个特征:继承、封装、多态
12、varchar和char的区别,各能存多少字节?
答:char(n) 定长 索引效率高 程序里面使用trim去除多余的空白 ,n 必须是一个介于 1 和 8,000 之间的数值,存储大小为 n 个字节
varchar(n) 变长 效率没char高 灵活 ,n 必须是一个介于 1 和 8,000 之间的数值。存储大小为输入数据的字节的实际长度,而不是 n 个字节
13、一个汉字在utf-8编码下占多少字节?
答:3个字节,用mb_strlen($str,‘utf8‘)函数可以测试出,一个汉字在gbk编码下占两个字节
14、说说mysql 水平分区和垂直分区?
答:数据库分区: 数据库分区是一种物理数据库设计技术,DBA和数据库建模人员对其相当熟悉。虽然分区技术可以实现很多效果, 但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。
水平分区,垂直分区
分区主要有两种形式:这里一定要注意行和列的概念(row是行,column是列)
水平分区(Horizontal Partitioning)
这种形式分区是对表的行进行分区,通过这样的方式不同分组里面的物理列分割的数据集得以组合,从而进行个体分割(单分区)或集体分割(1个或多个分区)。
所有在表中定义的列在每个数据集中都能找到,所以表的特性依然得以保持。
举个简单例子:一个包含十年发票记录的表可以被分区为十个不同的分区,每个分区包含的是其中一年的记录。
一定要通过某个属性列来分割,譬如这里使用的列就是年份
垂直分区(Vertical Partitioning)
这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应的行。
举个简单例子:一个包含了大text和BLOB列的表,这些text和BLOB列又不经常被访问,这时候就要把这些不经常使用的text和BLOB了划分到另一个分区,
在保证它们数据相关性的同时还能提高访问速度。
15、谈谈你对memcache的了解?
答:memcached 是高效、快速的分布式内存对象缓存系统 ,通过在内存里维护一个统一的巨大的Hash表,能够用来存储各种格式的数据。主要用于加速 WEB 动态应用程序。
工作原理:首先 memcached 是以守护程序方式运行于一个或多个服务器中,随时接受客户端的连接操作,客户端可以由各种语言编写,目前已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客户端在与 memcached 服务建立连接之后,接下来的事情就是存取对象了,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到 memcached 中的对象实际上是放置内存中的,并不是保存在 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。注意,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。
16、有一只猴子,旁边有100根香蕉,他离家有50米远,每次只能搬50根香蕉,不然就会被压死,每走一米就要吃掉一根,问最多能将几根香蕉搬回家?
答:16根.
问题简化成走最短的路,背更多的水果.但路和水果之间有限制! 题目已经限制,猴子最多背50,我们计算其消耗仅剩下50根的米处,
假设猴子第一次背了50根,走了X米,在回来搬第2个50根,就有:
100-3X ......... 剩下的香蕉数(先走X,往反2X)
50-X ............ 剩下的米处
问题就明白了:
(100-3X)-(50-X)=50-2X ........回到家时的香蕉数
问题就简化为在条件: (100-3X)<=50的情况下,求
(50-2X)的最大值!
得到: X=17时, 50-2X 最大值 16
17、dir/upload.image.jpg请写出至少五种以上方法,获取文件类型,必须使用php内置函数,可以封装成方法,方法不能明显重复。
答:$file = "dir/upload.image.jpg";
第一种:
function getTypeOne($filename){
if(empty($filename)) return false;
$arr = array();
$arr = explode(‘.‘,$filename);
return $arr[count($arr)-1];
}
echo getTypeOne($file);
第二种:
function getTypeTwo($filename){
if(empty($filename)) return false;
return str_replace(‘.‘,‘‘,strrchr($filename,‘.‘));//strrchr() 函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。如果成失败,否则返回 false
}
echo getTypeTwo($file);
第三种:
function getTypeThree($filename){
if(empty($filename)) return false;
//substr()截取字符串函数
//strrchr() 函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。如果成失败,否则返回 false
return substr(strrchr($filename,‘.‘),1);
}
echo getTypeThree($file);
第四种://end — 将数组的内部指针指向最后一个单元
echo end(explode(‘.‘,$str));
第五种:
//pathinfo — 返回文件路径的信息
$file = pathinfo($str);
echo $file[‘extension‘];
18、使用索引的好处和坏处都有哪些?
答:如果表上没有索引.在对表进行相关操作时会对表执行表面扫描.表越大,扫描时间越长.主要是扫描时需要顺序的存取数据的每一行.在做简单的查询时索引可以有效地提高速度.
如果在做巨复杂的查询时.表基本上会进行表扫描操作.索引的存贮主要是包含一个索引搜索键值跟一个指向包含该值行的一个指针还有行值.所以索引内存部分比表空间少.使用操作语句时,索取索引时间比表扫描快.
索引也有坏处(小坏处,忽略不计).对一个表进行的INSERT或者是DELETE时 操作都需要对表上的每个索引进行额外的更新,增加了处理时间.单索引跟联合索引对于update 更改索引操作也是如此
19、MySQL_connect和MySQL_pconnect有什么不同?
简单的来说MySQL_pconnect是用来在php与MySQL间建立一条持续连接, 一般php的执行模式是脚本开始执行时初始化所有资源, 脚本运行结束后释放所有资源. 而MySQL_pconnect的方式则不这样, MySQL_connect每次都是重新通过tcp 或者unix domian socket跟sql服务器建立关系, 每次握手都是要消耗不少服务器资源的.
使用pconnect时, 有请求连接MySQL时, php会检查是否之前有条相同的连接(以相同的用户名密码连接到同一个MySQL服务器)已经建立, 如果有的话就直接使用这条连接, 值得注意的是这个相同的连接的概念是对进程来说的, 不同的进程call MySQL_pconnect建立会建立起多条连接.
connect与pconnect不会带来功能的差异, 只有性能上的差别.
一般php有俩种运行模式, 一是作为cgi运行, 二是作为apache的模块运行. 作为cgi的时候connect跟pconnect没什么不同, 因为每次cgi进行运行结束后都会被销毁清理掉资源.
php作为apache模块方式运行时, 可以使用到数据库持续连接, 但可能会存在潜在的问题, 这也是哥哥回答的一点.
假设MySQL服务器被配置为最大支持10个并发. 而apache被配置为使用100个子进程.
apache由一个父进程来协调将收到的http request分发给哪个空闲中的子进程处理, 这样很快处理了10个http请求, 假设10个都分配给了不同的子进程, 那末10条跟MySQL间的持久连接就建立了, MySQL的能力已经到了极限.
这时又来了一个http请求, apache将它分给其他的任意不在这10个子进程中的进程, 那末这个进程就没有办法建立到MySQL的连接了, 因为坑位已经满了.
使用持久连接还会有其他方面的问题.
如果在你脚本中使用了持久连接, 又进行了锁表操作的话, 如果到脚本结束也没有去解锁的话. 那么下次再运行这个脚本的话, 它为了获得lock table会在那里无尽地等待过去的它unlock table, 过去的它已经不能回来了, 这里成了个死循环. 除非重启web或者MySQL服务器. 另一个会造成锁定的就是事务了.
避免这个东东的办法可以用register_shutdown_function来注册个回调函数, 在这里面释放表锁定, 或回滚事务.
20、构造函数和析构函数各是什么?他们可以接受参数吗?
构造函数:__construct() 可以接受参数 (是在创建对象实例后自动执行的成员方法)
析构函数:__destruct() 不能带有任何参数 (用来在对象使用结束后释放所使用的计算机资源)
21、php代码:setcookie(‘key‘,‘value‘);print($_COOKIE[‘key‘]);输出结果?
答案:不会输出任何结果,此题考查的是cookie机制的实现原理,这就涉及到cookie数据的移动过程了,Cookie数据按照下面的方式移动:
- 如果你在你的浏览器中输入了web的URL,浏览器会象这个URL的web站点发送请求,比如,你在浏览器中输入一下URL:http: //www.verizon.com,浏览器会将请求发送到Verizon的web服务器,请求它的首页。
- 当浏览器发送请求时,它会查看你机器上跟域名www.verizon.com有关的Cookie文件,如果存在同www.verizon.com有关的 Cookie,浏览器就会把相关的Cookie“键-值”对数据跟请求一起发送到服务器,如果不存在同www.verizon.com有关的 Cookie,则浏览器不发送Cookie到服务器。
- Verizon的web服务器收到Cookies数据和一个页面的Http请求,如果收到了Cookie“键-值”对,Verizon的web服务器将能够使用它们。
- 如果没有收到Cookie“键-值”对,Verizon的web服务器就能知道你以前没有访问过这个站点,服务器建立一个新的用户ID,并在把你所请求的 页面发回到你的浏览器时,把用户ID“键-值”对发送到你的机器,你的硬盘就会驻留了对应这个站点的“键-值”对Cookie。
- web服务器可以在你访问站点时,随时的更改“键-值”对或者加入一个新的“键-值”对。
- 同“键-值”对发送到客户端的还有同这个“键-值”对相关的一些其它信息,其中之一就是Cookie有效期,另一个就是路径(为了在同一个站点的不通部分关联不同的Cookie)。
从以上资料中可以看出,当用户访问题目中代码所在的页面时,客户端浏览器将像web服务器发送请求,根据页面代码,web服务器将会建立一个名为key的cookie值, 只有当用户请求的页面返回到客户端浏览器时才会将key这个cookie值发送到客户端的机器,而在本次web请求时并没有一起发送key这个cookie值(因为客户端机器并不存在key这个cookie的值),所以就输出不了任何东西,只有当客户端浏览器再次向web服务器发送http请求(刷新或跳转到别的页面)时web服务器才能接收到key,才能输出key的值
顺便来一段session的实现与工作原理,因为大家总是把这两种方式放在一起讨论
session的工作流程:当客户端访问服务器时,服务器根据需求设置session,将会话信息保存在服务器上,同时将标示session的session_id传递给客户端浏览器,
浏览器将这个session_id保存在内存中(也可以在php.ini里设置参数将其保存在用户的url中),我们称之为无过期时间的cookie。浏览器关闭后,这个cookie就清掉了,它不会存在用户的cookie临时文件。以后浏览器每次请求都会额外加上这个参数值,再服务器根据这个session_id,就能取得客户端的数据状态。
如果客户端浏览器意外关闭,服务器保存的session数据不是立即释放,此时数据还会存在,只要我们知道那个session_id,就可以继续通过请求获得此session的信息;但是这个时候后台的session还存在,但是session的保存有一个过期
时间,一旦超过规定时间没有客户端请求时,他就会清除这个session。
session的session存储机制,默认的session是保存在files中,即以文件的方式保存session数据
session的实例问题
现有系统A,B; 假设A系统是可以独立运行的web系统,即可以和浏览器直接处理session, B系统是基于mobile的,需要调用A系统的功能接口,
在保持A不改变的情况下,即登陆验证,session存储都不变的情况下,B系统能处理前端用户的请求。
这里提供的方案是使用PHP实现
在用户登陆成功后,将保存的session的session-id返回给B系统,然后B系统每次请求其他接口都带session_id。
A系统在session_start前加上session_id(session_id);
这样B系统就能安全的调用A
22、php代码:
try{
require(‘d:/www/log.txt‘);//已知此文件已被删除
echo ‘yes‘;
}catch{
echo ‘catch‘;
}以上一段代码的输出的结果?
答案:没有任何输出,因为当require包含的文件不存在时,会导致一个致命错误(Fatal error),程序就此终止,不会再往下执行。解释到这里肯定要说一下include包含的文件不存在时产生一个警告(Warning),该语句后面的程序会继续执行。
23、sort(),asort(),ksort()三个函数的区别?
答案:一、一维数组
假设有一个一维数组,如下:
1 | $sortArr = array("name"=>"hiro", "age"=>"23", "city"=>"Shanghai", "code"=>"200051"); |
print_r()输出的原始数组结果为:
1 | Array ( [name] => hiro [age] => 23 [city] => Shanghai [code] => 200051 ) |
1.sort()函数:根据数组下标进行升序排列;print_r()输出的数组结果为(输出时只有数组下标,而不是键名):
1 | Array ( [0] => 23 [1] => 200051 [2] => Shanghai [3] => hiro ) |
2.rsort()函数:与sort()函数相反,根据数组下标进行降序排列;print_r()输出的数组结果为(输出时只有数组下标,而不是键名):
1 | Array ( [0] => hiro [1] => Shanghai [2] => 200051 [3] => 23 ) |
3.asort()函数:根据数组的键名进行升序排列;print_r()输出的数组结果为:
1 | Array ( [age] => 23 [code] => 200051 [city] => Shanghai [name] => hiro ) |
4.arsort()函数:与asort()函数相反,根据数组的键名进行降序排列;print_r()输出的数组结果为:
1 | Array ( [name] => hiro [city] => Shanghai [code] => 200051 [age] => 23 ) |
5.ksort()函数:根据数组的键值进行升序排列;print_r()输出的数组结果为:
1 | Array ( [age] => 23 [city] => Shanghai [code] => 200051 [name] => hiro ) |
6.krsort()函数:与ksort()函数相反,根据数组的键值进行降序排列;print_r()输出的数组结果为:
1 | Array ( [name] => hiro [city] => Shanghai [code] => 200051 [age] => 23 ) |
7.reverse_array()函数:反向当前的数组排列顺序;print_r()输出的数组结果为:
1 | Array ( [name] => hiro [age] => 23 [city] => Shanghai [code] => 200051 ) |
8.shuffle()函数:随机地排列数组顺序(每次刷新后排列的顺序都不相同);print_r()输出的数组结果为(只是其中一种随机排列):
1 | Array ( [0] => 23 [1] => 200051 [2] => Shanghai [3] => hiro ) |
二、二维数组
假设有一个二维数组,如下:
12345 | $person = array( array("hiro", "23", "suzhou"), array("yoyo", "25", "shanghai"), array("janstar", "28", "xinjiang")); |
print_r()输出的原始数组结果为:
1 | Array ( [0] => Array ( [0] => hiro [1] => 23 [2] => suzhou ) [1] => Array ( [0] => yoyo [1] => 25 [2] => shanghai ) [2] => Array ( [0] => janstar [1] => 28 [2] => xinjiang ) ) |
二维数组的排序是根据每维的键名排序的,所以需要额外地编写比较函数。先举三个例子:
1.按每维的第一个元素升序排列,代码如下:
12345678910111213 | function compare0($x, $y) { if($x[0] == $t[0]) { return 0; } elseif ($x[0] < $y[0]) { return -1; } else { return 1; }} usort($person, compare0);echo "按第一个元素正向排序:";print_r($person); |
输出的结果如下:
1 | 按第一个元素正向排序:Array ( [0] => Array ( [0] => hiro [1] => 23 [2] => suzhou ) [1] => Array ( [0] => janstar [1] => 28 [2] => xinjiang ) [2] => Array ( [0] => yoyo [1] => 25 [2] => shanghai ) ) |
2.按每维的第三个元素升序排列,代码如下:
12345678910111213 | function compare2($x, $y) { if($x[2] == $t[2]) { return 0; } elseif ($x[2] < $y[2]) { return -1; } else { return 1; }} usort($person, compare2);echo "按第三个元素正向排序:";print_r($person); |
输出的结果如下:
1 | 按第三个元素正向排序:Array ( [0] => Array ( [0] => yoyo [1] => 25 [2] => shanghai ) [1] => Array ( [0] => hiro [1] => 23 [2] => suzhou ) [2] => Array ( [0] => janstar [1] => 28 [2] => xinjiang ) ) |
3.按每维的第三个元素升序排列,代码如下:
12345678910111213 | function reverse_compare2($x, $y) { if($x[2] == $t[2]) { return 0; } elseif ($x[2] < $y[2]) { return 1; //改变后即可反向 } else { return -1; //改变后即可反向 }} usort($person, reverse_compare2);echo "按第三个元素反向排序:";print_r($person); |
输出的结果如下:
1 | 按第三个元素反向排序:Array ( [0] => Array ( [0] => janstar [1] => 28 [2] => xinjiang ) [1] => Array ( [0] => hiro [1] => 23 [2] => suzhou ) [2] => Array ( [0] => yoyo [1] => 25 [2] => shanghai ) ) |
24、php的垃圾收集机制是怎样的?
答案:“PHP可以自动进行内存管理,清除不再需要的对象。PHP使用了引用计数(reference counting)这种单纯的垃圾回收(garbage collection)机制。每个对象都内含一个引用计数器,每个reference连接到对象,计数器加1。当reference离开生存空间或被设为 NULL,计数器减1。当某个对象的引用计数器为零时,PHP知道你将不再需要使用这个对象,释放其所占的内存空间。
每一种计算机语言都有自己的自动垃圾回收机制,让程序员不必过分关心程序内存分配,php也不例外,但是在面向对象编程(OOP)编程中,有些对象需要显式的销毁;防止程序执行内存溢出。
一、PHP 垃圾回收机制(Garbage Collector 简称GC)
在PHP中,没有任何变量指向这个对象时,这个对象就成为垃圾。PHP会将其在内存中销毁;这是PHP的GC垃圾处理机制,防止内存溢出。
当一个PHP线程结束时,当前占用的所有内存空间都会被销毁,当前程序中所有对象同时被销毁。GC进程一般都跟着每起一个SESSION而开始运行的.gc目的是为了在session文件过期以后自动销毁删除这些文件.
二、__destruct /unset
__destruct() 析构函数,是在垃圾对象被回收时执行。
unset 销毁的是指向对象的变量,而不是这个对象。
三、 Session 与 GC
由于PHP的工作机制,它并没有一个daemon线程来定期的扫描Session信息并判断其是否失效,当 一个有效的请求发生时,PHP 会根据全局变量 session.gc_probability和session.gc_divisor的值,来决定是否启用一个GC, 在默认情况下,session.gc_probability=1, session.gc_divisor =100也就是说有1%的可能性启动GC(也就是说100个请求中只有一个gc会伴随100个中的某个请求而启动).
GC的工作就是扫描所有的Session信息,用当前时间减去session最后修改的时间,同session.gc_maxlifetime参数进行比较,如果生存时间超过gc_maxlifetime(默认24分钟),就将该session删除。
但是,如果你Web服务器有多个站点,多个站点时,GC处理session可能会出现意想不到的结果,原因就是:GC在工作时,并不会区分不同站点的session.
那么这个时候怎么解决呢?
1. 修改session.save_path,或使用session_save_path()让每个站点的session保存到一个专用目录,
2. 提供GC的启动率,自然,GC的启动率提高,系统的性能也会相应减低,不推荐。
3. 在代码中判断当前session的生存时间,利用session_destroy()删除.
25、传值和传引用的区别?
答案:传值的话,如果是非对象,会传一个值的拷贝,对这个变量做任何改动都不影响原值。
传引用或者传对象,是传真实的内存地址,对这个变量做的改动会影响原值。
function func1($a) {
$a = $a + 1;
}
function func2(&$a) {
$a = $a + 1;
}
$sample = 1;
func1($sample);
echo $sample; // 输出 1
$sample = 1;
func2($sample);
echo $sample; // 输出 2
26、求2012-11-11 11:11:11和2012-12-5 12:28:59 两个日期的差数(天数)
方法一:先用strtotime转换成unix时间戳,然后相减,除以一天的秒数86400.
方法二:先用mktime转换成unix时间戳,然后相减,除以一天的秒数86400.
具体代码如下:
方法一:
class Dtime{
function get_days($date1, $date2){
$time1 = strtotime($date1);
$time2 = strtotime($date2);
return abs($time2-$time1)/86400;
}
}
$Dtime = new Dtime;
echo $Dtime->get_days(‘2007-2-5‘, ‘2007-3-6‘);
方法二:
$temp = explode(‘-‘, ‘2007-2-5‘);
$time1 = mktime(0, 0, 0, $temp[1], $temp[2], $temp[0]);
$temp = explode(‘-‘, ‘2007-3-6‘);
$time2 = mktime(0, 0, 0, $temp[1], $temp[2], $temp[0]);
echo ($time2-$time1)/86400;
27、索引分几种?主键和唯一索引的区别?
索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍。
索引的类型:MySQL提供多种索引类型供选择:
(一)普通索引
这是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建:
创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);
创建表的时候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) );
(二)唯一性索引
这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。唯一性索引可以用以下几种方式创建:
创建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);
创建表的时候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表)
);
(三)主键
主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。如果你曾经用过AUTO_INCREMENT类型的列,你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我们也可以通过修改表的方式加入主键,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每个表只能有一个主键。
(四)全文索引
MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。它可以通过CREATE TABLE命令创建,也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见MySQL documentation。
(四)单列索引与多列索引
索引可以是单列索引,也可以是多列索引。下面我们通过具体的例子来说明这两种索引的区别。假设有这样一个people表:
CREATE TABLE people ( peopleid SMALLINT NOT NULL AUTO_INCREMENT, firstname CHAR(50)
NOT NULL, lastname CHAR(50) NOT NULL, age SMALLINT NOT NULL, townid SMALLINT NOT
NULL, PRIMARY KEY (peopleid) );
28、用php正则匹配所有包含index.com域名及所有子域名下的超链接的url
29、静态缓存机制是如何实现的,如何判断静态页面是否过期,静态文件的生成时间怎么保存?
一、可以 根据模板生成静态文件:模版是没有内容的页面,可以是html类型的也可以是php类型的,简单的说就是:1、获取模板的结构代码内容(非内容性的,如html标签等)2、将关键字进行内容替换(把关键字替换为从数据库里面取出来的数据),3、将替换好的内容写入一个新的html页面(fopen、fget、fwrite、fclose)
二、实现即时更新:1、采用计划任务定时更新过期静态文件;2、在数据进行增加、修改和删除操作时重新生成静态页面
静态文件的生成时间无需刻意保存,可根据相应php函数获取:
filemtime
( string filename )
文件上次被修改的时间,出错时返回 FALSE。时间以 Unix 时间戳的方式返回,可用于 返回
date
()。
例如:
$a
=
filemtime
(
"log.txt"
);
echo
"修改时间:"
.
date
(
"Y-m-d H:i:s"
,
$a
);
filectime
( string filename )
返回文件创建的时间,如果出错则返回 FALSE。时间以 Unix 时间戳的方式返回。
例如:
$a
=
filectime
(
"log.txt"
);
echo
"创建时间:"
.
date
(
"Y-m-d H:i:s"
,
$a
);
fileatime
( string filename )
返回文件上次被访问的时间,如果出错则返回 FALSE。时间以 Unix 时间戳的方式返回。
例如:
$a
=
fileatime
(
"log.txt"
);
echo
"修改时间:"
.
date
(
"Y-m-d H:i:s"
,
$a
);
30、已知一个用户评论表comment,包含字段 id,userid,content,instime,四个字段,写出查询所有用户的最后评论时间和用户id的sql语句
SELECT id,userid,instime FROM `comment` c WHERE c.instime=(SELECT MAX(instime) FROM `comment` WHERE userid = c.userid ) ORDER BY id;
转载 遇到过的一些php笔试题