PHP move file at certain time - php

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 ;)

Related

PHP set proc_open to output directly to user

I'm using proc_open with pdftk to pre-fill some forms with data, this works pretty well, but rather than save the result to a file and then read the file back, I'd like to print the file directly out. I've got this working so I'm not having any problems. But I'd like to direct the output of proc_open directly to the stream returned to the user so that I don't have to hold the value in memory in php. So far I have the following:
$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","error.txt","a") );
$process = proc_open($command, $descriptorspec, $pipes);
if( is_resource( $process ) ) {
fwrite($pipes[0], $fdf);
fclose($pipes[0]);
echo stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($process);
}
I'd like to direct the result directly out to the use as you would get in the above code, without actually saving the value in a variable and then printing it out. Is there a way to direct a stream in php's output directly to the output. I'd like to do this to save memory and reduce the time it takes for the code to run.
Does anyone know of a function for a stream in php that prints the stream result directly out. Or is there a setting for proc_open that does this. Either way I fear this may not work at all, as I may need to add a content-length header to the output to display the PDF directly. If anyone knows of the function to print the stream directly out, is there also a way to get the byte length of the stream without actually reading it in.
Since no one has posted an answer this I may as well post the answer I've found.
Open a stream to php://output with fopen mode w, and use stream_copy_to_stream to send the data from the proc_open process to the user directly. There does not appear to be an easy method to get the length or size of the data in the stream however.
$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","error.txt","a") );
$process = proc_open($command, $descriptorspec, $pipes);
if( is_resource( $process ) ) {
fwrite($pipes[0], $fdf);
fclose($pipes[0]);
/* New Code */
if( $fout = fopen("php://output","w") ) {
stream_copy_to_stream($pipes[1],$fout);
fclose($fout);
}
fclose($pipes[1]);
$result = proc_close($process);
}

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?

Creating a PHP Online Grading System on Linux: exec Behavior, Process IDs, and grep

Background
I am writing a simple online judge (a code grading system) using PHP and MySQL. It takes submitted codes in C++ and Java, compiles them, and tests them.
This is Apache running PHP 5.2 on an old version of Ubuntu.
What I am currently doing
I have a php program that loops infinitely, calling another php program by
//for(infinity)
exec("php -f grade.php");
//...
every tenth of a second. Let's call the first one looper.php and the second one grade.php. (Checkpoint: grade.php should completely finish running before the "for" loop continues, correct?)
grade.php pulls the earliest submitted code that needs to be graded from the MySQL database, puts that code in a file (test.[cpp/java]), and calls 2 other php programs in succession, named compile.php and test.php, like so:
//...
exec("php -f compile.php");
//...
//for([all tests])
exec("php -f test.php");
//...
(Checkpoint: compile.php should completely finish running before the "for" loop calling test.php even starts, correct?)
compile.php then compiles the program in test.[cpp/java] as a background process. For now, let's assume that it's compiling a Java program and that test.java is located in a subdirectory. I now have
//...
//$dir = "./sub/" or some other subdirectory; this may be an absolute path
$start_time = microtime(true); //to get elapsed compilation time later
exec("javac ".$dir."test.java -d ".$dir." 2> ".$dir
."compileError.txt 1> ".$dir."compileText.txt & echo $!", $out);
//...
in compile.php. It's redirecting the output from javac, so javac should be running as a background process... and it seems like it works. The $out should be grabbing the process id of javac in $out[0].
The real problem
I want to stop compiling if for some reason compiling takes more than 10 seconds, and I want to end compile.php if the program stops compiling before 10 seconds. Since the exec("javac... I called above is a background process (or is it?), I have no way of knowing when it has completed without looking at the process id, which should have been stored in $out earlier. Right after, in compile.php, I do this with a 10 second loop calling exec("ps ax | grep [pid].*javac"); and seeing if the pid still exists:
//...
$pid = (int)$out[0];
$done_compile = false;
while((microtime(true) - $start_time < 10) && !$done_compile) {
usleep(20000); // only sleep 0.02 seconds between checks
unset($grep);
exec("ps ax | grep ".$pid.".*javac", $grep);
$found_process = false;
//loop through the results from grep
while(!$found_process && list(, $proc) = each($grep)) {
$boom = explode(" ", $proc);
$npid = (int)$boom[0];
if($npid == $pid)
$found_process = true;
}
$done_compile = !$found_process;
}
if(!done_compile)
exec("kill -9 ".$pid);
//...
... which doesn't seem to be working. At least some of the time. Often, what happens is test.php starts running before the javac even stops, resulting in test.php not being able to find the main class when it tries to run the java program. I think that the loop is bypassed for some reason, though this may not be the case. At other times, the entire grading system works as intended.
Meanwhile, test.php also uses the same strategy (with the X-second loop and the grep) in running a program in a certain time limit, and it has a similar bug.
I think the bug lies in the grep not finding javac's pid even when javac is still running, resulting in the 10 second loop breaking early. Can you spot an obvious bug? A more discreet bug? Is there a problem with my usage of exec? Is there a problem with $out? Or is something entirely different happening?
Thank you for reading my long question. All help is appreciated.
I just came up with this code that will run a process, and terminate it if it runs longer than $timeout seconds. If it terminates before the timeout, it will have the program output in $output and the exit status in $return_value.
I have tested it and it seems to work well. Hopefully you can adapt it to your needs.
<?php
$command = 'echo Hello; sleep 30'; // the command to execute
$timeout = 5; // terminate process if it goes longer than this time in seconds
$cwd = '/tmp'; // working directory of executing process
$env = null; // environment variables to set, null to use same as 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("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
);
// start the process
$process = proc_open($command, $descriptorspec, $pipes, $cwd, $env);
$startTime = time();
$terminated = false;
$output = '';
if (is_resource($process)) {
// process was started
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /tmp/error-output.txt
// loop infinitely until timeout, or process finishes
for(;;) {
usleep(100000); // dont consume too many resources
$stat = proc_get_status($process); // get info on process
if ($stat['running']) { // still running
if (time() - $startTime > $timeout) { // check for timeout
// close descriptors
fclose($pipes[1]);
fclose($pipes[0]);
proc_terminate($process); // terminate process
$return_value = proc_close($process); // get return value
$terminated = true;
break;
}
} else {
// process finished before timeout
$output = stream_get_contents($pipes[1]); // get output of command
// close descriptors
fclose($pipes[1]);
fclose($pipes[0]);
proc_close($process); // close process
$return_value = $stat['exitcode']; // set exit code
break;
}
}
if (!$terminated) {
echo $output;
}
echo "command returned $return_value\n";
if ($terminated) echo "Process was terminated due to long execution\n";
} else {
echo "Failed to start process!\n";
}
References: proc_open(), proc_close(), proc_get_status(), proc_terminate()

How to background a process via proc_open and have access to STDIN?

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'),
);

How can I invoke the MySQL interactive client from PHP?

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.

Categories