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>
Related
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)
I'm having trouble using Zend HTTP on a URL:
$bestBuyClient = new Zend_Http_Client('https://api.bestbuy.com/v1/products(search=pizza&salePrice>10&salePrice<15)?apiKey=MyKeyHere&page=1&numItems=10&format=json&show=sku&name&productId&type®ularPrice&salePrice&upc&modelNumber&image&largeFrontImage&mediumImage&thumbnailImage&largeImage&shortDescription&longDescription');
$response = $bestBuyClient->request();
$json="";
if($response->isSuccessful()){
$jsonTxt=$response->getBody();
$json = #json_decode($jsonTxt,true);
}
$jsonProducts=$json;
return $jsonProducts;
For some reason, this gives me an error:
Invalid URI supplied
Whats wrong this this specific url?
Edit: In PostMan or browser request sends proper data.
Can you change:
$bestBuyClient = new Zend_Http_Client('https://api.bestbuy.com/v1/products(search=pizza&salePrice>10&salePrice<15)?apiKey=MyKeyHere&page=1&numItems=10&format=json&show=sku&name&productId&type®ularPrice&salePrice&upc&modelNumber&image&largeFrontImage&mediumImage&thumbnailImage&largeImage&shortDescription&longDescription');
$response = $bestBuyClient->request();
To
$shoppableClient = new Zend_Http_Client(sprintf('https://api.bestbuy.com/v1/products'."%s?%s", urlencode('(search=pizza&salePrice>10&salePrice<15)'), 'apiKey=MyKeyHere&page=1&numItems=10&format=json&show=sku&name&productId&type®ularPrice&salePrice&upc&modelNumber&image&largeFrontImage&mediumImage&thumbnailImage&largeImage&shortDescription&longDescription'));
Please let me know if works :).
So I'm trying to get a grasp of OpenID, and I feel I understand the theory, etc... now it's come to implementing it. I've got a very basic setup that sends a curl request to the google provider address..
https://www.google.com/accounts/o8/id
parses the returned XRDS xml file
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/server</Type>
<Type>http://openid.net/srv/ax/1.0</Type>
<Type>http://specs.openid.net/extensions/ui/1.0/mode/popup</Type>
<Type>http://specs.openid.net/extensions/ui/1.0/icon</Type>
<Type>http://specs.openid.net/extensions/pape/1.0</Type>
<URI>https://www.google.com/accounts/o8/ud</URI>
</Service>
</XRD>
</xrds:XRDS>
After retrieving the actual provider for google from their XRDS document I redirect using this function...
public function RedirectToEndpoint() {
$params = array();
$params['openid.mode'] = 'checkid_setup';
$params['openid.ns'] = 'http://specs.openid.net/auth/2.0';
$params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$params['openid.return_to'] = $this->URLs['return_to'];
$params['openid.realm'] = $this->URLs['realm'];
$join = stripos($this->URLs['openid_server'], '?') ? '&' : '?';
$redirect_to = $this->URLs['openid_server'] . $join . $this->array2url($params);
if (headers_sent()){ // Use JavaScript to redirect if content has been previously sent (not recommended, but safe)
echo '<script language="JavaScript" type="text/javascript">window.location=\'';
echo $redirect_to;
echo '\';</script>';
}else{ // Default Header Redirect
header('Location: ' . $redirect_to);
}
}
The array2url is a simple function which converts the assoc array $params to append to the query string.
The generated url is such...
https://www.google.com/accounts/o8/ud?openid.mode=checkid_setup&openid.ns=http://specs.openid.net/auth/2.0&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.return_to=http://learn.local/openid/return.php&openid.realm=http://learn.local/openid/index.html&
However, you end up at a page requested is invalid. And a nice 400 Bad Request.. any ideas?
All in all, I couldn't feel more stupid! It came down to setting my realm correctly. I had a realm which lead to my return address being out of the available "scope" so to speak. For future people who run into a 400 error, it might be..
$openid->SetReturnAddress(('http://learn.local/openid/return.php')); //.return_to
$openid->SetDomain(('http://learn.local/openid/index.html')); //Realm
A poorly configured realm.. facepalm
It is now...
$openid->SetDomain(('http://learn.local')); //Realm
A remote server is POSTing XML to my server via RPC. I can see the XML in my Apache logs when I turn on mod security, but I can't access the XML from my PHP script. It's supposed to be a POST request, but the $_POST array is empty.
My understanding is that RPC is supposed to call my function with the data, but that doesn't seem to be happening.
This ridiculously simple script should write the XML to a log file, yet it does nothing:
include_once('xmlrpc/xmlrpc.inc');
include_once('xmlrpc/xmlrpcs.inc');
function ImportOrders($xml)
{
$FH=fopen('Log/In.txt','a');
fwrite($FH,'Package recieved:'.print_r($xml,true)."\n");
// set appropriate response code
$response = 0; // see defined response codes for this application
// send success or failure response code
if($response == 0)
return new xmlrpcresp(new xmlrpcval($response, "string"));
else
return new xmlrpcresp(0, $response, $error_message);
}
$Server = new xmlrpc_server(
array("ImportOrders"=>array("function"=>"ImportOrders")
)
);
They are sending me this:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<methodCall>
<methodName>ImportOrders</methodName>
<params>
<param>
<value><int>2</int></value>
</param>
<param>
<value><struct>
<member><name>order_0</name>
<value><struct>
<member><name>order_id</name>
....
Why isn't my function being called?!?
Got it! Apparently the data is in "$GLOBALS['HTTP_RAW_POST_DATA']".
require 'kd_xmlrpc.php';
$xmlrpc_request = XMLRPC_parse($GLOBALS['HTTP_RAW_POST_DATA']);
$methodName = XMLRPC_getMethodName($xmlrpc_request);
$params = XMLRPC_getParams($xmlrpc_request);
ImportOrders($params);
function ImportOrders($params)
{
$FH=fopen('Log/In.txt','a');
fwrite($FH,'OrderDataRes has been loaded.'."\n");
fwrite($FH,'$params: '.print_r($params,true)."\n");
}
I'm also using a differnt library, from:
http://www.keithdevens.com/software/xmlrpc/source.php
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)