Link to home
Start Free TrialLog in
Avatar of mamuscia
mamusciaFlag for United States of America

asked on

How to use PHP bitmasks to assign and de-assign error codes from an array

I have a PHP application that reads an Excel file, then parses through each row and column in the file to determine if the data meets requirements before loading it into a MySQL database.  I'd like to create an array of error codes that I can use to set multiple error messages for a given row.  For example:

$error_codes = array(0 => 'No Errors', 2=>'Column A error msg', 4=>'Column B error msg', 8=>'Column C error msg');

Then as I check each Excel row and column, I'd like to OR the values into a single integer so that I can display all the errors that occurred for that row.  For example, if I find that Row 1, Col A and Col B do not meet requirements, I like to apply both error msg 2 and 4 from the array above.  Then, after all processing I'd like to show all applicable error msgs for that row.  

I know this can work with bitmasks and ORing, but not sure how to structure this.  Also, is there a limit on the number of error codes I can define, and do they have to be divisible by 2?  Can I use 1,2,3,4,5,6,7,8,9,10....etc?  How can I use one variable to store all error codes that occured, and how could I then check the value to determine what error msgs to display?

Thanks for insight and sample code.
SOLUTION
Avatar of Dave Baldwin
Dave Baldwin
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
...easier and much more maintainable to simply store the full values instead of trying to mash them down...
No kidding!  Bitmasks are the stuff of script kiddies and tenured college professors with time to waste.  Just don't do that.  

Here is a better design.  It is a teaching example showing the errors that can arise when you upload files via the PHP POST method.  The PHP script receives a numeric indicator of the error.  As you can see from the array, it is rather easy to produce a meaningful error message.

// LIST OF THE ERRORS THAT MAY BE REPORTED IN $_FILES[]["error"] (THERE IS NO #5)
$errors = array
( 0 => "Success!"
, 1 => "The uploaded file exceeds the upload_max_filesize directive in php.ini"
, 2 => "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"
, 3 => "The uploaded file was only partially uploaded"
, 4 => "No file was uploaded"
, 5 => "UNDEFINED ERROR"
, 6 => "Missing a temporary folder"
, 7 => "Cannot write file to disk"
)
;
/* ... */
// SKIP OVER EMPTY SPOTS - NOTHING UPLOADED
$error_code = $my_uploaded_file["error"];
if ($error_code == 4) continue;
/* ... */
// IF THERE ARE ERRORS
if ($error_code != 0)
{
    $error_message = $errors[$error_code];
    die("Sorry, Upload Error Code: $error_code: $error_message");
}

Open in new window

To add to Ray's sugggestion, you can use either foreach() to loop over all error codes, or you can use in_array() to see if your list of errors contains a specific one:

<?php

$error_code_messages = array(
  0 => "Unable to open the spreadsheet!",
  1 => "Column A had an error!",
  2 => "Column B had an error!",
  3 => "Column C had an error!",
  4 => "Column D had an error!",
);

// Let's say your application triggered errors 1 and 3:
$triggered_errors = array(1,3);

// Show all triggered error messages
foreach($triggerered_errors as $error_code)
{
  echo $error_code_messages[$error_code] . "<br>\n";
}

// Or if you want to check for a specific error code:
if(in_array(0,$triggered_errors))
{
  // 0 = Unable to open the spreadsheet!
  echo $error_code_messages[0];
}
else
{
  // Since 0 is not an error that was thrown/triggered, you can assume the
  // user was able to open the spreadsheet.
}
?>

You can also define constants to use in your code to make it slightly more readable:

<?php
define("ERR_UNABLE_TO_OPEN_SPREADSHEET",0);

if(in_array(ERR_UNABLE_TO_OPEN_SPREADSHEET,$triggered_errors))
{
  // 0 = Unable to open the spreadsheet!
  echo $error_code_messages[0];
}
else
{
  // Since 0 is not an error that was thrown/triggered, you can assume the
  // user was able to open the spreadsheet.
}

?>

I'll slightly disagree with one thing that Ray joke about - bitmasks do have their benefits, but the situations are very limited, like I said before. If you have a situation where you are tracking LOTS of on/off flags, this can be useful. For example, let's say you're building a scheduling application and you want to store an Outlook-like grid that says whether a 15-minute block of time is used up. You might have a string that looks like this:

$scheduleBusyMap = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

That string might indicate that there are no busy blocks of time in a 24-hour period (24 hours divided into four 15-minute blocks).

$scheduleBusyMap = "11011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

That one could indicate the person is busy from 12:00 AM - 12:30 AM, and from 12:45 AM to 1:30 AM.

Now, you could store the above string as either a 96-byte string, or you could store it as a 12-byte number. That's 84 bytes of savings, which doesn't seem like much, but when you consider that it's 84 bytes of savings for every 24 hour period for possibly thousands to hundreds of thousands of users, those savings can add up quickly and increase the performance of a web application by reducing the amount of data that has to be transferred around.

I just wanted to point out that there ARE some limited scenarios where bitmasks can help, but unless you're building an operating system from scratch, they're probably not going to benefit an error-code system.
Bit-masks are essential for scanning keyboards in assembly language because that's the format the data comes in.  But those are also 8-bit microprocessors.  It is a good technique to know but not always to use.
Here is a little demo program that let's you construct a bit-mask and identify the bits in it.
Save it as 'PHPBitMask.php'.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<title>PHP Bit Mask</title>
</head>
<body>
<h1>PHP Bit Mask</h1>
<?php 
if(isset($_POST['submit'])) {
$cbval = 0;
foreach($_POST['cb'] as $value) {
	$cbval += $value;
	}
echo "Total checkbox values = $cbval<br><br>";
echo "Includes...&nbsp;&nbsp;";
if($cbval & 128) echo "128&nbsp;&nbsp;";
if($cbval & 64) echo "64&nbsp;&nbsp;";
if($cbval & 32) echo "32&nbsp;&nbsp;";
if($cbval & 16) echo "16&nbsp;&nbsp;";
if($cbval & 8) echo "8&nbsp;&nbsp;";
if($cbval & 4) echo "4&nbsp;&nbsp;";
if($cbval & 2) echo "2&nbsp;&nbsp;";
if($cbval & 1) echo "1&nbsp;&nbsp;";
echo "<br><br>";
}
 ?>
<form action="PHPBitMask.php" method="POST">
<input type="checkbox" name="cb[]" value="128" />&nbsp;128&nbsp;
<input type="checkbox" name="cb[]" value="64" />&nbsp;64&nbsp;
<input type="checkbox" name="cb[]" value="32" />&nbsp;32&nbsp;
<input type="checkbox" name="cb[]" value="16" />&nbsp;16&nbsp;
<input type="checkbox" name="cb[]" value="8" />&nbsp;8&nbsp;
<input type="checkbox" name="cb[]" value="4" />&nbsp;4&nbsp;
<input type="checkbox" name="cb[]" value="2" />&nbsp;2&nbsp;
<input type="checkbox" name="cb[]" value="1" />&nbsp;1&nbsp;<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Open in new window

Avatar of mamuscia

ASKER

thanks for the sample....i may use it for simplier things (like check boxes), but because my error_codes may be numerous, i've decided to utilize arrays and save the serialized array into the MySQL database.