<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>visual77 &#187; tutorial</title>
	<atom:link href="http://visual77.com/blog/tag/tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>http://visual77.com</link>
	<description>Ramblings from Steve Phillips</description>
	<lastBuildDate>Sat, 10 Sep 2011 21:19:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Setting up dynamic themes on Kohana</title>
		<link>http://visual77.com/blog/2010/04/kohana-dynamic-theme/</link>
		<comments>http://visual77.com/blog/2010/04/kohana-dynamic-theme/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 18:43:22 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[kohana]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://visual77.com/blog/?p=584</guid>
		<description><![CDATA[It&#8217;s been a little over six months since I first began to use Kohana framework for all PHP development, and I thoroughly love the system. The only issue I&#8217;ve had with Kohana is the lack of built in, intuitive support for dynamic themes. I was unable to find an easy method to set up a [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>It&#8217;s been a little over six months since I first began to use <a href="http://visual77.com/blog/tag/kohana">Kohana</a> framework for all <a href="http://visual77.com/blog/tag/php">PHP</a> development, and I thoroughly love the system. The only issue I&#8217;ve had with Kohana is the lack of built in, intuitive support for dynamic themes. I was unable to find an easy method to set up a theme that automatically wraps itself around all pages, while remaining dynamic enough to change certain elements on a page to page basis.</p>
<p>Over the past few days, I have been exploring methods to do this, with the following requirements:</p>
<ul>
<li>Keep <em>all </em>theme files separate from the application</li>
<li>Require <em>no</em> changes to existing controllers and views to implement or change a theme</li>
<li>Allow multiple applications on the same Kohana build to use the same theme</li>
<li>Provide support for cascading themes</li>
</ul>
<p>After a few failed attempts, I have <a href="http://visual77.com/blog/tag/tutorial">found a solution</a> that covers all four requirements and is pretty easy to implement. Of course, it is easier to implement this from the start, but if you have an existing Kohana site, it shouldn&#8217;t be too difficult to integrate this theming setup into the site. <strong>The concept of the theme is simple: create a theme as a module and then  use hooks to implement the theme elements as appropriate.</strong></p>
<p><span id="more-584"></span></p>
<h3>Step 1 &#8211; Enable hooks</h3>
<p>Without hooks, this theming set up won&#8217;t be able to execute at the proper time, and timing is essential. In order to enable hooks, <strong>open up application/config/config.php and change $config['enable_hooks'] to TRUE</strong>. With hooks enabled, all files within a hooks directory are included. This will be the starting point for inserting the theme content around the template.</p>
<h3>Step 2 &#8211; Create a theme folder</h3>
<p>One of my stated goals for the theme was to keep all theme files inside a single folder. This encapsulation allows for very easy modification, copying and replacing of themes. <strong>Make a folder called themes, and a subfolder named after the theme.</strong> This theme folder will operate just like a module folder, containing config, controllers, hooks, views, etc. My directory tree now looks like this:</p>
<pre>/httpdocs
    /application
    /modules
    /system
    /themes
        /visual77
            /config
            /controllers
            /css
            /hooks
            /images
            /views
    /index.php
</pre>
<h3>Step 3 &#8211; Add the theme folder to the list of enabled modules</h3>
<p>In order to use the theme folder just as a module folder, you need to register the folder in the list of modules being used by your application.<strong> Open up application/config/config.php and add the theme folder to your list of modules at the end.</strong> This lets Kohana make full use of the directory.</p>
<pre class="brush:php">$config['modules'] = array
(
    DOCROOT.'themes/visual77',
);</pre>
<h3><strong> </strong><strong>Step 4 &#8211; Create a hook for adding theme content</strong></h3>
<p>The most important step is creating a hook to add your theme content around your template content. You want to let your template proceed as normal, and after completion, add your theme data.</p>
<p>To create hooks in Kohana, just create a file inside your hooks directory. All files in that directory will be loaded automatically. For instance, <strong>make a file called theme.php inside themes/&lt;theme-name&gt;/hooks.</strong></p>
<p>In order to do the theming, the ideal hook to use is <em>system.post_controller</em>. The previous hook, <em>system.post_controller_constructor</em>, is before the controller has executed; the following hook, <em>system</em>.<em>send_headers</em>, is after <em>system.execute</em>, and therefore can&#8217;t manipulate the controller.</p>
<p>The goal is then to create a hook on <em>system.post_controller</em> and manipulate the controller to take the template data and move it within the overall theme. To access the controller, call Kohana::$instance and begin manipulating. My hook file looks like this:</p>
<pre class="brush:php">&lt;?php defined('SYSPATH') or die('No direct access allowed');

// set my hook up to execute at the appropriate time
event::add('system.post_controller', 'visual77_theme');

function visual77_theme() {
    // grab the controller
    $controller = Kohana::$instance;

    // pull the original template aside
    $temp = $controller-&gt;template;
    // replace the template with my theme template
    $controller-&gt;template = new View('visual77/index');
    // put the original template into the content section of my theme
    $controller-&gt;template-&gt;content = $temp;
    // free up some memory by unsetting the temp variable
    unset($temp);
}
</pre>
<h3><strong>Step 5 &#8211; Begin building the theme</strong></h3>
<p>Now that the hook is in place, the only thing left to do is build your theme. In my example, <strong>create an index.php file in themes/&lt;theme-name&gt;/views/&lt;theme-name&gt;</strong>. This index file will contain the wrapper HTML for your theme, leaving the original template to drop neatly inside the content section that you define. When you begin adding css and images, you can keep it inside the theme directory. The usual .htaccess restriction on modules only applies to the module directory, which is why I put the themes outside of the module folder.</p>
<p>While building, remember to keep all theme related content, such as views and controllers, inside the theme directory. This makes the theme ultra portable and easily removed. To change themes, just change the name of the theme from Step 3 to the new theme directory.</p>
<p>In a system like this, you can even cascade themes. One great example of cascading themes is including barebones files like CSS resets and jQuery files. On a current project, I have to build an internal client administration and an external company website. Both use certain shared libraries and both need a CSS reset and jQuery files. Using cascading themes and module sharing, I can blend these two sites very neatly. The file structure for this project looks like this:</p>
<pre>/httpdocs
    /internal_application
    /external_application
    /modules
        /shared_libraries
    /system
    /themes
        /internal_theme
        /external_theme
        /default
    /index.php
</pre>
<p>Both internal and external applications include modules/shared_libraries and themes/default. However, internal_application also includes themes/internal_theme and external_application includes themes/external_theme. A switch statement in index.php dynamically switches the application based on the hostname. In the end, I  have two sites running smoothly in parallel on a single Kohana build.</p>
<h3>Final Thoughts</h3>
<p>Kohana is a fantastic system, but really needs better support for dynamic theming. In my build process for this theming pattern, I tried to emulate the wordpress theme convention, where all theme files are kept clustered and are easily swapped out for a new theme.</p>
<p>To see a full theme example, you can<strong> <a href="http://visual77.com/blog/wp-content/uploads/2010/04/visual77.zip">download my Sample Kohana Theme</a></strong> and then modify it to fit your needs. Just remember to enable hooks and include this theme as a module!</p>
<div class="shr-publisher-584"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2010/04/kohana-dynamic-theme/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to flatten an array in PHP</title>
		<link>http://visual77.com/blog/2010/03/php-flatten-array/</link>
		<comments>http://visual77.com/blog/2010/03/php-flatten-array/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 23:57:18 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[kohana]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://visual77.com/blog/?p=577</guid>
		<description><![CDATA[In a recent Kohana project, I came across a somewhat odd PHP scenario &#8211; I had a multidimensional array that I needed to compress to a single dimensional array, but retaining all of the non array values. Basically, I need to make this change: Array ( to =&#62; Array ( 0 =&#62; stevep 1 =&#62; [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>In a recent <a title="Kohana articles" href="http://visual77.com/blog/tag/kohana">Kohana</a> project, I came across a somewhat odd <a title="PHP articles" href="http://visual77.com/blog/tag/php">PHP</a> scenario &#8211; I had a multidimensional array that I needed to compress to a single dimensional array, but retaining all of the non array values. Basically, I need to make this change:</p>
<pre>Array
    (
        to =&gt; Array
            (
                0 =&gt; stevep
                1 =&gt; bobw
            )
        bcc =&gt; Array
            (
                0 =&gt; paulj
            )
    )

Array
    (
        0 =&gt; stevep
        1 =&gt; bobw
        2 =&gt; paulj
    )
</pre>
<p>I looked around a bit for an existing PHP snippet to do just this, but they were all overly complex and used recursive callback functions. I had a feeling I could pull this off in a much more clean fashion. I toyed around a bit with the <a title="PHP:Array Functions" href="http://www.php.net/manual/en/ref.array.php" target="_blank">array functions</a> and the <a title="PHP:ArrayObject" href="http://www.php.net/manual/en/class.arrayobject.php" target="_blank">ArrayObject</a> library, and this is <a title="Tutorials written by Steve Phillips" href="http://visual77.com/blog/tag/tutorial">what I settled with</a>:</p>
<pre class="brush:php">$new_array = new ArrayObject();
array_walk_recursive($old_array, array($new_array, 'offsetSet'));
$flattened_array = array_keys($new_array-&gt;getArrayCopy());
</pre>
<p>The big drawback is the way <a title="PHP:ArrayObject::OffsetSet" href="http://www.php.net/manual/en/arrayobject.offsetset.php" target="_blank">ArrayObect::offsetSet()</a> accepts its parameters, compared to how <a title="PHP:array_walk_recursive" href="http://php.net/manual/en/function.array-walk-recursive.php" target="_blank">array_walk_recursive()</a> sends the callback parameters; they are reversed.  This causes the values to become keys, which has the effect of canceling out duplicate values. If your script needs duplicate values to remain intact, then this solution won&#8217;t work for you. Otherwise, it should work out just fine.</p>
<div class="shr-publisher-577"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2010/03/php-flatten-array/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dealing with PHP and character encoding</title>
		<link>http://visual77.com/blog/2010/02/dealing-with-php-and-character-encoding/</link>
		<comments>http://visual77.com/blog/2010/02/dealing-with-php-and-character-encoding/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 04:05:56 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/blog/?p=567</guid>
		<description><![CDATA[How many times have you been presented with a character encoding glitch on a PHP site that you thought was working properly? You finished the site months ago with no issues, but now you are being told some weird character is showing up on that page? Chances are, that character is either Ã, Â or [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>How many times have you been presented with a character encoding glitch on a <a title="More PHP related articles" href="http://visual77.com/blog/tag/php">PHP</a> site that you thought was working properly? You finished the site months ago with no issues, but now you are being told some weird character is showing up on that page? Chances are, that character is either Ã, Â or Ä, possibly followed by some other random character. If I&#8217;m right, keep reading. If not, I offer my deepest condolences, for you are knee deep in a character encoding issue that I cannot help you with.</p>
<p>So what is it that causes that Ã to show up? In short &#8211; you have UTF-8 encoded data set to display as ISO-8859-1. But the more important question is how to prevent this from happening in the future. The easy answer to that &#8211; store all data in the same format as the final display. Convert the encoding as soon as you receive the data, either through an input field, reading a file or any other method. Don&#8217;t put anything in your <a title="MySQL related articles" href="http://visual77.com/blog/tag/mysql">database</a> unless you are sure it is in the right format.</p>
<p>First, an introduction to the three important character encodings that you are likely to deal with &#8211; ASCII, UTF-8 and ISO-8859-1. Character encoding is, in a nutshell, the exact method that characters are stored and displayed by a computer. Since computers only deal in binary, there must be some way to convert from binary into a character. Character encodings come in two flavors (at least, two flavors I&#8217;ll be discussing) &#8211; single byte and multi byte encodings. Single byte encodings, such as ASCII and ISO-8859-1, use a single byte to represent a character. For instance, the letter &#8220;M&#8221; in ASCII is represented as 0x4D, whereas the number 4 is 0&#215;34.</p>
<p>A single byte is limited to only 256 possible values, which rapidly becomes a limitation when you want to use characters not typically seen in English, such as &#8220;ç&#8221; or &#8220;ß&#8221;, and when you begin thinking about Asian languages, you can quickly see there simply isn&#8217;t room for all characters. Multi byte encodings use one or more bytes to represent a character. Each byte still only has 256 possibilities, but 2 bytes have 65,536 possibilities. But, what if there is confusion as to whether or not you are using single or multi byte encoding? Is that short string &#8220;0x3C 0xA5&#8243; supposed to be the UTF-8 character å or the ISO-8859-1 string ÃÑ? And there we are &#8211; a sudden bug has shown up.</p>
<p>ASCII is the oldest of the three and the most basic. The ASCII character set started out as just 128 characters, and very English-centric. You can see that the basic <a title="ASCII table" href="http://www.asciitable.com/">ASCII table</a> is very restricted to the English speaking world. The extended ASCII table goes off into some weird directions and is rarely used. The full ASCII table is only 256 characters, and thus fits neatly into a single byte, and so it is a single byte encoding.</p>
<p><a title="ISO-8859-1 character listing" href="http://www.pemberley.com/janeinfo/latin1.html">ISO-8859-1</a> is also a single byte encoding, but you can see that it is a bit better in the extended range to support many Latin based languages. Unlike ASCII, ISO-8859-1 can handle the majority of Latin based languages without too much issue. It fails when you go outside of the Latin based languages, however.</p>
<p>The third character encoding is <a title="UTF-8 character table" href="http://www.utf8-chartable.de/unicode-utf8-table.pl">UTF-8</a>, which is designed to support over 1.1 million characters, more than enough for all existing languages (and a few dead ones). Unlike ASCII and ISO-8859-1, UTF-8 is not limited to a single byte, but can vary between 1 and 4 bytes, depending on the character being used.</p>
<p>One thing to take note of is that the first 128 characters of all three encodings are identical. This is why a character encoding issue on an English website can take so long to spot. You can go months not knowing that you have a character encoding issue because the only characters you used were the same in all 3 encodings &#8211; 0x4D is an M in ASCII, UTF-8 and ISO-8859-1.</p>
<p><strong>On to the meat of this article &#8211; dealing with character encodings in PHP. Namely, how to detect and convert encodings.</strong></p>
<p>The magic bullet of dealing with character encodings in PHP can be summed up in three functions &#8211; <a title="PHP documentation" href="http://php.net/mb_detect_encoding" target="_blank">mb_detect_encoding()</a>, <a title="PHP documentation" href="http://php.net/mb_detect_order" target="_blank">mb_detect_order()</a> and <a title="PHP documentation" href="http://php.net/iconv" target="_blank">iconv()</a>. The mb libraries are designed for working with multibyte languages and iconv is a function to convert from one encoding type to another. One nonobvious restriction to the multibyte languages is the lack of native support for ISO-8859-1, since that is a single byte language. mb_detect_order() can be used to specify the order of encodings to scan when attempting to detect an encoding on a string.</p>
<p>The basics of dealing with character encoding conversion in PHP is a simple three step process:</p>
<ol>
<li>Set the encoding types to scan (ASCII, UTF-8, ISO-8859-1). Luckily, this only has to be done once.</li>
<li>Identify the encoding of the string to convert.</li>
<li>Convert to the desired encoding type (I prefer UTF-8).</li>
</ol>
<p>But, let&#8217;s cut to the crap. Sample code!</p>
<pre class="brush:php">// tell the multibyte library which encodings to use
mb_detect_order('ASCII, UTF-8, ISO-8859-1');

// tell the browser that we are using UTF-8
header('content-type: text/plain; charset=UTF-8');

$string = "Fün wîth èñcøding!";

// UTF string displays properly
echo $string . "\r\n";

// convert to ISO-8859-1, which will confuse the browser
$string = iconv(
    mb_detect_encoding($string),
    'ISO-8859-1',
    $string
);
echo $string . "\r\n";

// convert back to UTF-8, which the browser understands
$string = iconv(
    mb_detect_encoding($string),
    'UTF-8',
    $string
);
echo $string . "\r\n";
</pre>
<div class="shr-publisher-567"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2010/02/dealing-with-php-and-character-encoding/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to unchunk data received through PHP sockets</title>
		<link>http://visual77.com/blog/2010/02/how-to-unchunk-data-received-through-php-sockets/</link>
		<comments>http://visual77.com/blog/2010/02/how-to-unchunk-data-received-through-php-sockets/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 18:24:38 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regular expressions]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/blog/?p=554</guid>
		<description><![CDATA[When using the PHP socket functions to pull data from another website, you&#8217;ll often find yourself dealing with chunked data. Chunked data often looks like this: 1e this line is 30 characters lon 2c g, while this line is 44 characters long. an 21 d this line is 33 characters long As you can see, [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>When using the <a href="http://visual77.com/blog/tag/php">PHP</a> socket functions to pull data from another website, you&#8217;ll often find yourself dealing with chunked data. Chunked data often looks like this:</p>
<pre>1e
this line is 30 characters lon
2c
g, while this line is 44 characters long.
an
21
d this line is 33 characters long
</pre>
<p>As you can see, each chunk is preceded by a hex string. This hex string corresponds to the string length of the following chunk. Line breaks are included in the chunk, as you can see in the second chunk. So to unchunk the string, you have to find every hex string that is preceded by, and followed by, a line break (or start of end of string), and if the following block of code is equal in length to the hex value, strip out the hex value.</p>
<p>I accomplished this with a <a href="http://visual77.com/blog/tag/regular-expressions">regular expression</a> and preg_replace_callback. In essence, it finds each block of code that follows this pattern:</p>
<ol>
<li>start of string / hex string on it&#8217;s own line</li>
<li>anything</li>
<li>hex string on it&#8217;s own line / end of string</li>
</ol>
<p>Once it has found all of those patterns, it replaces only the ones where the hex value of #1 is equal to the string length of #2.</p>
<p>My unchunk function:</p>
<pre class="brush:php">function unchunk($result) {
    return preg_replace_callback(
        '/(?:(?:\r\n|\n)|^)([0-9A-F]+)(?:\r\n|\n){1,2}(.*?)'
        .'((?:\r\n|\n)(?:[0-9A-F]+(?:\r\n|\n))|$)/si',
        create_function(
            '$matches',
            'return hexdec($matches[1]) == strlen($matches[2]) ?
                 $matches[2] :
                 $matches[0];'
        ),
        $result
    );
}
</pre>
<div class="shr-publisher-554"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2010/02/how-to-unchunk-data-received-through-php-sockets/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Storing on/off switches through binary representation</title>
		<link>http://visual77.com/blog/2010/01/storing-onoff-switches-through-binary-representation/</link>
		<comments>http://visual77.com/blog/2010/01/storing-onoff-switches-through-binary-representation/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 19:26:34 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[nightlife project]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/blog/?p=502</guid>
		<description><![CDATA[A brief tutorial on how to store a series of on/off switches as binary data, converted to a decimal integer.]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>As part of the Nightlife Project, you will have to store some data through binary representation in the payment_rates table. While doing the writeup on the <a href="http://visual77.com/blog/tag/mysql">MySQL</a> schema, I decided that this section was too large to easily fit inside of that article and it should be its own article. The goal of this article is to explain how database schemas employ the principles of binary notation to store a sequence of on/off flags in a single field.</p>
<p><strong>Imagine this scenario</strong>: You are the head of maintenance at an office and are trying to determine which lightbulbs get the most usage and should be replaced with high efficiency bulbs. In order to determine which gets the most usage, you walk through the building in the morning, at lunch and again at night and make a note of which bulbs are on and which are off. Once you&#8217;ve gathered your data, you store the information in a database and after 2 months, you will view the results and determine the top used bulbs and replace them with higher efficiency bulbs to save electricity.</p>
<p>After each walk through the building, you have a list of lights and a corresponding on/off value for each one. Your list may look something like this:</p>
<table>
<tbody>
<tr>
<td>Reception</td>
<td>Break Room</td>
<td>Bathroom</td>
<td>Office 1</td>
<td>Office 2</td>
<td>Office 3</td>
<td>Office 4</td>
<td>Hallway</td>
<td>Copy Room</td>
</tr>
<tr>
<td>On</td>
<td>Off</td>
<td>Off</td>
<td>Off</td>
<td>On</td>
<td>On</td>
<td>Off</td>
<td>On</td>
<td>Off</td>
</tr>
</tbody>
</table>
<p>The obvious way to store this data is to create a table called &#8216;lights&#8217; and give it 10 fields &#8211; a timestamp (we need to know when this walk through occurred, after all) and a field for each of the 9 rooms. <strong>However, this obvious way has a few nasty shortcomings.</strong> What if you decide to add additional lights to be checked, such as desk lamps or the front walkway? Adding additional fields rarely ends well. This is also extremely inefficient, as you now have an 10 field table when a 2 field table would suffice.</p>
<p>Instead of storing it through this obvious, but inefficient method, instead <strong>you can convert that list of on/off switches into a binary string</strong>. Using the same data above, the binary string would look like this: 100011010. Each of the lights that are on is a 1 and each light that is off is a 0. Each character represents a room &#8211; the first position is reception, the second position is break room, etc. Converting this binary string to decimal, 100011010 becomes 282 (<a title="convert from binary to decimal" href="http://www.wikihow.com/Convert-from-Binary-to-Decimal" target="_blank">why?</a>).</p>
<table>
<tbody>
<tr>
<td>Reception</td>
<td>Break Room</td>
<td>Bathroom</td>
<td>Office 1</td>
<td>Office 2</td>
<td>Office 3</td>
<td>Office 4</td>
<td>Hallway</td>
<td>Copy Room</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>The key thing behind storing binary information in a database is this: <strong>no other combination of binary will equal that number</strong>. There is simply no other set of on/off values that will add up to 282. This lets us store an infinite amount of on/off values in a single integer slot, without ambiguity and always available for reading. As far as how you will read it, look into your language&#8217;s &#8220;bitwise and&#8221; and &#8220;bitwise or&#8221; operators. An example in <a href="http://visual77.com/blog/tag/php">PHP</a> would be:</p>
<pre class="brush:php">$user_permission = 6; // binary 0110

$view            = 1; // binary 0001
$edit            = 2; // binary 0010
$create          = 4; // binary 0100
$delete          = 8; // binary 1000

if($user_permission &amp; $view)
    echo 'user can view';

if($user_permission &amp; $edit)
    echo 'user can edit';

if($user_permission &amp; $create)
    echo 'user can create';

if($user_permission &amp; $delete)
    echo 'user can delete';</pre>
<p>You can use a system like this for storing user permissions(which is how *nix permissions work), which days of the week an event occurs(the nightlife project will be doing this for storing payment rates), or any other piece of information that can be summed up in a series of on/off switches. <strong>Using binary storage is extremely efficient and flexible.</strong> Remember, however, that any additional fields to be added should be added to the left side of the string to preserve old data.</p>
<div class="shr-publisher-502"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2010/01/storing-onoff-switches-through-binary-representation/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The Nightlife Project &#8211; Part 1 &#8211; Introduction to the Problem</title>
		<link>http://visual77.com/blog/2009/12/the-nightlife-project-part-1-introduction-to-the-problem/</link>
		<comments>http://visual77.com/blog/2009/12/the-nightlife-project-part-1-introduction-to-the-problem/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 22:48:34 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[nightlife project]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/blog/?p=473</guid>
		<description><![CDATA[The Nightlife Project is a novice PHP/MySQL tutorial that will teach you beginning/intermediate PHP through a series of lessons that build a nightlife tracker.]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>&#8220;A carelessly planned project takes three times longer to complete than expected; a carefully planned project takes only twice as long.&#8221;</p>
<p><a href="http://visual77.com/blog/tag/nightlife-project">The Nightlife Project</a> is a novice <a href="http://visual77.com/blog/tag/php">PHP</a>/<a href="http://visual77.com/blog/tag/mysql">MySQL</a> tutorial. While you don&#8217;t have to know a whole lot to get started, you should understand the basics of PHP and MySQL. Knowledge of variables, functions and flow control is required. If the following block of code makes sense to you, you are ready to start the project:</p>
<pre class="brush:php">&lt;?php
repeat('foo', 15);
function repeat($string, $count) {
     for($i = 0; $i &lt; $count; ++$i) {
          mysql_query("INSERT INTO `data` VALUES ('$string')");
     }
}
?&gt;</pre>
<p>Now, an explanation is due.</p>
<p>You work for Vision Nightlife, a nightlife promotion company working out of Las Vegas. Your company hires promoters to hand out nightclub flyers for the various clubs that have hired your company. These promoters give flyers to tourists for things like free entry to Domi Lounge, a free drink at Club Septuro, etc. Each flyer is stamped with a unique code identifying the promoter that drove the tourists to the club. The club will then pay your company, based on how many people your promoters drove to their club. The amount is based on how many people and what day of the week. For example, Hoodoo Lounge pays $1 per person on Friday or Saturday nights, if you bring between 1 and 10 people. If you bring between 11 and 20 people, it is $1.50 per person, and 21 or more people is $2.25 per person. On a Wednesday night, those amounts are cut in half.  Your company wants you to write software to keep track of all of this information.</p>
<p>Your software needs to track clubs, promoters, payment rates, referral amounts and payout amounts.</p>
<p>This is just an introduction to the nightlife project. Part 2 will begin looking at the database structure and writing the ideal schema for each table.</p>
<div class="shr-publisher-473"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2009/12/the-nightlife-project-part-1-introduction-to-the-problem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Filtering an array with a string mask in PHP</title>
		<link>http://visual77.com/blog/2009/12/filtering-an-array-with-a-string-mask-in-php/</link>
		<comments>http://visual77.com/blog/2009/12/filtering-an-array-with-a-string-mask-in-php/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 20:21:47 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/?p=456</guid>
		<description><![CDATA[I&#8217;ve been working on a solution the Kohana problem of the Validation library being unable to validate cleanly inside multidimensional arrays, and the root of this problem is passing a mask to the Validation::add_rules() method to identify deeply nested elements. In the course of trying to work out this problem, I wrote a function that [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>I&#8217;ve been working on a solution the Kohana problem of the Validation library being unable to validate cleanly inside multidimensional arrays, and the root of this problem is passing a mask to the Validation::add_rules() method to identify deeply nested elements. In the course of trying to work out this problem, I wrote a function that accepts a mask and an array and returns the filtered array. While it doesn&#8217;t get me any closer to my actual goal, I do think it is an interesting function nonetheless and could be quite useful in the right circumstances. In the future, I might tweak this to allow you to invert the results, whereby it deletes anything that matches the mask, rather than preserves those that match the mask.</p>
<p>An example of a mask would be &#8220;messages/*/timestamp&#8221; would only keep elements of the array that matched $array['messages'][*]['timestamp'] with * being a wildcard.</p>
<pre class="brush:php">
function array_mask_filter($mask, $array, $ci = false) {
    if(!is_string($mask)) {
        throw new exception('filter mask must be a string');
    }

    if(!is_array($array)) {
        throw new exception('variable to be filtered must be an array');
    }

    $mask_chunks = explode('/', $mask);

    $this_mask = array_shift($mask_chunks);

    if($this_mask != '*') {
        foreach(array_keys($array) as $key) {
            $key = $ci ? strtolower($key) : $key;
            $this_mask = $ci ? strtolower($this_mask) : $this_mask;
            if($key !== $this_mask) {
                unset($array[$key]);
            }
        }
    }

    foreach(array_filter($array, 'is_array') as $key=>$element) {
        $array[$key] = array_mask_filter($element, implode('/', $mask_chunks));
        if(empty($array[$key])) {
            unset($array[$key]);
        }
    }

    return $array;
}
</pre>
<div class="shr-publisher-456"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2009/12/filtering-an-array-with-a-string-mask-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Revised convertObjectToArray function for PHP</title>
		<link>http://visual77.com/blog/2009/12/revised-convertobjecttoarray-function-for-php/</link>
		<comments>http://visual77.com/blog/2009/12/revised-convertobjecttoarray-function-for-php/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 17:46:49 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/?p=452</guid>
		<description><![CDATA[Back in July, I wrote an article about converting an object to array in PHP and mentioned the difficulties I was having with filtering private and protected keys to remove undesirable characters. I found a solution not long after, but never got around to writing a follow up. Here is my current function library to [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>Back in July, I wrote an<a href="http://www.visual77.com/2009/07/php-convert-object-to-array/"> article about converting an object to array</a> in PHP and mentioned the difficulties I was having with filtering private and protected keys to remove undesirable characters. I found a solution not long after, but never got around to writing a follow up. Here is my current function library to convert an object to an array, recursively, while maintaing nice keys.</p>
<pre class="brush:php">
< ?php

function convertObjectToArray(&#038;$element) {
    // the recursive call can't operate through objects, so they
    // must be handled specially
    if(is_object($element)) {
        // typecast the object to an array, and clean up private and
        // protected keys
        $element = convertObjectToArray_keyCleanup((array)$element);
        // begin the recursion again to go through this object-turned-array
        // this is not strictly necesary, as removing it will cause the
        // recursion to happen in convertToXml, but putting it here makes it
        // more readable and ever so slightly faster.
        array_walk_recursive(
            $element,
           'convertObjectToArray'
        );
    }
    return $element;
}

function convertObjectToArray_keyCleanup($array) {
    // find every invalid key (private and protected member properties)
    foreach(array_filter(array_keys($array), 'convertObjectToArray_invalidKey')
        as $invalidKey) {
        // change the key name by copy / delete / create
        $data = $array[$invalidKey];
        unset($array[$invalidKey]);
        // find out the correct key name by getting the last chunk that
        // is only ascii 32 - 126, the standard set of printable characters
        // User�Types => Types
        $key = preg_replace(
            '/^.*[^\x20-\x7E]([\x20-\x7E]*)$/',
            '\\1',
            $invalidKey
        );
        $array[$key] = $data;
    }

    return $array;
}

function convertObjectToArray_invalidKey($key) {
    // a key is invalid if it has any characters that are outside
    // of the ascii range 32 - 126, which is the standard set of printable
    // characters
    return preg_match('/[^\x20-\x7E]/', $key);
}

?>
</pre>
<div class="shr-publisher-452"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2009/12/revised-convertobjecttoarray-function-for-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>mysql_insert_id and insert ignore</title>
		<link>http://visual77.com/blog/2009/11/mysql_insert_id-and-insert-ignore/</link>
		<comments>http://visual77.com/blog/2009/11/mysql_insert_id-and-insert-ignore/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 22:14:08 +0000</pubDate>
		<dc:creator>visual77</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.visual77.com/?p=421</guid>
		<description><![CDATA[While working on some code recently, I realized that mysql_insert_id fails when using insert ignore. When using insert, mysql_insert_id returns the primary key of the newly inserted row. However, nothing is returned with insert ignore if a key conflict prevents a record from being inserted. If you are wanting to get the key that a [...]]]></description>
			<content:encoded><![CDATA[<!-- Start Shareaholic LikeButtonSetTop --><!-- End Shareaholic LikeButtonSetTop --><p>While working on some code recently, I realized that mysql_insert_id fails when using insert ignore. When using insert, mysql_insert_id returns the primary key of the newly inserted row. However, nothing is returned with insert ignore if a key conflict prevents a record from being inserted. If you are wanting to get the key that a conflict was just hit against, in as dynamic of a way as possible, you can use this script to find the primary key when insert ignore does not enter a record. This is useful if you are setting up a many-to-many pivot table and don&#8217;t want duplicate data on either side. When you attempt to insert a new record, it either gives you the new key or the key of the one that already existed.</p>
<pre class="brush:php">
$db->query($sql)

// if an insert id exists, use it
if ($db->insert_id != 0) {
    $id = $db->insert_id;
// if there is no insert id and there was no error and insert ignore was ued
} elseif($db->insert_id == 0 &#038;&#038;
    empty($db->error) &#038;&#038;
    preg_match('/^\s*insert\s+ignore/si', $sql)) {

    // find the table that was queried
    preg_match('/^\s*insert\s+ignore\s+into\s+([-`a-zA-Z0-9_]+)/si', $sql, $extract);
    $table = trim($extract[1], '`');

    // change insert ignore  to insert
    $Sql = preg_replace('/^\s*insert\s+ignore/si', 'insert', $sql);

    // query and scan the error for the key conflict
    $db->query($sql);
    $error = $db->error;
    preg_match('/^Duplicate entry \'(.*)\' for key (\d+)$/', $error, $extract);

    $value = $extract[1];
    $key = $extract[2];

    // in the case of multi column keys, figure out what the keys actually are
    if(strstr($value, '-') &#038;&#038; !strstr($sql, $value)) {
        $values = explode('-', $value);
        $finished = false;
        while(!$finished) {
            foreach($values as $k=>&#038;$v) {
                if(strstr($Sql, $v.'-'.$values[$k+1])) {
                    $values[$k] = $v.'-'.$values[$k+1];
                    unset($values[$k+1]);
                    $values = array_values($values);
                    break;
                }
                $finished = true;
            }
        }
        $value = $values;
    }

    // look up all keys on the table, isolating the primary key
    $keySql = "show keys from `$table`";
    $keyResult = $db->query($keySql);
    $keys = array();
    while($row = $keyResult->fetch_assoc()) {
        if(strtolower($row['Key_name']) == 'primary') {
            $primary = $row['Column_name'];
        }
        $keys[$row['Key_name']][] = $row;
    }

    // build a where clause to find the primary based on key conflicts
    $keys = array_values($keys);
    if(!is_array($keys[$key-1])) {
        $unique = $keys[$key-1]['Column_name'];
        $where = "`$unique` = '".$db->real_escape_string($value)."'";
    } else {
        foreach($keys[$key-1] as $key) {
            $whereParts[] = "`{$key['Column_name']}` = '".$db->real_escape_string($value[$key['Seq_in_index']-1])."'";
        }
        $where = implode(' and ', $whereParts);
    }

    // get the primary key that conflicted with the insert
    $sql = "select `$primary` from `$table` where $where";
    if(is_object($result)) {
        $result = $result->fetch_assoc();
        $id = $result[$primary];
    }
}

echo $id;
</pre>
<div class="shr-publisher-421"></div><!-- Start Shareaholic LikeButtonSetBottom --><!-- End Shareaholic LikeButtonSetBottom -->]]></content:encoded>
			<wfw:commentRss>http://visual77.com/blog/2009/11/mysql_insert_id-and-insert-ignore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->
