php命令執行
1. php eval怎樣執行系統命令
eval — 把字元串作為PHP代碼執行
說明
mixedeval( string $code_str )
把字元串code_str作為PHP代碼執行。 除了其他,該函數能夠執行儲存於資料庫文本欄位內的PHP代碼。
使用eval()時需注意幾個因素:注意字元必須是有效的PHP代碼,包括結尾的分號,以不至於解釋器在eval()之後退出。並且正確地轉義code_str中的東西。你可以使用一個PHP閉合標簽來混合輸出HTML和PHP代碼。
同時需注意eval中的變數會被保留在之後的主腳本中。
參數
code_str需要被執行的字元串code_str不能包含 PHP Opening tags。
return語句會立即中止當前字元串的執行。
返回值
eval()返回NULL,除非在執行的代碼中return了一個值,函數返回該值。 如果在執行的代碼中有一個解析錯誤,eval()返回FALSE,之後的代碼將正常執行。無法使用 set_error_handler() 捕獲eval()中的解析錯誤。
範例
Example #1eval()例子 - 簡單的文本合並
<?php
$string = 'cup';
$name = 'coffee';
$str = 'This is a $string with my $name in it.';
echo $str. "\n";
eval("\$str = \"$str\";");
echo $str. "\n";
?>
以上常式會輸出:
This is a $string with my $name in it.This is a cup with my coffee in it.
Note: 因為是一個語言構造器而不是一個函數,不能被 可變函數 調用。
Tip和直接將結果輸出到瀏覽器一樣,可使用輸出控制函數來捕獲當前函數的輸出,然後(例如)保存到一個 string 中。
Note:
如果在執行的代碼中產生了一個致命的錯誤(fatal error),整個腳本會退出。
linux 中
shell中的eval命令將會首先掃描命令行進行所有的替換,然後再執行命令。該命令使用於那些一次掃描無法實現其功能的變數。該命令對變數進行兩次掃描。這些需要進行兩次掃描的變數有時候被稱為復雜變數。
例如
$:cat ext
count=3
cmd=echo
cmd="$cmd \$$count"
ext 11 22 33
此時cmd=" echo $3"
eval $cmd 等價於 "echo 33 "
2. 如何通過PHP執行linux命令
我使用的意思是想通過php代碼做的更好對任意那麼的目錄可讀可寫可卸載,可以執行kill pid等的命令。
當然還存在還存在的做法,這是我使用的猜測,您不妨試看看,
1、把php的運行網民改為root,這種可能會存在必須的風險。
2、在apache裡面指定可以對某個root許可權的文件或目錄做操作,該做法沒試驗過。可能您能試驗成功的話,希望反饋一下哦。
求助者:恩,第一種做法,我使用的想過,可就是我是想參考我集團的思路來,所以這種做法沒嘗試過。因為它存在安全疑問。
第二個做法,應該可以,可就是太局限性了。要是文件多咋辦,還存在我要想執行個kill,services restart等,肯定就不行了。
大家集團貌似是,寫了個linux命令,和您們的思路貌似是一樣的回者答:這是大家的做法:用VC寫個服務,該服務的運行身份是root,也可以給其最大許可權,php調用這個服務做操作。 該做法可行,只是就得多一種底層語言。
還存在的做法經測試:
第一種做法,成功。
我使用的項目用是VC寫的服務。
第一種做法,可以改變PHP的運行身份,SuexecUserGroup指定CGI程序運行時所使用的網民和組。非CGI程序的請求仍然使用User指令所指定的網民身份處理。該指令取代了Apache的VirtualHosts配置中的User和Group指令。建議您看下類似的文檔,個人做調試。好像還存在別的做法哦。好像是用super。這種您得個人摸索。我只提供思路哦`` 哈哈`` 謝謝``
3. linux下如何執行PHP腳本
在 Linux 下執行 php 腳本時通常是可以使用以下命令:
#/usr/local/php/bin/phptest.php
為簡化輸入可把此php執行程序 到系統命令目錄下:
#cp/usr/local/php/bin/php/usr/sbin/
驗證:輸入以下命令,如正確獲取 php 版本,說明操作成功。
#php-v
這樣,以後再執行PHP腳本時可直接採用以下輸入方式即可。
#phpa.php
4. 如何通過PHP執行linux命令
首先先要給大家介紹PHP執行linux系統命令的幾個基本函數。
system函數
說明:執行外部程序並顯示輸出資料。
語法:string system(string command, int [return_var]);
返回值: 字元串
詳細介紹:
本函數就像是 C 語中的函數 system(),用來執行指令,並輸出結果。若是 return_var 參數存在,則執行 command 之後的狀態會填入 return_var 中。同樣值得注意的是若需要處理用戶輸入的資料,而又要防止用戶耍花招破解系統,則可以使用 EscapeShellCmd()。若 PHP 以模塊式的執行,本函數會在每一行輸出後自動更新 Web 伺服器的輸出緩沖暫存區。若需要完整的返回字元串,且不想經過不必要的其它中間的輸出界面,可以使用 PassThru()。
實例代碼:
< ?php
$last_line = system('ls', $retval);
echo 'Last line of the output: ' . $last_line;
echo '<hr/>Return value: ' . $retval;
?>
exec函數
說明:執行外部程序。
語法:string exec(string command, string [array], int [return_var]);
返回值: 字元串
詳細介紹:
本函數執行輸入 command 的外部程序或外部指令。它的返回字元串只是外部程序執行後返回的最後一行;若需要完整的返回字元串,可以使用 PassThru() 這個函數。
要是參數 array 存在,command 會將 array 加到參數中執行,若不欲 array 被處理,可以在執行 exec() 之前呼叫 unset()。若是 return_var 跟 array 二個參數都存在,則執行 command 之後的狀態會填入 return_var 中。
值得注意的是若需要處理使用者輸入的資料,而又要防止使用者耍花招破解系統,則可以使用 EscapeShellCmd()。
實例代碼:
< ?php
echo exec('whoami');
?>
popen函數
說明:打開文件。
語法:int popen(string command, string mode);
返回值: 整數
詳細介紹:
本函數執行指令開檔,而該文件是用管道方式處理的文件。用本函數打開的文件只能是單向的 (只能讀或只能寫),而且一定要用 pclose() 關閉。在文件操作上可使用 fgets()、fgetss() 與 fputs()。若是開檔發生錯誤,返回 false 值。
實例代碼:
< ?
$fp = popen( "/bin/ls", "r" );
?>
通過上述函數,PHP可以執行linux系統的shell命令。
5. PHP命令執行PHP腳本,結束之前,內存會回收嗎
再詳細說下問題:
unix下,用php命令來執行php腳本,在php結束之前,內存有沒有機會被回收?新的GC演算法有沒有機會被調用?
出現這個問題,是因為線上有個離線數據導入腳本,需要把幾千萬行數據篩選入庫,發現,在執行過程中,到達一定程度,就會拋出內存使用超過最大值。
1Fatalerror:
那第一想到的就是程序是不是有什麼bug,造成內存超出,看了半天沒有發現問題,於是,突然出現了這個疑問。那要解決這個疑問,最好的辦法就去翻源碼吧。
在之前我這么說:
都知道,PHP5.3有了新的垃圾回收機制:GC,它不是重點,不談它的原理。
經過翻閱PHP源碼,發現,調用這個的時機是在main/main.c::php_request_shutdown這個函數中,
12/*7.Shutdownscanner/executor/compilerandrestoreinientries*/zend_deactivate(TSRMLS_C);
php_request_shutdown,通過名字就能看出,它是在php請求結束的時候執行的,在這里會執行gc_collect_cycles來清理內存。
其實這句話是沒錯,但它只針對於SAPI介面(之前我就錯在這個地方。),在用PHP命令執行php腳本的時候,是不會執行這個php_request_shutdown的。
那回到最初的問題,過程中到底有沒有執行GC呢?
為了更直觀有效的知道答案,我選擇了最BT,最暴力的方法,攔截gc_collect_cycles,輸出error_log到文件,只要執行了,
那肯定會輸出log來。
重新編譯PHP後,果不其然,符合官方的說法,只要buckets滿超過默認值1000,就會啟動GC來清理沒用的內存,防止內存泄露。
那問「什麼時間觸發的GC呢?」,答「buckets超過1000的時候啊」,這不屁話嘛,要的是真真正正的執行流程,so。。不斷的debug,
不斷的grep,不斷的step,不斷的C+T,終於搞清楚了。下面就來根據官方的說法詳細談談,PHP到底是怎麼觸發的。
有一點要注意,PHP的命令入口和sapi介面的入口是不同的,我就載在這個地方,以為都公用一個。
測試代碼以官方文檔為例:
1234567891011121314<?phpclassFoo{public$var='3.1415962654';}for($i=0;$i<=1000000;$i++){$a=newFoo;$a->self=$a;}echomemory_get_peak_usage()," ";?>
這樣的代碼,在PHP5.3之前,肯定會造成大量的內存泄露,不過,誰在開發時又能開發出這么變態的代碼來?除非這個人很變態。^.*
那PHP的命令入口是什麼?流程又是什麼?
主要函數流程如下:
入口main函數(sapi/cli/php_cli.c)==》php_execute_script(main/main.c)==>zend_execute_scripts(Zend/zend.c)==>execute(Zend/zend_vm_execute.h)
調用GC的地方在execute里。
簡單描述下這個過程,
main是入口,它的作用是根據我們傳遞的參數做不同的設置,最後會把我們的php腳本作為一個zend_file_handle指針傳遞給
php_execute_script函數,zend_file_handle其實就是把FILE*做了一下封裝,保存了一些其他的文件信息。
php_execute_script會做一些文件檢查工作,把php腳本加到哈希表included_files中。
php_execute_scripts會執行zend_compile_file函數來解釋我們寫的PHP代碼,最後執行execute。
應該都知道Zend把腳本解析完會生成op代碼保存到哈希表:active_op_array中,execute會逐個執行每個op,
op基本上都對應一個ZEND_ASSIGN_*_HANDLER這樣的一個宏,它就保存在active_op_array->opline->handlers中。
在進入到execute之後:
首先初始化execute_data,它保存了很多重要信息,上下文信息,然後調用ZEND_VM_SET_OPCODE宏,
把execute_data->opline的指針指向active_op_array->opline->handlers。
之後,execute會執行一個while循環,逐條執行opline:
(1){intret;#ifdefZEND_WIN32if(EG(timed_out)){zend_timeout(0);}#endifif((ret=EX(opline)->handler(execute_dataTSRMLS_CC))>0){switch(ret){case1:EG(in_execution)=original_in_execution;return;case2:op_array=EG(active_op_array);gotozend_vm_enter;case3:execute_data=EG(current_execute_data);default:break;}}}
每個handlers都會執行一個宏:ZEND_VM_NEXT_OPCODE(),它意思就是跳到下一個Opline,這樣就能逐條執行了。
最後跟蹤上面的PHP代碼會執行ZEND_ASSIGN_SPEC_CV_VAR_HANDLER這個宏,它是幹嘛的?他就是變數賦值
下面代碼執行的操作:
1234classA{}$a=newA();
這里就會執行這個宏。
在這個宏里有段代碼:
_FASTCALLZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS){zend_op*opline=EX(opline);zend_free_opfree_op2;zval*value=_get_zval_ptr_var(&opline->op2,EX(Ts),&free_op2TSRMLS_CC);zval**variable_ptr_ptr=_get_zval_ptr_ptr_cv(&opline->op1,EX(Ts),BP_VAR_WTSRMLS_CC);if(IS_CV==IS_VAR&&!variable_ptr_ptr){if(zend_assign_to_string_offset(&EX_T(opline->op1.u.var),value,IS_VARTSRMLS_CC)){if(!RETURN_VALUE_UNUSED(&opline->result)){EX_T(opline->result.u.var).var.ptr_ptr=&EX_T(opline->result.u.var).var.ptr;ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);ZVAL_STRINGL(EX_T(opline->result.u.var).var.ptr,Z_STRVAL_P(EX_T(opline->op1.u.var).str_offset.str)+EX_T(opline->op1.u.var).str_offset.offset,1,1);}}elseif(!RETURN_VALUE_UNUSED(&opline->result)){AI_SET_PTR(EX_T(opline->result.u.var).var,EG(uninitialized_zval_ptr));PZVAL_LOCK(EG(uninitialized_zval_ptr));}}else{value=zend_assign_to_variable(variable_ptr_ptr,value,0TSRMLS_CC);if(!RETURN_VALUE_UNUSED(&opline->result)){AI_SET_PTR(EX_T(opline->result.u.var).var,value);PZVAL_LOCK(value);}}/*zend_assign_to_variable()alwaystakescareofop2,neverfreeit!*/if(free_op2.var){zval_ptr_dtor(&free_op2.var);};ZEND_VM_NEXT_OPCODE();}
free_op2.var保存的是newA的對象.
free_op2.var這個是哪兒來的呢?
在整個execute期間,維持一個execute_data結構,裡面有個Ts指針
1union_temp_variable*Ts;
它用來保存一些臨時的變數信息,比如newA(),這個會保存到Ts鏈表裡,
opline->op2.u.var這個裡面保存了此臨時變數所在的位置,然後Ts+這個值是一個zval*指針,它就保存了newA產生的對象.
在代碼中
1if(free_op2.var){zval_ptr_dtor(&free_op2.var);};
zval_ptr_dtor會根據free_op2.var的值執行到Zend/zend_execute_API.c::_zval_ptr_dtor函數中,
_APIvoid_zval_ptr_dtor(zval**zval_ptrZEND_FILE_LINE_DC)/*{{{*/{zval*zv=*zval_ptr;#ifDEBUG_ZEND>=2printf("Recingrefcountfor%x(%x):%d->%d ",*zval_ptr,zval_ptr,Z_REFCOUNT_PP(zval_ptr),Z_REFCOUNT_PP(zval_ptr)-1);#endifZ_DELREF_P(zv);if(Z_REFCOUNT_P(zv)==0){TSRMLS_FETCH();if(zv!=&EG(uninitialized_zval)){GC_REMOVE_ZVAL_FROM_BUFFER(zv);zval_dtor(zv);efree_rel(zv);}}else{TSRMLS_FETCH();if(Z_REFCOUNT_P(zv)==1){Z_UNSET_ISREF_P(zv);}GC_ZVAL_CHECK_POSSIBLE_ROOT(zv);}}
GC_ZVAL_CHECK_POSSIBLE_ROOT(zv);
它就是最終GC演算法執行的地方.
gc_collect_cycles就在這個宏中執行了..
所以..
回到上面的問題,
php無論在SAPI介面或命令端,都會執行GC演算法來進行垃圾內存回收.
6. 怎麼用php命令執行php代碼
PHP執行命令的四種方法
方法一:使用exec函數執行系統外部命令
原型:function exec(string $command,array[optional] $output,int[optional]
$return_value)
<?
exec("dir",$outPut);
print_r($outPut);
?>
說明:列出和PHP執行文件同級目錄下的所有目錄及文件信息。
知識點:exec執行系統外部命令時不會輸出結果,而是返回結果的最後一行,如果你想得到結果你可以使用第二個參數,讓其輸出到指定的數組,此數組一個記錄代表輸出的一行,即如果輸出結果有20行,則這個數組就有20條記錄,所以如果你需要反復輸出調用不同系統外部命令的結果,你最好在輸出每一條系統外部命令結果時清空這個數組,以防混亂。第三個參數用來取得命令執行的狀態碼,通常執行成功都是返回0。
方法二:使用system函數執行系統外部命令
原型:function system(string $command,int[optional] $return_value)
1
2
3
<?
system("dir");
?>
知識點:system和exec的區別在於system在執行系統外部命令時,直接將結果輸出到游覽器,如果執行命令成功則返回true,否則返回false。第二個參數與exec第三個參數含義一樣。
方法三:使用函數passthru執行系統外部命令
原型:function passthru(string $command,int[optional] $return_value)
知識點:passthru與system的區別,passthru直接將結果輸出到游覽器,不返回任何值,且其可以輸出二進制,比如圖像數據。
方法四:反撇號`(和~在同一個鍵)執行系統外部命令
1
2
3
<?
echo `dir`;
?>
知識點:在使用這種方法執行系統外部命令時,你要確保shell_exec函數可用,否則是無法使用這種反撇號執行系統外部命令的。