This is a brilliant little trick if I can get it to work - I have hundreds data columns from dozens of tables spread across a dozen data forms (they are HTML print forms) and they are all html with embedded php variables. Very normal. However the customer had a requirement to know what field went in where - a very good question.
So what did I do? I worked on a solution that allows the key'd arrays from the database to give up their column names. a brilliant move! except I need to do it via variable variables, and guess what, they DON'T work in a foreach loop.
here is the code
if ($_REQUEST['data']=="false"){
$supera = array("RowService", "RowSite", "RowCustomer", "RowEngineer"); //there can be many of these they are key'd arrays $RowService['column_name_1']; is the format
foreach($supera as $super){
foreach(${$super} as $key=>$value){
if (!is_numeric($key)){
${$super}[$key] = "<span style=\"color:pink;\">".$key."</span>";
}
}
}
}
as you can see I want a kill switch easy mechanism to cut and paste the key'd arrays that aren't to show real data any more rather they are to show (in pink) the column name, and (perhaps) the table name too. There is a lot of code already in place and this would be a brilliant option if it can be made to work
EDIT: this is the PHP error:
Warning: Invalid argument supplied for foreach()
EDIT: THE CODE ACTUALLY ALREADY WORKS: FIX IS TO test for is_array()
if(is_array(${$super})) foreach(${$super} as $key=>$value){
will work, as opposed to just
foreach(${$super} as $key=>$value){
I'm not sure what you are trying to achieve but your code (simplified) works just fine:
$a = array("asd", "qwe");
$asd = array("a" => 1, "b" => 2, "c" => 3);
$qwe = array("d" => 4, "e" => 5, "f" => 6);
foreach ($a as $item)
{
foreach ($$item as $key => $value)
{
echo $key . ": " . $value . "<br />";
}
}
Output:
a: 1
b: 2
c: 3
d: 4
e: 5
f: 6
Most likely one of your variables is empty (not an array) and that's why you receive that warning.
Personally, I find variable variables to be a really bad idea. There are a few ways around it.
For example:
$process = array(&$RowService,&$RowSite,&$RowCustomer,&$RowEngineer);
foreach($process as $p) {
foreach($p as $k=>$v) {
$p[$k] = "<span style=\"color:pink\">".$v."</span>";
}
}
Using references means you can affect the original variables.
If the above doesn't work (I'm not that great with references XD), try this:
$process = array($RowService,$RowSite,$RowCustomer,$RowEngineer);
foreach($process as $p) {
foreach($p as $k=>$v) {
$p[$k] = "<span style=\"color:pink\">".$v."</span>";
}
}
list($RowService,$RowSite,$RowCustomer,$RowEngineer) = $process;
As per my understanding of your requirement.
If you want to get table name with pink color then you just need to use below code
$supera = array("RowService", "RowSite", "RowCustomer", "RowEngineer"); //there can be many of these they are key'd arrays $RowService['column_name_1']; is the format
$super = array();
foreach($supera as $key=>$value){
if (!is_numeric($value)){
$super[$value] = "<span style=\"color:pink;\">".$value."</span>";
}
}
print_r($super);
Related
BACKGROUND: I have a database that looks like this.
TITLE ANDROID OS X WINDOWS
World of Goo 1 1 1
Superman 64 GOTY Edition 0 1 1
Seinfeld: The Game 1 0 1
And so on, intended to represent a game collection. There's one varchar column representing the title, and then booleans for each platform.
My desire is to use PHP to turn that database into a page that reads
Super Mario 64 (N64)
World of Goo (Windows, Android)
And so on, just listing off which platforms a title is available for.
PROBLEM: Depending on which solution I use, I either wind up with (Windows) (Android) or (Windows,Android)(Windows,Android)(Windows,Android)(Windows,Android).
Here's what's written.
$q = mysqli_query($c,"SELECT * FROM GAMES");
while ($row = mysqli_fetch_assoc($q)) {
$platforms = array();
foreach ($row AS $column => $value) {
if ($column == "Name") {
echo "<br />" . $value;
continue;
}
if ($value == 1) {
array_push($platforms,$column);
}
if (count($platforms)) {
print_r($platforms);
}
}
}
The intent of this code is
Loop over every item in a row.
If the cell you're on is the name, echo it.
If the cell you're on has a "1" in it, then we own the game for that platform, so store the name of that platform in an array.
At the end of the row, show me that array.
Now here's the problem: if I execute that code, the array is fully-formed, but I don't get one array back, I get one array per column in my database, so it just echoes the platforms back over and over.
If I move line #3 ("$platforms = array();") into the foreach loop, then that problem is avoided, but I don't get one fully-formed array, I get a separate array for each individual platform.
So... where should I be putting that line? I'm messing something simple up with the way I manage that platforms array, but I'm not clever or experienced enough to figure it out. Any help would be fantastic.
This should resolve your issue.
while ($row = mysqli_fetch_assoc($q)) {
$platforms = array();
echo $row['TITLE'];
foreach($row as $column => $val):
$val == 1 ? $platforms[] = $column:;
endforeach;
echo '<pre>', print_r($platforms, true) ,'</pre>';
}
I am trying to organize an array of data to be sent in an email. I have no problem getting the data, but I am not sure how to organize it.
Foreach: Here outputs a list of questions generated by the user in the backend
$message = array();
foreach($questions['questions'] as $key => $value){
if(is_array($value) && isset($value[ 'questionlist'])){
foreach($value as $key => $subquestion){ //line 119
foreach ($subquestion as $key => $value){
$message[] = $value['a-question'];
}
}
}
}
I am trying to conjoin the data with each other, the data from the foreach and the $_POST data which is check values.
My logic for doing it this way is because one comes from the database, one is just form data (that does not need to be saved to the database it comes from the front end unlike the data from the database that is generated via backend) That said there perhaps is a better way, but I pretty much got this I am just not sure how to join the data so it looks like
<li>MYARRAYDATA - MYFORMDATA</li>
<li>MYARRAYDATA - MYFORMDATA</li>
<li>MYARRAYDATA - MYFORMDATA</li>
//The form input data '0', '1' values
$checks = $_POST['personalization_result'];
//Putting that data into array_values
$checkValues = array_values($checks);
//Then passing the array_values into 'implode' and organizing it with a list (<li>)
$checkString = '<li>'.implode('</li><li>',$checkValues).'</li>';
//Then testing with var_dump outputs a nice list of '0','1' values
var_dump ($checkString);
Trying the same method but trying to conjoin the foreach array and the check values does not work, here is an example.
//Similar to $checkValues I pass the data from the foreach into "array_values"
var_dumping this works fine.
$arrayValues = array_values($message);
//This is obvious it's the same as above it "implodes" the data nicely into a list(<li>)
$arrayString = '<li>'.implode('</li><li>',$arrayValues).'</li>';
//This var dumps the "$arrayString" nicely
var_dump ($arrayString)
Again the actual question is here, how do I conjoin each piece of data?
My Attempts: Here are my attempts for "conjoining" the data.
// This does not work well (maybe by cleaning up it can work) but it outputs 2 separate lists
var_dump ($arrayString.'_'.$checkString);
//I tried to run it inside one implode variable this is invalid arguments
$checkString = '<li>'.implode('</li><li>',$arrayValues.'_'.$checkValues).'</li>';
//Modified one implode variable this outputs see below
$checkString = '<li>'.implode('</li>'.$arrayValues.'<li>',$checkValues).'</li>';
<li>Array
1</li>
<li>Array
0</li>
<li>Array
1</li>
<li>Array
0</li>
var_dump results: Here is the var_dump result of each array, I want to combine these into one list
$_POST array
// Var dump of form $_POST DATA
var_dump ($checkString);
//Result
1 //This is generated through the $_POST method not on database
0 //This is generated through the $_POST method not on database
1 //This is generated through the $_POST method not on database
0 //This is generated through the $_POST method not on database
DATABASE array
// Var dump of datbase generated from backend
var_dump ($arrayString);
//Result
I am 1 //This is generated in the backend and is stored on a database
Hi I am 2 //This is generated in the backend and is stored on a database
civil is 3 //This is generated in the backend and is stored on a database
THIS IS FOURTA //This is generated in the backend and is stored on a database
The Goal
I am 1 - 1 //This is checked
Hi I am 2 - 0 //This is NOT checked
civil is 3 - 1 //This is checked
THIS IS FOURTA - 0 //This is NOT checked
The Answer: Thanks to #xdim222
I didn't understand it at first, because of the increment, but now I understand it all, initially it would have worked but my variables were under the foreach statement and that was causing it not to return the array.
At least in my opinion thats what it was, because when I added the variable above the foreach it worked.
I modified the answer to suit my code.
//$messages = array('test1', 'test2', 'test3', 'test4', 'test5');
//Instead of using this array I used the array generated in my foreach above.
// Instead of this $checks = array(1,0,1,0); I take the $_POST value which generates an array, you can see above.
$checkValues = array_values($checks);
$checkString = implode($checkValues);
$i=0;
foreach($messages as $msg) {
echo $msg . ' - ' . ( isset($checkString[$i])? $checkString[$i] : 0 ) . '<br>';
$i++;
}
Again thanks to #xdim222 for being patient, reading my long question, and most importantly helping me learn, by asking this question and finding a solution this stuff really sticks and is in my opinion the best way to learn (by asking). :)
To make it easier, I assign $messages and $checks directly, I have tried this code and it works. You might have different elements of your arrays, but I think you can figure it out from my code below:
$messages = array('test1', 'test2', 'test3', 'test4', 'test5');
$checks = array(1,0,1,0);
$i=0;
foreach($messages as $msg) {
echo $msg . ' - ' . ( isset($checks[$i])? $checks[$i] : 0 ) . '<br>';
$i++;
}
PS: I made a mistake in my previous answer by incrementing $i before echoing things out, array element should start by 0.
While waiting for your reply to my comment above, I'm trying to write some code here..
I assume you want to display the questions that were pulled from database and it should be displayed based on what user chose in the form. So you may use this code:
foreach($questions['questions'] as $key => $value){
if(is_array($value) && isset($value[ 'questionlist'])){
foreach($value as $key => $subquestion){ //line 119
foreach ($subquestion as $key => $value){
$message[$key] = $value['a-question'];
}
}
}
}
I added $key in $message in the code above, with an assumption that $key is the index of a question, and this index will be matched with what user chose in the form. Then we can list all the questions that a user have chosen:
foreach($checks as $check)
echo '<li>'.$check . ' - ' . $message[$check].'</li>';
Is this what you want?
Based on your update:
$i=0;
foreach($message as $msg) {
$i++;
echo '<li>'. $msg . ' - ' . ( isset($checks[$i])? $checks[$i] : 0 ) . '</li>';
}
Maybe this is what you want.
As I said, there should be a relation between the $message and $checks, otherwise the above code looks a bit weird, because how do we know that a question is selected by user? Maybe you should show how you get that $_POST['personalization_result'] in your HTML.
The code below is written mainly using PHP, but I am hoping to speed up the process, and parsing strings in PHP is slow.
Assume the following where I get a string from the database, and converted it into an array.
$data['options_list'] = array(
"Colours" => array('red','blue','green','purple'),
"Length" => array('3','4','5','6'),
"Voltage" => array('6v','12v','15v'),
);
These subarrays will each be a dropdown Select list, an the end user can select exactly 1 from each of the select lists.
When the user hits submit, I will want to match the submitted values against a "price table" pre-defined by the admins. Potentially "red" and "6v" would cost $5, but "red" and "5"(length) and "6v" would cost $6.
The question is, how to do so?
Currently the approach I have taken is such:
Upon submission of the form (of the 3 select lists), I get the relevant price rules set by the admin from the database. I've made an example of results.
$data['price_table'] =
array(
'red;4'=>'2',
'red;5'=>'3',
'red;6'=>'4',
'blue;3'=>'5',
'blue;4'=>'6',
'blue;5'=>'7',
'blue;6'=>'8',
'green;3'=>'9',
'green;4'=>'10',
'green;5'=>'11',
'green;6'=>'12',
'purple;3'=>'13',
'purple;4'=>'14',
'purple;5'=>'15',
'purple;6'=>'16',
'red;3'=>'1',
'red;3;12v'=>'17',
'blue;6;15v'=>'18',
);
Note : The order of the above example can be of any order, and the algorithm should work.
I then explode each of the above elements into an array, and gets the result that matches the best score.
$option_choices = $this->input->post('select');
$score = 0;
foreach($data['price_table'] as $key=>$value)
{
$temp = 0;
$keys = explode(';',$key);
foreach($keys as $k)
{
if(in_array($k, $option_choices))
{
$temp++;
}else{
$temp--;
}
}
if($temp > $score)
{
$score = $temp;
$result = $value;
}
}
echo "Result : ".$result;
Examples of expected results:
Selected options: "red","5"
Result: 3
Selected Options: "3", "red"
Result: 1
Selected Options: "red", "3", "12v"
Result: 17
The current method works as expected. However, handling these using PHP is slow. I've thought of using JSON, but that would mean that I would be giving the users my whole price table, which isn't really what I am looking for. I have also thought of using another language, (e.g python) but it wouldn't particularly be practical considering the costs. That leaves me with MySQL.
If someone can suggest a cheap and cost-efficient way to do this, please provide and example. Better still if you could provide an even better PHP solution to this which works fast.
Thank you!
It looks like you did work to make the results read faster but you're still parsing and testing every array part against the full list? This would probably run faster moving the search to MySQL and having extra columns there.
Since you can control the array (or test string) perhaps try fixed length strings:
$results = explode("\n", "
1 Red v1
22 Blue v2
333 Green v3");
$i = 0;
while($i < count($results)) {
$a = substr($results[$i], 0, 10);
$b = substr($results[$i], 10, 20);
$c = substr($results[$i], strpos(' ', strrev($results[$i]))-1);
if(stripos($userInput, $a . $b . $c) !== false) {
// parse more...
Supposedly JavaScript is good at this with memoizaion:
http://addyosmani.com/blog/faster-javascript-memoization/
I'm currently working on a generic form creation class and had an issue yesterday.
I made a snippet to reproduce the problem.
Essentially I want to delete elements that are grouped from the original elements array after the whole group has been drawn and I'm doing this while looping over the elements array.
The code snippet should cover the problem, am I missing something here? From my knowledge deleting an element while foreach is completely safe and legal since foreach internally only uses a copy that may be modified during the loop.
$ids = array('a' => array(), 'b' => array(), 'c' => array());
$groups['g1'] = array('a', 'c');
foreach($ids as $id => $element) {
//var_dump($ids);
$g_id = '';
// search the id in all groups
foreach($groups as $group_id => $group) {
if(in_array($id, $group)) {
$g_id = $group_id;
break;
}
}
// element is part of a group
if($g_id !== '') {
//echo $g_id;
// element a and c gets unset within loop and should not be in $ids anymore
foreach($groups[$g_id] as $field_id) {
unset($ids[$field_id]);
echo $field_id;
}
unset($groups[$g_id]);
} else {
if($id === 'a' || $id === 'c')
echo $id;
}
}
Element 'c' gets unset within the foreach(groups ..) loop but is afterwards again outputted in the else branch. Also when i var_dump($fields) at the beginning i always get 'a', 'b' and 'c' inside. I'm using PHP 5.4.7.
Thanks in advance
EDIT: i made a mistake in the sample code, its now updated. All comments about using the wrong index (it would have been 0,1 etc) were correct of course.
The values when using var_dump are unset now, but i still get into the else with 'c' one time.
EDIT2:
Im not done with the original code but after reading through the comments I currently came up with following solution to the posted code snippet above:
$ids=array("a"=>array(),"b"=>array(),"c"=>array(),"d"=>array(),"e"=>array());
$groups=array(array("a"),array("c", "e"));
array_walk($groups,function($v,$i)use(&$ids){
$in_both = array_intersect(array_keys($ids),$v);
//var_dump($in_both);
foreach($in_both as $b) {
unset($ids[$b]);
}
});
print_r($ids);
or
$ids=array("a"=>array(),"b"=>array(),"c"=>array(),"d"=>array(),"e"=>array());
$groups=array(array("a"),array("c"));
array_walk($ids,function($v,$i)use(&$ids, $groups){
$in_both = array();
foreach($groups as $g) {
if(in_array($i,$g)) {
$in_both = array_intersect(array_keys($ids),$g);
}
}
foreach($in_both as $b) {
unset($ids[$b]);
}
});
print_r($ids);
Using a foreach does not work for me in this case, because i need to change the $ids array while the loop is iterating over it.
In the very most basic situation a code something like this:
$ids = array('a', 'b');
while(count($ids)) {
array_pop($ids);
echo 'pop';
}
echo 'empty';
Allthough foreach can change the original values from the array it will not change the copy of the array used for the iteration as nl-x already stated.
Thanks to Passerby for the idea of using array_walk for this.
EDIT3:
Updated code snipped once more. The second snipped allthough behaves undefined as well. Deleting elements from an array while iterating over its seems to be a bad idea.
Chris, if I understand correctly, you don't expect 'C' to be outputted in the else branch?
But it should be outputted. Your logic is:
you do foreach ids and start with id 'a'.
then you clear ids a and c from ids and delete the group g1 that contained 'a'. During this step the deleted ids will be outputted, being a and c. (Clearing a and c from ids will have no impact on the foreach($ids as $id) as foreach will continue with the untouched copy even after ids array has been cleared.)
then you do id 'b': it is not found in any group. (actually, there isn't any group left by now anyway)
so for 'b' you enter the else branch. But the if() inside the else branch prevents output
then you do id 'c', which is also not found in any group, because you have already deleted group g1! There are no groups left, remember?
so for 'c' you also enter the else branch. And this time the if() inside the else branch allows the output! The output being just c
So the total output is indeed acc.
It is good to know that a foreach() that continues with a untouched copy even after its elements were cleared, is a specific PHP thing. Other language do no necessarily do the same.
Spent some time reading your code, and I guess your procedure is:
For every element in $ids, check if it exists in some sub-array in $groups;
If it exists, delete everything in $ids that also exists in this sub-array.
Following the above logic, I come up with this:
$ids=array("a","b","c","d","e");
$groups=array(array("a","c"),array("c","e"));
array_walk($groups,function($v,$i)use(&$ids){
$ids=array_diff($ids,$v);
});
print_r($ids);//debug
Live demo
I'm double checking now. But I think unsetting an array with foreach is not really safe.
What I usually would do is take a foreach, and start with the highest indexes and descrease the index along the way. for($i = count($arr)-1; $i >= 0; $i--) { unset($array[$i]); }
I'll edit this post in a few minutes.
edit: i was confused. The for with $i++ is indeed the culprit. foreach is safe (in php! not in all languages)
<?php
$arr = Array(1,2,3,4,5,6,7,8,9,10);
foreach ($arr as $key=>$val)
unset($arr[$key]);
echo implode(',',$arr); // returns nothing
$arr = Array(1,2,3,4,5,6,7,8,9,10);
for ($i=0; $i<count($arr); $i++)
unset($arr[$i]);
echo implode(',',$arr); // returns 6,7,8,9,10
$arr = Array(1,2,3,4,5,6,7,8,9,10);
for ($i=count($arr)-1; $i>=0; $i--)
unset($arr[$i]);
echo implode(',',$arr); // returns nothing
?>
$ids[$field_id] does not exist, you are using the value instead of the key.
You should simply unset using the right key :
if (in_array($field_id, $ids))
unset($ids[array_search($field_id, $ids)]);
If you want to remove the element from the array, shouldn't you 'splice' it out instead with array_splice?
From the PHP manual: http://php.net/manual/en/function.array-splice.php
Your foreach wont make any changes since a copy of array is used.. you will need to use pass by reference in order for this to work. one of the way is mentioned below
while(list($key,$value) = each($array)){
if(your reason to unset)
unset($array[$key]);
}
this will remove the element from the array.
I have a feeling I'm going to get scolded for this but here is the question.
$seq_numbers = range('1', '24');
foreach($seq_numbers as $seq_number)
{
Bullet <?php echo $seq_number;?>
// (this successfully creates - Bullet 1, Bullet 2, etc. -
below is the problem.
<?php echo $db_rs['bullet_($seqnumber)'];?>
} // this one doesn't work.
I've tried
with curly brackets {}
I basically have a few columns that are named same except for number at the end (bullet_1, bullet_2, bullet_3, etc.) and want to get the results using a loop.
Your problem is, that PHP doesn't replace variables inside strings enclosed with single quotes. You need to use $db_rs["bullet_{$seq_number}"] or one of those:
<?php
foreach ($seq_numbers as $seq_number) {
$key = 'bullet_' . $seq_number;
echo $db_rs[$key];
}
Even shorter, but a little less clear:
<?php
foreach ($seq_numbers as $seq_number) {
echo $db_rs['bullet_' . $seq_number];
}
An entirely different approach would be to loop over the result array. Then you don't even need $seq_numbers. Just as an afterthought.
<?php
foreach ($db_rs as $key => $value) {
if (substr($key, 0, 7) == 'bullet_') {
echo $value;
}
}
Oh...and watch out for how you spell your variables. You are using $seq_number and $seqnumber.
<?php echo $db_rs['bullet_'.$seqnumber];?>
why not:
$db_rs['bullet_'.$seqnumber]
If not, what are your fields, and what does a var_dump of $db_rs look like?
try this...
$seq_numbers = range('1', '24');
foreach($seq_numbers as $seq_number)
{
Bullet <?php echo $seq_number;?>
// (this successfully creates - Bullet 1, Bullet 2, etc. -
below is the problem.
<?php echo $db_rs["bullet_($seqnumber)"];?>
} // now it works.