<?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>Jasny · web development</title>
	<atom:link href="http://www.jasny.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jasny.net</link>
	<description>Helping you out with PHP, MySQL &#38; Javascript</description>
	<lastBuildDate>Fri, 15 Feb 2013 22:36:04 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Jasny Bootstrap &#8211; File upload with existing file</title>
		<link>http://www.jasny.net/articles/jasny-bootstrap-file-upload-with-existing-file/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=jasny-bootstrap-file-upload-with-existing-file</link>
		<comments>http://www.jasny.net/articles/jasny-bootstrap-file-upload-with-existing-file/#comments</comments>
		<pubDate>Fri, 15 Feb 2013 15:16:50 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Frontend]]></category>

		<guid isPermaLink="false">http://www.jasny.net/?p=876</guid>
		<description><![CDATA[I&#8217;m happy to say that many developers have found their way to Jasny Bootstrap. Especially the file upload component, is very popular. It can replace any normal &#60;input type="file"&#62; element to display a nice widget that is consistent across browsers and can show a preview for images. This is just an image The documentation shows [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m happy to say that many developers have found their way to <a href="http://jasny.github.com/bootstrap/" target="_blank">Jasny Bootstrap</a>. Especially the <a href="http://jasny.github.com/bootstrap/javascript.html#fileupload">file upload component</a>, is very popular. It can replace any normal <code>&lt;input type="file"&gt;</code> element to display a nice widget that is consistent across browsers and can show a preview for images.</p>
<div style="text-align: center">
<img src="http://www.jasny.net/wp-content/uploads/bootstrap-fileupload.png" alt="This is just an image" width="188" height="208" class="size-full wp-image-877" style="border: 1px solid #EEE; margin-bottom: 0" /><small>This is just an image</small>
</div>
<p>The documentation shows the HTML to use, but it doesn&#8217;t show how to use it with existing files. I&#8217;ll explain it here.<br />
<span id="more-876"></span></p>
<h3>The basics</h3>
<p>The HTML stays largely the same. Change <code>fileupload-new</code> to <code>fileupload-exists</code> for the <code>.fileupload</code> container div <nobr><i>(line 1)</i></nobr>. Put the <code>&lt;img&gt;</code> for the existing image in the <code>.fileupload-preview</code> div <nobr><i>(line 4)</i></nobr>. If you&#8217;re not image preview, put the file name in the <code>.fileupload-preview</code> div instead.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="html4strict"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="de1"><pre class="de1"><span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload fileupload-exists&quot;</span> data-provides<span class="sy0">=</span><span class="st0">&quot;fileupload&quot;</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-new thumbnail&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;width: 200px; height: 150px;&quot;</span>&gt;&lt;<span class="kw2">img</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;http://www.placehold.it/200x150/EFEFEF/AAAAAA&amp;text=no+image&quot;</span> <span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-preview fileupload-exists thumbnail&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;max-width: 200px; max-height: 150px; line-height: 20px;&quot;</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">img</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;/images/example.png&quot;</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn btn-file&quot;</span>&gt;&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-new&quot;</span>&gt;</span>Select image<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-exists&quot;</span>&gt;</span>Change<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;file&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;myimage&quot;</span> <span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;#&quot;</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn fileupload-exists&quot;</span> data-dismiss<span class="sy0">=</span><span class="st0">&quot;fileupload&quot;</span>&gt;</span>Remove<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">&lt;div class="fileupload fileupload-exists" data-provides="fileupload"&gt;
  &lt;div class="fileupload-new thumbnail" style="width: 200px; height: 150px;"&gt;&lt;img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&amp;text=no+image" /&gt;&lt;/div&gt;
  &lt;div class="fileupload-preview fileupload-exists thumbnail" style="max-width: 200px; max-height: 150px; line-height: 20px;"&gt;
    &lt;img src="/images/example.png"&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;span class="btn btn-file"&gt;&lt;span class="fileupload-new"&gt;Select image&lt;/span&gt;&lt;span class="fileupload-exists"&gt;Change&lt;/span&gt;&lt;input type="file" name="myimage" /&gt;&lt;/span&gt;
    &lt;a href="#" class="btn fileupload-exists" data-dismiss="fileupload"&gt;Remove&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre></div></div>

<p>When a user presses submit without changing or removing the image, the form post contains an entry for &#8216;myimage&#8217; without a new file. When clear is pressed the value for &#8216;myimage&#8217; is an empty string. In PHP you could handle it as</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">&nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span> <span class="sy0">==</span> <span class="st_h">''</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// Delete file</span>
&nbsp; <span class="br0">&#125;</span> <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="re0">$_FILES</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'error'</span><span class="br0">&#93;</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// Save uploaded file</span>
&nbsp; <span class="br0">&#125;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">  if (isset($_POST['myimage']) &amp;&amp; $_POST['myimage'] == '') {
    // Delete file
  } elseif ($_FILES['myimage']['error'] == 0)  {
    // Save uploaded file
  }</pre></div></div>

<h3>Omit from POST</h3>
<p>However this in some languages and frameworks you can&#8217;t easily make the distinction between no file being selected and the post containing an empty string. In that case you can use the `data-name` attribute and leave you the `name` attribute on the <code>&lt;input type="file"&gt;</code>.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="html4strict"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="de1"><pre class="de1"><span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload fileupload-exists&quot;</span> data-provides<span class="sy0">=</span><span class="st0">&quot;fileupload&quot;</span> data-<span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;myimage&quot;</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-new thumbnail&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;width: 200px; height: 150px;&quot;</span>&gt;&lt;<span class="kw2">img</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;http://www.placehold.it/200x150/EFEFEF/AAAAAA&amp;text=no+image&quot;</span> <span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-preview fileupload-exists thumbnail&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;max-width: 200px; max-height: 150px; line-height: 20px;&quot;</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">img</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;/images/example.png&quot;</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn btn-file&quot;</span>&gt;&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-new&quot;</span>&gt;</span>Select image<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-exists&quot;</span>&gt;</span>Change<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;file&quot;</span> <span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;#&quot;</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn fileupload-exists&quot;</span> data-dismiss<span class="sy0">=</span><span class="st0">&quot;fileupload&quot;</span>&gt;</span>Remove<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">&lt;div class="fileupload fileupload-exists" data-provides="fileupload" data-name="myimage"&gt;
  &lt;div class="fileupload-new thumbnail" style="width: 200px; height: 150px;"&gt;&lt;img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&amp;text=no+image" /&gt;&lt;/div&gt;
  &lt;div class="fileupload-preview fileupload-exists thumbnail" style="max-width: 200px; max-height: 150px; line-height: 20px;"&gt;
    &lt;img src="/images/example.png"&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;span class="btn btn-file"&gt;&lt;span class="fileupload-new"&gt;Select image&lt;/span&gt;&lt;span class="fileupload-exists"&gt;Change&lt;/span&gt;&lt;input type="file" /&gt;&lt;/span&gt;
    &lt;a href="#" class="btn fileupload-exists" data-dismiss="fileupload"&gt;Remove&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre></div></div>

<p>Now when the user presses submit without changing or clearing the file, the &#8216;myimage&#8217; entry will not be part of the post data. In the next PHP example both <code>$_FILES</code> and <code>$_POST</code> are processed and present in <code>$data</code>.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1">&nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span> <span class="sy0">==</span> <span class="st_h">''</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// Delete file</span>
&nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// Handle uploaded file</span>
&nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">  if (isset($data['myimage'])) {
     if ($data['myimage'] == '') {
       // Delete file
     } else {
       // Handle uploaded file
     }
  }</pre></div></div>

<h3>Posting a specific value</h3>
<p>In some cases this still won&#8217;t do, for instance when you&#8217;re using a form builder which combines the defaults with posted data. In that case you can manually add the <code>&lt;input type="hidden"&gt;</code> and set it to a specific value. <i>(In the following example &#8217;1&#8242; is chosen, but you can also use the basename of the file or whatever you want.)</i></p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="html4strict"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="de1"><pre class="de1"><span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload fileupload-exists&quot;</span> data-provides<span class="sy0">=</span><span class="st0">&quot;fileupload&quot;</span> data-<span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;myimage&quot;</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;hidden&quot;</span> <span class="kw3">name</span><span class="sy0">=</span><span class="st0">&quot;myimage&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;1&quot;</span> <span class="sy0">/</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-new thumbnail&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;width: 200px; height: 150px;&quot;</span>&gt;&lt;<span class="kw2">img</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;http://www.placehold.it/200x150/EFEFEF/AAAAAA&amp;text=no+image&quot;</span> <span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-preview fileupload-exists thumbnail&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;max-width: 200px; max-height: 150px; line-height: 20px;&quot;</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">img</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;/images/example.png&quot;</span> <span class="sy0">/</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="kw2">div</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn btn-file&quot;</span>&gt;&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-new&quot;</span>&gt;</span>Select image<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;fileupload-exists&quot;</span>&gt;</span>Change<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;file&quot;</span> <span class="sy0">/</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;#&quot;</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn fileupload-exists&quot;</span> data-dismiss<span class="sy0">=</span><span class="st0">&quot;fileupload&quot;</span>&gt;</span>Remove<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;</span>
&nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span>
<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">&lt;div class="fileupload fileupload-exists" data-provides="fileupload" data-name="myimage"&gt;
  &lt;input type="hidden" name="myimage" value="1" /&gt;
  &lt;div class="fileupload-new thumbnail" style="width: 200px; height: 150px;"&gt;&lt;img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&amp;text=no+image" /&gt;&lt;/div&gt;
  &lt;div class="fileupload-preview fileupload-exists thumbnail" style="max-width: 200px; max-height: 150px; line-height: 20px;"&gt;
    &lt;img src="/images/example.png" /&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;span class="btn btn-file"&gt;&lt;span class="fileupload-new"&gt;Select image&lt;/span&gt;&lt;span class="fileupload-exists"&gt;Change&lt;/span&gt;&lt;input type="file" /&gt;&lt;/span&gt;
    &lt;a href="#" class="btn fileupload-exists" data-dismiss="fileupload"&gt;Remove&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre></div></div>

<p>In this case when the user presses submit without changing or clearing the file, the &#8216;myimage&#8217; entry will be &#8217;1&#8242;. When the user clears the image it will be an empty string. In the next PHP example both <code>$_FILES</code> and <code>$_POST</code> are processed and combined with all the default/original values as <code>$data</code>.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">&nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span> <span class="sy0">===</span> <span class="st_h">''</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// Delete file</span>
&nbsp; <span class="br0">&#125;</span> <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#91;</span><span class="st_h">'myimage'</span><span class="br0">&#93;</span> <span class="sy0">!==</span> <span class="st_h">'1'</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// Handle uploaded file</span>
&nbsp; <span class="br0">&#125;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">  if ($data['myimage'] === '') {
    // Delete file
  } elseif ($data['myimage'] !== '1') {
    // Handle uploaded file
  }</pre></div></div>

<h3>Please contribute</h3>
<p>If you&#8217;re using the file upload component with Ruby, Python, C# or Java, please leave a comment with the above PHP examples in your language. Thanks.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/jasny-bootstrap-file-upload-with-existing-file/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Making a 26-Hour Day without waking up early</title>
		<link>http://www.jasny.net/articles/how-i-made-a-26-hour-day-alternative/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-i-made-a-26-hour-day-alternative</link>
		<comments>http://www.jasny.net/articles/how-i-made-a-26-hour-day-alternative/#comments</comments>
		<pubDate>Tue, 01 Jan 2013 18:05:14 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Random thoughts]]></category>

		<guid isPermaLink="false">http://www.jasny.net/?p=826</guid>
		<description><![CDATA[I just read the very interesting article &#8216;How I Made a 26-Hour Day&#8216; by Andrew Dumont. As many I&#8217;m also struggling to get more out of a day. He has some very good ideas about how to achieve that. The thing I didn&#8217;t like so much about it, was the statement that you have to [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>I just read the very interesting article &#8216;<a href="http://andrewdumont.me/how-i-made-a-26-hour-day">How I Made a 26-Hour Day</a>&#8216; by Andrew Dumont. As many I&#8217;m also struggling to get more out of a day. He has some very good ideas about how to achieve that.</p>
<p>The thing I didn&#8217;t like so much about it, was the statement that you have to become a morning person to be more productive. I&#8217;ve tried waking up early, but finding that it just wouldn&#8217;t work for me.</p>
<p>Much of my social life takes place in the evening and at night, like going out with friends, salsa dancing, etc. Having to go to bed early to keep my daily rhythm would mean I&#8217;d have to give up much of my social life. Let&#8217;s say I&#8217;d only go out on Friday and/or Saturday, going to bed around 2:30. I would struggle to get back into rhythm and feel almost jet-lagged.<br />
<span id="more-826"></span></p>
<h3>The alternative</h3>
<p>Taking Andrew&#8217;s schedule as example:</p>
<p style="padding-left: 15px">
<strong>8:00am</strong> &#8211; Roll out of bed, make breakfast, get ready for work and consume several cups of coffee<br />
<strong>8:45am</strong> &#8211; Arrive at Moz<br />
<strong>5:30pm</strong> &#8211; Leave Moz<br />
<strong>6:00pm</strong> &#8211; Eat dinner<br />
<strong>7:00pm</strong> &#8211; Answer emails, return calls<br />
<strong>8:30pm</strong> &#8211; Go to the gym<br />
<strong>9:15pm</strong> &#8211; Blog or hack on Stride<br />
<strong>10:30pm</strong> &#8211; HOLY HELL, FREE BLOCK<br />
<strong>12:30am</strong> &#8211; Read, then head to bed
</p>
<p>The advantage here, it that you can easily do something social with friends (or girlfriend) from 9:15 to 12:30, just by choosing not to blog/hack today and without changing the rest of you schedule or rhythm. Also shifting from going to bed at 2:30 during the weekend to 12:30 during the week is much easier than switching between 2:30 and 9:30pm.</p>
<p>Last, eating diner only 3 hours before going to bed isn&#8217;t ideal. It takes about 2 hours to process carbs before you can use that energy. So basically you&#8217;ll put on almost your diner as body weight, which you need to work off in the morning. Instead going to the gym in the evening allows you to burn of extra energy directly.</p>
<p>Anyways, thanks Andrew for giving me some good pointers about how to achieve this New Year resolution <img src='http://www.jasny.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/how-i-made-a-26-hour-day-alternative/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linkify: turning URLs into clickable links in PHP</title>
		<link>http://www.jasny.net/articles/linkify-turning-urls-into-clickable-links-in-php/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=linkify-turning-urls-into-clickable-links-in-php</link>
		<comments>http://www.jasny.net/articles/linkify-turning-urls-into-clickable-links-in-php/#comments</comments>
		<pubDate>Mon, 26 Mar 2012 22:31:34 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[top]]></category>

		<guid isPermaLink="false">http://www.jasny.net/?p=539</guid>
		<description><![CDATA[Turning links like www.example.com and http://twitter.com into clickable links. Sounds like an easy task, right? We&#8217;ll there are a few problems that might arise, especially if the text is already HTML formatted. This function first takes out all potential dangers, by extracting links and tags and replacing them with a placeholder. It than extracts all [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>Turning links like www.example.com and http://twitter.com into clickable links. Sounds like an easy task, right? We&#8217;ll there are a few problems that might arise, especially if the text is already HTML formatted.</p>
<p>This function first takes out all potential dangers, by extracting links and tags and replacing them with a placeholder. It than extracts all URLs and replaces them with a placeholder, storing the full HTML link. At the end it replaces all placeholders with the links and tags.<br />
<span id="more-539"></span><br />
<script src="https://gist.github.com/2000705.js"> </script></p>
<p>This is also a nice example for how to use <a href="http://php.net/manual/en/functions.anonymous.php">PHP closures</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/linkify-turning-urls-into-clickable-links-in-php/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>A secure backdoor for PHP</title>
		<link>http://www.jasny.net/articles/a-secure-backdoor-for-php/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-secure-backdoor-for-php</link>
		<comments>http://www.jasny.net/articles/a-secure-backdoor-for-php/#comments</comments>
		<pubDate>Tue, 11 May 2010 14:48:23 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Authentication]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[top]]></category>

		<guid isPermaLink="false">http://www.jasny.net/?p=415</guid>
		<description><![CDATA[A backdoor provides access to an application through a different method that the normal authentication process. There are many ways to do this. Some are more secure than others.<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>A <a href="http://en.wikipedia.org/wiki/Backdoor_%28computing%29" target="_blank">backdoor</a> provides access to an application bypassing the normal authentication process. There are many ways to do this. Some are more secure than others.</p>
<h3>Why do you need a backdoor?</h3>
<p>In a perfect word you could just deliver an application and all would be good. However in the real world there are unforeseen issues which need to be solved. This means that you as a developer will need access to the application. To reproduce the problem, you usually want to run the application logged in as the user that spotted the issue.</p>
<p>Another use of the backdoor is in a situation where you want to allow a user, that has already been authenticated, to bypassing further authentication. For example if you have a (web hosting) control panel where the user is already logged in, you can allow him to directly access the dashboard of the application without have to enter his password again. This requires a backdoor, since you don&#8217;t know his (unencrypted) password.<br />
<span id="more-415"></span></p>
<h3>A very simple solution</h3>
<p>The most simple solution is to use a backdoor password. This password will work for every user. A variation on this, is to have a superuser account, that is allowed to switch to any user on the system.</p>
<p>This solution is fine if you&#8217;re the only developer working on these applications. However in a professional environment this solution won&#8217;t do. With this method is easy to give somebody super privileges, but hard to take them away. This requires changing the backdoor password. Which is a tedious job if you&#8217;re managing any serious number of applications.</p>
<h3>The secure way</h3>
<p>It is easier if there is a project management system where you and other developers can log into. From within that system, the developer can directly login the customer application as any user. Within that application you can configure on which team each developer is. That limits to which applications the developer has access. More important, simply blocking the user account on the project management system will lock the developer out completely.</p>
<h3>Private and public keys</h3>
<p>The best known method for logging into a system, is the use of private/public (DSA) keys with SSH. The SSH client signs the request with the private key. The SSH server has the public key in the authorized_key file. It verifies the credentials using the public keys and grands access on success.</p>
<p>We can use the same method with PHP using the <a href="http://php.net/openssl" title="OpenSSL in PHP manual" target="_blank">OpenSLL</a> extension. We&#8217;ll let the client (project management system) sign the username and system name (URL) using openssl_sign. This signature is verified on the server (customer application) using openssl_verify. To unsure the login URL can&#8217;t be reused later, we&#8217;ll throw in a 5 second timeout.</p>
<h3>Generating the keys</h3>
<p>The keys can be generated on the (*nix) command line, using the &#8216;openssl&#8217; binary. I&#8217;m using RSA keys, but DSA should also work if preferred.</p>
<pre># Generate private key
openssl genrsa -out master.key 1024
# Generate public key
openssl rsa -in master.key -pubout -out master.pub</pre>
<p>The public key should be copied to the &#8216;pubkeys&#8217; directory of the server application. Make sure the private key is absolutely private. Anybody who has a copy of that, can use the backdoor.</p>
<h3>Download</h3>
<p><i>Don&#8217;t use the downloaded code without replacing the private and public key!</i><br />
<a href="http://github.com/jasny/backdoor/archives/master" target="_blank">Download the code @ github</a><br />
<a href="http://www.jasny.net/code/backdoor/client/" target="_blank">A (not to impressive) demo</a></p>
<p>If I overlooked security issues with this implementation, please leave a comment below.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/a-secure-backdoor-for-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Versioning MySQL data: Multi-table records</title>
		<link>http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=versioning-mysql-data-multi-table-records</link>
		<comments>http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 01:41:45 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=342</guid>
		<description><![CDATA[In the article &#8216;Versioning MySQL data&#8216;, I showed the basics of implementing a revisioning system using trigger. As Jens Schauder already pointed out, often the data of a record is spread across multiple tables, like an invoice with multiple invoice lines. Having each invoice line versioned individually isn&#8217;t really useful. Instead we want a new [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>In the article &#8216;<a href="http://www.adaniels.nl/articles/versioning-mysql-data/">Versioning MySQL data</a>&#8216;, I showed the basics of implementing a revisioning system using trigger. As Jens Schauder already pointed out, often the data of a record is spread across multiple tables, like an invoice with multiple invoice lines. Having each invoice line versioned individually isn&#8217;t really useful. Instead we want a new revision of the whole invoice on each change.<br />
<span id="more-342"></span><br />
<strong>The perfect solution</strong><br />
Ideally a change of one or more parts of the invoice would be changed, a new revision would be created. There are several issues in actually creating this those. Detecting the change of multiple parts of the invoice at once, generating a single revision, would mean we need to know if the actions are done within the same transaction. Unfortunately there is a connection_id(), but no transaction_id() function in MySQL. Also, the <a href="http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html#error_er_cant_update_used_table_in_sf_or_trg" target="_blank">query would fail</a> when a query inserts or updates a record in the child table, using the parent table. We need to come up with something else.</p>
<p>In the implementation we currently have in production, we version the rows in the parent as well in the child tables. For each version of the parent row, we register which versions of the child rows ware set. This however has really complicated the trigger code and tends to need a lot of checking an querying slowing the write process down. Since nobody ever looks at the versions of the child rows, the application forces a new version of the parent row. The benefits of versioning both are therefor minimal.</p>
<p><strong>Only versioning the parent</strong><br />
For this new (simplified) implementation, we will only have one revision number across all tables of the record. Changing data from the parent table, will trigger a new version. This will not only copy the parent row to the revisioning table, but also the rows of the children.</p>
<p>Writing to the child will not trigger a new version, instead it will update the data in the revisioning table. This means that when changing the record, you need to write to the parent table, before writing to the child tables. To force a new version without changing values use</p>
<pre>UPDATE mytable SET _revision=NULL where id=$id</pre>
<p>The parent and child tables are defined as</p>
<pre>CREATE TABLE `mytable` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '',
  `description` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB

CREATE TABLE `mychild` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `mytable_id` int(10) unsigned NOT NULL DEFAULT '0',
  `title` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `mytable_id` (`mytable_id`),
  CONSTRAINT `mychild_ibfk_1` FOREIGN KEY (`mytable_id`) REFERENCES `mytable` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB</pre>
<p>Note that we are using InnoDB tables here. MyISAM doesn&#8217;t have foreign key constraints, therefor it&#8217;s not possible to define a parent-child relationship.</p>
<p><strong>Insert, update and delete</strong><br />
In the parent trigger, two different things happen concerning the child rows. When a new version is created, the data of `mychild` is copied to the revisioning table. On a revision switch, data will be copied from the revisioning table into `mychild`. The &#8220;`_revision_action` IS NULL&#8221; condition, means that `_revision_mytable` is only updated when a new revision is created.</p>
<pre>CREATE TRIGGER `mytable-afterupdate` AFTER update ON `mytable`
  FOR EACH ROW BEGIN
    DECLARE `newrev` BOOLEAN;
    
    UPDATE `_revision_mytable` SET `id` = NEW.`id`, `name` = NEW.`name`, `description` = NEW.`description`, `_revision_action`='update' WHERE `_revision`=NEW.`_revision` AND `_revision_action` IS NULL;
    SET newrev = (ROW_COUNT() &gt; 0);
    INSERT INTO `_revhistory_mytable` VALUES (NEW.`id`, NEW.`_revision`, @auth_uid, NOW());
    
    IF newrev THEN
       INSERT INTO `_revision_mychild` SELECT *, NEW.`_revision` FROM `mychild` WHERE `mytable_id` = NEW.`id`;
    ELSE
       DELETE `t`.* FROM `mychild` AS `t` LEFT JOIN `_revision_mychild` AS `r` ON 0=1 WHERE `t`.`mytable_id` = NEW.`id`;
       INSERT INTO `mychild` SELECT `id`, `mytable_id`, `title` FROM `_revision_mychild` WHERE `_revision` = NEW.`_revision`;
    END IF;
  END

CREATE TRIGGER `mychild-afterinsert` AFTER INSERT ON `mychild`
  FOR EACH ROW BEGIN
    DECLARE CONTINUE HANDLER FOR 1442 BEGIN END;
    INSERT IGNORE INTO `_revision_mychild` (`id`, `mytable_id`, `title`, `_revision`) SELECT NEW.`id`, NEW.`mytable_id`, NEW.`title`, `_revision` FROM `mytable` AS `p` WHERE `p`.`id`=NEW.`mytable_id`;
  END

CREATE TRIGGER `mychild-afterupdate` AFTER UPDATE ON `mychild`
  FOR EACH ROW BEGIN
    REPLACE INTO `_revision_mychild` (`id`, `mytable_id`, `title`, `_revision`) SELECT NEW.`id`, NEW.`mytable_id`, NEW.`title`, `_revision` FROM `mytable` AS `p` WHERE `p`.`id`=NEW.`mytable_id`;
  END

CREATE TRIGGER `mychild-afterdelete` AFTER DELETE ON `mychild`
  FOR EACH ROW BEGIN
    DECLARE CONTINUE HANDLER FOR 1442 BEGIN END;
    DELETE `r`.* FROM `_revision_mychild` AS `r` INNER JOIN `mytable` AS `p` ON `r`.`_revision` = `p`.`_revision` WHERE `r`.`id` = OLD.`id`;
  END</pre>
<p>Changing data in table `mychild` simply updates the data in the revisioning table. The revision number is grabbed from the field in the parent table.</p>
<p>Switching the revision can only be done through the parent table. This will also automatically change the data in the child tables. We simply delete all rows of the record and replace them with data from the revisioning table. This would however trigger the deletion of the data in `_revision_child` on which the insert has nothing to do. To prevent this, we can abuse that fact that a trigger can&#8217;t update data of a table using in the insert/update/delete query. This causes <a href="http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html#error_er_cant_update_used_table_in_sf_or_trg">error 1442</a>. With a continue handler we can ignore this silently.</p>
<p>The InnoDB constraints will handle the cascading delete. Deleting child data <a href="http://dev.mysql.com/doc/refman/5.4/en/innodb-foreign-key-constraints.html" target="_blank">won&#8217;t activate the deletion trigger</a>, which is all the better in this case.</p>
<p><strong>Without a primary key</strong><br />
A primary key is not required for the child table, since versioning is done purely based on the id of `mytable`.</p>
<pre>CREATE TABLE `mypart` (
  `mytable_id` int(10) unsigned NOT NULL,
  `reference` varchar(255) NOT NULL,
  KEY `mytable_id` (`mytable_id`),
  CONSTRAINT `mypart_ibfk_1` FOREIGN KEY (`mytable_id`) REFERENCES `mytable` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB</pre>
<p>This does cause an issue for the update and delete triggers of the child table. It can&#8217;t use the primary to id to locate the current version of the modified/removed row. This can be solved by a trick I got from PhpMyAdmin. We can simply locate the record by comparing the old values of all fields. There is no constraint for the table enforcing the uniqueness of a row, so we could be targeting multiple identical rows. Since they are identical, it doesn&#8217;t matter which one we target, as long as we limit to 1 row.</p>
<pre>CREATE TRIGGER `mypart-afterupdate` AFTER UPDATE ON `mypart`
  FOR EACH ROW BEGIN
    DELETE FROM `_revision_mypart` WHERE `_revision` IN (SELECT `_revision` FROM `mytable` WHERE `id` = OLD.`mytable_id`) AND `mytable_id` = OLD.`mytable_id` AND `reference` = OLD.`reference` LIMIT 1;
    INSERT INTO `_revision_mypart` (`mytable_id`, `reference`, `_revision`) SELECT NEW.`mytable_id`, NEW.`reference`, `_revision` FROM `mytable` AS `p` WHERE `p`.`id`=NEW.`mytable_id`;
  END

CREATE TRIGGER `mypart-afterdelete` AFTER DELETE ON `mypart`
  FOR EACH ROW BEGIN
    DECLARE CONTINUE HANDLER FOR 1442 BEGIN END;
    DELETE FROM `_revision_mypart` WHERE `_revision` IN (SELECT `_revision` FROM `mytable` WHERE `id` = OLD.`mytable_id`) AND `mytable_id` = OLD.`mytable_id` AND `reference` = OLD.`reference` LIMIT 1;
  END</pre>
<p><strong>Unique keys</strong><br />
The revisioning table has multiple versions of a record. Unique indexes from the original table should be converted to non-unique indexes in the revisioning table. This information can be fetched using INFORMATION_SCHEMA.</p>
<pre>SELECT c.CONSTRAINT_NAME, GROUP_CONCAT(CONCAT('`', k.COLUMN_NAME, '`')) AS cols FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS `c` INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS `k` ON c.TABLE_SCHEMA=k.TABLE_SCHEMA AND c.TABLE_NAME=k.TABLE_NAME AND c.CONSTRAINT_NAME=k.CONSTRAINT_NAME WHERE c.TABLE_SCHEMA=DATABASE() AND c.TABLE_NAME='mytable' AND c.CONSTRAINT_TYPE='UNIQUE' AND c.CONSTRAINT_NAME != '_revision' GROUP BY c.CONSTRAINT_NAME</pre>
<p><strong>Revisioning and replication</strong><br />
Baron Schwartz pointed out a <a href="http://www.mysqlperformanceblog.com/2008/09/29/why-audit-logging-with-triggers-in-mysql-is-bad-for-replication/" target="_blank">race condition</a> when relying on auto-increment keys in triggers with replication. Actions carried out through triggers on a master are <a href="http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html#qandaitem-22-5-1-12" target="_blank">not replicated to a slave server</a>. Instead, <a href="http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html#qandaitem-22-5-1-10" target="_blank">triggers on the slave will be invoked</a>, which should do the same action as on the master.</p>
<p>It probably isn&#8217;t needed to have a copy of the revisioning tables on the slave. This would mean that we could simply omit the triggers. Unfortunately this causes problems when changing the revision. In that case we are forced to move switching of a revision out of the database. Instead the application needs to select the data from all revisioning tables and write that to the original tables. Any other thoughts on solving this issue are welcome.</p>
<p><strong id="download">Download</strong><br />
<a href='http://github.com/jasny/mysql-revisioning/archives/master'>&#8211;> Download mysql-revisioning script @github <--</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Versioning MySQL data</title>
		<link>http://www.jasny.net/articles/versioning-mysql-data/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=versioning-mysql-data</link>
		<comments>http://www.jasny.net/articles/versioning-mysql-data/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 16:36:18 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Frontend]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=291</guid>
		<description><![CDATA[Advantages of a VCS above a nightly backup are that you can walk to the individual changes for a document, see who made each change and revert back to specific revision if needed. These are features which would also be nice for data stored in a database. This article shows how to use triggers to can implement versioning for data stored in a MySQL db.<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>As a developer you&#8217;re probably using a versioning control system, like subversion or git, to safeguard your data. Advantages of using a VCS are that you can walk to the individual changes for a document, see who made each change and revert back to specific revision if needed. These are features which would also be nice for data stored in a database. With the use of <a href="http://dev.mysql.com/doc/refman/5.0/en/triggers.html" target="_blank">triggers</a> we can implement versioning for data stored in a MySQL db.<br />
<span id="more-291"></span></p>
<p><strong>The revisioning table</strong><br />
We will not store the different versions of the records in the original table. We want this solution to be in the database layer instead of putting all the logic in the application layer. Instead we&#8217;ll create a new table, which stores all the different versions and lives next to the original table, which only contains the current version of each record. This revisioning table is copy of the original table, with a couple of additional fields.</p>
<pre>CREATE TABLE `_revision_mytable` LIKE `mytable`;

ALTER TABLE `_revision_mytable`
  CHANGE `id` `id` int(10) unsigned,
  DROP PRIMARY KEY,
  ADD `_revision` bigint unsigned AUTO_INCREMENT,
  ADD `_revision_previous` bigint unsigned NULL,
  ADD `_revision_action` enum('INSERT','UPDATE') default NULL,
  ADD `_revision_user_id` int(10) unsigned NULL,
  ADD `_revision_timestamp` datetime NULL default NULL,
  ADD `_revision_comment` text NULL,
  ADD PRIMARY KEY (`_revision`),
  ADD INDEX (`_revision_previous`),
  ADD INDEX `org_primary` (`id`);</pre>
<p>The most important field is `_revision`. This field contains a unique identifier for a version of a record from the table. Since this is the unique identifier in the revisioning table, the original id field becomes a normal (indexed) field.</p>
<p>We&#8217;ll also store some additional information in the revisioning table. The `_revision_previous` field hold the revision nr of the version that was updated to create this revision. Field `_revision_action` holds the action that was executed to create this revision. This field has an extra function that will discussed later. The user id and timestamp are useful for blaming changes on someone. We can add some comment per revision.</p>
<p>The database user is probably always the same. Storing this in the user id field is not useful. Instead, we can set variable @auth_id after logging in and on connecting to the database to the session user.</p>
<p><strong>Altering the original table</strong><br />
The original table needs 2 additional fields: `_revision` and `_revision_comment`. The `_revision` field holds the current active version. The field can also be used to revert to a different revision. The value of `_revision_comment` set on an update or insert will end up in the revisioning table. The field in the original table will always be empty.</p>
<pre>ALTER TABLE `mytable`
  ADD `_revision` bigint unsigned NULL,
  ADD `_revision_comment` text NULL,
  ADD UNIQUE INDEX (`_revision`);</pre>
<p><strong>The history table</strong><br />
Saving each version is not enough. Since we can revert back to older revisions and of course delete the record altogether, we want to store which version of the record was enabled at what time. The history table only needs to hold the revision number and a timestamp. We&#8217;ll add the primary key fields, so it&#8217;s easier to query. A user id field is included again to blame.</p>
<pre>CREATE TABLE `_revhistory_mytable` (
  `id` int(10) unsigned,
  `_revision` bigint unsigned NULL,
  `_revhistory_user_id` int(10) unsigned NULL,
  `_revhistory_timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
  INDEX (`id`),
  INDEX (_revision),
  INDEX (_revhistory_user_id),
  INDEX (_revhistory_timestamp)
) ENGINE=InnoDB;</pre>
<p><strong>How to use</strong><br />
Inserting, updating and deleting data should work as normal, including the <a href="http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html" target="_blank">INSERT &#8230; ON DUPLICATE KEY UPDATE syntax</a>. When updating the _revision field shouldn&#8217;t be changed.</p>
<p>To switch to a different version, we would do something like</p>
<pre>UPDATE mytable SET _revision=$rev WHERE id=$id;</pre>
<p>However if the record has been deleted, there will be no record in the original table, therefore the update won&#8217;t do anything. Instead we could insert a record, specifying the revision.</p>
<pre>INSERT INTO mytable SET _revision=$rev;</pre>
<p>We can combine these two into a statement that works either way.</p>
<pre>INSERT INTO mytable SET id=$id, _revision=$rev ON DUPLICATE KEY UPDATE _revision=VALUES(_revision);</pre>
<p>The above query shows that there an additional constraint. The only thing that indicates that different versions is of the same record, is the primary key. Therefore value of the primary key can&#8217;t change on update. This might mean that some tables need to start using surrogate keys if they are not.</p>
<p><strong>On Insert</strong><br />
Let&#8217;s dive into the triggers. We&#8217;ll start with before insert. This trigger should get the values of a revision when the _revision field is set, or otherwise add a new row to the revision table.</p>
<pre>CREATE TRIGGER `mytable-beforeinsert` BEFORE INSERT ON `mytable`
  FOR EACH ROW BEGIN
    DECLARE `var-id` int(10) unsigned;
    DECLARE `var-title` varchar(45);
    DECLARE `var-body` text;
    DECLARE `var-_revision` BIGINT UNSIGNED;
    DECLARE revisionCursor CURSOR FOR SELECT `id`, `title`, `body` FROM `_revision_mytable` WHERE `_revision`=`var-_revision` LIMIT 1;
  
    IF NEW.`_revision` IS NULL THEN
      INSERT INTO `_revision_mytable` (`_revision_comment`, `_revision_user_id`, `_revision_timestamp`) VALUES (NEW.`_revision_comment`, @auth_uid, NOW());
      SET NEW.`_revision` = LAST_INSERT_ID();
    ELSE
      SET `var-_revision`=NEW.`_revision`;
      OPEN revisionCursor;
      FETCH revisionCursor INTO `var-id`, `var-title`, `var-body`;
      CLOSE revisionCursor;
      
      SET NEW.`id` = `var-id`, NEW.`title` = `var-title`, NEW.`body` = `var-body`;
    END IF;
    
    SET NEW.`_revision_comment` = NULL;
  END

CREATE TRIGGER `mytable-afterinsert` AFTER INSERT ON `mytable`
  FOR EACH ROW BEGIN
    UPDATE `_revision_mytable` SET `id` = NEW.`id`, `title` = NEW.`title`, `body` = NEW.`body`, `_revision_action`='INSERT' WHERE `_revision`=NEW.`_revision` AND `_revision_action` IS NULL;
    INSERT INTO `_revhistory_mytable` VALUES (NEW.`id`, NEW.`_revision`, @auth_uid, NOW());
  END</pre>
<p>If the `_revision` field is NULL, we insert a new row into the revision table. This action is primarily to get a revision number. We set the comment, user id and timestamp. We won&#8217;t set the values, action and previous id yet. The insert might fail or be converted into an update action by insert on duplicate key update. If the insert action fails, we&#8217;ll have an unused row in the revisioning table. This is a problem, since the primary key has not been set, so it won&#8217;t show up anywhere. We can clean up these phantom records once in a while to keep the table clean.</p>
<p>When `_revision` is set, we use a cursor to get the values from the revision table. We can&#8217;t fetch to values directly into NEW, therefore we first fetch them into variables and than copy that into NEW.</p>
<p>After insert, we&#8217;ll update the revision, setting the values and the action. However, the insert might have been an undelete action. In that case `_revision_action` is already set and we don&#8217;t need to update the revision. We also add an entry in the history table.</p>
<p><strong>On Update</strong><br />
The before and after update trigger do more or less the same as the before and after insert trigger.</p>
<pre>CREATE TRIGGER `mytable-beforeupdate` BEFORE UPDATE ON `mytable`
  FOR EACH ROW BEGIN
    DECLARE `var-id` int(10) unsigned;
    DECLARE `var-title` varchar(45);
    DECLARE `var-body` text;
    DECLARE `var-_revision` BIGINT UNSIGNED;
    DECLARE `var-_revision_action` enum('INSERT','UPDATE','DELETE');
    DECLARE revisionCursor CURSOR FOR SELECT `id`, `title`, `body`, `_revision_action` FROM `_revision_mytable` WHERE `_revision`=`var-_revision` LIMIT 1;
    
    IF NEW.`_revision` = OLD.`_revision` THEN
      SET NEW.`_revision` = NULL;
      
    ELSEIF NEW.`_revision` IS NOT NULL THEN 
      SET `var-_revision` = NEW.`_revision`;
      
      OPEN revisionCursor;
      FETCH revisionCursor INTO `var-id`, `var-title`, `var-body`, `var-_revision_action`;
      CLOSE revisionCursor;
      
      IF `var-_revision_action` IS NOT NULL THEN
        SET NEW.`id` = `var-id`, NEW.`title` = `var-title`, NEW.`body` = `var-body`;
      END IF;
    END IF;

    IF (NEW.`id` != OLD.`id` OR NEW.`id` IS NULL != OLD.`id` IS NULL) THEN
-- Workaround for missing SIGNAL command
      DO `Can't change the value of the primary key of table 'mytable' because of revisioning`;
    END IF;

    IF NEW.`_revision` IS NULL THEN
      INSERT INTO `_revision_mytable` (`_revision_previous`, `_revision_comment`, `_revision_user_id`, `_revision_timestamp`) VALUES (OLD.`_revision`, NEW.`_revision_comment`, @auth_uid, NOW());
      SET NEW.`_revision` = LAST_INSERT_ID();
    END IF;
    
    SET NEW.`_revision_comment` = NULL;
  END

CREATE TRIGGER `mytable-afterupdate` AFTER UPDATE ON `mytable`
  FOR EACH ROW BEGIN
    UPDATE `_revision_mytable` SET `id` = NEW.`id`, `title` = NEW.`title`, `body` = NEW.`body`, `_revision_action`='UPDATE' WHERE `_revision`=NEW.`_revision` AND `_revision_action` IS NULL;
    INSERT INTO `_revhistory_mytable` VALUES (NEW.`id`, NEW.`_revision`, @auth_uid, NOW());
  END</pre>
<p>If `_revision` is not set, it has the old value. In that case a new revision should be created. Setting `_revision` to NULL will have the same behaviour of not setting `_revision`. Next to the comment, user id and timestamp, we add also set the previous revision.</p>
<p>As said before, it&#8217;s very important that the value of primary key doesn&#8217;t change. We need to check this and trigger an error, if it would be changed.</p>
<p><strong>On Delete</strong><br />
Deleting won&#8217;t create a new revisiong. However we do want to log that the record has been deleted. Therefore we add an entry to the history table with `_revision` set to NULL.</p>
<pre>CREATE TRIGGER `mytable-afterdelete` AFTER DELETE ON `mytable`
  FOR EACH ROW BEGIN
    INSERT INTO `_revhistory_mytable` VALUES (OLD.`id`, NULL, @auth_uid, NOW());
  END</pre>
<p><strong>To conclude</strong><br />
Using triggers we can implement the basic versioning functionality to MySQL. Since this is completely done the by database, it can be added to an existing application, without having to change to application code (or with very little changes). Using the history table, we can get the data of the database on any moment in time.</p>
<p>There are some situations where this solution as a bit to basic. A record might span across multiple table, like an invoice with invoice lines. In that case, we don&#8217;t want to revision each individual invoice line, but the invoice as a whole. I&#8217;ll come around in a follow up with a solution for this. I can tell up front that this solution is unfortunately not as clean as these basics.</p>
<p><strong>Continue reading</strong><br />
Please continue reading the follow up article &#8216;<a href="http://www.adaniels.nl/articles/versioning-mysql-data-multi-table-records/">Versioning MySQL data: Multi-table records</a>&#8216;. At the bottom of that article you&#8217;ll find <a href="http://www.adaniels.nl/articles/versioning-mysql-data-multi-table-records/#download">a download link</a> for a script that adds revisioning to existing MySQL tables.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/versioning-mysql-data/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>EAV multi-value fields</title>
		<link>http://www.jasny.net/articles/eav-multi-value-fields/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=eav-multi-value-fields</link>
		<comments>http://www.jasny.net/articles/eav-multi-value-fields/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 16:59:51 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=278</guid>
		<description><![CDATA[In the article &#8216;An alternative way of EAV modelling&#8217;, I discussed how to do EAV modelling by casting all values (except text) to integers. I&#8217;ll continue on that and talk about more advanced topics like multi-value fields. As binary set Not all questions have only a single option. Some fields we want to represent by [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>In the <a href="http://www.adaniels.nl/articles/an-alternative-way-of-eav-modeling/">article &#8216;An alternative way of EAV modelling&#8217;</a>, I discussed how to do EAV modelling by casting all values (except text) to integers. I&#8217;ll continue on that and talk about more advanced topics like multi-value fields.<br />
<span id="more-278"></span></p>
<p><strong>As binary set</strong><br />
Not all questions have only a single option. Some fields we want to represent by radio-buttons, allow the user to select any number of options. For this we can mimic the behaviour of the SET field type of MySQL. A SET is almost similar to an ENUM, except that each bit represents an option. The value can have multiple bits enabled to represent multiple options.</p>
<p>Example: field options for field &#8216;programming language&#8217;</p>
<pre>+-------+-------------+
| value | description |
+-------+-------------+
| 1     | C/C++       |
| 2     | PHP         |
| 4     | Java        |
| 8     | Python      |
| 16    | Ruby        |
+-------+-------------+</pre>
<p>Choosing &#8216;C/C++&#8217;, &#8216;PHP&#8217; and &#8216;Python&#8217; would result in value 11.</p>
<p>There are 2 major disadvantages to this approach. First, with an integer, the number of options is limited to 4*8 = 32. Second, retrieving the description of options would cause joining field on field_option to be done like:</p>
<pre>SELECT value_display(`field_name`, value_display(`field_type`, `value`.`value`, GROUP_CONCAT(`field_option`.`description`), `value`.`text`, `precision`, `date_format`)) FROM `value` INNER JOIN `field` ON `value`.`fid` = `field`.`fid` LEFT JOIN `field_option` ON `value`.`fid` = `field_option`.`fid` AND (IF(`field`.`field_type`='SET, `value`.`value` &amp; `field_option`.`value`, `value`.`value` = `field_option`.`value`)) WHERE `value`.`item_id`=? GROUP BY `value`.`fid`;</pre>
<p>Because of this, the index on the value isn&#8217;t used. Instead, a function has to be performed on each option of the field. This should still give decent enough performance, because this scales linearly and not exponential.</p>
<p><strong>Multiple values</strong><br />
Another way is to store multiple values for the same property. This would mean replacing the primary key from the value table by a normal index.</p>
<pre>CREATE TABLE `value` (
  `item_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `fid` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `value` int(11) NOT NULL DEFAULT '0',
  `text` text,
  KEY `item_field`  (`item_id`,`fid`),
  KEY `value` (`fid`,`value`),
  KEY `text` (`text`(255))
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

SELECT value_display(`field_name`, value_display(`field_type`, `value`.`value`, GROUP_CONCAT(`field_option`.`description`), `value`.`text`, `precision`, `date_format`)) FROM `value` INNER JOIN `field` ON `value`.`fid` = `field`.`fid` LEFT JOIN `field_option` ON `value`.`fid` = `field_option`.`fid` AND `value`.`value` = `field_option`.`value` WHERE `value`.`item_id`=? GROUP BY `value`.`fid`;</pre>
<p>The disadvantage of this, is that structural integrity is no longer enforced by the database. Only for a field with the type &#8216;SET&#8217;, multiple values should be allowed. However the database will allow multiple values for other field types (like numeric fields) as well. It is up to the application to replace existing values.</p>
<p><strong>Ranges with a single field</strong><br />
A completely different type of multi-value is ranges. A range has a top and bottom value. We can solve this by saving 2 values in the database. Of the values, the the highest one is always the upper limit and the lowest is the bottom limit.</p>
<pre>delimiter |
CREATE FUNCTION `value_display` (`type` enum('NUMBER', 'ENUM', 'DATE', 'TIME', 'TEXT'), `value` INT, &lt;strong&gt;`max_value` INT&lt;/strong&gt;, `option` VARCHAR(255), `text` TEXT, `precision` INT, `date_format` VARCHAR(50)) RETURNS VARCHAR(255) CHARACTER SET latin1 NO SQL
BEGIN
  // ...
END

SELECT value_display(`field_name`, value_display(`field_type`, MIN(`value`.`value`), IF(COUNT(*)&gt;1, MAX(`value`.`value`, NULL), GROUP_CONCAT(`field_option`.`description`), `value`.`text`, `precision`, `date_format`)) FROM `value` INNER JOIN `field` ON `value`.`fid` = `field`.`fid` LEFT JOIN `field_option` ON `value`.`fid` = `field_option`.`fid` AND `value`.`value` = `field_option`.`value` WHERE `value`.`item_id`=? GROUP BY `value`.`fid`;</pre>
<p><strong>Range by 2 fields</strong><br />
Another was of looking at ranges is that the are simply 2 individual fields, eg `min weight` and `max weight`. When filtering you might want to get all items that have 70 kg in their weight range. You would translate this to `min weight` <= 70 and `max weight` >= 70. (In the example query `min weight` has fid=2 and `max weight` fid=3.)</p>
<pre>SELECT `item`.* FROM `item` INNER JOIN `value` ON `item`.`id`=`value`.`item_id` AND `value`.`fid` IN (2, 3) WHERE (`value`.`fid`=2 AND `value`.`value` &lt;= 70) OR (`value`.`fid`=3 AND `value`.`value` &gt;= 70) HAVING count(*) =2 GROUP BY `item`.`id`;</pre>
<p><strong>Conclusion</strong><br />
We see that using multi-value fields forces to group on fid and generally complicates the queries. If you only need ranges it might be a good idea to use 2 fields instead to keep the queries simpler.</p>
<p><i>The code in this article has not been tested.</i></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/eav-multi-value-fields/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Doing multiple inheritance in PHP</title>
		<link>http://www.jasny.net/articles/how-i-php-multiple-inheritance/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-i-php-multiple-inheritance</link>
		<comments>http://www.jasny.net/articles/how-i-php-multiple-inheritance/#comments</comments>
		<pubDate>Sat, 26 Sep 2009 19:38:48 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Linux desktop]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=242</guid>
		<description><![CDATA[Officially PHP doesn&#8217;t support multiple inheritance. There are several ways around this, without having to duplicate code. PHP 5.4 will support Traits. This concept is almost similar to mixins. For more information check the PHP manual. Wrapper The most commonly used method is to use a wrapper object. 1 2 3 4 5 6 7 [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>Officially PHP doesn&#8217;t support multiple inheritance. There are several ways around this, without having to duplicate code.</p>
<p><span style="font-style: italic; color: #21759B">PHP 5.4 will support Traits. This concept is almost similar to mixins. For more information check <a href="http://www.php.net/manual/en/language.oop5.traits.php">the PHP manual</a>.</span><br />
<span id="more-242"></span></p>
<h2>Wrapper</h2>
<p>The most commonly used method is to use a <a href="http://en.wikipedia.org/wiki/Wrapper_pattern">wrapper</a> object.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar" style="right: 15px;" ><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"style=" height: 252px;"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
</pre></td><td class="de1"><pre class="de1"><span class="kw2">&lt;?php</span>
&nbsp;
abstract <span class="kw2">class</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="re0">$path</span><span class="sy0">;</span>
&nbsp; 
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$path</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span> <span class="sy0">=</span> <span class="re0">$path</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> <span class="kw3">rename</span><span class="br0">&#40;</span><span class="re0">$newname</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw3">rename</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="sy0">,</span> <span class="re0">$newname</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span> <span class="sy0">=</span> <span class="re0">$newname</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">File</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> getContents<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">file_get_contents</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">Dir</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> <span class="kw3">scandir</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">scandir</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">Symlink</span>
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">protected</span> <span class="re0">$node</span><span class="sy0">;</span>
&nbsp;
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$node</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">node</span> &nbsp;<span class="sy0">=</span> <span class="re0">$node</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> target<span class="br0">&#40;</span><span class="re0">$resolve</span><span class="sy0">=</span><span class="kw4">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$resolve</span> ? <span class="kw3">realpath</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">node</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw3">readlink</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">node</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp; 
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __call<span class="br0">&#40;</span><span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$args</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">call_user_func_array</span><span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">node</span><span class="sy0">,</span> <span class="re0">$method</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$args</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re0">$dir</span> <span class="sy0">=</span> <span class="kw2">new</span> <span class="kw3">Dir</span><span class="br0">&#40;</span><span class="st0">&quot;/proc&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$linktodir</span> <span class="sy0">=</span> <span class="kw2">new</span> <span class="kw3">Symlink</span><span class="br0">&#40;</span><span class="kw2">new</span> <span class="kw3">Dir</span><span class="br0">&#40;</span><span class="st0">&quot;/proc/self&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw3">var_dump</span><span class="br0">&#40;</span><span class="re0">$linktodir</span><span class="sy0">-&gt;</span><span class="me1">scandir</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// Will be called through __call()</span>
<span class="kw1">echo</span> <span class="re0">$linktodir</span><span class="sy0">-&gt;</span><span class="me1">target</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">&lt;?php

abstract class FsNode
{
  public $path;
  
  public function __construct($path) {
    $this-&gt;path = $path;
  }

  public function rename($newname) {
    rename($this-&gt;path, $newname);
    $this-&gt;path = $newname;
  }
}

class File extends FsNode
{
  public function getContents() {
    return file_get_contents($this-&gt;path);
  }
}

class Dir extends FsNode
{
  public function scandir() {
    return scandir($this-&gt;path);
  }
}

class Symlink
{
  protected $node;

  public function __construct($node) {
    $this-&gt;node  = $node;
  }

  public function target($resolve=false) {
    return $resolve ? realpath($this-&gt;node-&gt;path) : readlink($this-&gt;node-&gt;path);
  }
  
  public function __call($method, $args) {
    return call_user_func_array(array($this-&gt;node, $method), $args);
  }
}

$dir = new Dir("/proc");
$linktodir = new Symlink(new Dir("/proc/self"));

var_dump($linktodir-&gt;scandir()); // Will be called through __call()
echo $linktodir-&gt;target(true), "\n";</pre></div></div>

<p>A disadvantage is that is no longer possible to see if a node is a dir by using instanceof. Also, if most of the methods are defined in the wrapped class, this solution will hurt performance.</p>
<h2>Mixin</h2>
<p>A far more interesting approach is to use a <a href="http://en.wikipedia.org/wiki/Mixin">mixins</a>. When you call a non-static method, $this is always passed to that method. This is also the case if the calling object is not inherited from the called class. We can use that to our advantage to do the reverse of the wrapper.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar" style="right: 15px;" ><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"style=" height: 252px;"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
</pre></td><td class="de1"><pre class="de1">abstract <span class="kw2">class</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="re0">$mixin</span><span class="sy0">;</span>
&nbsp; <span class="kw2">public</span> <span class="re0">$path</span><span class="sy0">;</span>
&nbsp; 
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$path</span><span class="sy0">,</span> <span class="re0">$mixin</span><span class="sy0">=</span><span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span> <span class="sy0">=</span> <span class="re0">$path</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">mixin</span> <span class="sy0">=</span> <span class="re0">$mixin</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; <span class="kw2">function</span> <span class="kw3">rename</span><span class="br0">&#40;</span><span class="re0">$newname</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw3">rename</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="sy0">,</span> <span class="re0">$newname</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span> <span class="sy0">=</span> <span class="re0">$newname</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; <span class="kw2">public</span> &nbsp;<span class="kw2">function</span> __call<span class="br0">&#40;</span><span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$args</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">mixin</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">ctype_alnum</span><span class="br0">&#40;</span><span class="re0">$method</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">is_callable</span><span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">mixin</span><span class="sy0">,</span> <span class="re0">$method</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">eval</span><span class="br0">&#40;</span><span class="st0">&quot;return <span class="es4">{$this-&gt;mixin}</span>::<span class="es4">$method</span>(&quot;</span> <span class="sy0">.</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw3">empty</span><span class="br0">&#40;</span><span class="re0">$args</span><span class="br0">&#41;</span> ? <span class="st_h">'$args['</span> <span class="sy0">.</span> <span class="kw3">join</span><span class="br0">&#40;</span><span class="st_h">'], $args['</span><span class="sy0">,</span> <span class="kw3">array_keys</span><span class="br0">&#40;</span><span class="re0">$args</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st_h">']'</span> <span class="sy0">:</span> <span class="st_h">''</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st0">&quot;);&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="kw3">trigger_error</span><span class="br0">&#40;</span><span class="st0">&quot;Call to undefined method &quot;</span> <span class="sy0">.</span> <span class="kw3">get_class</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st0">&quot;::<span class="es4">$method</span>()&quot;</span><span class="sy0">,</span> <span class="kw4">E_USER_ERROR</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">File</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> getContents<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">file_get_contents</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">Dir</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> <span class="kw3">scandir</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">scandir</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">Symlink</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> target<span class="br0">&#40;</span><span class="re0">$resolve</span><span class="sy0">=</span><span class="kw4">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$resolve</span> ? <span class="kw3">realpath</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw3">readlink</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re0">$dir</span> <span class="sy0">=</span> <span class="kw2">new</span> <span class="kw3">Dir</span><span class="br0">&#40;</span><span class="st0">&quot;/proc&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$linktodir</span> <span class="sy0">=</span> <span class="kw2">new</span> <span class="kw3">Dir</span><span class="br0">&#40;</span><span class="st0">&quot;/proc/self&quot;</span><span class="sy0">,</span> <span class="st_h">'Symlink'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw3">var_dump</span><span class="br0">&#40;</span><span class="re0">$linktodir</span><span class="sy0">-&gt;</span><span class="me1">scandir</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">echo</span> <span class="re0">$linktodir</span><span class="sy0">-&gt;</span><span class="me1">target</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span> <span class="co1">// Will be called through __call()</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">abstract class FsNode
{
  public $mixin;
  public $path;
  
  public function __construct($path, $mixin=null) {
    $this-&gt;path = $path;
    $this-&gt;mixin = $mixin;
  }

  function rename($newname) {
    rename($this-&gt;path, $newname);
    $this-&gt;path = $newname;
  }

  public  function __call($method, $args) {
    if (isset($this-&gt;mixin) &amp;&amp; ctype_alnum($method) &amp;&amp; is_callable(array($this-&gt;mixin, $method))) {
      return eval("return {$this-&gt;mixin}::$method(" . (!empty($args) ? '$args[' . join('], $args[', array_keys($args)) . ']' : '') . ");");
    }
    trigger_error("Call to undefined method " . get_class($this) . "::$method()", E_USER_ERROR);
  }
}

class File extends FsNode
{
  public function getContents() {
    return file_get_contents($this-&gt;path);
  }
}

class Dir extends FsNode
{
  public function scandir() {
    return scandir($this-&gt;path);
  }
}

class Symlink extends FsNode
{
  public function target($resolve=false) {
    return $resolve ? realpath($this-&gt;path) : readlink($this-&gt;path);
  }
}

$dir = new Dir("/proc");
$linktodir = new Dir("/proc/self", 'Symlink');

var_dump($linktodir-&gt;scandir());
echo $linktodir-&gt;target(true), "\n"; // Will be called through __call()</pre></div></div>

<p><b>caveat:</b> The Symlink class is never instantiated. Properties defined in the Symlink class are ignored. Also, since Symlink doesn&#8217;t extends Dir, it&#8217;s not possible to access protected properties defined in Dir.</p>
<h2>Compile time mixin</h2>
<p>To see if a node is a symlink, you would need to do </p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar"><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">isset</span><span class="br0">&#40;</span><span class="re0">$file</span><span class="sy0">-&gt;</span><span class="me1">mixin</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="br0">&#40;</span><span class="re0">$file</span><span class="sy0">-&gt;</span><span class="me1">mixin</span> <span class="sy0">===</span> <span class="st_h">'Symlink'</span> <span class="sy0">||</span> <span class="kw3">is_subclass_of</span><span class="br0">&#40;</span><span class="re0">$file</span><span class="sy0">-&gt;</span><span class="me1">mixin</span><span class="sy0">,</span> <span class="st_h">'Symlink'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; <span class="co1">//...</span>
<span class="br0">&#125;</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">if (isset($file-&gt;mixin) &amp;&amp; ($file-&gt;mixin === 'Symlink' || is_subclass_of($file-&gt;mixin, 'Symlink'))) {
  //...
}</pre></div></div>

<p>It would be nicer if you could simply use instance of. This is only possible by defining all combination. We can still use mixins though to prevent having to duplicate code.</p>

<div class="bwp-syntax-block clearfix">
<div class="bwp-syntax-toolbar" style="right: 15px;" ><div class="bwp-syntax-control"><a href="javascript:;" class="bwp-syntax-source-switch" title="View Source Code"></a></div></div>
<div class="bwp-syntax-wrapper clearfix bwp-syntax-simple"style=" height: 252px;"><table class="php"><tbody><tr class="li1"><td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
</pre></td><td class="de1"><pre class="de1">abstract <span class="kw2">class</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">protected</span> <span class="re0">$mixin</span><span class="sy0">;</span>
&nbsp; <span class="co1">// Same as above</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">File</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="co1">// Same as above</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> <span class="kw3">Dir</span> <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="co1">// Same as above</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">interface</span> <span class="kw3">Symlink</span>
<span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> Symlink_Methods <span class="kw2">extends</span> FsNode
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">public</span> <span class="kw2">function</span> target<span class="br0">&#40;</span><span class="re0">$resolve</span><span class="sy0">=</span><span class="kw4">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$resolve</span> ? <span class="kw3">realpath</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw3">readlink</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">path</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> SymlinkFile <span class="kw2">extends</span> <span class="kw3">File</span> implements <span class="kw3">Symlink</span>
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">protected</span> <span class="re0">$mixin</span> <span class="sy0">=</span> <span class="st_h">'Symlink_Methods'</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> SymlinkDir <span class="kw2">extends</span> <span class="kw3">Dir</span> implements <span class="kw3">Symlink</span>
<span class="br0">&#123;</span>
&nbsp; <span class="kw2">protected</span> <span class="re0">$mixin</span> <span class="sy0">=</span> <span class="st_h">'Symlink_Methods'</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re0">$dir</span> <span class="sy0">=</span> <span class="kw2">new</span> <span class="kw3">Dir</span><span class="br0">&#40;</span><span class="st0">&quot;/proc&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$linktodir</span> <span class="sy0">=</span> <span class="kw2">new</span> SymlinkDir<span class="br0">&#40;</span><span class="st0">&quot;/proc/self&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw3">var_dump</span><span class="br0">&#40;</span><span class="re0">$linktodir</span><span class="sy0">-&gt;</span><span class="me1">scandir</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">echo</span> <span class="re0">$linktodir</span><span class="sy0">-&gt;</span><span class="me1">target</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span> <span class="co1">// Will be called through __call()</span>
&nbsp;
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$dir</span> instanceof <span class="kw3">Dir</span><span class="br0">&#41;</span> &nbsp;<span class="sy0">;</span> <span class="co1">// True</span>
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$dir</span> instanceof <span class="kw3">Symlink</span><span class="br0">&#41;</span> &nbsp;<span class="sy0">;</span> <span class="co1">// False</span>
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$linktodir</span> instanceof <span class="kw3">Dir</span><span class="br0">&#41;</span> &nbsp;<span class="sy0">;</span> <span class="co1">// True</span>
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$linktodir</span> instanceof <span class="kw3">Symlink</span><span class="br0">&#41;</span> &nbsp;<span class="sy0">;</span> <span class="co1">// True</span></pre></td></tr></tbody></table></div>
<div class="bwp-syntax-source"><pre class="no-parse">abstract class FsNode
{
  protected $mixin;
  // Same as above
}

class File extends FsNode
{
  // Same as above
}

class Dir extends FsNode
{
  // Same as above
}

interface Symlink
{}

class Symlink_Methods extends FsNode
{
  public function target($resolve=false) {
    return $resolve ? realpath($this-&gt;path) : readlink($this-&gt;path);
  }
}

class SymlinkFile extends File implements Symlink
{
  protected $mixin = 'Symlink_Methods';
}

class SymlinkDir extends Dir implements Symlink
{
  protected $mixin = 'Symlink_Methods';
}

$dir = new Dir("/proc");
$linktodir = new SymlinkDir("/proc/self");

var_dump($linktodir-&gt;scandir());
echo $linktodir-&gt;target(true), "\n"; // Will be called through __call()

if ($dir instanceof Dir)  ; // True
if ($dir instanceof Symlink)  ; // False
if ($linktodir instanceof Dir)  ; // True
if ($linktodir instanceof Symlink)  ; // True</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/how-i-php-multiple-inheritance/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Hide Gnome Panel</title>
		<link>http://www.jasny.net/articles/hide-gnome-panel/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hide-gnome-panel</link>
		<comments>http://www.jasny.net/articles/hide-gnome-panel/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 18:17:18 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Random thoughts]]></category>
		<category><![CDATA[top]]></category>

		<guid isPermaLink="false">http://blog.adaniels.nl/?p=215</guid>
		<description><![CDATA[This article shows how to move Gnome Panels to the Compiz widget layer.<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>Since a few months I&#8217;ve done away with using the Gnome main menu. Instead I use <a href="http://do.davebsd.com/">Gnome Do</a>. I removed the bottom toolbar long ago, because always use alt-tab. </p>
<p>I&#8217;m not using the top toolbar much either. It was just taking up valuable screen space. I contains only the notification area and a logout button. I was looking at a way to remove it completely. The answer came in the Compiz widget layer. By placing it on the widget layer, fullsize windows actually fill the full screen, but the notification area is still available for applications who need it.</p>
<p>To move Gnome panel to the Widget layer, open &#8216;CompizConfig Settings Manager&#8217; and enable &#8216;Widget Layer&#8217;. Go to tab &#8216;Behaviour&#8217; and add the following text for the &#8216;Widget Windows&#8217; field:</p>
<pre>(class=Gnome-panel &amp; type=Dock)</pre>
<p>The desktop will now be completely clean:<br />
<a rel="shadowbox" href="http://www.jasny.net/wp-content/uploads/desktop-clean.png"><img src="http://www.jasny.net/wp-content/uploads/desktop-clean-300x187.png" alt="Desktop clean" title="desktop-clean" width="300" height="187" class="alignnone size-medium wp-image-217" /></a></p>
<p>With <F9> we can display the widget layer, where the panel is found:<br />
<a rel="shadowbox" href="http://www.jasny.net/wp-content/uploads/desktop-widgets.png"><img src="http://www.jasny.net/wp-content/uploads/desktop-widgets-300x187.png" alt="Desktop Widgets" title="desktop-widgets" width="300" height="187" class="alignnone size-medium wp-image-219" /></a></p>
<p>PS. The widgets you see on the widget layer are <a href="http://www.screenlets.org/index.php/Home">screenlets</a>. Ubuntu has the screenlets package in the universe repository.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/hide-gnome-panel/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How I PHP: How to take a website offline.</title>
		<link>http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-i-php-how-to-take-a-website-offline</link>
		<comments>http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/#comments</comments>
		<pubDate>Wed, 17 Jun 2009 18:48:34 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Linux desktop]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[top]]></category>

		<guid isPermaLink="false">http://blog.adaniels.nl/?p=211</guid>
		<description><![CDATA[I&#8217;ve seen a lot of methods used to take a website temporarily off-line for maintenance. Most involve a using PHP to disable the site or renaming the index file. There is however a far better method of doing this, by placing the following in the vhost file or in an .htaccess file in the document [...]<p class="extra"><a href="http://lessmade.com/themes/min" title="min theme" >A minimal wordpress theme by Jared Erickson</a></p>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve seen a lot of methods used to take a website temporarily off-line for maintenance. Most involve a using PHP to disable the site or renaming the index file. There is however a far better method of doing this, by placing the following in the vhost file or in an .htaccess file in the document root:</p>
<pre>Header always set Retry-After "Thu, 18 Jun 2009 08:00:00 +0200"
Redirect 503 /</pre>
<p>This way you are sure no part of the site is used. Also by returning a 503 http response, search-engine crawlers will not reindex your site right at the moment it is down. You can use &#8216;ErrorDocument&#8217; to place a different text than the apache default.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
