0

I'm having some trouble using the PHP exec() function. Whenever the script I'm attempting to run is short, exec() works just fine. But if the script takes any more than a second or so, it fails. Note, I've attempted run the long script manually on the command line, and it works just fine. It seems as though the PHP interpreter is killing my external script if it takes any longer than a second or so to run. Any thoughts or suggestions? Here is my code:

<?php
    $fileName = "foobar.docx";
    $argVar = $fileName;
    exec("python3 /var/www/html/jan8/alexandrina.py /var/www/html/jan8/$argVar");
    echo "$output";
?>

And here is my script:

#!/usr/bin/env python3

import docx
import sys

docxFile = "".join(sys.argv[1:])

# The Three Lines Below Create a New Variable "htmlFile"
# "htmlFile" is the same as "docxFile", except ".docx" is cut off
# and replaced with ".html"
myNumber = len(docxFile) - 5
htmlFile = docxFile[0:myNumber]
htmlFile = htmlFile + '.html'

def generateHTML(filename):
    doc = docx.Document(filename)
    fullText = []
    for para in doc.paragraphs:
        fullText.append('<p>')
        fullText.append(para.text)
        fullText.append('</p>')
        fullText.append('\n')
    return '\n'.join(fullText)

file = open(htmlFile, "w")
file.write(generateHTML(docxFile))
file.close()

print("end python script")

Additional notes: I've increased the max execution time limits in php.ini, but I don't think that should matter, as the "long script" should only take a few seconds to run. Also, when I refer to the "short script", and the "long script", I'm actually referring to the same script. The difference between the "long script" and the "short script" is just the time to execute as it may vary depending on the size of the file I'm asking the script to process. Anyway... any suggestions would really be appreciated!

15
  • What happens if you type the python command on the command line? Does the prompt return immediately? Or do you have to wait for the python script to complete before you can type another command? Commented Jan 10, 2017 at 4:01
  • If I run the python script on the command line, it works just fine. Commented Jan 10, 2017 at 4:07
  • Yes but when you run from the command prompt -- once you hit 'enter' after typing in the command, does it return immediately or do you have to wait until the long-running python process completes? Commented Jan 10, 2017 at 4:10
  • When I run the script to process a large file, it takes a few seconds before the process completes, it does not return immediately. However, if I run the script to process a small file, it returns almost immediately. Commented Jan 10, 2017 at 4:13
  • 1
    Thank you so much for the help S. Imp. I was able to finally solve the problem using your debugging suggestions. Really appreciate the help! Probably would not have been able to figure it out without your assistance. Commented Jan 10, 2017 at 6:36

2 Answers 2

1

Ordinarily, php exec function should block until the command you run has completed. I.e., the PHP script will halt, waiting for the command to finish until continuing with the rest of your script. I was half thinking that your server was experiencing a max_execution_time timeout, but you've clearly stated that even just a couple of seconds is too long and even these fairly short scripts are having trouble.

A couple of solutions occur to me. The simplest one is to alter the python command so that a) any output is routed to a file or output stream and b) the process is run in the background. According to the docs on exec:

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.

I also would like you to make use of the two additional optional parameters for the exec function.

$fileName = "foobar.docx";
$argVar = $fileName;
$cmd = "python3 /var/www/html/jan8/alexandrina.py /var/www/html/jan8/$argVar";
// modify your command to toss output, background the process, and output the process id
$cmd_modified = $cmd . " >/dev/null & echo \$!";
$cmd_output = NULL; // this will be an array of output
$cmd_return_value = NULL; // this will be the return value of the script
exec($cmd_modified, $cmd_output, $cmd_return_value);
echo "exec has completed</br>";
echo "output:<br>" . print_r($cmd_output, TRUE) . "<br>";
echo "return value: " . print_r($cmd_return_value, TRUE);

This may help or may not. If it does not, we still might be able to solve the problem using posix commands.

EDIT: according to crispytx, the long scripts are resulting in a $cmd_return_val of 1 which means an error is happening. Try changing this one line:

$cmd_modified = $cmd . " >/dev/null & echo \$!";

to this

$cmd_modified = $cmd . " & echo \$!";

And let us know what the output of $cmd_output is -- it should at the very least have the process id of the newly spawned process.

Sign up to request clarification or add additional context in comments.

Comments

0

Thanks for all the help S. Imp. I had a little trouble debugging using your suggestions because I happened to be using AJAX to call the script. However, I wrote simpler script using your suggestions to try and debug the problem and this is what I found:

Array ( [0] => Traceback (most recent call last): [1] => File "/var/www/html/jan8/alexandrina.py", line 28, in [2] => file.write(generateHTML(docxFile)) [3] => UnicodeEncodeError: 'ascii' codec can't encode character '\u2026' in position 25: ordinal not in range(128) )

So it looks like the problem has to do with ascii encoding! Even though the larger file was just a docx file with the same text as the shorter docx file repeated over and over again for 300 pages. It seems that if a docx file exceeds 1 pages, ascii characters are inserted that aren't present in single page docx files. I have no idea if this post will ever end up helping anyone, but who knows!

[SOLVED]

1 Comment

Glad you sorted it out. If you use exec, you should always pay attention to the return_val.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.