phpbuffer
㈠ 解析php中的内存管理,PHP动态分配和释放内存
本篇文章是对PHP中的内存管理 PHP动态分配和释放内存进行了详细的分析介绍 需要的朋友参考下摘要 内存管理对于长期运行的程序 例如服务器守护程序 是相当重要的影响 因此 理解PHP是如何分配与释放内存的对于创建这类程序极为重要 本文将重点探讨PHP的内存管理问题
一 内存 在PHP中 填充一个字符串变量相当简单 这只需要一个语句"<?php $str = hello world ; ?>"即可 并且该字符串能够被自由地修改 拷贝和移动 而在C语言中 尽管你能够编写例如"char *str = "hello world ";"这样的一个简单的静态字符串 但是 却不能修改该字符串 因为它生存于程序空间内 为了创建一个可操纵的字符串 你必须分配一个内存块 并且通过一 个函数(例如strp())来运卖复制其内容
复制代码 代码如下: { char *str; str = strp("hello world"); if (!str) { fprintf(stderr "Unable to allocate memory!"); } }由于后面我们将分析的各种原因 传统型内存管理函数(例如malloc() free() strp() realloc() calloc() 等等)几乎都不能直接为PHP源代码所使用
二 释放内存 在几乎所有的平台上 内存管理都是通旁滑逗过一种请求和释放模式实现的 首先 一个应用程序请求它下面的层(通常指"操作系统") "我想使用一些内存空间" 如果存在可用的空间 操作系统就会把它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序 当 应用程序使用完这部分内存 它应该被返回到OS 这样以来 它就能够被继续分配给其它程序 如果该程序不返回这部分内存 那么OS无法知道是否这块内存不 再使用并进而再分配给另一个进程 如果一个内存块没有释放 并且所有者应用程序丢失了它 那么 我们就说此应用程序"存在漏洞" 因为这部分内存无法再为 其它程序可用 在一个典型的客户端应用程序中 较小的不太经常的内存泄漏有时能够为OS所"容忍" 因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS 这并没有什么 因为OS知道它把该内存分配给了哪个程序 并且它能够确信当该程序终止时不再需要该内存 而对于长时间运行的服务器守护程序 包括象Apache这样的web服务器和扩展php模块来说 进程往往被设计为相当长时间一直运行 因为OS不能清理内存使用 所以 任何程序的泄漏 无论是多么小 都将导致重复操作并最终耗尽所有的系统资源 现 在 我们不妨考虑用户空间内的stristr()函数 为了使用大小写不敏感的搜索来查找一个字符串 它实际上创建了两个串的各自的一个小型副本 然后执 行一个更传统型的大小写敏感的搜索来查找相对的偏移量 然而 在定位该字符串的偏移量之后 它不再使用这些小写版本的字符串 如果它不释放这些副本 那 么 每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存 最后 web服务器进程将拥有所有的系统内存 但却不能够使用它 你可以理直气壮地说 理想的解决方案就是编写良好 干净的 一致的代码 这当然不错 但是 在一个象PHP解释器这样的环境中 这种观点仅对了一半
三 错误处理 为了实现"跳出"对用户空间脚本及其依赖的扩展函数的一个活动请求 需要使用一种方法来 完全"跳出"一个活动请求 这是在Zend引擎内实现的 在一个请求的开始设置一个"跳出"地址 然后在任何die()或exit()调用或在遇到任何关 键错误(E_ERROR)时执行一个longjmp()以跳转到该"跳出"地址 尽管让好这个"跳出"进程能够简化程序执行的流程 但是 在绝大多数情况下 这会意味着将会跳过资源清除代码部分(例如free()调用)并最终导致出现内存漏洞 现在 让我们来考虑下面这个简化版本的处理函数调用的引擎代码
复制代码 代码如下: void call_function(const char *fname int fname_len TSRMLS_DC){ zend_function *fe; char *lcase_fname; /* PHP函数名是大小写不敏感的 *为了简化在函数表中对它们的定位 *所有函数名都隐含地翻译为小写的 */ lcase_fname = estrnp(fname fname_len); zend_str_tolower(lcase_fname fname_len); if (zend_hash_find(EG(function_table) lcase_fname fname_len + (void **)&fe) == FAILURE) { zend_execute(fe >op_array TSRMLS_CC); } else { php_error_docref(NULL TSRMLS_CC E_ERROR "Call to undefined function: %s()" fname); } efree(lcase_fname); }
当 执行到php_error_docref()这一行时 内部错误处理器就会明白该错误级别是critical 并相应地调用longjmp()来中断当前 程序流程并离开call_function()函数 甚至根本不会执行到efree(lcase_fname)这一行 你可能想把efree()代码行移 动到zend_error()代码行的上面 但是 调用这个call_function()例程的代码行会怎么样呢?fname本身很可能就是一个分配的 字符串 并且 在它被错误消息处理使用完之前 你根本不能释放它 注意 这个php_error_docref()函数是trigger_error()函数的一个内部等价实现 它的第一个参数是一个将被添加到docref的可选的文档引用 第三个参数可以是任何我们熟悉的E_*家族常量 用于指示错误的严重程度 第四个参数(最后一个)遵循printf()风格的格式化和变量参数列表式样 四 Zend内存管理器 在 上面的"跳出"请求期间解决内存泄漏的方案之一是 使用Zend内存管理(ZendMM)层 引擎的这一部分非常类似于操作系统的内存管理行为 分配内存 给调用程序 区别在于 它处于进程空间中非常低的位置而且是"请求感知"的 这样以来 当一个请求结束时 它能够执行与OS在一个进程终止时相同的行为 也就是说 它会隐式地释放所有的为该请求所占用的内存 图 展示了ZendMM与OS以及PHP进程之间的关系 图 Zend内存管理器代替系统调用来实现针对每一种请求的内存分配 除 了提供隐式内存清除功能之外 ZendMM还能够根据php ini中memory_limit的设置控制每一种内存请求的用法 如果一个脚本试图请求比 系统中可用内存更多的内存 或大于它每次应该请求的最大量 那么 ZendMM将自动地发出一个E_ERROR消息并且启动相应的"跳出"进程 这种方法 的一个额外优点在于 大多数内存分配调用的返回值并不需要检查 因为如果失败的话将会导致立即跳转到引擎的退出部分 把PHP内部代码和 OS的实际的内存管理层"钩"在一起的原理并不复杂 所有内部分配的内存都要使用一组特定的可选函数实现 例如 PHP代码不是使用malloc( ) 来分配一个 字节内存块而是使用了emalloc( ) 除了实现实际的内存分配任务外 ZendMM还会使用相应的绑定请求类型来标志该内存块 这 样以来 当一个请求"跳出"时 ZendMM可以隐式地释放它 经常情况下 内存一般都需要被分配比单个请求持续时间更长的一段时间 这 种类型的分配(因其在一次请求结束之后仍然存在而被称为"永久性分配") 可以使用传统型内存分配器来实现 因为这些分配并不会添加ZendMM使用的那 些额外的相应于每种请求的信息 然而有时 直到运行时刻才会确定是否一个特定的分配需要永久性分配 因此ZendMM导出了一组帮助宏 其行为类似于其它 的内存分配函数 但是使用最后一个额外参数来指示是否为永久性分配 如果你确实想实现一个永久性分配 那么这个参数应该被设置为 在这 种情况下 请求是通过传统型malloc()分配器家族进行传递的 然而 如果运行时刻逻辑认为这个块不需要永久性分配 那么 这个参数可以被设置为零 并且调用将会被调整到针对每种请求的内存分配器函数 例如 pemalloc(buffer_len )将映射到malloc(buffer_len) 而pemalloc(buffer_len )将被使用下列语句映射到emalloc(buffer_len) #define in Zend/zend_alloc h: #define pemalloc(size persistent) ((persistent)?malloc(size): emalloc(size)) 所有这些在ZendMM中提供的分配器函数都能够从下表中找到其更传统的对应实现 表格 展示了ZendMM支持下的每一个分配器函数以及它们的e/pe对应实现 表格 传统型相对于PHP特定的分配器
分配器函数 e/pe对应实现 void *malloc(size_t count); void *emalloc(size_t count);void *pemalloc(size_t count char persistent); void *calloc(size_t count); void *ecalloc(size_t count);void *pecalloc(size_t count char persistent); void *realloc(void *ptr size_t count); void *erealloc(void *ptr size_t count); void *perealloc(void *ptr size_t count char persistent); void *strp(void *ptr); void *estrp(void *ptr);void *pestrp(void *ptr char persistent); void free(void *ptr); void efree(void *ptr); void pefree(void *ptr char persistent);你可能会注意到 即使是pefree()函数也要求使用永久性标志 这是因为在调用pefree()时 它实际上并不知道是否ptr是一种永久性分 配 针对一个非永久性分配调用free()能够导致双倍的空间释放 而针对一种永久性分配调用efree()有可能会导致一个段错误 因为内存管理器会试 图查找并不存在的管理信息 因此 你的代码需要记住它分配的数据结构是否是永久性的 除了分配器函数核心部分外 还存在其它一些非常方便的ZendMM特定的函数 例如 void *estrnp(void *ptr int len); 该函数能够分配len+ 个字节的内存并且从ptr处复制len个字节到最新分配的块 这个estrnp()函数的行为可以大致描述如下
复制代码 代码如下: void *estrnp(void *ptr int len) { char *dst = emalloc(len + ); memcpy(dst ptr len); dst[len] = ; return dst; }在 此 被隐式放置在缓冲区最后的NULL字节可以确保任何使用estrnp()实现字符串复制操作的函数都不需要担心会把结果缓冲区传递给一个例如 printf()这样的希望以为NULL为结束符的函数 当使用estrnp()来复制非字符串数据时 最后一个字节实质上都浪费了 但其中的利明显 大于弊 void *safe_emalloc(size_t size size_t count size_t addtl); void *safe_pemalloc(size_t size size_t count size_t addtl char persistent); 这 些函数分配的内存空间最终大小是((size*count)+addtl) 你可以会问 "为什么还要提供额外函数呢?为什么不使用一个 emalloc/pemalloc呢?"原因很简单 为了安全 尽管有时候可能性相当小 但是 正是这一"可能性相当小"的结果导致宿主平台的内存溢出 这可能会导致分配负数个数的字节空间 或更有甚者 会导致分配一个小于调用程序要求大小的字节空间 而safe_emalloc()能够避免这种类型的陷 井 通过检查整数溢出并且在发生这样的溢出时显式地预以结束 注意 并不是所有的内存分配例程都有一个相应的p*对等实现 例如 不存在pestrnp() 并且在PHP 版本前也不存在safe_pemalloc()
五 引用计数 慎重的内存分配与释放对于PHP(它是一种多请求进程)的长期性能有极其重大的影响 但是 这还仅是问题的一半 为了使一个每秒处理上千次点击的服务器高效地运行 每一次请求都需要使用尽可能少的内存并且要尽可能减少不必要的数据复制操作 请考虑下列PHP代码片断
复制代码 代码如下: <?php $a = Hello World ; $b = $a; unset($a); ?>在第一次调用之后 只有一个变量被创建 并且一个 字节的内存块指派给它以便存储字符串"Hello World" 还包括一个结尾处的NULL字符 现在 让我们来观察后面的两行 $b被置为与变量$a相同的值 然后变量$a被释放 如 果PHP因每次变量赋值都要复制变量内容的话 那么 对于上例中要复制的字符串还需要复制额外的 个字节 并且在数据复制期间还要进行另外的处理器加 载 这一行为乍看起来有点荒谬 因为当第三行代码出现时 原始变量被释放 从而使得整个数据复制显得完全不必要 其实 我们不妨再远一层考虑 让我们设想 当一个 MB大小的文件的内容被装载到两个变量中时会发生什么 这将会占用 MB的空间 此时 已经足够了 引擎会把那么多的时间和内存浪费在这 样一种无用的努力上吗? 你应该知道 PHP的设计者早已深谙此理 记住 在引擎中 变量名和它们的值实际上是两个不同的概念 值本身是一个无名的zval*存储体(在本例中 是一个字符串值) 它被通过zend_hash_add()赋给变量$a 如果两个变量名都指向同一个值 会发生什么呢?
复制代码 代码如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") &helloval sizeof(zval*) NULL); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") &helloval sizeof(zval*) NULL); }此 时 你可以实际地观察$a或$b 并且会看到它们都包含字符串"Hello World" 遗憾的是 接下来 你继续执行第三行代码"unset($a);" 此时 unset()并不知道$a变量指向的数据还被另一个变量所使 用 因此它只是盲目地释放掉该内存 任何随后的对变量$b的存取都将被分析为已经释放的内存空间并因此导致引擎崩溃 这个问题可以借助于 zval(它有好几种形式)的第四个成员refcount加以解决 当一个变量被首次创建并赋值时 它的refcount被初始化为 因为它被假定仅由 最初创建它时相应的变量所使用 当你的代码片断开始把helloval赋给$b时 它需要把refcount的值增加为 这样以来 现在该值被两个变量 所引用
复制代码 代码如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") &helloval sizeof(zval*) NULL); ZVAL_ADDREF(helloval); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") &helloval sizeof(zval*) NULL); }现在 当unset()删除原变量的$a相应的副本时 它就能够从refcount参数中看到 还有另外其他人对该数据感兴趣 因此 它应该只是减少refcount的计数值 然后不再管它
六 写复制(Copy on Write) 通过refcounting来节约内存的确是不错的主意 但是 当你仅想改变其中一个变量的值时情况会如何呢?为此 请考虑下面的代码片断
复制代码 代码如下: <?php $a = ; $b = $a; $b += ; ?>通过上面的逻辑流程 你当然知道$a的值仍然等于 而$b的值最后将是 并且此时 你还知道 Zend在尽力节省内存 通过使$a和$b都引用相同的zval(见第二行代码) 那么 当执行到第三行并且必须改变$b变量的值时 会发生什么情况呢? 回答是 Zend要查看refcount的值 并且确保在它的值大于 时对之进行分离 在Zend引擎中 分离是破坏一个引用对的过程 正好与你刚才看到的过程相反
复制代码 代码如下: zval *get_var_and_separate(char *varname int varname_len TSRMLS_DC) { zval **varval *var; if (zend_hash_find(EG(active_symbol_table) varname varname_len + (void**)&varval) == FAILURE) { /* 变量根本并不存在 失败而导致退出*/ return NULL; } if ((*varval) >refcount < ) { /* varname是唯一的实际引用 *不需要进行分离 */ return *varval; } /* 否则 再复制一份zval*的值*/ MAKE_STD_ZVAL(var); var = *varval; /* 复制任何在zval*内的已分配的结构*/ zval__ctor(var); /*删除旧版本的varname *这将减少该过程中varval的refcount的值 */ zend_hash_del(EG(active_symbol_table) varname varname_len + ); /*初始化新创建的值的引用计数 并把它依附到 * varname变量 */ var >refcount = ; var >is_ref = ; zend_hash_add(EG(active_symbol_table) varname varname_len + &var sizeof(zval*) NULL); /*返回新的zval* */ return var; }现在 既然引擎有一个仅为变量$b所拥有的zval*(引擎能知道这一点) 所以它能够把这个值转换成一个long型值并根据脚本的请求给它增加
七 写改变(change on write) 引用计数概念的引入还导致了一个新的数据操作可能性 其形式从用户空间脚本管理器看来与"引用"有一定关系 请考虑下列的用户空间代码片断
复制代码 代码如下: <?php $a = ; $b = &$a; $b += ; ?>在 上面的PHP代码中 你能看出$a的值现在为 尽管它一开始为 并且从未(直接)发生变化 之所以会发生这种情况是因为当引擎开始把$b的值增加 时 它注意到$b是一个对$a的引用并且认为"我可以改变该值而不必分离它 因为我想使所有的引用变量都能看到这一改变" 但是 引擎是如何 知道的呢?很简单 它只要查看一下zval结构的第四个和最后一个元素(is_ref)即可 这是一个简单的开/关位 它定义了该值是否实际上是一个用户 空间风格引用集的一部分 在前面的代码片断中 当执行第一行时 为$a创建的值得到一个refcount为 还有一个is_ref值为 因为它仅为一 个变量($a)所拥有并且没有其它变量对它产生写引用改变 在第二行 这个值的refcount元素被增加为 除了这次is_ref元素被置为 之外 (因为脚本中包含了一个"&"符号以指示是完全引用) 最后 在第三行 引擎再一次取出与变量$b相关的值并且检查是否有必要进行分离 这一次该值没有被分离 因为前面没有包括一个检查 下面是get_var_and_separate()函数中与refcount检查有关的部分代码
复制代码 代码如下: if ((*varval) >is_ref || (*varval) >refcount < ) { /* varname是唯一的实际引用 * 或者它是对其它变量的一个完全引用 *任何一种方式 都没有进行分离 */ return *varval; }这一次 尽管refcount为 却没有实现分离 因为这个值是一个完全引用 引擎能够自由地修改它而不必关心其它变量值的变化
八 分离问题 尽管已经存在上面讨论到的复制和引用技术 但是还存在一些不能通过is_ref和refcount操作来解决的问题 请考虑下面这个PHP代码块
复制代码 代码如下: <?php $a = ; $b = $a; $c = &$a; ?>在 此 你有一个需要与三个不同的变量相关联的值 其中 两个变量是使用了"change on write"完全引用方式 而第三个变量处于一种可分离 的" on write"(写复制)上下文中 如果仅使用is_ref和refcount来描述这种关系 有哪些值能够工作呢? 回答是 没有一个能工作 在这种情况下 这个值必须被复制到两个分离的zval*中 尽管两者都包含完全相同的数据(见图 )
图 引用时强制分离
同样 下列代码块将引起相同的冲突并且强迫该值分离出一个副本(见图 )
图 复制时强制分离
复制代码 代码如下: <?php $a = ; $b = &$a; $c = $a; ?> lishixin/Article/program/PHP/201311/20951
㈡ PHP问题求大神解答
php缓冲区,一般默认是开启的,大小为4096比特,也就是4k左右,整个流程来说,是php缓冲区->apache缓冲区- >浏览器缓冲区。
1 当缓冲区满的时候,会自动将缓冲区里面的内容往下一级缓冲区输送
2 当php程序运行结束的时候,缓冲区内容也会自动清空并输出
3人为使用ob_flush将php缓冲区内容输送到Apache缓冲区,使用flush将Apache缓冲区内容输送到浏览器缓冲区
!使用ini_set是无法修改buffer的设置。
㈢ php读取文件的数据,文件名为text.txt,求详细代码。本人新手
<h1>读取文件内容</h1>
***********第一种读取方式********************<br>
<?
$file_path ="test.txt";
if(file_exists($file_path)){ //先判断文件是否存在
//打开文件
$fp = fopen($file_path,"a+");
//读取文件内容
$con = fread($fp,filesize($file_path));
echo "文件的内容是:<br>".$con;
//在默认情况下,得到的内容输出到网页后,不会换行,因为网页不认\r\n是换行符,把\r\n体换成<br />
$con = str_replace("\r\n","<br />",$con);
echo "猛薯<br>文件的内容是:<br>".$con;
//关闭
fclose($fp);
}else{
echo "文件不存在!";
}
?>
<hr>
*************第二种读取方式*******************<br>
<?php
if(file_exists($file_path)){
$con = file_get_contents($file_path);
$con = str_replace("\r\n","<br />",$con);
echo "文件的内容是:<br>"弯塌.$con;
}else{
echo "文件不枝闹者存在!";
}
?>
<hr>
************第三种读取方式(大文件、循环读取)**********<br>
<?php
$fp = fopen($file_path,"a+");
$buffer = 1024; //设置读取1024个字节
$str = "";
//一边读,一边判断是否到达文件末尾
while(!feof($fp)){
$str.= fread($fp,$buffer);
}
$str = str_replace("\r\n","<br />",$str);
echo $str;
fclose($fp);
?>
㈣ 关于php配置文件中output_buffering选项的问题
默认情况下,php buffer是开启的,而且该buffer默认值是4096,即4kb。你可以通过在php.ini配置文件中找到output_buffering配置.当echo,print等输出用户数据的时候,输出数据都会写入到php output_buffering中,直到output_buffering写满,会将这些数据通过tcp传送给浏览器显示。你也可以通过ob_start()手动激活php output_buffering机制,使得即便输出超过了4kb数据,也不真的把数据交给tcp传给浏览器,因为ob_start()将php buffer空间设置到了足够大。只有直到脚本结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。
㈤ PHP文件指针和偏移量是啥意思
试解释一下:
1、文件指针
文件指针有两种含义。
一种是意指文件的句柄,可以理解为对文件进行操作所需的入口点,其实质是系统分配的资源;
另一种是意指文件当前读写所在的位置,就比如是时钟当前所在的时间点。
2、偏移量
由于通常对文件进行读写操作时,是以“流”式进行的(简单点说,不像通常打开一个 word 文档,可以直接通过鼠标选择对其中的某个句子进行编辑,php 的文件处理,是按一个字节一个字节顺序“流”读取的)。
比如,以下的代码就是每次读1024字节,读取整个文件:
//打开文件
$fp=fopen($file_path,"a+");
//定义每次读取的多少字节
$buffer=1024;
//一边读取。一边判断是否达到文件末尾
while(!feof($fp)){
//按1024个字节读取数据
$content=fread($fp,$buffer);
echo$content;
}
偏移量,就是当前的文件指针到指定的文件位置的距离(就是字节数),比如,从文件头读取1024字节,这个1024就是偏移量。
㈥ PHP里的output_buffering 怎么开启
在PHP.INI可以设置以下与输出缓冲有关的:
名称 默认值 作用范围 修正记录
output_buffering "0" PHP_INI_PERDIR
output_handler NULL PHP_INI_PERDIR 自 PHP 4.0.4 起可用
implicit_flush "0" PHP_INI_ALL 在 PHP <= 4.2.3 版本中是 PHP_INI_PERDIR
简单解释如下:
output_buffering boolean/integer
该选项设置为 On 时,将在所有的脚本中使用输出控制。如果要限制输出缓冲区的最大值,可将该选项设定为指定的最大字节数(例如 output_buffering=4096)。从PHP 4.3.5 版开始,该选项在 PHP-CLI 下总是为 Off。
output_handler string
该选项可将脚本所有的输出,重定向到一个函数。例如,将 output_handler 设置为 mb_output_handler() 时,字符的编码将被修改为指定的编码。设置的任何处理函数,将自动的处理输出缓冲。
注意: 不能同时使用 mb_output_handler() 和 ob_iconv_handler(),也不能同时使用 ob_gzhandler() 和 zlib.output_compression。
注意: 只有内置函数可以使用此指令。对于用户定义的函数,使用 ob_start()。
implicit_flush boolean
默认为 FALSE。如将该选项改为 TRUE,PHP 将使输出层,在每段信息块输出后,自动刷新。这等同于在每次使用 print()、echo() 等函数或每个 HTML 块之后,调用 PHP 中的 flush() 函数。
不在web环境中使用 PHP 时,打开这个选项对程序执行的性能有严重的影响,通常只推荐在调试时使用。在 CLI SAPI 的执行模式下,该标记默认为 TRUE。
参见 ob_implicit_flush()。
设置了肯定会有用的,除非你修改的PHP.INI位置不是系统使用的那个,比如一般是C::\WINDOWS\PHP.INI,当然可以设置到其它地方。另外控制台程序是不缓冲的。
另外,你还可以在程序里面控制输出缓冲,请参考手册里面的“CXIV. Output Control 输出控制函数”那一章,主要有如下函数:
flush -- 刷新输出缓冲
ob_clean -- Clean (erase) the output buffer
ob_end_clean -- Clean (erase) the output buffer and turn off output buffering
ob_end_flush -- Flush (send) the output buffer and turn off output buffering
ob_flush -- Flush (send) the output buffer
ob_get_clean -- Get current buffer contents and delete current output buffer
ob_get_contents -- Return the contents of the output buffer
ob_get_flush -- Flush the output buffer, return it as a string and turn off output buffering
ob_get_length -- Return the length of the output buffer
ob_get_level -- Return the nesting level of the output buffering mechanism
ob_get_status -- Get status of output buffers
ob_gzhandler -- ob_start callback function to gzip output buffer
ob_implicit_flush -- Turn implicit flush on/off
ob_list_handlers -- List all output handlers in use
ob_start -- Turn on output buffering
output_add_rewrite_var -- Add URL rewriter values
output_reset_rewrite_vars -- Reset URL rewriter values
例子程序:
<?php
ob_start();
echo "Hello\n";
setcookie("cookiename", "cookiedata");
ob_end_flush();
?>
㈦ 如何解决PHP无法修改header信息问题
第一种方法很简单!就是尽量避免在肆者header和setcookie之前有任何的输出内容。尽量将他们写在前面。
第二种解决办法就是利用PHP的outbuffer 输出缓冲,旅滑PHP的输出缓冲是这样的 ,将当前脚本的所有输出内容都放到outbuffer里面,当程序执行完毕之后 将header和outbuffer一并发送给客户端。
有两种做裂镇薯法 一种是在PHP.ini中开启outbuffer output_buffering默认值为0 可以设置为Off或者On 如果要限制输出缓冲区的最大值,可将该选项设定为指定的最大字节数(例如 output_buffering=4096)。
另一种PHP无法修改header信息方法是在PHP脚本中做开启:
在程序的开始出或者公共文件开始处 调用函数ob_start();
这样我们就开启了PHP的输出缓冲
㈧ php每次连接php文件都需要读取一个文件的数据,有没有方法是能够将读的数据存入缓存中,连接时从缓存读取
xcache缓存,请自行参考官方说明和用法
还有一个比较繁琐的方法,当你第一次读取一定数量的数据的时候,把这一次的数据另存为一个谨蠢1.txt,依次类推,你每次连接的时候只要祥启陪去读最后依次访旁凯问的文件即可。记得存贮读取次数
㈨ php检测上传文件大小的问题
在用PHP进行文件上传的操作中,需要知道怎么控制上传文件大小的设置,而文件可传大小是受到多种因素制约的,现总结如下:
1、php.ini:upload_max_filesize 所上传的文件的最大大小。默认值2M。
2、php.ini:memory_limit 本指令设定了一个脚本所能够申请到的最大内存字节数,默认值8M。如果不需要任何内存上的限制,必须将其设为 -1。如果内存不够,则可能出现错误:Fatal error: Allowed memory size of X bytes exhausted (tried to allocate Y bytes)
3、php.ini:post_max_size 设定POST数据所允许的最大大小。此设定也影响到文件上传。要上传大文件,该值必须大于 upload_max_filesize。
4、php.ini:max_execution_time = 30 ; Maximum execution time of each script, in seconds
5、php.ini:max_input_time = 60 ; Maximum amount of time each script may spend parsing request data
6、如果用到mysql的BLOB进行二进制文件存储,则需要设置my.ini:max_allowed_packet=xxM
7、httpd.conf
在 Apache 里面有一个选项是 LimitRequestBody,这个选项可以限制用户送出的 HTTP 请求内容。这个选项可以在 .htaccess 或 httpd.conf 里使用,而如果在 httpd.conf 内使用,分别可以用在 virtualhost 或目录属性设定。而 LimitRequestBody 的设定值是介乎 0 (无限制) 至 2147483647 (2GB)。
例如要在目录 D:/AppServ/www 设定上传限制为 100K,可以在 .htaccess 或 httpd.conf 加入以下语句:
LimitRequestBody 1024000000
Options Indexes FollowSymLinks MultiViews ExecCGI
AllowOverride All
Order allow,deny
Allow from all
LimitRequestBody 1024000000Options Indexes FollowSymLinks MultiViews ExecCGIAllowOverride AllOrder allow,denyAllow from all
如果透过 .htaccess 设定,储存档案后会立即生效;如透过 httpd.conf 设定,须要重新启动 Apache。
PHP关于文件上传部分,特别提到表单隐藏域:MAX_FILE_SIZE,意思是接收文件的最大尺寸。文档中给出的例子如下:
<form enctype="multipart/form-data" action="_URL_" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="30000">
Send this file: <input name="userfile" type="file">
<input type="submit" value="Send File">
form>
Send this file:
这里设置MAX_FILE_SIZE = 30000,期待一种可能,使得浏览器在传送文件之前能够依此作出预先判断,如果文件尺寸大于30000字节,则不执行实际的POST动作。也就是不往服务器发送文件内容,而是直接在客户端提醒用户“你试图上传的文件超过30000字节”。
这的确是一个非常棒的主张,但在现实中却暂时无法实现。不是因为这个限制可以“被简单地绕过”,而是IE和FireFox这两个主流浏览器都不支持这个特性。PHP的这个建议尚未被采纳。
MAX_FILE_SIZE还有一个用场:后台PHP会判断接收到的文件大小是否大于这个值,如果超出,$_FILES['thisfile']['error']会被设置为UPLOAD_ERR_FORM_SIZE(2),同时放弃保存临时文件,将$_FILES['thisfile']['size']置0。
这个例子,没问题,表现正常,当我试图上传一个40多K的文件时,PHP程序报告“文件超过MAX_FILE_SIZE”。
但是,如果我们将表单中的MAX_FILE_SIZE从30000减少到1000,情形又如何呢?
上传800字节的文件,正常;
上传40K的文件,PHP报告文件过大,也正常;
上传3000个字节的文件,PHP未报告错误,它成功保存了文件!出乎意料!
问题就出在main/rfc1867.c中判断文件是否超长的这部分代码上。php每次从buffer中读取FILLUNIT字节长度的内容后,首先判断“已经读到的内容长度(total_bytes)”是否大于MAX_FILE_SIZE,然后再增加“已经读到的内容长度(total_bytes)”。这样一来,和预计的结果之间至多会有FILLUNIT字节的误差,而FILLUNIT=1024*5=5K。(点击bug了解详细内容)
这就是说,当MAX_FILE_SIZE<5K时,上传一个大于MAX_FILE_SIZE,但是小于5K的文件是没有问题的。
当然,因为这个设置很容易被绕过,所以服务器端编程不应当依赖于MAX_FILE_SIZE。而且,5K到底是个很小的数值,对大多数上传文件的表单来说没有影响。
PHP中post_max_size,upload_max_filesize, MAX_FILE_SIZE的设置,和客户端上传给服务器端的流量大小无关。
Apache服务器从客户端接收长度不超过LimitRequestBody字节数的请求,然后传送给php模块,php模块再决定是否保存成临时文件,设置$_FILES全局变量,移交给script进一步处理。
这个Apache的LimitRequestBody选项缺省值=0,允许Request body的最大字节数是2G(Linux + Apache)
最后还要注意的是:
html本身能够post数据也是有限制的,不能超过2G。
ftp客户端有文件偏移指针的2GB边界限制,未使用特殊编译flag编译的ftp服务器端或者客户端,无论在什么FS中都不支持大于2GB的文件。不知道PHP会不会也有这种情况。
㈩ PHP 如何将上传的文件转化为buffer数据格式
$upfile=readfile($_FILES['fileField']['tmp_name']);
就可以了。如果想用get方式传输文件的话,就把它base64一下,变成字符串。
$str=base64_encode($upfile);
就可以把生成的字符串放到url的get参数里来传输。