PHP Looping through JSON data without knowing the numbers of data - php

I am trying to get all images from an image API. It returns a maximum of 500 result at a time and if the result has a next_page field, then I have to grab the value of that field and add it to the URL. The code should continue looping until that field is absent. I used the following code to grab the first two pages:
$key = true;
$link = 'https://url.com/dhj/?prefix=images&type=download';
$json = file_get_contents($link);
$data = json_decode($json, true);
$dataArray = array();
foreach ($data["images"] as $r)
{
array_push($dataArray, array($r["id"], $r["image"]));
}
while($key)
{
if($data["next_page"])
{
$key=true;
$link2 = "https://url.com/dhj/?prefix=images&type=download&next_page=" . $data[$next_page];
$json2 = file_get_contents($link2);
$data2 = json_decode($json2, true);
foreach ($data2["images"] as $r2)
{
array_push($dataArray, array($r2["id"], $r2["image"]));
}
}
else
{
$key=false;
}
}
This should fetch 2000 records but is only fetching 1000 records, so it appears the loop is not working as expected.

So your problem is that you are only fetching twice. The second time, you never check $data2 for a next page, so everything stops. You do not want to keep going like this, or you will need $data3, $data4, etc.
A do/while loop is similar to a while loop, except that it always runs at least once. The condition is evaluated at the end of the loop instead of the beginning. You can use that behaviour to ensure you always get the first page of data, and then use the condition to check if you should keep getting more.
$page = "";
do {
$link = "https://url.com/dhj/?prefix=images&type=download&next_page=$page";
$json = file_get_contents($link);
$data = json_decode($json, true);
foreach ($data["images"] as $r) {
$dataArray[] = [$r["id"], $r["image"]];
}
$page = $data["next_page"] ?? "";
} while ($page);
Note I've got rid of your array_push() call. This is rarely used in PHP because the $var[] syntax is less verbose and doesn't require predeclaration of the array. Likewise, calls to array() have long been replaced by use of array literal syntax.
The expression $page = $data["next_page"] ?? "" uses the null coalesce operator, and is identical to:
if (isset($data["next_page"])) {
$page = $data["next_page"];
} else {
$page = "";
}

Related

PHP getting all files into array issue

I have an small piece of PHP code that needs to put every file in the current directory into an array.
I have done this by making reading the dir with glob() and when it meets another dir it will loop.
My code I have as of now:
<?php
$find = '*';
$result = array();
function find($find)
{
foreach (glob($find) as $entry)
{
$result[] = $entry;
echo $entry.'<br>';
if (is_dir($entry)){
$zoek = ''.$entry.'/*';
find($zoek);
}
}
return $result;
}
print_r(find($find));
?>
When I execute the code the echo print exactly what I want. But the printed array doesn't give me the values I want, it only gives the values in the first dir it will come by then it seems to stop adding the value in the array.
What am I doing wrong?
You need to actually preserve the results you produce in the recursive callings to your function:
<?php
function listNodesInFolder($find) {
$result = [];
foreach (glob($find) as $entry) {
$result[] = $entry;
if (is_dir($entry)) {
$result = array_merge($result, find($entry.'/*'));
}
}
return $result;
}
print_r(find('*'));
Once on it I also fixes a few other issues with your code:
$result should be declared as an array inside your function, that that even if it does not loop you still return an array and not something undefined.
indentation and location of brackets got adjusted to general coding standards, that makes reading your code much easier for others. Get used to those standards, it pays out, you will see.
no need for an extra variable for the search pattern inside the conditional.
a speaking name for the function that tells what it actually does.
you should not name variables and functions alike ("find").
You need to add the result of find() to the array
Edit added array_merge - Cid's idea
<?php
$find = '*';
function find($find)
{
$result = array();
foreach (glob($find) as $entry)
{
$result[] = $entry;
echo $entry.'<br>';
if (is_dir($entry)){
$zoek = ''.$entry.'/*';
$result = array_merge($result, find($zoek));
}
}
return $result;
}
print_r(find($find));
?>

PHP json_encode & SQL server callback function returns only one result

I'm trying to set up a PHP callback function for use in our application. It needs to pull data from a SQL server, and while I can get it to work initially, it's not quite doing what I want.
Code:
//Callback function for passing queries
function queryCallback($conn, $query) {
$response = sqlsrv_query($conn, $query);
while ($row = sqlsrv_fetch_array($response)){
if ($row === false) {
die(print_r(sqlsrv_errors(), true));
}
$responseData[] = $row;
}
foreach($responseData as $v) {
$output[key($v)] = current($v);
}
$responseDataJSON = JSON_encode($output, 128);
return $responseDataJSON;
}
In the above, $conn represents our server creds, as passed to sqlsrv_connect(), and $query is the string containing the query passed to SQL. Both have been verified as working.
Issue:
This code contacts the server correctly, and runs the query, but it only returns one result. This is obviously a problem with how the loops are set up, but I just can't spot it
My feeling is that the following $row = sqlsrv_fetch_array($response) is fetching the whole row as an array, but your usage of $output[key($v)] = current($v) is only returning the first column with the same key, and overwriting the $output index with every iteration.
foreach($responseData as $v) {
$output[key($v)] = current($v);
}
lets say you instead perform
foreach($responseData as $k => $v) {
$output[$k] = $v;
}
At which point this is redundant as $responseData[] already is this structure.
You may actually want this if you plan to extract just the first column out of your row.
foreach($responseData as $v) {
$output[] = current($v);
}

list=allpages does not deliver all pages

i have the problem, that i want to fill a list with the names of all pages in my wiki. My script:
$TitleList = [];
$nsList = [];
$nsURL= 'wiki/api.php?action=query&meta=siteinfo& siprop=namespaces|namespacealiases&format=json';
$nsJson = file_get_contents($nsURL);
$nsJsonD = json_decode($nsJson, true);
foreach ($nsJsonD['query']['namespaces'] as $ns)
{
if ( $ns['id'] >= 0 )
array_push ($nsList, $ns['id']);
}
# populate the list of all pages in each namespace
foreach ($nsList as $n)
{
$urlGET = 'wiki/api.php?action=query&list=allpages&apnamespace='.$n.'&format=json';
$json = file_get_contents($urlGET);
$json_b = json_decode( $json ,true);
foreach ($json_b['query']['allpages'] as $page)
{
echo("\n".$page['title']);
array_push($TitleList, $page["title"]);
}
}
But there are still 35% pages missing, that i can visit on my wiki (testing with "random site"). Does anyone know, why this could happen?
MediaWiki API doesn't return all results at once, but does so in batches.
A default batch is only 10 pages; you can specify aplimit to change that (500 max for users, 5,000 max for bots).
To get the next batch, you need to specify the continue= parameter; in each batch, you will also get a continue property in the returned data, which you can use to ask for the next batch. To get all pages, you must loop as long as a continue element is present.
For example, on the English Wikipedia, this would be the first API call:
https://en.wikipedia.org/w/api.php?action=query&list=allpages&apnamespace=0&format=json&aplimit=500&continue=
...and the continue object will be this:
"continue":{
"apcontinue":"\"Cigar\"_Daisey",
"continue":"-||"
}
(Updated according to comment by OP, with example code)
You would now want to flatten the continue array into url parameters, for example using `
See the more complete explanation here:
https://www.mediawiki.org/wiki/API:Query#Continuing_queries
A working version of your code should be (tested with Wikipedia with a slightly different code):
# populate the list of all pages in each namespace
$baseUrl = 'wiki/api.php?action=query&list=allpages&apnamespace='.$n.'&format=json&limit=500&'; // Increase limit if you are using a bot, up to 5,000
foreach ($nsList as $n) {
$next = '';
while ( isset( $next ) ) {
$urlGET = $baseUrl . $next;
$json = file_get_contents($urlGET);
$json_b = json_decode($json, true);
foreach ($json_b['query']['allpages'] as $page)
{
echo("\n".$page['title']);
array_push($TitleList, $page["title"]);
}
if (isset($json_b['continue'])) {
$next = http_build_query($json_b['continue']);
}
}
}

Php - Foreach returning one value, first or last

If I use return in my function, I will get only one value.
If I use echo, I get all the values. I don't get it.
foreach($matches[0] as $matchbun)
{
$var1 = str_split($matchbun, 34);
$replace_line = "-";
$var_final = str_replace($replace_line, " ", $var1[1]);
$replace_url = array('google.com', '/name/');
$replace_url_with = array('yahoo.com', '/url_');
$url_final = str_replace($replace_url, $replace_url_with, $matchbun);
return ''.ucfirst($url_final).'';
}
Seems that I can't insert the echoes into a database, they appear blank if I run the function.
What to do?
When you have a return the code would not execute further. Generate the whole data, then return that data.
You can either built an array. Like -
$urls= array();
foreach($matches[0] as $matchbun)
{
.....
$urls[]= ucfirst($url_final);
}
return $urls;
Or You can generate a string. Like -
$urls= '';
foreach($matches[0] as $matchbun)
{
.....
$urls.= ucfirst($url_final);
}
return $urls;
Well, if you use return, you'll exit from that function on first iteration.
If you use echo, you are not exiting the function, you are echoing every iteration of the foreach loop.
Take return out of loop. and put data you want to return in a variable. Like this:
foreach($matches[0] as $matchbun)
{
$var1 = str_split($matchbun, 34);
$replace_line = "-";
$var_final = str_replace($replace_line, " ", $var1[1]);
$replace_url = array('google.com', '/name/');
$replace_url_with = array('yahoo.com', '/url_');
$url_final = str_replace($replace_url, $replace_url_with, $matchbun);
$myNewVariable .= $url_final;
}
return $myNewVariable;

Delete from json using php

my Current json code :
{"Results":[{"username":"test","password":"test"},{"username":"test","password":"test"},{"username":"google","password":"test"},{"username":"yahoo","password":"test"},{"username":"hotmail","password":"test"}]}
i want to remove this :
{"username":"google","password":"test"}
from the code using php.
i tried deleting by decoding json to array but cant get it done.
any solution ?
$json_obj = json_decode($json_string);
$unset_queue = array();
foreach ( $json_obj->Results as $i => $item )
{
if ($item->username == "google")
{
$unset_queue[] = $i;
}
}
foreach ( $unset_queue as $index )
{
unset($json_obj->Results[$index]);
}
// rebase the array
$json_obj->Results = array_values($json_obj->Results);
$new_json_string = json_encode($json_obj);
<?php
$JSON = '{"Results":['
. '{"username":"test","password":"test"},'
. '{"username":"test","password":"test"},'
. '{"username":"google","password":"test"},'
. '{"username":"yahoo","password":"test"},'
. '{"username":"hotmail","password":"test"}'
. ']}';
// use json_decode to parse the JSON data in to a PHP object
$jsonInPHP = json_decode($JSON);
// now iterate over the results and remove the one that's google
$results = count($jsonInPHP->Results);
for ($r = 0; $r < $results; $r++){
// look for the entry we are trying to find
if ($jsonInPHP->Results[$r]->username == 'google'
&& $jsonInPHP->Results[$r]->password == 'test'){
// remove the match
unset($jsonInPHP->Results[$r]);
// now we can either break out of the loop (only remove first match)
// or you can use subtract one from $r ($r--;) and keep going and
// find all possible matches--your decision.
break;
}
}
// now that we removed items the keys will be off. let's re-order the keys
// so they're back in-line
$jsonInPHP->Results = array_values($jsonInPHP->Results);
// dump the new JSON data, less google's entry
echo json_encode($jsonInPHP);
Would be how I approach it. I like to avoid foreach(...){} statements when I need to modify the array itself. The above code, by the way, leaves you with:
{
"Results":[
{"username":"test","password":"test"},
{"username":"test","password":"test"},
{"username":"yahoo","password":"test"},
{"username":"hotmail","password":"test"}
]
}
$json = '
{
"Results":[
{"username":"test","password":"test"},
{"username":"test","password":"test"},
{"username":"google","password":"test"},
{"username":"yahoo","password":"test"},
{"username":"hotmail","password":"test"}
]
}';
$arr = json_decode($json, true);
array_filter($arr, function($v) {
return !($v['username'] == 'google' && $v['password'] == 'test');
});
$json = json_encode($arr);
$input='{"Results":[{"username":"test","password":"test"},{"username":"test","password":"test"},{"username":"google","password":"test"},{"username":"yahoo","password":"test"},{"username":"hotmail","password":"test"}]}';
$json = json_decode($input,true);
$match = array('username'=>'google', 'password'=>'test');
unset($json['Results'][array_search($match,$json['Results'])]);
To do it without a foreach but assuming you know the exact values you want to remove
Old question, formatting your JSON differently would help a lot.
Each result entry should have a unique key to identify it.
This makes it easy when needing to remove or update that result.
No reason to iterate over entire JSON this way.
Code would look like this
<?php
$jsonString = '{"Results":{'
.'{"username1":{"username":"google","password":"test1"}}'
.'{"username2":{"username":"yahoo","password":"test2"}}'
.'{"username3":{"username":"msonline","password":"test3"}}'
. '}}';
$jsonInPHP = json_decode($jsonString);
$password = $jsonInPHP["username1"]["pasword"];//Returns test1
$username = $jsonInPHP["username1"]["username"];//Returns google
?>
$myArray=json_decode($theJSONstring);
unset($myArray['Results'][2]);

Categories