4

I am trying to convert this code snippet from PHP to Python (programming newbie) and am finding difficulty in doing so:

The PHP that I am trying to convert is as follows:

$fp = fsockopen($whmcsurl, 80, $errno, $errstr, 5); if ($fp) { $querystring = ""; foreach ($postfields AS $k=>$v) { $querystring .= "$k=".urlencode($v)."&"; } $header="POST ".$whmcsurl."modules/servers/licensing/verify.php HTTP/1.0\r\n"; $header.="Host: ".$whmcsurl."\r\n"; $header.="Content-type: application/x-www-form-urlencoded\r\n"; $header.="Content-length: ".@strlen($querystring)."\r\n"; $header.="Connection: close\r\n\r\n"; $header.=$querystring; $data=""; @stream_set_timeout($fp, 20); @fputs($fp, $header); $status = @socket_get_status($fp); while (!@feof($fp)&&$status) { $data .= @fgets($fp, 1024); $status = @socket_get_status($fp); } @fclose ($fp); } 

It corresponding Python code that I wrote is as follows:

fp = socket.socket(socket.AF_INET,socket.SOCK_STREAM) fp.connect(("my ip", 80)) if (fp): querystring = "" #print postfields for key in postfields: querystring = querystring+key+"="+urllib.quote(str(postfields[key]))+"&" header = "POST "+whmcsurl+"modules/servers/licensing/verify.php HTTP/1.0\r\n" header+="Content-type: application/x-www-form-urlencoded\r\n" header+="Content-length: "+str(len(querystring))+"\r\n" header+="Connection: close\r\n\r\n" #header+=querystring data="" request = urllib2.Request(whmcsurl,querystring,header) response = urllib2.urlopen(request) data = response.read() 

Here, I am faced with the following error:

request = urllib2.Request(whmcsurl,querystring,header) File "/usr/lib64/python2.6/urllib2.py", line 200, in __init__ for key, value in headers.items(): AttributeError: 'str' object has no attribute 'items' 

So I am guessing that Python is expecting a dictionary for the header. But the PHP sends it as a string.

May I know how to solve this issue?

Thanks in advance

2 Answers 2

7

You are overcomplicating things, by quite some distance. Python takes care of most of this for you. There is no need to open a socket yourself, nor do you need to build headers and the HTTP opening line.

Use the urllib.request and urllib.parse modules to do the work for you:

from urllib.parse import urlopen from urllib.request import urlopen params = urlencode(postfields) url = whmcsurl + 'modules/servers/licensing/verify.php' response = urlopen(url, params) data = response.read() 

urlopen() takes a second parameter, the data to be sent in a POST request; the library takes care of calculating the length of the body, and sets the appropriate headers. Most of all, under the hood it uses another library, httplib, to take care of the socket connection and producing valid headers and a HTTP request line.

The POST body is encoded using urllib.parse.urlencode(), which also takes care of proper quoting for you.

You may also want to look into the external requests library, which provides an easier-to-use API still:

import requests response = requests.post(whmcsurl + 'modules/servers/licensing/verify.php', params=params) data = response.content # or response.text for decoded content, or response.json(), etc. 
Sign up to request clarification or add additional context in comments.

2 Comments

So, in this case, I don't need to put write code for the header? Is that what is handled by params = urlencode(postfields)
The headers are handled entirely by urlopen(). Because you send a body (a second parameter) a POST is sent, and the content type and content length headers are set. The Host header is always set.
2

your headers should look like this

headers = { "Content-type" : "application/x-www-form-urlencoded" }; 

1 Comment

There is much more wrong here. The POST ... HTTP/1.0 line is not a header and does not need to be constructed in any case, for example.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.