I want to convert my php code to python code.
$u = 'http://httpbin.org/post'; $req = array( 'check' => 'command', 'parameters' => array( 0 => array('parameter' => '1', 'description' => '2'), 1 => array('parameter' => '3', 'description' => '4') ) ); $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $u); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($req)); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); $response = curl_exec($curl); php test.php { "args": {}, "data": "", "files": {}, "form": { "check": "command", "parameters[0][parameter]": "1", "parameters[0][description]": "2", "parameters[1][parameter]": "3", "parameters[1][description]": "4" },
this code successfully fetching data from remote api, but when i try to write it with Python requests – array of parameters is sending with wrong data.
url = 'http://httpbin.org/post' req = {'check': 'command', 'parameters': ({'parameter': '1', 'description': '2'}, {'parameter': '3', 'description': '4'})} try: fetch = requests.post(url, data = req) except requests.exceptions.RequestException as e: print(e) print(fetch.text) python3 test.py { "args": {}, "data": "", "files": {}, "form": { "check": "command", "parameters": [ "parameter", "description", "parameter", "description" ] },
“Parameters”, sended by my Python script is invalid
Advertisement
Answer
PHPs http_build_query
and it’s corresponding $_GET
and $_POST
parsing are completely arbitrary in how they work. Thus you must implement this functionality yourself.
Let’s compare the outputs of PHPs http_build_query
to pythons urlencode
(which requests uses internally to build the parameters)
PHP
$req = array( 'check' => 'command', 'parameters' => array( 0 => array('parameter' => '1', 'description' => '2'), 1 => array('parameter' => '3', 'description' => '4') ) ); $query = http_build_query($req); $query_parsed = urldecode($query); echo $query; echo $query_parsed;
Result:
check=command¶meters%5B0%5D%5Bparameter%5D=1¶meters%5B0%5D%5Bdescription%5D=2¶meters%5B1%5D%5Bparameter%5D=3¶meters%5B1%5D%5Bdescription%5D=4 check=command¶meters[0][parameter]=1¶meters[0][description]=2¶meters[1][parameter]=3¶meters[1][description]=4
Python
from urllib.parse import urlencode, unquote req = {'check': 'command', 'parameters': ({'parameter': '1', 'description': '2'}, {'parameter': '3', 'description': '4'})} query = urlencode(req) query_parsed = unquote(query) print(query) print(query_parsed)
Result:
check=command¶meters=%28%7B%27parameter%27%3A+%271%27%2C+%27description%27%3A+%272%27%7D%2C+%7B%27parameter%27%3A+%273%27%2C+%27description%27%3A+%274%27%7D%29 check=command¶meters=({'parameter':+'1',+'description':+'2'},+{'parameter':+'3',+'description':+'4'})
This looks quite a bit different but apparently conforms to the standard and thus httpbin interprets this correctly.
To make python behave the same as PHP, I’ve adapted this answer to create the following:
from collections.abc import MutableMapping from urllib.parse import urlencode, unquote def flatten(dictionary, parent_key=False, separator='.', separator_suffix=''): """ Turn a nested dictionary into a flattened dictionary :param dictionary: The dictionary to flatten :param parent_key: The string to prepend to dictionary's keys :param separator: The string used to separate flattened keys :return: A flattened dictionary """ items = [] for key, value in dictionary.items(): new_key = str(parent_key) + separator + key + separator_suffix if parent_key else key if isinstance(value, MutableMapping): items.extend(flatten(value, new_key, separator, separator_suffix).items()) elif isinstance(value, list) or isinstance(value, tuple): for k, v in enumerate(value): items.extend(flatten({str(k): v}, new_key, separator, separator_suffix).items()) else: items.append((new_key, value)) return dict(items) req = {'check': 'command', 'parameters': ({'parameter': '1', 'description': '2'}, {'parameter': '3', 'description': '4'})} req = flatten(req, False, '[', ']') query = urlencode(req) query_parsed = unquote(query) print(query) print(query_parsed)
Which outputs
check=command¶meters%5B0%5D%5Bparameter%5D=1¶meters%5B0%5D%5Bdescription%5D=2¶meters%5B1%5D%5Bparameter%5D=3¶meters%5B1%5D%5Bdescription%5D=4 check=command¶meters[0][parameter]=1¶meters[0][description]=2¶meters[1][parameter]=3¶meters[1][description]=4
which seems to be what you want.
Now you should be able to pass the result of flatten
as data
to get the desired behaviour.