PHP exec() Not Working With ffmpeg - php

I'm attempting to run the following command in PHP (on Ubuntu):
<?php
if (exec("/home/johnboy/ffmpeg/ffmpeg -i test1.mp4 -acodec aac -ab 128kb -vcodec mpeg4 -b 1220kb -mbd 1 -s 320x180 final_video.mov"))
{ echo "Success"; }
else { echo "No good"; }
And I always get "No good" echoed back, and no file created.
Interestingly, if I run the same exact command in Shell, it works, no problems.
Also, when I run the same code above, but subsitute "whoami" instead of the ffmpeg stuff, it works. (It echoes back "Success")
Any ideas on why this wouldn't be working? Thanks.

get the stderr will give the result
try
ffmpeg -i inputfile [more_params] 2>&1

Can the apache/web user reach /home/johnboy/ffmpeg/ffmpeg? That is, perhaps /home/johnboy is 0700 instead of 0755?
Perhaps there are resource limits affecting loading of such a large program and all its libraries?
If you run the script to the php cli sapi, does it behave correctly? Even when running as the apache user?
What does strace -ff show when the apache web user runs the php script through the php cli?

Use this
$ffmpeg = "ffmpeg Installed path";
$flvfile = "source video file with root path";
$png_path " "Destination video file with root path and file type";
exec("$ffmpeg -y -i $flvfile -vframes 1 -ss 00:01:60
-an -vcodec png -f rawvideo -s 110x90 $png_path");

You are using relative paths to the file names. Are you sure you are executing the command in the right directory?

There would be some issues if you want to execute something that way.
1. Maybe you have some permission issue, the webserver have limitation to handle some execution to the system.
2. Maybe your path file is incorrect.
3. you can try to use shell_exec to perform the execution to the system.
Anyway, what I would do to make my execution would go smoothly are,
I will write 2 programs with message passing included between them, for example client server program.
The server would wait some messages from the client to execute some command (all of the command, it would be no permission issues). All you have to do in you web is to call your client application.
What I emphasize is to build some interface from web and the system. It would solve a lot of problem with permission issues.
hope this help.

The function exec() only returns the last line of output, I suspect that the last line of that command is blank. if you want the entire contents of the command you should use shell_exec().
Also keep track of where the command is executing, try: print(shell_exec("pwd"));

Enable safemode and it will work

$output = shell_exec('/home/person/www/ffmpeg 2>&1');
echo "<pre>$output</pre>";
Notice the 2>&1 part ...

Related

How i can run function exec in PHP

I can't add * to my code to find file
this code work
exec("mediaconvert -t wav -i /home/20220228/11/23401.rec -o /var/www/html/test.mp3");
if i add a the *, it don't work
exec("mediaconvert -t wav -i /home/20220228/11/*01.rec -o /var/www/html/test.mp3");
p.s. in path is only one file, when i try execute this code from shell it work. Pls help me)
Filename expansion and other bash-specific features may/will not work in other shells (e.g. standard POSIX). If your command with * is not executed in bash/compatible, it won't work as expected. You need to verify the environment/shell that your PHP installation executes commands in.
Run the following test script:
<?php
exec('echo "$SHELL"', $out);
var_dump($out);
When I run the PHP script directly on CLI, I get "/bin/bash" for the shell that's called. When I run it via browser, curiously I get "/sbin/nologin" instead. There are different environments for user apache that executes PHP via browser calls, and the "actual" user logging in via SSH. Bash shell is not available for the Apache user by default.
These results are from a Centos7 server with Apache 2.4/PHP 8.1.4 running. Your mileage may vary. Bottom line: if the command you are executing depends on bash-specific features, it must execute in a bash environment, or another shell that supports the required features.
If bash is not available, your other option is using e.g. glob to get files matching the pattern in your directory, and then loop over them while executing the command for each specific file.
Edit: As pointed out by #Sammitch (see comments), /sbin/nologin is a common "shell name" choice for non-login users, and most likely uses /bin/sh. This should still allow for filename expansion/globbing. Testing browser script call with exec('ls *.php', $out); the wildcard functions as expected.
You may find this question/answer relevant: Use php exec to launch a linux command with brace expansion.
I recommend you do the opposite. First, get the files you want to input then you exec. For instance:
$input_files = ...
exec("mediaconvert -t wav -i " . $input_files . " -o /var/www/html/test.mp3");
You can try to find files with glob() function and after that you can use exec(). You can try a similiar solution with the following code:
$input_files = '/home/20220228/11/*01.rec';
foreach (glob($input_files) as $filename) {
exec("mediaconvert -t wav -i " . $filename . " -o /var/www/html/test.mp3");
}

ffmpeg command executes via command line, but not via PHP script

I am working on a simple video upload and compression system and I am currently using the following process.
First Step
I use a multipart/form-data to upload the original video file, which I store in /var/www/site/videos_pre/video.mp4. My public folder is var/www/site/public_html/. I store an entry in my database with the video information.
Second step
I have a converter process which is very basic, but does the job (at least in CLI).
It has the following code:
public function converter($content_id)
{
$content = $this->videos_m->get($content_id);
$id = uniqid();
$name_mp4 = $content->name_slug.'_'.$id.'.mp4';
$name_webm = $content->name_slug.'_'.$id.'.webm';
$command_mp4 = 'ffmpeg -i ../videos_pre/'.$content->original_file.' -b:v 1500k -bufsize 1500k ./videos/'.$name_mp4;
system($command_mp4);
$command_webm = 'ffmpeg -i ./videos/'.$name_mp4.' -c:v vp9 -c:a libvorbis ./videos/'.$name_webm;
system($command_webm);
$update_video = new stdClass();
$update_video->archivo_mp4 = $name_mp4;
$update_video->archivo_webm = $name_webm;
$this->db->where('content_id', $content_id);
$this->db->update('Videos', $update_video);
}
Third step - where the problem occurs
I have tested this on Windows 10 and Ubuntu 18.04. The code works on Windows 10 in both php and cli. The code on Ubuntu only works with cli.
The resulting commands are something like this:
// First command to reduce the bitrate of the mp4
ffmpeg -i /var/www/site/videos_pre/video.mp4 -b:v 1500k -bufsize 1500k /var/www/site/public_html/videos/video_5e757d3e0d762.mp4
// Second command to convert the mp4 to a webm to get both types
ffmpeg -i /var/www/site/public_html/videos/video_5e757d3e0d762.mp4 -c:v vp9 -c:a libvorbis /var/www/site/public_html/videos/video_5e757d3e0d762.webm
If I execute those commands they work perfectly. If I run the php script, be it in the browser or via CLI, literally nothing happens. No error messages nothing.
I am not sure if it's a permission issue, if there's something specific for php to run this, or some module I've not activated. I have enough execution time, I have it at 600 seconds, but as I said it doesn't even take time, it just does nothing.
I can even echo the commands and they appear. So, basically the problem is I need to be able to run those commands from PHP. I did it on Windows, but Ubuntu 18.04 won't let me. Both OSs have ffmpeg recently installed and I've been able to convert on both of them.
I tried changing paths from absolute to relative, no difference at all.
So, I managed to solve it, and it turns out it was a permission problem.
I had my /var/www/site folder with permissions like this: myuser:www-data. After checking this answer on a similar issue, I changed the folder permission to www-data:root and it worked instantly.
I hope that permission change doesn't affect the rest of things, but for now everything's working fine.

FFMpeg working in command line but not in PHP script

I am using FFMpeg to convert videos and it is working fine from the command line. I am using the following command:
ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv
However, when I run the command using PHP script, the output video is not encoded.
exec("ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv",$output, $returnvalue);
$returnvalue = 127;
FFMPEG installed path :
[root#localhost ~]# which ffmpeg
/root/bin/ffmpeg
My Script Path :
www.domainname.com/core/foldername/ffmpeg.php
Please provide me solution for the same ASAP.
Thank you.
The natural way to run ffmpeg from PHP scripts is something like:
<?php
echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -i input.avi output.avi &");
echo "Done.\n";
?>
There are several issues that need to be pointed out here. The first one is that, although we specified we want ffmpeg to be executed in the background (using the ampersand operator "&"), PHP script will not continue it's execution until ffmpeg has finished its execution. This is due to the fact, mentioned in one of the notes for the ​PHP's exec() function that says:
If a program is started with this function, in order for it to
continue running in the background, the output of the program must be
redirected to a file or another output stream. Failing to do so will
cause PHP to hang until the execution of the program ends.
Don't be confused about the example showing ​shell_exec() call instead of ​exec(). All of the ​PHP's Program execution functions share the similar code base and limitations.
So, to work around this issue, we need to do something like this:
<?php
echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -i input.avi output.avi >/dev/null 2>/dev/null &");
echo "Done.\n";
?>
The part that says ">/dev/null" will redirect the standard OUTPUT (stdout) of the ffmpeg instance to /dev/null (effectively ignoring the output) and "2>/dev/null" will redirect the standard ERROR (stderr) to /dev/null (effectively ignoring any error log messages). These two can be combined into a shorter representation: ">/dev/null 2>&1". If you like, you can ​read more about I/O Redirection.
An important note should be mentioned here. The ffmpeg command-line tool uses stderr for output of error log messages and stdout is reserved for possible use of pipes (to redirect the output media stream generated from ffmpeg to some other command line tool). That being said, if you run your ffmpeg in the background, you'll most probably want to redirect the stderr to a log file, to be able to check it later.
One more thing to take care about is the standard INPUT (stdin). Command-line ffmpeg tool is designed as an interactive utility that accepts user's input (usually from keyboard) and reports the error log on the user's current screen/terminal. When we run ffmpeg in the background, we want to tell ffmpeg that no input should be accepted (nor waited for) from the stdin. We can tell this to ffmpeg, using I/O redirection again ** "ffmpeg command-line tool in the background would be similar to this:
<?php
echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -y -i input.avi output.avi </dev/null >/dev/null 2>/var/log/ffmpeg.log &");
echo "Done.\n";
?>
The ​"-y" option is used to auto-overwrite the output file (output.avi) without asking for yes/no confirmation. If you need the opposite scenario, to auto-cancel the entire process if the output file already exists, then use "-n" option instead.
Wrapper Libraries
Some PHP libraries allow wrapping ffmpeg calls into PHP objects, and give you a nice syntax to work with if you don't like to use the command line. One of these is the actively maintained ​PHP-FFMpeg. It only requires you to ​download a recent ffmpeg and ffprobe build apart from installing the PHP components. Then you can run PHP code like this:
$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open('video.mpg');
$video
->filters()
->resize(new FFMpeg\Coordinate\Dimension(320, 240))
->synchronize();
$video
->save(new FFMpeg\Format\Video\X264(), 'export-x264.mp4')
Of course you need to take care of running such a task in the background. Libraries such as ​GearmanClient facilitate this.
Note: ​ffmpeg-php is an extension that is not developed since 2007 (and requires "ffmpeg-0.4.9_pre1 or higher"), which means that you are restricted to use a very old version of ffmpeg, without possibility to update it to the latest version. Since a lot of changes/improvements are being made, inside ffmpeg's code, every day, it makes ffmpeg-php incompatible with the latest ffmpeg.
Read the official documentation for more info.
I covered the solution that helps most people that I spoke to about this in another thread.
https://stackoverflow.com/a/38626752/2074077
Essentially, your user needs access to the public directories.
<?php
exec('whoami'); // Gives you the running user; often it's www-data
?>
Then change your public ownership to the whoami user.
sudo chown -R www-data:root /var/www
This happened to me, I found this on another forum; the trick inside of PHP is to give the absolute path to FFMPEG. Try running it like this..
exec("/root/bin/ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv",$output, $returnvalue);
Something about the fact that php is a different user than you are when typing straight into the command line. I guess it doesn't have the same shortcut list or whatever it is.
Not sure exactly why but it worked for me!
Good luck.

PHP exec not executing command

I have used php's exec to execute FFmpeg command but its not woking when I open it in browser. But when i run this php file script in terminal it works fine.And my php safe mode is off. please help me to get it solved. my php code is
<?php
$output=exec("ffmpeg -f image2 -i /home/phedra/imgs/image/img%03d.png -r 12 -s 610x489 /home/phedra/imgs/video/out.avi", $out);
echo $out;
echo $output;
?>
try giving full path where the ffmpeg application is located.
e.g.
/usr/bin/ffmpeg
So your function might look like:
$output=exec("/usr/bin/ffmpeg -f image2 -i /home/phedra/imgs/image/img%03d.png -r 12 -s 610x489 /home/phedra/imgs/video/out.avi", $out);
You must check what is the location of "ffmpeg".
I had this problem and it turned out it was Apache's permission on the public directory.
Note: I am running Ubuntu 14 on AWS
After installing FFmpeg I had to change the /var/www/* ownership to www-data.
sudo chown -R www-data:root /var/www
(the www-data is the important part here)
Then I had the following code running, and it works when I access it via URL (Apache)
// test.php
$run = system("/opt/ffmpeg/bin/ffmpeg -i /var/www/html/input.mp4 -vf scale=640:480 /var/www/html/output.mp4 &");
if($run) {
echo "success";
} else {
echo "failed";
}
The /opt/ffmpeg/bin/ffmpeg is where my FFmpeg is running from. Yours might be /usr/bin/ffmpeg or something else. You can locate it by typing locate ffmpeg in the command line and looking through the list it gives you.
The input file was a public .mp4 file and the output.mp4 file was going to the same location.
Run this in your command line: php test.php - works
Run this from your browser: yourwebsite.com/test.php - works
Note that if you are on windows you must use COMMAS. I.E:
$output=exec('"/usr/bin/ffmpeg" -f image2 -i /home/phedra/imgs/image/img%03d.png -r 12 -s 610x489 /home/phedra/imgs/video/out.avi', $out);
Like #Arfeen mentioned in his answer, you should execute the command with the path of ffmpeg, but, the given path in the answer "/usr/bin/ffmpeg" is not always the same.
First locate your ffmpeg by using the command :
which ffmpeg
The result in my case is :
/usr/local/bin/ffmpeg
Then go back to your php code and replace "ffmpeg" in the command by the path of ffmpeg (which is /usr/local/bin/ffmpeg in my case).

FFMPEG command doesn't work in PHP. (Incompatibilty with MAMP)

I'm a bit of a beginner when it comes to PHP, and I'm trying to create a simple(ish) system where files are input, and then converted to html5 video in various resolutions.
I've sorted out how to handle multiple file uploads etc, but now I'm having a problem.
I can't seem to get exec to execute FFMPEG in PHP.
For example, if I type this into my command line (Terminal on Mac OSX 10.8), It converts the video correctly:
ffmpeg -i /Users/charlieryan/Desktop/MOV01785.MPG websample.mov
This correctly outputs the converted video file into my home directory.
However if I run this in PHP as follows:
exec('ffmpeg -i /Users/charlieryan/Desktop/MOV01785.MPG websample.mov');
Absolutely nothing happens ... my stat monitor doesn't register any change in processor use, and I can't find the output file anywhere on my system.
Since I'm a bit of a noob at this, I'm assuming I'm doing something wrong, but what is it?
Thanks,
Charlie
After alot of help from birgire and a lot of fiddling around I've sorted it.
This problem comes from an incompatibility with the MAMP sandbox. Which can be solved as follows:
Go to Terminal and type:
sudo nano /Applications/MAMP/Library/bin/envvars
Then comment out the following lines with a hash (#)
# DYLD_LIBRARY_PATH="/Applications/MAMP/Library/lib:$DYLD_LIBRARY_PATH"
# export DYLD_LIBRARY_PATH
And then add the following line to the file
export PATH="$PATH:/opt/local/bin"
Then, go back to MAMP and restart your servers, navigate back to the page, and you'll be good to go.
You should first try to see if exec() is allowed:
<?php echo exec('echo "exec() is working"');?>
if it's working you should get
exec() is working
If it works you should try
exec('/full/path/to/ffmpeg -i /Users/charlieryan/Desktop/MOV01785.MPG websample.mov');
I had the same problem, If you use MAMP, the problem is because mamp's php can't find the correct library, I don't know why!, so.. here's the trick.
- You should use system's php to execute the php which will call to ffmpeg
In your php code (ex: lib.php | index.php):
function callToSysPHP ($videoName) {
// $cmd = '/path to php/php <your php script> args';
// In my case
$cmd = '/usr/bin/php myffmpeg.php ' . $videoName;
shell_exec($cmd);
}
In myffmpeg.php:
$videoName = $argv[1];
//$cmd = 'path to your ffmpeg/your ffmpeg command';
// In my case my ffmpeg cmd looks like
$cmd = '/usr/sbin/' . 'ffmpeg -f image2 -framerate 25 -i ./files/pngs/%1d.png -vf scale=480:640 -vcodec libx264 -refs 16 -preset ultrafast ./files/pngs/'. $videoName .'.mp4 2>&1';
echo '<pre>'; print_r(shell_exec($cmd)); echo '</pre>';
Basically from your mamp php, call a system php to execute a php file wich calls a ffmpeg throught shell_exec();
I hope this can help you.
have you ffmpeg installed on windows machine? what happens if you run the same command from command line without php, does it work? If it doesn't, it hasn't to do anything with PHP.
If '/usr/local/bin/' is the directory where you can find the ffmepg executable try this one:
<?php
$cmd = 'PATH="/usr/local/bin/"; ffmpeg -i /your/file/destination/batman.mp4 2>&1';
echo "<pre>".shell_exec($cmd)."</pre>";
?>

Categories