目錄:
一、如何使用php導入導出csv?
二、php接收POST數據的方式有哪些?
三、如何讓json_encode()不轉義斜槓?我在作服務器返回一些數據時須要返回一些地址,可是默認的json_code是會對 / 轉義成 \/ 的
四、新浪微博、QQ空間、今日頭條PC版、蘑菇街、美麗說等網站是如何實現滾屏加載的?即:無刷新動態加載數據技術的應用
五、移動瀏覽器的判斷方法(通用)
六、php中如何優化多個 if...elseif...elseif...else... 語句的狀況?
七、php如何檢測當前是否是正在使用HTTPS協議?
八、php如何實如今數組$items的任意位置插入數據?
九、如何快速提取URL中的域名?以下 $url='http://bbs.sijiaomao.com/read.php?tid=942&fid=22';如何快速提取 "bbs.sijiaomao.com"
十、若是用foreach來訪問PHP的數組, 遍歷的順序是固定的麼? 有什麼規律可循呢 ?php
十一、php中如何使用file_get_contents()發送post請求?html
十二、如何判斷php是線程安全仍是非線程安全的?nginx
1三、php線程安全與非線程安全版本的區別?程序員
1四、Windows下的PHP開發環境搭建——PHP線程安全與非線程安全、Apache版本選擇,及詳解五種運行模式。web
1五、線程與進程的區別ajax
1六、FastCgi與PHP-fpm之間是個什麼樣的關係apache
1七、PHP的線程安全模式(Thread Safety)編程
一、如何使用php導入導出csv?json
<?php //讀取csv文件中數據:使用php內置函數fgetcsv() function input_csv($handle) { $out = array (); $n = 0; while ($data = fgetcsv($file_handle, 10000)) { $num = count($data); for ($i = 0; $i < $num; $i++) { $out[$n][$i] = $data[$i]; } $n++; } return $out; } //導出數據到csv function export_csv($filename,$data) { header("Content-type:text/csv"); header("Content-Disposition:attachment;filename=".$filename); header('Cache-Control:must-revalidate,post-check=0,pre-check=0'); header('Expires:0'); header('Pragma:public'); echo $data; } ?>
二、php接收POST數據的方式有哪些?windows
一般狀況下用戶使用瀏覽器網頁表單向服務器post提交數據,咱們使用PHP接收用戶POST到服務器的數據,並進行適當的處理。但有些狀況下,如用戶使用客戶端軟件向服務端php程序發送post數據,而不能用$_POST來識別,那又該如何處理呢?
①$_POST方式接收數據
$_POST方式是經過 HTTP POST 方法傳遞的變量組成的數組,是自動全局變量。如使用$_POST['name']就能夠接收到網頁表單以及網頁異步方式post過來的數據,即$_POST只能接收文檔類型爲Content-Type: application/x-www-form-urlencoded提交的數據。
②$GLOBALS['HTTP_RAW_POST_DATA']方式接收數據
若是用過post過來的數據不是PHP可以識別的文檔類型,好比 text/xml 或者 soap 等等,咱們能夠用$GLOBALS['HTTP_RAW_POST_DATA']來接收。$HTTP_RAW_POST_DATA 變量包含有原始的POST數據。此變量僅在碰到未識別MIME 類型的數據時產生。$HTTP_RAW_POST_DATA 對於enctype="multipart/form-data" 表單數據不可用。也就是說使用$HTTP_RAW_POST_DATA沒法接收網頁表單post過來的數據。
③php://input方式接收數據
若是訪問原始 POST 數據的更好方法是 php://input。php://input 容許讀取 POST 的原始數據。和 $HTTP_RAW_POST_DATA 比起來,它給內存帶來的壓力較小,而且不須要任何特殊的php.ini設置,而php://input不能用於 enctype="multipart/form-data"。
例如,用戶使用某個客戶端應用程序post給服務器一個文件,文件的內容咱們無論它,可是咱們要把這個文件完整的保存在服務器上,咱們能夠使用以下代碼:
$input = file_get_contents('php://input'); file_put_contents($original, $input); //$original爲服務器上的文件
以上代碼使用file_get_contents('php://input')接收post數據,而後將數據寫入$original文件中,其實能夠理解爲從客戶端上傳了一個文件到服務器上,此類應用很是多,尤爲是咱們PHP開發要與C,C++等應用程序開發進行產品聯合開發時會用到,例如本站有文章:拍照上傳就是結合flash利用此原理來上傳照片的。
如下是一個小示例,演示了$_POST,$GLOBALS['HTTP_RAW_POST_DATA']和php://input三種不一樣方式的接收POST數據處理:
a.html
<form name="demo_form" action="post.php" method="post"> <p><label>Name: </label><input type="text" class="input" name="name"></p> <p><label>Address: </label><input type="text" class="input" name="address"></p> <p><input type="submit" name="submit" class="btn" value="Submit"></p> </form>
post.php
header("Content-type:text/html;charset=utf-8"); echo '$_POST接收:<br/>'; print_r($_POST); echo '<hr/>'; echo '$GLOBALS[\'HTTP_RAW_POST_DATA\']接收:<br/>'; print_r($GLOBALS['HTTP_RAW_POST_DATA']); echo '<hr/>'; echo 'php://input接收:<br/>'; $data = file_get_contents('php://input'); print_r(urldecode($data));
輸出結果:
$_POST接收:
Array( [name] => xiaoqiang [address] => huilongguan [submit] => Submit)
$GLOBALS['HTTP_RAW_POST_DATA']接收:
php://input接收:
name=xiaoqiang&address=huilongguan&submit=Submit
三、如何讓json_encode()不轉義斜槓?我在作服務器返回一些數據時須要返回一些地址,可是默認的json_code是會對 / 轉義成 \/ 的,因此解決辦法有以下兩種:
echo str_replace("\\/", "/", json_encode("<font color='red'>www.baidu.com<\/font>")); //第一種方式:正則替換 echo json_encode("<font color='red'>www.baidu.com<\/font>", JSON_UNESCAPED_SLASHES); //第二種方式:php5.4+ echo json_encode("百度", JSON_UNESCAPED_UNICODE); //漢字不轉義爲\u開頭的UNICODE數據,必須PHP5.4+
四、新浪微博、QQ空間、今日頭條PC版、蘑菇街、美麗說等網站是如何實現滾屏加載的?即:無刷新動態加載數據技術的應用
//①、首先,咱們要獲取瀏覽器可視區域頁面的高度 var winH = $(window).height(); //②、而後,當滾動頁面的時候須要作的事情是:計算頁面總高度(當滾動底部時,頁面新加載數據,因此頁面總高度是動態變化的),計算滾動條位置(滾動條位置也是隨着加載頁面的高度動態變化的),而後構造一個公式,計算相對比例。 $(window).scroll(function () { var pageH = $(document.body).height(); //頁面總高度 var scrollT = $(window).scrollTop(); //滾動條top var aa = (pageH-winH-scrollT)/winH;//aa值越小,滾動條越接近底部 理想狀態下:頁面總高度 = 瀏覽器可視區域頁面高度 + 滾動條正好在底部時的top高度 }); //③、當滾動條接近頁底時,觸發ajax加載,在本例中咱們使用jQuery的getJSON方法,向服務端result.php發送請求,請求的參數爲page,即頁數。 if(aa<0.02){ $.getJSON("result.php",{page:i},function(json){ ..... }); } //④、若是請求響應成功返回JSON數據,則解析JSON數據,並將數據追加到頁面DIV#container後,若是沒有JSON數據返回,則說明數據所有顯示完畢。 if(json){ var str = ""; $.each(json,function(index,array){ //遍歷 var str = "..."; //獲取的JSON數據 $("#container").append(str); //追加 }); i++; //頁數+1 }else{ $(".nodata").show().html("別滾動了,已經到底了。。。"); return false; } //完整的代碼 $(function(){ var winH = $(window).height(); //頁面可視區域高度 var i = 1; //設置當前頁數 $(window).scroll(function () { var pageH = $(document.body).height(); var scrollT = $(window).scrollTop(); //滾動條top var aa = (pageH-winH-scrollT)/winH; if(aa<0.02){ $.getJSON("result.php",{page:i},function(json){ if(json){ var str = ""; $.each(json,function(index,array){ var str = "<div class=\"single_item\"><div class=\"element_head\">"; var str += "<div class=\"date\">"+array['date']+"</div>"; var str += "<div class=\"author\">"+array['author']+"</div>"; var str += "</div><div class=\"content\">"+array['content']+"</div></div>"; $("#container").append(str); }); i++; }else{ $(".nodata").show().html("別滾動了,已經到底了。。。"); return false; } }); } }); });
$(window).scroll(function(){ var scrollTop = $(this).scrollTop(); var scrollHeight = $(document).height(); var windowHeight = $(this).height(); if(scrollTop + windowHeight == scrollHeight){ alert("you are in the bottom"); } });
五、移動瀏覽器的判斷方法(通用)
<?php /** * 移動瀏覽器判斷 * * @return bool */ function browse_is_mobile () { return false; $user_agent = $_SERVER['HTTP_USER_AGENT']; if(preg_match("/iPhone/i", $user_agent) || preg_match("/iPod/i", $user_agent) || preg_match("/Android/i", $user_agent)){ return true; } else { return false; } } /** * 檢測瀏覽器類型 * * @return bool|int */ function check_mobile_browse () { $user_agent = $_SERVER['HTTP_USER_AGENT']; if(preg_match("/iPhone/i", $user_agent) || preg_match("/iPod/i", $user_agent)){ return 1; } elseif (preg_match("/Android/i", $user_agent)) { return 2; } else { return false; } } ?>
六、php中如何優化多個 if...elseif...elseif...else... 語句的狀況?
<?php //對於不少時候咱們須要用N多個if,elseif,elseif…來達到連續斷定完後取出某個值的效果,例如: $data = array(); if("login"==$type){ $data = array("uid"=>1,"pwd"=>123); }elseif("register"==$type){ $data = array("username"=>"max","new_pwd"=>432); }elseif("put_info"==$type){ $data = array("something"=>"Hello"); } //向上面這樣的連續判斷效率較低,有些人會說改爲switch case 的寫法,效率會高過if,可是依然是十分的繁瑣,以下: $data = array(); switch($type){ case "login": $data = array("uid"=>1,"pwd"=>123); break; case "register": $data = array("username"=>"max","new_pwd"=>432); break; case "put_info": $data = array("something"=>"Hello"); break; } //可是這樣寫依然會比較麻煩,且運行效率也不會過高,當數據量較大的時候速度會比較慢,如上程序改爲以下樣式: //優勢:在php中數組使用的是hashtable,時間複雜度是O(1),運行速度遠遠高於以上兩種,另外書寫起來也更簡便的多。即便傳入的參數是未定義的,也不會浪費大量的系統資源 $data_arr = array( "login" => array("uid"=>1,"pwd"=>123), "register" => array("username"=>"max","new_pwd"=>432), "put_info" => array("something"=>"Hello") ); if(isset($data_arr[$type])){ $data = $data_arr[$type]; } ?>
七、php如何檢測當前是否是正在使用HTTPS協議?
<?php function is_HTTPS(){ if(!isset($_SERVER['HTTPS'])) return FALSE; if($_SERVER['HTTPS'] === 1){ //Apache return TRUE; }elseif($_SERVER['HTTPS'] === 'on'){ //IIS return TRUE; }elseif($_SERVER['SERVER_PORT'] == 443){ //其餘 return TRUE; } return FALSE; } ?>
八、php如何實如今數組$items的任意位置插入數據?
<?php $items= ['蘋果','橘子','梨','菠蘿','香蕉','火龍果'] ; /* $items 傳入的數組 $index 要插入的位置 $value 要插入的數據 */ function insertAt($items, $index, $value) { return $items; } $items=insertAt($items, 2 , '橙子'); //執行完成後,結果以下: ['蘋果','橘子','橙子','梨','菠蘿','香蕉','火龍果'] ; ?>
九、如何快速提取URL中的域名?以下 $url='http://bbs.sijiaomao.com/read.php?tid=942&fid=22';如何快速提取 "bbs.sijiaomao.com"
<?php echo parse_url($url, PHP_URL_HOST); ?>
十、若是用foreach來訪問PHP的數組, 遍歷的順序是固定的麼? 有什麼規律可循呢 ?
<?php //PHP中遍歷數組的順序, 是和元素的添加前後相關的! 因此無論是索引數組仍是關聯數組,結果都同樣,添加的順序就是依據! 至於爲何會這樣,就須要深刻探尋數組的底層實現原理了 $items[2] = 2015; $items[1] = 2014; $items[0] = 2013; foreach ($items as $key => $val) { //結果是什麼? echo $key,' => ' ,$val, "\n"; } ?>
十一、php中如何使用file_get_contents()發送post請求?
<?php //咱們知道PHP中的file_get_contents無比強大,不只僅能讀取文件內容,還能設置超時時間採集網頁數據。那麼,可否用file_get_contents來發送post請求呢,若是能,改如何寫? $postdata = http_build_query( array( 'username' => '號外', 'password' => '123456' ) ); $opts = array('http' => array( 'method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata ) ); $context = stream_context_create($opts); $result = file_get_contents('http://www.baidu.com/server.php', false, $context); ?>
1三、如何判斷php是線程安全仍是非線程安全的?
什麼是線程安全與非線程安全?
線程安全就是在多線程環境下也不會出現數據不一致,而非線程安全就有可能出現數據不一致的狀況。
線程安全因爲要確保數據的一致性,因此對資源的讀寫進行了控制,換句話說增長了系統開銷。因此在單線程環境中效率比非線程安全的效率要低些,可是若是線程間數據相關,須要保證讀寫順序,用線程安全模式
這個主要是針對web server 而言,在windows環境下,若是你使用的web server 是apchae 或者 iis 7如下版本,則應該選擇線程安全的安裝文件,而若是你使用Fast-cgi模式時,能夠選擇非線程安全,由於 web sever 自己能保證線程安全。
固然還有二進制文件編譯時所使用的編譯器:vc9 (vs系列) vc6(gcc)
如樓上所言,是針對web server的,部分web server在處理應用請求的時候是用多線程而非多進程的方式處理,線程方式由於涉及到共享寄存器和內存,因此很容易出錯,這個時候程序就須要花一些額外的經歷去處理寄存器中的數據一致性,即保證線程安全。
因此是否採用線程安全主要看你的web server所採用的PHP請求處理方式,若是是多線程處理,那麼請選擇線程安全的,不然選擇非線程安全的,如樓上所說Fast-cgi方式可選擇非線程安全的
先從字面意思上理解,None-Thread Safe就是非線程安全,在執行時不進行線程(thread)安全檢查;Thread Safe就是線程安全,執行時會進行線程(thread)安全檢查,以防止有新要求就啓動新線程的 CGI 執行方式耗盡系統資源。
再來看PHP的兩種執行方式:ISAPI和FastCGI。FastCGI執行方式是以單一線程來執行操做,因此不須要進行線程的安全檢查,除去線程安全檢查的防禦反而能夠提升執行效率,因此,若是是以 FastCGI(不管搭配 IIS 6 或 IIS 7)執行 PHP ,都建議下載、執行 non-thread safe 的 PHP (PHP 的二進位檔有兩種包裝方式:msi 、zip ,請下載 zip 套件)。而線程安全檢查正是爲ISAPI方式的PHP準備的,由於有許多php模塊都不是線程安全的,因此須要使用Thread Safe的PHP。
說到這裏,你們應該知道應該如何選擇哪一個版本的PHP了。None-Thread Safe or Thread Safe,您會選擇哪一個?
Windows下的PHP如今的版本已是5.3.6,如今的Windows版本能夠在PHP官方PHP For Windows(http://windows.php.net/download/)下載,下載的時候同版本有VC9 x86 Non Thread Safe、VC9 x86 Thread Safe、VC6 x86 Non Thread Safe、VC6 x86 Thread Safe等四個版本。那麼這些版本有什麼區別呢?
VC9的版本是用legacy VS 2008編譯的,VC6的版本是用legacy VS6編譯的。
若是你是在windows下使用IIS+PHP的話,你須要下載VC9的版本。
若是你是在windows下使用Apache+PHP的話,你須要下載VC6的版本。
Non Thread Safe是指非線程安全,Thread Safe則是指線程安全。
若是是使用ISAPI的方式來運行PHP就必須用Thread Safe(線程安全)的版本;而用FastCGI模式運行PHP的話就沒有必要用線程安全檢查了,用None Thread Safe(NTS,非線程安全)的版本可以更好的提升效率。
如何判斷:
經過phpinfo(); 查看其中的 Thread Safety 項,這個項目就是查看是不是線程安全,若是是:enabled,通常來講應該是ts版,不然是nts版。
1三、php線程安全與非線程安全版本的區別是什麼?
Windows版的PHP從版本5.2.1開始有Thread Safe(線程安全)和None Thread Safe(NTS,非線程安全)之分,這二者不一樣在於何處?到底應該用哪一種?這裏作一個簡單的介紹
從2000年10月20日發佈的第一個Windows版的PHP3.0.17開始的都是線程安全的版本,這是因爲與Linux/Unix系統是採用多進程的工做方式不一樣的是Windows系統是採用多線程的工做方式。若是在IIS下以CGI方式運行PHP會很是慢,這是因爲CGI模式是創建在多進程的基礎之上的,而非多線程。
通常咱們會把PHP配置成以ISAPI的方式來運行,ISAPI是多線程的方式,這樣就快多了。但存在一個問題,不少經常使用的PHP擴展是以Linux/Unix的多進程思想來開發的,這些擴展在ISAPI的方式運行時就會出錯搞垮IIS。所以在IIS下CGI模式纔是PHP運行的最安全方式,但CGI模式對於每一個HTTP請求都須要從新加載和卸載整個PHP環境,其消耗是巨大的。
爲了兼顧IIS下PHP的效率和安全,微軟給出了FastCGI的解決方案。FastCGI可讓PHP的進程重複利用而不是每個新的請求就重開一個進程。同時FastCGI也能夠容許幾個進程同時執行。這樣既解決了CGI進程模式消耗太大的問題,又利用上了CGI進程模式不存在線程安全問題的優點。
所以,若是是使用ISAPI的方式來運行PHP就必須用Thread Safe(線程安全)的版本;而用FastCGI模式運行PHP的話就沒有必要用線程安全檢查了,用None Thread Safe(NTS,非線程安全)的版本可以更好的提升效率。
PHP官方http://php.net/上關於widows的版本有4個:VC9 x86 Non Thread Safe,VC9 x86 Thread Safe,VC6 x86 Non Thread Safe,VC6 x86 Thread Safe;那麼有什麼區別呢?
1.支持的服務器不一樣
VC9版本是針對IIS服務器的版本,沒有對APACHE的支持,而VC6版本對IIS和apache都提供了支持
VC6 是什麼?VC6 就是 legacy Visual Studio 6 compiler ,就是使用這個編譯器編譯的。
VC9 是什麼?VC9 就是 the Visual Studio 2008 compiler ,就是用微軟的 VS 編輯器編譯的。
那咱們如何選擇下載哪一個版本的 PHP 呢?
若是你是在 windows 下使用 Apache+PHP 的,請選擇 VC6 版本;
若是你是在 windows 下使用 IIS+PHP 的,請選擇 VC9 版本;
2.運行方式的不一樣
PHP有2中運行方式:ISAPI和FastCGI。
ISAPI執行方式是以DLL動態庫的形式使用,能夠在被用戶請求後執行,在處理完一個用戶請求後不會立刻消失,因此須要進行線程安全檢查,這樣來提升程序的執行效率,因此若是是以ISAPI來執行PHP,建議選擇Thread Safe版本;
而FastCGI執行方式是以單一線程來執行操做,因此不須要進行線程的安全檢查,除去線程安全檢查的防禦反而能夠提升執行效率,因此,若是是以FastCGI來執行PHP,建議選擇Non Thread Safe版本。
對於apache服務器來講通常選擇isapi方式,而對於nginx服務器則選擇FastCGI方式。
3.總結
PHP所推出的Thread Safe主要針對的是Windows下以IIS來運行PHP的狀況,由於Windows中頻繁申請進程開銷較大,因此在Windows中要以多線程方式來運轉PHP,這時候就須要Thread Safe版本。而在Linux系統下,PHP絕大多數狀況下都以多進程方式運行,因此直接使用None Thread Safe便可。
若是是使用ISAPI的方式來運行PHP就必須用Thread Safe(線程安全)的版本;而用FastCGI模式運行PHP的話就沒有必要用線程安全檢查了,用None Thread Safe(NTS,非線程安全)的版本可以更好的提升效率。
若是有多線程,就用線程安全版;若是隻有一個線程,就用非線程安全版。
1四、Windows下的PHP開發環境搭建——PHP線程安全與非線程安全、Apache版本選擇,及詳解五種運行模式
Windows下的PHP開發環境搭建——PHP線程安全與非線程安全、Apache版本選擇,及詳解五種運行模式。
今天爲在Windows下創建PHP開發環境,在考慮下載何種PHP版本時,遭遇一些讓我困惑的狀況,爲了解決這些困惑,不出意料地牽扯出更多讓我困惑的問題。
爲了將這些困惑一網打盡,我花了一下午加一夜的時間查閱了大量資料,並作了一番實驗後,終於把這些困惑全都搞得清清楚楚了。
說實話,之因此花了這麼多時間,很大程度上是因爲網上的資料幾乎全都是支離破碎、以訛傳訛的。既然我已經搞懂了,就花時間整理出來,即方便本身看,也便於你們閱讀。相信經過這篇文章,能夠解答不少在Windows下搭建PHP開發環境的朋友的困惑。
關於從何處下載Apache:
要安裝Apache,你可能想固然地會去Apache官方網站下載適用於Windows的二進制版本。而這偏偏錯了!
PHP官方不建議在Windows下安裝從apache.org網站下載的Apache二進制安裝包。緣由是若是你使用來自apache.org的安裝包,則因爲這些安裝包是基於陳舊的Visual Studio 6編譯的,致使你不得沒必要須使用一樣陳舊的PHP版本(即VC6的PHP版本。也即便用Visual Studio 6編譯的PHP版本)才能與其配合使用。
要想使用最新版的PHP,應遵從PHP的官方建議。PHP官方的建議是你在Windows下能夠使用IIS,或者使用來自Apache Lounge(www.apachelounge.com)的Apache版本。
Apache Lounge所提供的Apache二進制安裝包是使用VC11創建的。所以可搭配最新版本的PHP使用。
網上不少資料說若是你是在Windows下使用 Apache,則必須使用PHP的VC6版本,只有使用IIS時才能使用VC9及以上版本,徹底是沒有搞清狀況的以訛傳訛。
如何選擇PHP版本(選擇線程安全仍是非線程安全):
在Windows下安裝PHP,在選擇PHP版本上頗有講究。
Windows下的PHP版本分兩種:線程安全版本與非線程安全版本。
若是你打算使用IIS,則你能夠以ISAPI或FastCGI這兩種方式來安裝PHP。CGI的方式由於效率低下,故不予考慮。
若是你要在IIS中以FastCGI方式使用PHP,則你應該使用PHP的非線程安全的版本(Non-Thread Safe,NTS)。緣由是以FastCGI方式安裝PHP時,PHP擁有獨立的進程,而且FastCGI是單一線程的,不存在多個線程之間可能引起的相互干擾(這種干擾一般都是因爲全局變量和靜態變量致使的)。因爲省去了線程安全的檢查,所以使用FastCGI方式比ISAPI方式的效率更高一些。
若是你要在IIS中以ISAPI的方式使用PHP,則你應該使用PHP的線程安全版本(Thread Safe,TS)。緣由是PHP以ISAPI方式安裝時,PHP沒有獨立的進程,而是做爲DLL被IIS加載運行的,便是依附於Web服務器進程的。當Web服務器運行在多線程模式下(IIS正是這種狀況),PHP天然也就運行在多線程模式下。只要是在多線程模式下運行,就可能存在線程安全問題,所以應選擇PHP的線程安全版本。
但在這裏還有必要說明一下,儘管Apache自己是線程安全的,同時你也選擇了PHP的線程安全版本,但因爲一些Apache和PHP下的第三方擴展最初是基於Unix的多進程思想開發出來的,在設計開發時沒有考慮線程安全的問題,所以,不排除在這種狀況下仍然存在IIS被某些第三方擴展搞崩潰的可能。
若是你打算使用Apache,則你能夠以模塊、ISAPI、FastCGI這三種方式來安裝PHP。CGI的方式由於效率低下,故不予考慮。
若是你要在Apache中以模塊方式安裝PHP,則你應該使用PHP的線程安全的版本。緣由是當PHP做爲Apache的模塊安裝時,PHP沒有獨立的進程,而是做爲模塊以DLL的形式被加載到Apache中的,是隨Apache的啓動而啓動的,而Windows下的Apache爲多線程工做模式,所以PHP天然也就運行在多線程模式下。所以,這種狀況下應使用PHP的線程安全版本。
再來看ISAPI的狀況。一般認爲ISAPI是配合IIS使用的,由於ISAPI最初就是微軟爲IIS開發的。但Apache如今也能夠經過加載mod_isapi.so模塊來實現ISAPI的功能,以容許PHP以ISAPI的方式安裝。.so文件是Apache自1.3版本後製定的用於Windows下的模塊命名規則,對於Windows下的Apache而言,.so與.dll文件同樣,都是動態連接庫文件。
當要以ISAPI方式來安裝PHP時,一般是加載一個名如phpXisapi.dll的DLL文件,其中的X爲阿拉伯數字四、5等等這樣子。
但通常不建議在Apache中以ISAPI方式來安裝PHP,緣由是到目前爲止,Apache經過mod_isapi.so模塊來實現的ISAPI功能並不完整,並未完整實現微軟對ISAPI所制定的所有規範。
一樣的,因爲以ISAPI方式來安裝PHP時,PHP也沒有獨立的進程,也是做爲模塊被加載到Apache中的,所以,一樣也須要使用PHP的線程安全版本。
若是你要在Apache中以FastCGI方式使用PHP,則同在IIS中使用FastCGI的PHP的狀況同樣,你應該使用PHP的非線程安全的版本。緣由是在Apache中以FastCGI方式安裝PHP時,PHP擁有獨立的進程,而且FastCGI是單一線程的,故應使用PHP的非線程安全版本以提升性能。
1五、線程與進程的區別
這麼解釋問題吧:
1。單進程單線程:一我的在一個桌子上吃菜。
2。單進程多線程:多我的在同一個桌子上一塊兒吃菜。
3。多進程單線程:多我的每一個人在本身的桌子上吃菜。
多線程的問題是多我的同時吃一道菜的時候容易發生爭搶,例如兩我的同時夾一個菜,一我的剛伸出筷子,結果伸到的時候已經被夾走菜了。。。此時就必須等一我的夾一口以後,在還給另一我的夾菜,也就是說資源共享就會發生衝突爭搶。
1。對於 Windows 系統來講,【開桌子】的開銷很大,所以 Windows 鼓勵你們在一個桌子上吃菜。所以 Windows 多線程學習重點是要大量面對資源爭搶與同步方面的問題。
2。對於 Linux 系統來講,【開桌子】的開銷很小,所以 Linux 鼓勵你們儘可能每一個人都開本身的桌子吃菜。這帶來新的問題是:坐在兩張不一樣的桌子上,說話不方便。所以,Linux 下的學習重點你們要學習進程間通信的方法。
--
補充:有人對這個開桌子的開銷頗有興趣。我把這個問題推廣說開一下。
開桌子的意思是指建立進程。開銷這裏主要指的是時間開銷。
能夠作個實驗:建立一個進程,在進程中往內存寫若干數據,而後讀出該數據,而後退出。此過程重複 1000 次,至關於建立/銷燬進程 1000 次。在我機器上的測試結果是:
UbuntuLinux:耗時 0.8 秒
Windows7:耗時 79.8 秒
二者開銷大約相差一百倍。
這意味着,在 Windows 中,進程建立的開銷不容忽視。換句話說就是,Windows 編程中不建議你建立進程,若是你的程序架構須要大量建立進程,那麼最好是切換到 Linux 系統。
大量建立進程的典型例子有兩個,一個是 gnu autotools 工具鏈,用於編譯不少開源代碼的,他們在 Windows 下編譯速度會很慢,所以軟件開發人員最好是避免使用 Windows。另外一個是服務器,某些服務器框架依靠大量建立進程來幹活,甚至是對每一個用戶請求就建立一個進程,這些服務器在 Windows 下運行的效率就會不好。這"可能"也是放眼全世界範圍,Linux 服務器遠遠多於 Windows 服務器的緣由。
--
再次補充:若是你是寫服務器端應用的,其實在如今的網絡服務模型下,開桌子的開銷是能夠忽略不計的,由於如今通常流行的是按照 CPU 核心數量開進程或者線程,開完以後在數量上一直保持,進程與線程內部使用協程或者異步通訊來處理多個併發鏈接,於是開進程與開線程的開銷能夠忽略了。
另一種新的開銷被提上日程:核心切換開銷。
現代的體系,通常 CPU 會有多個核心,而多個核心能夠同時運行多個不一樣的線程或者進程。
當每一個 CPU 核心運行一個進程的時候,因爲每一個進程的資源都獨立,因此 CPU 核心之間切換的時候無需考慮上下文。
當每一個 CPU 核心運行一個線程的時候,因爲每一個線程須要共享資源,因此這些資源必須從 CPU 的一個核心被複制到另一個核心,才能繼續運算,這佔用了額外的開銷。換句話說,在 CPU 爲多核的狀況下,多線程在性能上不如多進程。
於是,當前面向多核的服務器端編程中,須要習慣多進程而非多線程。
--------------------------------------------------------------------------------------------------------
不少人答案說的是操做系統提供的多進程而不是單個程序內的多線程。
多線程使得程序內部能夠分出多個線程來作多件事情,而不會形成程序界面卡死。好比迅雷等多線程下載工具就是典型的多線程。一個下載任務進來,迅雷把文件平分紅10份,而後開10個線程分別下載。這時主界面是一個單獨的線程,並不會由於下載文件而卡死。並且主線程能夠控制下屬線程,好比某個線程下載緩慢甚至中止,主線程能夠把它強行關掉並重啓另一個線程。
另外就是一些程序的打印功能,好比記事本、Adobe Reader,打印的時候就只能打印,沒法在主界面進行操做,而Word就有「後臺打印」的功能,點了打印命令以後,還能夠回到主界面進行修改、保存等操做。
另外多線程除了並行完成一些任務之外,還有生產者-消費者模式。好比Windows命令行下在某個硬盤根目錄執行一個"dir/s | more"命令,前一條顯示硬盤裏的全部文件,要執行好久才能執行得完,後面那條命令會把前面命令的輸出分屏顯示出來。可是執行整條命令時,會馬上有顯示,也就是說,前面一條命令輸出滿一頁內容到緩衝區,more命令就把緩衝區封死了,等用戶敲了一個鍵顯示下一屏的時候,more命令把緩衝區的內容取出並清空,前面的命令才能輸出下一屏到緩衝區。這樣的多線程使得整條命令不用等待前面的命令所有執行完才能執行下一條命令。
多線程和多進程的區別。日常指的多進程是操做系統下同時運行多個進程,好比Word和Excel同時打開,而且能夠並行地同時執行一些操做。這種多進程和多線程沒什麼比如較的。能夠比較的是同一個程序裏的多線程和多進程。
多線程由於在同一個進程裏,因此能夠共享內存和其餘資源,好比迅雷裏10個線程一齊下載一個文件,這個文件是由進程打開的,而後10個線程均可以往裏寫入東西。若是是10個進程就不行了,操做系統不容許一個文件由兩個進程同時寫入。另外,Chrome就是一個典型的多進程程序,裏面每一個標籤頁、擴展、插件都是單獨的進程,各自獨佔資源,相互隔離,一個進程出錯死掉只會影響一個頁面或者插件,不再會出現Flash插件出錯崩潰致使整個瀏覽器崩潰的狀況了。
--------------------------------------------------------------------------------------------------------
多線程最通常的應用是簡化程序的寫法。好比對於IO工做而言,若是底層的API僅提供了同步操做函數,這樣一來,單線程的應用很難寫,可是支持多線程後,徹底能夠把IO操做轉入線程中執行,主線程仍然能夠進行正常的消息循環。
舉一個小例子。你用qq郵箱的中轉站功能,上傳一個文件,在文件傳輸的時候,你能夠最小化上傳窗口,去發送、查看郵件,這個就是典型的多線程例子。
打個比方:咱們寢室洗手檯有2個水龍頭,就是多線程。能夠知足2我的刷牙。否則排隊蛋疼。
舉個最最最簡單的例子,程序裏面要幹兩件絕不相干的事情A和B,各費時10分鐘,那單線程程序就會這樣:等A完了再執行B,總共耗時20分鐘。但若是將A和B用兩個線程來作則以下:等待兩個線程結束。若是兩個線程被分配到不一樣的cpu上,則理論耗時共10分鐘。
--------------------------------------------------------------------------------------------------------
一樣以吃飯舉例子,假設不少人須要吃飯吃飯,桌子不夠,那麼桌子就是緊缺資源。單線程就是整個餐廳只有一個單人桌,這我的吃完了,下一我的輪上。但大餐館用的多是八仙桌(好吧我比較喜歡這種古代的方正桌子),同時能容納八我的吃飯,這就是多線程:從一次一個變成了一次多個或者屢次多個。如何安排吃飯順序對程序員來講是個巨大的挑戰,主要問題在於對資源-桌子的安排上,舉例說明:
1.死鎖-你們都在等着吃飯,但須要特定條件才能開吃:桌一等着桌二的碗,桌二等着桌三的筷子,桌三呢,等着桌一的勺。因而這三桌就都不能吃飯。
2.非原子變量更新-空閒桌子的數字是要加以保護的,相似於特定人員才能修改,假如沒有保護,空桌子一下子是四個,一下子是五個,最終的數字每每是不正確的,服務員要被玩死-這就是多線程的加鎖操做。
還有其餘幾種,就很少說了,多線程的調度和使用是一個坑,是否能用好是程序員水平高低的一個標誌。
1六、FastCgi與PHP-fpm之間是個什麼樣的關係
我在網上查fastcgi與php-fpm的關係,查了快一週了,基本看了個遍,真是衆說紛紜,沒一個權威性的定義。
網上有的說,fastcgi是一個協議,php-fpm實現了這個協議; 有的說,php-fpm是fastcgi進程的管理器,用來管理fastcgi進程的; 有的說,php-fpm是php內核的一個補丁; 有的說,修改了php.ini配置文件後,沒辦法平滑重啓,因此就誕生了php-fpm; 還有的說PHP-CGI是PHP自帶的FastCGI管理器,那這樣的話幹嘛又弄個php-fpm出來,我就更暈了;
發個貼,想聽聽你們的理解,網上的我都已經看了個遍,由於我查了一週了,哈哈,因此想聽聽原創的理解。
-------------------------------------------------------------------------------------------------
剛開始對這個問題我也挺糾結的,看了《HTTP權威指南》後,感受清晰了很多。
首先,CGI是幹嗎的?CGI是爲了保證web server傳遞過來的數據是標準格式的,方便CGI程序的編寫者。
web server(好比說nginx)只是內容的分發者。好比,若是請求/index.html,那麼web server會去文件系統中找到這個文件,發送給瀏覽器,這裏分發的是靜態數據。好了,若是如今請求的是/index.php,根據配置文件,nginx知道這個不是靜態文件,須要去找PHP解析器來處理,那麼他會把這個請求簡單處理後交給PHP解析器。Nginx會傳哪些數據給PHP解析器呢?url要有吧,查詢字符串也得有吧,POST數據也要有,HTTP header不能少吧,好的,CGI就是規定要傳哪些數據、以什麼樣的格式傳遞給後方處理這個請求的協議。仔細想一想,你在PHP代碼中使用的用戶從哪裏來的。
當web server收到/index.php這個請求後,會啓動對應的CGI程序,這裏就是PHP的解析器。接下來PHP解析器會解析php.ini文件,初始化執行環境,而後處理請求,再以規定CGI規定的格式返回處理後的結果,退出進程。web server再把結果返回給瀏覽器。
好了,CGI是個協議,跟進程什麼的不要緊。那fastcgi又是什麼呢?Fastcgi是用來提升CGI程序性能的。
提升性能,那麼CGI程序的性能問題在哪呢?"PHP解析器會解析php.ini文件,初始化執行環境",就是這裏了。標準的CGI對每一個請求都會執行這些步驟(不閒累啊!啓動進程很累的說!),因此處理每一個時間的時間會比較長。這明顯不合理嘛!那麼Fastcgi是怎麼作的呢?首先,Fastcgi會先啓一個master,解析配置文件,初始化執行環境,而後再啓動多個worker。當請求過來時,master會傳遞給一個worker,而後當即能夠接受下一個請求。這樣就避免了重複的勞動,效率天然是高。並且當worker不夠用時,master能夠根據配置預先啓動幾個worker等着;固然空閒worker太多時,也會停掉一些,這樣就提升了性能,也節約了資源。這就是fastcgi的對進程的管理。
那PHP-FPM又是什麼呢?是一個實現了Fastcgi的程序,被PHP官方收了。
你們都知道,PHP的解釋器是php-cgi。php-cgi只是個CGI程序,他本身自己只能解析請求,返回結果,不會進程管理(皇上,臣妾真的作不到啊!)因此就出現了一些可以調度php-cgi進程的程序,好比說由lighthttpd分離出來的spawn-fcgi。好了PHP-FPM也是這麼個東東,在長時間的發展後,逐漸獲得了你們的承認(要知道,前幾年你們但是抱怨PHP-FPM穩定性太差的),也愈來愈流行。
好了,最後來回來你的問題。
網上有的說,fastcgi是一個協議,php-fpm實現了這個協議
對。
有的說,php-fpm是fastcgi進程的管理器,用來管理fastcgi進程的
對。php-fpm的管理對象是php-cgi。但不能說php-fpm是fastcgi進程的管理器,由於前面說了fastcgi是個協議,彷佛沒有這麼個進程存在,就算存在php-fpm也管理不了他(至少目前是)。 有的說,php-fpm是php內核的一個補丁
之前是對的。由於最開始的時候php-fpm沒有包含在PHP內核裏面,要使用這個功能,須要找到與源碼版本相同的php-fpm對內核打補丁,而後再編譯。後來PHP內核集成了PHP-FPM以後就方便多了,使用--enalbe-fpm這個編譯參數便可。
有的說,修改了php.ini配置文件後,沒辦法平滑重啓,因此就誕生了php-fpm
是的,修改php.ini以後,php-cgi進程的確是沒辦法平滑重啓的。php-fpm對此的處理機制是新的worker用新的配置,已經存在的worker處理完手上的活就能夠歇着了,經過這種機制來平滑過分。
還有的說PHP-CGI是PHP自帶的FastCGI管理器,那這樣的話幹嘛又弄個php-fpm出
不對。php-cgi只是解釋PHP腳本的程序而已。
----------------------------------------------------------------------------------------------
你(PHP)去和愛斯基摩人(web服務器,如 Apache、Nginx)談生意
你說中文(PHP代碼),他說愛斯基摩語(C代碼),互相聽不懂,怎麼辦?那就都把各自說的話轉換成英語(FastCGI 協議)吧。
怎麼轉換呢?你就要使用一個翻譯機(PHP-FPM)
(固然對方也有一個翻譯機,那個是他自帶的)
咱們這個翻譯機是最新型的,老式的那個(PHP-CGI)被淘汰了。不過它(PHP-FPM)只有年輕人(Linux系統)會用,老頭子們(Windows系統)不會擺弄它,只好繼續用老式的那個。
---------------------------------------------------------------------------------------------
Fastcgi是CGI的升級版,一種語言無關的協議,用來溝通程序(如PHP, Python, Java)和Web服務器(Apache2, Nginx), 理論上任何語言編寫的程序均可以經過Fastcgi來提供Web服務。
Fastcgi的特色是會在一個進程中依次完成多個請求,以達到提升效率的目的,大多數Fastcgi實現都會維護一個進程池。
而PHP-fpm就是針對於PHP的,Fastcgi的一種實現,他負責管理一個進程池,來處理來自Web服務器的請求。目前,PHP-fpm是內置於PHP的。
可是PHP-fpm僅僅是個「PHP Fastcgi 進程管理器」, 它仍會調用PHP解釋器自己來處理請求,PHP解釋器(在Windows下)就是php-cgi.exe.
---------------------------------------------------------------------------------------------
FASTCGI:WEB服務器與處理程序之間通訊的一種協議,是CGI的改進方案。
CGI程序反覆加載是CGI性能低下的主要緣由,若是CGI程序保持在內存中並接受FastCGI進程管理器調度,則能夠提供良好的性能、伸縮性、Fail-Over特性等。
FASTCGI是常駐型的CGI,它能夠一直運行,在請求到達時,不會花費時間去fork一個進程來處理。
FastCGI是語言無關的、可伸縮架構的CGI開放擴展,將CGI解釋器進程保持在內存中,以此得到較高的性能。
通常狀況下,FastCGI的整個工做流程是這樣的:
一、Web Server啓動時載入FastCGI進程管理器(IIS ISAPI或Apache Module)
二、FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程(可見多個php-cgi)並等待WebServer的鏈接。
三、當客戶端請求到達Web Server時,FastCGI進程管理器選擇並鏈接到一個CGI解釋器。 Web server將CGI環境變量和標準輸入發送到FastCGI子進程php-cgi。
四、FastCGI子進程完成處理後將標準輸出和錯誤信息從同一鏈接返回Web Server。當FastCGI子進程關閉鏈接時,請求便告處理完成。FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個鏈接。在CGI模式中,php-cgi在此便退出了。
-------------------------------------------------------------------------------------------
fastcgi 是 app server 和web server 之間的通訊協議。 正常架構 app server 是master,web server是client
php-fpm 帶兩個功能:1.實現了一個支持fastcgi協議的server程序 2. 進程管理器
有了php-fpm,就能夠把php腳本變成 多進程模式,採用fastcgi協議的app server,和web server進行通訊
-------------------------------------------------------------------------------------------
CGI => http://www.w3.org/CGI/
FastCGI => http://www.fastcgi.com/drupal/
FPM => FastCGI Process Manager(FastCGI進程管理器)
-------------------------------------------------------------------------------------------
fastcgi是一個協議,沒錯。php-fpm實現了這個協議,沒錯。 php-fpm的fastcgi協議須要有個金城吧?php-fpm實現的fastcgi進程就叫php-cgi= =。因此php-fpm就是他自身的fastcgi或php-cgi進程管理器,沒錯。php-fpm在5.2以前官方是沒有php-fpm的。php-fpm是做爲一個第三方的補丁你才能用的。5.2以後捏,官方就已經默認加入了,今後就不是一個補丁了。
-------------------------------------------------------------------------------------------
1七、PHP的線程安全模式(Thread Safety)
PHP自身是不支持線程的,可是它在安裝的時候,涉及到一個線程安全的問題,Windows下提供了二種安裝包,Linux下編譯安裝提供了–enable-maintainer-zts這個選項。不少人一看到「安全」,就覺得是好事,其實否則。既然PHP沒有線程,那麼這個線程安全指的是什麼呢?這和它的運行方式有關。這裏僅對Linux系統下流行的兩種PHP運行方式(LNMP和LNAMP)來說一下。若是是LNMP環境,也就是說PHP以php-fpm方式運行,那麼就不涉及到線程安全這個問題了,由於php-fpm是以多進程的方式來運行的。若是是以LNAMP或者LAMP方式運行(mod_php),那麼應該先了解下Apache的MPM,簡單點說,Apache支持以多線程的方式運行(Worker),也支持以多進程的方式運行(Prefork)。通常來說,Linux下的Apache絕大多數都是運行在Prefork模式下,這是出於穩定性的考慮。因此總結下,LNMP下不需線程安全,Apache下爲了穩定性的考慮,建議以多進程的方式運行(Prefork),這樣也是不須要線程安全的。最後一點,PHP安裝爲線程安全,會比非線程安全多佔用一些CPU,而且可能會增長bug或者不穩定的問題,這纔是重點,否則PHP就不必設置這個選項了。