PHP Foreach on MySQLi Result set - php

I have this chunk of code which works on my local XAMPP testing server. The problem is, when pushed to the production server, it breaks. This isn't an issue with the database connection, and PHP/MySQL are both at 5.3 on the production server so it isn't the use of old versions of either. I'm thinking it's the use of the foreach loop instead of the more standard while loop; if it's that, why?
<?php
$res = $mysqli->query('DESCRIBE '.$table);
$columnCount = 0;
echo '<ul>';
foreach($res as $field) {
if(in_array($field["Field"], $sheetData[0])) {
echo '<li>';
//var_dump($field);
echo $field['Field'].' - '.$field['Type'];
echo "</li>\r\n";
$columnCount++;
}
}
echo '</ul>';
?>
EDIT: To clarify, it breaks by not outputting anything at all; when inserting a simple echo statement inside the loop, it seems to not even execute it.
EDIT2: I've added an answer below which goes into slightly more detail about what the problem here actually was and why this code does actually work under certain conditions.

So since I asked this question ages ago I figure I should update it with some additional clarification by saying this: what I did first with the foreach loop does work. The caveat being that it only works in PHP 5.4+ as that's when the mysqli_result class implemented the Traversable interface. This means you can iterate over it using a foreach loop in later versions of PHP.
This change apparently wasn't super well-known at the time I posted my question (mid-2013) likely due to the fact that so many servers across the internet still use 5.3--likely because that's the latest version of PHP available to Ubuntu 12.x--which limits its utility to recently updated servers. But when you're in an environment that supports it this is a totally valid technique to use.

Do this instead:
if ($result = $mysqli->query('DESCRIBE ' . $table)) {
$columnCount = 0;
echo '<ul>';
/* fetch associative array */
while ($field = $result->fetch_assoc()) {
if (in_array($field["Field"], $sheetData[0])) {
echo "<li>$field[Field] - $field[Type]</li>\r\n";
$columnCount++;
}
}
echo '</ul>';
/* free result set */
$result->free();
}

Related

Testing if a combined variable name exists

I am sure this has been asked 100 times but cannot find the form of words to get at the answer either here or on Google.
I have a variable number of messages. They arrive as
$_GET['message1']; $_GET['message2']; $_GET['messageX']; etc
where X can be 1 to 100.
I need to test if they exist and then push them out to a DB. I tried
$i=1;
while (isset(parse_str("message$i")))
{
echo parse_str("output=message$i");
echo "<h1>This is test $output </h1>";
$i++;
}
which does not work. I thought the middle part worked but just re-tested and that is wrong too.
I am new to parse_str(). I thought I understood it and I understand the problem (it is a void function so cannot be used as a test) but cannot work out a solution for getting through the variables.
parse_str parses a string. What do you expect in a string "message$i"?
If you're sure that all your messages come from $_GET, use $_GET:
$i = 1;
while (isset($_GET['message' . $i])) {
echo $_GET['message' . $i];
$i++;
}
But obviously for storing such data, arrays are move convenient.

Possible to overide a foreach variable parameter within itself?

I have made a small script which uses the Twitch API. The API only allows a maximum of 100 results per query. I would like to have this query carry on until there are no more results.
My theory behind this, is to run a foreach or while loop and increment the offset by 1 each time.
My problem however, is that I cannot change the foreach parameters within itself.
Is there anyway of executing this efficiently without causing an infinite loop?
Here is my current code:
<?php
$newcurrentFollower = 0;
$offset=0;
$i = 100;
$json = json_decode(file_get_contents("https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=25&offset=".$offset));
foreach ($json->follows as $follow)
{
echo $follow->user->name . ' (' . $newcurrentFollower . ')' . "<br>";
$newcurrentFollower++;
$offset++;
$json = json_decode(file_get_contents("https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=25&offset=".$offset));
}
?>
Using a While loop:
while($i < $total)
{
$json = json_decode(file_get_contents("https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=25&offset=".$offset));
echo $json->follows->user->name . ' (' . $newcurrentFollower . ')' . "<br>";
$newcurrentFollower++;
$offset++;
$i++;
}
Ends up echoing this (No names are successfully being grabbed):
Here is the API part for $json->follows:
https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschannelfollows
You can use this:
$offset = 0;
$count = 1;
do {
$response = json_decode(file_get_contents(
'https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=100&offset=' . $offset
));
foreach($response->follows as $follow) {
echo $follow->user->name . ' (' . ($count++) . ')' . "</br>";
}
$offset+=25;
} while (!empty($response->follows));
You want to use a while loop here, not just a foreach. Basically:
while (the HTTP request returns results)
{
foreach ($json->follows as $follow)
{
do stuff
}
increment offset so the next request returns the next one not already processed
}
The trickiest part is going to be getting the while condition right so that it returns false when the request gets no more results, and will depend on what the API actually returns if there are no more results.
Also important, the cleanest way would be to have the HTTP request occur as part of the while condition, but if you need to do some complicated computation of the JSON return to check the condition, you can put an initial HTTP request before the loop, and then do another request at the end of each while loop iteration.
The problem is you're only capturing the key not the value. Place it into a datastructure to access the information.
Honestly I find a recursive function much more effective than a iterative/loop approach then just update a datatable or list before the next call. It's simple, uses cursors, lightweight and does the job. Reusable if you use generics on it too.
This code will be in c#, however I know with minor changes you'll be able to get it working in php with ease.
query = //follower object get request//
private void doProcessFollowers(string query)
{
HTTPParse followerData = new HTTPParse(); //custom json wrapper. using the basic is fine. Careful with your cons though
var newRoot = followerData.createFollowersRoot(query); // generates a class populated by json
if (newRoot[0]._cursor != null)
{
populateUserDataTable(newRoot); //update dataset
doProcessFollowers(newRoot[0]._links.next); //recurse
}
}
Anyway - This just allows you to roll through the cursors without needing to worry about indexes - unless you specifically want them for whatever reason. If you're working with generics you can just reuse this code without issue. Find a generic example below. All you need to do to make it reuseable is pass the correct class within the <> of the method call. Can work for any custom class that you use to parse json data with. Which is basically what the 'createfollowerroot()' is in the above code, except that's hard typed.
Also I know it's in c# and the topic is php, with a few minor changes to syntax you'll get it working easily.
Anyway Hope this helped somebody
Generic example:
public static List<T> rootSerialize<T>(JsonTextReader reader)
{
List<T> outputData = new List<T>();
while (reader.Read())
{
JsonSerializer serializer = new JsonSerializer();
var tempData = serializer.Deserialize<T>(reader);
outputData.Add(tempData);
}
return outputData;
}

PHP Foreach Loop Speed

I'm trying to take a list of 40,000 items and run a json request for each item. The process is super slow which I suspect is because each json request is finishing before the next request starts.
$result = mysql_query("SELECT * FROM $tableName");
while($row = mysql_fetch_array($result))
{
checkRank($row['Domain']);
}
checkRank is running something to the effect of:
$json = file_get_contents($jsonurl,0,null,null);
I'm thinking I could run 10 checkRanks at a time to speed the process up? Any other ideas / suggestions?
UPDATE:
For example this loop runs through my array in 27 secs.
for ($i=0; $i<=100; $i++) {
checkRank($domains[$i]);
$i++;
checkRank($domains[$i]);
$i++;
checkRank($domains[$i]);
$i++;
checkRank($domains[$i]);
$i++;
checkRank($domains[$i]);
$i++;
echo "checking " . $i . "<br/>";
}
The loop below takes over 40 seconds with the same array.
for ($i=0; $i<=100; $i++) {
checkRank($domains[$i]);
echo "checking " . $i . "<br/>";
}
Not sure if this will help much because I don't work with PHP but I did find this.
How can one use multi threading in PHP applications
Unless there is something else that you haven't mentioned, the best way to do this would be to do one JSON request and pass your items to it, and get the equal number of results back. That way, you minimize the server response time. I am not sure if you want to send 40,000 items in though, you might want to divide it into 2 parts, but that you can test this later.
so you checkRank() would look something like
function checkRank($domainsArray) {
$json = file_get_contents($jsonurl,$domainsArray);
}
http://www.phpied.com/simultaneuos-http-requests-in-php-with-curl/
This seems to be a nice way to speed up the processing. Thanks for all the input guys.
... it's a shame, I read on Stack Overflow today that PHP could not support threading as it would require fundamental changes to the language ...
https://github.com/krakjoe/pthreads

simple php foreach loop help needed

I have a for each loop like this
$sn_count = 1;
$prodfilter = "";
foreach($prods as $prod){
$prodfilter .= "<div class=\"product\">".$prod['product'][1]."</div>";
$sn_count++;
}
echo $prodfilter;
Now my problem my "product" class displaying border even if the $prod['product'][1] not available. So i would like to test it using if statement.
If (product value available) {
$prodfilter .= "<div class=\"product\">".$prod['product'][1]."</div>";
}
I tried like this.
if(!empty($prod['product'][1])) {
$prodfilter .= "<div class=\"product\">".$prod['product'][1]."</div>";
}
But its not working.
you can try couple of things
try this for a start
if(strlen(trim($prod['product'][$sn_count]))>0) {
$prodfilter .= "<div class=\"product\">".$prod['product'][$sn_count]."</div>";
}
or
if(isset($prod['product'][$sn_count])) {
$prodfilter .= "<div class=\"product\">".$prod['product'][$sn_count]."</div>";
}
The right thing in my opinion would be to check how many rows returned. I'll assume you are using MySQL since you did not specify. Please ask for additional help if you are not using it.
http://www.php.net/manual/en/function.mysql-num-rows.php
if (mysql_num_rows($prods)!=0) {
//Do your code
}
This should check if your query returned more than 0 rows (so it needs to be drawn). Does it fix it?
The right thing to do is to check if it's empty as you tried, but since it fails there obviously is some data there. You could do a var_dump and figure out what and why it is there which probably leads you to the source of the problem.
If by available you mean declared then isset is the right function to use by the way.

PHP EOF showing only one result [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
PHP EOF shows only one result from loop
Hello
Seems like I can not find the solution for such problem.
I am using the following code.
it should display all the results given by the mySQL loop in the EOF.
But it is showing only the first results, nothing else.
What I am doing wrong?
Please help me
function getYiBAdminBanner() {
global $site;
global $dir;
$queryYiBmenu = "SELECT * FROM `(YiB)_cPanel_Menu` WHERE Type = 'top'";
$resultYiBmenu=mysql_query($queryYiBmenu) or die("Errore select menu: ".mysql_error());
$countYiBmenu = mysql_num_rows($resultYiBmenu);
while($rowYiBmenu = mysql_fetch_array($resultYiBmenu)) {
$menu .= "<div id=\"menu\" style=\"display:none;\"><li><img class=\"imgmenu\" src=\"".$site['url'].$rowYiBmenu['linkIcon']."\">".$rowYiBmenu['linkTitle']."</li></div>";
}
if($countYiBmenu <= 0){
$menu = "No Modules Installed";
}
$bannerCode .= <<<EOF
<div style="width:520px; background-color: #EEE; height:30px;">
{$menu}
</div>
EOF;
return $bannerCode;
}
Though this won't fix your issue, I see you are using mysql_fetch_array(). This is rather pointless, as you are doing associative matching afterwards ($rowYiBmenu['linkHref'], for example). It will work for you, but it's a waste of resources, as the results will be loaded in a numeric array as well (making the $rowYiBmenu array twice as large, just wasting memory).
Also, you didn't declare the $menu variable, you just 'added on'. Before the while statement, put $menu = ''; (or anything else that will declare an empty string for that variable).
Lastly, use single quotes around html strings. That way you don't have to keep escaping double quotes for when adding an attribute. For example, the $menu line in the while statement should look like this:
$menu .= '<div id="menu" style="display:none;"><li><img class="imgmenu" src="'.$site['url'].$rowYiBmenu['linkIcon'].'">'.$rowYiBmenu['linkTitle'].'</li></div>';
I'm not sure if I helped you with your problem at all, but I thought this would help you clean up your code a bit (the cleaner the code, the less prone to errors and the easier it is to spot errors).
I have tried helping in the other duplicate question.
i feel you need to implement (learn?) some basic debugging on the data coming from the database. This should be very simple to solve.
I suggest changing your while() code to something like this to help debug whats happening:
while($rowYiBmenu = mysql_fetch_array($resultYiBmenu)) {
print "linkTitle: " . $rowYiBmenu['linkTitle'] ."<BR>";
print "linkHref: " . $rowYiBmenu['linkHref'] ."<BR><BR>";
}
exit;
You should see output of all results from the database (not just the first or last). After establishing that the correct data is being retrieved and looped through. you can get that $menu variable concatenation and $bannerCode + HereDoc EOF code sorted out.

Categories