4

This is my code so far

    $dataraw = $_SESSION['image'];
    $datagambar = json_encode($dataraw);

    echo '<pre>';
    print_r($dataraw);
    echo '</pre>';

    print($escaped_json);

    $type1 = gettype($dataraw);
    print($type1);

    $type2 = gettype($datagambar);
    print($type2);

This is $dataraw output, the type is array

Array
(
    [0] => Array
        (
            [FileName] => 20221227_202035.jpg
            [Model] => SM-A528B
            [Longitude] => 106.904251
            [Latitude] => -6.167665
        )

    [1] => Array
        (
            [FileName] => 20221227_202157.jpg
            [Model] => SM-A528B
            [Longitude] => 106.9042428
            [Latitude] => -6.1676580997222
        )

)

This is $datagambar output, the type is string

[{"FileName":"20221227_202035.jpg","Model":"SM-A528B","Longitude":106.904251,"Latitude":-6.167665},{"FileName":"20221227_202157.jpg","Model":"SM-A528B","Longitude":106.9042428,"Latitude":-6.167658099722223}]

Pass to python

echo shell_exec("D:\Anaconda\python.exe D:/xampp/htdocs/Klasifikasi_KNN/admin/test.py $datagambar");

This is my python test.py

import sys, json
import os
import pymysql
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import mplcursors as mpl
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score,hamming_loss,classification_report

json_list = []
escaped_json1 = sys.argv[1]

# this is working but its only a string of array json
# print(escaped_json1) 
# this is working but its only a string of array json

json_list.append(json.loads(escaped_json1))
parsed_data = json.loads(escaped_json1) 
print(json_list)
print(parsed_data)

When i do print(escaped_json1) it display a string of array json from php($datagambar).

python output:

Hello world has been called [{"FileName":"20221227_202035.jpg","Model":"SM-A528B","Longitude":106.904251,"Latitude":-6.167665},{"FileName":"20221227_202157.jpg","Model":"SM-A528B","Longitude":106.9042428,"Latitude":-6.167658099722223}]

I use apache as my server with phpmyadmin and anaconda.

T tried using print(type(escapedjson1)) or print(type(escapedjson1)) but it doesn't display the type

json.loads didn't change the type of data to python array

How to loads it and make the string array into a variable array so i can call it and convert it to dataframe?.

5
  • 1
    Maybe the shell is not interpreting the value of the $datagambar variable as a single argument, which is why you can see some output when you print it, but fails to parse as it may not be valid JSON, you can try wrapping the variable in single quotes: echo shell_exec("D:\Anaconda\python.exe D:/xampp/htdocs/Klasifikasi_KNN/admin/test.py '$datagambar'"); Commented Jan 10, 2023 at 16:51
  • Nope, escaping arguments doesn't work by simply wrapping them into single quotes, @RJK. You must do it properly, otherwise you risk code injection. Actually, I'd prefer an interface like pcntl_exec(), where you don't put a shell in the middle, but that function is POSIX-only, I'm afraid. Commented Jan 10, 2023 at 20:53
  • Can you share the output of print(type(escaped_json1)) Commented Jan 11, 2023 at 11:20
  • @executable it didn't print out anything Commented Jan 12, 2023 at 4:59
  • 1
    You should just use a temporary file to transmit your data. Commented Jan 13, 2023 at 19:53

2 Answers 2

5
+50

Update: A Completely different approach

There is a difficulty with the PHP script JSON-encoding a structure to produce a JSON string and then passing it as a command line argument since the string needs to be placed in double quotes because there can be embedded spaces in the encoded string. But the string itself can contain double quotes as start of string characters and within such a string. Confused? Who wouldn't be?

There is no problem however with writing such a string to a file and having the Python program read it in and decode it. But we don't want to have to deal with temporary files. So the solution is to pipe the data to the Python program where it can then be read in as stdin

Let's assume your array looks like:

$arr =
[
    [
        "FileName" => "\"\\  \nRon's20221227_202035.jpg",
        "Model" => "27_202035.jpg",
        "Longitude" => 106.90425,
        "Latitude" => 106.90425
    ],
    [
        "FileName" => "20221227_202157.jpg",
        "Model" => "SM-A528B",
        "Longitude" => 106.9042428,
        "Latitude" => -6.1676580997222
    ]
];

Note that I have modified your example slightly so that the first FileName field contains a " character, a ' character, an escape sequence \n representing the newline character and finally some spaces. Although your example does not contain these characters or some other escape sequence, I would like to be able to handle such a condition should it arise. This solution should work with such input.

PHP File

<?php
$arr =
[
    [
        "FileName" => "\"\\  \nRon's20221227_202035.jpg",
        "Model" => "27_202035.jpg",
        "Longitude" => 106.90425,
        "Latitude" => 106.90425
    ],
    [
        "FileName" => "20221227_202157.jpg",
        "Model" => "SM-A528B",
        "Longitude" => 106.9042428,
        "Latitude" => -6.1676580997222
    ]
];

// Encode string as JSON:
$json = json_encode($arr);

// Pipe the JSON string to the Python process's stdin and
// read the result from its stdout:
$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
);
$options = array('bypass_shell' => True); // Only has effect on Windows
//$process = proc_open("python3 test.py", $descriptorspec, $pipes, null, null, $options);
// For your actual environment:
$process = proc_open("D:/Anaconda/python.exe D:/xampp/htdocs/Klasifikasi_KNN/admin/test.py", $descriptorspec, $pipes, null, null, $options);

// Pipe the input for the Python program and close the pipe:
fwrite($pipes[0], $json);
fclose($pipes[0]);

// Read the result from the Python program and close its pipe
$result = stream_get_contents($pipes[1]);
fclose($pipes[1]);

# Now that we have closed the pipes, we can close the process:
$return_code = proc_close($process);

echo "Result from stdin:\n$result\n";

test.py

import json
import sys

DEBUG = True # for debugging purposes

if DEBUG:
    import os

    for k, v in sorted(os.environ.items()):
        print(k, '->', v, file=sys.stderr)
else:
    import numpy as np
    import pandas as pd

# Load from stdin:
arr = json.load(sys.stdin)
# print each dictionary of the array:
for d in arr:
    print(d)

Prints:

{'FileName': '"\\  \nRon\'s20221227_202035.jpg', 'Model': '27_202035.jpg', 'Longitude': 106.90425, 'Latitude': 106.90425}
{'FileName': '20221227_202157.jpg', 'Model': 'SM-A528B', 'Longitude': 106.9042428, 'Latitude': -6.1676580997222}
Sign up to request clarification or add additional context in comments.

20 Comments

Thankyou for replying this.. im still studying your answer, are you making a format that can works with json.loads? does my array can be change into like yours?
See my Python file above; it does a json.loads() against the passed argument to the program. The program first prints out the passed argument, which is a string, then it prints the result of running json.loads() against that string, which is a Python list and finally the code prints each element of the list, which is a Python dictionary. Each of these three print operations is separated by a dashed line (see above output).
"can be simplified by double-encoding the array" You shouldn't use json_encode() on the string to escape it. It happens to work but it's just an accident. It's not meant for that.
@Olivier See the updated code; it's a completely different and more robust approach (in my opinion, anyway).
A file approach is definitely much better (personally I would just use a temp file). Did you see the note on the proc_open page regarding the bypass_shell option? It looks safer to use it.
|
3

You just need to enclose in single quotes the argument to python:

shell_exec("python3 test.py '$json'");

Example

file.php

$data =
[
    [
        "FileName" => "20221227_202035.jpg",
        "Model" => "27_202035.jpg",
        "Longitude" => 106.90425,
        "Latitude" => 106.90425
    ],
    [
        "FileName" => "20221227_202157.jpg",
        "Model" => "SM-A528B",
        "Longitude" => 106.9042428,
        "Latitude" => -6.1676580997222
    ]
];

$json = json_encode($data);

// note: arg '$json' is single-quoted
echo shell_exec("python3 test.py '$json'");

test.py

import sys
import json
from pandas import json_normalize

data = sys.argv[1]

dict = json.loads(data)
df2 = json_normalize(dict) 

print(df2)

Output

              FileName     Model   Longitude  Latitude
0  20221227_202035.jpg  SM-A528B  106.904251 -6.167665
1  20221227_202157.jpg  SM-A528B  106.904243 -6.167658

See: Escaping double qoutes when sending JSON as argument in python program

11 Comments

Thankyou calo for answering. it didn't run the python file if i import from pandas.io.json import json_normalize
In file.php your $json variable is a string and not an array as in the actual input the OP needs to process.
@Booboo yes its a string of json array because shell exec from php cannot explicitly pass array to python. If i pass the $dataraw itself and not encode it first to $datagambar i get Warning: Array to string conversion
@calogero Your output is what im looking for... im running my php with apache server phpMyAdmin. When i try to import pandas only without using it or do anything else php is not executing the python file using shell_exec..
"You just need to enclose in single quotes" Did you test it on Windows? And what happens if the JSON string contains single quotes?
|

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.