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參數里來傳輸。