Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get command line errors in the PHP error log file

I'm trying to run the curl command in PHP file and am trying to list its output in the error log file. All the PHP errors are listed in the file except the errors I get from exec() function. The PHP code I'm trying is:

exec("nohup curl --output " . $_SERVER['DOCUMENT_ROOT'] . "/abc.mp3 http://192.99.8.170:8098/stream/1; --max-time $time_in_seconds > /devnull&");

How could I get the error generated by this command in the error log file? I have googled for this, but I couldn't get sufficient results.

like image 865
MKB Avatar asked Nov 08 '22 08:11

MKB


1 Answers

The command

There are several issues in the command itself.

exec("nohup curl --output ".$_SERVER['DOCUMENT_ROOT'] . "/abc.mp3 http://192.99.8.170:8098/stream/1; --max-time $time_in_seconds > /devnull&");

(I have wrapped the original line for clarity.)

No need in nohup

The main purpose of the nohup command is to have a process running if you get logged off the shell because of a terminal line hang-up. (When a shell exits, it sends SIGHUP to its child processes.) With nohup you can start a command and then log off the shell.

The curl command is indeed terminated on SIGHUP. You may use nohup to put the download process running in background. But your objective is to capture the command's output, whether STDIN or STDOUT. It is also important to know when the command completes its work and how. For instance, after executing the command synchronously, it is possible to check the exit code (zero indicates a success) and to check if the file is actually downloaded to the file system:

$output_dir = empty($_SERVER['DOCUMENT_ROOT']) ?
'/tmp/default-download-dir' : $_SERVER['DOCUMENT_ROOT'];
if (!is_dir($output_dir)) {
  if (!mkdir($output_dir, 0755, true))
    die("Failed to create directory $output_dir");
}

$url = 'http://php.net/images/logo.php';
$output_file = "{$output_dir}/logo.svg"; ;
// 2>&1 redirects standard error descriptor (2)
// to the standard output descriptor (1)
$command = sprintf("curl -o %s %s 2>&1",
  escapeshellarg($output_file),
  escapeshellarg($url));
$output = [];
exec($command, $output, $exit_code);
if ($exit_code != 0) {
  die("Failed to download $url to $output_file");
}

clearstatcache(true, $output_file);
if (!file_exists($output_file)) {
  die("File $output_file not found on file system, command: $command");
}

echo "$url has been saved to $output_file:\n",
  implode(PHP_EOL, $output), PHP_EOL;

Output

http://php.net/images/logo.php has been saved to /tmp/default-download-dir/logo.svg:
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  2202  100  2202    0     0   4171    0 --:--:-- --:--:-- --:--:--  4665

Note the use of escapeshellarg function. You should escape all shell arguments, otherwise the shell will interpret its special characters.

The semicolon

Strings separated with semicolon (;) are interpreted as different commands. So your --max-time $time_in_seconds > /devnull& is interpreted as the second command. I have no idea what you have tried to achieve, but you most likely don't need it there.

Redirection to /dev/null

There is a typo in your > /devnull& expression. You likely meant redirection to the /dev/null pseudo-device: > /dev/null.

Capturing the output to different file descriptors

In the code above, we have captured the standard output. You should use the proc_open() function, if you want to capture the output to other file descriptors as well:

$output_dir = empty($_SERVER['DOCUMENT_ROOT']) ?
  '/tmp/default-download-dir' : $_SERVER['DOCUMENT_ROOT'];
if (!is_dir($output_dir)) {
  if (!mkdir($output_dir, 0755, true))
    die("Failed to create directory $output_dir");
}

$url = 'http://php.net/images/logo.php';
$output_file = "{$output_dir}/logo.svg"; ;
$command = sprintf("curl -o %s %s",
  escapeshellarg($output_file),
  escapeshellarg($url));

$descriptors = [
  1 => ['pipe', 'w'], // stdout
  2 => ['pipe', 'w'], // stderr
];

$proc = proc_open($command, $descriptors, $pipes);
if (!is_resource($proc))
  die("Failed to open process for command $command");

if ($output = stream_get_contents($pipes[1]))
  echo "Output: $output\n\n";
fclose($pipes[1]);

if ($errors = stream_get_contents($pipes[2]))
  echo "Errors: >>>>>>>>\n$errors\n<<<<<<<\n\n";
fclose($pipes[2]);

$exit_code = proc_close($proc);

if ($exit_code != 0) {
  die("Failed to download $url to $output_file");
}

clearstatcache(true, $output_file);
if (!file_exists($output_file)) {
  die("File $output_file not found on file system, command: $command");
}

echo "$url\nhas been saved to $output_file\n";

Output

Errors: >>>>>>>>
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2202  100  2202    0     0   4231      0 --:--:-- --:--:-- --:--:--  4735

<<<<<<<

http://php.net/images/logo.php
has been saved to /tmp/default-download-dir/logo.svg

(curl outputs the "verbose" output to the standard error descriptor)

The fixed command

In the view of foregoing, your command should be built as follows:

$url = 'http://192.99.8.170:8098/stream/1';
$command = sprintf("curl -o %s %s --max-time $time_in_seconds",
  escapeshellarg($output_file),
  escapeshellarg($url));
like image 155
Ruslan Osmanov Avatar answered Nov 14 '22 21:11

Ruslan Osmanov