How to remove the Square Bracket in JSON using PHP - php

Below code is the returned JSON
[{"one":"id","two":"id","three":"id"},{"one":"id","two":"id","three":"id"}]
Below code is the desired result of the returned JSON (without the array bracket)
{"one":"id","two":"id","three":"id"},{"one":"id","two":"id","three":"id"}
Below code is to convert the array to the JSON format
include('connect-db.php');
$result = mysql_query("SELECT * FROM patientvaccinedetail");
$specific = [];
while($row = mysql_fetch_array( $result ,MYSQL_ASSOC)) {
echo "<tr>";
echo '<td width="100px">' . $row['id'] . '</td>';
echo '<td width="200px">' . $row['patientid'] . '</td>';
echo '<td width="200px">' . $row['vaccineid'] . '</td>';
//**********Convert the array into json*******************
$specific[] = ["one" => $row["id"],
"two" => $row["patientid"],
"three" => $row["vaccineid"]];
$result = json_encode($specific,JSON_UNESCAPED_UNICODE);
echo $result;
echo "</tr>";
echo "</table>";
?>
To send the request to the API, iam using Guzzle
And the format the API require is {xx:xx},{xx:xx}
without the square bracket, any idea how to remove it using PHP.
Thanks in advance
$client = new Client([
'headers' => ['Content-Type' => 'application/json',
'Token' => $token]
]);
$response = $client->post('http://localhost:91/Religious',
['body' => ***Where the json will be place***]
);

I read a nice solution in the comments of the first post by deceze ♦ with trim().
$yourJson = trim($yourJson, '[]');
You can also use regular expression:
// if nothing is found, your json has already no brackets or is invalid.
if (preg_match('/^\[(.+)\]$/', $yourJson, $new))
{
/**
* $new[0] = $yourJson
* $new[1] = what's in the parenthesis
*/
$yourJson = $new[1];
}
Or, you may use substr():
$yourJson = substr($yourJson, 1, strlen($yourJson) - 2);
EDIT:
When it says in the request body format : application/json, I do not think that you have to remove the brackets. Did you even try with them?

You are trying to convert a PHP array to a JSON array, so php wrap the result in brackets, it's totally normal. If you need a JSON object Then I would suggest to use JSON_FORCE_OBJECT as additional option(parameters) in json_encode.
$object = json_encode($array, JSON_FORCE_OBJECT);

Try this
str_replace(array('[', ']'), '', htmlspecialchars(json_encode($result), ENT_NOQUOTES));

You might need to use the implode function after a json decode. for example:
implode(',',json_decode($text_from_db or $array))
for example $text_from_db=["rice","beans"]
the result will be- rice,beans

you can trimit see example below
trim($data, '[]')

I've added comments as to what the OP is trying to do. But here's my solution for future visitors of this question.
class Thing implements \JsonSerializable
{
private $name;
private $description;
private $code;
/**
* Get the value of name
*/
public function getName()
{
return $this->name;
}
/**
* Set the value of name
*
* #return self
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get the value of description
*/
public function getDescription()
{
return $this->description;
}
/**
* Set the value of description
*
* #return self
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get the value of code
*/
public function getCode()
{
return $this->code;
}
/**
* Set the value of code
*
* #return self
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
public function jsonSerialize()
{
$vars = get_object_vars($this);
return $vars;
}
}
$thing = new Thing();
$thing->setName('Name');
$thing->setDescription('Description');
$thing->setCode('Code');
$results['items'] = [
'thing1' => $thing,
'thing2' => $thing
];
echo json_encode($results);
Here's the output
{
"items": {
"thing1": {
"name": "Name",
"description": "Description",
"code": "Code"
},
"thing2": {
"name": "Name",
"description": "Description",
"code": "Code"
}
}
}

This will remove the outer wrapper without disturbing any inner wrappers:
$wrapped = <<<EOD
[{"one":"id","two":"id","three":"id"},{"one":"id","two":"id","three":"id"}]
EOD;
$array = json_decode($wrapped, true);
$unwrapped = json_encode($array, JSON_FORCE_OBJECT);
print_r($unwrapped);
// {"0":{"one":"id","two":"id","three":"id"},"1":{"one":"id","two":"id","three":"id"}}

My suggestion is to use JSON string and perform String operations to remove all those not required characters.
Reason for doing this, the required output is not a valid JSON and won't be accepted by API. As you need it however, I would suggest you to convert the array into json using json_encode and then perform string operations to convert it into your desired output.

Related

Match Urls in results of api call

I have an api call that amongst it has Url's that are recalled in it's returned JSON.
I need to find those returned urls that have in them the string used for the original get request and have statuses of 200. I tried using the strpos method, but that didn't seem to work.
public function getCompanyData() {
$client = new Client();
$response = $client->request('GET', 'https://api.github.com/orgs/fakename');
$statusCode = $response->getStatusCode();
$body = $response->getBody()->getContents();
$confirmed = strpos($body,'api.github.com/orgs/fakename');
if($statusCode === 200 && $confirmed !== false) {
return $body;
}
else {
return $statusCode." Error";
}
}
Returned JSON -
{
"login": "fakename",
"id": 1214096,
"node_id": "***=",
"url": "https://api.github.com/orgs/fakename",
"repos_url": "https://api.github.com/orgs/fakename/repos",
"events_url": "https://api.github.com/orgs/fakename/events",
"hooks_url": "https://api.github.com/orgs/fakename/hooks",
"issues_url": "https://api.github.com/orgs/fakename/issues",
"members_url": "https://api.github.com/orgs/fakename/members{/member}",
"public_members_url": "https://api.github.com/orgs/fakename/public_members{/member}",
"avatar_url": "https://avatars3.githubusercontent.com/u/****?v=4",
"description": "",
"name": "fakename",
"company": null,
"blog": "fakename.com",
"location": null,
"email": null,
"twitter_username": null,
"is_verified": false,
"has_organization_projects": true,
"has_repository_projects": true,
"public_repos": 41,
"public_gists": 0,
"followers": 0,
"following": 0,
"html_url": "https://github.com/fakename",
"created_at": "2011-11-22T21:48:43Z",
"updated_at": "2020-09-11T23:05:04Z"
}
One approach would be as follows:
<?php
class SomeClass
{
/**
* #var int The status code of the last http request
*/
private $statusCode;
/**
* Get an array of decoded data from the given url.
* #param $url
* #return array
*/
public function getDataFromUrl($url) {
$client = new Client();
$response = $client->request('GET', $url);
$this->statusCode = $response->getStatusCode();
$body = $response->getBody()->getContents();
return $this->statusCode === 200 ? json_decode($body, true) : [];
}
/**
* Get all data for a given organization including nested ancillary data
* #param string $orgName
* #return array
*/
public function getCompanyData($orgName) {
$mainUrl = "https://api.github.com/orgs/$orgName";
$mainData = $this->getDataFromUrl($mainUrl);
if ($mainData && $this->statusCode === 200) {
$ancillaryUrls = $this->getAncillaryUrlsFromData($mainData, $orgName);
foreach ($ancillaryUrls as $property => $url) {
$ancillaryData = $this->getDataFromUrl($url);
$mainData[$property] = $ancillaryData;
}
}
return $mainData;
}
/**
* Get a JSON string containing all data for a given organization including nested ancillary data
* #param string $orgName
* #return array|mixed
*/
public function getCompanyDataAsJson($orgName) {
return json_encode($this->getCompanyData($orgName));
}
/**
* From the provided array of data, return an new array containing the ancillary urls
* which also need to be requested
* #param array $data
* #param string $orgName
* #return array
*/
public function getAncillaryUrlsFromData($data, $orgName) {
$urls = [];
if (is_array($data)) {
$targetUrl = "api.github.com/orgs/$orgName";
foreach ($data as $property => $value) {
// if property has '_url' and value is like our url, add it to our array of urls
if (strpos($property, '_url') !== false && strpos($value, $targetUrl) !== false) {
$cleanProp = str_replace('_url', '', $property);
$urls[$cleanProp] = $targetUrl;
}
}
}
return $urls;
}
}
Now, if you want the result as an array, you can call:
$someClass = new SomeClass();
$arrayOfData = $someClass->getCompanyData('fakename');
Or, if you want the result as a JSON string, you can call:
$someClass = new SomeClass();
$jsonData = $someClass->getCompanyDataAsJson('fakename');
And the response will have the following keys (in addition to the original main data) "repos", "events", "hooks", "issues", "members", "public_members" all filled with the responses from their individual calls.

Getting rid of ?: operator in PHP

I have a problem with PHP code for survey. The code only takes one value, "answer" and if answer is not available it takes "otherAnswer". I need it to take both "answer" and "otherAnswer"
Here is the code. Thanks for help.
protected function convertRequestToUserAnswersArray()
{
$answers = [];
if ($this->request->hasArgument('answers')) {
/** #noinspection PhpUnhandledExceptionInspection */
$requestAnswers = $this->request->getArgument('answers');
/** #noinspection PhpWrongForeachArgumentTypeInspection */
foreach ($requestAnswers as $questionUid => $requestAnswer) {
$answers[$questionUid] = $requestAnswer['answer'] ?: $requestAnswer['otherAnswer'];
}
}
return $answers;
}
Try to append both answers. If you want both answers you don't need to use ternary operator
protected function convertRequestToUserAnswersArray()
{
$answers = [];
if ($this->request->hasArgument('answers')) {
/** #noinspection PhpUnhandledExceptionInspection */
$requestAnswers = $this->request->getArgument('answers');
/** #noinspection PhpWrongForeachArgumentTypeInspection */
foreach ($requestAnswers as $questionUid => $requestAnswer) {
$answers[$questionUid] = $requestAnswer['answer'] +' '+ $requestAnswer['otherAnswer'];
}
}
return $answers;
}
We do not know how the $answers is going to be used. Because returning both answer and otherAnswer requires $answers to be array. Which means any user of $answers must be refactored.
Something like this might work:
$answers[$questionId] = ["answer" => $requestAnswer["answer"], "otherAnswers" => requestAnswer["otherAnswer"] ]
Just add some checking mechanism for the key existence.
Or you can concatenate it as suggested in another SO answer.
As you said you want both values then you can store into array as like below
$answers[$questionUid][] = $requestAnswer['answer'];
$answers[$questionUid][] = $requestAnswer['otherAnswer'];
By using above script $answers would have both values against $questionUid
Assuming that $answers[$questionUid] is an array, You can try to push the values to it:
/** #noinspection PhpWrongForeachArgumentTypeInspection */
foreach ($requestAnswers as $questionUid => $requestAnswer) {
$answers[$questionUid] = $requestAnswer['answer'] . '----' . $requestAnswer['otherAnswer'];
}
Hope this helps.

Can I get the effect of JSON_NUMERIC_CHECK without JSON?

Can i get the effect of JSON_NUMERIC_CHECK without JSON?
i.e. Recrusive replacement of numeric strings to ints or floats.
Example with JSON_NUMERIC_CHECK:
<?php
// some input from somewhre
$data = explode(',', 'abc,7,3.14');
echo "Before:"; var_dump($data);
$data = json_decode(json_encode($data, JSON_NUMERIC_CHECK), TRUE);
echo "After:"; var_dump($data);
But I geuss converting to json and back is slow, is there some other way to get the same result?
You can loop over your strings and cast any numeric value to int or float using the following code:
/**
* Normalize an object, array or string by casting all
* numeric strings it contains to numeric values.
*
* #param array|object|string $data
* #return mixed
*/
function normalize($data) {
if (is_array($data))
return array_map('normalize', $data);
if (is_object($data))
return (object) normalize(get_object_vars($data));
return is_numeric($data) ? $data + 0 : $data;
}
$data = "15,2.35,foo";
$data = normalize(explode(',', $data));
// => [15, 2.35, 'foo']
Hope this helps :)
More efficient way
/**
* Normalize an string or object by casting all
* numeric strings it contains to numeric values.
* Note that it changes the variable directly
* instead of returning a copy.
*
* #param object|string $data
* #return void
*/
function normalizeItem(&$data) {
if (is_object($data)) {
$data = get_object_vars($data);
normalize($data);
$data = (object) $data;
} else {
$data = is_numeric($data) ? $data + 0 : $data;
}
}
/**
* Applies normalizeItem to an array recursively.
*
* #param array &$list
* #return bool
*/
function normalize(&$list) {
return array_walk_recursive($list, 'normalizeItem');
}
You can use array_map() with a callback.
$data = explode(',', 'abc,7,3.14');
$re = array_map(function(&$a) {
return ctype_digit($a) ? intval($a) : $a;
}, $data);
var_dump($re);
https://eval.in/715641

PHP foreach array IDs

I have a foreach loop that is supposed to loop through JSON and return the appropriate ID of each video listed in JSON using the Youtube api.
Here is my code:
class Videos {
private $mVideoUrl;
function setVideoTitle($videoUrl){
$this->mVideoUrl= $videoUrl;
}
function getVideoTitle(){
return $this->mVideoUrl;
}
}
$jsonFile = file_get_contents($url);
$jfo = json_decode($jsonFile);
$items = $jfo->items;
$vidArray = array();
foreach ($items as $item){
if(!empty($item->id->videoId)){
$Videos = new Videos;
$Videos->setVideoUrl($item->id->videoId);
$id = $Videos->getVideoUrl();
array_push($vidArray, $id);
}
echo $vidArray[0];
}
Problem is, the array push is working correctly, but it is only adding the 1st ID in the list only for each loop iteration when i echo it. When I echo the $id variable, it prints all IDs just fine.
Ultimately i want to be able to create an object for each video, storing it's ID and other information.
I feel like this is a simple fix but i can't figure it out for the life of me.
I would appreciate any help!
Also if i am going about this all wrong, advice is appreciated as well!
Thanks!
I've played little bit with your code. I've modified your class. I've renamed plurar Videos to Video (singular).
Then I've added an attribute $id, because name of properties should be simple and represent the data we want to store in them.
Then I've added getter and setter for the $id property.
I don't know the $url, so I've just write simple JSON string instead. I tried to mimic the structure that you're using in your code.
Then I've added () to the end of new Video() to have proper constructor called.
And instead of pushing elements into array, I'm using proper $array[$index] = assignment.
Last thing, I've moved writing out the data out of the foreach-cycle. And I'm using var_export to get proper php code to play with if redirected to another file.
<?php
class Video
{
private $mVideoUrl;
private $id; // added id attribute
/**
* #return mixed
*/
public function getId() // added getter
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id) // added setter
{
$this->id = $id;
}
function setVideoTitle($videoUrl)
{
$this->mVideoUrl = $videoUrl;
}
function getVideoTitle()
{
return $this->mVideoUrl;
}
}
// ignored for now
// $jsonFile = file_get_contents($url);
$jsonFile = '{"items": [
{ "id": { "videoId": 1, "url": "http://www.youtube.com/1" } },
{ "id": { "videoId": 2, "url": "http://www.youtube.com/2" } },
{ "id": { "videoId": 3, "url": "http://www.youtube.com/3" } },
{ "id": { "videoId": 4, "url": "http://www.youtube.com/4" } },
{ "id": { "videoId": 5, "url": "http://www.youtube.com/5" } }
]
}';
$jfo = json_decode($jsonFile);
$items = $jfo->items;
$vidArray = array();
foreach ($items as $item)
{
if (!empty($item->id->videoId))
{
$Video = new Video(); // added brackets
$Video->setId($item->id->videoId); // changed to setId
$Video->setVideoTitle($item->id->url);
$id = $Video->getId();
$vidArray[$id] = $Video;
}
}
// write out all data
var_export($vidArray);
In your code your class Videos contains two functions
setVideoTitle(...),
getVideoTitle()
but in your foreach you have called $videos->getVideoUrl() , $videos->setVideoUrl(...)
what is this ???

Issues calculating signature for Amazon Marketplace API

I’m trying to calculate a signature to make Amazon Marketplace API calls, but I keep getting the following error:
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
I’ve wrapped the signature creation process into a class:
<?php
namespace App\Marketplace\Amazon;
class Signature
{
protected $signedString;
public function __construct($url, array $parameters, $secretAccessKey)
{
$stringToSign = $this->calculateStringToSign($url, $parameters);
$this->signedString = $this->sign($stringToSign, $secretAccessKey);
}
protected function calculateStringToSign($url, array $parameters)
{
$url = parse_url($url);
$string = "POST\n";
$string .= $url['host'] . "\n";
$string .= $url['path'] . "\n";
$string .= $this->getParametersAsString($parameters);
return $string;
}
protected function sign($data, $secretAccessKey)
{
return base64_encode(hash_hmac('sha256', $data, $secretAccessKey, true));
}
protected function getParametersAsString(array $parameters)
{
uksort($parameters, 'strcmp');
$queryParameters = [];
foreach ($parameters as $key => $value) {
$queryParameters[$key] = $this->urlEncode($value);
}
return http_build_query($queryParameters);
}
protected function urlEncode($value)
{
return str_replace('%7E', '~', rawurlencode($value));
}
public function __toString()
{
return $this->signedString;
}
}
But I can’t for the life of me see where I’m going wrong. I’ve followed the guide in the API, and looked at the Java example as well as the antiquated Marketplace PHP SDK*.
EDIT: And here is how I’m using the Signature class:
$version = '2011-07-01';
$url = 'https://mws.amazonservices.com/Sellers/'.$version;
$timestamp = gmdate('c', time());
$parameters = [
'AWSAccessKeyId' => $command->accessKeyId,
'Action' => 'GetAuthToken',
'SellerId' => $command->sellerId,
'SignatureMethod' => 'HmacSHA256',
'SignatureVersion' => 2,
'Timestamp' => $timestamp,
'Version' => $version,
];
$signature = new Signature($url, $parameters, $command->secretAccessKey);
$parameters['Signature'] = strval($signature);
try {
$response = $this->client->post($url, [
'headers' => [
'User-Agent' => 'my-app-name',
],
'body' => $parameters,
]);
dd($response->getBody());
} catch (\Exception $e) {
dd(strval($e->getResponse()));
}
As an aside: I know the Marketplace credentials are correct as I’ve logged in to the account and retrieved the access key, secret, and seller IDs.
* I’m not using the SDK as it doesn’t support the API call I need: SubmitFeed.
I’m not sure what I’ve changed, but my signature generation is working now. Below is the contents of the class:
<?php
namespace App\Marketplace\Amazon;
class Signature
{
/**
* The signed string.
*
* #var string
*/
protected $signedString;
/**
* Create a new signature instance.
*
* #param string $url
* #param array $data
* #param string $secretAccessKey
*/
public function __construct($url, array $parameters, $secretAccessKey)
{
$stringToSign = $this->calculateStringToSign($url, $parameters);
$this->signedString = $this->sign($stringToSign, $secretAccessKey);
}
/**
* Calculate the string to sign.
*
* #param string $url
* #param array $parameters
* #return string
*/
protected function calculateStringToSign($url, array $parameters)
{
$url = parse_url($url);
$string = "POST\n";
$string .= $url['host']."\n";
$string .= $url['path']."\n";
$string .= $this->getParametersAsString($parameters);
return $string;
}
/**
* Computes RFC 2104-compliant HMAC signature.
*
* #param string $data
* #param string $secretAccessKey
* #return string
*/
protected function sign($data, $secretAccessKey)
{
return base64_encode(hash_hmac('sha256', $data, $secretAccessKey, true));
}
/**
* Convert paremeters to URL-encoded query string.
*
* #param array $parameters
* #return string
*/
protected function getParametersAsString(array $parameters)
{
uksort($parameters, 'strcmp');
$queryParameters = [];
foreach ($parameters as $key => $value) {
$key = rawurlencode($key);
$value = rawurlencode($value);
$queryParameters[] = sprintf('%s=%s', $key, $value);
}
return implode('&', $queryParameters);
}
/**
* The string representation of this signature.
*
* #return string
*/
public function __toString()
{
return $this->signedString;
}
}
Try this function after calling your sign function:
function amazonEncode($text)
{
$encodedText = "";
$j = strlen($text);
for($i=0;$i<$j;$i++)
{
$c = substr($text,$i,1);
if (!preg_match("/[A-Za-z0-9\-_.~]/",$c))
{
$encodedText .= sprintf("%%%02X",ord($c));
}
else
{
$encodedText .= $c;
}
}
return $encodedText;
}
Reference
After you've created the canonical string as described in Format the
Query Request, you calculate the signature by creating a hash-based
message authentication code (HMAC) using either the HMAC-SHA1 or
HMAC-SHA256 protocols. The HMAC-SHA256 protocol is preferred.
The resulting signature must be base-64 encoded and then URI encoded.

Categories