如果您將 php chroot 到沒有 /bin/sh 的環境中,您將無法執行任何命令!即使您呼叫
mail() 並它呼叫 sendmail ... 事實上 sendmail 永遠不會被呼叫,因為 /bin/sh 不在 chroot 中!
因此結論:您必須有 /bin/sh 才能執行任何操作!!!
非常重要!
我花了好幾天時間才找到這個,希望對其他人有幫助!!!
在背景執行程式之前,應先關閉已鎖定的開啟檔案(特別是開啟的工作階段)。
這些函式也與反引號運算子密切相關。
如果您將 php chroot 到沒有 /bin/sh 的環境中,您將無法執行任何命令!即使您呼叫
mail() 並它呼叫 sendmail ... 事實上 sendmail 永遠不會被呼叫,因為 /bin/sh 不在 chroot 中!
因此結論:您必須有 /bin/sh 才能執行任何操作!!!
非常重要!
我花了好幾天時間才找到這個,希望對其他人有幫助!!!
為了更清楚說明最後幾篇文章的內容
"exec"、「反引號」、「system」等等在 Windows 2003 上預設會失敗。
您必須修改 cmd.exe 的安全性,才能為使用者帳戶 IUSR-電腦名稱提供必要的權限,至少是讀取和執行。
給 WINDOWS 使用者
我看了一下 start 命令。事實上它真的很有用。
這是我啟動特定 Apache SSL 伺服器的方式
<?php
$cmd = "start /D C:\OpenSA\Apache /B Apache.exe -D SSL";
exec($cmd,$output,$rv);
?>
/D 指定將啟動應用程式的路徑(相當於 cd 到該路徑)
/B 啟動應用程式,而沒有主控台視窗
所以要知道 start 的確切參數,您可以使用
<?php
exec("start /? > start.txt");
?>
您會在執行指令碼的同一個位置,取得一個名為 'start.txt' 的檔案,其中包含 start 的說明
對於 WIN 98,您可能需要稍微修改一下您的命令
exec("COMMAND.COM /C START program args >NUL");
(取自另一篇文章)
最後!堅持不懈終於有了回報,嘗試每一件小事好幾天了!
我不想使用批次檔。我正嘗試使用 PHP 來擺脫批次檔。
我不想呼叫一個檔案來解析參數,然後再呼叫一個 shell 來呼叫一個檔案。我現在的「系統」的批次檔有三層和五層之深。
我只是想執行一些東西。
CALL,已在 WinXP 上測試,將立即在更多作業系統上測試,在 PHP4 和 5 中,透過 exec、system,與 popen 和 passthru 搭配使用。
這是我拙劣的範例函式。
// CreateZip
function createzip ($target, $archive)
{ $ziputil = "call \"c:\\Program Files\\7-zip\\7z.exe\"";
$archived = escapeshellarg($archive);
$targeted = escapeshellarg($target);
$shellcommand= $ziputil." a -tzip ".$archived." ".$targeted."\n";
// 以下所有在 Win XP Pro 中都運作正常
passthru ($shellcommand);
exec ($shellcommand);
system ($shellcommand);
shell_exec ($shellcommand);
$proc= popen ($shellcommand, "r"); //$proc 包含輸出
WINDOWS 上名稱中含有空格的長路徑!
全部都在一個長長的串連命令列中,包含多個以引號括住的檔案名稱參數
shell 指令碼的喜悅!
關於 XP 使用者的注意事項:XP-Home 版本不允許直接設定檔案和資料夾的權限。您應該使用 cacls 命令列公用程式來執行此操作。
例如
cacls c:\windows\system32\cmd.exe /E /G IUSR_ADMIN2003:F
讓 IIS 使用者可以完全存取 cmd.exe(潛在的安全漏洞!),因此 PHP 可以建立分支並執行外部程式。
Win32 / PHP 4.3.6...
如果您打算在伺服器上啟動顯示訊息方塊的程式(需要伺服器端 OK 的程式),或是保持運作的程式(例如 notepad.exe),而且 exec 命令似乎進入了死循環,那麼您的程式可能已經啟動,但是您看不到它。因為 Web 伺服器是以系統處理程序執行,而且不允許與桌面互動。
要解決一部分問題(查看您執行的程式),請在 Windows 的控制台中,前往「管理工具」->「服務」,右鍵按一下伺服器服務,前往「屬性」,然後在第二個索引標籤(登入?)中勾選允許服務與桌面互動的方塊。按一下「確定」。重新啟動 Web 伺服器,並確定它是真的重新啟動(即查看工作管理員,確認服務已_關閉_),否則桌面選項將不會生效。
下一個階段是停止讓 PHP 等待處理程序完成(這會讓 PHP「迴圈」)。我透過建立一個小的 Delphi 應用程式來解決這個問題,這個應用程式會接收要執行的檔案路徑,並透過 WinExec API 執行它,這個 API 只會啟動子程式,而不會等待它完成 = 程式會完成,而 PHP.exe 會完成指令碼。問題解決了!
Delphi 程式碼片段
WinExec(PChar(<CMD>),SW_SHOW); // 將 <CMD> 取代為程式路徑。
我在這個頁面上發現了這個註解
[引文開始]
嘗試使用以下程式碼時,結果很糟,出現各種結果:例如「無法建立分支」、「存取遭拒」、「結果空白」,具體取決於我使用的設定,... 即使相同的程式碼可以從伺服器本身的命令列運作。
$retstr = exec('nslookup -type=mx myhost.com', $retarr);
我相信,除了 nslookup 之外,這也適用於 \system32\ 目錄中的大多數程式。
我必須學習到,以下方法最終才奏效
$retstr = exec('c:\php\safedir\nslookup -type=mx myhost.com', $retarr);
... 但僅在下列所列的先決條件下才能運作
1: nslookup.exe 必須放置 (複製) 在 \php\safedir\ 目錄中
2: \php\safedir\ 目錄必須包含在系統 PATH 環境變數中
3: cmd.exe 檔案必須放置在 \php\ 中,如上述其他注意事項所列
4: "c:\php\safedir\" 目錄必須在 php.ini 設定中設定
safe_mode_exec_dir = "c:\php\safedir\"
.. 也可能需要在 php-activescript.ini 中設定,具體取決於您的系統設定。
5: 必須使用完整路徑來參照 nslookup,否則會呼叫 \windows\system32\ 中的檔案。我遇到過因為權限不足而導致結果為空的情況!
希望這能幫助其他人節省一些時間和頭痛。
[引述結束]
這實在太複雜了。只需要兩件事
1. 針對 C:\Windows\System32 目錄中的 cmd.exe,為 IUSR 帳戶設定讀取和執行的特定權限
2. 針對所需的命令 (例如:C:\Widnows\System23 目錄中的 nslookup.exe),為 IUSR 帳戶設定讀取和執行的特定權限
只要滿足這兩個條件,exec 就能正常運作
(這適用於在 Windows 平台上執行的 IIS 伺服器)
嗨
我在執行 exec()、shell_exec() 時遇到問題 (PHP 不是在安全模式下執行)。
經過一番研究,我發現問題出在我的系統中啟用了 SELinux。
您可以透過查看 /var/log/messages 記錄來確認這一點
所以我停用了 SELinux,現在一切都正常了。
暫時停用 SELinux #> setenforce 0;
由於我覺得這不是個好主意,我仍然瀏覽了一些網站,找到了一個我認為不錯的解決方案。
Fedora 的 SELinux 政策有一些布林值 - 讓我們看看它對我們的 Apache 有什麼設定
# /usr/sbin/getsebool -a | grep httpd
allow_httpd_anon_write -- off
allow_httpd_mod_auth_pam -- off
allow_httpd_sys_script_anon_write -- off
httpd_builtin_scripting -- on
httpd_can_network_connect -- off
httpd_can_network_connect_db -- off
httpd_can_network_relay -- off
httpd_disable_trans -- off
httpd_enable_cgi -- on
httpd_enable_ftp_server -- off
httpd_enable_homedirs -- on
httpd_rotatelogs_disable_trans -- off
httpd_ssi_exec --off
httpd_suexec_disable_trans -- off
httpd_tty_comm -- off
httpd_unified -- on
從以上資訊可以確定 exec() 無法運作是因為此 httpd_ssi_exec -- off 設定
所以我將其開啟。
#> setsebool -P httpd_ssi_exec 1;
現在我可以看到 shell_exec('ls -al') 的輸出了
摩西
給蘭斯洛特
很簡單,在 Windows 上,exec($my_cmd) 會執行 'cmd /c $my_cmd'
如果 $my_cmd 中有任何空格,您必須將其放在雙引號中
cmd /c "$app $target" 將會運作
此外,如果 $app 和 $target 中有任何空格,它們也必須放在雙引號中
cmd /c ""$app" "$target""
因此,請將您的 $cmd 包含在另外兩個雙引號中,並且不要忘記跳脫反斜線 \\
$cmd = "\"\"C:\\my path with spaces\\targetapp.exe\" \"C:\\mypathnospaces\\targetfile.xxx\"\"";
然後 exec($cmd) 就會運作了 :)
不再需要 chdir 了...
我使用以下程式碼來 fork 處理程序
<?php
fclose(STDOUT); //關閉所有輸出,否則將無法運作
fclose(STDIN);
fclose(STDERR);
if(pcntl_fork()) {
exit; //返回呼叫者
}
//在背景執行的程式碼
pcntl_exec("/usr/bin/php",Array($_SERVER['argv'][1]));
?>
我從我的網站使用以下方式呼叫此腳本
<?php
function fork($script){ //執行相對於文件根目錄的 forked php 腳本。不會顯示任何輸出!
global $config;
$cmd = "/usr/bin/php \"" . dirname($_SERVER['SCRIPT_FILENAME']) . "/includes/forked/forkHelper.php\" \"" . $script . "\"";
exec($cmd);
}
?>
如果您嘗試使用 exec 來執行 cgi 並透過 php 檔案輸出內容,則標頭需要與內容分開,並分別輸出。
此外,至少在我嘗試執行的 cgi 中,缺少換行符,導致一些 javascript 無法正常運作,因此您可能必須將換行符加回結果輸出中。以下是我用來正確輸出我的 cgi 的程式碼...
<?PHP
putenv('REQUEST_METHOD=GET');
// 取得傳遞至 cgi 的參數..
putenv('QUERY_STRING=' . $_SERVER['QUERY_STRING']);
//當您遇到空行 ('') 時,您就會知道您已通過標頭
$inheader=true;
foreach($output as $val){
if($val=='')
$inheader=false;
if($inheader)
header($val);
else
echo($val . "\n"); // 輸出內容
}
?>
使用 schtasks.exe 排程 WinXP 工作,並使用 PHP 執行命令,有時可能會失敗。
這是因為在放置排程時,Apache 沒有權限存取某些系統檔案。我的做法是:建立一個普通的使用者帳戶,並將 Apache 服務指派為以該帳戶登入。
在「執行」視窗中開啟 'services.msc',在清單中尋找 Apache,按一下滑鼠右鍵並進入「內容」。按一下第二個索引標籤「登入」,並填寫「這個帳戶」欄位。
當然,Apache 必須在第一次設定時安裝為服務。
希望這對大家有幫助。
Fendy Ahmad
在我看來,最好的方法是將 cmd.exe 複製到您網頁目錄下的某個安全目錄中,將其新增至 Windows 路徑,然後從該處呼叫它來使用系統命令。看起來這樣做可以避開任何安全性漏洞
只是一個簡單的注意事項,可以幫助人們擺脫一些麻煩。
當使用
<?
$filepath = "檔案的路徑";
exec("program -command $filepath ");
fopen($filepath,rw);
?>
請務必對 Linux\unix 路徑使用 "\ " (反斜線 空格),而對 fopen 僅使用 " " 空格。這些都是您通常不會認為會導致問題的基本事情,但是當您嘗試將斜線傳遞給 fopen 時,它不是會中斷,就是會更好,會不正確地運作 =D。反之亦然,任何在檔案路徑/名稱中使用 "\ " 作為空格的程式都是如此。
當我使用 <? exec(" cp $path "); ?> 和 <? fopen("$path"); ?> 時,我遇到了這個問題。為了解決這個問題,我使用了 str_replace(" ","\ ",$path); 和 str_replace("\ ", " ",$path);
*請注意,這有很多虛擬碼,而且有更快、更有效的方法可以執行相同的操作,但我認為這可能對那些因檔案路徑而感到瘋狂的人有幫助 =D。
這些函數通常被認為是有害的,在沒有適當的輸入驗證程序的情況下,它們與 eval() 一樣糟糕。
如果您嘗試執行的操作可以使用其他機制來完成,** 即使需要更多時間,也請這樣做 **。
如果您的伺服器由於程式碼中缺少 escapeshell*** 而被「入侵」,請不要哭泣或責怪 PHP,您已經被警告過了。
關於「無法 fork」錯誤的更多資訊。
這快要把我逼瘋了!我確實檢查過是否已為 IUSR_[server] 帳戶設定讀取和執行 cmd.exe 的權限。但它仍然失敗。直到我絕望地去查看「特殊權限」時才發現。(按一下常規權限清單下方的進階索引標籤)。我在那裡發現,不知何故,IUSR_[server] 帳戶具有拒絕存取的特殊權限!當然,拒絕會覆蓋所有其他內容。
這是一個新設定的 XP pro 安裝。它一定是某個東西 (我猜是 IIS) 的預設設定,只是為了讓我們的生活更痛苦而設定了此拒絕權限。
我在 FreeBSD 伺服器上使用 PHP 4.4.0 的 `exec()` 和 `system()` 指令,遇到將 shell 腳本作為背景程序執行的問題。
我嘗試了以上所有方法,但都未能成功。後來我編寫了這個腳本,並確信它能在所有 Linux 版本上運作… 希望對大家有幫助…
我將我的 Shell 腳本放在 `$ExecCommand` 變數中。
然後使用 `proc_close` 和 `proc_open` 函式,程式碼如下:
`proc_close (proc_open ($ExecCommand,array(),$somefun));`
在以上程式碼執行後,其餘的 PHP 腳本會繼續執行....
希望對大家有幫助..
當我想要從 PHP 啟動一個無限期執行的 PERL 腳本時,也遇到過這個問題。不知何故,我無法讓 PHP 腳本在執行 PERL 腳本後返回。所以最後我找到了以下解決方案:
PHP 檔案
-------------------
<?php
exec("perl /home/chatserver.pl > /dev/null");
?>
-------------------
這個腳本將通過 HTTP 執行。
PERL 檔案
-------------------
#!/usr/bin/perl
fork and exit 1;
# 正常的程式碼在這裡...
-------------------
希望能幫助到有需要的人 :)
Margus
澄清一下,背景 shell 的 `exec()` 執行與 Unix 下的 `fork()` 不同。如果 PHP 像 Perl 和其他腳本語言一樣支持 `fork()` 會很有用。簡單地使用 `exec()` 執行一個程序並將其發送到後台是不同的。
一個真正的 `fork()` 會複製當前環境並複製正在運行的腳本,以便有兩個實例,一個子進程,一個父進程。子進程和父進程可以確定它們是哪個副本,然後基於此採取單獨的執行路徑。通常,一個副本將執行一些「忙碌的工作」,而另一個副本則返回正常執行。但是無論如何,兩個函數都存在於相同的程式碼中,而不是一個單獨的外部程式。`exec()` 無法為您執行此操作。
這個快速圖表對我非常有幫助(每個指令的最佳 (+) / 最差 (o))以及何時使用每個指令 (w)。
| exec(string cmd, [array cmd_output, [int cmd_exit_status]])
+- 第二個(可選)參數保存一個陣列,其中包含逐行的輸出。
+- 第三個(可選)參數保存執行程序的退出狀態。
w- 當命令的輸出僅對程式重要時。
| system(string cmd, [int cmd_exit_status])
+- 將 ascii 輸出直接回顯到瀏覽器(只有 stdout;stderr 必須通過在命令後加上 `2>&1` 來重定向以查看錯誤)。
+- 第二個(可選)參數保存執行程序的退出狀態。
w- 當命令的輸出對用戶很重要時。
我越回顧我的筆記,就越不關心最後兩個函數。
`shell_exec()` = `exec()` + `implode()` - 退出碼。
雖然能夠通過 php 管道傳輸二進制是必要的,但大多數人永遠不會使用 `passthru`。
| passthru(string cmd, [int cmd_exit_status])
+- 將二進制輸出直接回顯到瀏覽器視窗。
+- 第二個(可選)參數保存執行程序的退出狀態。
w- 當命令的輸出是二進制時。
| `shell_exec(string cmd)` <-- 維護與正常使用反引號同步的最小功能。
+- 返回完整的輸出作為一個字符串,而不是直接到瀏覽器(只有 stdout;stderr 必須重定向)。
o- 無法檢查退出狀態(應該使用將 stderr 和 stdout 都重定向到 `/dev/null` 的 `system()` 來獲取退出碼)。
我嘗試在 WinNT、Apache 2、PHP4 上 fork 一個 GUI 進程。
我在工作管理員的進程列表中看到了新進程 (notepad.exe),但是沒有記事本視窗出現!
在服務 -> Apache 中啟用「允許與桌面互動」複選框後,使用簡單的命令,一切都正常運作了。
`exec("start c:\\winnt\\notepad.exe");`
昨晚我花了約一個半小時的時間,試圖讓 Perl 在執行 `exec()` 命令後將值傳回我的 PHP 腳本。
由於我的 Perl 腳本正在使用 STDOUT(在傳遞命令行變數後),我期望在我的 .pl 腳本中使用的變數可以在 PHP 中存取,沒有任何問題。
當然,這沒有奏效,最後在朋友(Shawn = 超級巨星)的幫助下,我終於弄清楚了:您需要回顯 `exec()` 命令才能將值返回到 PHP。
由於我正在返回多個值,我在我的 .pl 腳本中添加了管道分隔符,然後使用 PHP 解析該字符串以將我的數據檢索到不同的變數中。
看看這個:
# 用數據點擊 .pl 腳本
`$mydata = exec("script.pl 'command line args' ");`
`exec("exit(0)");`
# 解析從 .pl 腳本返回的值
`list($strA, $strB) = split ('[|]', $mydata);`
`echo "valueA: " . $strA."<br>";`
`echo "valueB: " . $strB."<br>";`
萬歲!
/d
關於 Windows 中無法 fork 的訊息的更多資訊
我想確認這個問題與 `%SYSTEMROOT%\SYSTEM32` 上的權限有關。使用者(通常是匿名登入)必須對 cmd.exe 具有執行權限。
這與大多數其他程式設計語言不同。例如,在 C 中,`spawn` 和 `exec` 函數不會嘗試打開 shell,它們會直接建立新進程。PHP 會通過 cmd.exe(或 command.com)建立新進程,就像 C 的 `system()` 函數一樣。這對那些試圖執行批次檔的人有好處,但是對於執行其他 .exe 檔案來說效率非常低。
我對於提升 system32 目錄中的權限感到不安,但是您可以通過將 cmd.exe 複製到您的 PHP 目錄來解決此問題。Windows 會先在那裡查找,如果不存在,它將檢查路徑。注意:我指的是 php.exe 所在的目錄,而不是您的腳本目錄。
我通過在嘗試執行腳本時運行 filemon.exe 確認了這一點,您可以看到它正在嘗試啟動 cmd.exe 進程。
為什麼不使用每個 Windows 版本都提供的「start」工具在 Windows 機器上啟動背景程序?例如:
`exec("start song.mp3");`
這將導致 .MP3 檔案類型的預設處理應用程式開始播放所選歌曲..
AFICT,標準的 Unix Apache 配置在後台運行作業時會導致一個罕見的問題。`MaxRequestsPerChild` 指令導致子進程在 1000 個請求後終止,除非它們以「nohup」命令啟動,否則與子進程關聯的任何後台進程都將隨子進程一起死亡。因此,在後台啟動作業的正確方法是使用:
`exec('nohup my-command > /dev/null 2>&1 &')`
對於 Windows 用戶
請記住,許多無法 FORK 的錯誤是權限不足的結果。
CMD.EXE、TEMP 目錄(或您在 php.ini 中指定的任何目錄)以及您用於上傳或處理檔案的所有目錄是否需要具有寫入權限?通常是使用者 USER。
這對於所有使用 GD 庫或其他處理圖像的程式的人來說都會很有用。
要從 php 在後台執行腳本,您不需要使用 mikehup 或其他工具。只需執行:
`/usr/bin/php -q foobar.php >/dev/null 2>&1 &`;
mat
回覆:session_write_close()
要在會話中啟動後台進程,我建議
使用 start-stop-daemon 並通過 ENV 傳遞參數。
範例
----------------------------------------
<?php
// 在會話中..
exec("/some/where/launch.sh 300");
// ..立即結束。
?>
----------------------------------------
#!/bin/bash
# /some/where/launch.sh
T=$1
export T
DAEMON=/some/where/runme.pl
start-stop-daemon --start --quiet --background --exec $DAEMON
----------------------------------------
#!/usr/bin/perl
# /some/where/runme.pl
my $t = $ENV{'T'};
sleep($t);
----------------------------------------
讓我們更清楚地了解 `exec()` 中的「無法 fork」錯誤。
預設情況下,Windows XP 會將 cmd.exe 的所有權限設定為臨時網際網路使用者帳戶 (IUSER-[電腦名稱]) 為「拒絕」。這將覆蓋所有內容。
您必須修改 cmd.exe 的安全性,以給予 IUSER-電腦名稱帳戶至少讀取和執行權限,並刪除「拒絕」。
嘗試使用 `exec` 在 Win2K3(據說 Win2K 也會發生這種情況)上從 IIS 上運行的 PHP 腳本運行 helper 可執行檔,但無法調用該可執行檔。
在 Win2K 上使用 Apache 來提供調用相同 helper 可執行檔的頁面時,運行相同的 PHP 腳本則可以正常工作。
解決方案:在 Win2K3(可能還有 Win2K)上,給予 IIS IUSR_xxxxx 來賓使用者對 Windows 根目錄下 System32 資料夾中的 Cmd.exe 的讀取和執行權限。
這個問題讓我困惑了很久!希望這能讓其他人免於相同的命運!
對於無法執行可執行檔的 WIN2K Server 使用者,他們正在運行 Apache 1.3.22...
`exec('c:\\WINNT\\system32\\cmd.exe /c START c:\\file.exe');`
這是對我有效的唯一方法。
希望對大家有幫助
我需要知道當一群透過呼叫 system 啟動的背景任務終止時的狀況。
我找不到可以呼叫的函式,所以我建立了一個小函式。
它基本上是循環檢查 `ps` 命令返回的結果中是否存在某個字串。
我所有在背景執行的命令都會包含 `posix_getpid` 返回的 PID。
我能夠啟動許多背景任務,並有效地等待它們全部完成。
在這之前,我基本上會讓程式休眠 N 秒。
如果存在更廣為人知或更好的方法,我深感抱歉。
感謝,
新手
===============
===============
function wait_until_termination ($id, $duration){
$i = 0;
do {
$i += 1;
$cnt = `ps -auxww |
grep $id |
grep -v grep |
awk '{print $2}' |
grep -v $id|
wc -l` ;
if ($cnt > 0) {
sleep ($duration);
}
} while ($cnt != 0);
echo ("wait_until_termination (PID: $id, SEC: $duration) : 迴圈次數
:$i<BR>");
}