众所周知,php 里面 header之前有输出的话,会报错,例如下面这样

 

就这个错误,我们开始查阅php源代码,到底是怎样做的,至于php源代码分析,安装,和调试时怎样配置的,我会专门写一篇文章去记录的,这里我是使用php-cli命令行的sapi,方便啊,首先我们先看看var_dump的实现啦

1.var_dump

我们知道,var_dump是php的标准函数啦,不是扩展里面的东西,所以会容易比较好找

我们可以见到啦,var_dump调用了php_var_dump函数啦

之后又调用了php_printf,我猜这个应该都是php内核用到的输出函数吧,我们再去php_printf看看吧

可见,php_printf模仿了c的printf,又是一个不定参数的函数,上面可以看到,又调用了PHPWRITE这个宏

实际是php_output_write函数啦

 

我们看看这个函数的逻辑吧

1,输出层是否激活,如果激活就调用php_output_op函数

2,如果不激活,那么直接输出到stderr去

2。 PHP_OUT_ACTIVATED由来

我们是用php-cli这个sapi的,跟踪了php启动过程,发觉,每个sapi都会调用一个函数,那就是

这个文件时在php-cli.c里面,有兴趣的读者可以看看这个,php在开始接受请求之前都会调用它的,截取一部分函数吧

我看看见了一个函数,php_out_activate函数啦

激活了输出层啦,证明可以输出啦

3 回到php_output_op函数

流程

   1 如果开启了缓冲区的话(obstart这种函数啦),就进入php_output_handler_op函数

   2,如果没有开启的话,就直接赋值给临时通道(context)

   3,如果真的有内容输出的话,就执行php_output_header函数

我们重点看php_output_header函数

4 php_output_header

 

这个函数很简单啦,就是设置当前输出行和该页面的名称,也就是我们调用var_dump的位置啦

具体有什么用,下面就知道啦

5,header函数实现

 

跟到sapi_header_op函数

在这里我们终于可以看到报错的哪行信息啦

header_sent什么时候开始设置呢

答案就是在在上面的 php_output_header函数里面调用的php_header里面啦

6 php_header

该函数的作用就是发送一个header(content-type:text/html);的东西,然后设置 SG(headers_sent) = 1

7 下面来分析为什么开启ob_start不会报错

  答案是开启了 因为开启了缓冲区,还记得上面php_output_op函数里面的一句代码吗

/*
* broken up for better performance:
*  - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush
*  - or apply op to the handler stack
*/
if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) {

 

上面的注释大家应该应该很清楚吗,如果我们调用了一个ob_start函数,php内核会申请一个handler结构同时为这个结构申请一个缓冲区 php_output_buffer

typedef struct _php_output_handler {
    char *name;
    size_t name_len;
    int flags;
    int level;
    size_t size;
    php_output_buffer buffer;
    void *opaq;
    void (*dtor)(void *opaq TSRMLS_DC);
    union {
        php_output_handler_user_func_t *user;
        php_output_handler_context_func_t internal;
    } func;
} php_output_handler;

当然,申请完缓冲区,就会初始化它然后把它压入栈啦,然后把handler赋给 OG(handlers)

 

下一篇说下,为什么header之前不能有输出,来更加深入httpd协议

php里面为什么header之前有输出报错 源码分析的更多相关文章

  1. SAP MM 公司间STO发货单输出报错 - 合并工厂AUC1和存储位置6002没有货物收货地点 - 之对策

    SAP MM 公司间STO发货单输出报错 - 合并工厂AUC1和存储位置6002没有货物收货地点 - 之对策 昨天收到客户业务部门报错,说是业务对交货单0080022298做POD失败.相关交货单的输 ...

  2. Mysql报错注入原理分析(count()、rand()、group by)

    Mysql报错注入原理分析(count().rand().group by) 0x00 疑问 一直在用mysql数据库报错注入方法,但为何会报错? 百度谷歌知乎了一番,发现大家都是把官网的结论发一下截 ...

  3. EasyPlayerPro(Windows)流媒体播放器开发之ffmpeg log输出报错

    EasyPlayerPro主要基于ffmpeg进行开发,在EasyPlayerPro开发过程中,曾遇到一个相对比较棘手的问题,该问题一般在播放不是很标准的流或者网络情况较差,容易出现丢帧的情况特别容易 ...

  4. scrapy shell 中文网站输出报错.记录.

    UnicodeDecodeError: 'gbk' codec can't decode bytes in position 381-382: illegal multibyte sequence 上 ...

  5. 【MySQL】MySQL同步报错-> received end packet from server, apparent master shutdown: Slave I/O thread: Failed reading log event, reconnecting to retry报错解决和分析

    [root@db-ft-db-48 ~]# tail -f /mysqlLog/beside_index_err.log 140102 20:42:26 [Note] Slave: received ...

  6. cocos2d-x在android中响应返回键编译报错的bug分析

    先看一段代码如何在Android中加入返回按键的响应 <span style="font-size:18px;">自己派生CCKeypadDelegate的子类,然后注 ...

  7. php源码分析之php_info输出中css样式是怎么来的

    我们经常使用echo phpinfo();查看php的配置信息,但是大家知道里面的css样式是怎么来的吗? 我们查看源码(php源码/ext/standard/css.c) PHPAPI void p ...

  8. MySQL主从检验一致性工具pt-table-checksum报错的案例分析

    [问题] 有同事反馈我们改造过的MySQL5.7.23版本,使用pt-table-checksum工具比较主从数据库的一致性时报错 Unsafe statement written to the bi ...

  9. MySQL Server has gone away报错原因汇总分析(转自:http://cenalulu.github.io/mysql/mysql-has-gone-away/)

    原因1. MySQL 服务宕了 判断是否属于这个原因的方法很简单,执行以下命令,查看mysql的运行时长 $ mysql -uroot -p -e "show global status l ...

随机推荐

  1. IT讲师韩顺平:我为什么辞去百万年薪,自己创业?

    先自我介绍一下,我叫韩顺平,是一名IT讲师.国内很多自学PHP和Java的朋友都看过我的视频课程,算是有些知名度. 15年8月从传智辞职后,很多朋友非常关心我的去向,网上也流传各种说法,有的说我和某某 ...

  2. Linux使用者管理(1)---用户账号

    linux很重要的应用就是作为服务器的操作系统.服务器的作用是给多用户提供各种“服务”(可能是读服务器上的文件,或者是利用服务器进行数值计算)那么如果多用户共同拥有一台服务器,就需要对服务器上的用户进 ...

  3. shell编程基础(3)条件判断语句

    1,带参数的shellscript #this is program build 5.11 to test shell script ############ cxz ####### 5.11 ### ...

  4. 删除单链表的倒数第k个结点

    策略 直接遍历总数为len,再次遍历第len-k+1个就是答案,但是这样遍历了O(N+k)个,可以在O在更短的时间内找到 图示 参考代码 #include <iostream> using ...

  5. Drawit插件

    gvim用不了画矩形的功能,只能在vim下用 \di,\ds开始/结束画图(Vim里\按键没有被映射,可以做leader按键) 用鼠标选择一块之后,\b画矩形,\e画椭圆 选单行\a画箭头,\l画线 ...

  6. Web内容管理系统 Magnolia 安装使用-挖掘优良的架构(2)

    在Windows上安装社区版  tomcat集成版 Magnolia CMS社区版本为免费发行,不需要任何GNU通用公共许可协议(第3版)条款下的授权(这个许可协议允许您在特定条款和条件下,重新分配和 ...

  7. WPF 用 DataTemplate 合并DataGrid列表列头<类似报表设计>及行头列头样式 - 学习

    WPF中 DataGrid 列头合并,类似于报表设计.效果图如下↓ 1.新建一个WPF项目WpfApplication1,新建一个窗体DataGridTest,前台代码如下: <Window x ...

  8. ASP.NET MVC 学习4、Controller中添加SearchIndex页面,实现简单的查询功能

    参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-edit-method ...

  9. onkeypress与onkeydown及 oncopy和onpaste 事件区别详细说明

    onkeypress与onkeydown 具体区别: 1. 一个放开一个没有放开,onkeydown 先于 onkeypress 发生. 2.onkeypress 无法系统按钮. 2.onkeydow ...

  10. VB VS2003获取当前进程用户登录

    Page.User.Identity.Name获取当前进程用户名称,VS03才可以用