PHP iterate through sequental key values - php

I am grabbing Pokemon data from a JSON API, that is showing values for any Pokemon. The aim here is to grab data that shows what games a Pokemon can be found in and which areas in the game they are found located.
https://pokeapi.co/api/v2/pokemon/183/
This is accessed via its encounters key value. I am particularly interested in accessing via :
['location_area']['name'] and ['version']['name']
As a good URL example: https://pokeapi.co/api/v2/pokemon/183/encounters
Problem is, the encounters array index value is a URL, which I am accessing through my own Curl json function, which works fine, but will only give me array numeric index values.
public function getPokemonLocation($searchTerm)
{
/*
Get the Pokemon via search term name
*/
$url = $this->baseUrl.$searchTerm;
$pokemonLocation = $this->getUrl($url);
/*
$pokemonLocationUrl is the encounters subset i the array URL
*/
$pokemonLocationUrl = $pokemonLocation['location_area_encounters'];
$pokemonLocationEncounters = $this->getUrl('https://pokeapi.co/' . $pokemonLocationUrl);
echo "<pre>";
print_r($pokemonLocationEncounters);
echo "</pre>";
/*
Now grab the data needed from the name of location and what game regions they are from
*/
$pokemonAreaEncounterArea = array();
$pokemonAreaEncounterGame = array();
foreach($pokemonLocationEncounters as $key => $encounter)
{
$pokemonAreaEncounterArea[] = $encounter['location_area']['name'];
$pokemonAreaEncounterGame[] = $encounter['version_details'][0]['version']['name'];
}
$pokemonLocationAndRegion = array_combine($pokemonAreaEncounterGame,$pokemonAreaEncounterArea);
// print_r($pokemonLocationAndRegion);
return $pokemonLocationAndRegion;
}
Problem is, the encounters array index value is a URL, which I am accessing through my own Curl json function, which works fine, but will only give me array numeric index values.
I can easily get data, as shown above . Howwever would like to fully access all of the array indexes, not just one or a handful of data. Tempting to do this via multiple foreach, but would rather implement it cleanly.
EDIT: Here is 2nd example of Poke APi link above, if you get a 504 server Error - https://jsoneditoronline.org/?id=73911ec678c850f9b1ff131ac7ee738c

According to your json which is returning an index based array, this is how your code should be to work.
public function getPokemonLocation($searchTerm) {
/*
Get the Pokemon via search term name
*/
$url = $this->baseUrl . $searchTerm;
$pokemonLocation = $this->getUrl($url);
/*
$pokemonLocationUrl is the encounters subset i the array URL
*/
$pokemonLocationUrl = $pokemonLocation['location_area_encounters'];
$pokemonLocationEncounters = $this->getUrl('https://pokeapi.co/' . $pokemonLocationUrl);
echo "<pre>";
print_r($pokemonLocationEncounters);
echo "</pre>";
$pokemonAreaEncounterArea = array();
$pokemonAreaEncounterGame = array();
/*
Now grab the data needed from the name of location and what game regions they are from
*/
for($i=0,$size=count($pokemonLocation);$i<$size;$i++) {
$pokemonAreaEncounterArea[] = $pokemonLocation[$i]['location_area']['name'];
$pokemonAreaEncounterGame[] = $pokemonLocation[$i]['version_details'][0]['version']['name'];
}
$pokemonLocationAndRegion = array_combine($pokemonAreaEncounterGame, $pokemonAreaEncounterArea);
// print_r($pokemonLocationAndRegion);
return $pokemonLocationAndRegion;
}
to make it clearer
for($i=0,$size=count($pokemonLocation);$i<$size;$i++) {
$pokemonAreaEncounterArea[] = $pokemonLocation[$i]['location_area']['name'];
$pokemonAreaEncounterGame[] = $pokemonLocation[$i]['version_details'][0]['version']['name'];
}
this will allow you to traverse all elements in the result array, and put them on the same index in respective arrays of $pokemonAreaEncounterArea and $pokemonAreaEncounterGame

You can combine the target data as you iterate like this:
$array=json_decode($json,true);
foreach($array as $item){
$result[$item['version_details'][0]['version']['name']]=$item['location_area']['name'];
}
var_export($result);
Output:
array (
'diamond' => 'great-marsh-area-6',
'platinum' => 'sinnoh-route-215-area',
'heartgold' => 'mt-mortar-1f',
'ruby' => 'hoenn-route-120-area',
'emerald' => 'hoenn-safari-zone-expansion-south',
'leafgreen' => 'four-island-area',
'black-2' => 'route-22-area',
'x' => 'kalos-route-3-area',
)

Related

merge php arrey on action url get request

I have an IP phone that through 2 action urls makes a get request to my web server.
action urls:
http://192.168.25.126/action.php?ID=$call_id&remote=$display_remote
http://192.168.25.126/action.php?ID=$call_id&extension=$active_user
192.168.25.126 is the web server
action.php is printing to a log file the request
$call_id is a unique ID that the phone is giving to the current session
$remote is the caller's number
$extension is the ip phone extension number
on the server side I have the action.php that prints in a log file the requests through this simple line
<?php
file_put_contents("/tmp/post.log",print_r($_GET,true), FILE_APPEND));
?>
checking the log I can view the expected request
tail -f /tmp/post.log
Array
(
[ID] => 9
[remote] => +39123456789
)
Array
(
[ID] => 9
[extension] => 235
)
How can I merge in tmp.log the arreys with same ID like this?
Array
(
[ID] => 9
[remote] => +39123456789
[extension] => 235
)
pay attention that the first arrey is generated on the ringing event and the second arrey is generated when I pickup the phone(or better to say when a call in enstablished)so in a second moment
I cannot do this with only one action url like this
http://192.168.25.126/action.php?ID=$call_id&remote=$display_remote&extension=$active_user
due a limitation of my ip phone so I have to merge the 2 arreys. and if possible I would like,but this is not really necessary, that the log is printed only if the first arrey with same ID exist(so the log will appears only if an incoming call is answered and not when I make a call).
I'm a senior IT not a php coder so just want a suggestion to write the loop.. many thanks
From what I'm understanding this should do what you need - expecting IDs to be unique.
<?php
// get data from log
$fileData = file_get_contents("/tmp/post.log");
$data = json_decode($fileData, true); // make an array out of the json
// $data will now be something like this:
# $data = [["ID" => 9,"remote" => "+39123456789"],["ID" => 10,"remote" => "+41123456789"]];
// mocking input data
# $_GET = ['ID' => 10, 'otherparam' => 'bar'];
$key = array_search($_GET['ID'], array_column($data, 'ID')); // search for pre-saved data
if($key) { // an item with $ID was found -> merge new data
$item = array_merge($data[$key], $_GET);
$data[$key] = $item; // overwrite existing item with this ID
} else {
$item = $_GET; // create a new item, since we haven't found one
$data[] = $item; // append to data
}
file_put_contents("/tmp/post.log",json_encode($data,true))); // don't append, write the whole dataset
If the IDs are not unique, we could just grab the last added one (via end(), check if IDs match and merge there:
end($data); // set pointer to the end
$key = key($data); // get the key of the last element
if($data[$key]['ID']==$_GET['ID']) {
$item = array_merge($data[$key], $_GET); // merge old and new data
$data[$key] = $item; // overwrite item
}
EDIT:
If you only need the last call, we don't need to re-save the non-matching arrays, so this adapted code should do:
<?php
$fileData = file_get_contents("/tmp/post.log");
$data = json_decode($fileData, true);
// $data will now be something like this:
# $data = ["ID" => 9,"remote" => "+39123456789"]; // note, this time it's a one-dimentional (but assoc) array.
// mocking input data
# $_GET = ['ID' => 9, 'otherparam' => 'bar'];
// check if we have pre-saved data, that has an 'ID' and that matches our current one:
if(is_array($data) && isset($data['ID']) && $data['ID']==$_GET['ID']) { // the saved $ID was found -> merge new data
$data = array_merge($data, $_GET);
} else {
$data = $_GET; // create a new item, since we haven't found one
}
file_put_contents("/tmp/post.log",json_encode($data,true))); // don't append, write the whole dataset
Disclaimer: This code has no error checking whatsoever and will throw errors on a blank log (because json_decode will fail if there's no data yet), has some security issues (using $GET without sanitizing and writing that to a file...), doesn't test for proper input (what if no ID is sent), etc...

how to get API data from nested array by php

I want to get the data from array inside array as per the below code :
{"address":"0x64890972513558cb4e4b4a7f8af48d892fd097b7","ETH":{"**balance**":0,"totalIn":0,"totalOut":0},"countTxs":0,"tokens":[{"**tokenInfo**":{"**address**":"0xad640689e6950b7453729a4686edb3fdfd754616","**name**":"CIChain","decimals":"18","symbol":"CIC","totalSupply":"3000000000000000000000000000","owner":"0xecb64b92ffb5179b47c87d2f105d6eeebb132c68","lastUpdated":1527246490,"issuancesCount":0,"holdersCount":31528,"**price**":false}
i'm using this steps but I couldn't continue :
$address = "0x64890972513558cb4e4b4a7f8af48d892fd097b7"; //$_POST['address'];
$scan_url = 'https://api.ethplorer.io/getAddressInfo/'.$address.'?apiKey=freekey';
$scan_json = file_get_contents($scan_url);
$scan_array = json_decode($scan_json, true);
foreach($scan_array['tokens'] as $key => $eth) {
foreach($eth['tokenInfo'] as $key => $etth) {
echo $etth['name'];
}}
I want to retrieve the marked date by stars ** into echo in php so how can I get the nested data.
According to your url given you need to change you code like below
$scan_array = json_decode($scan_json, true);
foreach($scan_array['tokens'] as $key => $eth) {
echo $eth['tokenInfo']["name"]. "\n";
}
Live demo
Second foreach is giving all element from tokenInfo so either no need to use inner foreach or to get all element no need to use like $etth['name'] this, only $etth will give is enough.

undefined index in multidimensional array

I'm using amazon products API.
$ItemAttr = $Item['ItemAttributes'];
Now $ItemAttr contains a multidimensional array.
if(is_array($ItemAttr["Author"])){$Author = implode(", ", $ItemAttr["Author"]);
}else{
$Author = $ItemAttr["Author"];}
Now when i use the above code i'm getting Undefined index: Author in line 1 and line 3
I tried like this
if(isset($ItemAttr["Author"])) {
if(is_array($ItemAttr["Author"])){$Author = implode(", ", $ItemAttr["Author"]);
}else{
$Author = $ItemAttr["Author"];}
}
It eliminates that error.
But later, When I use code like this $RetVal = array( 'Author' => $Author); i'm getting Undefined variable : Author error
Can anyone tell me the proper way?
Please note: $Item['ItemAttributes']; may or may no contain Author key. I mean if the returned product is a book, the array will return author key. Else it will not..
Initialize the empty variable $Author on top?
$Author = ""; //initialize here
if(isset($ItemAttr["Author"]))
{
if(is_array($ItemAttr["Author"]))
{
$Author = implode(", ", $ItemAttr["Author"]);
}
else
{
$Author = $ItemAttr["Author"];
}
}
I implemented the amazon books api just last month and i remember this exact same problem. How lucky are you as i never had me to help :(
Amazon is very annoying because there is no consistency within their returned structure (well, except for what's below, but that makes it annoying to consume):
if one item is returned, it's an OBJECT
if multiple items are returned, it's an ARRAY
if nothing is returned, NOTHING exists at all
Personally i think they should have used empty arrays at least, and stick to arrays. You can always add objects to arrays >< but at least the structure would be consistant.
The way i got around it, was to create a new representation of the returned structure which GUARANTEED that everything was an array and that the WHOLE STRUCTURE was pre-defined. This way i could later access the data knowing 100% that it won't give me errors like it doesn't exist or is being accessed as an object when it is an array.
First, create the structure how you want it to be such as:
$structure = array(
'isbn' => '',
'authors' => array(),
'pictures' => array(),
'title' => ''
);
Then create a function or object method (depending on your style) to consume the amazon data returned and find what it can and insert it into your custom structure.
Remember to check that first it exists, and then if it is an array or an object so you know how to access it. It helps to print out a few returned results from amazon with a few different books.
Then, to access details about the book, you can rely on the data in the $structure ;) everything is an array, and everything is guaranteed to exist so doing:
foreach ($structure['authors']...
Won't produce an error that its not an array, doesn't exist or is in fact an object!!!
The sort of pseudo code would be:
$returned_amazon_data = get_amazon_data('http://amazon.com/api/book=1234567');
$book = consume_amazon_result($returned_amazon_data);
if ($book) {
//print out the authors, if no authors were found, will just stay blank as it's GUARANTEED to always be an array of strings
print implode($book['authors']);
}
Have fun! I know i did(nt)...
You can combine your two conditional statements, as well as predefine $Author:
$Author = '';
if(isset($ItemAttr["Author"]) && is_array($ItemAttr["Author"])){
$Author = implode(", ", $ItemAttr["Author"]);
}elseif(isset($ItemAttr["Author"])){
$Author = $ItemAttr["Author"];
}
this should eliminate both errors.

Build a json in php from POST data

I need to update a json list of object via url post data. For example, with url:
http://myweb.com/index.php?name=Peter&surname=Brown
in php, using get method:
$name = $_GET["name"];
$surname = $_GET["surname"];
$json = array();
$json["nombre"] = $name;
$json["lat"] = $lat;
$data[] = $json;
$json_end= json_encode($data);
and json_end efectively is done like I want:
[{"name":"Peter","surname":"Brown"}]
My question is about how I can do it incrementing the json, in order to build an array like:
[{"name":"Peter","surname":"Brown"}]
[{"name":"newname","surname":"newsurname"}]
// and so on
each time user use the url with new parameters.
Do I need to write to a file, or to database? Any tips will be apreciated.
The idea is to be able that any user can add some dat using url. I tried to store the json to a fiel but the storing is durable only along the current session.
<?
/* This needs to be at the top of your file, without ANYTHING above it */
session_start();
/* ... */
if(!array_key_exists('entries', $_SESSION))
{
$_SESSION['entries'] = array();
}
$_SESSION['entries'][] = array("name" => $_GET["name"], "surname" => $_GET["surname"]);
$json_string = json_encode($_SESSION['entries']);
This would produce a single JSON. However I don't know whether you meant to or not, but your output is a series of separate JSONs. You could do this by replacing the last line above with:
$json_string = '';
foreach($_SESSION['entries'] as $entry){
$json_string.= json_encode($entry) . "\n";
}
You would also probably want a way to reset/empty the array. In which case I'd change the if test from:
if(!array_key_exists('entries', $_SESSION))
to:
if(!array_key_exists('entries', $_SESSION) || array_key_exists('reset', $_GET))
Which you could use by visiting
http://myweb.com/index.php?reset
Edit: If somewhere you add the following code:
foreach($_SESSION['entries'] as $id=>$entry){
printf("%2d: %s\n", $id, json_encode($entry));
}
You'll get a list of the json elements enumerated by their respective keys. For example, it might look like:
0: "[{\"name\":\"Peter\",\"surname\":\"Brown\"}]"
1: "[{\"name\":\"newname\",\"surname\":\"newsurname\"}]"
2: "[{\"name\":\"George\",\"surname\":\"Washington\"}]"
3: "[{\"name\":\"John\",\"surname\":\"Adams\"}]"
If you then add the following code:
if(array_key_exists('del', $_GET) && is_numeric($_GET['del']))
{
$key = (int)$_GET['del'];
if(array_key_exists($key, $_SESSION['entries']))
{
unset($_SESSION['entries'][$key]);
}
else
{
printf('<strong>ERROR: $_GET['del'] = %d but $_SESSION['entries'][%d] doesn't exist.</strong>', $key, $key);
}
}
you'll be able to delete individual json entries by specifying id as the del GET parameter.
For example,
http://myweb.com/index.php?del=2
would delete the entry corresponding to '[{"name":"George","surname":"Washington"}]';
And the remaining entries would be:
0: "[{\"name\":\"Peter\",\"surname\":\"Brown\"}]"
1: "[{\"name\":\"newname\",\"surname\":\"newsurname\"}]"
3: "[{\"name\":\"John\",\"surname\":\"Adams\"}]"
4: "[{\"name\":\"Thomas\",\"surname\":\"Jefferson\"}]"
Just make a nested array of users:
$data = array (
0 => array("name"=>"Peter","surname"=>"Brown"),
1 => array("name"=>"newname","surname"=>"newsurname")
);
echo json_encode($data);
// [{"name":"Peter","surname":"Brown"},{"name":"newname","surname":"newsurname"}]
I think it would be easiest to store the data in a session, something like this:
<?php
session_start();
if (isset($_GET['name'])) {
$_SESSION['json'][] = $_GET;
}
echo json_encode($_SESSION['json']);
?>
Edit: You may want to filter the $_GET array before storing it in the session so that you don't store values that aren't meant to be stored.
Edit: Of course, if you want to save this data for more than one session you would need to use files or a database (or perhaps a cookie). It all depends on what you want to do with the information.

Array Sorting Question for News System

I'm currently stuck trying to figure out how to sort my array files. I have a simple news posting system that stores the content in seperate .dat files and then stores them in an array. I numbered the files so that my array can sort them from lowest number to greatest; however, I have run into a small problem. To begin here is some more information on my system so that you can understand it better.
The function that gathers my files is:
function getNewsList() {
$fileList = array();
// Open the actual directory
if($handle = opendir(ABSPATH . ADMIN . "data")) {
// Read all file from the actual directory
while($file = readdir($handle)) {
if(!is_dir($file)) {
$fileList[] = $file;
}
}
}
// Return the array.
return $fileList;
}
On a seperate file is the programming that processes the news post. I didn't post that code for simplicity's sake but I will explain how the files are named. The files are numbered and the part of the post's title is used... for the numbering I get a count of the array and add "1" as an offset. I get the title of the post, encode it to make it file-name-friendly and limit the amount of text so by the end of it all I end up with:
// Make the variable that names the file that will contain
// the post.
$filename = "00{$newnumrows}_{$snipEncode}";
When running print_r on the above function I get:
Array (
[0] => 0010_Mira_mi_Soledad.dat
[1] => 0011_WOah.dat
[2] => 0012_Sinep.dat
[3] => 0013_Living_in_Warfa.dat
[4] => 0014_Hello.dat
[5] => 001_AS.dat
[6] => 002_ASASA.dat
[7] => 003_SSASAS.dat
...
[13] => 009_ASADADASADAFDAF.dat
)
And this is how my content is displayed. For some reason according to the array sorting 0010 comes before 001...? Is there a way I can get my array to sort 001 before 0010?
You can use natcasesort(array) function of php which will sort an array using a "natural order" algorithm and you will get the desired output
HTH.
:Malay
Take the filename and extract the prefix number as integer number:
// $filename has the format: "00{$newnumrows}_{$snipEncode}"
function generateSortKey($filename)
{
$separatorPos = stripos($filename, '_');
$prefix = trim(substr($filename, 0, $separatorPos));
return intval($prefix);
}
Than create an associative array from the list of files, the keys will be used as sortable value later:
function toSortableArray($files)
{
$result = array();
foreach ($files as $filename)
{
$key = generateSortKey($filename);
$value = $filename;
$result[$key] = $value;
}
return $result;
}
and at last use krsort():
$list = getNewsList();
$sortableList = toSortableArray($list);
krsort($sortableList); // after that $sortableList is
// sorted by key in descending order now
FIX: ksort() => krsort()
The issue is with underscore. Always numerical characters get sorted before underscore.
See whether you get the desired result using sort($your_array, SORT_NUMERIC).
For more info, refer PHP Manual for sort
You may also use natcasesort() (as Malay suggested) or natsort(). But both maintain index association.

Categories