I have been searching for a while in how to successfully exec a Python script through PHP, just for a test thats all.
I've never actually worked with Python and a while since I programmed in PHP but looked for a simple code to send data from PHP to Python and then in .py send back data to PHP.
I have tried exec in PHP, with and without json enc/dec without any success.
These are the commands that have I tried in PHP:
* $result = shell_exec('pythontest.py' . escapeshellarg(json_encode($data)));
* exec("python pythontest.py", $resultData);
var_dump($resultData);
with no success.
In pythontest.py: a print to send back data.
Tried with full paths of both Python and pythontest.py (PHP).
enc/dec with json works in PHP file so nothing seems to be wrong in the PHP code still I can't run the script!
As I said, I haven't worked with Python before so I wonder if there is more needed than just writing the code in the script in order to make it work?
I have seen many posts about this and tried their code that "would work for them" but not for me^^
Additional info: PHP through WAMP, .py in same map. It is supposed to be web based, if that makes it difference.
Check to make sure that the directory containing python.exe is in the PATH of your PHP script (via getenv('PATH')).
Try running python c:\path\to\pythontest.py directly via a Windows command prompt. Does that work? If not, debug PATHs and issues from there, then try again in PHP.
If your WAMP stack runs PHP with limited permissions, check to make sure that user has "Read and execute" type permissions on the python.exe file, as well as the entire directory which contains it, recursively. This might be overkill, but recursively setting perms for that user on the whole python distribution directory rules out permissions-related problems.
Try qualifying the python executable's name with .exe, e.g. c:\python27\python.exe pythontest.py (you might have tried that anyway, since you say you tried with "full paths", but I'm throwing it out there to make sure you included the .exe).
Try replacing the contents of pythontest.py with something extremely simple (e.g. print 'hello') and check whether or not behavior changes.
Also, please post the contents (or at least first lines) of pythontest.py.
I have now tried changing the path, as python.exe was not in the same directory.
My end result on this was
$output = getenv('PATH');
echo "Real Path: " . $output . "<br>";
$ret = apache_getenv("PATH");
echo "Apache Path: " . $ret . "<br>";
apache_setenv("PATH", "C:/Python33");
$ret = apache_getenv("PATH");
echo "Apache new path: " . $ret . "<br>";
$output = getenv('PATH');
echo "Real path, hopefully changed: " . $output . "<br>";
this was just to see if i could change the path, since i have never done that before.
i have now only
import sys, json
print ("hello")
in my python file and tried to run it through cmd, and it worked.
but when i try run it with php, it fails once again.
i have also looked over the permissions:
admin, user have permission to read and execute, i even added "Everyone" with full permission on folder and sub-folder/files just to see if that made any difference.
something i have missed or did i do something wrong with permission, python code or paths ?
Related
<?php // BISMILLAHIRRAHMANIRRAHEEM
error_reporting(E_ALL);
ini_set("display_errors", 1);
// tried the following with soffice, soffice.com, soffice.exe, soffice.bin
// MS-DOS: soffice, soffice.com, soffice.bin all work successufully and generate the pdf
$ex = "soffice.com --headless --convert-to html \"" . getcwd() . DIRECTORY_SEPARATOR . "sources" . DIRECTORY_SEPARATOR . "test.docx\" --outdir \"" . getcwd() . DIRECTORY_SEPARATOR . "results\"";// 2>&1";
chdir("C:\Program Files\LibreOffice\program");
echo $ex . "<br />";
exec($ex, $output);
//exec("mkdir rr", $output); // generates directory
//exec("dir soff*", $output);
//exec("a.bat", $output); // doesn't generate pdf
print_r($output);
?>
Hi, I'm using IIS with Windows 7, PHP 5.6.39. I am unable to convert a docx document to pdf by calling LibreOffice via PHP. The command output to screen in the code example works if executed in MS-DOS window but doesn't work in php's exec() or shell_exec(). The folder seems to have the appropriate permissions since my upload scripts and exec("mkdir newdir") are working.
exec("dir"); also outputs directory listings for the mentioned path, so DOS navigation commands seem to work as well.
I'd like to avoid the solution to make another user. Not elegant. This shouldn't be difficult INSHAALLAH.
By not working, I mean no document is generated and no output/ error is generated by exec() either which makes it difficult to debug.
Thank you for your time.
Update:
After some fiddling, I've realized the return code is: -1073741515
Google results show that its apparently a File I/O failure.
Another script I have downloaded which does something similar, also gave the same error. So looking into the causes. As I said before, the directories can be made and files uploaded as it has permissions.
In the link I've posted, there seems to be need for making new user. Is it possible that IIS has permissions to the directory but not the PHP exec()?
On Linux, it gives me error code 77, permission denied?
BISMILLAHIRRAHMANIRRAHEEM
ALHAMDOLILLAH after much search, finally found the answer.
Windows:
I did some permissions etc earlier, should be trivial with IIS. But what finally solved the problem was this.
Apparently there needs to be specified -env:UserInstallation=file:///C:\some\path because you cannot run multiple instances of LibreOffice concurrently without specifying a different profile folder (Reference).
Also, see the same solution here.
When executing a program via PHP over IIS, the user account for Windows is the IUSR account.
So,
Give IUSR write (and modify? I give full) permissions to be able to write to C:\inetpub\wwwroot\path directory.
Change directory to LibreOffice path for soffice.com (Not needed if providing full path when executing):
chdir("C:\\Program Files\\LibreOffice\\program");
Set HOME environment variable, as LibreOffice needs a writable temporary path. IUSR must have permissions to this path. I simply re-use wwwroot (This step could be optional):
putenv("HOME=C:\\inetpub\\wwwroot\\temp");
Execute in PHP, something like:
exec("\"C:\\Program Files\\LibreOffice\\program\\soffice.com\" --headless \"-env:UserInstallation=file:///C:/inetpub/wwwroot/LibreOfficeProfilePath1\" --convert-to pdf:writer_pdf_Export --outdir \"C:\\inetpub\\wwwroot\\result\" \"C:\\inetpub\\wwwroot\\source\\file.docx\"", $output, $ret);
// Displaying the command output
print_r($output);
echo "<br />\n\n<br />"; // Line breaks for view-source
echo "Return code: " . $ret;
Clean up by removing the profile directories for LibreOffice. Since you'd be making unique directories on-the-fly on a server environment for concurrent sessions of LibreOffice, you'd like to delete them too. Following snippet from here:
exec("rmdir /S /Q \"C:\\inetpub\\wwwroot\\LibreOfficeProfilePath1\"");
You could look to generate this profile path automatically, like:
// Do this before executing soffice command and pass it to -env
$profilepath = "C:/inetpub/wwwroot/LibreOfficeProfilePath" . date("YmdHis") . rand(0, 999999);
// Make sure to replace '/' with '\' when deleting
exec("rmdir /S /Q \"" . str_replace("/", "\\", $profilepath) . "\""); // Windows
exec("rm -rf \"" . str_replace("/", "\\", $profilepath) . "\"); // Linux
or instead use PHP to delete directory with files in it as shown here.
LibreOffice running as a service and PHP requesting document conversions may be a better solution but this post relates to invoking LibreOffice each time a document conversion is needed and then letting it close. A separate process method may also be used to avoid waiting for LibreOffice to complete conversion.
Linux:
Similar steps for www-data, as that is the user account for apache in Linux. See the solution here.
www-data does not have $HOME directory so it needs to be specified as indicated in (3) above.
env path would be something like:
\"-env:UserInstallation=file:///var/www/tmp\"
Notice the three / after file: regardless of Windows or Linux, even though paths in Linux start with /, or maybe they ignore the slash in Windows, seems inconsistent to me, though.
INSHAALLAH it'll work after that.
Last night I spent 5.5 hours trying make PHP execute and receive the output of Virtualenv’ed Python script. Nothing worked; except for scripts that were not Virtualenv’ed.
What I am trying to do:
I am trying to make PHP call a virtualenv’d install of the Newspaper lib output text when I call it.
What I have now:
PHP: (updated)
<?php
$output = exec('newspaper2/bin/python3 /var/www/html/components/python/test.py 2>&1', $output2);
print_r(error_get_last());
echo $output2;
echo $output;
…this works when using a non-virtualenv script
Python: (updated)
from newspaper import Article
url = 'http://example.com/'
article = Article(url)
article.download()
article.html
article.parse()
article.authors
article.publish_date
string = article.text
print(string)
What the issue is:
I can run the script that PHP is running from the command line and it outputs just fine.
What I have tried:
With PHP, (I have tried all the “exec” calls for PHP) it cannot seem to open the virtual environment and returns nothing.
Before the script I have called “python3” and a few other things to no avail.
Yes, I have chmoded it to be executable…
I feel like this should be so simple.
I have tried suggestions on other posts and all over the web to no avail.
Questions:
Did I set up the virtualenv wrong?
At the top of the Python script, instead of the “#!/usr/bin/env python3” should I call something else?
If so, where do I find it? Should I start from scratch and will that
help?
Thank you for your help;
PS: I am running Ubuntu16, PHP7 and I need to use Python3
In the virtualenv'ed scripts (i.e. installed via the setuptools' entry-points), you should not touch the shebang (#!... first line). It is populated by the virtualenv & setuptools & related tools.
If you specify your own shebang, then it is not virtualenv'ed script. In that case, call python directly:
exec('/path/to/venv/bin/python3 /var/www/html/components/python/testing.py');
Alternatively, you can put the absolute path to the virtualenv's python binary to the py-script, but this does not look a good idea.
Also, remember that virtualenvs are non-relocatable. So they should stay in the path where they were created.
Also note that exec() returns only the last line of the output. You probably want shell_exec() or exec('...', $output) to get the whole output.
Also, it is unclear what happens with your script, and what is being printed on stderr. Try this command to see what is the error:
exec('/path/to/script 2>&1', $output)
#OR:
exec('/path/to/venv/bin/python3 /path/to/script 2>&1', $output)
OK, I finally figured it out and learned a lot in the process. The newspaper lib that I am using by default tries to write to the base of the users home directory. In this case, it was attempting to write to www-data, /var/www.
To fix this:
Go to the settings.py file in the newspaper library.
Edit the variable DATA_DIRECTORY = '.newspaper_scraper' and change it to DATA_DIRECTORY = '.path/to/writable/directory'
Save the file and you should be good to go.
I have no idea why it was not returning the errors that would have explained this sooner.
Hope this helps anyone else.
Thank you so much Sergey Vasilyev for your help. I appreciate it greatly.
I've been working on a local app over the last few days and I've noticed that one of my 'exec()' functions to call an external program didn't fire correctly. Upon further investigation it was obvious that the program did execute, but it quit prematurely as an important line utilizing 'file_get_contents()' didn't retrieve the contents of the file specified.
The file is a plaintext file without an extension. I'm guessing that 'file_get_contents()' is treating the file as a directory since there is no extension? It's strange because if I manually execute the same program from a web browser, everything works perfectly.
Here's an example line for clarity -
while(file_get_contents('plaintextfile') == "something"){
/// Do This
}
The above works just fine when I visit /program.php from a web browser, but when calling it like this it gives me a file/folder not found error for 'plaintextfile'.
exec('php /program.php', $output);
foreach($output as $output){
print $output . "<br>";
}
Thanks in advance to anyone who can shed some light on this situation. I'm really puzzled by this...
PHP as executed from the browser and executed by the command line (in the exec() call) may use different php.ini configurations, and may have different file search paths. The best course of action is to supply the full path to plaintextfile.
if(!file_get_contents('/path/to/plaintextfile')){
// file couldn't be read
}
I have a Python program that parses files, takes a path as and argument and parses all files in the given path and all sub directories - using os.walk(path). I want to call this from my php Web App, so the user can specify a path, which is then passed as an argument to the parser. (Passing a path is ok because its all on an internal network).
I can call the parser fine and pass the arguments ok using popen(), but the path that the Python program receives is always invalid. I have had the php script output the command it is sending to the browser. If I copy and paste that command into a command window, the parser works fine.
I know the path the php script passes is invalid from the result of os.path.exists(path) in the Python script
This is the code to call the Python program:
$path = $_REQUEST['location'];
echo "Path given is: ".$path;
$command = 'python C:\Workspaces\parsers\src\main\main.py '. intval($mode).' "'.$path.'"';
echo "<p>".$command."</p>";
$parser = popen($command, 'r');
if ($parser){
echo "<p>Ran the program</p>";
while (!feof($parser)){
$read = fgets($parser);
if (!$read)
echo "<p>Reached end of file</p>";
else
echo "<p>".$read."</p>";
}
}
The command echoed in the browser is like:
python C:\Workspaces\parsers\src\main\main.py 2 "I:\Dir1\Dir2\Dir3"
Where the 2 is just another argument to the script and $_REQUEST['location'] is defined from an input text box in a form on the calling page.
This is on a Windows system, so I am assuming this has something to do with the backslashes in the path.
Basically, I am unsure as to how all the backslashes are being handled. I would like to understand how strings containing backslashes are sent to the php page, and how they are sent again using popen(). I think the result being printed to the browser is not the raw command string, and I can't be sure how many backslashes are really in the command being issued by popen().
If anyone has any ideas I'd really appreciate it.
Edit:
So in the Python program the path is used as follows:
nfiles=0
print 'Parsing all files in directory tree '+path+"<br />"
start = time.time()
if not os.path.exists(path):
print "<p>Path is NOT REAL!!!</p>"
else:
print "<p>Path IS real!</p>"
for root, dirs, files in os.walk(path):
for f in files:
file = os.path.join(root,f)
print file
nfiles+=1
...Code to run parser...
print nfiles, "Files parsed<br />"
This is echoed back to the browser from the $read variable.
Output of that is:
Parsing all files in directory tree I:\Dir1\Dir2\Dir3
Path is NOT REAL!!!
0 Files parsed
This is identical to the output if the command is run from the command line (the command being copied from the browser and pasted into the cmd window). EXCEPT, when run that way the path IS real, and all the files are parsed. (and in the command window the html markup shows too)
The web server and parsers are hosted on my local machine.
Check to see what user the PHP server is running as. If I:\ is a network drive, don't expect those to be mapped under that user. Use a UNC path instead.
Things to try:
a different path (we know C:\Workspaces\parsers\src\main\ works, why don't you try that?)
I'm attempting to get PHP to call a batch file which will take an RTF file and convert it to a PDF using an OpenOffice macro. I've tested the batch file on the command line and it works fine, but I'm not having any luck calling and using the same batch file from PHP.
My machine OS is XP professional SP 3. I'm running IIS 6 and PHP version 5.2.9.
I've granted execute permissions to the internet user on c:\windows\system32\cmd.exe.
I specified the full path to the batch file being executed and the full path to the RTF file to be converted.
The PHP looks like this where $arg is the RTF to be converted:
$arg = "C:\\web_root\\whatever\\tempOutput.rtf";
$command = "c:\\windows\\system32\\cmd.exe /c c:\\web_root\\whatever\\convert.bat $arg";
Then inside a try-catch I call the exec command:
exec("$command 2>&1 && exit", $ret, $err);
I echo the results after the catch:
echo "ret: ";
print_r ($ret);
print "<br>";
echo "err is ";
echo $err;
print "<br>";
echo "DONE!";
And this is what I see:
ret: Array ( )
err is 0
DONE!
The RTF file does not get converted and I'm not seeing the errors. Any ideas on what I can try next? Thanks!!!
I'm going to bet this is about permissions.
In a typical setup, PHP runs as apache - so you'll want to make sure apache has the rights to execute the batch file.
also, check this relevant SO question, and this google search.
Looks like the output array is empty. Is your batch script supposed to have output?
Also, escapeshellcmd and escapeshellarg should be used
Are you using IIS as your webserver? If so, the PHP exec function will not work by default and you should NOT circumvent the security measures that prevent it from running.
Check your event viewer and you should find some errors pertaining to your problem. Run a query through google for: IIS PHP exec. This should give you a large selection of information about the problem.
Basically, the PHP exec function tries to fork a new cmd.exe instance. IIS prohibits this because it could open a security hole in the system.
The best solution that I have come up with is to have your php script either write the command that you want to execute to a flat file or make a database entry. You will then need to write a seperate script that is launched by the windows scheduler to run every 10 minutes or so that will check your flat file or database for commands to run. The new script will then run the commands and then place either the results or an execution confirmation that your web app will be able to access at a later time.
It's a kludge for sure.
Is PHP running in safe-mode? If so, shell commands are escaped with escapeshellcmd. Perhaps this is the problem?
Do you have control of the server running the PHP script?