PHP Lex Engine Sourcecode Analysis(undone)
catalog
. PHP词法解析引擎Lex简介
. PHP标签解析
1. PHP词法解析引擎Lex简介
Relevant Link:
2. PHP标签解析
\php-5.4.41\Zend\zend_language_scanner.l
int lex_scan(zval *zendlval TSRMLS_DC)
{
restart:
//设置当前token的首位置为当前位置
SCNG(yy_text) = YYCURSOR; yymore_restart:
//这段注释定义了各个类型的正则表达式匹配,在词法解析程序(如bison、re2c等)程序将本文件转化为c代码时会用到
/*!re2c
re2c:yyfill:check = 0;
LNUM [0-9]+
DNUM ([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*)
EXPONENT_DNUM (({LNUM}|{DNUM})[eE][+-]?{LNUM})
HNUM "0x"[0-9a-fA-F]+
BNUM "0b"[01]+
LABEL [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
WHITESPACE [ \n\r\t]+
TABS_AND_SPACES [ \t]*
TOKENS [;:,.\[\]()|^&+-/*=%!~$<>?@]
ANY_CHAR [^]
NEWLINE ("\r"|"\n"|"\r\n") /* compute yyleng before each rule */
<!*> := yyleng = YYCURSOR - SCNG(yy_text);
。。
0x1: 匹配PHP标签
1.1 <script language=php>、<script language='php'>、<script language="php">
//首先是匹配<script language=php>标签,源码如下,无论这里面有多少个空白字符全部无视,最后php也可以加上单引号或双引号
<INITIAL>"<script"{WHITESPACE}+"language"{WHITESPACE}*"="{WHITESPACE}*("php"|"\"php\""|"'php'"){WHITESPACE}*">"
{
YYCTYPE *bracket = (YYCTYPE*)zend_memrchr(yytext, '<', yyleng - (sizeof("script language=php>") - )); //因为<script>标签本身是在html中的,所以判断当前是否在扫描html,如果是的话就跳转到inline_html去
if (bracket != SCNG(yy_text))
{
/* Handle previously scanned HTML, as possible <script> tags found are assumed to not be PHP's */
YYCURSOR = bracket;
goto inline_html;
} //不然就将当前状态改为ST_IN_SCRIPTING并返回T_OPEN_TAG,表示这是一个php的标签。
HANDLE_NEWLINES(yytext, yyleng);
zendlval->value.str.val = yytext; /* no copying - intentional */
zendlval->value.str.len = yyleng;
zendlval->type = IS_STRING;
BEGIN(ST_IN_SCRIPTING);
return T_OPEN_TAG;
}
1.2 <%=、<%
<INITIAL>"<%"
{
//检查php.ini里面的asp_tags标签是否为On,如果是则表示进入脚本并返回T_OPEN_TAG
if (CG(asp_tags))
{
zendlval->value.str.val = yytext; /* no copying - intentional */
zendlval->value.str.len = yyleng;
zendlval->type = IS_STRING;
BEGIN(ST_IN_SCRIPTING);
return T_OPEN_TAG;
}
else
{
//否则就转到inline_char_handler去
goto inline_char_handler;
}
}
1.3 <?=、<?
//短标签<?=和<?
<INITIAL>"<?"
{
//判断short_open_tag是否为On
if (CG(short_tags))
{
zendlval->value.str.val = yytext; /* no copying - intentional */
zendlval->value.str.len = yyleng;
zendlval->type = IS_STRING;
BEGIN(ST_IN_SCRIPTING);
return T_OPEN_TAG;
}
else
{
goto inline_char_handler;
}
} //"<?=" 不需要short_open_tag标志打开
<INITIAL>"<?="
{
zendlval->value.str.val = yytext; /* no copying - intentional */
zendlval->value.str.len = yyleng;
zendlval->type = IS_STRING;
BEGIN(ST_IN_SCRIPTING);
return T_OPEN_TAG_WITH_ECHO;
}
1.4 <?php
<INITIAL>"<?php"([ \t]|{NEWLINE})
{
zendlval->value.str.val = yytext; /* no copying - intentional */
zendlval->value.str.len = yyleng;
zendlval->type = IS_STRING;
HANDLE_NEWLINE(yytext[yyleng-]);
BEGIN(ST_IN_SCRIPTING);
return T_OPEN_TAG;
}
1.5 inline_char_handler
如果以上的标签匹配都失败,就会匹配ANY_CHAR,判断是否扫描完了,是的话直接返回0,不是就接下去执行inline_char_handler和inline_html段的代码
<INITIAL>{ANY_CHAR}
{
if (YYCURSOR > YYLIMIT)
{
return ;
}
inline_char_handler:
while ()
{
/*
inline_char_handler中的代码是对整个字符串扫描,memchr表示的是从YYCURSOR开始的YYLIMIT - YYCURSOR长度内的字符串中搜索'<'字符
1. 如果找到则匹配'?'、'%'、's'等字符,如果满足条件则结束循环
2. 而匹配到's'或'S'则将YYCURSOR往回退一格并重新开始php标签的匹配
*/
YYCTYPE *ptr = memchr(YYCURSOR, '<', YYLIMIT - YYCURSOR);
YYCURSOR = ptr ? ptr + : YYLIMIT;
if (YYCURSOR < YYLIMIT)
{
switch (*YYCURSOR)
{
case '?':
if (CG(short_tags) || !strncasecmp((char*)YYCURSOR + , "php", ) || (*(YYCURSOR + ) == '='))
{ /* Assume [ \t\n\r] follows "php" */
break;
}
continue;
case '%':
if (CG(asp_tags))
{
break;
}
continue;
case 's':
case 'S':
/* Probably NOT an opening PHP <script> tag, so don't end the HTML chunk yet
* If it is, the PHP <script> tag rule checks for any HTML scanned before it */
YYCURSOR--;
yymore();
default:
continue;
}
YYCURSOR--;
}
break;
}
..
1.6 inline_html
如果是inline_html的代码,直接复制这段代码(PHP引擎对HTML代码原样输出),随后返回T_INLINE_HTML
..
//inline_html扫描的是不在php标签里面的的代码,也就是说这些php代码可能夹杂在诸如html等代码中
inline_html:
yyleng = YYCURSOR - SCNG(yy_text); if (SCNG(output_filter))
{
int readsize;
size_t sz = ;
readsize = SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC);
zendlval->value.str.len = sz;
if (readsize < yyleng)
{
yyless(readsize);
}
}
else
{
zendlval->value.str.val = (char *) estrndup(yytext, yyleng);
zendlval->value.str.len = yyleng;
}
zendlval->type = IS_STRING;
HANDLE_NEWLINES(yytext, yyleng);
return T_INLINE_HTML;
}
从PHP源代码中我们也可以看到,PHP对结束闭合标签是可选的,解析器并不会强制要求一定要有结束闭合标签,PHP官方文档解释如下
The closing tag of a PHP block at the end of a file is optional, and in some cases omitting it is helpful when using include or require, so unwanted whitespace will not occur at the end of files, and you will still be able to add headers to the response later. It is also handy if you use output buffering, and would not like to see added unwanted whitespace at the end of the parts generated by the included files.
不使用结束闭合标签的好处有以下几个
. 如果这个是一个被别人包含的程序,没有这个结束符,可以减少很多很多问题,比如说:header, setcookie, session_start这些动作之前不能有输出,如果不小心在?> 后边加了不可见字符(多余的空格、换行符)等破坏页面显示,就会报"Header already sent"错误,不写的话不会有此问题。另,可以直接把光标移到最后,接着编程
. PHP闭合标签"?>"在PHP中对PHP的分析器是可选的。但是,如果使用闭合标签,任何由开发者,用户,或者FTP应用程序插入闭合标签后面的空格都有可能会引起多余的输出、php错误、之后的输出无法显示、空白页。因此,所有的php文件应该省略这个php闭合标签,并插入一段注释来标明这是文件的底部并定位这个文件在这个应用的相对路径。这样有利于你确定这个文件已经结束而不是被删节的
Relevant Link:
http://php.net/manual/en/language.basic-syntax.instruction-separation.php
http://doophp.sinaapp.com/archives/php/end-symbol.html
http://blog.csdn.net/yanhui_wei/article/details/7951424
http://blog.csdn.net/wuyangbotianshi/article/details/41728091
Copyright (c) 2014 LittleHann All rights reserved
PHP Lex Engine Sourcecode Analysis(undone)的更多相关文章
- Nginx Parsing HTTP Package、header/post/files/args Sourcecode Analysis
catalog . Nginx源码结构 . HTTP Request Header解析流程 . HTTP Request Body解析流程 1. Nginx源码结构 . core:Nginx的核心源代 ...
- NetLink Communication Mechanism And Netlink Sourcecode Analysis
catalog . Netlink简介 . Netlink Function API Howto . Generic Netlink HOWTO kernel API . RFC Linux Netl ...
- BROOTKIT Pinciple、Code Analysis(undone)
目录 . Rootkit相关知识 . BROOTKIT源码分析 . 关键技术点 . 防御策略 1. Rootkit相关知识 关于rootkit的相关其他知识,请参阅以下文章 http://www.cn ...
- Linux Kernel File IO Syscall Kernel-Source-Code Analysis(undone)
目录 . 引言 . open() syscall . close() syscall 0. 引言 在linux的哲学中,所有的磁盘文件.目录.外设设备.驱动设备全部被抽象为了"文件" ...
- SQLChop、SQLWall(Druid)、PHP Syntax Parser Analysis
catalog . introduction . sqlchop sourcecode analysis . SQLWall(Druid) . PHP Syntax Parser . SQL Pars ...
- TOMOYO Linux(undone)
目录 . TOMOYO Introduction . TOMOYO Sourcecode Analysis 1. Introduction TOMOYO是一款基于LSM Framework实现的LSM ...
- Java资源大全中文版(Awesome最新版)
Awesome系列的Java资源整理.awesome-java 就是akullpp发起维护的Java资源列表,内容包括:构建工具.数据库.框架.模板.安全.代码分析.日志.第三方库.书籍.Java 站 ...
- Linux LSM(Linux Security Modules) Hook Technology
目录 . 引言 . Linux Security Module Framework Introduction . LSM Sourcecode Analysis . LSMs Hook Engine: ...
- awesome-java
Awesome Java A curated list of awesome Java frameworks, libraries and software. Awesome Java Ancient ...
随机推荐
- C#微信公众号开发系列教程五(接收事件推送与消息排重)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- 快速备份和还原 MySQL 数据库的另一种方法
一直使用 SQL Server 作为公司产品的数据库来存储系统数据,所以备份还原一直都不是问题,因为 SQL Server 的备份还原非常迅速和易用.但今年公司改变策略,使用起 MySQL 数据库作为 ...
- unity3d 我的面试经历
昨天在上海的一家公司面试成功了 这是我第一次面试,也是我的第一份工作 先上我的简历给大家参考下吧 个人简历 个人信息: 姓 名: 廖旭升 学 历: 无 民 族: 汉 ...
- 使用markdown编辑evernote(印象笔记)的常用方法汇总
原文发表在我的博客主页,转载请注明出处 前言 正所谓工欲善其事,必先利其器,本文将要介绍的evernote和markdown都是程序员必备的工具 虽然国内现在有了很多evernote的替代品,做的比较 ...
- js的一些冷门的用法
1.delete 2.void 0 3.>>> 4.>>0 字符串转为数字 5.[] == ![] 6.
- NPOI2.0学习(二)
如果你要编辑的行和单元格,原本没有值,或者从未创建过的,就必须先创建. //在第二行创建行 IRow row = sheet.CreateRow(); //在第二行的第一列创建单元格 ICell ce ...
- shell读取文件内容
Shell脚本,执行解释速度快.代码简单易于理解.在shell代码编写过程中,经常会用到读取文件内容. 写法一: ------------------------------------ ...
- springMVC+mybatis 进行单元测试时 main SqlSessionFactoryBean - Parsed configuration file: 'class path resource' 无限的读取xml文件
今天终于写完的Dao层的操作,怀着无比激动的心情,进行单元测试,就在最后一个方法,对的就是最后一个方法,启动单元测试就会报以下错误: [2016-05-11 18:25:01,691] [WARN ] ...
- [转]java web简单权限管理设计
原文地址:http://blog.csdn.net/zwx19921215/article/details/44467099 最近在做一个网站类型项目,主要负责后台,ui框架选型为jquery eas ...
- 【BZOJ 4598】【SDOI 2016 Round2 Day1 T3】模式字符串
2016-05-21因为BZOJ上“ 数据文件太过巨大,仅提供前三组数据测试.”所以我考场上写的60分的点分治交上去也A了. 我的这个点分治的时间复杂度是$O(Tnmlogn)$的,听题解时没听懂$O ...