JSON error when using Wordpress POST request to external API - php

I am trying to connect to the Listmonk API through wp_remote_post() on WordPress. I created a custom plugin for this.
Some parts work, but when I need to submit data that is an array or integer, I get errors. Also when I try to use wp_json_encode(), as recommended online, the API gives me a 400 error.
I hope someone can help!
I tried a lot of things. My POST code is:
$response = wp_remote_post($listmonk_url, array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode($listmonk_username . ':' . $listmonk_password),
'Content-Type: application/json',
),
'body' => $body,
));
And my body content is:
$body = array(
'name' => $name,
'email' => $email,
'status'=> 'enabled',
'lists' => 2,
'preconfirm_subscriptions' => true,
) ;
Whenever I try to use wp_json_encode() on $body, the API gives me:
[http_response] => WP_HTTP_Requests_Response Object ( [response:protected] => Requests_Response Object ( [body] => {"message":"Invalid email."} [raw] => HTTP/1.1 400 Bad Request Server
The encoded JSON was:
{"name":"john","email":"jan#jan.com","status":"enabled"}
And when I don't use json encoding, my 'lists' never passes through correctly, as you can see below, where the returned JSON shows lists is empty:
"lists":[]}
Is there something I am not seeing?

Related

Failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request - PHP Error

SOLUTION: I had malformed my JSON data for the payload body. The "ttl" => 30 was in the incorrect array() method. This probably won't help anyone in the future, moving the ttl key/value pair made this work correctly as seen below.
$data = array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),
),
"ttl" => 30
);
I have checked numerous other StackOverflow questions and cannot find a solution that works. I should note that I am testing this using a local XAMPP server running on port 8080. Not sure if that matters. I have been able to get this working using Postman, but translating it to PHP has been problematic. Am I missing something? I am not all that familiar with PHP, but need this for work.
EDIT: Some more information about what the API is expecting. It's a fairly simple API that requires a JSON body, a Basic Authorization header, and a Content-Type: application/json.
Here is the JSON body I am using in Postman. This is a direct copy/paste from Postman, which is successfully communicating with the API:
{
"statement": {
"actor": {
"mbox": "mailto:test#example.com"
}
},
"ttl": 30
}
Is there a syntax error in my below PHP code for this? Again, I am learning PHP on the fly so I'm unsure if I am properly constructing a JSON payload using the array() method in PHP.
My code below has the $https_user,$https_password, and $url domain changed for obvious security reasons. In my actual PHP code, I have the same credentials and domain used in Postman.
The $randomSessionID serves no real purpose other than an identification number for future requests. Has no affect on the API response failing or succeeding.
<?php
$https_user = 'username';
$https_password = 'password';
$randomSessionID = floor((mt_rand() / mt_getrandmax()) * 10000000);
$url = 'https://www.example.com/session/' . $randomSessionID . '/launch';
$json = json_encode(array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),"ttl" => 30
)
));
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/json\r\n'.
"Authorization: Basic ".base64_encode("$https_user:$https_password")."\r\n",
'content' => $json
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
?>
SOLUTION: I had malformed my JSON data for the payload body. The "ttl" => 30 was in the incorrect array() method. This probably won't help anyone in the future, but moving the ttl key/value pair made this work correctly as seen below.
$data = array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),
),
"ttl" => 30
);

How to Update an Xero Invoice Using wp_remote_post()

I am trying to update the invoice template of an Xero invoice. My issue is that I get a 400 error and a response saying:
NoDataProcessedException No data has been processed for this endpoint. This endpoint is expecting Invoice data to be specifed in the request body
So my authentication works perfectly but its claiming that I have no data in the body of my post request. As you can see in my code below I have specified data in the body of the request. So have I just formatted it wrong or am I doing something else wrong?
$xeroInvoiceId = '7b601c90-642b-4b6c-9a21-3969ff339cb0';
$updateInvoiceArgs = array(
'headers' => array(
'xero-tenant-id' => $tenantId,
'Authorization' => 'Bearer ' . $refreshTokenBody->access_token,
),
'body' => array(
'InvoiceID' => $xeroInvoiceId,
'BrandingThemeID' => '5d4dd402-c851-497e-aae1-9ff265c0d15a'
)
);
$res = wp_remote_post('https://api.xero.com/api.xro/2.0/Invoices/' . $xeroInvoiceId, $updateInvoiceArgs);
var_dump($res);
You are trying to post template or invoice data?

Dropbox API - Error: expected list got dict

I am currently building a routine that needs to download files from one specific Dropbox folder , send them to another server and then move them to another folder on Dropbox.
I am using the /files/move_batch API endpoint for Dropbox to do so.
Here are the params sent to the API to move multiples files (well I'm only trying to move one file right now as it's still not working) :
$params = array(
'headers' => array(
'method' => 'POST',
'content-type' => 'application/json; charset=utf-8',
),
'body' => json_encode(array(
'entries' => array(
'from_path' => self::$files[0],
'to_path' => '/Applications/Archives/' . substr(self::$files[0], strrpos(self::$files[0], '/') + 1),
),
'autorename' => true,
)),
);
But I keep getting the same error message :
Error in call to API function "files/move_batch": request body: entries: expected list, got dict
I don't know what the API means by a list or how it should be formated.
The entries value should be a list of dict, one per file you want to move, each one containing both a from_path and a to_path. Your code is supplying the entries value to be a single dict though. (In PHP you can make both lists and dicts using the array keyword.)
It's easier to see and work with when you break it into pieces. Here's a working sample that does that.
<?php
$fileop1 = array(
'from_path' => "/test_39995261/a/1.txt",
'to_path' => "/test_39995261/b/1.txt"
);
$fileop2 = array(
'from_path' => "/test_39995261/a/2.txt",
'to_path' => "/test_39995261/b/2.txt"
);
$parameters = array(
'entries' => array($fileop1, $fileop2),
'autorename' => true,
);
$headers = array('Authorization: Bearer <ACCESS_TOKEN>',
'Content-Type: application/json');
$curlOptions = array(
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($parameters),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_VERBOSE => true
);
$ch = curl_init('https://api.dropboxapi.com/2/files/move_batch');
curl_setopt_array($ch, $curlOptions);
$response = curl_exec($ch);
echo $response;
curl_close($ch);
?>
To move just one file using this batch endpoint, you would change that line to something like:
'entries' => array($fileop1),

How do i update object using php-sdk? (The parameter object is required)

$response = $facebook->api(
'me/objects/namespace:result',
'POST',
array(
'app_id' => app_id,
'type' => "namespace:result",
'url' => "http://samples.ogp.me/370740823026684",
'title' => "Sample Result",
'image' => "https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png",
'description' => ""
)
);
I get the following error.
The parameter object is required
I don't know where to add the parameter object.
I have been facing the same issue for the past couple of days, in the end I stopped trying to use the Facebook PHP SDK to send the request and resorted to using just sending a HTTP Request.
I am creating an object rather than updating one, but the implementation shouldn't differ much from your needs. I was getting the same error (The parameter object is required) and the below implementation resolved that issue.
I used the vinelab HTTP client composer package and built a request like this:
$request = [
'url' => 'https://graph.facebook.com/me/objects/namespace:object',
'params' => [
'access_token' => $fbAccessToken,
'method' => 'POST',
'object' => json_encode([
'fb:app_id' => 1234567890,
'og:url' => 'http://samples.ogp.me/1234567890',
'og:title' => 'Sample Object',
'og:image' => 'https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png',
'og:description' => 'Sample Object'
])
]
];
// I'm using Laravel so this bit might look different for you (check the vine lab docs if you use that specific HTTP client)
$response = HttpClient::post($request);
// raw content
$response->content();
// json
$response->json();
As I said, I used the vinelab HTTP package in my implementation, you should be able to use any similar package or directly use curl in PHP instead.

Post JSON with PHP CURL to a Tin Can API LRS

Sorry, I can only post 2 hyperlinks so I'm going to have to remove the http : //
Background
I'm, trying to convert the code here: https://github.com/RusticiSoftware/TinCan_Prototypes/blob/92969623efebe2588fdbf723dd9f33165694970c/ClientPrototypes/StatementIssuer/StatementIssuer.java
into PHP, specifically the makeRequest function. This code posts data to a Tin Can Compliant Learner Record Store.
The current version of my PHP code is here:
tincanapi.co.uk/wiki/tincanapi.co.uk:MediaWikiTinCan
The specification for the Tin Can API which everything should conform to is here:
scorm.com/wp-content/assets/tincandocs/TinCanAPI.pdf
There is also a working java script function that Posts data in the right format here (see the XHR_request function I think):
https://github.com/RusticiSoftware/TinCan_Prototypes/blob/92969623efebe2588fdbf723dd9f33165694970c/ClientPrototypes/GolfExample_TCAPI/scripts/TCDriver.js
I don't have access to the code or server that I'm posting to, but the end result should be an output here: beta.projecttincan.com/ClientPrototypes/ReportSample/index.html
Problem
I'm trying to use Curl to POST the data as JSON in PHP. Curl is returning 'false' but no error and is not posting the data.
On the recommendation of other questions on this site, I've tried adding 'json=' to the start of the POSTFIELDS, but since the Java and JavaScript versions does have this, I'm not sure this is right.
Can anybody suggest either how I might fix this or how I might get useful errors out of curl? My backup is to output the relevant JavaScript to the user's browser, but surely PHP should be able to do this server side?
Very grateful for any help.
Andrew
At least one thing is wrong: you should not be using rawurlencode on your Authorization header value.
Consider using php streams and json_encode() and json_decode() instead. The following code works.
function fopen_request_json($data, $url)
{
$streamopt = array(
'ssl' => array(
'verify-peer' => false,
),
'http' => array(
'method' => 'POST',
'ignore_errors' => true,
'header' => array(
'Authorization: Basic VGVzdFVzZXI6cGFzc3dvcmQ=',
'Content-Type: application/json',
'Accept: application/json, */*; q=0.01',
),
'content' => json_encode($data),
),
);
$context = stream_context_create($streamopt);
$stream = fopen($url, 'rb', false, $context);
$ret = stream_get_contents($stream);
$meta = stream_get_meta_data($stream);
if ($ret) {
$ret = json_decode($ret);
}
return array($ret, $meta);
}
function make_request()
{
$url = 'https://cloud.scorm.com/ScormEngineInterface/TCAPI/public/statements';
$statements = array(
array(
'actor' => array(
'name' => array('Example Name'),
'mbox' => array('mailto:example#example.com'),
'objectType' => 'Person',
),
'verb' => 'experienced',
'object' => array(
'objectType' => 'Activity',
'id'=> 'http://www.thincanapi.co.uk/wiki/index.php?Main_Page',
'definition' => array(
'name' => array('en-US'=>'TinCanAPI.co.uk-tincanapi.co.uk'),
'description' => array('en-US'=> 'TinCanAPI.co.uk-tincanapi.co.uk'),
),
),
),
);
return fopen_request_json($statements, $url);
}
list($resp, $meta) = make_request();
var_export($resp); // Returned headers, including errors, are in $meta
We've now released an open source library specifically for PHP, it uses a similar method as the accepted answer but rounds out the rest of the library as well. See:
http://rusticisoftware.github.io/TinCanPHP/
https://github.com/RusticiSoftware/TinCanPHP

Categories