引言
在文章《php 实现类似于pyhon中的Contruct库的功能(一) 基本设计思路》介绍了用php解析二进制数据的基本思路
在文章《php 实现类似于pyhon中的Contruct库的功能(二)实现适配器功能》说明了如何实现适配器功能。
在文章《php 实现类似于pyhon中的Contruct库的功能(三)实现if-else功能》说明了如何if-else功能。
这一次要实现的是do-while功能。
推荐PHP视频教程:https://www.php.cn/course/list/29/type/2.html
基本思路
1,修改词法分析规则,使其可以接受do,while关键字,为了引用内部变量,还需要识别 $ 符号
2,修改语法分析规则,使其可以接受do,while语句
3,修改编码器,生成可运行的php目标代码
4,目标代码的模板文件也要做一些小的修改
其中主要的工作内容还是修改语法分析规则文件。
实现内容
准备解析的结构体定义文件
struct student { char name[2]; do{ int; }while($lastError == 0); };
为了聚焦在do-while功能的实现上,这次只定义了一个结构体 student。循环语句定义如下:
do{ int; }while($lastError == 0);
解析过程中有一个内部变量 $lastError,保存每次解析的错误代号,如果为0则表示没有错误。
下面是完整的语法规则处理文件的内容
<?php /*! * structwkr的语法规则处理器 * 45022300@qq.com * Version 0.9.0 * * Copyright 2019, Zhu Hui * Released under the MIT license */ namespace Ados; require_once 'const.php'; require_once __SCRIPTCORE__.'syntax_rule/base_rules_handler.php'; class StructwkrRulesHandler extends BaseRulesHandler{ //语法分析的起始记号,归约到最后得到就是若干个结构体定义的列表 function startToken(){ return '_structList'; } //求出放在附加信息中的数组长度 function elementSize($extraArray){ if(count($extraArray)>0){ return intval($extraArray[0]); }else{ return 0; } } //二元操作符的通用处理函数 function biOpertors($stack,$op1Index,$op,$op2Index,$coder){ $t1= $this->topItem($stack,$op1Index); $exp1=$t1[TokenValueIndex]; $t2= $this->topItem($stack,$op2Index); $exp2=$t2[TokenValueIndex]; $s=$exp1.$op.$exp2; return [$s,[]]; } //处理移进,返回附加信息数组 function handleShift($tokenName,$stack,$coder){ if($tokenName=='_if'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } if($tokenName=='_else'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } if($tokenName=='_do'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 $coder->isInLoop = True; return [$coder->pushLine('')]; } if($tokenName=='_while'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } return []; } //语法规则处理函数名由规则右边部分与规则左边部分拼接而成 //语法规则定义的先后决定了归约时匹配的顺序,要根据实际的语法安排 //如果不熟悉语法,随意调整语法规则的先后次序将有可能导致语法错误 // struct list {{{ function _structList_0_structList_struct($stack,$coder){ $coder->pushBlockTail(); return ['#',[]]; } function _structList_0_struct($stack,$coder){ $coder->pushBlockTail(); return ['#',[]]; } // struct list }}} // struct {{{ function _struct_0_structName_blockStatement_semi($stack,$coder){ $t1= $this->topItem($stack,3); $structName = $t1[TokenValueIndex]; $t2= $this->topItem($stack,2); $extraArray=$t2[TokenExtraIndex]; return [$structName,$extraArray]; } // struct }}} // struct name {{{ function _structName_0_strukey_iden($stack,$coder){ $t1= $this->topItem($stack,1); $structName = $t1[TokenValueIndex]; $coder->pushBlockHeader($structName); return $this->pass($stack,1); } // struct name }}} // blockStatement {{{ function _blockStatement_0_lcb_statementList_rcb($stack,$coder){ return $this->pass($stack,2); } // blockStatement }}} // statement list {{{ function _statementList_0_statementList_statement($stack,$coder){ return $this->pass($stack,1); } function _statementList_0_statement($stack,$coder){ //此处0表示statementList是上一级节点,要做特殊处理 return $this->pass($stack,1); } // statement list }}} // statement {{{ function _statement_0_wholeExpression_semi($stack,$coder){ $t1= $this->topItem($stack,2); $elementName = $t1[TokenValueIndex]; $coder->pushCheckBody($elementName); return $this->pass($stack,2); } // statement }}} // if {{{ function _statement_0_ifStatement($stack,$coder){ return $this->pass($stack,1); } function _ifStatement_0_ifStatement_else_blockStatement($stack,$coder){ //取出_else 记号中保存的空白行所在的地址,替换为正确的内容 $t1= $this->topItem($stack,2); $lineIndex=$t1[TokenExtraIndex][0]; $content='else{'; $coder->resetLine($lineIndex,$content); $coder->pushLine('}'); return $this->pass($stack,3); } function _ifStatement_0_if_wholeExpression_blockStatement($stack,$coder){ //取出_if 记号中保存的空白行所在的地址,替换为正确的内容 $t1= $this->topItem($stack,3); $lineIndex=$t1[TokenExtraIndex][0]; $t2= $this->topItem($stack,2); $condtionExp=$t2[TokenValueIndex]; $content='if'.$condtionExp.'{'; $coder->resetLine($lineIndex,$content); $coder->pushLine('}'); return $this->pass($stack,3); } // if }}} // do while {{{ function _statement_0_whileStatement($stack,$coder){ return $this->pass($stack,1); } function _whileStatement_0_doBlock_whileExpression_semi($stack,$coder){ $t1= $this->topItem($stack,2); $condtionExp=$t1[TokenValueIndex]; $content='while('.$condtionExp.');'; $coder->pushLine($content); $coder->isInLoop = False; return $this->pass($stack,3); } function _whileExpression_0_whileLp_wholeExpression_rp($stack,$coder){ return $this->pass($stack,2); } function _whileLp_0_while_lp($stack,$coder){ return $this->pass($stack,2); } function _doBlock_0_do_blockStatement($stack,$coder){ //取出_do 记号中保存的空白行所在的地址,替换为正确的内容 $t1= $this->topItem($stack,2); $lineIndex=$t1[TokenExtraIndex][0]; $content='do {'; $coder->resetLine($lineIndex,$content); $coder->pushLine('}'); return $this->pass($stack,1); } // do while }}} // function expression {{{ //函数表达式 function _term_0_funcTerm($stack,$coder){ $t1= $this->topItem($stack,1); $funcName=$t1[TokenValueIndex]; $paraArray=$t1[TokenExtraIndex]; $paras = implode(",", $paraArray); $exp = $funcName.'('.$paras.')'; return [$exp,[]]; } function _funcTerm_0_funcExpLp_rp($stack,$coder){ return $this->pass($stack,2); } function _funcTerm_0_funcExpLeft_rp($stack,$coder){ return $this->pass($stack,2); } function _funcExpLeft_0_funcExpLeft_comma_expression($stack,$coder){ $t1= $this->topItem($stack,3); $t2= $this->topItem($stack,1); //函数的参数列表存放在附加信息中 $paraArray=$t1[TokenExtraIndex]; array_push($paraArray, $t2[TokenValueIndex]); return [$t1[TokenValueIndex],$paraArray]; } function _funcExpLeft_0_funcExpLp_expression($stack,$coder){ $t1= $this->topItem($stack,2); $t2= $this->topItem($stack,1); //函数的参数列表存放在附加信息中 $paraArray=$t1[TokenExtraIndex]; array_push($paraArray, $t2[TokenValueIndex]); return [$t1[TokenValueIndex],$paraArray]; } function _funcExpLp_0_iden_lp($stack,$coder){ return $this->pass($stack,2); } // function expression }}} // whole Expression {{{ function _wholeExpression_0_wholeExpression_bieq_expression($stack,$coder){ return $this->biOpertors($stack,3,'==',1,$coder); } function _wholeExpression_0_expression($stack,$coder){ return $this->pass($stack,1); } // whole Expression }}} // Expression {{{ //表达式可以进行管道运算 function _expression_0_expression_pipe_factor($stack,$coder){ $t1= $this->topItem($stack,1); $handlerName = $t1[TokenValueIndex]; $t2= $this->topItem($stack,3); $elementName = $t2[TokenValueIndex]; $coder->pushPipeBody($handlerName,$elementName); return $this->pass($stack,3); } function _expression_0_double_factor($stack,$coder){ $t1= $this->topItem($stack,1); $elementName = $t1[TokenValueIndex]; $parseFuncName = 'parseDouble'; $coder->pushParseBody($parseFuncName,$elementName); return $this->pass($stack,1); } function _expression_0_float_factor($stack,$coder){ $t1= $this->topItem($stack,1); $elementName = $t1[TokenValueIndex]; $parseFuncName = 'parseFloat'; $coder->pushParseBody($parseFuncName,$elementName); return $this->pass($stack,1); } function _expression_0_char_factor($stack,$coder){ $t1= $this->topItem($stack,1); $elementName = $t1[TokenValueIndex]; $size = $this->elementSize($t1[TokenExtraIndex]); $parseFuncName = 'parseFixStr'; $coder->pushParseBody($parseFuncName,$elementName,$size); return $this->pass($stack,1); } function _expression_0_int_factor($stack,$coder){ $t1= $this->topItem($stack,1); $elementName = $t1[TokenValueIndex]; $parseFuncName = 'parseInt'; $coder->pushParseBody($parseFuncName,$elementName,4); return $this->pass($stack,1); } function _expression_0_int($stack,$coder){ $elementName = ''; $parseFuncName = 'parseInt'; $coder->pushParseBody($parseFuncName,$elementName,4); return ['',[]]; } function _expression_0_factor($stack,$coder){ return $this->pass($stack,1); } // Expression }}} // factor {{{ function _factor_0_term($stack,$coder){ return $this->pass($stack,1); } // factor }}} // term {{{ function _term_0_lp_wholeExpression_rp($stack,$coder){ $t1= $this->topItem($stack,2); $s='('.$t1[TokenValueIndex].')'; return [$s,[]]; } function _term_0_term_dot_iden($stack,$coder){ $t1= $this->topItem($stack,3); $obj = $t1[TokenValueIndex]; $t2= $this->topItem($stack,1); $var = $t2[TokenValueIndex]; $exp = '$'.$obj.'[\''.$var.'\']'; return [$exp,[]]; } function _term_0_dollar_iden($stack,$coder){ $t1= $this->topItem($stack,1); $exp = '$'.$t1[TokenValueIndex]; return [$exp,[]]; } function _term_0_iden($stack,$coder){ $t1= $this->topItem($stack,1); //未指定数据长度时将长度值设为0 $valLen = '0'; $t2= $this->topItem($stack,2); return [$t1[TokenValueIndex],[$valLen]]; } function _term_0_num($stack,$coder){ return $this->pass($stack,1); } function _term_0_array($stack,$coder){ return $this->pass($stack,1); } // term }}} // array {{{ function _array_0_arrayLb_num_rb($stack,$coder){ $t1= $this->topItem($stack,2); $valLen = $t1[TokenValueIndex]; $t2= $this->topItem($stack,3); //将数据长度放入附加信息 return [$t2[TokenValueIndex],[$valLen]]; } function _arrayLb_0_iden_lb($stack,$coder){ return $this->pass($stack,2); } // array }}} }// end of class
下面是改进过后的编码器的内容
<?php /*! * structwkr编码器, * * 45022300@qq.com * Version 0.9.0 * * Copyright 2019, Zhu Hui * Released under the MIT license */ namespace Ados; require_once __SCRIPTCORE__.'coder/base_coder.php'; require_once __STRUCT_PARSE_TEMP__.'templateReplaceFuncs.php'; class StructwkrCoder extends BaseCoder{ public function __construct($engine) { if($engine){ $this->engine = $engine; }else{ exit('the engine is not valid in StructwkrCoder construct.'); } $this->isInLoop = False; } //编译得到的最终结果 public function codeLines(){ if(count($this->codeLines)<1){ return ''; } $script=''; for ($i=0;$i< count($this->codeLines);$i+=1) { $script.=$this->codeLines[$i]; } return $script; } //输出编译后的结果 public function printCodeLines(){ echo $this->codeLines(); } //添加一个块解析函数头 public function pushLine($content){ array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; } //重置一行的内容 public function resetLine($lineIndex,$line){ $this->codeLines[$lineIndex]=$line; } //添加一个块解析函数头 public function pushBlockHeader($structName){ $structName=ucfirst($structName); $content = makeBlockHeader($structName); return $this->pushLine($content); } //添加一个块解析函数体 public function pushParseBody($parseFuncName,$filedName='',$filedSize=0){ $content = makeParseBody($parseFuncName,$filedName,$filedSize); return $this->pushLine($content); } //添加一个管道处理 public function pushPipeBody($handler,$filedName=''){ $content = makePipeBody($handler,$filedName); return $this->pushLine($content); } //添加一个检查结果值的body public function pushCheckBody($filedName=''){ if($this->isInLoop){ $content = makeCheckBodyInLoop($filedName); }else{ $content = makeCheckBody($filedName); } return $this->pushLine($content); } //添加一个块解析类的tail public function pushBlockTail(){ $content = makeblockTail(); return $this->pushLine($content); } }
实现结果
自动生成的测试文件如下
<?php namespace Ados; //加载常量定义文件 require_once 'const.php'; require_once __STRUCT_PARSE_TEMP__.'templateBuidinFuncs.php'; require_once __STRUCT_PARSE_ADAPTER__.'int2str.adapter.php'; require_once __STRUCT_PARSE_ADAPTER__.'intoffset.adapter.php'; $context['pos']=0; $context['data']="\x41\x42\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43"; $expRes = Student::parse($context); $context['pos']+=$expRes['size']; print_r($expRes); /* $expRes = Teacher::parse($context); $context['pos']+=$expRes['size']; print_r($expRes); */ class Student{ static function parse($context,$size=0){ $valueArray=[]; $totalSize = 0; $name = parseFixStr($context,2); $lastError = $name['error']; /*checkBodyInLoop{{*/ if($name['error']==0){ $filed = 'name'; if($filed){ $valueArray[$filed]=$name['value']; }else{ $valueArray[]=$name['value']; } $context['pos']+=$name['size']; $totalSize+= $name['size']; } /*checkBodyInLoop}}*/ else{ return ['value'=>False,'size'=>0,'error'=>$name['error'],'msg'=>$name['msg']]; } do { $expRes = parseInt($context,4); $lastError = $expRes['error']; if($expRes['error']==0){ $filed = ''; if($filed){ $valueArray[$filed]=$expRes['value']; }else{ $valueArray[]=$expRes['value']; } $context['pos']+=$expRes['size']; $totalSize+= $expRes['size']; } }while($lastError==0); return ['value'=>$valueArray,'size'=>$totalSize,'error'=>0,'msg'=>'ok']; } }
可以看出在测试文件中自动生成了 do-while循环结构
运行测试文件的结果
Array ( [value] => Array ( [name] => AB [0] => 1 [1] => 2 [2] => 1094926913 [3] => 322 [4] => 1128415488 ) [size] => 22 [error] => 0 [msg] => ok )
对比测试数据
$context['data']="\x41\x42\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43";
在解析完两个字节的定长字符串 ‘AB’之后,开始按4个节一段 循环解析 整数值,直到剩下的内容无法解析为一个整数为止。
结论:do-while功能已经实现并通过了验证。
更多相关问题请访问PHP中文网:https://www.php.cn/
以上是php 实现类似于pyhon中的Construct库的功能(四)实现do-while功能的详细内容。更多信息请关注PHP中文网其他相关文章!

本文比较了酸和基本数据库模型,详细介绍了它们的特征和适当的用例。酸优先确定数据完整性和一致性,适合财务和电子商务应用程序,而基础则侧重于可用性和

本文讨论了确保PHP文件上传的确保,以防止诸如代码注入之类的漏洞。它专注于文件类型验证,安全存储和错误处理以增强应用程序安全性。

本文讨论了在PHP中实施API速率限制的策略,包括诸如令牌桶和漏水桶等算法,以及使用Symfony/Rate-limimiter之类的库。它还涵盖监视,动态调整速率限制和手

本文讨论了使用password_hash和pyspasswify在PHP中使用密码的好处。主要论点是,这些功能通过自动盐,强大的哈希算法和SECH来增强密码保护

本文讨论了OWASP在PHP和缓解策略中的十大漏洞。关键问题包括注射,验证损坏和XSS,并提供用于监视和保护PHP应用程序的推荐工具。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

Dreamweaver Mac版
视觉化网页开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

Atom编辑器mac版下载
最流行的的开源编辑器

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。