ffmpeg php exec not working - php

I have ffmpeg installed
safe_mode is off
when i do this: $movie = new ffmpeg_movie('Bear.wmv');
I can use getDuration(), getFilename().... wthout any problems, so it's all seems to be working
exec is working fine, cos when i do: $output = exec('ls -lart'); I get a nice little result.
but when I do this:
exec('ffmpeg -i Bear.wmv outputfile.flv')
nothing happens
if I add: $command_output, $result
the only result i guess is: array { }
I have tried everything I could think of:
exec('ffmpeg -i Bear.wmv outputfile.flv')
exec('ffmpeg.so -i Bear.wmv outputfile.flv')
exec('/usr/lib/php5/20090626/ffmpeg -i Bear.wmv outputfile.flv')
I've tried all sizes and folders and codecs but still don't get anything back
All i wanna do is convert that video, Bear.wmv to an flv file.
I'm very close to crying like a baby and/or jumping out of the window (im only on the first floor but still lol)
so Please help!!??!

FFMPEG is a application wich don't output to STDIO but STDERR, so you can redirect it to standard output:
$cmd = $FFMPEGDIR . " -i somefile.avi 2>&1"; // SEE 2>&1 !!
Extracting size:
exec( $cmd , $info );
echo "<pre>".print_r($info,true)."</pre>";
$resolution = preg_match( '#[ ,\t]([0-9]{3,4}x[0-9]{3,4})[ ,\t]#si' , implode( " " , $info ) , $durmatches );
$rtab = explode( "x" , $durmatches[1] );
$videowidth = $rtab[0];
$videoheight = $rtab[1];

Recently set ffmpeg up for audio stuff... it's a bit of a black art, ffmpeg is notorious for not playing nice (or consistently) - what works (worked) for me might not work for you!
try using: shell_exec()
or:
$command="{$FFMPEG_BINARY} ... rest of your options";
$process=proc_open($command, $descriptors, $pipes);
if (!$process)
{
// failed to exec...
}
else
{
// command ran...
}
my ffmpeg was in... "/usr/bin/ffmpeg" just check you've got right path too.

Related

Best way to open a PTY with PHP

Problem description
I would like to open a Linux pseudoterminal with PHP but it seems there is no simple way of doing that. I have experimented with different solutions but none seem to be good enough.
The goal of the PTY is to emulate a terminal with the capability of flawlessly interacting with programs such as zsh and sudo. Other programming languages including Python and C have functions or libraries for that. Python has the PTY library which can simply do pty.spawn("/bin/zsh"), and C has the openpty() function.
My ideal end goal is to have a PHP function that allows me to read and write from/into the PTY terminal and does not require installing external libraries. (A lot of shared hosting providers do not allow that.)
What I have tried so far
Using proc_open()
My initial idea was just to use the proc_open() PHP function to create a Bash terminal with stdin, stdout and stderr pipes (Based on Example #1 in the PHP documentation) This, however, did soon prove to be problematic because it is actually not a real PTY. Running stty -a errored with stty: stdin isn't a terminal. Here are the instructions for reproducing this.
Run this with php pty_test.php
Read the output of the shell with cat /tmp/stdout.
Input commands with > /tmp/stdin.
Here is the PHP code which I used for this:
<?php
/* pty_test.php */
ini_set('display_errors', 1);
ini_set('display_startup_ūūerrors', 1);
error_reporting(E_ALL);
define("STD_IN", 0);
define("STD_OUT", 1);
define("STD_ERR", 2);
set_time_limit(0);
umask(0);
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = "/bin/sh -i ";
$stdin_fifo = "/tmp/stdin";
$stdout_fifo = "/tmp/stdout";
posix_mkfifo($stdin_fifo, 0644);
posix_mkfifo($stdout_fifo, 0644);
$resource_stdin = fopen($stdin_fifo, "rb+");
$resource_stdout = fopen($stdout_fifo, "wb+");
$descriptorspec = array(
STD_IN => array("pipe", "rb"),
STD_OUT => array("pipe", "wb"),
STD_ERR => array("pipe", "wb")
);
$process = proc_open($shell, $descriptorspec, $pipes, null, $env = null);
stream_set_blocking($pipes[STD_IN], 0);
stream_set_blocking($pipes[STD_OUT], 0);
stream_set_blocking($pipes[STD_ERR], 0);
stream_set_blocking($resource_stdin, 0);
stream_set_blocking($resource_stdout, 0);
while (1) {
$read_a = array($resource_stdin, $pipes[STD_OUT], $pipes[STD_ERR]);
$num_changed_streams = stream_select($read_a, $write_a, $error_a, null);
if (in_array($resource_stdin, $read_a)) {
$input = fread($resource_stdin, $chunk_size);
fwrite($pipes[STD_IN], $input);
}
if (in_array($pipes[STD_OUT], $read_a)) {
$input = fread($pipes[STD_OUT], $chunk_size);
fwrite($resource_stdout, $input);
}
if (in_array($pipes[STD_ERR], $read_a)) {
$input = fread($pipes[STD_ERR], $chunk_size);
fwrite($resource_stdout, $input);
}
}
fclose($resource_stdin);
fclose($resource_stdout);
fclose($pipes[STD_IN]);
fclose($pipes[STD_OUT]);
fclose($pipes[STD_ERR]);
proc_close($process);
unlink($stdin_fifo);
unlink($stdout_fifo);
?>
Python PTY
I noticed that running python3 -c "import pty;pty.spawn('/bin/bash');" in the non-pty shell (which I described above) will result in a fully interactive PTY shell as I desired. This resulted in a half-good solution: setting the $shell variable to be python3 -c "import pty;pty.spawn('/bin/bash')" will spawn the interactive shell using Python3. But relying on external software is not ideal since having Python3 is not always guaranteed. (And this solution also feels way too hacky...)
/dev/ptmx
I was reading the source code of the proc_open() function also found the source for openpty(). Unfortunately, PHP can't directly call this function but perhaps it is possible to replicate the behavior of it.
I could fopen("/dev/ptmx","r+") to create a new slave but openpty() also uses grantpt() and unlockpt(), which are not available in PHP.
Foreign Function Interface
FFI allows access to external libraries. Maybe it would be possible to import pty.h and to run openpty(). Unfortunately, FFI is very experimental and may not always be available.
TL;DR
What is the safest and most reliable way to spawn a PTY using PHP?
You do not have to use FFI to write PHP shared library.
I just tried to write an open source PHP library for this purpose. I named it TeaOpenPTY. I think this can be a good example how to write a simple PHP library in C.
GitHub repo: https://github.com/ammarfaizi2/TeaOpenPTY
Precompiled Shared Lib: https://github.com/ammarfaizi2/TeaOpenPTY/raw/master/compiled/tea_openpty.so
How to use the TeaOpenPTY library?
File test.php
<?php
use TeaOpenPTY\TeaOpenPTY;
$app = "/usr/bin/bash";
$argv = [$app, "-i"];
$teaOpenPTY = new TeaOpenPTY($app);
echo "Starting TeaOpenPTY...\n";
$ret = $teaOpenPTY->exec(...$argv);
if ($ret === -1) {
echo "Error: ", $teaOpenPTY->error(), "\n";
}
echo "TeaOpenPTY terminated!\n";
Run
ammarfaizi2#integral:/tmp$ wget https://github.com/ammarfaizi2/TeaOpenPTY/raw/master/compiled/tea_openpty.so
[...output abbreviated...]
2020-12-28 14:39:20 (612 KB/s) - ‘tea_openpty.so’ saved [19048/19048]
ammarfaizi2#integral:/tmp$ echo $$ # Show the current bash PID
19068
ammarfaizi2#integral:/tmp$ php -d extension=$(pwd)/tea_openpty.so test.php
Starting TeaOpenPTY...
ammarfaizi2#integral:/tmp$ echo $$ # Now we are in the terminal spawned by tea_openpty
329423
ammarfaizi2#integral:/tmp$ stty -a
speed 38400 baud; rows 46; columns 192; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc
ammarfaizi2#integral:/tmp$ exit # Terminate the terminal
exit
TeaOpenPTY terminated!
ammarfaizi2#integral:/tmp$ echo $$
19068
ammarfaizi2#integral:/tmp$

How to use random name for image file generated using ffmpeg-php?

The image is generating fine with the below code
$thumbnail = 'images/thumbnail.jpg';
// shell command [highly simplified, please don't run it plain on your script!]
shell_exec("ffmpeg -i $video -deinterlace -an -ss 1 -t 00:00:01 -r 1 -y -vcodec mjpeg -f mjpeg $thumbnail 2>&1");
But it creates a file named thumbnail.jpg
I need to have random name for images generated to save it in the images folder and database. How can i generate a random name to thumbnail in the below code
$thumbnail = 'images/thumbnail.jpg';
Try the following:
$rand = rand(1,10000);
$uniqueName = uniqid($rand);
$thumbnail = "images/{$uniqueName}.jpg";
It will create a unique name for the thumbnail image. Using uniqid() and rand()
change the line
$thumbnail = 'images/thumbnail.jpg';
to
$thumbnail = 'images/img'.rand(99,999999).'.jpg';
it will create a random name for the image.
Random will never grant that EVERY filename generated this way is unique and not already in use.
I suggest using tempnam
Here is an example :
$tmpfname = tempnam("/YOURDIR", "images");
Since you stated in your comment that you need your filename to look like
$thumbnail = 'images/thumbnail+currentTime+randomnumber.jpg'
here's the code to do just that:
$thumbnail = 'images/thumbnail' . time() . rand(1,9) . '.jpg';
I suggest you edit your post and paste these requirements so other users can easily find them.

Create a thumbnail from uploaded pdf

I am trying to make a preview from pdf that users must to upload. I am using 1and1 hosting server, so I don´t have total control about what to install, and I don´t know how to install ImageMagick. I followed these steps and I was using this code (that is working in a different project using a VPS):
private function preViewPDF($filename)
{
$img_path = './assets/uploads/previews';
$file_name = explode(".", $filename)[0].".jpg";
$dir = './assets/upload/files/';
$img = new Imagick($dir."/".$filename.'[0]');
$img->setImageFormat('jpg');
$img->writeImage($img_path."/".$file_name);
return "previews/".$id.$type."/".$file_name;
}
After try that and get Imagick Class not Found Exception, I am trying to convert using exec command:
Actual code
private function preViewPDF($filename)
{
$file_name = explode(".", $filename)[0].".jpg";
$dir = getcwd().'/assets/uploads/files/';
if(file_exists($dir."/".$filename))
{
exec("convert ".$dir."/".$filename.'[0]'." ".$dir."/".$file_name, $output, $return_var);
var_dump($output);
echo "<br>";
var_dump($return_var);
}
else echo "no file";
echo "<br>".$dir."/".$filename.'[0]'."<br>";
echo "<br>".$file_name."<br>";
}
The var_dump($output); throws an empty array. And the $return_var is 1... general error :(
If I change the value between [] (the number of the page I want to convert) $output throws:
array(3) {
[0]=> string(0) ""
[1]=> string(70) "Requested FirstPage is greater than the number of pages in the file: 1"
[2]=> string(53) " No pages will be processed (FirstPage > LastPage)."
}
So... any ideas what am I doing wrong?? Thank you.
Extra Data
Only two little things more (maybe obvious). The first, if I emulate the order on a SSL connection it works (I get a image from a pdf). And second, permissions are not the reason (I tried to create and write a file -with fopen and fwrite- and it works).
EDIT
First, an explanation about my actual code:
$file_name = explode(".", $filename)[0].".jpg";
This line is because the extension of $filename is .pdf, so I need remove this part and concatenate the right extension .jpg (from hello.pdf I get hello.jpg).
$dir = getcwd().'/assets/uploads/files/';
This is the folder where the pdf is uploaded and the jpg preview must be saved.
if(file_exists($dir."/".$filename))
I put this line, simply because I though that the uploading of the pdf wasn´t finished and this was the reason that doesn´t work.
exec("convert ".$dir."/".$filename.'[0]'." ".$dir."/".$file_name, $output, $return_var);
This is the line where the command convert is executed... but doesn´t work.
Second thing is a new simple code I just tried:
if(file_exists("./DpRPJTmfSArPRuGZrOddLendfbhgHTrydwukMRvOMuSzVMDuBb.pdf"))
{
exec("convert ./DpRPJTmfSArPRuGZrOddLendfbhgHTrydwukMRvOMuSzVMDuBb.pdf[0] ./DpRPJTmfSArPRuGZrOddLendfbhgHTrydwukMRvOMuSzVMDuBb.jpg", $output, $return_var);
var_dump($output);
echo "<br>";
var_dump($return_var);
}
else echo "no hay fichero";
The $output is empty, and the $return_var is 1.
Forget all the dross and start simple with the file in the same folder as the code to see if Imagemagick is working.
convert input.pdf output.jpg
Also you have so many variables etc. in the Imagemagick code it is hard to read it.
I am also confused by your code and I would create the filename and path outside the convert code and you can echo it to ensure it contains what you expect.
This looks wrong:
$filename.'[0]'
I would try:
$filename[0]
I assume your pdf has more than one page?
Edit
Try this code - it has a different way of displaying any errors and allows you to view the contents of your command if you have lots of variables etc.
$error=array();
echo "<pre>";
$cmd = "./DpRPJTmfSArPRuGZrOddLendfbhgHTrydwukMRvOMuSzVMDuBb.pdf[0] ./DpRPJTmfSArPRuGZrOddLendfbhgHTrydwukMRvOMuSzVMDuBb.jpg";
// You can use this line to see what the $cmd ontains when using a lot of variables
echo $cmd;
exec("$cmd 2>&1", $error);
echo "<br>".print_r($error)."<br>";
echo "</pre>";
I make preview with this:
exec('convert -density 300 -trim "'.$file.'" -resize 600 -quality 85 -colorspace RGB -background white "'.$destination.'" &', $output, $return_var);
Where $file is tue original and $destination is the name of image.
With the & at the end, each image will be named image-0.jpg, image-1.jpg..
$return_var == 0 when all is OK

php exec() and tesseract goes ''Cannot open input file'

I use Ghostscript to strip images from PDF files into jpg and run Tesseract to save txt content like this:
Ghostscript located in c:\engine\gs\
Tesseract located in c:\engine\tesseract\
web located pdf/jpg/txt dir = file/tmp/
Code:
$pathgs = "c:\\engine\\gs\\";
$pathtess = "c:\\engine\\tesseract\\";
$pathfile = "file/tmp/"
// Strip images
putenv("PATH=".$pathgs);
$exec = "gs -dNOPAUSE -sDEVICE=jpeg -r300 -sOutputFile=".$pathfile."strip%d.jpg ".$pathfile."upload.pdf -q -c quit";
shell_exec($exec);
// OCR
putenv("PATH=".$pathtess);
$exec = "tesseract.exe '".$pathfile."strip1.jpg' '".$pathfile."ocr' -l eng";
exec($exec, $msg);
print_r($msg);
echo file_get_contents($pathfile."ocr.txt");
Stripping the image (its just 1 page) works fine, but Tesseract echoes:
Array
(
[0] => Tesseract Open Source OCR Engine v3.01 with Leptonica
[1] => Cannot open input file: 'file/tmp/strip1.jpg'
)
and no ocr.txt file is generated, thus leading into a 'failed to open stream' error in PHP.
Copying strip1.jpg into c:/engine/tesseract/ folder and running Tesseract from command (tesseract strip1.jpg ocr.txt -l eng) runs without any issue.
Replacing the putenv() quote by exec(c:/engine/tesseract/tesseract ... ) returns the a.m. error
I kept strip1.jpg in the Tesseract folder and ran exec(tesseract 'c:/engine/tesseract/strip1.jpg' ... ) returns the a.m. error
Leaving away the apostrophs around path/strip1.jpg returns an empty array as message and does not create the ocr.txt file.
writing the command directly into the exec() quote instead of using $exec doesn't make the change.
What am I doing wrong?
Halfer, you made my day:-)
Not exactly the way as described in your post but like this:
$path = str_replace("index.php", "../".$pathfile, $_SERVER['SCRIPT_FILENAME']);
$descriptors = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$cwd = $pathtess;
$command = "tesseract ".$path."strip1.jpg" ".$path."ocr -l eng";
$process = proc_open($command, $descriptors, $pipes, $cwd);
if(is_resource($process)) {
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
}
echo file_get_contents($path."ocr.txt");
Perhaps the missing environment variables in PHP is the problem here. Have a look at my question here to see if setting HOME or PATH sorts this out?

Getting script exit status code in php

Is there anyway to get the exit status code for a php script run in the background via exec($cmd, $output, $exitCode)?
For example:
exec('php script.php &', $output, $exitCode);
If the trailing '&' isn't included then $exitCode works as expected, it's always 0 otherwise.
For anybody that finds themselves here, my solution was to make a php script that takes a script as an argument. The new script is called to the background and handles exit statuses appropriately.
For example:
$cmd = 'php asynchronous_script.php -p 1';
exec("php script_executor.php -c'$cmd' &");
The second script looks something like
$opts = getOpt('c:');
$cmd = rtrim($opts['c'], '&');
$exitCode = 0;
$output = '';
exec($cmd, $output, $exitCode);
if ($exitCode > 0) {
...
}
I found something that is probably quite equivalent to Pradeep's solution. Someone posted about this on the function's documentation page.
http://www.php.net/manual/en/function.exec.php#101506

Categories