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)的更多相关文章

  1. Nginx Parsing HTTP Package、header/post/files/args Sourcecode Analysis

    catalog . Nginx源码结构 . HTTP Request Header解析流程 . HTTP Request Body解析流程 1. Nginx源码结构 . core:Nginx的核心源代 ...

  2. NetLink Communication Mechanism And Netlink Sourcecode Analysis

    catalog . Netlink简介 . Netlink Function API Howto . Generic Netlink HOWTO kernel API . RFC Linux Netl ...

  3. BROOTKIT Pinciple、Code Analysis(undone)

    目录 . Rootkit相关知识 . BROOTKIT源码分析 . 关键技术点 . 防御策略 1. Rootkit相关知识 关于rootkit的相关其他知识,请参阅以下文章 http://www.cn ...

  4. Linux Kernel File IO Syscall Kernel-Source-Code Analysis(undone)

    目录 . 引言 . open() syscall . close() syscall 0. 引言 在linux的哲学中,所有的磁盘文件.目录.外设设备.驱动设备全部被抽象为了"文件" ...

  5. SQLChop、SQLWall(Druid)、PHP Syntax Parser Analysis

    catalog . introduction . sqlchop sourcecode analysis . SQLWall(Druid) . PHP Syntax Parser . SQL Pars ...

  6. TOMOYO Linux(undone)

    目录 . TOMOYO Introduction . TOMOYO Sourcecode Analysis 1. Introduction TOMOYO是一款基于LSM Framework实现的LSM ...

  7. Java资源大全中文版(Awesome最新版)

    Awesome系列的Java资源整理.awesome-java 就是akullpp发起维护的Java资源列表,内容包括:构建工具.数据库.框架.模板.安全.代码分析.日志.第三方库.书籍.Java 站 ...

  8. Linux LSM(Linux Security Modules) Hook Technology

    目录 . 引言 . Linux Security Module Framework Introduction . LSM Sourcecode Analysis . LSMs Hook Engine: ...

  9. awesome-java

    Awesome Java A curated list of awesome Java frameworks, libraries and software. Awesome Java Ancient ...

随机推荐

  1. GridView的 OnRowDataBound 事件用法

    <asp:GridView ID="RptUsers" runat="server" AutoGenerateColumns="False&qu ...

  2. Adobe Reader & PDF 护眼设置

    1.首先选择“编辑”--->“首选项” 选择其他颜色,把RGB如下设置

  3. Matlab中数组元素引用——三种方法

    Matlab中数组元素引用——三种方法   1.Matlab中数组元素引用有三种方法 1 2 3 1.下标法(subscripts) 2.索引法(index) 3.布尔法(Boolean) 注意:在使 ...

  4. Android多线程文件下载

    版本信息 apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion " ...

  5. 什么是viewport,为什么需要viewport

    viewport:视口,视觉窗口,显示区域.在显示面积上手机屏幕相对桌面显示器要小很多,在几年前(现在也如此)大部分网站都是为桌面显示器浏览而设计,很少考虑到适应手机屏幕,所以如果用手机浏览大多网站时 ...

  6. Oracle 11g 7个压缩包说明

    最初,我以为都要解压.无意间看到的一博客,明白压缩包的含义.哈哈 Oracle11g有多张安装光盘: 文件名称                                              ...

  7. MVC 中的 ispostback

    总之呢就是在MVC中试下 ispostback那种效果, 环境就是:登录验证loinger, if (Request.HttpMethod == "POST"){} 没理解透彻 源 ...

  8. Collections的应用

    Collection : 接口  Collections : 集合的工具类    Arrays (数组的工具类)  只能操作list集合    说出Collection和Collections 的区别 ...

  9. Android AlertDialog

    在Android 4.2 中不推荐使用showDialog弹窗,这里简单总结一下AlertDialog的使用方法,以后复习的时候看着方便,详细使用方法需要的时候再研究. setTitle :为对话框设 ...

  10. Percona 开始尝试基于Ceph做上层感知的分布式 MySQL 集群,使用 Ceph 提供的快照,备份和 HA 功能来解决分布式数据库的底层存储问题

    本文由 Ceph 中国社区 -QiYu 翻译 英文出处:Using Ceph with MySQL 欢迎加入CCTG Over the last year, the Ceph world drew m ...