竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


274月/130

PHP中设置Session过期方法

发布在 邵珠庆

Session的有效期是随浏览器进程的,浏览器关掉后就没了,那么怎么像Cookies那样设置过期时间呢?下面这段代码就可以实现。

 
1
2
3
4
5
<?php
$cookies_life_time = 24 * 3600;   //过期时间,单位为秒,这里的设置即为一天
session_start();
setcookie(session_name() ,session_id(), time() + $cookies_life_time, "/");
?>
244月/130

企业持续集成成熟度模型简介

发布在 邵珠庆

构建—— 企业持续集成成熟度模型简介之一

当今软件开发领域的自动化推广相当显著,软件也越来越多的由大规模、分布式的团队开发完成,而严格的企业管理需求也是十分常见的。由此表现出来的敏捷软件开发和持续集成与企业开发项目的现实之间的碰撞也越来越显著。在软件开发的整个生命周期中,我们对自动化的投入在不断增加。在这方面的先行者已经跨过了团队级别的持续集成,而将他们的自动化成果与端到端的方案结合在一起了。这些在企业级持续集成方面的投入使得他们可以应对需求的变化,并快速交付高质量的软件,而且得到事半功倍的效果。尽管自动化有这么多的好处,但,对于自动化的采纳情况却并不均衡。比如,很多团队仍旧在手工、缓慢且高风险的部署中挣扎着;而某些团队却可以在一天内进行多次高效且足够安全的生产环境部署。其实,有很多方法或途径来改善我们的开发自动化,但是从哪里开始呢?

 企业的多样性

 

 当创建这篇指导书时,我们遇到的挑战就是:不同企业(甚至同一个企业的不同团队)都不具有统一性。医疗设备系统的某些需求可能就要比做游戏难,也可能比在电子商务网站上增加新功能要难,也可能会比创建一个内部SOA应用要难。因此,单一的成熟度模型不可能适应全部情况。因此,我们选择了企业持续集成的四个维度来衡量成熟度,它们分别是构建、部署、测试和报告。我们将每一个维度上所对应的实践归入某一等级之下,并解释为什么需要采纳(或不采纳)这些实践。通过这个模型,你可以了解业内在企业持续集成方面的平均水平,并可以据此反思,在哪些方面做得高于行业平均水平,还有哪些方面做得不足。这个模型所反映出来的评估尺度完全基于几年来数百个团队持第一手经验以及本领域的一些报告。为了解释如何使用这个模型,我们创建了三个有不同需求的企业案例。我们会分析他们的状况,并展示他们如何使用成熟度模型来计划哪些改进会给他们带来最高的投资回报率。

 成熟度模型中的级别

 在整篇文章中,企业持续集成不同维度的成熟级别会以相同的方式来阐述。级别分为:入门、新手、中等、进阶和疯狂。为了解释这些级别,下面我们举例说明各级别之间的关系。实例的出发点为:该过程为完全手工的,即某个工程师必须要手工执行一系列冗长且易出错的步骤来达到“将某个手工过程自动化”这一目标。那么对于这个“自动化某个过程”,它的成熟度模型如下所示:

 团队最初是入门级,因为他们已经写了一些辅助脚本,用于该过程中那些特别慢或问题较多的部分进行了自动化。这种自动化的益处在于节省时间且减少错误。为了进一步提高,团队将所有辅助脚本串接起来,实现了整个过程的单一脚本自动化,即达到了中级。而这个单一脚本的回报就是:这个操作过程可以很容易交给别人去做。当团队打算提高到进阶级时,需要用某个应用软件来调用执行该脚本。这个应用软件可能在后台执行的,但一定是每次都在正确的条件、时机和位置上运行的。比如,这个应用软件可能只需要用户点一下鼠标,或者只需要在某个特定的时间调用这个脚本,自动传入一些参数来执行。

 当然,进阶级或者疯狂级的定义都会随着时间的推移而改变。在持续集成诞生时,“代码提交后自动触发构建”就被认为是疯狂的,而在今天只能算是中级中的一个活动而已。

 构建、部署、测试和报告

 在我们的成熟度模型中,包括了四个维度,它们分别是构建、部署、测试和报告。这四个维度覆盖了整个端到端的构建生命周期,即从源代码直到产品。

构建

那种原始的以开发人员为中心的持续集成是为了从构建软件中得到快速的反馈。而当持续集成进入企业视角后,构建管理、项目之间的依赖以及构建过程上的管理控制都成为至关重要的元素了。大多数新项目一般在开始时,都是在开发机器上执行构建的,而且没有一个标准的过程。一个开发人员可能习惯于在他自己的IDE上进行构建,而另一个人可能写了一个构建脚本来做这件事。那些最不成熟的团队还会将那些使用这种过程构建出来的二进制文件部署并测试,甚至将其发布到生产环境中。这种因缺乏控制所导致的问题很快就显现出来了。因此,我们一开始就要找更好的方法。

成熟构建的第一步就是让构建过程标准化,并在非开发机器上进行正式的构建。使用非开发者机器进行构建意味着这种构建不会因开发者的机器环境发生了变化而导致污染。因为正式构建已经不在开发者的机器上进行,所以我们必然是每次都从某个固定的源文件控制中得到代码,并遵守一定的规则:比如每次都从某个分支签出最新版本,或者是打过某种标签的源代码等等。因些做到了这些之后,该团队就达到了入门级。

入门级的团队进一步采取行动,将构建步骤实现自动化执行。即构建服务器将指挥机器、按源代码签出规则得到源代码,并执行那些构建步骤,从而提供了初步受控的构建过程。典型的是:这些自动构建每日执行,尽管某些团队可能会一天执行两次以上。此时的团队就提高到了新手级。

而对中级的团队来说,他们开始更明显地关注并管理对于其它软件的依赖(包括子项目或第三方库)。中级使用依赖管理库来追踪这些库文件,并在构建时提供这些库文件,而不是使用某种口头约定方式。同样地,那些可能被其它构建所引用的构建也会通过依赖管理工具将其自身放在这个库中以便其它构建来引用。达到这一级别的控制后,自动构建就是很容易做到的了,而且也提供更有价值的反馈。中级团队采纳了持续构建(即每个开发人员提交时就自动构建或当依赖发生变化时)。所有的构建结果都被保存(可能放在一个网络服务器上,或干脆就在持续集成服务器上),并进行周期性的清理并标签以方便识别。规模大一些的团队将使用分布式构建设施来并行处理数量众多的构建。此时,对于很多组织来说,可以说满足了他们的需求。

对于更正规的组织(比如企业级)将会进一步做到进阶级,以控制构建过程。在这种环境下,团队象追踪源代码和依赖的变化一样,对构建过程的变化也进行记录跟踪。修改构建过程需要经过批准,对于登录官方构建机器,修改构建服务器配置等都是严格控制的。对于那种“服从是一个要素”的地方或那种将企业持续集成已成为一个生产系统的地方,应该将进阶级的受控构建过程做为目标。而对于没有这方面要求的其它团队来说,中级也就可以接受了。

另外,某些组织的管理控制规则更加严格,且要求必须能够完美地重新构建从前的发布版本(比如需要拿到与一年前的某次构建产物一模一样的产物)。这些组织将使用各种各样的技术来确保每个环境的可重复性。一些可能会有缜密细致地被版本控制化的脚本,在开始运行构建之前从安装操作系统开始来准备构建机器。另一些可能使用做好的虚拟机镜像来做类似的事情。我们把这种控制级别定义为疯狂级。因此,一些团队可能不需要达到这种方式。因为可能负担太大而收益太少。

部署—— 企业持续集成成熟度模型简介之二

部署是指将软件移动到它被测试的地方,或用户指定的某个位置,准备送给客户。对于web应用来说,这可能意味着将软件安装到某个web服务器上,并更新数据库或静态内容服务器。而对于一个视频游戏来说,这个测试部署可能是指安装这个软件版本到某些测试机器上,而产品部署则可能是指烧录一个光盘并给发行商。
部署最开始一般都是手工过程。部署工程师从某处拿到部署文件,再把它放到目标机器上,然后开始正式的安装过程。然而,这种手工过程会比较慢,而且部署失败率也可能要高一些。工程师常常被迫在晚上或周末加班,进行测试环境或生产环境的部署,因为这些环境平时需要正常运行,不能轻易地停止。更糟糕的是:每个环境很可能使用了不同的步骤进行手工操作(比如步骤前后顺序颠倒,这尤其容易发生在不同的操作人员之间),几乎无法保证:在某个环境上的成功部署表明在下一个环境中部署成功的可能性也同样高。

对于团队来说,抛弃完全的手工过程,使用一些辅助脚本或全过程脚本化是一个非常巨大的进步。纵观整个行业,大多数团队都会有一些辅助性脚本,但有完全脚本化部署方式的团队较少,特别是在受控环境中(如试运行环境或生产环境)。因此,业内在这方面的平均水平应该是在入门级。

而中级团队善于进行测试环境上的自动化部署。他们完全通过脚本以一键部署的方式在部分或全部的测试环境中进行部署。这大大解放了部署工程师,而且减少了测试人员因等待部署而浪费的时间。就像持续构建是中级构建团队的的特征一样,自动地部署到第一个测试环境是在部署这一维度上中级成熟度的标志。根据团队的动态性,在不打断测试人员工作的情况下,这种测试环境的自动部署应该发生在任何一次成功的持续构建之后或一天内的周期性部署。中级团队的最后一个特征是:建立标准化的各种环境部署顺序。虽然可能还会有一些环境变数,或两种部署方式,但在某个版本的全生命周期中(即从生产到部署上线),越早地成功部署,就意味着后续部署成功的可能性更大。达到这个级别是很多团队的目标。而进阶团队则把视线转到受控环境或生产环境上。部署到生产环境(或发布)只要按一下鼠标就行,生产环境发布就被自动触发,并有相应的发布版本可以进行灾难恢复。那些已经部署到内部测试环境的团队应该将目标定位到“进阶”:如果在所有环境中进行完全一致的部署过程,那么在生产环境部署时,会极大地减少最后一刻失败的可能性。进阶级团队的另一个特征是:将通过前面通过质量测试检验的版本全部自动地部署到部分或全部测试环境中。例如,得到测试经理的批准后,让某个构建版本自动地安装到压力测试环境中。

而疯狂级的团队的目标是“持续部署”,即自动部署到生产环境中而无需手工干预:得到一个版本后,自动部署到一系列的测试环境中。经过整个构建管道中的所有阶段,并且能通过所有的测试后,自动部署该版本到生产环境中。某些.com应用可以在一个小时之内就完成从源文件控制到发布的整个过程。显然,此时的自动化测试必须非常成熟,而且具有自动回滚和相应的监控手段。但是,在快节奏的竞争环境下,极其迅速地部署新功能也是一个核心竞争力,可以减轻大规模功能变更的风险。

测试—— 企业持续集成成熟度模型简介之三

持续集成一直同自动化测试相关联。这在马丁福勒的文章或更早期Steven McConnell对日构建和冒烟测试的相关实践描述中都有提及。而且在企业持续集成的领域中,我们会考虑很多种类型的自动化测试和手工测试。尽管如些,很多团队在测试方面还是比较弱。很常见的一个版本发布场景就是:某个团队完成一个版本后,手工测试一下基本功能就发布了。而其中的某一部分总是出错,而新功能也只做了少量测试。如果团队在测试方面比较成熟的话,他们能很快发现问题或缺陷,从而在生产率和信心方面都会有所增加。

测试成熟度 
目前,大多数团队或多或少都会有某种形式的自动化测试。比如一小撮单元测试套件或一些脚本化的测试,用于确保软件的基本功能是可以工作的。这些基本的自动化回归测试能够较早及比较容易地发现那些基本功能性问题。入门级的团队 通常刚刚开始习惯于做这种自动化测试。

为了达到新手级成熟度 ,应该有一套快速测试在每次构建时都运行。这些测试给团队增加了信心:软件基本上在任何时间都能工作。测试一旦失败,开发团队会得到即时通知,从而在他们忘记这个问题的上下文之前就有机会去修复这些失败的测试。因此,对于这一级别来说,对测试失败通知的响应是非常重要的:如果一个团队测试失败却不响应的话,那它应该低于测试成熟度的入门级。

中级成熟度 的团队会在这些同快速构建同时执行的测试的基础之上,扩大测试范围。企业持续集成的成熟测试是以多种多样的测试集合为特性的。一个中级团队不仅有快速测试和手工测试,而且还有自动化的功能测试。中级团队常常让持续集成系统同时运行一些静态源代码分析。静态分析可能不是每次都运行,但一定会周期性运行。而且一旦产生了某种严重的静态质量问题的话,一定修复之后才能发布。

进阶级成熟度 是以“完整测试”为标志的。每种测试都提供其所能提供的最大价值。单元测试覆盖了系统中所有复杂代码与逻辑。功能测试覆盖了系统中所有的重要功能。也会有边界测试和随机测试。同时,还要频繁运行静态代码分析,并补充以工具支持的运行时分析和安全扫描来发现那些可能因测试不足或无法测试而遗漏的问题。测试可能被分配在多种系统下运行,以使能并行执行,从而提供快速的反馈。达到进阶级需要相当大的投入,然而对于那些缺陷的成本很高且需要能够保持高速前进的团队来说,对是非常重要的。假如没有这类需求的话,一般来说,中级可能是一个更适当的目标。

在极端的情况下(也就是疯狂级成熟度 ),某些团队追求100%的测试覆盖率。尽管100%测试覆盖率的定义在变化,但它反映出至少每行代码都被测试覆盖到。在某些软件中,存在一个收益递减的点,在这一点上,对某行代码的自动化测试的价值要小对写测试的成本。追求100%的测试覆盖率意味着团队会做一些浪费的测试,然而其目的有可能是阻止因某些测试很有价值但很难写而不写测试找藉口。满足并保持100%的测试覆盖率可能也是一个自豪感与动力的源泉。对于进阶级团队来说,如果曾经发现的确错过了一些非常重要的测试的话,要求100%的测试覆盖也未尚不可。但对于大多数团队来说,简直可以说是变态啦。

报告—— 企业持续集成成熟度模型简介之四 

持续集成工具一直以来就负责报告最近一次构建的状态。报告是持续集成的一个至关重要的元素。在企业持续集成中,报告应包含所做软件的相关质量和内容方面的信息,以及与企业持续集成过程有关的度量信息。没有报告的团队就象一个没有雷达的飞机在飞行。如果没有人看测试结果的话,所有的测试都是无用的。同样,很多数据如果没有被提取成可消化利用的信息的话,就很难使用,一样可以视为无用。越成熟团队的报告,其可视化程度越高,有用的信息也会越多。
报告 

很多工具在构建过程中都会产生报告。在一个团队中,如果某人利用一些工具来产生报告,并分析它,之后会根据它来做出行动的话,这个团队就已经是入门级成熟度 了。注意:此级别上,如果团队的其他人想利用这些数据做些事情时,需要联系这个人,索要相关信息。当到了新手级成熟度 时,每个角色组(开发、测试、部署等)都会公布这类信息。一个构建服务器也可能提供一些信息,比如哪些代码变化了,源代码的分析报告、单元测试结果或编译错误等。测试人员也会公布他们自动测试和手工测试的结果报告。部署与发布人员会公布某个版本在生产环境的运行时长、记录的缺陷,以及发布速度等信息。但每个角色几乎各自为战,跨角色信息传递通常是手工完成的。事实上,这个级别应该是业内的平均水平,尽管很多企业有比较强大的跨角色或部门的展示能力。
中级成熟度 则有两个比较大的变化。第一个是每个角色组的关键信息集合可以被整个团队的其它人员访问。测试人员可以看到开发部分的信息:比如从上次测试人员测试过的版本到目前的版本有哪些文件变化了;开发人员能够知道测试人员正在测试哪个版本,目前的测试结果如何等。每个参与到版本生命周期的人都至少会得到对其有用的总结报告。有了更高的可视化程度,那么用于沟通基本数据所用的成本会减少,从而依据报告进行相应工作的时间就增加了。第二个是有历史报告。即不但有最近的活动报告,而且有过去的报告。比如可以拿出过去发布的测试数据与当前发布的数据进行对比。团队不但知道最近测试通过率是95%,还知道加了多少个测试,删除了多个测试,或者哪些测试之前通过了。95%的通过率比昨天的结果好,还是坏?我们是应该高兴,还是需要继续努力让它更高?
进阶级团队 能够利用历史报告信息进行趋势分析。中级团队记录了每个测试的失败,而进阶级团队利用报告分析出哪些测试经常被破坏。还可能分析出修改哪些文件后更有可能使单元测试失败?哪些会让功能测试套件失败?通过识别那些经常出错的代码帮助团队来发现哪些代码应该多加测试或进行重新设计实现。在特定的报告中,会有从不同的竖井(不同的角色团队)汇总在一起得到的数据,并互相迭加引用。进阶级团队也是真正使用这些特定报告并会采取相应行动的团队。生成这些可操作的跨功能团队的报告应该是企业持续集成的目标。而疯狂级报告是关于预测的。这样的疯狂级团队会收集每次交付客户之后得到的反馈度量信息,如从缺陷报告和接收到的技术支持的需求抽取相关信息。根据当前的一次发布与过去的某次发布之间的数据对比,团队应该可以预测在发布后的第一周内技术支持的压力有多大(比如,可能会接到多少个问题反馈)。在这种模式下,他们可能问更多有意思的问题,而不只是简单的问一下“我们的特性都做完了吗?”

244月/130

PHP读取文件的常见方法

发布在 邵珠庆

整理了一下PHP中读取文件的几个方法,方便以后查阅。

1.fread

string fread ( int $handle , int $length )

fread() 从 handle 指向的文件中读取最多 length 个字节。该函数在读取完最多 length 个字节数,或到达 EOF 的时候,或(对于网络流)当一个包可用时,或(在打开用户空间流之后)已读取了 8192 个字节时就会停止读取文件,视乎先碰到哪种情况。

fread() 返回所读取的字符串,如果出错返回 FALSE。

复制代码
<?php
    $filename = "/usr/local/something.txt";
    $handle = fopen($filename, "r");//读取二进制文件时,需要将第二个参数设置成'rb'
    
    //通过filesize获得文件大小,将整个文件一下子读到一个字符串中
    $contents = fread($handle, filesize ($filename));
    fclose($handle);
?>
复制代码

如果所要读取的文件不是本地普通文件,而是远程文件或者流文件,就不能用这种方法,因为,filesize不能获得这些文件的大小。此时,你需要通过feof()或者fread()的返回值判断是否已经读取到了文件的末尾。

例如:

复制代码
<?php
    $handle = fopen('http://www.baidu.com', 'r');
    $content = '';
    while(!feof($handle)){
        $content .= fread($handle, 8080);
    }
    echo $content;
    fclose($handle);
?>
复制代码

或者:

复制代码
<?php
    $handle = fopen('http://www.baidu.com', 'r');
    $content = '';
    while(false != ($a = fread($handle, 8080))){//返回false表示已经读取到文件末尾
        $content .= $a;
    }
    echo $content;
    fclose($handle);
?>
复制代码

 

2.fgets

 string fgets ( int $handle [, int $length ] )

  fgets()从 handle 指向的文件中读取一行并返回长度最多为 length - 1 字节的字符串。碰到换行符(包括在返回值中)、EOF 或者已经读取了 length - 1 字节后停止(看先碰到那一种情况)。如果没有指定 length,则默认为 1K,或者说 1024 字节。

复制代码
<?php
    $handle = fopen('./file.txt', 'r');
    while(!feof($handle)){
        echo fgets($handle, 1024);
    }
    fclose($handle);
?>
复制代码

Note: length 参数从 PHP 4.2.0 起成为可选项,如果忽略,则行的长度被假定为 1024。从 PHP 4.3 开始,忽略掉 length 将继续从流中读取数据直到行结束。如果文件中的大多数行都大于 8KB,则在脚本中指定最大行的长度在利用资源上更为有效。从 PHP 4.3 开始本函数可以安全用于二进制文件。早期的版本则不行。

3.fgetss

string fgetss ( resource $handle [, int $length [, string $allowable_tags ]] )

跟fgets功能一样,但是fgetss会尝试从读取的文本中去掉任何 HTML 和 PHP 标记,可以用可选的第三个参数指定哪些标记不被去掉。

复制代码
<?php
    $handle = fopen('./file.txt', 'r');
    while(!feof($handle)){
        echo fgetss($handle, 1024, '<br>');
    }
    fclose($handle);
?>
复制代码

 

4.file

array file ( string $filename [, int $use_include_path [, resource $context ]] )
将文件内容读入一个数组中,数组的每一项对应文件中的一行,包括换行符在内。不需要行结束符时可以使用 rtrim() 函数过滤换行符。

复制代码
<?php
    $a = file('./file.txt');
    foreach($a as $line => $content){
        echo 'line '.($line + 1).':'.$content;
    }
?>
复制代码

 5.readfile

int readfile ( string $filename [, bool $use_include_path [, resource $context ]] )

读入一个文件并写入到输出缓冲。返回从文件中读入的字节数。如果出错返回 FALSE 并且除非是以 @readfile() 形式调用,否则会显示错误信息。

<?php
    $size = readfile('./file.txt');
    echo $size;
?>

 

6.file_get_contents

string file_get_contents ( string $filename [, bool $use_include_path [, resource $context [, int $offset [, int $maxlen ]]]] )

将文件读入一个字符串。第三个参数$context可以用来设置一些参数,比如访问远程文件时,设置超时等等。

另外,file_get_contents相对于以上几个函数,性能要好得多,所以应该优先考虑使用file_get_contents。但是readfile貌似比file_get_contents性能好一点(?),因为它不需要调用fopen。

复制代码
<?php 
    $ctx = stream_context_create(array( 
        'http' => array( 
            'timeout' => 1    //设置超时
            ) 
        ) 
    ); 
    echo file_get_contents("http://www.baidu.com/", 0, $ctx); 
?>
复制代码

7.fpassthru

   int fpassthru ( resource $handle )

将给定的文件指针从当前的位置读取到 EOF 并把结果写到输出缓冲区。

复制代码
<?php 
    header("Content-Type:text/html;charset=utf-8"); 
    $handle = fopen('./test2.php', 'r');
    fseek($handle, 1024);//将指针定位到1024字节处
    fpassthru($handle);
?>
复制代码

 

8.parse_ini_file

array parse_ini_file ( string $filename [, bool $process_sections ] )

parse_ini_file() 载入一个由 filename 指定的 ini 文件,并将其中的设置作为一个联合数组返回。如果将最后的 process_sections 参数设为 TRUE,将得到一个多维数组,包括了配置文件中每一节的名称和设置。process_sections 的默认值是 FALSE。

注意:

1. 如果 ini 文件中的值包含任何非字母数字的字符,需要将其括在双引号中(")。
2. 有些保留字不能作为 ini 文件中的键名,包括:null,yes,no,true 和 false。值为 null,no 和 false 等效于 "",值为 yes 和 true 等效于 "1"。字符 {}|&~![()" 也不能用在键名的任何地方,而且这些字符在选项值中有着特殊的意义。

test.ini文件内容:

复制代码
; This is a sample configuration file
; Comments start with ';', as in php.ini

[first_section]
one = 1
five = 5
animal = BIRD

[second_section]
path = "/usr/local/bin"
URL = "http://www.example.com/~username
复制代码

test.php内容:

<?php 
    $config = parse_ini_file('./test.ini', ture);
    print_r($config);
?>

输出内容:

复制代码
Array
(
    [first_section] => Array
        (
            [one] => 1
            [five] => 5
            [animal] => BIRD
        )

    [second_section] => Array
        (
            [path] => /usr/local/bin
            [URL] => http://www.example.com/~username
        )

)
复制代码

 

 

 

几个注意事项:

1. 鼓励在处理二进制文件时使用 b 标志,即使系统并不需要,这样可以使脚本的移植性更好。 

2. allow_url_fopen选项激活了 URL 形式的 fopen 封装协议使得可以访问 URL 对象例如文件。默认的封装协议提供用 ftp 和 http 协议来访问远程文件,一些扩展库例如 zlib 可能会注册更多的封装协议。出于安全性考虑,此选项只能在 php.ini 中设置。

3. 如果要打开有特殊字符的 URL (比如说有空格),就需要使用 urlencode() 进行 URL 编码。

184月/130

JavaScript跨域总结与解决办法

发布在 邵珠庆

本文来自网络(http://f2e.me/200904/cross-scripting/,该网址已不能访问),仅作个人读书笔记之用,并稍作修改和补充。

什么是跨域

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。这里把涉及到跨域的一些问题简单地整理一下:

首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:

URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不同域名 不允许
特别注意两点:
第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

接下来简单地总结一下在“前台”一般处理跨域的办法,后台proxy这种方案牵涉到后台配置,这里就不阐述了,有兴趣的可以看看yahoo的这篇文章:《JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls

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://script.a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
    var doc = ifr.contentDocument || ifr.contentWindow.document;
    // 在这里操纵b.html
    alert(doc.getElementsByTagName("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.cnblogs.com/lab/cscript/cs2.html#paramdo';
    document.body.appendChild(ifr);
}

function checkHash() {
    try {
        var data = location.hash ? location.hash.substring(1) : '';
        if (console.log) {
            console.log('Now the data is '+data);
        }
    } catch(e) {};
}
setInterval(checkHash, 2000);

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://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实现的跨域数据传输

文章较长列在此处不便于阅读,详细请看 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中的代码:

b.com/index.html中的代码:

参考文章:《精通HTML5编程》第五章——跨文档消息机制https://developer.mozilla.org/en/dom/window.postmessage

6、利用flash

这是从YUI3的IO组件中看到的办法,具体可见http://wiht.link/YUI-intro
可以看在Adobe Developer Connection看到更多的跨域代理文件规范:ross-Domain Policy File SpecificationsHTTP Headers Blacklist

174月/130

git 分支管理 branch

发布在 邵珠庆

Git的分支管理是Git的神器。拥有了它就会使我么管理代码更加游刃有余。那么什么是Git的分支管理?为什么要使用Git的分支管理?Git分支管理怎么用?
     在集中式版本控制中,冲突的合并是可怕的,是令人恶心的。所以很多版本控制软件通过加锁来拒绝多个人同时访问一个文件;而有的版本管理软件,则不是通过加锁的方式,第一个提交的人会很顺畅,但是如果第二个人提交,那么面临它的将是恶心的冲突解决。
    而在分布式管理软件中,冲突解决、合并、衍合,则是一种容易的事情,它是版本管理中的常态。
     而合并、衍合的主体就是分支。
    分支其实就是指向某种代码状态的一个指针。而合并其实就是将两种代码状态合并到另一种代码状态中。
     在Git中,正确的使用方法中,无处不在使用分支。比如,提交实际上就是本地分支合并到远程分支,更新实际上就是将远程分支合并到本地分支,在开发过程中,每加入一个功能或特性,都加入一个分支,当实验成功后合并到主分支...
    为什么要使用分支管理?
     我们来设想下面几种情况:1、我们在基于一个稳定的版本在进行开发,突然在稳定版本上有一个紧急的bug需要我们解决。2、我们在软件中加入了一个小的特性,但是开发到一半的时候,发现开发组的另一个的想法更有创意,所以我们想废弃自己的更改。3、自己想在软件中同时加入多个特性,但是希望并行开发开发,而不是依次开发。
     如果采用单分支形式的话,以上可能也可以实现,但是实现的复杂度可能就会加大。而应用多分支管理时情况就变的简单了。
     如果我们开发新功能时是基于一个新的分支的话,如果稳定版本有一个紧急bug需要处理,那么我们就可以切换到稳定版本的分支,然后修改bug,修改之后,我们再次切换到原先的分支继续工作,最后我们将该分支合并到稳定分支即可。如果我们想废弃正在开发的某个特性,如果该特性在一个单独的分支上,只需要简单的删除该分支即可。如果我们想并行开发多个特性,我们可以创建多个分支,分别开发,然后将每个分支都合并到稳定分支上即可。
     多分支管理,我们可以维护一个稳定的分支,然后某些特性或实验性的开发可以单独作为一个分支,这样开发过程就不会影响到稳定的版本。而且Git中分支的创建和切换基本上没有多少消耗。
    Git如何进行分支管理?
     1、创建分支
     创建分支很简单:git branch <分支名>
     2、切换分支
     git checkout <分支名>
     该语句和上一个语句可以和起来用一个语句表示:git checkout -b <分支名>
     3、分支合并
     比如,如果要将开发中的分支(develop),合并到稳定分支(master),
     首先切换的master分支:git checkout master。
     然后执行合并操作:git merge develop。
     如果有冲突,会提示你,调用git status查看冲突文件。
     解决冲突,然后调用git add或git rm将解决后的文件暂存。
     所有冲突解决后,git commit 提交更改。
     4、分支衍合
     分支衍合和分支合并的差别在于,分支衍合不会保留合并的日志,不留痕迹,而 分支合并则会保留合并的日志。
     要将开发中的分支(develop),衍合到稳定分支(master)。
     首先切换的master分支:git checkout master。
     然后执行衍和操作:git rebase develop。
     如果有冲突,会提示你,调用git status查看冲突文件。
     解决冲突,然后调用git add或git rm将解决后的文件暂存。
     所有冲突解决后,git rebase --continue 提交更改。
     5、删除分支
     执行git branch -d <分支名>
     如果该分支没有合并到主分支会报错,可以用以下命令强制删除git branch -D <分支名>

174月/13

数据分析这点事

发布在 邵珠庆

 

 先声明一下,按照传统的定义,我还真不是数据分析高手,各种关联算法,只会最简单的一种(话说不少场合还算管用);各种挖掘技术,基本上一窍不通;各种牛逼的数据分析工具,除了最简单的几个免费统计平台之外,基本上一个都不会用。所以,各种高手高高手请随意BS,或自行忽略。这里说点高手不说的。

       从微博段子说起,微博上关于数据分析有两个段子,我经常当作案例讲,第一个段子,说某投资商对某企业所属行业有兴趣,要做背景调查,甲是技术流,一周分析各种网上数据,四处寻找行业材料,天天熬夜,终于写出一份报告;乙是人脉流,和对方高管喝了次酒,请对方核心人员吃了顿饭,所有内幕数据全搞定,问谁的方法是对的;第二个段子,某电商发现竞争对手淘宝店,周收入突然下降了30%,但是隔周后又自然恢复,中间毫无其他异常现象,于是老板让分析师分析,苦逼的分析师辛苦数日,做各种数学模型,总算找到勉强的理由自圆其说,老板读毕,虽说不能让人信服,却也没有更合理的解释,某日,见对手老板,闲聊此事,“你们某段时间怎么突然收入下降?”“嗨,别提了,丈母娘去世了,回家奔丧,公司放羊了。”老板恍然大悟。

       两个段子,第一个段子,微博上一边倒的说,苦逼分析没有人脉有用;第二个段子类似,一边倒的认为,人脉的消息比苦逼分析管用多了。但是我想说的是,这个解读绝对是错的!

       先说第一个段子,其实网络不乏这种“人脉达人”,特别是媒体圈,一些所谓的“IT名记”或者“著名评论家、分析师”和各种互联网大佬称兄道弟,天天秘闻不断,但是呢?他们从不研究产品,不分析用户,所以,他们知道了数据,却不懂数据背后是什么,更不知道什么是重要的,什么是次要的,我有时会批评身边这样的朋友,别天天觉得自己知道几个互联网大佬的花边新闻,就当自己是资深业内人士了,正因为掌握这些东西又觉得炫耀,才反而忽视了真正有价值的信息和有价值的数据。这就是为什么混网络媒体的,见过市面的各种达人,在互联网创业浪潮里,几乎没有成功几率的真实原因,自以为人脉广泛,无所不知,其实正因为缺乏最基本的数据背景分析,所以才是看上去什么都懂,细究下其实什么都不懂。请记住一点,除非你是富二代,官二代,衔着金钥匙出生,那不在我的讨论范围里,否则,没有苦逼的经历,就没有牛逼的成就。

      我常订阅一些著名分析师的微博,他们透露的数据往往是很有价值的(这是我订阅的原因),但是他们的解读通常是惨不忍睹的,这就是只看表象的恶果,而且随便翻看一下他们的数据解读,可以说他们的数据感和数据认知贫乏到可笑,甚至缺乏最基本的数据校核和考证的能力,他们拿到了某公司核心数据又怎样?没经历过苦逼的分析,他们其实什么都看不到。

      第二个段子同理,如果不是持续有效的数据跟踪,怎么能得出下降30%的结论,这一数据结论与人脉得到的消息相互验证,才会得到完整真实的结果,否则仅仅是闲聊,你怎能知道对方企业管理对业绩影响的范畴,苦逼的分析也许一时没有人脉的消息管用,但是你所得到的对数据的认知和积累,是人脉永远不会给你的。

      所以,再次强调,基本的数据跟踪和日常的数据感养成,绝不是可以忽略和无视的。人脉情报可以成为数据解读重要的信息来源,但是绝不能喧宾夺主,替代基本的数据分析工作。

 

     下面说一下数据感,什么是数据感?就是别人说一个数据出来,你会琢磨一下这个是否符合常理,与你日常的数据观测经验是否一致,如果不一致,那么可能的理由是哪些? 比如12306号称一天几十亿次点击,如果你有数据感,第一眼就会质疑这个“点击”定义的合理性;比如曾经有人说某国内图片分享网站一天多少亿访问量,第一眼就知道这个“访问量”定义是有歧义的,(事后官方解释是图片加载量,这个和访问量差异几十倍。) 数据感需要不断的培养,和基本的逻辑(比如你应该知道中国有多少网民,每天有多少人上网,一个大概什么类型,什么排名的网站会覆盖网民的比例是多少),以及善于利用各种工具,我以前在巨头公司,得益于公司巨大的数据资源,可以看到很多互联网的核心数据;但是离开后,才发现,其实互联网上公开可获取的数据途径是非常多的,而且善于利用的话非常有效。每天去查询一些感兴趣的数据,经过一段时间积累,想没有数据感都难。

      作为公司或团队负责人,怎么培养员工的数据感,我其实也有一个建议,平时可以搞一些小的竞猜,比如团队集体竞猜新产品或产品改版上线后的日活跃用户,或者pv数字,或者收入数据,等等;然后看谁的最准,一种是惩罚制,最不准的请最准的喝奶茶,吃冰淇淋;另一种不惩罚,最准的累计积分后公司可以发一些奖品鼓励,这样下去大家的数据感就会在日常培养起来,而且对团队的气氛培养也有帮助。

       数据感之后,谈数据分析的方法,我的建议是,不炫技,不苛求技术复杂度,最简单的数据,所包含的信息往往是最有价值的,而很多人恰恰这一步都没做好,就总想着弄一堆挖掘算法;数据的价值在于正确的解读,而不是处理算法的复杂度,切不可喧宾夺主。 大公司的kpi制度,往往会产生偏差,比如技术工程师的评定,要讲究“技术复杂度”、“技术领先性”,直接导致简单的事情没人肯做,最基本的工作不认真做!所以往往是大公司的分析工程师,为了评高级工程师,非要简单问题复杂化,四则运算就搞定的事情一定要弄一套诡异的算法,最终非但浪费了资源,消耗了时间,而且往往由于工程师对业务理解的漠视,对应的产品人员又对算法的陌生,导致了严重的理解歧义,从而出现各种误读。

 

       下面说关键,数据解读,正确的数据解读,是所有数据分析工作最关键的一步,这一步错了,前面的所有努力都是白搭,然后,往往很多人简单的以为“数据会说话”,他们认为把数据处理完一摆就ok了,所以我看到很多知名分析师拿着正确的数据信口胡诌;而更有甚者,显然是故意的行为,一个非常非常著名的、口碑极佳的跨国企业,曾经就同一份很酷的数据,在不同的场合下,为了市场公关的需求,做出不同的解读;这简直就是道德问题了。

      数据解读,不能是为了迎合谁,要遵循数据的本质,要遵循科学的逻辑,要有想象力(配合求证),可能有时候也需要依赖人脉关系所获得的情报,(这个也有很多典型范例),这个具体再怎么说可能我也说不清楚,说几个反面例子也许更容易理解。

      1、因果关联错误,或忽略关键因素,A和B的数据高度相关,有人就片面认为A影响了B,或者B影响了A;但是,有时候真实原因是C同时影响了A和B,有时候C被忽略掉了。

      2、忽略沉默的大多数,特别是网上投票,调查,极易产生这种偏差,参与者往往有一定的共同诉求,而未参与者往往才是主流用户。

      3、数据定义错误,或理解歧义,在技术与市场、产品人员沟通中产生信息歧义,直接导致所处理的数据和所需求的数据有偏差,结果显著不正确。

      4、强行匹配;不同公司,不同领域的数据定义可能不一致,在同一个公司内或领域内做对比,往往没有问题,大家对此都很习惯,却有评论家不懂装懂,强行将不同定义的数据放在一起对比做结论,显著失真

94月/131

HTML5 开发者需要了解的技巧和工具汇总

发布在 邵珠庆

HTML5现在已经成为了Web开发中的热门话题,大多数现代浏览器(Safari、Chrome,Firefox,IE10和移动设备)都支持HTML5。即使HTML5的规范还没有制定完成,但许多开发者已经将其作为Web开发项目中的主要技术。一些网站巨头,如Google、Facebook、Twitter和YouTube等,都建立在HTML5基础上。 



HTML5中最令人兴奋的功能莫过于画布(canvas)和强大的表单功能,画布功能已经可以在大部分浏览器中完美体验(除了IE),但对于新表单元素的支持还不是太好。对Web开发者来说,是时候开始HTML5开发了。 



要进行HTML5开发,本文中的一些技巧、工具可以让你缩短学习的时间,提高开发的效率。 



一、HTML5支持测试列表 



在开始之前,你需要了解现代的浏览器以及移动平台对于HTML5的支持情况。 

 

二、让HTML5元素可用 



老版本的IE浏览器不能识别新的HTML元素。但是,可以使用一些JavaScript或CSS解决方案来弥补这个缺陷。 

 

  • HTML5Shiv:此脚本可以使IE浏览器识别HTML5元素。
  • HTML5 Enabler:功能与HTML5Shiv类似。
  • Modernizr:它使得开发者可以在支持HTML5和CSS3的浏览器中充分利用HTML5和CSS3的特性进行开发,同时又不会牺牲其他不支持这些新技术的浏览器的控制。
  • HTML5 Reset:它提供了一组HTML、CSS文件,让你能够以最少的时间来启动一个新的项目。它使用modernizr来支持HTML5 和 CSS3。

三、浏览器插件 



下面是一些JavaScript插件,可以弥补一些浏览器对HTML5的支持问题。 



1. VideoJS 



VideoJS是一个HTML5的视频播放器,可以在所有浏览器中使用,包括IE6和移动设备。对于不支持HTML5的浏览器则自动使用Flash播放器来播放。 

 





2. AudioJS 



HTML音频播放器。用来让HTML5 的 <audio> 标签可以在各种浏览器上使用,包括移动设备。 

 





3. HTML5Widget 



HTML5的表单模块,包括日历,调色板,滑动部件,客户端验证等。 

 





4. Webforms2 



HTML5 表单属性的支持,例如pattern、required和autofocus。 

 





5. LimeJS 



LimeJS是HTML5的游戏框架,用于为现代触摸设备和桌面浏览器创建快速、本地化的游戏。 

 





6. FlexieJS 



支持CSS3弹性盒子模型(Flexible Box Model)。 

 





四、在线工具 



此外,还有一些在线工具,可以帮助开发者加快HTML5项目的开发。 



1. HTML5 Boilerplate 



HTML5Boilerplate 是一个HTML / CSS /JS模板,是实现跨浏览器正常化、性能优化、稳定的可选功能如跨域Ajax和Flash的最佳实践。开发者称之为技巧集合,目的是满足你开发一个跨浏览器,并且面向未来的网站的需求。 

 





2. Switch to HTML5 



非常有用的在线工具,可以根据你的喜好生成HTML5文档结构。 

 





3. Initializr 



Initializr是一个HTML5模板生成器,以帮助你开始HTML5项目的开发 。它建立在HTML5 Boilerplate之上。 

 





4. HTML5 Visual 速查表 

 





5. HTML5 Canvas 速查表 

 





6. HTML5 笔记 

 





五、其他 



你可以通过下面的链接来跟踪HTML5的更新。 



HTML5追踪 



你可以通过下面的链接获得HTML5网站的设计灵感。这个网站库中包含了大量的使用HTML5技术的网站。 



HTML5Gallery 



VIA http://www.queness.com/post/9375/tips-tricks-and-tools-you-will-need-to-start-using-html5-today 

34月/130

营销名词解释

发布在 邵珠庆

1. 4C

Customer(客户)、Cost(成本)、Convenience(便利性)、Communication(沟通)

2、4Ps营销理论

产品(Product)、价格(Price)、渠道(Place)、促销(Promotion);策略(Strategy);

3. 6W1H

6W:who-when-where-why-for whom-what

1H:how