adding up sums of multiple variables in php - php

ok
so I have been stuck on this problem for a while and I'm sure there is a more elegant way of doing it.
I have 3 columns in a database -
Stand1 | Stand2 | Stand3
each column will either have a stand number (i.e D30) or 'Not Assigned'
What I need to do is count how many stands have been assigned to that customer.
For example :
D30 | not assigned | not assigned would = 1
D30 | B30 | E30 = 3
The code I have so far is
if ($row["stand1"] == 'Not Assigned') {
$stand1 = '0';
}
else {
$stand1 = '1';
}
if ($row["stand2"] == 'Not Assigned') {
$stand2 = '0';
}
else {
$stand2 = '1';
}
if ($row["stand3"] == 'Not Assigned') {
$stand3 = '0';
}
else {
$stand3 = '1';
}
I then thought I could try and count how many stand were assigned :
$standcount = $stand1 + $stand2 + $stand3
But when I print this out (everything else is in an array so loops through every customer) all I get is the total 3 for every customer.
I tried saving the data into an array like:
$standcount = array($stand1, $stand2, $stand3);
But I get the same result. I thought a foreach loop may work but not sure how to do it.

I would suggest you to:
Set the columns' default value to NULL, so that if no value is provided in an entry you'll have a null value instead of a string (that can contains different letters, as in your case). After that you can simply perform the isset() check against each value.
Use a function to avoid code repetition (the main source of errors), something like:
function check($value) {
return (isset($value)) ? 1 : 0;
}
$stand_1 = check($row["stand1"]);
$stand_2 = check($row["stand2"]);
$stand_3 = check($row["stand3"]);
If you instead want to use a string as "Not Assigned" or "NA", you can perform a case-insensitive check with strcasecmp() between the strings in case, for any reason, a value contains an extra space or a lower-case letter.
In this case the check function would be:
function check($str) {
return (strcasecmp($str, "NA") == 0) ? 0 : 1;
}
$stand_1 = check($row["stand1"]);
$stand_2 = check($row["stand2"]);
$stand_3 = check($row["stand3"]);

Related

Calculate no of fields in MYSQL between two data types

OK weird question.
Table consists of multiple fields. Some with data type int(5) and the rest with datatype int(11)
So lets take a row...
id =>int(5)
var1 =>int(11)
var2 =>int(11)
var3 =>int(11)
var4 =>int(11)
var5 =>int(5)
var6 =>int(11)
var7 =>int(11)
var8 =>int(11)
How can I count the fields in PHP BETWEEN id (int(5)) and var (int(5))
I need to return the values in the fields between using php... but Im stuck. Bad table design doesnt help...but Im stuck with it.
The full scenario is that i need to create an if statement which says, output the name and and data of the int(5) field IF any of the fields between it and the next int(5) contain data
sorry... ugly I know!!!
If run this so far
$sql2 = 'SHOW COLUMNS from services2';
$result2 = getDBResults($sql2, $level, $testing);
$total = count($result2);
$i=2;
while ($i<($total-1))
{
$data = $result2[$i]['Field'];
if ($result2[$i][1]=='int(5)')
{
$html .= '<h2>'.preg_replace('/(?<!\ )[A-Z]/', ' $0', $result2[$i]['Field']).'</h2>';
}
else
{
];
// "$result - This is a seperate query run previously to get the row
if ($result[0][$data] == 1)
{
$html .= '<p>'.preg_replace('/(?<!\ )[A-Z]/', ' $0', $data).'</p>';
}
}
$i++;
}
I have not had a chance to actually test this, so dont beat me up if you need to tweek it a bit to smooth off any rough edges.
But its a fairly standard, if not totally simple, process of processing over the column names result array in a loop and just remembering the last int(5) column name in a variable so you can use it, if and only if, you have found some data in any int(11) column types before seeing the next int(5) column type.
Now I understand why you had trouble explaining what you wanted, I am having the same trouble describing a solution.
Anyway, have a look at this code and see if it makes any sence to you.
$sql2 = 'SHOW COLUMNS from services2';
$columns = getDBResults($sql2, $level, $testing);
$total = count($columns);
$print_column = null;
$found_data = false;
foreach ( $columns as $idx => $column ) {
// skip first 2 columns
if ($idx < 3 ) { continue; }
// first time thru loop so remember the first int5 column name we saw
if ( $column['Type'] == 'int(5)' && empty($print_column) ) {
$print_column = $column['Field'];
$found_data = false;
continue;
}
// found the next int5 column, do we need to print anything
if ( $column['Type'] == 'int(5)' && $found_data ) {
// This is where you would do any output creation,
// I just kept it simple.
echo $result[0][$print_column];
// reset state and the next field that might be printed.
$found_data = false;
$print_column = $column['Field'];
continue;
}
// This may not need to be an if, but just in case you have other field types
// that you are not interested in processing I made it an if.
if ( $column['Type'] == 'int(11)' && ! empty($result[0][$column['Field']]) ) {
$found_data = true;
}
} // endforeach

How to filter foreach array for integers

I have a for-each statement based off a php generated query..
I am trying to figure out how I can make sure all the IDDestinations of the records are the same.
For example in my current query I have 2 records with an IDDestination of 12, one record with an IDDestination of 9 and the last is 3.
I know how to do this in the query but I am trying to generate a message to the user if the IDDestinations are not equivalent.
My code so far.
foreach($results as $row) {
$IDDestination =(int) $row['IDDestination'];
if ($IDDestination == $IDDestination){
echo "<script>alert('All Courses Match Destination.');</script>";
} else {
echo "<script>alert('Courses have different Destinations);</script>";
}
var_dump($IDDestination);
}
This is currently just verifying that each record has an IDDestination Present and tells ME All courses Match.
How can I make it so the INTEGERS are equivalent and give me the same message?
Here's one way; use a variable outside your loop to determine if it's ok or not:
$everything_matches = true;
$id = null;
foreach($results as $row) {
// Set it for the first record.
if($id === null)
$id = $row['IDDestination'];
// If the current iteration's ID matches the first record, $everything_matches
// will stay true, otherwise it's false and we should kill the loop.
if($id != $row['IDDestination']) {
$everything_matches = false;
break;
}
}
// Output your message
$message = $everything_matches ? 'All courses match destination.' : 'Courses have different destinations.';
echo '<script>alert("' . $message . '");</script>';

Logical clean up

I am currently having logical structure errors and I can't seem to think of a proper way of writing it out so it looks clean. Currently, I have a table in my database named USER. User has 6 fields out of the many, named: first, second, third, fourth, fifth, sixth.
What my code does is switch the data with two of the fields. So for example: the data in first is changed with the data in sixth.
Before: First - 1, Sixth - 6
After: First - 6, Sixth - 1
Currently, what I have is something that looks very messy, and I'm not sure how I can clean it up.
if($switch == true){ /* $switch just indicates if the numbers being switched is one of the fields i.e. first, second, etc.. */
if($slot == 1){ // The number is being switched into the first slot
if($first == $number){
return 1; // error, can't switch with itself
} else if ($second == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE SECOND
// 2nd QUERY TO UPDATE THE DATA IN SECOND, WITH THE INFO STORED IN VARIABLE $temp
} else if ($third == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE THIRD
// 2nd QUERY TO UPDATE THE DATA IN THIRD, WITH THE INFO STORED IN VARIABLE $temp
} // ... continues to check for 4, 5, 6...
} else if($slot == 2){ /* Then checks to see if it was slot 2, i.e. Second */
// ....
} else if($slot == 3){ /* Then checks to see if it was slot 3, i.e. Third */
// ....
} else if($slot == 4){ /* Then checks to see if it was slot 4, i.e. Fourth */
// ....
} else if($slot == 5){ /* Then checks to see if it was slot 5, i.e. Fifth */
// ....
} else if($slot == 6){ /* Then checks to see if it was slot 6, i.e. Sixth */
// ....
}
}
It continues for each slot, , 6 times each... I know it's bad programming but I have just started learning PHP (it's my first language, so bear with me). Any suggestions on what I can do to make this cleaner? Or even a better way of writing it? If anyone cares to explain to me over Skype or anything, I would be really grateful. Thank you.
Use a switch statement:
if($switch == true){
switch($slot) {
case 1 :
if($first == $number){
return 1; // error, can't switch with itself
} else if ($second == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE SECOND
// 2nd QUERY TO UPDATE THE DATA IN SECOND, WITH THE INFO STORED IN VARIABLE $temp
} else if ($third == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE THIRD
// 2nd QUERY TO UPDATE THE DATA IN THIRD, WITH THE INFO STORED IN VARIABLE $temp
}
break;
case 2 :
// ....
break;
case 3 :
// ....
break;
case 4 :
// ....
break;
case 5 :
// ....
break;
case 6 :
// ....
break;
default:
// ...
}
}
You will notice a default at the bottom. It's always good to have one in place in case none of your conditions match.
Also notice the break keyword. Without it the code block does not stop at the end and will "fall through" to the next block. This can be handy sometimes but not in your case.
You could do something like this:
// This function returns the column name for the specified slot
function getSlotColumn($slotNum)
{
switch($slotNum)
{
case 1:
retrun "first";
case 2:
return "second";
......
}
}
then in the switching function
// This function swaps the values of the two specified slots
function swapValues($slot1Num, $slot2Num)
{
if($slot1Num == $slot2Num) return;
if($slot1Num < 1 || $slot1Num > 6) return;
if($slot2Num < 1 || $slot2Num > 6) return;
$slot1Col = getSlotColumn($slot1Num);
$slot2Col = getSlotColumn($slot2Num);
//get value of the first slot
$slot1Val = //SELECT $slot1Col FROM ... WHERE ... slot
// Now since we have the value of the first slot, we can update it from the second slot with this pseudo query
//UPDATE ... SET $slot1Col = $slot2Col WHERE ...
// Then update second slot from the value in $slot1Val
//UPDATE ... SET $slot2Col = $slot1Val WHERE ...
}
Then use it like this:
if(switch == true)
{
swapValues(1, 6);
}

PHP prevent double clean url (improvements?)

For a client at work we have build a website.The website has an offering page which can contain variants of the same type/build, so they ran into problems with double clean-urls.
Just now I wrote a function to prevent that from happening by appending a number to the URL. If thatclean url also exists it counts up.
E.g.
domain.nl/product/machine
domain.nl/product/machine-1
domain.nl/product/machine-2
Updated! return $clean_url; on recursion and on return
The function I wrote works fine, but I was wondering if I have taken the right approach and if it maybe could be improved. Here's the code:
public function prevent_double_cleanurl($cleanurl)
{
// makes sure it doesnt check against itself
if($this->ID!=NULL) $and = " AND product_ID <> ".$this->ID;
$sql = "SELECT product_ID, titel_url FROM " . $this->_table . " WHERE titel_url='".$cleanurl."' " . $and. " LIMIT 1";
$result = $this->query($sql);
// if a matching url is found
if(!empty($result))
{
$url_parts = explode("-", $result[0]['titel_url']);
$last_part = end($url_parts);
// maximum of 2 digits
if((int)$last_part && strlen($last_part)<3)
{
// if a 1 or 2 digit number is found - add to it
array_pop($url_parts);
$cleanurl = implode("-", $url_parts);
(int)$last_part++;
}
else
{
// add a suffix starting at 1
$last_part='1';
}
// recursive check
$cleanurl = $this->prevent_double_cleanurl($cleanurl.'-'.$last_part);
}
return $cleanurl;
}
Depending on the likeliness of a "clean-url" being used multiple times, your approach may not be the best to roll with. Say there was "foo" to "foo-10" you'd be calling the database 10 times.
you also don't seem to sanitize the data you shove into your SQL queries. Are you using mysql_real_escape_string (or its mysqli, PDO, whatever brother)?
Revised code:
public function prevent_double_cleanurl($cleanurl) {
$cleanurl_pattern = '#^(?<base>.*?)(-(?<num>\d+))?$#S';
if (preg_match($cleanurl_pattern, $base, $matches)) {
$base = $matches['base'];
$num = $matches['num'] ? $matches['num'] : 0;
} else {
$base = $cleanurl;
$num = 0;
}
// makes sure it doesnt check against itself
if ($this->ID != null) {
$and = " AND product_ID <> " . $this->ID;
}
$sql = "SELECT product_ID, titel_url FROM " . $this->_table . " WHERE titel_url LIKE '" . $base . "-%' LIMIT 1";
$result = $this->query($sql);
foreach ($result as $row) {
if ($this->ID && $row['product_ID'] == $this->ID) {
// the given cleanurl already has an ID,
// so we better not touch it
return $cleanurl;
}
if (preg_match($cleanurl_pattern, $row['titel_url'], $matches)) {
$_base = $matches['base'];
$_num = $matches['num'] ? $matches['num'] : 0;
} else {
$_base = $row['titel_url'];
$_num = 0;
}
if ($base != $_base) {
// make sure we're not accidentally comparing "foo-123" and "foo-bar-123"
continue;
}
if ($_num > $num) {
$num = $_num;
}
}
// next free number
$num++;
return $base . '-' . $num;
}
I don't know about the possible values for your clean-urls. Last time I did something like this, my base could look like some-article-revision-5. That 5 being part of the actual bullet, not the duplication-index. To distinguish them (and allow the LIKE to filter out false positives) I made the clean-urls look like $base--$num. the double dash could only occur between the base and the duplication-index, making things a bit simpler…
I have no way to test this, so its on you, but here's how I'd do it. I put a ton of comments in there explaining my reasoning and the flow of the code.
Basically, the recursion is unnecessary will result in more database queries than you need.
<?
public function prevent_double_cleanurl($cleanurl)
{
$sql = sprintf("SELECT product_ID, titel_url FROM %s WHERE titel_url LIKE '%s%%'",
$this->_table, $cleanurl);
if($this->ID != NULL){ $sql.= sprintf(" AND product_ID <> %d", $this->ID); }
$results = $this->query($sql);
$suffix = 0;
$baseurl = true;
foreach($results as $row)
{
// Consider the case when we get to the "first" row added to the db:
// For example: $row['titel_url'] == $cleanurl == 'domain.nl/product/machine'
if($row['title_url'] == $cleanurl)
{
$baseurl = false; // The $cleanurl is already in the db, "this" is not a base URL
continue; // Continue with the next iteration of the foreach loop
}
// This could be done using regex, but if this works its fine.
// Make sure to test for the case when you have both of the following pages in your db:
//
// some-hyphenated-page
// some-hyphenated-page-name
//
// You don't want the counters to get mixed up
$url_parts = explode("-", $row['titel_url']);
$last_part = array_pop($url_parts);
$cleanrow = implode("-", $url_parts);
// To get into this block, three things need to be true
// 1. $last_part must be a numeric string (PHP Duck Typing bleh)
// 2. When represented as a string, $last_part must not be longer than 2 digits
// 3. The string passed to this function must match the string resulting from the (n-1)
// leading parts of the result of exploding the table row
if((is_numeric($last_part)) && (strlen($last_part)<=2) && ($cleanrow == $cleanurl))
{
$baseurl = false; // If there are records in the database, the
// passed $cleanurl isn't the first, so it
// will need a suffix
$suffix = max($suffix, (int)$last_part); // After this foreach loop is done, $suffix
// will contain the highest suffix in the
// database we'll need to add 1 to this to
// get the result url
}
}
// If $baseurl is still true, then we never got into the 3-condition block above, so we never
// a matching record in the database -> return the cleanurl that was passed here, no need
// to add a suffix
if($baseurl)
{
return $cleanurl;
}
// At least one database record exists, so we need to add a suffix. The suffix we add will be
// the higgest we found in the database plus 1.
else
{
return sprintf("%s-%d", $cleanurl, ($suffix + 1));
}
}
My solution takes advantage of SQL wildcards (%) to reduce the number of queries from n down to 1.
Make sure that you ensure problematic case I described in lines 14-20 works as expected. Hyphens in the machine name (or whatever it is) could do unexpected things.
I also used sprintf to format the query. Make sure you sanitize any string that is passed through as a string (e.g. $cleanurl).
As #rodneyrehm points out, PHP is very flexible with what it considers a numeric string. You might consider switching out is_numeric() for ctype_digit() and see how that works.

Categorizing non-ID categories PHP loop

On my project there're various search results of different content-types. For unimportant reasons, not all content-types carry a unique ID. However, I tried to write this loop that will detect IDless content-types, and will give them a unique ID.
Basically, the results look like this:
Category ID 3
Category ID 3
Category ID 4
NON-ID Category 1
NON-ID Category 2
[...]
I tried this:
$current = $result->section;
// if there's a category ID -- use it
if ($current != null) echo $result->sectionid;
else
// if this is the first IDless category -- initialize. this happens once.
if ($virginity == true) {
$store = $current;
$virginity = false;
}
// if initialized and current category string is the same as stored category string -- print it
if (($virginity == 0) && ($store = $current)) {
echo $defaultID;
}
// if initialized and current category string is different from the stored category string -- set new default category +1 and print it
if (($virginity == false) && ($store != $current)) {
$defaultID = $defaultID++;
echo $defaultID;
$store = $current;
}
Can you see where I'm going here?
Trying to give each new category that comes up in the search results a unique ID, on the next loop session - check if the category string is same as the previous one, if so -- use the same ID, else -- bump ID by 1, print the new ID and store a new category.
However: This doesn't work properly.
Why?
Your code is a little tough to read, but a big red flag I see is this block:
//You have a single equals sign here v
if (($virginity == 0) && ($store = $current))
{
echo $defaultID;
}
That means that as long as $virginity==0, that line will always be run, and $store will always equal $current.
By the way, I'm going to recommend some reformatting and readability suggestions. Take them or leave them , though, it's just my opinion.
$current = $result->section;
if ($current != null)
{//if one of the results has brackets, put brackets on both
echo $result->sectionid;
}
else if ($virginity == true)
{// if this is the first IDless category -- initialize. this happens once.
$store = $current;
$virginity = false;
}
//you're setting $virginity=false or true, so doing !$virginity makes sense
// if it was actually a number, then comparing to 0 is better
// also, use parentheses only where really needed, otherwise it's just clutter
if (!$virginity && $store == $current)
{
echo $defaultID;
}
if (!$virginity && $store != $current)
{// if initialized and current category string is different from the stored category string -- set new default category +1 and print it
$defaultID = $defaultID++;
echo $defaultID;
$store = $current;
}

Categories