Unable to make POST request with files to another php website - php

Recently I have migrate my application from python2/pylons to python3/pyramid.
In my plyons app, I was using below code to make POST request to third party php website (also maintained by me).
register_openers()
datagen, headers = multipart_encode({
"biosamples_metadata": open(file_bs_md, "rb"),
"metastore": open(file_ds_md, "rb"),
"annotation-submit": "Validate Annotation Files"
})
# Create the Request object
url = config['php_website_url']
request = urllib.request.Request(url, datagen, headers)
# Actually do the request, and get the response
return_text = urllib.request.urlopen(request).read()
return return_text
This above code worked perfectly fine. However on python3, poster is not supported and I cannot use register_openers() which I don't even know do what.
In python3, I am using requests module.
import requests
from requests_toolbelt import MultipartEncoder
url = config['php_website_url']
m = MultipartEncoder(
fields={'biosamples_metadata': open(file_bs_md, 'rb'),
"metastore":open(file_ds_md, "rb"),
"annotation-submit": "Validate Annotation Files"
}
)
request = requests.post(url, data=m)
return_text = request.text
However, this code does not work properly. It goes to php app and executes the part of the code that is supposed to be executed when you do get request.
Here is what php code look like
public function handle_request () {
$TEMPLATE = 'content_main';
// Process POST
if ($this->isPOST()) {
$this->_annotationFiles = array();
return $this->error_span('This is Get');
}
else ($this->isGET()) {
$this->_annotationFiles = array();
return $this->error_span('This is Post')
}
Any help appreciated

I am not sure about your PHP code, but the below is the correct way to post files & data to a remote url with Python 3 and requests:
import requests
post_addr = "https://example.com/post_url"
data = {
'foo': 'bar',
'foo_a': 'bar_a':
}
files = {'file': open('report.xls', 'rb')}
r = requests.post(post_addr, data=data, files=files)

Related

How to send this PUT-request to prestashop?

I am working with Prestashop web service. I am trying to send a PUT (update) request to the API but with no luck. My request seems to be set up in the 'wrong' way (i.e. not in the way the server expects) Since Prestashop is open-source I took a look at the source code, specifically when it recieves a PUT request it does the following (I don't write php-code):
$input_xml = null;
// if a XML is in PUT or in POST
if (($_SERVER['REQUEST_METHOD'] == 'PUT') || ($_SERVER['REQUEST_METHOD'] == 'POST')) {
$putresource = fopen("php://input", "r");
while ($putData = fread($putresource, 1024)) {
$input_xml .= $putData;
}
fclose($putresource);
}
if (isset($input_xml) && strncmp($input_xml, 'xml=', 4) == 0) {
$input_xml = substr($input_xml, 4);
}
From the code above I understood that my data should look something like this: xml=<data><here></here></data> but I don't know where to put this, should it be in the request-body or embedded in the url? is the "xml=" implicit when you send a request with Content-Type = text/xml? I did try different combinations of the request and still getting the same 404 error. I tried this:
let updateOrderState (orderId:int64) (stateId:int64) (credentials:AuthInfo) =
// url looks like this: http://www.webstoreexample.com/entity/id
let auth = BasicAuth credentials.Key ""
let orderApi = credentials.Api + "/orders/" + orderId.ToString();
let orderAsXml = Http.RequestString(orderApi, httpMethod = "GET", headers = [auth])
let xml = Order.Parse(orderAsXml).XElement // at this point, I have the data
xml.Element(XName.Get("order")).Element(XName.Get("current_state")).SetValue(stateId) // field 'current_state' gets modified
let xmlData = xml.ToString()
// HERE the put request
Http.RequestString(url = credentials.Api + "/orders",
headers = [ auth;
"Content-Type","text/xml" ],
httpMethod= HttpMethod.Put,
body= HttpRequestBody.TextRequest(xmlData))
Variations on the PUT-request didn't work as well, here I changed the request body from TextRequest into FormValues:
Http.RequestString(url = credentials.Api + "/orders",
headers = [ auth;
"Content-Type","text/xml" ],
httpMethod= HttpMethod.Put,
body= HttpRequestBody.FormValues ["xml", xmlData]) // xml=xmlData
Another thing I tried is adding the id to the url (even tho in the docs they say that this is not required):
Http.RequestString(url = credentials.Api + "/order/" + orderId.ToString(), // added the id to the url
headers = [ auth;
"Content-Type","text/xml" ],
httpMethod= HttpMethod.Put,
body= HttpRequestBody.FormValues ["xml", xmlData]) // xml=xmlData
Specifically, I am tring to the update the value of the current_state node of an order. Getting the data and modifying it works as expected but sending the modified data doesn't seem to work and I still recieve the 404: Not found error
Any Help on this would be greatly apprecited!
Okay, I just tested it with library and example that I give in comments, also I repetead same requests using CURL with same positive results, so there is nothing PHP language specific.
I think you need just repeat same Headers/Body in your application.
HTTP REQUEST HEADER
PUT /16011/api/orders/8 HTTP/1.1
Authorization: Basic TlpCUEJKTkhaWFpFMzlCMVBDTkdTM1JQN0s2NTVVQ0Y6
Host: localhost
Accept: */*
Content-Length: 2411
Content-Type: application/x-www-form-urlencoded
XML SENT
<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<order>
<id>8</id>
<id_address_delivery xlink:href="http://localhost/16011/api/addresses/5">5</id_address_delivery>
<id_address_invoice xlink:href="http://localhost/16011/api/addresses/5">5</id_address_invoice>
<id_cart xlink:href="http://localhost/16011/api/carts/8">8</id_cart>
<id_currency xlink:href="http://localhost/16011/api/currencies/1">1</id_currency>
<id_lang xlink:href="http://localhost/16011/api/languages/1">1</id_lang>
<id_customer xlink:href="http://localhost/16011/api/customers/2">2</id_customer>
<id_carrier xlink:href="http://localhost/16011/api/carriers/3">3</id_carrier>
<current_state xlink:href="http://localhost/16011/api/order_states/2" notFilterable="true">10</current_state>
<module>bankwire</module>
<invoice_number>0</invoice_number>
<invoice_date>0000-00-00 00:00:00</invoice_date>
<delivery_number>0</delivery_number>
<delivery_date>0000-00-00 00:00:00</delivery_date>
<valid>0</valid>
<date_add>2015-09-17 08:29:17</date_add>
<date_upd>2015-10-20 03:45:13</date_upd>
<shipping_number notFilterable="true"></shipping_number>
<id_shop_group>1</id_shop_group>
<id_shop>1</id_shop>
<secure_key>45838497c9182b0d361473894092de02</secure_key>
<payment>Bank wire</payment>
<recyclable>0</recyclable>
<gift>0</gift>
<gift_message></gift_message>
<mobile_theme>0</mobile_theme>
<total_discounts>0.000000</total_discounts>
<total_discounts_tax_incl>0.000000</total_discounts_tax_incl>
<total_discounts_tax_excl>0.000000</total_discounts_tax_excl>
<total_paid>24.450000</total_paid>
<total_paid_tax_incl>24.450000</total_paid_tax_incl>
<total_paid_tax_excl>23.510000</total_paid_tax_excl>
<total_paid_real>0.000000</total_paid_real>
<total_products>16.510000</total_products>
<total_products_wt>17.170000</total_products_wt>
<total_shipping>7.280000</total_shipping>
<total_shipping_tax_incl>7.280000</total_shipping_tax_incl>
<total_shipping_tax_excl>7.000000</total_shipping_tax_excl>
<carrier_tax_rate>4.000</carrier_tax_rate>
<total_wrapping>0.000000</total_wrapping>
<total_wrapping_tax_incl>0.000000</total_wrapping_tax_incl>
<total_wrapping_tax_excl>0.000000</total_wrapping_tax_excl>
<round_mode>2</round_mode>
<conversion_rate>1.000000</conversion_rate>
<reference>ECHCBFWGR</reference>
<associations></associations>
</order>
</prestashop>

PHP get data from DELETE request

I am using jquery plugin for multiple file upload. Everything is working fine, except delete the images. Firebug say that JS it is sending DELETE request to the function. How can I get data from delete request?
PHP delete code:
public function deleteImage() {
//Get the name in the url
$file = $this->uri->segment(3);
$r = $this->session->userdata('id_user');
$q=$this->caffe_model->caffe_get_one_user($r);
$cff_name= $q->name;
$cff_id = $q->id_caffe;
$w = $this->gallery_model->gallery_get_one_user($gll_id);
$gll_name = $w->name;
$success = unlink("./public/img/caffe/$cff_name/$gll_name/" . $file);
$success_th = unlink("./public/img/caffe/$cff_name/$gll_name/thumbnails/" . $file);
//info to see if it is doing what it is supposed to
$info = new stdClass();
$info->sucess = $success;
$info->path = $this->getPath_url_img_upload_folder() . $file;
$info->file = is_file($this->getPath_img_upload_folder() . $file);
if (IS_AJAX) {//I don't think it matters if this is set but good for error checking in the console/firebug
echo json_encode(array($info));
} else { //here you will need to decide what you want to show for a successful delete
var_dump($file);
}
}
and JS is using jQuery-File-Upload plugin: link
Generally, if the DELETE request sends data in the request body, you can read the data by using the following code:
$data = file_get_contents("php://input");
Depending on the encoding of the data (usually JSON or form-encoded), you use json_decode or parse_str to read the data into usable variables.
For a simple example, see this article, where the author uses form-encoded data to handle a PUT request. DELETE works similarly.
In your case however, it looks like the file name is read from the request URL (the call to $this->uri->segment(3);). When I look at your code, it seems that the variable $gll_id is not initailized and you don't check if the resulting object $w and the variable $gll_name are empty. Maybe this is causing the delete to fail. Turn on error logging with ini_set("log_errors",1); and have a look at your server error log. If the unlink fails, the error log should contain the path PHP tried to unlink - it's likely that the path is not correct.

Soap not getting sent correctly, need to get the request

I have this class to send a SOAP-request (the class also defines the header)
class Personinfo
{
function __construct() {
$this->soap = new SoapClient('mysource.wsdl',array('trace' => 1));
}
private function build_auth_header() {
$auth->BrukerID = 'userid';
$auth->Passord = 'pass';
$auth->SluttBruker = 'name';
$auth->Versjon = 'v1-1-0';
$authvalues = new SoapVar($auth, SOAP_ENC_OBJECT);
$header = new SoapHeader('http://www.example.com', "BrukerAutorisasjon", // Rename this to the tag you need
$authvalues, false);
$this->soap->__setSoapHeaders(array($header));
}
public function hentPersoninfo($params){
$this->build_auth_header();
$res = $this->soap->hentPersoninfo($params);
return $res;
}
}
The problem is that there's something wrong with my function and the response is an error. I'd like to find out what content I am sending with my request, but I can't figure out how.
I've tried a try/catch-block in the hentPersoninfo-function that calls $this->soap->__getLastRequest but it is always empty.
What am I doing wrong?
Before I ever start accessing a service programmatically, I use SoapUI to ensure that I know what needs sent to the service, and what I should expect back.
This way, you can ensure the issue isn't in the web service and/or in your understanding of how you should access the web service.
After you understand this, you can narrow your focus onto making the relevant SOAP framework do what you need it to do.

PHP PEAR HTTP PUT

I've got problems with PHP PEAR and HTTP PUT. I want to create a HTTP PUT request and attach a file to it and send it to a REST service. Here's my current code:
require_once ('includes/HTTP_Request/Request.php');
$url = 'http://myurl.com/';
$req =& new HTTP_Request();
$req->setMethod(HTTP_REQUEST_METHOD_PUT);
$req->setURL($url);
$req->addHeader('Content-type', 'multipart/form-data');
$tmp_file = 'temp.rdf';
$result = $req->addFile('metadata', $tmp_file, 'text/xml');
if (PEAR::isError($result))
{
echo $result->getMessage();
}
$response = $req->sendRequest();
if (PEAR::isError($response)) {
echo $response->getMessage();
} else {
echo $req->getResponseBody();
}
This code should work correctly, but obviously is doesn't. I always get the respond by the REST repository that the header doesn't contain multipart/form-data.
Does anyone know what I can do to get the code to work? Thanks in anticipation!
Use setBody( string $body) instead of addFile.
Sets the request body (for POST, PUT
and similar requests)

Form uploading files to different server without following

How can I send a file in django to a different server without user being redirected to the server ? So all goes to rewriting this simple php function in django :
$filename = 'C:/tmp/myphoto.jpg';
$handler = 'http://www.example.com/upload.php';
$field = 'image';
$res = send_file($filename, $handler, $field);
if ($res) {
echo 'done.';
} else {
echo 'something went wrong.';
}
Function on the second server is just simple php func that reads files from $_FILES:
<?php
move_uploaded_file(
$_FILES['image']['tmp_name'],
'/var/www/image/uploaded-file.jpg'
);
echo 'file saved.';
?>
I've already tried django-filetransfers, and it works but I somehow cannot make it stay on the page from which I am uploading file. I have edited the upload_handler view and files are sent properly but after that I'm redirected to my second server :
def upload_handler(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect("/upload")
upload_url, upload_data = prepare_upload(request, "address of my server/")
form = UploadForm()
return direct_to_template(request, '/upload.html',
{'form': form, 'upload_url': upload_url, 'upload_data': upload_data,
'uploads': UploadModel.objects.all()})
And here's my approach. I'm using functions from httplib and also multipart_encode function from python-poster that creates me file headers :
def file_upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
f = request.FILES['file']
logging.debug(f)
status = send_file(request.FILES['file'])
c = RequestContext(request, {
"status" : status,
})
template = "management/status.html"
result = render_to_string(template, c)
return HttpResponse(result)
else:
form = UploadFileForm()
return render_to_response('management/file_upload.html', {'form': form})
def send_file(file):
datagen, headers = multipart_encode({"myfile": file})
conn = httplib.HTTPConnection(HOST)
conn.request('POST', '/rte/', file, headers)
res = conn.getresponse()
if res.status != 200:
logging.debug("error \n")
logging.debug(file)
logging.debug("\n")
logging.debug(headers)
return res.status
HTML:
<form action="{{ views.file_upload }}" method="POST" enctype="multipart/form-data">
{{ form.as_p }}
<input type="submit" value="Upload" />
</form>
As a result I get 'Error 500' and in debug :
2010-10-20 18:12:55,819 DEBUG thumb.php4.jpg
2010-10-20 18:14:55,968 DEBUG error
2010-10-20 18:14:55,968 DEBUG thumb.php4.jpg
2010-10-20 18:14:55,969 DEBUG
2010-10-20 18:14:55,969 DEBUG {'Content-Length': 15019, 'Content-Type': 'multipart/form-data; boundary=02cafbc1d080471284be55dc1095b399'}
My functions are based on python/django docs and few solutions I've found on the internet. Functionality looks the same but somehow it doesn't work. Should I take different approach ? In php I do not need to define headers etc.
Well, first of all I'd like to ask why are you doing this? Is it because of the storage or load or perhaps failover? In case it's storage, why are you sending the file to the second server via HTTP? I guess a simple SSH file transfer would be just fine (scp). In case it's failover you'll be better off with rsync.
If using your own second server is not mandatory you might as well go with a CDN service.

Categories