Post JSON with PHP CURL to a Tin Can API LRS - php

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

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 log into a web service with php post request

So i need to gain access to a web service containing some json, but to do so I was told to make use of PHP POST method to first log into the web service. I was giving an array with 3 types/values.
{
"Username":"user",
"password":"1234",
"LoginClient":"user"
}
I have been searching all day for a solution, but have come up short :(.
Any advice or push into a right direction would be much appreciated.
Hope I have explained this clearly enough.
you could do as follows:
$url = 'http://yourDomain.net/api/auth/';
$data = array('Username' => 'user', 'password' => '1234', 'LoginClient' => 'user');
$opts = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
)
);
$context = stream_context_create($opts); //Creates and returns a stream context with any options supplied in options preset.
$response = file_get_contents($url, false, $context);
var_dump($response);
Or you could read about CURL as another option to make POST requests.

PHP post to WebAPI

Well, I know that the headline look simple, but i was looking from 3 days for an example on how to make the POST request to webapi.
Currently I am using JQuery to do my POST, but I need some php script to run and talk to my C# webAPI, and it seems impossible to find some examples or explain on how to do that.
Someone gave me then Code :
$response = file_get_contents('http://localhost:59040/api/Email/SendEmails');
$response = json_decode($response);
echo ($response);
But this one does nothing - Not even an error on how to go more into the problem.
I simpley need a php script to make the POST request to webapi who gets 1 param(String) and return An ok answer or Error,
After Maalls answer from this post How do I send a POST request with PHP?
The answer was really simple and the code was the following :
$url = 'http://server.com/path';
$data = array('key1' => 'value1', 'key2' => 'value2');
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
var_dump($result);
Thanks Maalls and dbau for the answer :).

Wikimedia api and php

I am using the Wikimedia api and php. I need to get first main image from article and all text in article. I have got code for it, but it takes only short info and very little picture. I tried to change many parameters, but it is not working.
Code is here:
function get_wiki_url($title) {
$context = stream_context_create(array(
'http' => array(
'method'=>"POST",
'content' => $reqdata = http_build_query(array(
'action' => 'opensearch',
'search' => $title,
'prop' => 'info',
'format' => 'xml',
'inprop' => 'url'
)),
'header' => implode("\r\n", array(
"Content-Length: " . strlen($reqdata),
"User-Agent: MyCuteBot/0.1",
"Connection: Close",
""
))
)));
if (false === $response = file_get_contents("http://ru.wikipedia.org/w/api.php", false, $context)) {
return false;
}
//парсим строку
$xml = simplexml_load_string($response);
return $xml->Section->Item;
}
var_dump ($pages_data = get_wiki_url("article header"));
Your query appears to be running a search for $title (parameter action=opensearch); if you want the article and main image (I presume you want HTML, not wikitext), you need to use action=parse -- see the Mediawiki parse documentation.
Example URL for getting the Hyperloop page:
http://ru.wikipedia.org/w/api.php?action=parse&format=xml&page=Hyperloop
The documentation has details on all the options available.

file_get_contents(): stream does not support seeking

I'm getting this error:
`file_get_contents(): stream does not support seeking
I have no clue to fix it. There is no Resource Id or whatsoever.
This is my code:
$postData = array('name' => $name, 'description' => $description, 'date_begin' => $start, 'date_end' => $end);
$stream = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n"
. "Authorization: Basic Y3Nub2VrOnNuMDNr\r\n",
'method' => 'POST',
'content' => http_build_query($postData)
)
);
return stream_context_create($stream);
And in the file where the stream returns to. Its the function getApiContext.
$responseJson = json_decode(file_get_contents('http://10.0.0.89/api/v1/projects', false, BaseController::getApiContext(), true));
And then I get this annoying error. I know about cUrl, but I must use streams.
why have you got true on your file_get_contents offset param? perhaps you meant to put this in the json_decode if so, try this:
$responseJson = json_decode(file_get_contents('http://10.0.0.89/api/v1/projects', false, BaseController::getApiContext()),true);
It seems you are passing the fourth parameter to file_get_contents, this is not supported for remote streams (as per the documentation: http://no1.php.net/manual/en/function.file-get-contents.php)
Change your call to file_get_contents to exclude it (or pass it to json_decode if that was your intent).
$responseJson = json_decode(file_get_contents('http://10.0.0.89/api/v1/projects', false, BaseController::getApiContext()));

Categories