4 Ways To Call Python Scripts From PHP

So you have a PHP project that needs to call a Python script to do some processing?

There are 4 possible ways to call a Python script from PHP:

  • Call the Python script in the command line, using shell_exec() or exec().
  • Set the Python script as an API endpoint, and do a CURL call from PHP.
  • Alternatively on an HTML page – Call the Python script, then pass the output to PHP.
  • Finally, set the Python script as a socket endpoint.

Let us walk through examples of each method – Read on!

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

EXAMPLE CODE DOWNLOAD

Source code on GitHub Gist

Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

 

PHP CALL PYTHON

All right, let us now get into the examples of calling a Python script from PHP.

 

METHOD 1) COMMAND LINE

1A) PYTHON

1a-cli.py
print("Hello from Python CLI.")

This is probably one of the easiest methods, create your Python script as usual – This is just a dummy script.

 

1B) PHP

1b-cli.php
<?php
$script = __DIR__ . DIRECTORY_SEPARATOR . "1a-cli.py";
$result = shell_exec("python $script");
echo "PHP got the result - $result";

In PHP, use shell_exec() or exec() to call the Python script.

 

 

METHOD 2) CURL

2A) PYTHON

2a-curl.py
# (A) LOAD FLASK
from flask import Flask
app = Flask(__name__)

# (B) DUMMY ENDPOINT
@app.route("/")
def hello():
  return "Hello from Python CURL."

# (C) GO!
if __name__ == "__main__":
  app.run(host = "localhost", port = "8008")

There’s no need to be confused –

  • Your “regular Apache-Mysql-PHP” stack will still run at http://localhost:80.
  • Python will deploy an “alternative” HTTP server at http://localhost:8008.

 

2B) PHP

2b-curl.php
<?php
$c = curl_init();
curl_setopt($c, CURLOPT_URL, "http://localhost:8008/");
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($c);
echo "PHP got the result - $result";

From PHP, we do a CURL call to Python at http://localhost:8008.

 

 

METHOD 3) FETCH

3A) HTML JAVASCRIPT

3a-fetch.html
/ (A) CALL PYTHON SCRIPT
function callPY () {
  fetch("http://localhost:8008", {
    method : "POST",
    mode : "cors"
  })
  .then(res => res.text())
  .then(res => callPHP(res))
  .catch(err => console.error(err));
}
 
// (B) CALL PHP SCRIPT
function callPHP (res) {
  // (B1) DATA FROM PYTHON
  let data = new FormData();
  data.append("data", res);

  // (B2) FETCH PHP
  fetch("http://localhost/3c-fetch.php", {
    method : "POST",
    body : data
  })
  .then(res => res.text())
  .then(res => console.log(res))
  .catch(err => console.error(err));
}
 
// (C) GO!
callPY();

This roundabout alternative involves a “third party”, HTML/Javascript – On the HTML page, we call the Python script first, then pass the result to PHP.

 

3B) PYTHON

3b-fetch.py
# (A) LOAD FLASK
from flask import Flask, Response, request
app = Flask(__name__)
 
# (B) ALLOWED ORIGINS
allowed = ["http://localhost", "https://localhost"]
 
# (B) DUMMY ENDPOINT
@app.route("/", methods=["POST"])
def hello():
print(request.environ["HTTP_ORIGIN"])
  if "HTTP_ORIGIN" in request.environ and request.environ["HTTP_ORIGIN"] in allowed:
    response = Response("Hello from Python FETCH.", status=200)
    response.headers.add("Access-Control-Allow-Origin", request.environ["HTTP_ORIGIN"] )
    response.headers.add("Access-Control-Allow-Credentials", "true")
    return response
  else:
    return Response("Not Allowed", status=405)
 
# (D) GO!
if __name__ == "__main__":
app.run(host = "localhost", port = "8008")

No need to be confused, this is the same as the previous example with minor additions:

  • This will still deploy a Python HTTP server at http://localhost:8008.
  • We also output cross-origins (CORS) headers to support the fetch() calls… Yep, localhost and localhost:8008 are considered to be “different domains”.

 

3C) PHP

3c-fetch.php
<?php
echo "PHP received - " . $_POST["data"];

Since Javascript has “already called Python”, we process whatever output from Python as usual.

 

 

METHOD 4) SOCKET

4A) PYTHON

4a-socket.py
# (A) LOAD SOCKET MODULE
import socket
 
# (B) CREATE SOCKET SERVER
s = socket.socket()
s.bind(("127.0.0.1", 8008)) # bind to 127.0.0.1:8008
s.listen(1) # allow only 1 client
print("Ready")
 
# (C) ACCEPT CONNECTION
conn, addr = s.accept() 
print("Connection from: " + str(addr))
while True:
  data = conn.recv(1024).decode()
  if data:
    print("Received: " + str(data))
  break
conn.close()

Finally, we can also set a Python endpoint using TCP.

 

4B) PHP

4b-socket.php
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, "127.0.0.1", "8008");
socket_write($socket, "Hello from PHP!");
socket_close($socket);

In PHP, we connect to the Python endpoint and do the “data exchange”.

P.S. If you get “socket_create() is an invalid function”, enable the module in php.iniextension=sockets

 

 

EXTRAS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

PASSING PARAMETERS

  • Yes, Python does accept command-line arguments.
    • import sys
    • print(sys.argv)
  • In CURL/fetch, we can do POST/GET as usual.
  • In sockets, we are pretty much sending/receiving data between 2 servers.

 

WHICH IS THE BEST METHOD?

It depends.

  • If you just want something simple, the command line will do.
  • If you have multiple Python scripts, it is better to set up many endpoints.
  • If you are dealing with huge amounts of data, socket will be better.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *