我是靠谱客的博主 自然楼房,这篇文章主要介绍php解析bt,PHP基于闭包思想实现的BT(torrent)文件解析工具实例详解,现在分享给大家,希望可以做个参考。

PHP基于闭包思想实现的BT(torrent)文件解析工具实例详解

发布于 2017-09-08 20:05:36 | 124 次阅读 | 评论: 0 | 来源: 网友投递

PHP开源脚本语言PHP(外文名: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,入门门槛较低,易于学习,使用广泛,主要适用于Web开发领域。PHP的文件后缀名为php。

这篇文章主要介绍了PHP基于闭包思想实现的BT(torrent)文件解析工具,结合具体实例形式分析了php针对torrent文件的读取与解析相关操作技巧,需要的朋友可以参考下

本文实例讲述了PHP基于闭包思想实现的torrent文件解析工具。分享给大家供大家参考,具体如下:

PHP对静态词法域的支持有点奇怪,内部匿名函数必须在参数列表后面加上use关键字,显式的说明想要使用哪些外层函数的局部变量。

function count_down($count)

{

return $func = function()

use($count,$func)

{

if(--$count > 0)

$func();

echo "wown";

};

}

$foo = count_down(3);

$foo();

我本来是想这样的。但是不行,会在第7行调用$func的时候报错。

错误是Fatal error: Function name must be a string in - on line 7

反复试验后发觉,外部的匿名函数应该通过引用传值传给内部,否则是不行的:

function count_down($count)

{

return $foo = function()

use(&$count,&$foo)

{

echo $count."n";

if(--$count > 0)

$foo();

};

}

$foo = count_down(4);

$foo();

像上面这样写就对了。

下面是另一种方法:

function count_down_again($count)

{

return function()use($count)

{

printf("wow %dn",$count);

return --$count;

};

}

$foo = count_down_again(5);

while($foo() >0);

不过,这段代码有点小错误。编译虽然没错,但是$foo函数每次返回的都是4.

也就是use关键字看上去像是支持静态词法域的,在这个例子上,它只是对外层函数使用的变量作了一个简单拷贝。

让我们稍微修改一下,把第3行的use($count)改为use(&$count):

function count_down_again($count)

{

return function()use(&$count)

{

printf("wow %dn",$count);

return --$count;

};

}

$foo = count_down_again(5);

while($foo() >0);

这样才正确。

我个人使用的方式是基于类的,做成了类似下面的形式:

class Foo

{

public function __invoke($count)

{

if($count > 0)

$this($count - 1);

echo "wown";

}

}

$foo = new Foo();

$foo(4);

这样做的行为也是正确的。

这样不会像前一个例子那样失去了递归调用的能力。

虽然这是一个类,但是只不过是在手动实现那些支持闭包和静态词法域的语言中,编译器自动实现的动作。

其实今天早上,我本来准备用类scheme的风格写一个解析器的。可能稍微晚点吧。scheme风格的函数式编程是这样的:

function yet_another_count_down($func,$count)

{

$func($count);

if($count > 0)

yet_another_count_down($func,$count - 1);

}

yet_another_count_down(function($var){echo $var."n";},6);

它不是很依赖静态词法域,虽然scheme对静态词法域的支持还是很不错的。它主要还是利用了first-class-function。当然,这也是一种典型的闭包。

我实现的torrent解析工具的代码如下:

$file_name = '1.torrent';

$file = fopen($file_name,'r');

$nil = new Parser($file);//构造解析器

$nil = $nil();//进行解析

$pos = ftell($file);

echo '读取到文件位置'.sprintf('0x%08X',$pos)."rn";

fseek($file,0,SEEK_END);

echo '还剩下'.(ftell($file) - $pos).'字节未读取'."rn";

if(!feof($file))

{

echo '文件还未结束,再读一个字符:';

$ch = fgetc($file);

if(is_string($ch) && ereg('w',$ch))

{

echo $ch."rn";

}

else

{

printf('0x%02X',$ch);

echo "rn";

}

echo '现在的文件位置是'.sprintf('0x%08X',ftell($file))."rn";

echo '文件'.(feof($file)?'已结束':'还未结束')."rn";

}

fclose($file);//解析器后面不再工作了,此时可以释放文件指针了。

$info = @$nil['value'][0]['info'];

if(!$info)

{

echo '这是一个有效的B-Encoding文件,但它不是一个有效的种子文件';

exit();

}

$name = $info['name.utf-8'] ?$info['name.utf-8']:$info['name'];

if(!$name)

{

echo '这是一个有效的B-Encoding文件,但它不是一个有效的种子文件';

exit();

}

echo $name."rn";

if($info['files'])

{

$index = 0;

foreach($info['files'] as $f)

{

$index += 1;

$path = $f['path.utf8'] ?$f['path.utf8'] :$f['path'];

if(!$path)

{

echo '文件列表中的第'.$index."个文件不含目录rn";

continue;

}

if(0 === strpos($path[0],"_____padding_file_"))continue;

$under_folder = false;

foreach($path as $item)

{

if($under_folder)

{

echo '/';

}else{

$under_folder = true;

}

echo $item;

}

echo "rn";

}

}

else

{

echo "仅有一个文件rn";

}

class Parser

{

private $_file;

public function __construct($file)

{

$this ->_file = $file;

}

public function __invoke($parent = array())

{

$ch = $this ->read();

switch($ch)

{

case 'i':

{

$n = $ch;

while(($ch = $this ->read()) != 'e')

{

if(!is_numeric($ch))

{

echo '在';

echo sprintf(

'0x%08X',ftell($this ->_file));

echo '解析数字时遇到错误',"rn";

echo '在i和e之间不应该出现非数字字符'."rn";

echo '意外的字符'.sprintf('0x%02X',$ch);

exit();

}

else

{

$n .= $ch;

}

}

$n += 0;

$offset = count($parent['value']);

$parent['value'][$offset] = $n;

return $parent;

}

break;

case 'd':

{

$node = array();

//这个$node变量作为字典对象准备加入到$parent的孩子节点中去

//$node['type'] = 'd';

while('e' != ($tmp = $this($node)))

{//每次给$node带来一个新孩子

$node = $tmp;

}

$child_count = count($node['value']);

if($child_count % 2 != 0)

{

echo '解析结尾于';

echo sprintf('0x%08X',ftell($this ->_file));

echo '的字典时遇到错误:'."rn";

echo '字典的对象映射不匹配';

exit();

}

$product = array();

for($i = 0; $i < $child_count; $i += 2)

{

$key = $node['value'][$i];

$value = $node['value'][$i + 1];

if(!is_string($key))

{

echo '无效的字典结尾于';

echo sprintf('0x%08X',ftell($this ->_file));

echo ":rn";

echo '解析[k => v]配对时遇到错误,k应为字符串';

exit();

}

$product[$key] = $value;

}

/*

* 思想是这样的:子节点想要加入父节点时,

* 往父节点的value数组添加。

* 当父节点收集好所需的信息后,

* 父节点自身再从它的value节点整合内容

* 对于字典和列表统一这样处理会大大降低代码量

*/

$offset = count($parent['value']);

$parent['value'][$offset] = $product;

return $parent;

}

break;

case 'l';

{

$node = array();

while('e' != ($tmp = $this($node)))

{

$node = $tmp;

}

$offset = count($parent['value']);

$parent['value'][$offset] = $node['value'];

return $parent;

}

break;

case 'e':

return 'e';

break;

default:

{

if(!is_numeric($ch))

{

$this ->unexpected_character(

ftell($this ->_file) - 1,$ch);

}

$n = $ch;

while(($ch = $this ->read()) != ':')

{

$n .= $ch;

if(!is_numeric($n))

{

unexpected_character(

ftell($this ->_file) - 1,$ch);

}

}

$n += 0;

$str = '';

for(; $n > 0; --$n)

{

$str .= $this ->read();

}

$offset = count($parent['value']);

$parent['value'][$offset] = $str;

return $parent;

}

break;

}

}

/*

* read函数包裹了$this ->_file变量

*/

function read()

{

if(!feof($this ->_file))

{

return fgetc($this ->_file);

}else{

echo '意外的文件结束';

exit();

}

}

/*

* unexpected_character函数接收2个参数

* 它用于指明脚本在何处遇到了哪个不合法的字符,

* 并在返回前终止脚本的运行。

*/

function unexpected_character($pos,$val)

{

$hex_pos = sprintf("0x%08X",$pos);

$hex_val = sprintf("0x%02X",$val);

echo 'Unexpected Character At Position ';

echo $hex_pos.' , Value '.$hex_val."rn";

echo "Analysing Process Teminated.";

exit();

}

}

?>

这里很有趣的是,明明我对文件调用了fseek($file,0,SEEK_END);移动到文件末尾了,但是feof还是报告说文件没有结束,并且fgetc返回一个0,而没有报错。但是此时文件实际上已经到末尾了。

希望本文所述对大家PHP程序设计有所帮助。

相关阅读:

PHP基于闭包思想实现的BT(torrent)文件解析工具实例详解

php基于闭包实现函数的自调用(递归)实例分析

PHP基于单例模式实现的mysql类

PHP基于单例模式实现的数据库操作基类

php的$_FILES的临时储存文件与回收机制详解

PHP数据的提交与过滤基本操作实例详解

PHP文件上传实例详解!!!

php源码之将图片转化为data/base64数据流实例详解

php 修改上传文件大小限制实例详解

PHP中闭包的使用示例

php基于双向循环队列实现历史记录的前进后退等功能

php基于mcrypt_encrypt和mcrypt_decrypt实现字符串加密解密的方法

最后

以上就是自然楼房最近收集整理的关于php解析bt,PHP基于闭包思想实现的BT(torrent)文件解析工具实例详解的全部内容,更多相关php解析bt,PHP基于闭包思想实现内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(118)

评论列表共有 0 条评论

立即
投稿
返回
顶部