run Python script from PHP (2)

…run Python script from PHP

Kolejnym krokiem – chciałem sprawdzić to co wcześniej udało się osiągnąć, ale w ten sposób, aby miast schematu Python <–> PHP <–> Python użyć PHP <–> PHP <–> Python. Idąc dalej, można sobie wyobrazić, że to pierwsze PHP to strona z której wysyłamy zapytanie do (drugiego) PHP etc…

Rozbudowałem także część opisową, teraz schemat wygląda tak:

kod końcowego skryptu – Pythona:

Python wczytuje argumenty podane przez wywołujący program w linii komend, są to pary klucz=wartość, rozdzielone spacją, sys.argv odczytuje je jako listę, przy czym na pierwszym miejscu [0] występuje ścieżka pliku Pythona.
Dodałem też przedstawienie się versji Pythona (będzie to ważne przy testowaniu np. z venv) i moment startu i końca działania skryptu (wrócimy do tego później).

#!/usr/bin/env python
# coding=utf-8

import sys
from datetime import datetime

print 'Python: start: ' + str(datetime.now()) + '<br>'
args = {}
if sys.argv:
   for pair in sys.argv:
      #print pair
      #print '<br>'
      one = pair.split('=', 1)
      if one and len(one) == 2 and one[0]:
         #print one[0]
         #print '<br>'
         args[one[0].decode('utf-8')] = one[1].decode('utf-8')
print 'Python: Python-version: ' + str(sys.version) + '<br>'
print 'Python: RX-DATA:<br>'
print(args)
print '<br>Python: stop: ' + str(datetime.now()) + '<br>'
print 'Python: tested by: http://blog.wiks.eu'

wyjście Pythona może wyglądać np tak:

Python: start: 2018-05-12 09:10:49.836750
Python: Python-version: 2.7.9 (default, Aug 13 2016, 16:41:35) [GCC 4.9.2]
Python: RX-DATA:
{u'city_name': u'Cz\u0119stochowa', u'lat': u'50.7651978', u'lon': u'19.1587636'}
Python: stop: 2018-05-12 09:10:49.836967
Python: tested by: http://blog.wiks.eu 

kod (środkowego/)’kopiącego’ PHP:
Podobnie jak w Pythonie – przedstawiamy się versją i mierzymy czas.
Wyświetlamy także sposób w jaki wywołujemy Pythona i to co nam Python zwrócił.

<?php
/* PHP running Python
 */
echo 'PHP: PHPversion: '.phpversion().'<br>'."\n"; // 5.6.33-0+deb8u1
echo 'PHP: start: '.date("Y-m-d H:i:s.").gettimeofday()['usec'].'<br>'."\n";
$raw_data = file_get_contents('php://input');
echo 'PHP: RX RAW-DATA: '.gettype($raw_data).' --> '; // string
print_r($raw_data); // {"arg1": "tralala", "arg2": 123.45, "arg3": "unicode str ąśćęłóźć "}
echo "<br>"."\n";
$data = json_decode( $raw_data, true );
echo 'PHP: JSON DECODED: '.gettype($data).' --> '; // string
print_r( $data );
echo "<br>"."\n";
$cli_data = '';
if($data){
    foreach($data as $key => $value) {
        $cli_data .= '"'.$key.'='.$value.'" ';
    }
}
$python_dir_path = '/home/wiks/Dokumenty/projects/weather/python2';
$python_filename = 'php_fired.py';
$command = $python_dir_path.'/'.$python_filename.' '.$cli_data;
echo 'PHP: COMMAND-LINE for Python: '.$command."<br>"."\n";
$output_from_python = shell_exec($command);
echo 'PHP: RX from Python: <br>'."\n";
echo '--------<br>'."\n";
echo $output_from_python;
echo "\n".'<br>--------<br>'."\n";
echo 'PHP: stop: '.date("Y-m-d H:i:s.").gettimeofday()['usec'].'<br>'."\n";
echo 'PHP: tested by: http://blog.wiks.eu'."\n";
?>

kod (pierwszego) PHP/html:
PHP osadzony w kodzie HTML -nadaje się do odpalenia ze strony www. Sprawdziłem działanie na localhost i na zdalnym host -oba postawione na Apache2.

Pobieramy URL i dane do wysłania require 'url_and_data.php';, przedstawiamy się versją, zamieniamy array wejściową na JSON, wysyłamy – przy pomocy cURL /niże też bez cURL/, wyświetlamy to co odebrano. Voila:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test PHP fired Python</title>
</head>
<body>
<?php
require 'url_and_data.php';
echo 'PHP-TEST: PHPversion: '.phpversion().'<br>';
echo 'PHP-TEST: ARRAY TO SEND: ';
print_r($data);
echo '<br>';
$dataj = json_encode( $data );
echo 'PHP-TEST: TX JSON_ENCODE --> ';
print_r($dataj);
echo ' --> TYPE: '.gettype($dataj).'<br>'; // string

$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $dataj);
$result = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 200 ) {
    die("Error: call to URL $url failed with status $status, response $result, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
print 'PHP-TEST: RX-result: (with curl:)<br>';

print '------------<br>';
print($result);
print '<br>------------<br>';
print 'PHP-TEST: tested by: http://blog.wiks.eu';
?>
</body>
</html>

Pod require 'url_and_data.php' kryją się definicje URL i DATA do przesłania, np:

<?php 
$url = 'http://localhost/run_python.php'; 
$data = array('city_name' => 'Częstochowa',
              'lat' => '50.7651978', 
              'lon' => '19.1587636'
              );        

w powyższych danych przykładowo – przesyłam nazwę miejscowości i współrzędne geograficzne…

Można to oczywiście też wykonać bez cURL`a:

echo ' --> TYPE: '.gettype($dataj).'<br>'; // string

// use key 'http' even if you send the request to https://...
$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'method'  => 'POST',
        'content' => $dataj 
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { // Handle error  
}
print 'PHP-TEST: RX-result: (curl-less:)<br>';

wynik działania:

PHP-TEST: PHPversion: 5.6.33-0+deb8u1
PHP-TEST: ARRAY TO SEND: Array ( [city_name] => Częstochowa [lat] => 50.7651978 [lon] => 19.1587636 )
PHP-TEST: TX JSON_ENCODE --> {"city_name":"Cz\u0119stochowa","lat":"50.7651978","lon":"19.1587636"} --> TYPE: string
PHP-TEST: RX-result: (with curl:)
------------
PHP: PHPversion: 5.6.33-0+deb8u1
PHP: start: 2018-05-12 09:10:49.818623
PHP: RX RAW-DATA: string --> {"city_name":"Cz\u0119stochowa","lat":"50.7651978","lon":"19.1587636"}
PHP: JSON DECODED: array --> Array ( [city_name] => Częstochowa [lat] => 50.7651978 [lon] => 19.1587636 )
PHP: COMMAND-LINE for Python: /home/wiks/Dokumenty/projects/JS_PHP_Python/clue/python/php_fired.py "city_name=Częstochowa" "lat=50.7651978" "lon=19.1587636"
PHP: RX from Python:
--------
Python: start: 2018-05-12 09:10:49.836750
Python: Python-version: 2.7.9 (default, Aug 13 2016, 16:41:35) [GCC 4.9.2]
Python: RX-DATA:
{u'city_name': u'Cz\u0119stochowa', u'lat': u'50.7651978', u'lon': u'19.1587636'}
Python: stop: 2018-05-12 09:10:49.836967
Python: tested by: http://blog.wiks.eu
--------
PHP: stop: 2018-05-12 09:10:49.838728
PHP: tested by: http://blog.wiks.eu
------------
PHP-TEST: tested by: http://blog.wiks.eu

…a gdyby tak zrobić to z JavaScript?

Loading Disqus Comments ...
Loading Facebook Comments ...

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *