Foreach while loop php issue - php

I'm trying to display only the names that are not empty from this array on a new line for each. Currently, using this, it is only displaying "$playerName1"'s name 10 times. I'm trying to figure out why it's not actually looping through all 10 playerName's. It seems to only be checking $playerName1.
$z = array($playerName1, $playerName2, $playerName3, $playerName4, $playerName5, $playerName6, $playerName7, $playerName8, $playerName9, $playerName10);
$zCounter = 1;
foreach ($z as $allNames) {
while ($allNames != "" && $zCounter < 11) {
echo $allNames . "<br>";
$zCounter++;
}
}

Your problem is that you are going through the inner while loop for only the first player name. The outer foreach loop should be plenty:
foreach ($z as $playerName) {
if ("" !== $playerName) {
echo $playerName . "<br />";
}
}

Unless you want to output each name 10 times, remove the while loop. You can still check to make sure the name is not empty by using !='' or empty()
<?php
$z = array($playerName1, $playerName2, $playerName3, $playerName4, $playerName5, $playerName6, $playerName7, $playerName8, $playerName9, $playerName10);
foreach($z as $name){
if(!empty($name)){
echo $name.'<br>';
}
}

you need to reset the $zCounter after each while loop
foreach ($z as $allNames) {
while ($allNames != "" && $zCounter < 11) {
echo $allNames . "<br>";
$zCounter++;
}
$zCounter = 0;
}
otherwise after the first while loop finishes, $zCounter will always be 11

Related

regex not working as expected when matching file names with wildcards

I am writing a PHP function that takes an array of file names and removes file names from the array if they do not match a set of criteria input by the user. The function iterates through the array and compares each value to a regex. The regex is formed by inserting variables from user input. If the user didn't specify a variable, regex wildcard characters are inserted in the variable's place. The file names are all very systematic, like 2020-06-N-1.txt so I know exactly how many characters to expect in the file names and from the user input. However, when I run the code, file names that don't match the regex are still in the array. Some non-matching file names are taken out, but many others are left in. Parts of my PHP code are below. Any help is appreciated.
function fileFilter() {
global $fileArray, $fileFilterPattern;
/* The loop starts at 2 and goes to count()-1 because the first 2 elements were removed
earlier with unset */
for ($j = 2; $j < count($fileArray) - 1; $j++) {
if(!(preg_match($fileFilterPattern, $fileArray[$j]))) {
unset($fileArray[$j]);
}
}
return;
}
// If user does not provide a filter value, it gets converted into wildcard symbol
if ($month == '') {
$month = '..';
}
if ($year == '') {
$year = '....';
}
if ($section == '') {
$section = '.';
}
$fileFilterPattern = "/{$year}-{$month}-{$section}-.\.txt/";
/* function only runs if user applied at least one filter */
if (!($month == '..' && $year == '....' && $section == '.')) {
fileFilter();
}
Below I have included an example of how the array contains elements that aren't matches. I obtain my output array using echo json_encode($fileArray);
My input:
month is ""
year is ""
section is "L"
Expected result:
Array contains only files that have L in the section spot (YEAR-MONTH-**SECTION**-NUMBER.txt)
Resulting array:
{"8":"2020-06-L-1.txt","9":"2020-06-L-2.txt","10":"2020-06-L-3.txt","11":"2020-06-L-4.txt","12":"2020-06-L-5.txt","15":"2020-06-N-3.txt","16":"2020-06-N-4.txt","17":"2020-06-N-5.txt","18":"2020-06-N-6.txt","19":"2020-06-O-1.txt","20":"2020-06-O-2.txt","21":"2020-06-O-3.txt","22":"2020-06-O-4.txt","23":"2020-06-S-1.txt","24":"2020-06-S-2.txt","25":"2020-06-S-3.txt"}
The problem is using unset() inside a loop. On the next iteration, the index is no longer the same as it was before you messed with the array using unset(). Sometimes, you deal with this by using array_values(), but in this case it's simpler to just build a second array that has only the values you want. The following code works. I've used array_values() just to take the string that you provided and get the indexes back to normal.
That said, since the "first 2 elements were removed
earlier with unset" you need to run array_values() on the array before you get to this part.
<?php
$str ='{"8":"2020-06-L-1.txt","9":"2020-06-L-2.txt","10":"2020-06-L-3.txt","11":"2020-06-L-4.txt","12":"2020-06-L-5.txt","15":"2020-06-N-3.txt","16":"2020-06-N-4.txt","17":"2020-06-N-5.txt","18":"2020-06-N-6.txt","19":"2020-06-O-1.txt","20":"2020-06-O-2.txt","21":"2020-06-O-3.txt","22":"2020-06-O-4.txt","23":"2020-06-S-1.txt","24":"2020-06-S-2.txt","25":"2020-06-S-3.txt"}';
$fileArray = json_decode($str, true);
$fileArray = array_values($fileArray);
echo '<p>fileArray: ';
var_dump($fileArray);
echo '</p>';
function fileFilter() {
global $fileArray, $fileFilterPattern;
$filteredArray = [];
for ($j = 0; $j < count($fileArray); $j++) {
if(preg_match($fileFilterPattern, $fileArray[$j]) === 1) {
//unset($fileArray[$j]);
array_push($filteredArray, $fileArray[$j]);
}
}
echo '<p>filteredArray: ';
var_dump($filteredArray);
echo '</p>';
//return;
}
$month =='';
$year = '';
// If user does not provide a filter value, it gets converted into wildcard symbol
if ($month == '') {
$month = '..';
}
if ($year == '') {
$year = '....';
}
if ($section == '') {
$section = '.';
}
$section = 'L';
$fileFilterPattern = "#{$year}-{$month}-{$section}-.\.txt#";
echo '<p>fileFilterPattern: ';
var_dump($fileFilterPattern);
echo '</p>';
/* function only runs if user applied at least one filter */
if (!($month == '..' && $year == '....' && $section == '.')) {
fileFilter();
}
?>
The main problem is that the count decreases each time you unset, so you should define the count once. Assuming the -1 and $j = 2 are correct for your scenario:
$count = count($fileArray) - 1;
for ($j = 2; $j < $count; $j++) {
if(!(preg_match($fileFilterPattern, $fileArray[$j]))) {
unset($fileArray[$j]);
}
}
There are others ways where you don't have to assume and then keep track of the keys:
foreach($fileArray as $k => $v) {
if(!preg_match($fileFilterPattern, $v)) {
unset($fileArray[$k]);
}
}
I would get rid of your fileFilter function and use this handy function instead, which will return all items that match the pattern:
$fileArray = preg_grep($fileFilterPattern, $fileArray);

OOP Issue Stopping PHP Functioning & MySQL Data Array Retrieval Issue

Now a very kind StackOverflow use has helped me out with a lot of my issues however there's two remaining probelms with my code before it's ready to go, any ideas would be great as i'm currently screaming at it:
First of all i'm using the following to try and pull data from a MySQL Database, return it as a Numeric Array and Order It By ID. There's 2 items in there and no matter what I do I can only get 1 to display (I need it to display ALL data when the table fills up more):
$query = "SELECT * FROM batch ORDER by ID";
$result = $mysqli->query($query);
/* numeric array */
$row = $result->fetch_array(MYSQLI_NUM);
printf ("%s (%s)\n", $row[0], $row[1]);
?>
Secondly, slightly off topic but this code below was given by a StackOverflow user however I can't get it to work, they've geared it to OOP which is not an area i'm familiar with and no matter what I do to correct the $this-> or public / private it still refuses to work (the aim of the code is to have a number in $userinput which gets checked against the $widgetBatches array for the closest match (i.e. input is 1100 and closest is 1000) this then gets deducted from the input (to leave 100) and the process loops again to check and this time returns 100 as the closest, this process continues until the $userinput reaches 0 or a negative number:
<?php
$userinput = 10000; // Our magic variable - user input
$iterations = 0;
function Widget($userinput)
{
$this->iterations++;
$widgetRequested = $userinput;
$widgetBatches = array("250", "500", "1000", "2000");
echo "Iteration " . $iterations;
echo "<br/>";
echo "Widget requested: " . $widgetRequested;
echo "<br/>";
$closest = GetClosest($widgetBatches, $widgetRequested);
echo "Closest: " . $closest;
echo "<br/>";
$widgetRemaining = $widgetRequested - $closest;
echo "Remainder: " . $widgetRemaining;
echo "<hr/>";
if($widgetRemaining > 0)
{
Widget($widgetRemaining);
}
else
{
echo "The value is now below or equaling zero: " . $widgetRemaining . "!";
}
}
function GetClosest($array, $value)
{
$lowest = null;
foreach($array as $val)
{
if($lowest == null || abs($value - $lowest) > abs($val - $value))
{
$lowest = $val;
}
}
return $lowest;
}
?>
This:
<?php
function Widget($input) {
$currentValue = $input; // Set internal variable from input (Think of this as an initial "remainder")
$i = 0;
$widgetBatches = [250, 500, 1000, 2000]; // Setup batch array
while ($currentValue > 0) { // While the remainder is more than 0
$i++;
echo "Iteration " . $i . "<br/>";
echo "Widget requested: " . $currentValue . "<br/>";
$closest = GetClosest($widgetBatches, $currentValue); // Find the closest value from batch array
echo "Closest: " . $closest . "<br/>";
$currentValue = $currentValue - $closest; // Work out new remainder
echo "Remainder: " . $currentValue . "<hr/>";
}
// Loop will exit when remainder is less than 0
echo "The value is now below or equaling zero: " . $currentValue . "!";
}
function GetClosest($array, $value) {
$result = null; // Innitialise the returned variable in case of failure
foreach($array as $val) { // For every array value, unless stopped
$result = $val; // Set result to current array value
if($value <= $result) break; // Stop foreach loop if value is less than or equal to result
}
return $result; // Return last result from Foreach loop
}
Widget(9000);
?>
Hopefully the comments are useful... I put more detail in than I would usually...
Did you try fetchAll(), I use PDO so not sure, but would suggest you use a while loop, like:
while ($result = $mysqli->query($query));
Or:
foreach($result as $r) then $r['data'];
I'm %100 sure the loop will iterate and pull out every data, which you can send to a table or a list.

PHP testing for a next item

I can't figure out how to test if there's a next item in my array by using the key to test against. I think this is better explained in code. I know there's an easier way, I'm just a noob!
Basically I want to know if there is another item in the array and if so get the ->comp_id value.
for($i=0; $i<count($allcomps); $i++)
{
if($allcomps[$i]->comp_id == $curCompID)
{
$currentIndex = $i;
if($allcomps[$i+1]->comp_id == null )
{
echo "there isn't a next";
}
//echo $allcomps[$currentIndex+1]->comp_id;
}
}
You're already looping through allcomps, so why do you need a check for the next one?
Why not check within the loop?
for($i=0; $i<count($allcomps); $i++) {
if (isset($allcomps[$i]->comp_id) and $allcomps[$i]->comp_id == $curCompID) {
$currentIndex = $i;
}
}
I think a foreach might be even easier:
foreach($allcomps as $i=>$comp) {
if (isset($comp->comp_id) and $comp->comp_id == $curCompID) {
$currentIndex = $i;
}
}

Convert 'if else' statements to a loop in PHP?

How can I convert this into a loop in PHP?
$number = 4; // This number is unknown and can be any number.
if ($number === 1) {
echo $red;
} else if ($number === 2) {
echo $yellow;
} else if ($number === 3) {
echo $orange;
} else if ($number === 4) {
echo $black;
} else if ($number === 5) {
echo $green;
} else if ($number === 6) {
echo $grey;
} else if ($number === 7) {
echo $brown;
} else if ($number === 8) {
echo $blue;
} else if ($number === 9) {
echo $silver;
} else if ($number === 10) {
echo $gold;
} else if ($number === 11) {
echo $white;
}
etc...
Right now the $number can be any number, so I would have to somehow loop through the numbers from 1 to unlimited, until it finds what $number is equal to. In this case, number is equal to 4.
I'm not sure why you want to do it like this, but:
$i = 1;
while ($i !== $number) {
$i++;
}
$int = $i;
To do what you want, you should use an array map, but an switch might do the trick too.
PHP don't actually know 1 = one, so you can't iterate through it with a loop.
You have to provide this mapping to it, be it by switching instead of loads of ifs, or creating an array map.
Why not just create a array of items that are the 'lookup table' in the order need like:
$items = ['item_1', 'item_2', 'item_3', … 'item_n'];
or have a string of items like:
$items = explode('|', 'item_1|item_2|item_3|item_n');
//| being the delemiter or what ever might not occur inside any items
then have your $number (might need to minus 1 to $number if items start with 1 and so on to get correct item) used in the array to get the specific item without a loop like:
//$number = 3
$number--;
echo $items[$number];//echos 'item3'
but it almost seems like you then want something like:
//$number = 3
$items = explode('|', 'red|pink|gold|invisible');
echo ${$items[$number - 1]};
//translates into `echo $gold;`
//echos whatever is in $gold
Reading some of your comments it seems like you might be best off to rethink your logic/variables and use arrays and such instead of possibly hundreds of differently named variables that you have to check every time which can't be converted into a simple loop like you wish it could be. The only other possibly is using variables variables like many, including me, have mentioned but you seem to shoot them down. I wouldn't recommend variables variables personally but it would possibly speed up time without needing to do any looping. To effectively minimize code without the need of many if/elses you need to have logic that is consistent.
I think this is what you mean :
echo ${"file" . $number};
But that is showing variable for $filen, for example : $file1, file2, etc. If you want to make it as number, you can do like this :
echo ${"file" . intToEnglish($number)};
You can make intToEnglish(int $number) yourself or need us for help?
I'm not quite sure why you need to loop this, but if you really need to loop this, you can try this :
$i = 0;
while ($i !== $number) {
$i++;
}
echo ${"file" . intToEnglish($i)};
But, make sure that echo ${"file" . intToEnglish($number)}; is exist or you will go through infinite looping.
-- EDIT --
This is the case with your edited colour variable case. If you want to make it simple (looping), you muse change how your variable assingned. Example :
$colour = array("green","yellow","red","blue","black");
$i = 0;
while ($i !== $number) {
$i++;
}
echo $colour[$i];
Actually that looping is not really necessary until you have process inside it. You can just define it directly like this :
echo $colour[number];
-- EDIT 2 ---
This is with checking things :
while($i <= $number) {
if($i === $number) { echo $colour[number]; }
else { echo 'Checking'. $i; }
}
Loop is completly the wrong construct for your problem.
Use an array like so:
<?php
$number = 2;
$english = array("zero","one","two","three","four");
echo "file" . $english[$number];
?>
displays filetwo
After OP edit all becomes clear -- try:-
<?php
$number = 2;
$red = "crimson";
$clear = "glass";
$yellows = array("gold","lemon","acid","ochre");
$orange = "tangerine";
$black = "charcoal";
$objects = array(&$clear,&$red,&$yellows,&$orange,&$black);
var_dump( $objects[$number] );
?>
outputs:
array(4) { [0]=> string(4) "gold" [1]=> string(5) "lemon" [2]=> string(4) "acid" [3]=> string(5) "ochre" }

Replace value in array doesn't work

I'm going crazy, spent a couple of hours trying different methods in replace values in arrays, but I can't get it to work.
foreach($potentialMatches as $potentialKey)
{
$searchKeywordQuery = "SELECT keyword, id FROM picture WHERE id='$potentialKey'";
$searchKeywords = mysql_query($searchKeywordQuery) or die(mysql_error());
while ($searchKeyWordsRow = mysql_fetch_array($searchKeywords))
{
$keyword = $searchKeyWordsRow['keyword'];
$pictureKeywordArray[$searchKeyWordsRow['id']]['keywords'] = explode(",", $keyword);
$pictureKeywordArray[$searchKeyWordsRow['id']]['match'] = 4;
}
}
foreach($pictureKeywordArray as $key = > $picValue)
{
foreach($picValue['keywords'] as $key = > $picIdValue)
{
if ($picIdValue == $searchIdKey)
{
echo $picValue['match'];
$picValue['match']++;
echo $picValue['match'];
}
}
}
foreach($pictureKeywordArray as $key = > $picValue)
{
echo $picValue['match'];
}
I'm novice as you can see, When I echo the picValue['match'] in the foreach loop it gives me a correct value after "++". But then below when I call the array again it gives me the value of 4 instead of 5 as intended. Thanks in advance for any help with this.
Cause you work with the item copy in first case try $pictureKeywordArray[$key]['match'] instead of $picValue['match']
In that second foreach you need to call it by reference:
foreach($pictureKeywordArray as $key => &$picValue)
{ //^-- `&` makes it by reference
foreach($picValue['keywords'] as $key => $picIdValue)
{
if ($picIdValue == $searchIdKey)
{
echo $picValue['match'];
$picValue['match']++; //now updates what you want it to update
echo $picValue['match'];
}
}
}
foreach works on a copy of the data. You must use a reference to modify the original:
foreach ($foo as $i => &$f)
{
$f++;
}
unset($f); // important to do this if you ever want to reuse that variable later

Categories