2012-02-02 35 views
9

Tôi gặp sự cố này: Trên máy chủ web ISS, cửa sổ 7 x64 chuyên nghiệp, máy chủ zend được cài đặt. Chạy lệnh này theo php:php exec: không trả về đầu ra

exec('dir',$output, $err); 

$output is empty, $err=1. Vì vậy, exec không đảm bảo đầu ra, có vẻ như có một số lỗi. Php disable_functions trống, php không ở chế độ an toàn, là tiêu chuẩn, tôi kiểm tra tất cả tùy chọn. Nó có vẻ là một lỗi chung, thậm chí tìm kiếm trên google không cho kết quả.

Hãy viết từng giải pháp và giải pháp cuối cùng của anh ấy.

+0

có thể do có lỗi? :) kiểm tra xem mã lỗi 1 có nghĩa là gì ... – Catalin

+0

nếu tôi khởi chạy cùng lệnh trên cmd shell với php script.php nó hoạt động, khi tôi khởi chạy nó từ trình duyệt (vì vậy máy chủ web) nó không hoạt động, tôi thực sự không hiểu trong đó lỗi là – albanx

+0

@albanx: Điều đó sẽ dẫn tôi tin rằng các quyền nếu nó hoạt động khi bạn chạy nó và không phải khi IIS. –

Trả lời

13

Có một vài bài viết đến các phần liên quan của Manual PHP như this one:

tôi đã gặp khó khăn trong việc sử dụng PHP exec lệnh để thực hiện bất kỳ lô hàng tệp. Thực hiện các lệnh khác (tức là "dir") hoạt động tốt). Nhưng nếu tôi thực hiện một tập tin thực thi, tôi nhận được không có đầu ra từ lệnh exec.

Thiết lập máy chủ Tôi có máy chủ Windows Server 2003 chạy IIS6 và PHP 5.2.3. Trên máy chủ này, tôi có:

  1. Cấp quyền thực thi cho Người dùng Internet trên c: \ windows \ system32 \ cmd.exe.
  2. Cấp cho mọi người-> Kiểm soát hoàn toàn vào thư mục trong đó tệp lô được viết.
  3. Cấp cho mọi người-> Kiểm soát hoàn toàn trên toàn bộ thư mục c: \ cygwin \ bin và nội dung của nó.
  4. Cấp cho người dùng Internet quyền "đăng nhập theo lô".
  5. Chỉ định đường dẫn đầy đủ cho từng tệp đang được thực thi.
  6. Đã kiểm tra các tập lệnh này chạy từ dòng lệnh trên máy chủ và chúng hoạt động tốt.
  7. Đảm bảo rằng% systemroot% \ system32 nằm trong đường dẫn hệ thống.

Nó chỉ ra rằng ngay cả với tất cả những điều trên trên máy chủ, tôi phải chỉ định đường dẫn đầy đủ đến cmd.exe trong cuộc gọi exec.

Khi tôi sử dụng cuộc gọi: $output = exec("c:\\windows\\system32\\cmd.exe /c $batchFileToRun");

sau đó tất cả mọi thứ làm việc tốt. Trong tình huống của tôi, $batchFileToRun là đường dẫn hệ thống thực tế vào tệp lô (tức là kết quả của cuộc gọi đến đường dẫn thực()).

Còn một số ít trên cả trang hướng dẫn sử dụng execshell_exec. Có lẽ sau thông qua họ sẽ nhận được nó và làm việc cho bạn.

+0

Tôi sẽ cố gắng làm theo các bước này, nhưng nó không phải là một thực thi hàng loạt. – albanx

-1

Hãy xem Apache error_log, có thể bạn sẽ tìm thấy thông báo lỗi.

Ngoài ra, bạn có thể thử sử dụng popen thay vì exec. Nó cung cấp cho kiểm soát nhiều hơn bởi vì bạn có thể tách quá trình bắt đầu từ đầu ra đọc:

$p = popen("dir", "r"); 
if (!$p) 
    exit("Cannot run command.\n"); 
while (!feof($p)) 
    echo fgets($p); 
pclose($p); 
+0

Anh ấy đang dùng Windows với máy chủ IIS. – Treffynnon

+0

Tôi đã cố gắng để tìm IIS đăng nhập, nhưng tôi không thể hiểu được họ đang ở trên win7 – albanx

0

Vì mục đích bảo mật, máy chủ của bạn có thể bị hạn chế quyền truy cập vào lệnh "exec". Trong trường hợp này, có thể bạn nên liên hệ với công ty lưu trữ để xóa giới hạn này (nếu có).

+0

Tôi có máy chủ cục bộ và exec không có giới hạn như tôi biết – albanx

9

Lý do chính khiến bạn không nhận được đầu ra từ một lệnh như dir là do dir không tồn tại. Đó là một phần của dấu nhắc lệnh, và giải pháp cho vấn đề cụ thể này là tốt, trong trang này ở đâu đó.

Bạn có thể tìm thấy điều này bằng cách nhấn WIN + R, và gõ vào dir hoặc start cho rằng vấn đề - một thông báo lỗi xuất hiện!

Tuy nhiên, điều này có thể xảy ra, tôi thấy rằng cách đáng tin cậy nhất để thực hiện bất kỳ quá trình liên quan nào trong Windows là sử dụng Mô hình đối tượng thành phần. Bạn nói cho chúng tôi để chia sẻ kinh nghiệm của chúng tôi, phải không?

$ tôi nghe mọi người cười

lấy lại bình tĩnh của bạn chưa?

Vì vậy, đầu tiên chúng ta sẽ tạo ra các đối tượng COM:

$pCOM = new COM("WScript.Shell"); 

Sau đó, chúng tôi sẽ chỉ cần chạy những gì bao giờ cần phải được chạy.

$pShell = $pCom->Exec("C:\Random Folder\Whatever.exe"); 

Cool! Bây giờ, nó sẽ treo cho đến khi mọi thứ được hoàn thành trong nhị phân đó. Vì vậy, những gì chúng ta cần làm bây giờ là lấy đầu ra.

$sStdOut = $pShell->StdOut->ReadAll; # Standard output 
$sStdErr = $pShell->StdErr->ReadAll; # Error 

Có một số thứ khác bạn có thể làm - tìm hiểu là những gì quá trình ID, mã lỗi, vv Mặc dù this example là dành cho Visual Basic, nó dựa trên các chương trình tương tự.

4

EDIT: Sau một vài động nghiên cứu, cách duy nhất tôi thấy để thực hiện lệnh DIR là như thế:

cmd.exe /c dir c:\ 

Vì vậy, bạn có thể thử giải pháp của tôi sử dụng:

$command = 'cmd.exe /c dir c:\\'; 

Bạn có thể sử dụng chức năng proc_open quá, cho phép bạn truy cập vào stderr, trả lại mã trạng thái và stdout.

$stdout = $stderr = $status = null; 
    $descriptorspec = array(
     1 => array('pipe', 'w'), // stdout is a pipe that the child will write to 
     2 => array('pipe', 'w') // stderr is a pipe that the child will write to 
    ); 

    $process = proc_open($command, $descriptorspec, $pipes); 

    if (is_resource($process)) { 
     // $pipes now looks like this: 
     // 0 => writeable handle connected to child stdin 
     // 1 => readable handle connected to child stdout 
     // 2 => readable handle connected to child stderr 

     $stdout = stream_get_contents($pipes[1]); 
     fclose($pipes[1]); 

     $stderr = stream_get_contents($pipes[2]); 
     fclose($pipes[2]); 

     // It is important that you close any pipes before calling 
     // proc_close in order to avoid a deadlock 
     $status = proc_close($process); 
    } 

    return array($status, $stdout, $stderr); 

Phần thú vị với proc_open, so với các chức năng khác như popen hoặc exec, là nó cung cấp tùy chọn riêng cho nền tảng Windows như:

suppress_errors (windows only): suppresses errors generated by this function when it's set to TRUE 
bypass_shell (windows only): bypass cmd.exe shell when set to TRUE 
0

Bạn có thể kiểm tra permisssions của IIS tài khoản để cmd. exe

cacls C:\WINDOWS\system32\cmd.exe 

Nếu ở đầu ra là dòng như (COMPUTERNAME = tên máy tính của bạn):

C:\WINDOWS\system32\cmd.exe COMPUTERNAME\IUSR_COMPUTERNAME:N 

Điều đó có nghĩa là người dùng không có quyền thực thi cmd.

Bạn có thể thêm quyền thực thi với lệnh:

cacls C:\WINDOWS\system32\cmd.exe /E /G COMPUTERNAME\IUSR_COMPUTERNAME:R 
1

Tôi biết tôi không có quyền trả một câu trả lời như tôi phải làm điều đó nhưng tôi vẫn không hiểu tại sao nó sẽ không làm việc trên MACCHINE của tôi, nhưng tôi tìm thấy một dự phòng (sử dụng giải pháp proc_open) bằng phương pháp khác:

public static function exec_alt($cmd) 
{ 
    exec($cmd, $output); 
    if (!$output) { 
     /** 
     * FIXME: for some reason exec() returns empty output array @mine,'s machine. 
     *  Somehow proc_open() approach (below) works, but doesn't work at 
     *  test machines - same empty output with both pipes and temporary 
     *  files (not we bypass shell wrapper). So use it as a fallback. 
     */ 
     $output = array(); 
     $handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true)); 
     if (is_resource($handle)) { 
      $output = explode("\n", stream_get_contents($pipes[1])); 
      fclose($pipes[1]); 
      proc_close($handle); 
     } 
    } 
    return $output; 
} 

Hy vọng điều này sẽ giúp ai đó.

+1

Tôi nghĩ rằng khóa này là đối số 'bypass_shell'.Từ những gì tôi hiểu về nó, 'exec()' gọi 'cmd/c' trên lệnh bạn truyền nó. Và vì lý do nào đó, nó không tìm thấy tệp 'cmd.exe' ban đầu này (có lẽ vì các biến môi trường cục bộ hoặc bất kỳ thứ gì). Bằng cách bỏ qua shell ngầm được cung cấp bởi PHP, và nói rõ ràng lệnh chạy "shell" cmd' đặc biệt này trong thư mục cụ thể này ", PHP thực hiện thành công những gì bạn nói với nó. – cartbeforehorse

1

Tôi đã cùng một vấn đề và sau khi dành nhiều giờ và tách cà phê

Chỉ cần vô hiệu hóa User Account Control (UAC) trong Windows 7 con đường ngắn: P C: \ Windows \ System32 \ UserAccountControlSettings. exe và chọn "Không bao giờ thông báo"

và php exec() hoạt động tốt!

tôi sử dụng: Apache Version: 2.2.11
PHP Version: 5.2.8
Windows 7 SP1 32bit

Trân trọng! : D

+0

Tôi không nhớ ngay bây giờ, nhưng ngay cả tôi cũng đã bị vô hiệu hóa UAC vào thời điểm đó, nhưng ngay cả điều này cũng cần lưu ý. Tốt nhất +1. – albanx

0

Hãy thử điều này:

shell_exec('dir 2>&1'); 

Nó hoạt động tốt trên Windows 8.1 64bits với UAC được kích hoạt.

0

Nếu bạn đang ở trên máy tính Windows và cố gắng để chạy một thực thi như thế này:

shell_exec("C:\Programs\SomeDir\DirinDir\..\DirWithYourFile\YourFile.exe"); 

và không có đầu ra hoặc tệp của bạn không bắt đầu, thì bạn nên thử loại này:

chdir("C:\Programs\SomeDir\DirinDir\..\DirWithYourFile"); 
shell_exec("YourFile.exe"); 

Nó sẽ hoạt động.

Điều này đặc biệt có ích nếu một người sử dụng đường dẫn tương đối từ thư mục mà kịch bản hiện đang được đặt, ví dụ:

$dir = dirname(__FILE__).'\\..\\..\\..\\web\\'; 

Và đừng quên để chdir() lại có xuất xứ folder nếu bạn cần chạy các chương trình khác.

Các vấn đề liên quan