• 2009-11-20

    php引用符号(&)的作用 - [php]

    php的引用(就是在变量或者函数、对象等前面加上&符号)

    PHP 中引用的意思是:不同的名字访问同一个变量内容.
    与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容在内存中存放的地址

    变量的引用

    PHP 的引用允许你用两个变量来指向同一个内容

    <?
    $a="ABC";
    $b =&$a;
    echo $a;//这里输出:ABC
    echo $b;//这里输出:ABC
    $b="EFG";
    echo $a;//这里$a的值变为EFG 所以输出EFG
    echo $b;//这里输出EFG
    ?>


    函数的传址调用
    传址调用我就不多说了 下面直接给出代码

    function test(&$a)
    {
    $a=$a+100;
    }
    $b=1;
    echo $b;//输出1
    test($b);  //这里$b传递给函数的其实是$b的变量内容所处的内存地址,通过在函数里改变$a的值 就可以改变$b的值了
    echo "<br>";
    echo $b;//输出101

    要注意的是,在这里test(1);的话就会出错,原因自己去想

    函数的引用返回
    先看代码

    function &test()
    {
    static $b=0;//申明一个静态变量
    $b=$b+1;
    echo $b;
    return $b;
    }

    $a=test();//这条语句会输出 $b的值 为1
    $a=5;
    $a=test();//这条语句会输出 $b的值 为2

    $a=&test();//这条语句会输出 $b的值 为3
    $a=5;
    $a=test();//这条语句会输出 $b的值 为6

    下面解释下: 
    通过这种方式$a=test();得到的其实不是函数的引用返回,这跟普通的函数调用没有区别 至于原因: 这是PHP的规定
    PHP规定通过$a=&test(); 方式得到的才是函数的引用返回
    至于什么是引用返回呢(PHP手册上说:引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。) 这句狗屁话 害我半天没看懂

    用上面的例子来解释就是
    $a=test()方式调用函数,只是将函数的值赋给$a而已, 而$a做任何改变 都不会影响到函数中的$b
    而通过$a=&test()方式调用函数呢, 他的作用是 将return $b中的 $b变量的内存地址与$a变量的内存地址 指向了同一个地方
    即产生了相当于这样的效果($a=&b;) 所以改变$a的值 也同时改变了$b的值 所以在执行了
    $a=&test();
    $a=5;
    以后,$b的值变为了5

    这里是为了让大家理解函数的引用返回才使用静态变量的,其实函数的引用返回多用在对象中

    对象的引用

    <?
    class a{
    var $abc="ABC";
    }
    $b=new a;
    $c=$b;
    echo $b->abc;//这里输出ABC
    echo $c->abc;//这里输出ABC
    $b->abc="DEF";
    echo $c->abc;//这里输出DEF
    ?>

    以上代码是在PHP5中的运行效果
    在PHP5中 对象的复制 是通过引用来实现的。上列中$b=new a; $c=$b; 其实等效于$b=new a; $c=&$b;
    PHP5中默认就是通过引用来调用对象, 但有时你可能想建立一个对象的副本,并希望原来的对象的改变不影响到副本 . 为了这样的目的,PHP定义了一个特殊的方法,称为__clone.

    引用的作用
    如果程序比较大,引用同一个对象的变量比较多,并且希望用完该对象后手工清除它,个人建议用 "&" 方式,然后用$var=null的方式清除. 其它时候还是用php5的默认方式吧. 另外, php5中对于大数组的传递,建议用 "&" 方式, 毕竟节省内存空间使用。


    取消引用
    当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:

    <?php
    $a = 1;
    $b =& $a;
    unset ($a);
    ?>  

    不会 unset $b,只是 $a。


    global 引用
    当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。也就是说和这样做是相同的:

    <?php
    $var =& $GLOBALS["var"];
    ?>  

    这意味着,例如,unset $var 不会 unset 全局变量。

    $this
    在一个对象的方法中,$this 永远是调用它的对象的引用。


    //下面再来个小插曲
    php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。

    通俗的讲
    1:如果有下面的代码

    $a="ABC";
    $b=$a;

    其实此时 $a与$b都是指向同一内存地址 而并不是$a与$b占用不同的内存

    2:如果在上面的代码基础上再加上如下代码

    $a="EFG";

    由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断 自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储

    Tag:php
  • 2009-11-19

    转一个《 浅析豆瓣的 Google Analytics 应用》,备用

    大家好,我是owen,主要从事 Online marketing 方面的工作,平时主要专注于 SEM 和 Web analytics。这次很荣幸能够应 Denis 之邀,在我爱水煮鱼抛砖引玉,发表 Web analytics 方面的文章,希望以后能够在这里,与大家多多交流这方面的知识。今天首先给大家简单谈谈豆瓣网怎么应用 Google Analytics。

    豆瓣 Google Analytics 代码加载模式

    豆瓣从今年开始也加入 Google Analytics 的统计阵营。让我们通过它加载的 Google Analytics 源码,简单分析一下它都是怎么应用的。

    我们先从豆瓣的源码来看看它的Google Analytics统计代码

    豆瓣 Google Analytics 代码
    豆瓣 Google Analytics 代码

    我们知道一般默认的 Google Analytics代码如下:

    默认  Google Analytics 统计代码
    默认 Google Analytics 统计代码

    两相对比,我们就会发现豆瓣加载 ga.js 的方式与默认的方式有些不太一样,由于豆瓣并没有采用 https 加密访问,所以撇弃了默认的ga.js加载方式。

    默认的统计函数,pageTracker 也被豆瓣改成了 _ga ,这个只是名称定义上的区别,并没有什么实质的改变。豆瓣的主要应用是下面两个函数:

    使用 _ga._addOrganic 识别非主流搜索引擎

    再来看豆瓣比默认 Google Analytics 代码增加的部分,那就是多了数个 _ga._addOrganic ,这是 Google Analytics 添加自定义搜索引擎的代码。尽管 Google Analytics 对于主流的搜索引擎都能自动识别,但毕竟能识别的是国外的主流搜索引擎,在国内,像搜狐的 Sogou,QQ 的 soso,网易的有道等搜索引擎,都不能被 Google Analytics 正确识别,而被当作推荐来源。这时候我们就可以利用_addOrganic 参数来识别这些非主流搜索引擎,如豆瓣的做法。

    使用 _addIgnoredOrganic 忽略关键字

    除了添加自定义搜索引擎,豆瓣在最后还添加了如下这些代码:

    _ga._addIgnoredOrganic("豆瓣");
    _ga._addIgnoredOrganic("douban");
    _ga._addIgnoredOrganic("豆瓣网");
    _ga._addIgnoredOrganic("www.douban.com");

    这些代码用来把引号中的关键词从搜索引擎的关键词报告中排除,而当成直接点击量来源。

    为什么要这么做?因为一个知名的大网站,来自这些品牌词的搜索流量都非常大,常常是排在前几位的搜索关键词来源,而这通常是因为搜索引擎养成现在的 人都懒得记网址,直接搜索品牌名来记住域名。这些品牌词对于网站的关键词来源分析并没有很直接的帮助,所以在来自品牌词的流量很大的情况下,可以直接把这 些关键词识别成直接点击量来源。

    关于自定义 Google Analytics 搜索引擎排除特定关键词为直接点击量来源的语法,可以参考 Google Code 上关于这方面的详细介绍。

    通过 _setVar 识别用户

    当我们登录豆瓣后,再来分析豆瓣的源码,会发现多了一个ga._setVar(”xxxx”)的 Google Analytics 参数。

    豆瓣使用 Google Analytics 的._setVar参数来跟踪登录用户行为
    豆瓣使用 Google Analytics 的._setVar参数来跟踪登录用户行为

    _setVar() 函数是 Google Analytics 的用户定义函数,主要用于对特定来源的用户行为进行分类,例如可以对登录浏览的用户设置一个数值,然后在 Google Analytics 后台的访问者/用户定义 中查看其浏览属性。

    Google Analytics 访问者/用户定义报告
    Google Analytics 访问者/用户定义报告

    分析豆瓣的源码可以知道,豆瓣对每一个登录后的用户,都赋以一个专门的 id 值,这样可以在用户定义报告里,看到整体的登录用户访问行为,乃至每个登录用户的浏览行为。通过这样设定后,豆瓣便可以轻易获取高忠诚度访问用户的访问行为。关于_setVar()的更多说明,请参阅 Google Analytics的技术文档

    如何根据访问者在我的网站上访问的页面或在表单上做出的响应对其进行分类?在 Google Analytics 官方的帮助文件,也给出了另外一个应用案例

    值得注意的是,原来在设置 _setVar() 函数的时候,整个网站的跳出率会出现重大的偏差,不过在最近的google analytics官方博客,指出该bug已经修正,客户在进行这方面设置的时候,还是要注意对比前后数据是否有重大偏差。

    通过 _trackPageview 区分不同类型的评论

    豆瓣上的书评,影评和乐评可以说是豆瓣网站的核心价值所在。一般评论的URL格式如下:

    豆瓣上单条评论的URL
    豆瓣上单条评论的URL

    当我们查看该页面的网页源代码时,会发现有趣的现象:

    豆瓣单条评论页的 Google Analytics 代码
    豆瓣单条评论页的 Google Analytics 代码

    我们知道,一般 Google Analytics 的_trackPageview() 括弧中的参数是留空的, Google Analytics 会自动捕获网址的 URL 参数,如果在 _trackPageview()括弧中输入特定的数值,那么在 Google Analytics 的报表中,URL 将是我们指定的参数,而不再是我们在地址栏看到的 URL。

    如上面的例子,我们在 Google Analytics 中看到的URL将是/book/review/1946018/,而不再是我们在浏览器地址栏看到的/review/1946018/

    当所在频道是电影或者音乐时,_trackPageview() 中的参数将根据所在频道的属性,变为/movie/xxxxx 或者 /music/xxxxx的数值。

    豆瓣通过对的参数进行重新指定,主要有以下的好处:

    保证了用户和搜索引擎看到的 URL 比较简短,达到 URL 对用户友好和对搜索引擎友好的目的;而在 Google Analytics 报告中,通过 内容/内容细目/ 报告,又能了解到各个频道总的浏览情况。

    在GA的内容细目报告中,将会多出 /book/ /music/ /movie/ 这样的文件夹来,总而获得各个频道的合计浏览数据。

    而如果只是使用默认 _trackPageview(),你将只能得到所有评论页面的浏览数据,而无法得到细分的各个频道的浏览数据。

    关于_trackPageview()的具体的使用方法可参照 Google Code 的说明

    注意事项:使用 _trackPageview() 参数重新指定 URL 之后,网站覆盖图的数据将受到影响。可参阅 Google Analytics 的官方帮助文件

    除了豆瓣使用 _trackPageview() 来对URL进行重写,大众点评网也采用了类似的做法(应该是比豆瓣更早采用。。。因为是我在点评网任职时候实验的做法;那时候豆瓣还没有使用 Google Analytis 统计代码,呵呵),有兴趣的同学可以自己去研究点评的 Google Analytis 代码。

    Tag:
  • 2009-11-17

    一些PHP的Tips,面试会遇到 - [php]

     

    HTTP协议中几个状态码的含义:503 500 401 200 301 302
        2xx: (成功)
        3xx (重定向)
        4xx: Client Error 使用者端(浏览器)错误讯息
        5xx: Server Error  服务器端错误讯息
        400(错误请求)     服务器不理解请求的语法。
        401(未授权)     请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。
        500(服务器内部错误)     服务器遇到错误,无法完成请求。
        503(服务不可用)     服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。

    Include require include_once require_once 的区别.
        require() :如果文件不存在,会报出一个fatal error.脚本停止执行
        include() : 如果文件不存在,会给出一个 warning,但脚本会继续执行
        _once: 会检测是否包含过了,包含过了就不包含了

    关于HereDOC:
        <?php
        $a = "---------";
        echo <<<HAHA
        $a
        \$a
        HAHA
        ?>
        输出:   -----------
                    $a

    关于php的魔法引用:
        如果php.ini不可改,可以使用.htaccess文件禁用,加入下面的代码 php_flag magic_quotes_gpc Off
        相关函数:stripslashes — 去掉反斜杠,得到原始数据。       addslashes — 使用反斜线引用字符串

        最好设置为OFF,然后自己过滤,在PHP6中已经关闭了,或者用下面的函数:
        if (get_magic_quotes_gpc())
        {
            function stripslashes_deep($value)
            {
                $value = is_array($value)?array_map('stripslashes_deep',$value):stripslashes($value);
                return $value;
            }
            $_GET     = array_map('stripslashes_deep', $_GET);
            $_POST    = array_map('stripslashes_deep', $_POST);
            $_COOKIE  = array_map('stripslashes_deep', $_COOKIE);
            $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
        }

    一些编译php时的configure 参数
    1.作为APACHE模块编译
    –with-apxs2
    2.作为fastcgi编译
    –enable-fastcgi
    –enable-force-cgi-redirect
    3.动态加载PHP的extension
    加载模块的后面加上shared关键词
    例如–with-gd=shared
    4.enable的扩展选项一样可以使用shared关键词作为外部扩展模块载入
    5.with-EXTENSIONS-dir和单纯的with-EXTENSIONS的作用相同
    同样是指定加载特定模块
    只是可以指定目录
    ./configure --prefix=/usr/local/php --with-config-file-path=/etc \
    --with-apxs2 --enable-fastcgi --enable-force-cgi-redirect \
    --with-gd=shared \
    --with-jpeg-dir \
    --with-png-dir \
    --with-zlib-dir \
    --enable-gd-native-ttf \
    --with-freetype-dir=shared \
    --with-zlib=shared \
    --with-mysql=shared \
    --with-mcrypt=shared \
    --with-pear=shared \
    --with-curl=shared \
    --with-curlwrappers=shared \
    --with-xmlrpc=shared \
    --without-sqlite --disable-debug --disable-rpath \
    --enable-mbstring=shared \
    --enable-exif=shared \
    --enable-zip=shared \
    --enable-ftp=shared

    Safe_mode 打开后哪些地方受限.
    启动safe_mode,会对许多PHP函数进行限制,特别是和系统相关的文件打开、命令执行等函数。

    解决多进程/线程同时读写一个文件的问题

    对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!!用一般的文件操作方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失。

    对于这样的问题,一般的解决方案时当一进程对文件进行操作时,首先对其它进行加锁
    所以一般的方案是:
    $fp = fopen("/tmp/lock.txt", "w+");
    if (flock($fp, LOCK_EX)) {
        fwrite($fp, "Write something here\n");
        flock($fp, LOCK_UN);
    } else {
        echo "Couldn't lock the file !";
    }
    fclose($fp);

    但在PHP中,flock似乎工作的不是那么好!在多并发情况下,似乎是经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器的cpu占用很高,甚至有时候会让服务器彻底死掉。好像在很多linux/unix系统中,都会有这样的情况发生。

    如果不考虑使用flock()函数,也同样会有很好的解决方案来解决我们的问题。
    方案一:对文件进行加锁时,设置一个超时时间.

    if($fp = fopen($fileName, 'a')) {
        $startTime = microtime();
        do {
                $canWrite = flock($fp, LOCK_EX);
            if(!$canWrite) usleep(round(rand(0, 100)*1000));
        } while ((!$canWrite) && ((microtime()-$startTime) &lt; 1000));
        if ($canWrite) {
          fwrite($fp, $dataToSave);
        }
        fclose($fp);
    }
    超时设置为1ms,如果这里时间内没有获得锁,就反复获得,直接获得到对文件操作权为止,当然。如果超时限制已到,就必需马上退出,让出锁让其它进程来进行操作。
    方案二:不使用flock函数,借用临时文件来解决读写冲突的问题。
    大致原理如下:
    1。将需要更新的文件考虑一份到我们的临时文件目录,将文件最后修改时间保存到一个变量,并为这个临时文件取一个随机的,不容易重复的文件名。
    2。当对这个临时文件进行更新后,再检测原文件的最后更新时间和先前所保存的时间是否一致。
    3。如果最后一次修改时间一致,就将所修改的临时文件重命名到原文件,为了确保文件状态同步更新,所以需要清除一下文件状态。
    4。但是,如果最后一次修改时间和先前所保存的一致,这说明在这期间,原文件已经被修改过,这时,需要把临时文件删除,然后返回false,说明文件这时有其它进程在进行操作。

    方案四:将所有要操作的进程放入一个队列中。然后专门放一个服务完成文件操作。
    队列中的每一个排除的进程相当于第一个具体的操作,所以第一次我们的服务只需要从队列中取得相当于具体操作事项就可以了,如果这里还有大量的文件操作进程,没关系,排到我们的队列后面即可,只要愿意排,队列的多长都没关系。
    参考:http://hqlong.com/2009/01/530.html

    使用mod_rewrite,在服务器上没有/archivers/567.html这个物理文件时,重定向到index.php?id=567

    先php.ini配置中打开mod_rewrite。然后在.htaccess文件中写入:ErrorDocument 404 index.php?id=567

    对于大流量的网站,您采用什么样的方法来解决各页面访问量统计问题

    网站性能优化 提高网站访问速度的14条实践规则

    具体参考:提高网站性能的14条法则:http://www.629d.com/a/200907/62.html

    主要:

    第一条、尽可能的减少 HTTP 的请求数 (Make Fewer HTTP Requests )
    第二条、使用CDN(内容分发网络): Use a Content Delivery Network
    第三条、 添加Expire/Cache-Control 头:Add an Expires Header
    第五条、将css放在页面最上面 ( Put Stylesheets at the Top)
    第六条、将script放在页面最下面 (Put Scripts at the Bottom )


    Tag:php tips
  • 2009-11-17

    应该具有什么样的技能,才算得上PHP程序员?

    应该具有什么样的技能,才算得上PHP程序员?你的技术又是在什么水平级别上? CU上的BS同学写了以下文章。欢迎各位对号入座。

    1、PHP编程能力

    说不清,留空

    2、MySQL能力
    在开发上的应用基于几个能力体现:
    1、了解:知道用PHP连接数据库;懂得写一些简单的SQL;建一些简单的索引;懂得用工具简单操作一下数据库(增删改库表结构数据等等)。
    2、熟悉:懂得在开发应用上设计数据库,建立一些有效的索引,用explain分析SQL性能,压力测试等等。
    3、很熟悉:深入了解数据库索引、存储引擎原理以及运行机制,能有效地构建高性能可扩展的数据库结构/架构,有效地优化数据库性能配置并加以调试,分析数据库运行状态。
    4、精通:简单地说具备以上所有能力的同时,有多年高负载分布式环境下的优化管理经验。


    据我观察以及交往经验,70%的PHPer处在了解阶段,25%处于熟悉阶段,>4%很熟悉,精通的人基本就不是phper了。

    70%这个群体最容易忽视MySQL,以为MySQL只是简单的存储媒介,没有优化意识,认为加个内存、CPU就能解决问题。
    典型事件:join、order by、group by等语句性能一塌糊涂,数据库根本没有设计(仅限于拆成一个主表,N个附表等),搞不清字段类型及作用,碰到大表的复杂查询就没辙。

    20%这个群体的人只是MySQL运行机制理解不透彻,对影响MySQL性能的关健因素把握不明确,不熟练。
    典型事件:熟读手册,但说不清索引原理,不知道二叉树、HASH等算法对于数据库的作用

    >4%的群体已经基本可以胜任DBA的职能。

    3、OOP能力
    1、了解:了解变量的作用域、类型,及其意义,了解继承机制等,懂得复用、封装概念。
    2、熟悉:熟练应用接口、抽象等技术混合开发程序,并理解其中含义,一般研究过JAVA。
    3、很熟悉:有过OOP架构设计经验,熟悉设计模式、UML,熟悉PHP对象运行机制,内容管理等。
    4、精通:应该是架构师级别了,不限于PHP。

    经常我们会碰到一些自称熟悉OOP却连public、private、protected、static都解释不清的人,是肯定没有经历过正规的OOP项目。

    4、大型网站经验
    1、了解:熟悉PHP开发下的缓存应用(memcache、APC等);接触过LVS、SQUID应用;
    有一定的session处理方案;熟悉负载均衡;熟悉PHP数据连接池应用;了解PHP编程性能优化。
    2、熟悉:掌握分布式缓存及缓存性能优化、熟悉存储系统、文件系统、数据库,开发可扩展平台。能结合负载均衡合理布置流量,对PHP运行性能进行监控与分析。
    3、非常熟悉:具备系统分析师能力,已经超出phper环节...
    4、精通:太深奥..

    5、DOM开发能力
    留空

    6、*nux应用能力
    ...
    ------------------------------------------------------------------------------------------------

    路漫漫其修远兮,吾将上下而求索

    Tag:
  • 2009-11-11

    我的第一个python脚本 - [python]

    呵呵,最近在学习python,只明白了大概,很多还不会,不熟悉。现在放一个python程序,目标是:遍历文件夹里的torrent文件,分析hash info 加密后是否跟原文件的文件名相同,不同的话,记录log文件。我写起来有点复杂,感觉还不是按照python的思维来写程序,要学的还很多。

    #! /usr/bin/python

    from sys import *
    from bencode import *
    import hashlib
    import os
    import os.path

    #-----test-----
    #if len(argv) != 2:
    #    print "ERROR: use ./33.py filename"
    #    exit(2)
    #file_name = argv[1]
    #-----test-----

    def check_torrent_hash(file_name):
        filename ='torrent/'+file_name
        metainfo_file = open(filename, 'rb')
        if metainfo_file:
            metainfo = bdecode(metainfo_file.read())
        else:
            print "ERROR: Not a valid torrent file"
            exit(1)
        metainfo_file.close()
        info = metainfo['info']
        hahaha =  bencode(info)
        mySha1 = hashlib.sha1()   
        mySha1.update(hahaha)
        mySha1_Digest = mySha1.hexdigest()
        up_str = mySha1_Digest.upper();
        OK = file_name.split('.')   
        #print up_str
        #print OK[0]
        if not up_str==OK[0]:
            error_file = open('/home/changyou/wget/error.log', 'a+')
            error_file.writelines(up_str+'\n')
            error_file.close()
            return 'NO~~please check /home/changyou/wget/error.log'
        else:
            return 'OK!!!'

    rootdir = "/home/changyou/wget/torrent/"
    for parent, dirnames, filenames in os.walk(rootdir):
        for filename in filenames:
            print check_torrent_hash(filename)


     

  • 2009-11-10

    python取BT种子的hashinfo - [python]

    折腾了1天,BT果然是变态,名副其实。

    BT是python编写,他的种子文件时以Bencoding编码格式编码,具体如下
    无论是web服务器提供的那个.torrent文件,还是peers和trackers进行的信息交互,都是基于Bencoding格式的。
    1 字符串:首先是字符串长度,然后是一个:号,接着是串内容,比如5:hello,就是指hello这个字符串。
    2 整数:以“i”开头(int的意思),然后是十进制数字,最后是一个“e”结尾,如i3e表示3,i-3e表示-3,i0e表示0,i-0e是非法的。
    3 列表:以“l”开头(list的意思),以“e”结尾。比如 l5:hello5:worldi1234ee 代表 ["hello","world",1234]
    4 字典:以“d”开头(dictionary),以“e”结尾。比如 d3:cow3:moo4:spam4:eggse,则代表{"cow":"moo", "spam","eggs"}

    这里,我们要取的info是种子文件里‘字典’info后面的所有(包括d,到最后的包括e),很长一串。

    最开始写了一个PHP脚本,只是分析的种子文件,只是把种子文件里的数据用数组的形式显,然后用函数sha1(),结果得到的hashinfo不正确。崩溃ing

    后来google了下,发现用python比较靠谱,因为有现成的模块,代码如下:

    #! /usr/bin/python
    ffrom sys import *
    from bencode import *
    import hashlib

    mySha1 = hashlib.sha1()  //新建对象
    if len(argv) != 2:
        print "ERROR: use ./hash_info.py filename"

        exit(2)
    filename = argv[1]
    metainfo_file = open(filename, 'rb')
    try:
        metainfo = bdecode(metainfo_file.read())
    except ValueError:
        print "ERROR: Not a valid torrent file"
        exit(1)
    metainfo_file.close()
    info = metainfo['info'] //取列表的info
    hahaha =  bencode(info) //取torrent的info

    mySha1.update(hahaha)
    mySha1_Digest = mySha1.hexdigest()
    print mySha1_Digest  //得到info sha加密后的数据!!

    ---------------------------------------------------------------------

    注意:在linux下自带的python里没有hashlib模块,和bencod模块

    需要下载安装,hashlib     http://code.krypto.org/python/hashlib/

    bencod需要下载BitTorrent源码,或者下载单独文件:http://www.pinking.net.cn/scrip/bencode.py,跟脚本程序放在同一目录下即可