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?
Related
I am trying to move a file from one folder to another at a specific time. In order to achieve this I am trying to use the Linux at command with a pipe :
`mv file /to/dest | at h:m d.m.y`
This is what I've written:
$move = "mv $filename /destination/folder";
$at = "at $my_datetime";
$res = execute_pipe($move,$at);
where the execute_pipe function is defined as following:
function execute_pipe($cmd1 , $cmd2)
{
$proc_cmd1 = proc_open($cmd1,
array(
array("pipe","r"), //stdin
array("pipe","w"), //stdout
array("pipe","w") //stderr
),
$pipes);
$output_cmd1 = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value_cmd1 = proc_close($proc_cmd1);
$proc_cmd2 = proc_open($cmd2,
array(
array("pipe","r"), //stdin
array("pipe","w"), //stdout
array("pipe","w") //stderr
),
$pipes);
fwrite($pipes[0], $output_cmd1);
fclose($pipes[0]);
$output_cmd2 = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value_cmd2 = proc_close($proc_cmd2);
return $output_cmd2;
}
The problem is that the files get moved right away, ignoring the at command. What am I missing? Is there a better way to do this?
To me it seems like your problem has nothing to do with PHP. You're just using the Shell incorrectly.
The Man page of at reads:
at and batch read commands from standard input or a specified file
which are to be executed at a later time, using /bin/sh.
But your usage of the shell does execute your "mv file /destination" command, and then pipes the OUTPUT of that command to at. On a successful moving operation that output will ne nothing. So by using the pipe you actually move the file right away and tell at to do nothing at your specified time.
Read the man page of at by typing man at into your terminal to resolve the issue. Hint: if you want to use STD INPUT, echo'ing your command might help ;)
To my PHPeoples,
This is sort of a weird PHPuzzle, but I'm wondering if it's PHPossible.
The end goal is the equivalent functionality of
mysql mydb < file.sql
But with an API like this
./restore < file.sql
Where restore is a PHP script like this
#!/usr/bin/env php
$cmd = "msyql mydb";
passthru($cmd, $status);
However, I want to pass STDIN to the passthru command.
The clear benefit here is that I can put restore somewhere in a pipeline and everything works peachy. Here's an example
# would be pretty awesome!
ssh $remote "msyqldump $config mydb | gzip" | gzip -dc | ./restore
Anyway, I doubt it's possible using passthru, but perhaps with proc_open in some way?
As a last case resort, in the event of an unsolvable PHPredicament, I would do something like this
./restore file.sql
With script like this
#!/usr/bin/env php
$cmd = sprintf("mysql mydb < %s", $argv[1]);
passthru($cmd, $status);
PHPwnd
./restore
#!/usr/bin/env php
<?php
// set descriptors
$desc = array(
0 => array("file", "php://stdin", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
// open child proc
$proc = proc_open("mysql -uUSER -pPASS mydb", $desc, $pipes);
if (is_resource($proc)) {
// display child proc stdout
echo stream_get_contents($pipes[1]);
// close file streams
array_map('fclose', $pipes);
// get return value
$ret = proc_close($proc);
// display return value
printf("command returned %s\n", $ret);
}
Example use
cat file.sql.gz | gzip -dc | ./restore
What! PHProfound!
Turns out passthru already does this! PHenomenalP!
Check it out, PHPals:
gzip.php
#!/usr/bin/env php
<?php
passthru("gzip", $status);
if ($status !== 0) {
error_log("gzip exited with status %d", $status);
}
How PHProgressivist!
echo "hello" | php gzip.php | gzip -dc
Output
hello
For some strange reason this
echo system("echo 'echo hello > /dev/pts/2' | /usr/bin/at 19:36");
Refuses to work from my php script, however the command works fine when I just enter it through command line.
I know php has permission to execute some commands. I can run 'ls' from the php script but not the 'at' command. I've tried playing around with file permissions, but so far to no avail :(
edit
Permissions for /usr/bin/at are:
-rwxr-sr-x 1 daemon daemon 42752 Jan 15 2011 at
I think it's a permissions problem, if I execute the php file from my ssh terminal it works fine, but not from the web.
What you are executing is
echo 'hello' > /dev/pts/2 | /usr/bin/at 19:36
meaning
echo 'hello' > /dev/pts/2
and pipe stdout to /usr/bin/at 19:36 but since you already redirected the echo to /dev/pts/2, this will be empty. What you probably meant to do is:
echo system("echo 'echo hello > /dev/pts/2' | /usr/bin/at 19:36");
You might also want to use shell_exec to pass the command through a shell or alternatively proc_open which gives you better control over stdin/out/err of the command you are executing. Your example would correspond to (adapted example from php.net docs):
<?php
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
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('/usr/bin/at', $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], 'echo "hello" > /dev/pts/2');
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$return_value = proc_close($process);
echo "command returned $return_value. stdout: $stdout, stderr: $stderr\n";
} else {
echo "Process failed";
}
?>
In your php.ini file check for disable_functions sometimes functions like system are disabled for security reasons.
I'm happily using proc_open to pipe data into another PHP process.
something like this
$spec = array (
0 => array('pipe', 'r'),
// I don't need output pipes
);
$cmd = 'php -f another.php >out.log 2>err.log';
$process = proc_open( $cmd, $spec, $pipes );
fwrite( $pipes[0], 'hello world');
fclose( $pipes[0] );
proc_close($process);
In the other PHP file I echo STDIN with:
echo file_get_contents('php://stdin');
This works fine, but not when I background it. Simply by appending $cmd with & I get nothing from STDIN. I must be missing something fundamental.
It also fails with fgets(STDIN)
Any ideas please?
You can't write to STDIN of a background process (at least, not in the normal way).
This question on Server Fault may give you some idea of how to work around this problem.
Unrelated: you say do don't need outputs in the spec, yet you specify them im your $cmd; you can write $spec like this:
$spec = array (
0 => array('pipe', 'r'),
1 => array('file', 'out.log', 'w'), // or 'a' to append
2 => array('file', 'err.log', 'w'),
);
I'm trying to get
`mysql -uroot`;
to enter the MySQL interactive client just as executing
$ mysql -uroot
from the shell does.
It's okay if the PHP script exists after (or before), but I need it to invoke the MySQL client.
I've tried using proc_open() and of course system(), exec() and passthru(). Wondering if anyone has any tips.
New solution:
<?php
$descriptorspec = array(
0 => STDIN,
1 => STDOUT,
2 => STDERR
);
$process = proc_open('mysql -uroot', $descriptorspec, $pipes);
Old one:
Save for tab completion (you could probably get it in there if you read out bytes with fread instead of using fgets), this gets you on your way, lots left to tweak:
<?php
$descriptorspec = array(
0 => array("pty"),
1 => array("pty"),
2 => array("pty")
);
$process = proc_open('mysql -uroot', $descriptorspec, $pipes);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking(STDIN,0);
do {
echo stream_get_contents($pipes[1]);
echo stream_get_contents($pipes[2]);
while($in = fgets(STDIN)) fwrite($pipes[0],$in);
} while (1);
I guess it does work, but it's waiting for some input. Try sending some sql commands to it's stdin. Of course, since the backtick operator doesn't support IO remapping, you'll need more complex process handling.