How to recreate this PHP code in Python? - php

I've found a PHP script that lets me do what I asked in this SO question. I can use this just fine, but out of curiosity I'd like to recreate the following code in Python.
I can of course use urllib2 to get the page, but I'm at a loss on how to handle the cookies since mechanize (tested with Python 2.5 and 2.6 on Windows and Python 2.5 on Ubuntu...all with latest mechanize version) seems to break on the page. How do I do this in python?
require_once "HTTP/Request.php";
$req = &new HTTP_Request('https://steamcommunity.com');
$req->setMethod(HTTP_REQUEST_METHOD_POST);
$req->addPostData("action", "doLogin");
$req->addPostData("goto", "");
$req->addPostData("steamAccountName", ACC_NAME);
$req->addPostData("steamPassword", ACC_PASS);
echo "Login: ";
$res = $req->sendRequest();
if (PEAR::isError($res))
die($res->getMessage());
$cookies = $req->getResponseCookies();
if ( !$cookies )
die("fail\n");
echo "pass\n";
foreach($cookies as $cookie)
$req->addCookie($cookie['name'],$cookie['value']);

Similar to monkut's answer, but a little more concise.
import urllib, urllib2
def steam_login(username,password):
data = urllib.urlencode({
'action': 'doLogin',
'goto': '',
'steamAccountName': username,
'steamPassword': password,
})
request = urllib2.Request('https://steamcommunity.com/',data)
cookie_handler = urllib2.HTTPCookieProcessor()
opener = urllib2.build_opener(cookie_handler)
response = opener.open(request)
if not 200 <= response.code < 300:
raise Exception("HTTP error: %d %s" % (response.code,response.msg))
else:
return cookie_handler.cookiejar
It returns the cookie jar, which you can use in other requests. Just pass it to the HTTPCookieProcessor constructor.
monkut's answer installs a global HTTPCookieProcessor, which stores the cookies between requests. My solution does not modify the global state.

I'm not familiar with PHP, but this may get you started.
I'm installing the opener here which will apply it to the urlopen method. If you don't want to 'install' the opener(s) you can use the opener object directly. (opener.open(url, data)).
Refer to:
http://docs.python.org/library/urllib2.html?highlight=urllib2#urllib2.install_opener
import urlib2
import urllib
# 1 create handlers
cookieHandler = urllib2.HTTPCookieProcessor() # Needed for cookie handling
redirectionHandler = urllib2.HTTPRedirectHandler() # needed for redirection
# 2 apply the handler to an opener
opener = urllib2.build_opener(cookieHandler, redirectionHandler)
# 3. Install the openers
urllib2.install_opener(opener)
# prep post data
datalist_tuples = [ ('action', 'doLogin'),
('goto', ''),
('steamAccountName', ACC_NAME),
('steamPassword', ACC_PASS)
]
url = 'https://steamcommunity.com'
post_data = urllib.urlencode(datalist_tuples)
resp_f = urllib2.urlopen(url, post_data)

Related

PHP authentication code to python

I am trying to use python to login to my bittrex account and set up an automatic trading bot (written by myself in python).
However my problem is that I cannot authenticate myself. There is an API document provided by bittrex, but the code is in PHP (and i really dont know PHP)...
The main problem is that I am was not involved so far in the hmac hash authentication... so I am kinda lost here.
The PHP code provided by bittrex is the following:
$apikey='xxx';
$apisecret='xxx';
$nonce=time();
$uri='https://bittrex.com/api/v1.1/market/getopenorders?apikey='.$apikey.'&nonce='.$nonce;
$sign=hash_hmac('sha512',$uri,$apisecret);
$ch = curl_init($uri);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('apisign:'.$sign));
$execResult = curl_exec($ch);
$obj = json_decode($execResult);
I also tried to make up something based on other stackoverflow posts... but all I could come up was this:
import hashlib
import hmac
import requests
import time
apikey = 'xxx'
apisecret = 'xxx'
def request_comkort(url, payload ):
tosign = "&".join( [i + '=' + payload[i] for i in payload] )
sign = hmac.new( apisecret, tosign , hashlib.sha512);
headers = {'sign': str(sign.hexdigest()), 'nonce': str(int(time.time())), 'apikey': apikey }
r = requests.post(url, data=payload, headers=headers)
print tosign, '\n'
print sign, '\n'
print headers, '\n'
print url, '\n'
print payload, '\n'
print headers, '\n'
return r.text
print request_comkort("https://bittrex.com/api/v1.1/account/getbalances", {})
Unfortunately it doesn't really work..
I get error:
{"success":false,"message":"APIKEY_NOT_PROVIDED","result":null}
If someone could help me out or point me in the right direction, that would be awesome. I can hardly wait to run my trading bot...:)
Thank you in advance!
I was having the same problem and came up with this.
Unfortunally I have passes the key and nonce problem but having issues with secret key. Not very familiar with encryption. If you can help...
Here is the code. Notice I{m using python 2.7 on ubuntu. so requests and urllib may work diferent to your version
enter code here
import json
import time
import hashlib
import hmac
nonce = str('{:10.0f}'.format(time.time()))
apikey = 'mykey'
apisecret = 'mysecret'
url = 'https://api.bittrex.com/api/v1.1/account/getbalances?apikey=apikey'
url += '&nonce=' + str(int(time.time()))
sign = hmac.new(b'apisecret', b'url', hashlib.sha512).hexdigest()
headers = {'&secret': sign}
request = requests.get(url, sign)
balance = json.loads(urllib.urlopen(url).read())
print(balance)

file_get_contents() returns extra underscore on angular.callbacks

I built a PHP file with the sole purpose of hiding the API keys for Google Search, but part of the file_get_contents() always echo angular.callbacks._0_({ instead of angular.callbacks._0({
This small change makes the rest of the response worthless as Angular throws Uncaught TypeError: angular.callbacks._0_ is not a function. Although the workaround does works flawlessly, I would like to know if someone found the root of this issue or a better solution that is strictly PHP (no curl or any other package.)
search.php
<?php // Created by Deovandski on 2/14/2016
header('Content-type: application/json');
# Setup Base URL and array for Parameters
$host = 'https://www.googleapis.com/customsearch/v1?';
$queries = array();
$queries['cx'] = "XXX";// CSE KEY
$queries['key'] = "XXX"; // API KEY
# Setup possible incoming params
if (isset($_GET['search_term'])) $queries['q'] = $_GET['search_term'];
if (isset($_GET['result_count'])) $queries['result_count'] = $_GET['result_count'];
if (isset($_GET['callback'])) $queries['callback'] = $_GET['callback'];
# Build query and Final URL
$queriesURL = http_build_query($queries) . "\n";
$finalURL = $host.$queriesURL;
echo $finalURL;
/* echo $finalURL output (I only edited the keys out):
https://www.googleapis.com/customsearch/v1?cx=XXX&key=XXX&q=Hatsune+Miku&result_count=10&callback=angular.callbacks._0
*/
// Setup Response
$response = file_get_contents($finalURL);
// workaround
$fixedResponse = str_replace("angular.callbacks._0_", "angular.callbacks._0", $response);
echo $fixedResponse;
?>
This is part of a correct Google API response:
// API callback
angular.callbacks._0({
"kind": "customsearch#search",
"url": {
"type": "application/json",
"template": "https://www.googleapis.com/customsearch/v1?q={searchTerms}&num={count?}&start={startIndex?}&lr={language?}&safe={safe?}&cx={cx?}&cref={cref?}&sort={sort?}&filter={filter?}&gl={gl?}&cr={cr?}&googlehost={googleHost?}&c2coff={disableCnTwTranslation?}&hq={hq?}&hl={hl?}&siteSearch={siteSearch?}&siteSearchFilter={siteSearchFilter?}&exactTerms={exactTerms?}&excludeTerms={excludeTerms?}&linkSite={linkSite?}&orTerms={orTerms?}&relatedSite={relatedSite?}&dateRestrict={dateRestrict?}&lowRange={lowRange?}&highRange={highRange?}&searchType={searchType}&fileType={fileType?}&rights={rights?}&imgSize={imgSize?}&imgType={imgType?}&imgColorType={imgColorType?}&imgDominantColor={imgDominantColor?}&alt=json"
},
I put up a live version of this issue that can be seen on my FTP server. The PHP file can be viewed through this link (AngularJS parameters included on it).
The problem is the escape sequences \n. Which is passed as part of the request. And which is interpreted as space and as part of the callback function name and replaced by the side of the API to underline.
To understand just try this option and look at the result:
$queriesURL = http_build_query($queries) . "\n" . "after";
So just take away a newline.

Send json data to php api through python

I am new to python. I have created a gui based app to insert values into database.
I have created a Rest api to handle db operations. How can i append the api URL with json created in python.
app.py
from Tkinter import *
import tkMessageBox
import json
import requests
from urllib import urlopen
top = Tk()
L1 = Label(top, text="Title")
L1.pack( side = TOP)
E1 = Entry(top, bd =5)
E1.pack(side = TOP)
L2 = Label(top, text="Author")
L2.pack( side = TOP)
E2 = Entry(top, bd =5)
E2.pack(side = TOP)
L3 = Label(top, text="Body")
L3.pack( side = TOP)
E3 = Entry(top, bd =5)
E3.pack(side = TOP)
input = E2.get();
def callfunc():
data = {"author": E2.get(),
"body" : E3.get(),
"title" : E1.get()}
data_json = json.dumps(data)
# r = requests.get('http://localhost/spritle/api.php?action=get_uses')
#url = "http://localhost/spritle/api.php?action=insert_list&data_json="
#
url = urlopen("http://localhost/spritle/api.php?action=insert_list&data_json="%data_json).read()
tkMessageBox.showinfo("Result",data_json)
SubmitButton = Button(text="Submit", fg="White", bg="#0094FF",
font=("Grobold", 10), command = callfunc)
SubmitButton.pack()
top.mainloop()
Error:
TypeError: not all arguments converted during string formatting
i AM GETTING error while appending url with data_json ?
There is an error on string formating:
Swap this:
"http://localhost/spritle/api.php?action=insert_list&data_json="%data_json
by this:
"http://localhost/spritle/api.php?action=insert_list&data_json=" + data_json
or:
"http://localhost/spritle/api.php?action=insert_list&data_json={}".format(data_json)
The following statements are equivalents:
"Python with " + "PHP"
"Python with %s" % "PHP"
"Python with {}".format("PHP")
"Python with {lang}".format(lang="PHP")
Also, I don't think sending JSON data like this via URL is a good idea. You should encode the data at least.
You are trying to use % operator to format the string, and you need to put the %s placeholder into the string:
"http://localhost/spritle/api.php?action=insert_list&data_json=%s" % data_json
Or use other methods suggested in another answer.
Regarding the data transfer - you definitely need to use POST request and not GET.
Check this, using urllib2 and this, using requests.

Uploading file via an API call [duplicate]

I want to do an HTTP POST that looks like an HMTL form posted from a browser. Specifically, post some text fields and a file field.
Posting text fields is straightforward, there's an example right there in the net/http rdocs, but I can't figure out how to post a file along with it.
Net::HTTP doesn't look like the best idea. curb is looking good.
I like RestClient. It encapsulates net/http with cool features like multipart form data:
require 'rest_client'
RestClient.post('http://localhost:3000/foo',
:name_of_file_param => File.new('/path/to/file'))
It also supports streaming.
gem install rest-client will get you started.
Another one using only standard libraries:
uri = URI('https://some.end.point/some/path')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'If you need some headers'
form_data = [['photos', photo.tempfile]] # or File.open() in case of local file
request.set_form form_data, 'multipart/form-data'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| # pay attention to use_ssl if you need it
http.request(request)
end
Tried a lot of approaches but only this was worked for me.
I can't say enough good things about Nick Sieger's multipart-post library.
It adds support for multipart posting directly to Net::HTTP, removing your need to manually worry about boundaries or big libraries that may have different goals than your own.
Here is a little example on how to use it from the README:
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
File.open("./image.jpg") do |jpg|
req = Net::HTTP::Post::Multipart.new url.path,
"file" => UploadIO.new(jpg, "image/jpeg", "image.jpg")
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
end
You can check out the library here:
http://github.com/nicksieger/multipart-post
or install it with:
$ sudo gem install multipart-post
If you're connecting via SSL you need to start the connection like this:
n = Net::HTTP.new(url.host, url.port)
n.use_ssl = true
# for debugging dev server
#n.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = n.start do |http|
curb looks like a great solution, but in case it doesn't meet your needs, you can do it with Net::HTTP. A multipart form post is just a carefully-formatted string with some extra headers. It seems like every Ruby programmer who needs to do multipart posts ends up writing their own little library for it, which makes me wonder why this functionality isn't built-in. Maybe it is... Anyway, for your reading pleasure, I'll go ahead and give my solution here. This code is based off of examples I found on a couple of blogs, but I regret that I can't find the links anymore. So I guess I just have to take all the credit for myself...
The module I wrote for this contains one public class, for generating the form data and headers out of a hash of String and File objects. So for example, if you wanted to post a form with a string parameter named "title" and a file parameter named "document", you would do the following:
#prepare the query
data, headers = Multipart::Post.prepare_query("title" => my_string, "document" => my_file)
Then you just do a normal POST with Net::HTTP:
http = Net::HTTP.new(upload_uri.host, upload_uri.port)
res = http.start {|con| con.post(upload_uri.path, data, headers) }
Or however else you want to do the POST. The point is that Multipart returns the data and headers that you need to send. And that's it! Simple, right? Here's the code for the Multipart module (you need the mime-types gem):
# Takes a hash of string and file parameters and returns a string of text
# formatted to be sent as a multipart form post.
#
# Author:: Cody Brimhall <mailto:brimhall#somuchwit.com>
# Created:: 22 Feb 2008
# License:: Distributed under the terms of the WTFPL (http://www.wtfpl.net/txt/copying/)
require 'rubygems'
require 'mime/types'
require 'cgi'
module Multipart
VERSION = "1.0.0"
# Formats a given hash as a multipart form post
# If a hash value responds to :string or :read messages, then it is
# interpreted as a file and processed accordingly; otherwise, it is assumed
# to be a string
class Post
# We have to pretend we're a web browser...
USERAGENT = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6"
BOUNDARY = "0123456789ABLEWASIEREISAWELBA9876543210"
CONTENT_TYPE = "multipart/form-data; boundary=#{ BOUNDARY }"
HEADER = { "Content-Type" => CONTENT_TYPE, "User-Agent" => USERAGENT }
def self.prepare_query(params)
fp = []
params.each do |k, v|
# Are we trying to make a file parameter?
if v.respond_to?(:path) and v.respond_to?(:read) then
fp.push(FileParam.new(k, v.path, v.read))
# We must be trying to make a regular parameter
else
fp.push(StringParam.new(k, v))
end
end
# Assemble the request body using the special multipart format
query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
return query, HEADER
end
end
private
# Formats a basic string key/value pair for inclusion with a multipart post
class StringParam
attr_accessor :k, :v
def initialize(k, v)
#k = k
#v = v
end
def to_multipart
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"\r\n\r\n#{v}\r\n"
end
end
# Formats the contents of a file or string for inclusion with a multipart
# form post
class FileParam
attr_accessor :k, :filename, :content
def initialize(k, filename, content)
#k = k
#filename = filename
#content = content
end
def to_multipart
# If we can tell the possible mime-type from the filename, use the
# first in the list; otherwise, use "application/octet-stream"
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"; filename=\"#{ filename }\"\r\n" +
"Content-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n"
end
end
end
Here is my solution after trying other ones available on this post, I'm using it to upload photo on TwitPic:
def upload(photo)
`curl -F media=##{photo.path} -F username=#{#username} -F password=#{#password} -F message='#{photo.title}' http://twitpic.com/api/uploadAndPost`
end
Fast forward to 2017, ruby stdlib net/http has this built-in since 1.9.3
Net::HTTPRequest#set_form): Added to support both application/x-www-form-urlencoded and multipart/form-data.
https://ruby-doc.org/stdlib-2.3.1/libdoc/net/http/rdoc/Net/HTTPHeader.html#method-i-set_form
We can even use IO which does not support :size to stream the form data.
Hoping that this answer can really help someone :)
P.S. I only tested this in ruby 2.3.1
Ok, here's a simple example using curb.
require 'yaml'
require 'curb'
# prepare post data
post_data = fields_hash.map { |k, v| Curl::PostField.content(k, v.to_s) }
post_data << Curl::PostField.file('file', '/path/to/file'),
# post
c = Curl::Easy.new('http://localhost:3000/foo')
c.multipart_form_post = true
c.http_post(post_data)
# print response
y [c.response_code, c.body_str]
restclient did not work for me until I overrode create_file_field in RestClient::Payload::Multipart.
It was creating a 'Content-Disposition: multipart/form-data' in each part where it should be ‘Content-Disposition: form-data’.
http://www.ietf.org/rfc/rfc2388.txt
My fork is here if you need it: git#github.com:kcrawford/rest-client.git
Well the solution with NetHttp has a drawback that is when posting big files it loads the whole file into memory first.
After playing a bit with it I came up with the following solution:
class Multipart
def initialize( file_names )
#file_names = file_names
end
def post( to_url )
boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
parts = []
streams = []
#file_names.each do |param_name, filepath|
pos = filepath.rindex('/')
filename = filepath[pos + 1, filepath.length - pos]
parts << StringPart.new ( "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + param_name.to_s + "\"; filename=\"" + filename + "\"\r\n" +
"Content-Type: video/x-msvideo\r\n\r\n")
stream = File.open(filepath, "rb")
streams << stream
parts << StreamPart.new (stream, File.size(filepath))
end
parts << StringPart.new ( "\r\n--" + boundary + "--\r\n" )
post_stream = MultipartStream.new( parts )
url = URI.parse( to_url )
req = Net::HTTP::Post.new(url.path)
req.content_length = post_stream.size
req.content_type = 'multipart/form-data; boundary=' + boundary
req.body_stream = post_stream
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
streams.each do |stream|
stream.close();
end
res
end
end
class StreamPart
def initialize( stream, size )
#stream, #size = stream, size
end
def size
#size
end
def read ( offset, how_much )
#stream.read ( how_much )
end
end
class StringPart
def initialize ( str )
#str = str
end
def size
#str.length
end
def read ( offset, how_much )
#str[offset, how_much]
end
end
class MultipartStream
def initialize( parts )
#parts = parts
#part_no = 0;
#part_offset = 0;
end
def size
total = 0
#parts.each do |part|
total += part.size
end
total
end
def read ( how_much )
if #part_no >= #parts.size
return nil;
end
how_much_current_part = #parts[#part_no].size - #part_offset
how_much_current_part = if how_much_current_part > how_much
how_much
else
how_much_current_part
end
how_much_next_part = how_much - how_much_current_part
current_part = #parts[#part_no].read(#part_offset, how_much_current_part )
if how_much_next_part > 0
#part_no += 1
#part_offset = 0
next_part = read ( how_much_next_part )
current_part + if next_part
next_part
else
''
end
else
#part_offset += how_much_current_part
current_part
end
end
end
there's also nick sieger's multipart-post to add to the long list of possible solutions.
I had the same problem (need to post to jboss web server). Curb works fine for me, except that it caused ruby to crash (ruby 1.8.7 on ubuntu 8.10) when I use session variables in the code.
I dig into the rest-client docs, could not find indication of multipart support. I tried the rest-client examples above but jboss said the http post is not multipart.
The multipart-post gem works pretty well with Rails 4 Net::HTTP, no other special gem
def model_params
require_params = params.require(:model).permit(:param_one, :param_two, :param_three, :avatar)
require_params[:avatar] = model_params[:avatar].present? ? UploadIO.new(model_params[:avatar].tempfile, model_params[:avatar].content_type, model_params[:avatar].original_filename) : nil
require_params
end
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
Net::HTTP.start(url.host, url.port) do |http|
req = Net::HTTP::Post::Multipart.new(url, model_params)
key = "authorization_key"
req.add_field("Authorization", key) #add to Headers
http.use_ssl = (url.scheme == "https")
http.request(req)
end
https://github.com/Feuda/multipart-post/tree/patch-1
Using http.rb gem:
HTTP.post("https://here-you-go.com/upload",
form: {
file: HTTP::FormData::File.new(file_path)
})
Details
Haha, seems like doing this without a gem is a well guarded secret.
I used HTTParty gem:
HTTParty.post(
'http://localhost:3000/user',
body: {
name: 'Foo Bar',
email: 'example#email.com',
avatar: File.open('/full/path/to/avatar.jpg')
}
)
https://github.com/jnunemaker/httparty/blob/master/examples/multipart.rb
https://github.com/jnunemaker/httparty
gem install httparty

Webrequest faster downloading (Googled for days)

Im working on a project that downloads up to 5000 individual pieces of data from a server. It basically is a PHP page that takes POST variable, gets the data from the DB and sends it back to the .NET client.
It is slow. It takes about 1 second per request. I've googled a lot and tried all sorts of tweaks to the code, like the famous proxy-setting etc. But nothing speeds it up.
Any idea's? All solutions that make this super fast are welcome. Even C-written DLL's or anything you can think of. This just needs to be a lot faster.
Public Function askServer(oCode As String) As String
oBytesToSend = Encoding.ASCII.GetBytes("cmd=" & System.Web.HttpUtility.UrlEncode(oCode))
Try
oRequest = WebRequest.Create(webServiceUrl)
oRequest.Timeout = 60000
oRequest.Proxy = WebRequest.DefaultWebProxy
CType(oRequest, HttpWebRequest).UserAgent = "XXXXX"
oRequest.Method = "POST"
oRequest.ContentLength = oBytesToSend.Length
oRequest.ContentType = "application/x-www-form-urlencoded"
oStream = oRequest.GetRequestStream()
oStream.Write(oBytesToSend, 0, oBytesToSend.Length)
oResponse = oRequest.GetResponse()
If CType(oResponse, HttpWebResponse).StatusCode = Net.HttpStatusCode.OK Then
oStream = oResponse.GetResponseStream()
oReader = New StreamReader(oStream)
oResponseFromServer = oReader.ReadToEnd()
oResponseFromServer = System.Web.HttpUtility.UrlDecode(oResponseFromServer)
Return oResponseFromServer
Else
MsgBox("Server error", CType(vbOKOnly + vbCritical, MsgBoxStyle), "")
Return ""
End If
Catch e As Exception
MsgBox("Oops" & vbCrLf & e.Message, CType(vbOKOnly + vbCritical, MsgBoxStyle), "")
Return ""
End Try
End Function
Some ideas :
Run the http requests in parallel. (Client)
If the data response size allows it get all data needed in one request (you need change your server implementation).
Caching data. (Server)

Categories