在美国Apple Online Store订购iPad的攻略

原创文章,转载请注明出处 http://wuhongsheng.com/

在美国Apple Online Store订购iPad的攻略

文章开篇前,我们先来算个帐:32G Wifi+3G版本的iPad,在淘宝上面销售的均价是人民币7850元。官方售价为美元729,折合人民币4980元。中间奸商赚取差价2870元。

然后我们再算算,从美国购买iPad发国际快递回国内,价格为官方价格729美元+国际快递费用27美元,折合人民币5162元。

足足比淘宝上面便宜了2688元。如果购买两台,那么省下来的钱,足够买第三台了。

相信大家都比我会算数。

当然,也有很多人想到这点了。但是他们没法买。为什么?因为在美国的Apple Online Store购买iPad,必须要有美国的地址。身在国内的人们,运气好的在美国有朋友可以帮忙代购,运气不好就只能干瞪眼。那些找美国朋友的,也会欠下一 个人情,早晚要还。而且现在美国全境大部分的线下商店的iPad都早已脱销了,就算有钱也不一定能买到。最后还是需要在Apple Online Store预定。

OK,我们来总结下在Apple Online Store订购iPad所需要具备的条件吧。

1.一个美国的地址
2.一张支持美元支付的信用卡,国内国外的无所谓,卡上的额度必须要够,为你所购买的iPad价格的2倍。比如购买32G Wifi+3G版本,价格是729美元,那么卡上就必须要够729*2=1458美元(等额10000人民币)。为什么要这么多,我会在后面说明。
3.关税问题
4.足够的耐心,把本文看完,并且可以等待10个工作日的订货周期

我们继续,先解决第一个也是最重要的一个问题,美国的地址。

中华民族的智慧是无穷的,包括身在海外的华人。在遥远的大洋彼岸,有为数众多的,华人开的快递公司,比如AAE。他们除了运营着中美之间的快递业务 外,还提供了一些增值服务,比如为你提供美国地址,然后把美国地址所收到的包裹快递回国内。

看到这里,你就知道,美国地址的问题有解了。

当然,Apple也不是吃素的。由于提供转运服务的快递公司能提供的收件点有限,一个地址被无数人使用,所以是绝对过不了苹果的审核关的。因为 iPad现在的产能严重不足,全球严重缺货,所以苹果使用了机器+人工的方式对地址进行识别。对于同一个地址,一定时间内订购超过2台以上iPad的,就 会被取消订单。

还是那句话,中华民族的智慧是无穷的。

废话说了很多,我们先开始吧。既然是攻略,总要有步骤的。

我们先去gels注册一个帐号。gels是AAE旗下一家专门提供运转服务的公司,他们为不同等级的会员提供美国各个州的收件地址。我们要知道,在 美国买东西,都是有消费税的,每个州的税率都不一样,有些州还免税,比如阿拉斯加、俄勒冈,都是免税的州。gels就提供了两个俄勒冈的收件地址,这样我 们用来购买iPad就不用交税了,可以省下至少7%的消费税。

gels的注册地址(必须要从这个地址注册,而且要在推荐注册人里面留下我的ID,没有推荐人的话你是无法注册成功的): http://url.cn/2038Ab

gels注册完后,你是看不到任何可用的收件地址的。提供运转服务毕竟不是什么光明正大的事情(从推荐注册的方式就能看出来)。你需要先充值一定的 金额,获得相应的会员级别后,才能看到对应级别会员可用的地址。等级越高,可用的地址就越多,而且会有免税州的地址,费用也能更加便宜。充值进去的金额会 被直接充当快递费。如果你不需要用他们的服务了,充值的费用可以退还,但必须要扣人民币50元的手续费。

这里我建议大家直接充值1000块钱升级为白金会员。因为只有这个等级的会员才能拥有免税州的地址,这样购买iPad才能免税。等iPad到手后, 再要求他们把剩余的钱都退回来,也就只需要再付50块钱而已。

OK,这里我假设大家都升级为白金会员了。这时可以在个人页面上看到“美国俄勒冈州GELS仓库(OR)收货地址”,我们就选这个地址吧。但这个地 址不能直接用,还需要单独处理下。

注意!!请不要使用备用地址里面的OR收货地址!!这个地址可能会导致收货失败!!血的教训,不止我一 个人因为寄送到这个地址而导致无法收货!!

然后就是激动人心的下订了。我们打开 http://store.apple.com/us/browse/home/shop_ipad/family/ipad ,选上一款自己心仪的iPad,丢进购物车,然后去结算。

结算页面,首先是填收货地址。要注意的地方来了,我们!!千万!!不能按照gels给的地址原样填上。

首先是为了确保收货人的唯一性,gels给每个会员分配了一个ID,比如ABCDE,这个ID必须要填写到名(First Name)上。如果你这个地方填错了,那么你就收不到货了。切记,这个ID不能填写到别的地方,包括填到姓(Last Name)里面。原创文章http://wuhongsheng.com/

把ID填写到first name里面后,last name就没关系了。我们可以随便乱填,不填你的名字都无所谓,这个不影响收货。比如我们可以在last name里面填上kelwen甚至ungi啥的。但如果万一订单出了问题,你要打国际长途查询,对方要求你的名字,你就要能正确说出来,避免杯具。

接着是Area Code和Primary Phone,这里填写的是电话号码。最好我们直接使用gels给的号码,或者你对自己修改后的地址很有信心,那么可以自己填一个。比如前阵很流行的 Google Voice,注册成功的朋友肯定都搞到了一个美国的电话号码。如果没有,可以把gels给的号码后面四位改改填上去。最后Area Code里面填写电话号码的前三位数字,如503,Primary Phone填写电话号码的后四位,如666-6666。反正这里自己发挥想象力,确保电话号码是一个格式上合法的假号码,或者真号码,都可以。

Email Address和Company Name都可以留空不填

最重要的地方来了,地址填写部分。地址填写一共有两栏,一栏写不下可以写另外一栏。按照gels给的地址,肯定是一栏可以写下的,但我们不能这样 干,否则Apple第一关,电脑自动检查重复地址就过不去了。Apple的程序对地址的自动识别率还是非常高的。原创文章 http://wuhongsheng.com/

我们在这里要做的,就是把地址改为程序识别不出来,但快递员人工又能正常的阅读并且投递。

聪明的小朋友一定想到了,我们加一些无关紧要的话进去不就好了吗?bingo!

比如,我们可以把地址拆成两部分,然后在第一部分的开头加上一些东西,在第二部分结尾也加上一些东西,地址里面的数字改改(当然不是单纯的把 first改为1st这么简单,这样的话程序也是可以识别出来的)。

再说明白一点。比如gels给出来的地址是1 NW 3 ST,那么拆成两部分就是1 NW和3 ST,我们把第一部分改为PLS SHIP TO #1 NW,第二部分改为#3 ST PORTLAND OR,这样就可以了。但我建议大家还是继续发挥自己的想像力,尽量区别开来。

改了地址后,请到http://maps.google.com/,输入修改后的地址,看看google搜索出来的地址是否还是原来的位置。如果 是,那么就没问题。

最难的一部分已经搞定了,后面的Zip Code输入邮编,然后把This is a business address选上,点击Continue保存并且进入到下一步的信用卡信息填写。

信用卡资料填写,大部分的地方都和收件地址一样。但是First Name和Last Name必须要填写你信用卡上面的英文名字。因为信用卡支付要匹配这部分的。所以这里必须要填写真实信息。其余部分照抄收件信息即可。

之后就是Continue,然后苹果会对你的信用卡进行两次1美元的扣款(也有一次的),以确认你的信用卡可用。然后苹果会再扣你所购买的iPad 的金额(比如729美元)。这三次对信用卡的扣款都是预授权形式的。也就是并没有实际进行消费,只对信用卡里面相应的金额做冻结。只有在苹果给你寄出 iPad以后才会正式扣款

只要扣款成功,苹果就会给你显示一个订单概况。但这个概况不代表苹果和你之间的合约已经构成。

说说文章开头提到额度的问题。不知道是因为国内信用卡在苹果上面走的通道有问题,还是其他原因。我的几张信用卡(中行和招行)在苹果寄出iPad后 正式扣款的时候,并没有对原先做的预授权进行完成预授权,而是重新扣了一次同样额度的刷卡消费。这样造成的后果是,产生了两笔同样金额的消费,但只有后面 一笔是刷卡消费,前面一笔仍然是预授权冻结的状态。所以造成了我中行的卡上没有留下足够的额度,造成苹果扣款失败。之后打了中行的电话要求临时提额,并且 打了一个国际长途用我蹩脚的英语找苹果的人给重新扣款,但最后还是因为成功扣款太晚,fedex没收到扣款后的结果,最后把我这个订单给退回了苹果的回收 站ELK GROVE, CA,导致购买失败。原创文章http://wuhongsheng.com/

所以为了保险,建议大家一定要在卡上留有足够的额度,以防出现意外的情况。

继续回到刚才的流程。支付后,在苹果销售部门正常上班的情况下,你会在一个小时内收到苹果发来的一封名为“Order Acknowledgement”的邮件。收到这封邮件表明苹果已经收到你的订单和付款,并且订单已经通过了初步的审核。同样,这封邮件也不会构成苹果和 你之间的任何合约,苹果一样能随时取消你的订单。

之后的时间就是看人品了。在订单提交成功的3个工作日内,苹果会有人工对订单进行复审。只要在3个工作日内你没收到苹果发来的,标题为 “Action Required”的邮件,那么恭喜你,你的订单基本上已经成功,并且已经提交到富士康进行生产了。之后你会有两个星期的漫长等待,中间你不会收到任何苹 果发来的邮件,就跟石沉大海一样。在后台查询订单的状态都是 Not yet shipped 原创文章http://wuhongsheng.com/

在9-10个工作日左右,登录Apple Online Store查询订单的Status,订单状态会变为 Prepared for Shipment,在这个状态下,就是iPad生产好,准备从富士康发货了。一般会在1-2天内从富士康通过fedex发到美国。

所有发出来的iPad,都是先从深圳,过关到香港,然后从香港空运到美国,之后在美国中转几次,最后送到gels的地址。

gels在签收后,会对货物统一整理,然后到他们的大仓库。这个时候在gels的网站就可以对货物进行操作了。在gels上面提交运单,等上几 天,iPad就会原包送到你手上。因为没有你的允许,gels是不会拆开包裹的。他们寄送的时候,会在原有的fedex包装上面重新打包一层寄给你。真正 做到了原包未拆封。原创文章http://wuhongsheng.com/

OK!整个购买iPad的攻略就到此为止。如果你不再需要gels的帐号,可以联系他们的客服要求退回余额。

最后说说关税,一般情况下,你需要如实申报寄送的物品,但是否需要交关税主要看海关抽查,运气不好被抽上的话,只要属于正常的自用范围,是不需要征 税的。如果超出范围,那么一台iPad需要交600-1000的关税。但就算要缴税,也比淘宝上面买的便宜1000多。

Firefox升级后cookie失效(丢失)的终极解决方案

每次升级Firefox,一些论坛的Cookie就会失效,需要重新登录。这是因为,很多论坛的Cookie是绑定User Agent的,一旦User Agent改变(Firefox每次升级,User Agent就会改变),Cookie就会失效。这个问题,可以通过固定Firefox的User Agent的方法解决这个问题,方法如下:
在地址栏输入 about:config 回车,然后在下面的窗口点击鼠标右键,选择“新建”->“字符串”,出来的对 话框中输入

general.useragent.override

,按确定后,会让你输入刚才那个选项的值,也就是你 要设定的User Agent。比如,我的系统是Windows 2003,Firefox 是3.0b2pre,我指定的User Agent是:

Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9) Gecko/Firefox/3.0

如果你用的是Firefox 2.0.0.x系列,Windows是XP,那么可以设成:

Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1) Gecko/Firefox/2.0

这个修改立刻生效,从About对话框中就可以看的 出来。设定完后,可以到下面这个网页查看自己的 User Agent 设置的是否正确: http://www.useragentstring.com/

当然,做了上面的设定以后,因为User Agent改变了,所有绑定 User Agent 的论坛,都会要求你重新登录一次。不过,只要重新登录一次后,以后升级Firefox时就不用再登录了(除非你将原来的配置文件夹删除),cookie会 一直有效,直到真的过期为止。

扩展php的异常处理类

使用PHP编程时,虽然可以跟踪异常的路线,但是在实际应用中需要使用不同的异常处理类处理不同的异常。 所以,我们就有必要写一个PHP扩展异常处理类了。

例如:

<?php
class FileExists extends Exception
{
//文件不存在异常
}
class FileOpen extends Exception
{
 //文件不能打开异常
}
$path = "E://www.phpdo.net";
try
{
 open_file($path);
}
catch(FileExists $e)
{
 echo "程序运行异常: ".$e->getMessage()."\n";
}
catch(FileOpen $e)
{
 echo "程序运行异常,".$e->getMessage()."\n";
}
catch(Exception $e)
{
 echo "不可预知的异常";
 echo "异常信息:".$e->getMessage()."\n";
 echo "异常代码:".$e->getCode()."\n";
 echo "文件名:".$e->getFile()."\n";
 echo "异常代码所在的行".$e->getLine()."\n";
 echo "异常信息传递路线:";
 print_r($e->getTrace()); //返回数组形式的传递路线
 echo $e->getTraceAsString(); //返回字符串形式的传递路线
}

function open_file($path)
{
 if(!file_exists($path))
 {
 //抛出FileExists异常
 throw new FileExists("www.php.net不存在",1);
 }
 if(!fopen("$path",r))
 {
 //抛出FileOpen异常
 throw new FileOpen("www.php.net无法打开",2);
 }
}
?>

结果:
程序运行异常: http://www.php.net/不存在
php扩展异常处理类时需要注意的是: 捕获特定异常时,还需要捕获Exception类,用于处理未捕获的异常; 捕获异常时,需要按照顺序从上向下捕获(如果先捕获Exception类,则会导致异常不能被正确的代码处理,例如将“catch(Exception $e)“语句放到“catch(FileExists $e)”之前,会发生什么?)所以在设定时,需要将特定异常的catch语句写在前面,将一般的Exception语句写在最后。
根据这个例子,我们能看出使用php扩展异常处理类的优点是什么呢?
可自定义扩展类; 根据不同的异常做出不同的反应;提高代码的可读性,使得不同的异常容易被区分 。

探究PHP底层运行机制

本文详细讲解了PHP底层的运行机制,包括PHP内容的运作并结合实例讲解了PHP从启动到停止的整个生命周期。

简介
我们从未手动开启过PHP的相关进程,它是随着Apache的启动而运行的;PHP通过mod_php5.so模块和Apache相连(具体说来是SAPI,即服务器应用程序编程接口);
PHP总共有三个模块:内核、Zend引擎、以及扩展层; PHP内核用来处理请求、文件流、错误处理等相关操作; Zend引擎(ZE)用以将源文件转换成机器语言,然后在虚拟机上运行它; 扩展层是一组函数、类库和流,PHP使用它们来执行一些特定的操作。比如,我们需要mysql扩展来连接MySQL数据库; 当ZE执行程序时可能会需要连接若干扩展,这时ZE将控制权交给扩展,等处理完特定任务后再返还;
最后,ZE将程序运行结果返回给PHP内核,它再将结果传送给SAPI层,最终输出到浏览器上。
深入探讨
真是的内部运行过程没有这么简单。以上过程只是个简略版,让我们再深入挖掘一下,看看幕后还发生了些什么。
◆Apache启动后,PHP解释程序也随之启动;
◆PHP的启动过程有两步:
第一步是初始化一些环境变量,这将在整个SAPI生命周期中发生作用;
第二步是生成只针对当前请求的一些变量设置。

PHP启动第一步
不清楚什么第一第二步是什么?别担心,我们接下来详细讨论一下。让我们先看看第一步,也是最主要的一步。要记住的是,第一步的操作在任何请求到达之前就发生了。
启动Apache后,PHP解释程序也随之启动;

PHP调用各个扩展的MINIT方法,从而使这些扩展切换到可用状态。看看php.ini文件里打开了哪些扩展吧; MINIT的意思是“模块初始化”。各个模块都定义了一组函数、类库等用以处理其他请求。
一个典型的MINIT方法如下:
PHP_MINIT_FUNCTION(extension_name){ /* Initialize functions, classes etc */ }
PHP启动第二步
当一个页面请求发生时,SAPI层将控制权交给PHP层。于是PHP设置了用于回复本次请求所需的环境变量。同时,它还建立一个变量表,用来存放执行过程中产生的变量名和值。

PHP调用各个模块的RINIT方法,即“请求初始化”。一个经典的例子是Session模块的RINIT,如果在php.ini中启用了Session模块,那在调用该模块的RINIT时就会初始化$_SESSION变量,并将相关内容读入;

RINIT方法可以看作是一个准备过程,在程序执行之间就会自动启动。
一个典型的RINIT方法如下:
PHP_RINIT_FUNCTION(extension_name) { /* Initialize session variables,
pre-populate variables,
redefine global variables etc */ }
PHP关闭第一步
如同PHP启动一样,PHP的关闭也分两步:
一旦页面执行完毕(无论是执行到了文件末尾还是用exit或die函数中止),PHP就会启动清理程序。它会按顺序调用各个模块的RSHUTDOWN方法。
RSHUTDOWN用以清除程序运行时产生的符号表,也就是对每个变量调用unset函数。
一个典型的RSHUTDOWN方法如下:
PHP_RSHUTDOWN_FUNCTION(extension_name) { /* Do memory management,
unset all variables used in the last PHP call etc */ }
PHP关闭第二步
最后,所有的请求都已处理完毕,SAPI也准备关闭了,PHP开始执行第二步:
PHP调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会。
一个典型的RSHUTDOWN方法如下:
PHP_MSHUTDOWN_FUNCTION(extension_name) { /* Free handlers and persistent memory etc */ }
这样,整个PHP生命周期就结束了。要注意的是,只有在服务器没有请求的情况下才会执行“启动第一步”和“关闭第二步”。

原文地址:http://cn1997.blog.163.com/blog/static/49155474201042494823590/

PHP中session失效和不传递的解决办法

有很多人发现这个问题,为什么他写的session不能传递到下一个页面去。总结一下,一般有两种情况:

我们先写个php文件:<?=phpinfo()?>, 传到服务器去看看服务器的参数配置。

转到session部分,看到session.use_trans_sid参数被设为了零。

这个参数指定了是否启用透明SID支持,即session是否随着URL传递。我个人的理解是,一旦这个参数被设为0,那么每个URL都会启一个session。这样后面页面就无法追踪得到前面一个页面的session,也就是我们所说的无法传递。两个页面在服务器端生成了两个session文件,且无关联。(不知道这样理解对不对?请高手指教。)

所以一个办法是在配置文件php.ini里把session.use_trans_sid的值改成1。

当然我们知道,不是谁都有权限去改php的配置的,那么还有什么间接的解决办法呢?

下面就用两个实例来说明吧:

文件1 t1.php

<?php
//表明是使用用户ID为标识的session
session_id(SID);
//启动session
session_start();
//将session的name赋值为junstyle
$_SESSION['name']="junstyle";
//输出session,并设置超链接到第二页t2.php
echo "<a href=\"t2.php\">".$_SESSION['name']."</a>";
?>

文件2: t2.php


<?php
表明是使用用户ID为标识的session
session_id(SID);
//启动session
session_start();
//输出t1.php中传递的session。
echo "This is ".$_SESSION['name'];
?>

所以,重点是在session_start();前加上session_id(SID);,这样页面转换时,服务器使用的是用户保存在服务器session文件夹里的session,解决了传递的问题。

第二个可能的原因是对服务器保存session的文件夹没有读取的权限,还是回到phpinfo.php中,查看session保存的地址:

session.save_path: var/tmp

所以就是检查下var/tmp文件夹是否可写。

写一个文件:t3.php来测试一下:


<?
echo var_dump(is_writeable(ini_get("session.save_path")));
?>

如果返回bool(false),证明文件夹写权限被限制了,那就换个文件夹咯,在你编写的网页里加入:

//设置当前目录下session子文件夹为session保存路径。
$sessSavePath = dirname(__FILE__).'/session/';
//如果新路径可读可写(可通过FTP上变更文件夹属性为777实现),则让该路径生效。
if(is_writeable($sessSavePath) && is_readable($sessSavePath))
{session_save_path($sessSavePath);}

大功告成,希望对你有帮助。

http://havi.blogbus.com/logs/64083922.html

IE6下margin的大小为双倍的解决方法

此问题为IE6下的double margin bug,当一个用float浮动的元素,再设定margin的时候,IE6会把该值渲染为双倍大小。
例如CSS:

float:left;margin-left:100px;

IE6会将margin-left显示成200px;

测试代码如下:

<html>
<head>
<title>test margin with float in IE 6</title>
<style type="text/css">
body{margin:0;padding:0;}
div{margin-bottom:20px;}
.dflml,.dfrmr{width:200px;height:200px;}
.dflml{float:left;margin-left:100px;background-color:#DDD;}
.dfrmr{float:right;margin-right:100px;background-color:#CCC;}
.hk{_display:inline;background-color:red;}
</style>
</head>

<body>
<div>
 <div>float left and margin-left 100px</div>
 <div>float right and margin-right 100px</div>
</div>
<div>
 <div>float left and margin-left 100px <strong>with hack</strong></div>
 <div>float right and margin-right 100px <strong>with hack</strong></div>
</div>
</body>
</html>

将上述代码复制,另存为“test.html”,双击运行即可见到效果;

此Bug的解决方法:

给浮动元素添加“display:inline”的css样式或者直接设置margin为一半的值(如:_margin-left:5px;)即可。

PHP session有效期探讨

PHP中的session有效期默认是1440秒(24分钟)【weiweiok 注:php5里默认的是180分】,也就是说,客户端超过24分钟没有刷新,当前session就会失效。很明显,这是不能满足需要的。
一个已知管用的方法是,使用session_set_save_handler,接管所有的session管理工作,一般是把session信息存储到数据库,这样可以通过SQL语句来删除所有过期的session,精确地控制session的有效期。这也是基于PHP的大型网站常用的方法。但是,一般的小型网站,似乎没有必要这么劳师动众。
但是一般的Session的生命期有限,如果用户关闭了浏览器,就不能保存Session的变量了!那么怎么样可以实现Session的永久生命期呢?
大家知道,Session储存在服务器端,根据客户端提供的SessionID来得到这个用户的文件,然后读取文件,取得变量的值,SessionID可以使用客户端的Cookie或者Http1.1协议的Query_String(就是访问的URL的“?”后面的部分)来传送给服务器,然后服务器读取Session的目录……
要实现Session的永久生命期,首先需要了解一下php.ini关于Session的相关设置(打开php.ini文件,在“[Session]”部分):
1、session.use_cookies:默认的值是“1”,代表SessionID使用Cookie来传递,反之就是使用Query_String来传递;
2、session.name:这个就是SessionID储存的变量名称,可能是Cookie,也可能是Query_String来传递,默认值是“PHPSESSID”;
3、session.cookie_lifetime:这个代表SessionID在客户端Cookie储存的时间,默认是0,代表浏览器一关闭SessionID就作废……就是因为这个所以Session不能永久使用!
4、session.gc_maxlifetime:这个是Session数据在服务器端储存的时间,如果超过这个时间,那么Session数据就自动删除!
还有很多的设置,不过和本文相关的就是这些了,下面开始讲使用永久Session的原理和步骤。
前面说过,服务器通过SessionID来读取Session的数据,但是一般浏览器传送的SessionID在浏览器关闭后就没有了,那么我们只需要人为的设置SessionID并且保存下来,不就可以……
如果你拥有服务器的操作权限,那么设置这个非常非常的简单,只是需要进行如下的步骤:
1、把“session.use_cookies”设置为1,打开Cookie储存SessionID,不过默认就是1,一般不用修改;
2、把“session.cookie_lifetime”改为正无穷(当然没有正无穷的参数,不过999999999和正无穷也没有什么区别);
3、把“session.gc_maxlifetime”设置为和“session.cookie_lifetime”一样的时间;
在PHP的文档中明确指出,设定session有效期的参数是session.gc_maxlifetime。可以在php.ini文件中,或者通过ini_set()函数来修改这一参数。问题在于,经过多次测试,修改这个参数基本不起作用,session有效期仍然保持24分钟的默认值。
由于PHP的工作机制,它并没有一个daemon线程,来定时地扫描session信息并判断其是否失效。当一个有效请求发生时,PHP会根据全局变量session.gc_probability/session.gc_divisor(同样可以通过php.ini或者ini_set()函数来修改)的值,来决定是否启动一个GC(Garbage Collector)。
默认情况下,session.gc_probability = 1,session.gc_divisor =100,也就是说有1%的可能性会启动GC。GC的工作,就是扫描所有的session信息,用当前时间减去session的最后修改时间(modified date),同session.gc_maxlifetime参数进行比较,如果生存时间已经超过gc_maxlifetime,就把该session删除。
到此为止,工作一切正常。那为什么会发生gc_maxlifetime无效的情况呢?
在默认情况下,session信息会以文本文件的形式,被保存在系统的临时文件目录中。在Linux下,这一路径通常为\tmp,在 Windows下通常为C:\Windows\Temp。当服务器上有多个PHP应用时,它们会把自己的session文件都保存在同一个目录中。同样地,这些PHP应用也会按一定机率启动GC,扫描所有的session文件。
问题在于,GC在工作时,并不会区分不同站点的session。举例言之,站点A的gc_maxlifetime设置为2小时,站点B的 gc_maxlifetime设置为默认的24分钟。当站点B的GC启动时,它会扫描公用的临时文件目录,把所有超过24分钟的session文件全部删除掉,而不管它们来自于站点A或B。这样,站点A的gc_maxlifetime设置就形同虚设了。
找到问题所在,解决起来就很简单了。修改session.save_path参数,或者使用session_save_path()函数,把保存session的目录指向一个专用的目录,gc_maxlifetime参数工作正常了。
严格地来说,这算是PHP的一个bug?
还有一个问题就是,gc_maxlifetime只能保证session生存的最短时间,并不能够保存在超过这一时间之后session信息立即会得到删除。因为GC是按机率启动的,可能在某一个长时间内都没有被启动,那么大量的session在超过gc_maxlifetime以后仍然会有效。
解决这个问题的一个方法是,把session.gc_probability/session.gc_divisor的机率提高,如果提到100%,就会彻底解决这个问题,但显然会对性能造成严重的影响。另一个方法是自己在代码中判断当前session的生存时间,如果超出了 gc_maxlifetime,就清空当前session。
但是如果你没有服务器的操作权限,那就比较麻烦了,你需要通过PHP程序改写SessionID来实现永久的Session数据保存。查查php.net的函数手册,可以见到有“session_id”这个函数:如果没有设置参数,那么将返回当前的SessionID,如果设置了参数,就会将当前的SessionID设置为给出的值……
只要利用永久性的Cookie加上“session_id”函数,就可以实现永久Session数据保存了!
但是为了方便,我们需要知道服务器设置的“session.name”,但是一般用户都没有权限查看服务器的php.ini设置,不过PHP提供了一个非常好的函数“phpinfo”,利用这个可以查看几乎所有的PHP信息!
------------------------------------------------------------------------------------
<title>PHP相关信息显示</title>
<?phpinfo()?>
------------------------------------------------------------------------------------
打开编辑器,输入上面的代码,然后在浏览器中运行这个程序,会见到PHP的相关信息(如图1所示)。其中有一项“session.name”的参数,这个就是我们需要的服务器“session.name”,一般是“PHPSESSID”。
记下了SessionID的名称后,我们就可以实现永久的Session数据储存了!
复制代码 代码如下:
session_start();
ini_set('session.save_path','/tmp/');
//6个钟头
ini_set('session.gc_maxlifetime',21600);
//保存一天
$lifeTime = 24 * 3600;
setcookie(session_name(), session_id(), time() + $lifeTime, "/");

后记:
其实真正的永久储存是不可能的,因为Cookie的保存时间有限,而服务器的空间也有限……但是对于一些需要保存时间比较长的站点,以上方法就已经足够了!
把session放入mysql的Example:
数据库里建表:session ( sesskey varchar32 , expiry int11 , value longtext)
code:
代码执行前已经连接数据库了。
复制代码 代码如下:
define('STORE_SESSIONS','mysql');
if (STORE_SESSIONS == 'mysql') {
if (!$SESS_LIFE = get_cfg_var('session.gc_maxlifetime')) {
$SESS_LIFE = 1440;
}
function _sess_open($save_path, $session_name) {
// 如果没有连接数据库,可以在此执行mysql_pconnect,mysql_select_db
return true;
}
function _sess_close() {
return true;
}
function _sess_read($key) {
$value_query = mysql_query("select value from sessions where sesskey = '" .addslashes($key) . "' and expiry > '" . time() . "'");
$value = mysql_fetch_array($value_query);
if (isset($value['value'])) {
return $value['value'];
}
return false;
}
function _sess_write($key, $val) {
global $SESS_LIFE;
$expiry = time() + $SESS_LIFE;
$value = $val;
$check_query = mysql_query("select count(*) as total from sessions where sesskey = '" . addslashes($key) . "'");
$check = mysql_fetch_array($check_query);
if ($check['total'] > 0) {
return mysql_query("update sessions set expiry = '" . addslashes($expiry) . "', value = '" . addslashes($value) . "' where sesskey = '" . addslashes($key) . "'");
} else {
return mysql_query("insert into sessions values ('" . addslashes($key) . "', '" . addslashes($expiry) . "', '" . addslashes($value) . "')");
}
}
function _sess_destroy($key) {
return mysql_query("delete from sessions where sesskey = '" . addslashes($key) . "'");
}
function _sess_gc($maxlifetime) {
mysql_query("delete from sessions where expiry < '" . time() . "'");
return true;
}
session_set_save_handler('_sess_open', '_sess_close', '_sess_read', '_sess_write', '_sess_destroy', '_sess_gc');
}
danoo_session_name( 'dtvSid' );
danoo_session_save_path(SESSION_WRITE_DIRECTORY);

还是有点不明白,open,write那些参数哪里来的。
修改php.ini配置的两个常用函数:
get_cfg_var('session.gc_maxlifetime') : 取得session.gc_maxlifetime的值
ini_set('session.cookie_lifetime','0') : 设置session.cookie_lifetime的值为0。

php中如何把字符串的第一个字符变成小写

lcfirst — 用这个函数可以把字符串的第一个字符变成小写(Make a string's first character lowercase),php5.3以前的版本不支持这个函数,你可以把下面的这个函数放到全局范围:
if (!function_exists('lcfirst')) {
	function lcfirst($str)
	{
		$str = is_string($str) ? $str : '';
		if(mb_strlen($str) > 0) {
			$str[0] = mb_strtolower($str[0]);
		}
		return $str;
	}
}

The advantage of the above over just strolower ing where needed is that your PHP code will simply switch to the native function once you upgrade to PHP5.3

Updated after comments. The function does now check whether there actually is a first character in the string and that it is an alphabetic character in the current locale. It is also multibyte aware now.

google maps api教程(一):用google maps生成向导生成即时地图

用google maps生成向导生成即时地图。google提供了一个向导来生成google maps的代码片段,你可以把它放入到你的网站页面中。点击此处转到向导页,并按照里面的3个简单的步骤操作。

1、定制地图的长宽、缩放级别、中心位置、中心位置的链接地址、中心位置的地址说明。当点击中心位置的那个箭头时会显示这些信息。

2、输入你网站的网址,以便生成一个API key。

3、点击生成按钮就可以生成代码了。

最后把生成的代码复制到您自己的网页中就可以使用了,以下为生成的代码例子:

  <!-- ++Begin Map Search Control Wizard Generated Code++ -->
  <!--
  // Created with a Google AJAX Search Wizard
  // http://code.google.com/apis/ajaxsearch/wizards.html
  -->

  <!--
  // The Following div element will end up holding the map search control.
  // You can place this anywhere on your page
  -->
  <div id="mapsearch">
    <span style="color:#676767;font-size:11px;margin:10px;padding:4px;">Loading...</span>
  </div>

  <!-- Maps Api, Ajax Search Api and Stylesheet
  // Note: If you are already using the Maps API then do not include it again
  //       If you are already using the AJAX Search API, then do not include it
  //       or its stylesheet again
  //
  // The Key Embedded in the following script tags is designed to work with
  // the following site:
  // http://www.junstyle.com.cn
  -->
  <script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAurOz_u21LMSjFODxuxTsbxSWkWNcz8otOi80ukkm5C_9fVjCfhS7lPl_eE2MldQL6fDI9jugOBzLoA"
    type="text/javascript"></script>
  <script src="http://www.google.com/uds/api?file=uds.js&v=1.0&source=uds-msw&key=ABQIAAAAurOz_u21LMSjFODxuxTsbxSWkWNcz8otOi80ukkm5C_9fVjCfhS7lPl_eE2MldQL6fDI9jugOBzLoA"
    type="text/javascript"></script>
  <style type="text/css">
    @import url("http://www.google.com/uds/css/gsearch.css");
  </style>

  <!-- Map Search Control and Stylesheet -->
  <script type="text/javascript">
    window._uds_msw_donotrepair = true;
  </script>
  <script src="http://www.google.com/uds/solutions/mapsearch/gsmapsearch.js?mode=new"
    type="text/javascript"></script>
  <style type="text/css">
    @import url("http://www.google.com/uds/solutions/mapsearch/gsmapsearch.css");
  </style>

  <style type="text/css">
    .gsmsc-mapDiv {
      height : 275px;
    }

    .gsmsc-idleMapDiv {
      height : 275px;
    }

    #mapsearch {
      width : 365px;
      margin: 10px;
      padding: 4px;
    }
  </style>
  <script type="text/javascript">
    function LoadMapSearchControl() {

      var options = {
            zoomControl : GSmapSearchControl.ZOOM_CONTROL_ENABLE_ALL,
            title : "Googleplex",
            url : "http://www.google.com/corporate/index.html",
            idleMapZoom : GSmapSearchControl.ACTIVE_MAP_ZOOM,
            activeMapZoom : GSmapSearchControl.ACTIVE_MAP_ZOOM
            }

      new GSmapSearchControl(
            document.getElementById("mapsearch"),
            "1600 Amphitheatre Parkway, Mountain View, CA",
            options
            );

    }
    // arrange for this function to be called during body.onload
    // event processing
    GSearch.setOnLoadCallback(LoadMapSearchControl);
  </script>
  <!-- ++End Map Search Control Wizard Generated Code++ -->

把以上的代码放置到你的页面的body之间,不要放在head里面。

本文参考自:http://econym.org.uk/gmap/wizard.htm

oracle virtualbox3.2.0.0发布

看到virtualbox3.2.0.0发布了,下载,安装后用了一下,我以前建的两个虚拟主机居然都打不开,自从oracle收购了sun之后,好像这是发布的第一个带oracle标识的版本,看新闻增加了以下特性:

- 可动态增加或减少VM 的内存使用
- CPU hot-plugging 支持(Linux guest 支持 hot-add 和 hot-remove,Windows guest 仅支持hot-add)
- 新的Hypervisor 特性
- VM 运行时也可删除snapshots
- 能够在GUI 中设置multi-monitor guest
- USB tablet/keyboard的基本模拟
- LsiLogic SAS controller的基本模拟
- RDP 视频加速
- 可通过API 和VBoxManage 配置NAT engine
- Guest Additions:支持从host 系统执行 guest 应用程序
- 增强了 OVF 支持

但现在在win7 64位下我以前的虚拟主机不能用,所以安装后就卸载了,还是用3.1.6算了。不知道下一个版本会怎么样,期待。