存档

‘php函数’ 分类的存档

24

如何适当提高谷歌广告点击率和单价之二:
2、用户体验

不管在什么地方都会有人谈用户体验,而要有一个高的广告价格用户体验也相当重要。最简单的方式就是把自己也当作一个访问者,会不会对自己做的站点有兴趣,用 户体验的优秀程度影响着广告的转换率,所以直接关系到你的广告单价。你要把每个访问你站点的人当作你的赚钱对象,所以你得对他好不要把访问者当作点击机器,那样你会得不偿失的。尽管很多人认为adsense更钟情于新访问者,但是只有一个对你内容有兴趣的访问者才会静下心来阅读你网站的内容,才有机会去发现并点击他感兴趣的广告,你才有钱赚如果你的站仅仅是能通过各种手段获得用户的来访,他们并不在乎你的网站内容,但是会有意无意地点击你的广告,不过他们也会在广告页面打开之前就关闭掉或者根本不看广告的内容,这样你的广告价格就会越来越低。

你可以不奢望用户访问之后还会再来,最起码得让他们有兴趣把他打开的页面看完,这是Google Adsense的最低用户体验。实现这个也不难,把你的页面结构设计得合理一些,颜色搭配和谐一些,网站内容规范一些,信息完整一些,就足够了。同一广告在什么网站上价格最高?是相关性最好的站点。

大部分发布者都有一个误解,认为高价的关键词和高价的广告就能带来高的收入。我们可以这样假设,一个一点击最高价为10美元的汽车发动机广告在你的论文站点上出现一个点击可能也只有1美分。Google的内容定位广告非常强调相关性以及准确匹配。所以当你发现你的站点上出现不相关的英文广告时,就再也不要暗自庆幸了。

3、准确匹配

什么样的内容最能准确匹配?文本内容。Google Adsense最中意的是文本内容,因为那样可以更加方便地获取关键词和匹配广告。Google Adsense的技术一直在改进,目前通过JS投放的广告匹配不受影响,iframe投放可能依然有一些问题。尽量避免大两的图片或者FLASH的页面,这样的页面很难匹配到广告,更不用说准确匹配了Google Adsense的关键词定位也是非常复杂,它会考虑很多因素,包括域名和url的名称、meta的内容和页面的内容,这些都直接影响着你的网页上出现的广告,所以你得注意你网页上的任何一个内容,让他忠实于你的主题。

4、更新和差异更新

更新是一个网站必须的,搜索引擎更喜欢不断更新的站点,除非你的站点评级非常高,否则你比不过那个采集你但是保持更新的站,Google Adsense也一样,很多人的确是在更新并且在不断更新,因为设置采集更新不是一件特别复杂的事情,只是他忽略了一个重大的问题:差异性。做垃圾站除了优化的技巧以外,更重要的是差异性。因为垃圾站最大的缺陷就是内容在互联网上高度重复,而发布者可以通过差异更新来克服这个弱点,如果不再是一个高度重复的内容而是独有的,那么至少在搜索引擎眼里就不再是垃圾站点。  差异更新包括新增内容和编辑之前的内容。简而言之就是让你的信息和他人的不再一样,你可以通过编辑标题,文本内容的结构来实现。这样的工作你需要坚持地做,直到你的很多内容都和互联网上的有差异,然后你的垃圾站就成了一个好站点,Google Adsense会喜欢的差异更新包括新增内容和编辑之前的内容。

简而言之就是让你的信息和他人的不再一样,你可以通过编辑标题,文本内容的结构来实现。这样的工作你需要坚持地做,直到你的很多内容都和互联网上的有差异,然后你的垃圾站就成了一个好站点,Google Adsense会喜欢的。大体的原则差不多就这些,具体的执行情况个人不同所以会有很大的差距。不过我们需要知道没有适合所有人的灵丹妙药,从某种程度上讲广告主的预算一定的情况下,各个站长在努力争取更多的一部分,不会出现所有站长都能赚大钱的情况。如果你发现你努力了但是单价依然很低,那么有可能是其他人比你更加努力或者这些建议并不适合你。你可以访问广告发布者论坛,看看其他人给的一些建议,或许你会有新的启发。另外的一种垃圾站点,通过搜索引擎优化或者其他的方式获得大量的流量,在页面上放置了无数的广告和弹出窗口,甚至有恶意代码和木马程序,应该算是真正的垃圾站了,所以在这里我们就不谈这种类型的站点了。

20

当我们在接受未知客户端提交的数据,由于各客户端的编码不统一,但在我们的服务器端最终只能以一种编码方式来处理,这种情况下就会涉及到一个将接受到的字符转换为特定编码的问题。

这时可能会想到直接用iconv来进行转码,但我们知道,iconv这个函数需要提供的两个参数为输入编码和输出编码,而我们现在根本不知道接受的字符串是什么编码,如果这个时候能得到接收字符是什么编码就好了。
对于这样的问题,一般会有两种解决方案。
方案一:
要客户端提交数据时,指定所提交的编码,这时就需要多给一个用来指定编码的变量。

< ?php
$string = $_GET['charset'] === 'gbk' ? iconv('gbk','utf-8',$_GET['str']) : $_GET['str'];
?>
对于这种情况,如果在没有约定或者我们不能控制客户端的情况下,似乎这种方案使用不是很好。
方案二
直接由服务器端来检测所接收的数据编码。
这种方案当然是最理想了的了,现在问题是怎么检测一个字符的编码吗?对于这种情况,在php里,mb_string这个扩展中的mb_check_encoding提供了我们所需要的功能。
$str = mb_check_encoding($_GET['str'],'gbk') ? iconv('gbk','utf-8',$_GET['str']) : $_GET['str'];
但这需要打开mb_string这个扩展,有些时候可能我们的生产服务器中没有打开这个扩展。对于这种情况,需要自己借助如下函数来判断编码。
以下函数非本人所写
function isGb2312($string) {
 for($i=0; $i 127) {
   if( ($v >= 228) && ($v < = 233) )
   {
    if( ($i+2) >= (strlen($string) - 1)) return true;
    $v1 = ord( $string[$i+1] );
    $v2 = ord( $string[$i+2] );
    if( ($v1 >= 128) && ($v1 < =191) && ($v2 >=128) && ($v2 < = 191) )
     return false;
    else
     return true;
   }
  }
 }
 return true;
}
function isUtf8($string) {
 return preg_match('%^(?:
 [\x09\x0A\x0D\x20-\x7E] # ASCII
 | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
 | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
 | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
 | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
 | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
 )*$%xs', $string);
}
这里我们就可以使以上任何一个函数来实现编码的检测。并将其转换成指定的编码。
$str = isGb2312($_GET['str'],'gbk') ? iconv('gbk','utf-8',$_GET['str']) : $_GET['str'];
更多的精彩请访问 http://www.jxuan.com/

12

最近的一个项目,里面有一个比较大的表单,用户完成它需要很多时间,很多用户花了千辛万苦完成之后,一提交发现SESSION过期,系统退出了,所以引起了研究如何设置SESSION以及保持SESSION在线的需要,下面是一些心得体会。

什么是SESSION?

按照WIKI的解释,SESSION是存在于两个通信设备间的交互信息,在某一时间建立,经过一定的时间后失效。常见的SESSION有:TCP SESSION、WEB SESSION(HTTP SESSION)、LOGIN SESSION等。
根 据OSI模型中,会话实现的位置不同,SESSION主要分为几种,一种是应用层会话,包括WEB SESSION(HTTP SESSION)和telnet远程登录session;会话层实现的,包括Session Initiation Protocol(SIP)和Internet Phone Call;在传输层实现的有TCP SESSION。
本文主要讨论WEB SESSION,其一般有两种:客户端SESSION和服务器端SESSION,后一种最常见的属于Java Beans提供的。

SESSION是做什么的?

在计算机领域,特别是网络方面,SESSION使用的特别广泛,也可以称为是对话(Dialogue)、会话等,一般是指在两个通信设备间存储的状态,有时也发生在用户和计算机之间(Login SESSION)。
区别于无状态的通信,SESSION通常用来存储通信状态,因此通信的双方至少有一方需要存储SESSION的历史记录,从而实现两者间的通信。

SESSION(WEB SESSION)是怎么实现的?

浏览器和服务器之间进行HTTP通信时,通常会包含一个 HTTP Cookie 来标识状态,通常会有一个唯一的 SESSIONID ,SESSION通常记录着用户的一些验证信息和级别。
在 几中编程语言中最常用的Http Session Token是,JSESSIONID(JSP),PHPSESSID(PHP),ASPSESSIONID(ASP),这个标识通常由哈希函数产生,能够 唯一表示这个用户的身份,在服务器和客户端通信时,作为GET或者POST的参数存储在客户端。
SESSION的实现方式通常有两种,服务器端SESSION和客户端SESSION,两种方式各有优缺点。

服 务器端SESSION实现容易并且效率比较高,但是遇到负载均衡或者高可用性需求的时候,处理起来就比较困难,对于那种内生系统不存在存储设备的时候,也 是不可用的。负载均衡可以通过共享文件系统或者强制客户只能登录到一台服务器上来实现,但是这样会降低效率。对于没有存储的设备,也可以通过使用 RAM(参考参考资料6)来解决服务器端SESSION的实现,这种方法这对哪些客户端链接有限的系统有效(诸如路由或者接入点设备)。
客户 端SESSION的使用可以解决服务器端SESSION的一些问题,比如避免了负载均衡的算法等,但是同时也会产生一些自身的问题。客户端SESSION 使用Cookie和加密技术来在不同的请求间保存状态。在每一个动态页面结束后,会统计当前的SESSION,并把它发回客户端。每次成功请求后,会把 cookie再发送到服务器端,来让服务器“记起”这个用户的身份。客户端SESSION最重要的问题就是安全问题,一旦cookie被劫持或者篡改了, 用户的信息的安全性就丧失了。

PHP中如何设置SESSION?

搭建好PHP的开发环境后,通过phpinfo()可以查看到与SESSION有关的部分包括:
SESSION模块,在PHP V5.2.9版本中,一共有25个变量。其中,平时设置中常会用到的几个有:
session.cookie_lifetime 设置存储SESSIONID的cookie过期时间
session.name SESSION的COOKIE名称,默认为PHPSESSID
session.save_handler SESSION的存储方式,默认为FILE
session.save_path Fedora下面默认存储在/var/lib/php/session

session.gc_probability
session.gc_divisor
session.gc_maxlifetime 这三个选项用来处理GC机制发生的机率

session.cache_limiter (nocache,private,private_no_expire,public)
session.cache_expire 这两个选项是用来缓存SESSION的页面

先 来考虑第一个问题,SESSION多久会过期,他是如何过期的?如果要在PHP程序中使用SESSION,一定要先引用session_start(), 这个函数一执行,就会在SESSION的存储目录(如果使用了file handler)生成一个SESSION文件,里面内容是空的,同时浏览器会见里一个name为PHPSESSID的cookie,里面存储着一个 hash出来的SESSION的名字。
SESSION的过期依赖于一个垃圾回收机制(Garbage Collection),SESSION创建后作为一个文件存放在服务器上,客户端脚本每访问一次SESSION中的变量,SESSION文件的访问时间 就会进行更新。每次访问都是根据客户端存储的SESSIONID去请求服务器中存储的唯一的SESSION,当客户端的cookie过期后,就无法知道要 访问的是哪一个SESSION,尽管此时服务器上的SESSION文件还没有被过期收回,这样就会造成服务器资源的浪费。
但是同时,如果我们 希望用户的session马上过期的话,我们就可以通过设置cookie的办法来实现。SESSION的回收是在每次访问页面的时候进行的,回收的机率由 session.gc_probability,session_gc_divisor指定,默认士1/100。如果设置为1,则每次超过了 SESSION的生存周期去访问的话,SESSION一定会被回收。

两种需求:1、保持SESSION不过期或延长SESSION过期时间;2、使SESSION立即过期。
1、 保持SESSION不过期和延长SESSION过期时间非常必要,特别是在内部应用系统中或者有很大的表单的时候。想想你的老板在填写一个表单,刚好碰上 午饭时间,留着这个表单等吃饭回来,填写完剩余的内容,提交后他看到什么,一般来说都是一个登录界面。想要提高用户体验,关键是要让老板的表单不出问题, 我们就必须延长SESSION的生存周期。
保持SESSION不过期和延长SESSION过期时间,可以通过设置 session.gc_maxlifetime来实现,不过首先需要保证客户端的cookie不会在gc执行回收之前失效。通过设置一个较长的 gc_maxlifetime可以实现延长session的生存周期,可是对于不是所有请求都会保持很久的应用来说,这么做对于服务器配置显然不是一个最 佳的选择。
我们知道SESSION的回收机制是根据SESSION文件的最后访问时间来判断的,如果超过了maxlifetime,则根据回收机率进行回收。所以我们只需要定期的去访问一下SESSION就可以了,而这可以通过刷新页面来实现,根据这个思路,解决的方法就有了。
通过JS定期的去访问页面;利用Iframe定期的刷新页面;
直接利用程序发送HTTP请求,这样就可以避免在页面中嵌入其他的元素;

下面是利用JS发送请求实现的保持SESSION不过期的实现方法,这样我们就只需要在需要SESSION保持长时间的页面(比如大表单页面)。
<script type=”text/javascript”>
function keepMeAlive(imgName){
myImg = document.getElementById(imgName);
if(myImg) myImg.src = myImg.src.replace(/\?.*$/, ‘?’ + Math.random());
}

window.setInterval(“keepMeAlive(‘phpImg’);”, 4000);
</script>
<img id=”phpImg” src=”http://www.phpplot.com/phpplot/session/sess_refresh.php?” width=”1″ height=”1″ />
其中URL后加入一个随机数是为了避免这个链接的请求被浏览器缓存。

2、使SESSION立即过期的方法就比较多了,我们可以session_destroy(),也可以用上面的思路,请求一个session_destroy的页面。

SESSION安全吗?

PHP的手册中明确写出:SESSION并不能保证储存在SESSION中的信息一定只能被他的创建者所看到。
如 果想要安全的处理一些远程的操作,那么HTTPS是唯一的选择。最基本的,不要认为一个用户信息在SESSION中存在就认为这个用户一定就是他本人,虽 然SESSION中的信息会给你他已经经过了用户名和密码验证的假象。所以,如果需要做一些修改密码或者类似的事情的时候,让用户重新输入密码是一个比较 好的选择。
早期的Apache版本并没有采用COOKIE的方式来存储PHPSESSID,而是采用的URL-rewrite,也就是每个 URL后面都会加上PHPSESSID=<sessionid>来表明它属于那个激活的SESSION,新版的Apache已经将这个属性设 置为默认关闭。
session.use_trans_id = 0;

所以从这个意义上来讲,延长SESSION的时间过长 或者保持SESSION一直在线对于安全来说始终不是一件好事情。终极的解决办法就是用户提交跳转到登录窗口,登录后又能够回到填写页面,并且所有的数据 都还在。这个的实现方式现在用Ajax来解决应该没什么困难,每隔一定时间就把当前的用户数据POST到一个存储位置,不管是XML或者JSON。

拾遗:

对于客户端不支持JavaScript的情况可以采用的方法:
1、写一个浮层,显示在最顶层,如果用户未禁用JS,则让浮层消失;
2、将所有的INPUT都设置为disable,然后再用JS设置为enabled;
以上这两种方式都是在JS被禁用的时候,所有功能都不能用,如何在JS被禁用的情况下使我们的应用仍然正常工作,这个貌似就比较困难。实现这个的所花的时间和所收到的效果大家要权衡一下。

05

每天都要接触google、百度等搜索引擎,使用的搜索指令也局限在那么少数几个,如sitelink等;其实对于google来说,有些特殊的搜索指令的作用是非常大的,尤其对于研究SEO的朋友,如 In-系列搜索指令:通过intitle/inurl/intext三个搜索指令定义关键词的位置。     其中,学会使用inurl是最重要的一个搜索技巧。 In-系列搜索指令是Google搜索中最重要的位置关键词查找方式,通过intitle/inurl/intext三个搜索指令定义关键词的位置,分别查找在标题、链接、正文包含搜索关键词的网页结果。不过,这三个搜索指令因为字数较长、而且容易混淆,在实际搜索中往往被普通用户所漠视,事实上,对于目标明确的搜索者来说,In-系列搜索指令往往最为简洁,能够大幅简化搜索结果,提高搜索精确度。 inurlIn-系指令中最强大的一个,换句话说,这个高级指令能够直接从网站的URL入手挖掘信息,只要略微了解普通网站的URL格式,就可以极具针对性地找到你所需要的资源——甚至隐藏内容。     用在seo上,inurl起的作用就大多了。     比如,我们大家都知道gov域名的权重都比较高,如果自己的网站能从gov网站弄一些链接的话,对于自身的网站排名是有不小的提高的。     比如,在google中输入 inurl:gov.cn/forum/*register 你就会发现很多gov网站可以添加链接,其他类似的就看你的发现了,不过链接有一个度的问题,过尤不及,链接最好是相关的网站,不然,过多的差质量的网站的链接对于优化的网站来说未必就是一种运气。祸兮福之所倚,福兮祸之所伏。     其他的类似的,大家可以发挥想象,比如:
inurl:gov.cn/forum/*reg
inurl:gov.cn/bbs/*register
inurl:gov.cn/bbs/*reg
inurl:gov.cn/*register
inurl:gov.cn/*reg
inurl:edu.cn/*reg
……

这样的手法其实也不是才有,很多人已经在大肆地使用了,通过上述指令搜索出来的网站,你进入一看就知道已经很多的a,很多的url了。这里有一个风险,这样大量被蹂躏的gov网站导出了大量了垃圾链接,将来某一天,搜索引擎未必不会采取措施来排除这些垃圾链接。祝大家好运。

十一
26

配置错误信息回报的等级。

语法: int error_reporting(int [level]);

返回值: 整数

函数种类: PHP 系统功能

内容说明

本函数用来配置错误信息回报的等级,参数 level 是一个整数的位遮罩 (bitmask),见下表。

遮罩值    表示名称

1    E_ERROR
2    E_WARNING
4    E_PARSE
8    E_NOTICE
16    E_CORE_ERROR
32    E_CORE_WARNING

* E_NOTICE 表示一般情形不记录,只有程序有错误情形时才用到,例如企图存取一个不存在的变量,或是呼叫 stat() 函数检视不存在的文件。
* E_WARNING 通常都会显示出来,但不会中断程序的执行。这对除错很有效。例如:用有问题的正则表达式呼叫 ereg()。
* E_ERROR 通常会显示出来,亦会中断程序执行。意即用这个遮罩无法追查到内存配置或其它的错误。
* E_PARSE 从语法中解析错误。
* E_CORE_ERROR 类似 E_ERROR,但不包括 PHP 核心造成的错误。
* E_CORE_WARNING 类似 E_WARNING,但不包括 PHP 核心错误警告。

十一
26

1. 串行化的基础认识:   是指将一个变量(包括对象)转换成字节流的过程。串行化有效的解决了对象的保存和传输的问题.例如,如果在用session并使用了 session_register() 来注册对象,这些对象会在每个 PHP 页面结束时被自动序列化,并在接下来的每个页面中自动解序列化,这样在每个PHP页面中都可以使用这些对象。PHP为我们提供了两个函数,用来进行串行化和反串行化的操作,这两个函数分别是:serialize()和unserialize()。serialize()可以处理除资源指针之外的所有类型,该函数返回一个可以被存储在任何地点的字节流表达式的字符串。

<?php
//整型
$var = 23;
echo serialize($var).”\n”;    //i:23;

//浮点型
$var = 1.23;
echo serialize($var).”\n”;    //d:1.229999999999999982236431605997495353221893310546875;

//字符串
$var = “This is a string”;
echo serialize($var).”\n”;    //s:16:”This is a string”;

//布尔型
$var = true;
echo serialize($var).”\n”;    //b:1;

//数组变量
$var = array(“abc”, “def”, “xyz”, “123″);
echo serialize($var).”\n”;    //a:4:{i:0;s:3:”abc”;i:1;s:3:”def”;i:2;s:3:”xyz”;i:3;s:3:”123″;}

$var = array(“index1″=>”abc”, “index2″=>”def”, “index3″=>”xyz”, “index4″=>”123″);
echo serialize($var).”\n”;    //a:4:{s:6:”index1″;s:3:”abc”;s:6:”index2″;s:3:”def”;s:6:”index3″;s:3:”xyz”;s:6:”index4″;s:3:”123″;}

//对象序列化
class A
{
public $a = “a string”;
public $b = 123;
public $c = 123.12;
}
$obj = new A;
$str = serialize($obj);
echo $str.”\n”;              //O:1:”A”:3:{s:1:”a”;s:8:”a string”;s:1:”b”;i:123;s:1:”c”;d:123.1200000000000045474735088646411895751953125;}
$obj2 = unserialize($str);   //进行反序列化
var_dump($obj2 == $obj);     //bool(true)
?>

2. 在用 unserialize()时需要注意的一个问题: 在一个PHP页面中要 unserialize() 一个对象,需要该页面包含该对象的类的定义。也就是,如果序列化了 page1.php 中类 A 的对象 $a, 要在 page2.php 中将其反序列化重建类 A 的对象 $a,则 page2.php 中必须要出现类 A 的定义。这可以这样实现,将类 A 的定义放在一个包含文件中,并在 page1.php 和 page2.php 都包含此文件。 所以强烈建议在所有的页面中都包括这些注册的对象的类的定义,即使并不是在所有的页面中都用到了这些类。如果没有这样做,一个对象被反序列化了但却没有其类的定义,它将失去与之关联的类并成为 stdClass 的一个对象而完全没有任何可用的函数。(stdClass是一个空类,里面没有属性也没有方法

var_dump(get_class_methods(stdClass));var_dump(get_class_vars(stdClass));)

//classa.inc:
class A
{
var $one = 1;

function show_one()
{
echo $this->one;
}
}

//page1.php:
include(“classa.inc”);

$a = new A;
$s = serialize($a);
$fp = fopen(“store”, “w”); // 将 $s 存放在某处使 page2.php 能够找到
fputs($fp, $s);
fclose($fp);

//page2.php:
include(“classa.inc”);      // 为了正常解序列化需要这一行

$s = implode(“”, @file(“store”));
$a = unserialize($s);

$a->show_one(); // 现在可以用 $a 对象的 show_one() 函数了

?>

如果以上的例子中 $a 通过运行 session_register(“a”) 成为了会话的一部分,$a会在该PHP 页面结束时被自动序列化,在其他PHP页面中会自动反序列化从而可以使用该对象,那么应该在所有的页面中包含 classa.inc 文件,而不只是 page1.php 和 page2.php。

3.__sleep() __wakeup()

serialize() 检查类中是否有 __sleep() ,如果有,则该函数将在任何序列化之前运行。该函数必须返回一个需要进行序列化保存的成员属性数组,并且只序列化该函数返回的这些成员属性. 该函数有两个作用: 第一. 在序列化之前,关闭对象可能具有的任何数据库连接等. 第二. 指定对象中需要被序列化的成员属性,如果某个属性比较大而不需要储存下来,可以不把它写进__sleep要返回的数组中,这样该属性就不会被序列化

相反地,unserialize() 从字节流中创建了一个对象之后,马上检查是否具有__wakeup 的函数的存在。如果存在,__wakeup 立刻被调用。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

<?php
class User
{
public $name;
public $id;

function __construct()
{
$this->id = uniqid();          //give user a unique ID 赋予一个不同的ID
}

function __sleep()
{
return(array(“name”));        //do not serialize this->id 不串行化id
}

function __wakeup()
{
$this->id = uniqid();         //give user a unique ID
}
}

$u = new User;
$u->name = “HAHA”;

$s = serialize($u);                   //serialize it 串行化 注意不串行化id属性,id的值被抛弃

$u2 = unserialize($s);                //unserialize it 反串行化 id被重新赋值
//$u and $u2 have different IDs $u和$u2有不同的ID
var_dump($u);
var_dump($u2);
?>

———- PHP debug ———-
object(User)#1 (2) {
["name"]=>
string(4) “HAHA”
["id"]=>
string(13) “47fa045529f69″
}
object(User)#2 (2) {
["name"]=>
string(4) “HAHA”
["id"]=>
string(13) “47fa04552a49a”

}
输出完成 (耗时: 0 秒) – 正常终止