PHP How do I loop through pages of this api? - php

So basically I am trying to get the sum of AveragePrice of every single page on this api. Right now it only gets first page the things i've tried have only gotten it to go on an endless loop crashing wamp. Heres my code for 1 page of working.
I am just really unsure how I can get it to loop through pages and get sum of every page.
<?php
function getRap($userId){
$url = sprintf("https://www.roblox.com/Trade/InventoryHandler.ashx?userId=" . $userId . "&filter=0&page=1&itemsPerPage=14");
$results = file_get_contents($url);
$json = json_decode($results, true);
$data = $json['data']['InventoryItems'];
$rap = 0;
foreach($data as $var) {
$rap += $var['AveragePrice'];
}
echo $rap;
}
$userId = 1;
getRap($userId);
?>

You may get better answers by looking into the API you are working with regarding how many pages to look for. You want to loop until you hit the max pages. There should be an value in the result of your request that tells you that you've asked for a page that doesn't exist (ie. no more results). If you can get a total number of results to search for then you could do a for loop with that as your limit.
//Change the function to accept the page number as a variable
function getRap($userId, $i){
$url = sprintf("https://www.roblox.com/Trade/InventoryHandler.ashx?userId=" . $userId . "&filter=0&page=" . $i . "&itemsPerPage=14");
//work out how many pages it takes to include your total items
// ceil rounds a value up to next integer.
// ceil(20 / 14) = ceil(1.42..) == 2 ; It will return 2 and you will look for two pages
$limit = ceil($totalItems / $itemsPerPage);
// Then loop through calling the function passing the page number up to your limit.
for ($i = 0; $i < $limit; $i++) {
getRap($userId, $i);
}
If you cannot get the total number of items, you could loop while a fail state hasn't occured
// look for a fail state inside your getRap()
function getRap($userId, $i) {
if ($result = error) { //you will have to figure out what it returns on a fail
$tooMany = TRUE;
}
}
for ($i = 0; $tooMany !== TRUE ; $i++) {
getRap($userId, $i);
}
Edit: Reviewing my answer, looking for the fail state inside your function is poor form (and won't work because of the scope of the variable in this case). You could pass the variable back and forth, but I'll leave that part up to you.
To get the total, make sure that your function doesn't print the result (echo $rap) but returns it for further use.
Full example
<?php
function getRap($userId, $i){
$url = sprintf("https://www.roblox.com/Trade/InventoryHandler.ashx?userId=" . $userId . "&filter=0&page=" . $i . "&itemsPerPage=25");
$results = file_get_contents($url);
$json = json_decode($results, true);
if ($json['msg'] == "Inventory retreived!") {
$data = $json['data']['InventoryItems'];
$rap = 0;
foreach($data as $var) {
$rap += $var['AveragePrice'];
}
return $rap;
} else {
return FALSE;
}
}
$total = 0;
$userId = 1;
for ($i = 0; $i < 1000 /*arbitrary limit to prevent permanent loop*/ ; $i++) {
$result = getRap($userId, $i);
if ($result == FALSE) {
$pages = $i;
break;
} else {
$total += getRap($userId, $i);
}
}
echo "Total value of $total, across $pages pages";
?>

Related

Pagination for foreach loop

I currently have a method inside my "car class" that display the car:
static function getCars(){
$autos = DB::query("SELECT * FROM automoviles");
$retorno = array();
foreach($autos as $a){
$automovil = automovil::fromDB($a->marca, $a->modelo, $a->version, $a->year, $a->usuario_id, $a->kilometraje, $a->info,
$a->hits, $a->cilindrada, $a->estado, $a->color, $a->categoria, $a->precio, $a->idAutomovil);
array_push($retorno, $automovil);
}
return $retorno;
}
In my index.php I call that function
foreach(car::getCars() as $a){
That allows me to display the info this way ( of course inside the foreach I have a huge code with the details I'll display.
Is there a way to implement a pagination to that thing so I can handle 8 cars per page, instead of showing all of them at the same page?
You can add a $limit and $page parameter on your function so that it will only return a maximum of $limit number of items starting from $limit * $page(or will call it the $offset). You also need to add a function to get the total number of rows you have for automoviles table.
static function getCars($page = 0, $limit = 8){
$offset = $limit * max(0, $page - 1);
//replace this with prepared statement
$autos = DB::query("SELECT * FROM automoviles LIMIT $offset, $limit");
$retorno = array();
foreach($autos as $a){
$automovil = automovil::fromDB($a->marca, $a->modelo, $a->version, $a->year, $a->usuario_id, $a->kilometraje, $a->info,
$a->hits, $a->cilindrada, $a->estado, $a->color, $a->categoria, $a->precio, $a->idAutomovil);
array_push($retorno, $automovil);
}
return $retorno;
}
static function getTotal()
{
//query to get total number of rows in automoviles table
}
In your index.php do this:
foreach(car::getCars((isset($_GET['page']) ? $_GET['page'] : 1)) as $a){
...
}
and add the pagination links.
$total = car::getTotal();
if($total > 8) {
for($i = 1; $i <= intval(ceil(1.0 * $total / $limit)); $i++) {
echo '' . $i . ';
}
}

When using Magento, PDF cuts off after first page

Using Magento with Zend_Pdf and a couple of custom classes that allow for the printing/downloading of PDFs with certain header/table specifications. The problem is that it cuts off after the first page and doesn't create a new page when the items list is more than about 20 items.
This code:
public function getOutput()
{
$this->pages[] = $this->page;
return $this->render();
}
And this code:
$pdf = new PrintPdf();
$pdf->generate($sourceData);
$output = $pdf->getOutput();
echo $output;
Are where I believe the error is happening in. If I change the "return" in the first code to "echo" it will output the correct data to the browser, but when I then try and pass it through the second code, it only puts out one page of data.
Any advice would be appreciated as I have been working on this for about 2 weeks.
UPDATE:
I was told this piece of code:
private function drawLineItems($tableData)
{
$this->drawHeading($this->__('Line Items'));
// Draw table
$this->decOffset(35);
$this->colorLine(cBLUE);
$this->page->setLineWidth(0.5);
$this->page->drawLine($this->pMargin, $this->yOffset, $this->pWidth - $this->pMargin, $this->yOffset);
$this->fontSize(FONT_SMALL);
$this->colorFill(cBLUE);
$this->decOffset(15);
$sum = ($this->pMargin + 10);
for($idx = 0; $idx < sizeof($tableData['heading']); $idx++) {
$pos = $sum;
$this->page->drawText($tableData['heading'][$idx], $sum, $this->yOffset);
$sum += ($tableData['width'][$idx] + 10);
$tableData['width'][$idx] = $pos;
}
$this->decOffset(10);
$this->page->drawLine($this->pMargin, $this->yOffset, $this->pWidth - $this->pMargin, $this->yOffset);
$this->fontSize(8);
$this->colorFill(cLIGHT);
$this->colorLine(cBORDER);
foreach($tableData['rows'] as $row) {
$this->decOffset(15);
$yOffset = $this->yOffset;
for($idx = 0; $idx < sizeof($row); $idx++) {
if ($tableData['heading'][$idx] == 'Description') {
$lines = $this->_breakTextToLines($row[$idx], $tableData['width'][$idx + 1] - $tableData['width'][$idx]);
foreach ($lines as $line) {
$this->page->drawText($line, $tableData['width'][$idx], $yOffset);
$yOffset -= 10;
}
} else {
$this->page->drawText($row[$idx], $tableData['width'][$idx], $this->yOffset);
}
}
$this->decOffset($this->yOffset - $yOffset);
$this->page->drawLine($this->pMargin, $this->yOffset, $this->pWidth - $this->pMargin, $this->yOffset);
}
$this->decOffset(20);
$this->fontSize(FONT_NORMAL);
$this->colorFill(cDARK);
$this->page->drawText($this->__('Grand Total') . ': ' . $tableData['total'], $this->pWidth - 125, $this->yOffset);
}
is probably where the problem is as it doesn't form a new page after a certain number of items. My problem now lies in accomplishing this task. Help would still be appreciated.
I found that adding this code:
if( $this->yOffset < 25){
$this->yOffset = $this->pHeight - 25;
$yOffset = $this->yOffset;
$this->pages[] = $this->page;
$this->page = $this->newPage(Zend_Pdf_Page::SIZE_A4);
$this->fontSize(8);
$this->colorFill(cLIGHT);
$this->colorLine(cBORDER);
}
after
$yOffest = $this->yOffset
in the third part of the code in the question, fixed the problem!

Paging through api - PHP

I am trying to construct a php script that will page through an API. The api return ~25197 XML records. I am able to pass a start_offset and a end_offset to the API which will return a subset of the results.
The challenge I am having is that the for loop is not capturing the remaining records that are not within the 1000.
Example, the current for loop processes the records in blocks of 1000 (0-1000,1001-2000,2001-3000, etc.) I am not able to get the final block - 25,000 to 26,000. The for loop stop processing at 24,000 - 25,000. This leaves me with 197 unprocessed XML results.
<?php
//Set Start and Offset Parameters
$start_offset = 0;
$end_offset = 0;
$items_per_page = 1000;
$number = 0;
$counter = -2;
for ($count=0; $count<=100; $count++) {
$counter++;
//Validate that the counter is not null
if ($number != null){
echo "\n";
echo file_get_contents($static_url . "/sc_vuln_query-compliance.php?start=$start_offset&end=$end_offset&seq=$counter");
}
//Initialize the start and end offset variables
$end_offset = $number+=$items_per_page;
$start_offset = $number-$items_per_page+1;
//We want to start at record 0, reset start_offset back to 0 instead of 1
if($start_offset == 1) {
$start_offset = $number-$items_per_page;
}
// We are at the end of the total records, display the remaining
if ($number>$total_xml_records) {
$counter = $counter+1;
$padding = $end_offset + $items_per_page;
echo "\n";
echo file_get_contents($static_url. "/sc_vuln_query-compliance.php?start=$start_offset&end=$padding&seq=$counter");
break;
}
}
?>
Your code is at least buggy at this line $padding = $end_offset + $items_per_page; - here you raise the end for your last loop by another 1000 and therefor get ?start=25001&end=27000&seq=25.
Try $padding = $total_xml_records; instead, this will get you ?start=25001&end=25197&seq=25.
Anyway your code is quite complicated. Try this:
$total_xml_records = 25197; // index 0 .. 25196
$offset = 0;
$counter = 0;
while ($offset < $total_xml_records) {
echo "\n";
echo $static_url . "/sc_vuln_query-compliance.php?start=".($offset)."&end=".(min($offset+$items_per_page-1, $total_xml_records-1))."&seq=".($counter++);
$offset += $items_per_page;
}

How to exclude MySQL query from my loop (limit unnecessary queries)

I'm asking MySQL for data, but it slows down the whole script. Yet I have no idea how to get this out of a loop. I tried converting it to PHP array but honestly after day of tries I failed.
<?php
$id = '1';
include_once 'include_once/connect.php';
for ($x = 1; $x <= 5; $x++) {
for ($y = 1; $y <= 5; $y++) {
$xy = $x."x".$y;
$pullMapInfo = "SELECT value FROM mapinfo WHERE id='".$id."' AND xy='".$xy."'";
$pullMapInfo2 = mysql_query($pullMapInfo) or die('error here');
if ($pullMapInfo3 = mysql_fetch_array($pullMapInfo2)) {
#some code
} else {
#some code
}
}
}
?>
How to get MySQL query $pullMapInfo2 out of loop to shorten loading it by asking once?
If you want to fire script on your localhost you can c&p whole thing :-)
I'm not sure what you have in your table, but considering you are basically looping through virtually everything in it, I'd say do a single query for the given Id and then sort out what you need from the larger dataset.
Especially if you are always pulling back essentially the complete dataset for each id, there's no reason to even bother with the IN query, just pull it all back into a single PHP array, and then iterate through that as needed.
Use a MySQL IN clause
<?php
$id = '1';
include_once 'include_once/connect.php';
// first we create an array with all xy
$array = array();
for ($x = 1; $x <= 5; $x++) {
for ($y = 1; $y <= 5; $y++) {
$xy = $x."x".$y;
$array[] = $xy;
}
}
$in = "'" . implode("', '", $array) . "'";
$pullMapInfo = "SELECT xy, value FROM mapinfo WHERE id='".$id."' AND xy IN ({$in})";
$pullMapInfo2 = mysql_query($pullMapInfo) or die('error here');
// we create an associative array xy => value
$result = array();
while (($pullMapInfo3 = mysql_fetch_assoc($pullMapInfo2)) !== false) {
$result[ $pullMapInfo3['xy'] ] = $pullMapInfo3['value'];
}
// we make a loop to display expected output
foreach ($array as $xy)
{
if (array_key_exists($xy, $result)) {
echo '<div class="castle_array" style="background-image: url(tiles/'.$result[$xy].'.BMP)" id="'.$xy.'">'. $result[$xy] .'</div>';
} else {
echo '<div class="castle_array" id="'.$xy.'"></div>';
}
echo '<div class="clear_both"></div>';
}
?>

php - while loop is itering double the times expected and nested for loop is iterating 1.5 times more than expected

This script is supposed to to get a multidimensional array and iterate through the values.
The array size is 10 and each element should contain an associative array:
$games[0] => array('foo' => 'bar')
$games[1] => array('foo1' => 'bar1')
etc..
The while loop should iterate 5 times in this example. The for loop should iterate 10 times for each iteration of the while loop.
So I am expecting the echo to be:
countwhile = 5 countfor = 50 totalgames = 50
but im actually getting
countwhile = 5 countfor = 150 totalgames = 150
I believe $games array is not the problem because i have have made that call below before and have used print_r to view the contents and it is as expected.
This whole code is not in a function or class just as is on my index.php page, could the problem be to do with the variable scopes?
$totalruns = 5;
$endindx = 10;
$startindx = 0;
$countwhile = 0;
$countfor = 0;
$totalfilesize = 0;
$totalgames = 0;
$sizeof = 0;
while($totalruns > 0)
{
$games = $feedHandler->getGames($startindx, $endindx);
$sizeof = sizeof($games);
for($i=0; $i<$sizeof; $i++)
{
$totalfilesize += $games[$i]['swf_file_size'];
$countfor++;
}
$startindx += 10;
$endindx += 10;
$totalruns -= 1;
$totalgames += $sizeof;
unset($games);
}
echo'<p>' . ' countwhile = ' . $countwhile . ' countfor = ' . $countfor . '</p>';
problem 1:
$sizeof = sizeof($games)-1;
explain 1:
for($i=0, $sizeof = sizeof($games);$i<=$sizeof;$i++)
the above will execute 11 times is the sizeof($games) is 10
So, either
for($i=1, $sizeof = sizeof($games);$i<=$sizeof;$i++)
or
for($i=0, $sizeof=sizeof($games)-1;$i<=$sizeof;$i++)
problem 2 :
$e = sizeof($games);
explain 2 :
$e = count($games);
...
$e += $e;
If the final size of $games is 50, you just sum it to 100
so, it some kind of logic problem
I know the answer has been accepted, but thought I'd refactor and make this a little more clean.
function retrieveGamesInfo($limit, $start = 0)
{
$feedHandler = new FeedHandler(); // ignore this, just for testing to simluate your call
if ($start > $limit)
throw new Exception("Start index must be within the limit");
$result = Array(
'TotalGames' => 0,
'TotalFileSize' => 0
);
// iterate over the results in groups of 10
$range = $start;
while ($range < $limit)
{
$range_end = $range + 10; // change me to play with the grab amount
if ($range_end > $limit)
$range_end = $limit;
// grab the next 10 entries
$games = $feedHandler->getGames($range,$range_end);
$result['TotalGames'] += count($games);
foreach ($games as $game)
$result['TotalFileSize'] += $game['swf_file_size'];
$range = $range_end;
}
return $result;
}
var_dump(retrieveGamesInfo(50));
based one everything I've read and taken in, this should be a good supplement. The above provides the following result:
array(2) {
["TotalGames"]=>
int(50)
["TotalFileSize"]=>
int(275520)
}
As i said in my comment $e is overwritten at each loop, so what you have in $e at the end is just the last count of elements in $games *2.
Added with ajreal issues this means results are what your code is expected to render :-) and I'm quite sure your last $game is not just 10 elements but 50. Quiet sure... but it's hard to read.

Categories