<?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>Rommel Santor&#039;s Clog</title>
	<atom:link href="https://rommelsantor.com/clog/feed/" rel="self" type="application/rss+xml" />
	<link>https://rommelsantor.com/clog</link>
	<description>my exploits and misadventures in programming</description>
	<lastBuildDate>Thu, 04 Feb 2016 12:56:01 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.0.38</generator>
	<item>
		<title>30 Second Delay with PHP and Memcache Sessions</title>
		<link>https://rommelsantor.com/clog/2016/02/02/30-second-delay-php-memcache-sessions/</link>
		<comments>https://rommelsantor.com/clog/2016/02/02/30-second-delay-php-memcache-sessions/#comments</comments>
		<pubDate>Wed, 03 Feb 2016 07:08:02 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[Bugs]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=459</guid>
		<description><![CDATA[We upgraded the servers at NeatoShop.com and Neatorama.com a couple of weeks ago, and in the past week we started noticing and receiving reports that on &#8220;some&#8221; page loads there was a 30-second delay where the page seemed to hang before finally returning any content. The common things we could put a finger on were [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>We upgraded the servers at NeatoShop.com and Neatorama.com a couple of weeks ago, and in the past week we started noticing and receiving reports that on &#8220;some&#8221; page loads there was a 30-second delay where the page seemed to hang before finally returning any content.</p>
<p>The common things we could put a finger on were 1) it would seem to happen with a raw/initial page load (e.g., in a brand new incognito window), 2) it would not hang up anymore after that first page load, and 3) it seemed to happen only if we loaded neatoshop.com which was then redirected to www.neatoshop.com.</p>
<p>It took a ton of code profiling and countless attempts to reproduce the problem (because it didn&#8217;t happen for me on <i>every</i> new incognito page load), but I finally traced the delay down to <code>session_start()</code>. This didn&#8217;t really make sense to me because we&#8217;ve used php5-memcache (obviously with Memcached) for handling sessions with redundancy across our 7 web servers, and nothing regarding sessions nor Memcached changed on our end any time recently. So what could the problem be?</p>
<p><span id="more-459"></span>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">// <![CDATA[

// ]]&gt;</script></div>
</p>
<p>It started to seem like a pointless shot in the dark to keep googling for clues, but something that stuck out in my mind were reports of session <i>files</i> getting locked if there were two simultaneous requests from the same user. This didn&#8217;t seem to apply since we&#8217;re dealing with Memcached sessions and not file-based sessions, but then I noticed the new <code>memcache.lock_timeout</code> option in php5-memcache v3.0.4 which has a default value of 15 seconds.</p>
<p>Hmm&#8230; 15 seconds with a lock on two simultaneous requests seems like it could result in a 30 second delay&#8230; ya think? There&#8217;s one way to find out.</p>
<p>I tried changing the memcache.lock_timeout value to 2 seconds then trying to repro the problem. Once it seemed like I got the hang-up to occur, I held my breath and the page hung for 4 seconds before loading. Then I changed the value to 1 second and tried again, and as I&#8217;d hoped, the loading time was 2 seconds!</p>
<p>Finally, I&#8217;ve reduced the value to 0 seconds and there seems to no longer be any delay. I&#8217;m not certain of any side effects or unintended consequences of setting the value to zero, but whatever they are, they are insignificant as compared to every customer on an e-commerce site occasionally being subjected to a 30-second delay. I just thought I should share this tale of woe, as I couldn&#8217;t really find any good info on it, and I&#8217;m assuming there must be others facing the same issue.</p>
<p><b>Update!</b></p>
<p>After reducing the value to zero, I started getting reports of slow load times again, which indicates a value of zero is not valid because it causes the default of 15 seconds to be used. So we&#8217;re stuck using a 1-second lock_timeout, which is the only acceptable solution, but a 2-second delay is much better than 30 seconds!</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2016/02/02/30-second-delay-php-memcache-sessions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AngularJS Scroll to Top for New Pages on Single-Page-App</title>
		<link>https://rommelsantor.com/clog/2015/10/20/angularjs-scroll-to-top-for-new-pages-on-single-page-app/</link>
		<comments>https://rommelsantor.com/clog/2015/10/20/angularjs-scroll-to-top-for-new-pages-on-single-page-app/#comments</comments>
		<pubDate>Wed, 21 Oct 2015 07:53:35 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ngRoute]]></category>
		<category><![CDATA[SIngle Page App]]></category>
		<category><![CDATA[SPA]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=444</guid>
		<description><![CDATA[As promised in my last post, I&#8217;m going to try to keep updating with things I learn on my trek down the long road to Angular-ville. As far as I could tell, there isn&#8217;t much info about the issue I was facing online, so either I&#8217;m doing something wrong (and if I am, for heaven&#8217;s [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As promised in my last post, I&#8217;m going to try to keep updating with things I learn on my trek down the long road to Angular-ville. As far as I could tell, there isn&#8217;t much info about the issue I was facing online, so either I&#8217;m doing something wrong (and if I am, for heaven&#8217;s sake, don&#8217;t just sit there; please tell me!) or there aren&#8217;t as many people concerned with what I felt was a noticeable UX flaw in single page apps (SPA). To try to make clear my explanation of the issue, I&#8217;ll just walk through some steps that an end-user might experience with an SPA and how the page responds by default:</p>
<ol>
<li>User loads the home page. Angular fetches the template and inserts it into the ng-view.</li>
<li>User scrolls down the page a bit, say 600px.</li>
<li>User clicks a link to another page. Angular fetches the requested page&#8217;s template and inserts it into the ng-view, but the browser stays scrolled 600px, so the user doesn&#8217;t actually see the content they loaded.</li>
<li>User clicks the browser&#8217;s back button and sees again the content they were at before clicking the link.</li>
</ol>
<p><span id="more-444"></span>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">// <![CDATA[

// ]]&gt;</script></div>
</p>
<p>The quick, dirty, incomplete &#8220;solution&#8221; to this might be to simply detect when the route is changing and auto-scroll to the top of the window in all cases. However, if we did that, upon clicking back in step 4 above, the browser would scroll back to the top of the page instead of landing the user back where they came from. So what we need is a real solution that will auto-scroll to the top of the page when a *new* page is loaded, but allow the browser to restore the scroll position for any page that was navigated away from.</p>
<p>My first thought was to just store the most recently viewed page and detect a new page load, compare the new page to the most recent page, and if it&#8217;s different, scroll to the top. This doesn&#8217;t work, however, when the user clicks back more than one page.</p>
<p>My second thought was to just store the history of pages viewed and only scroll to top if the newly loaded page is not in that history. This, however, doesn&#8217;t take into consideration that a user may go back in the browser then go forward again, and if they go forward to a page they just came from, we don&#8217;t want that scrolling away on them.</p>
<p>No, what we need is to store the history of all pages loaded both backward and forward. Below is the solution I implemented which stores the current page, a stack for all backward pages, and another stack for all forward pages. When the location changes, the new URL is compared to the top of the backward stack and the forward stack. If it&#8217;s either one, the matching element is popped and we leave the scroll position where it is. If it&#8217;s neither, the user must be linking forward into a new path, so the forward stack is emptied.</p>
<p>Overall the solution works pretty nicely. The only less-than-usual thing to be aware of is that if you click a link that takes you backward or forward one page (i.e., instead of clicking the back button back to the homepage you click a &#8220;home&#8221; link), it will look to the code like you used your back button and leave the scroll position unchanged, but I actually like that behavior. It makes the whole SPA thing feel much more solid.</p>
<p>[<a href="https://github.com/rommelsantor/ng-bwdfwdscroll" target="_blank">GitHUB &raquo;</a>]</p>

<pre class="js:nocontrols:nogutter">&lt;script&gt;
// first thing's first; initialize the app
var app = angular.module('yourAppName', ['ngRoute']);// '

// use $rootScope since this is for application-wide behavior
app.run(function _bwdFwdDetect($rootScope, $location) {
  $rootScope.path = $location.path();// stores only the current page being viewed
  $rootScope.pathBwd = [];// stores up to the last page viewed before the current one
  $rootScope.pathFwd = [];// stores starting with the page viewed before coming back to the current one

  // detect that the location is about to change
  $rootScope.$on('$locationChangeStart', function(event) {
    var newPath = $location.path();// take note of the new path (using path instead of url is good)

    // grab the last backward page for comparison
    var bwd = !$rootScope.pathBwd.length ? null :
      $rootScope.pathBwd[$rootScope.pathBwd.length - 1];

    // grab the last forward page for comparison
    var fwd = !$rootScope.pathFwd.length ? null :
      $rootScope.pathFwd[$rootScope.pathFwd.length - 1];

    // if the new page is the last backward page, assume the user went "back"
    if (bwd == newPath) {
      // it's no longer the last backward page, so remove it
      $rootScope.pathBwd.pop();

      // and push into the forward stack the page we're just leaving to go backward from
      $rootScope.pathFwd.push($rootScope.path);
    }
    // the new page is the last page we came backward from, assume the user went "forward"
    else if (fwd == newPath) {
      // it's no longer the last forward page, so remove it
      $rootScope.pathFwd.pop();

      // and push into the backward stack the page we're going forward away from
      $rootScope.pathBwd.push($rootScope.path);
    }
    // we didn't go back or forward; assume it's a new forward trail being started
    else if ($rootScope.path != newPath) {
      // remember the page we're leaving as our last backward page
      $rootScope.pathBwd.push($rootScope.path);

      // empty out our forward stack since we're now starting a wholly new forward path
      $rootScope.pathFwd = [];

      // this is what it's all about; scroll to the top of the freshly-loaded page
      $('html,body').animate({ scrollTop: 0 }, 'slow');
    }

    // now that we're done with our comparisons, we can remember our new current page
    $rootScope.path = newPath;
  });
});
&lt;/script&gt;</pre>

<p><script type="text/javascript">// <![CDATA[
//< ![CDATA[
$("pre").attr({name:'code'});
// ]]&gt;</script></p>
<p>Of course this whole &#8220;new page detection&#8221; thing I&#8217;m doing doesn&#8217;t only have to be used to scroll to the top of the page. There could be any number of things you might want to do depending on whether the route is changing backward or forward or down a new path.</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2015/10/20/angularjs-scroll-to-top-for-new-pages-on-single-page-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AngularJS Auto-Focus Input After Router Template is Loaded in SPA</title>
		<link>https://rommelsantor.com/clog/2015/10/14/angularjs-auto-focus-input-after-router-template-is-loaded-in-spa/</link>
		<comments>https://rommelsantor.com/clog/2015/10/14/angularjs-auto-focus-input-after-router-template-is-loaded-in-spa/#comments</comments>
		<pubDate>Wed, 14 Oct 2015 10:46:16 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[autofocus]]></category>
		<category><![CDATA[ngRoute]]></category>
		<category><![CDATA[SIngle Page App]]></category>
		<category><![CDATA[SPA]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=422</guid>
		<description><![CDATA[It&#8217;s been just a little while (oh, only about 3.5 years) since I last published any new posts here. Too busy. At the moment I&#8217;ve been delving head-first into some modern frameworks like AngularJS and Bootstrap, so I plan to document things I learn along the way that I think will help other developers also new [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s been just a little while (oh, only about 3.5 years) since I last published any new posts here. Too busy.</p>
<p>At the moment I&#8217;ve been delving head-first into some modern frameworks like AngularJS and Bootstrap, so I plan to document things I learn along the way that I think will help other developers also new to these technologies who might come up against some of the same issues or who might just find interesting the things I&#8217;m discovering.</p>
<p>Without further ado, this is my first of such posts, which is a little more advanced than just starting to learn everything from scratch, but I do plan to back-track and cover more in future posts the basics of using AngularJS.</p>
<p><span id="more-422"></span>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">// <![CDATA[

// ]]&gt;</script></div>
</p>
<p>If you&#8217;re developing a Single Page Application (SPA) with Angular, you may find that loading an HTML fragment with a form input that should be auto-focused might not work. Assuming you&#8217;ve already set up ngRoute to dynamically control the routing of your application, the simplest way I came up with to set focus on an input after ensuring the HTML template is fully loaded is to define a callback for <code>$routeChangeSuccess</code> which is invoked after the route has finished changing. The best place to respond to that event is in a run block, since it&#8217;s an application-wide action we&#8217;re taking. The trick is that the DOM may still not be ready for you to set focus at that point, but setting focus inside a $timeout will ensure the $digest loop has ended.</p>
<p>The other, more obvious decision was to ensure the input I want to auto-focus has the &#8220;autofocus&#8221; attribute so it can be targeted using a simple jQuery selector. Below is a bit of sample code demonstrating what I just described with comments, so hopefully it&#8217;s all pretty obvious to you (and it <i>should</i> be if you&#8217;re using Angular yourself).</p>
<p>[<a href="https://github.com/rommelsantor/ng-dynautofocus" target="_blank">GitHUB &raquo;</a>]</p>

<pre class="js:nocontrols:nogutter">&lt;script&gt;
// first thing's first; initialize the app
var app = angular.module('yourAppName', ['ngRoute']);// '

//... do other things like set up your routing (not covered here)

// set up a Run Block
app.run(function _forceAutofocus($rootScope, $timeout) {

  // tell Angular to call this function when a route change completes
  $rootScope.$on('$routeChangeSuccess', function() {
    // we can't set focus at this point; the DOM isn't ready for us

    // instead, we define a callback to be called after the $digest loop
    $timeout(function(){
      // once this is executed, our input should be focusable, so find (with jQuery)
      // whatever is on the page with the autofocus attribute and focus it; fin.
      $('[autofocus]').focus();
    });
  });

});
&lt;/script&gt;</pre>

<p><script type="text/javascript">// <![CDATA[
//< ![CDATA[
$("pre").attr({name:'code'});
// ]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2015/10/14/angularjs-auto-focus-input-after-router-template-is-loaded-in-spa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fixing the IE7 &lt;Button&gt; Submit Value</title>
		<link>https://rommelsantor.com/clog/2012/03/12/fixing-the-ie7-submit-value/</link>
		<comments>https://rommelsantor.com/clog/2012/03/12/fixing-the-ie7-submit-value/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 18:22:52 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[attribute]]></category>
		<category><![CDATA[iesucks]]></category>
		<category><![CDATA[internet explorer]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=334</guid>
		<description><![CDATA[If you&#8217;ve ever used &#60;BUTTON&#62; tags in your HTML forms, you&#8217;ve probably noticed that there are a couple of problems with them in IE7 and older. For starters, clicking a BUTTON does not cause its form to be submitted. This means that a user will never be able to submit the form by clicking it. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;ve ever used <code>&lt;BUTTON&gt;</code> tags in your HTML forms, you&#8217;ve probably noticed that there are a couple of problems with them in IE7 and older.</p>
<p>For starters, clicking a BUTTON does not cause its form to be submitted. This means that a user will never be able to submit the form by clicking it. Furthermore, if you are using JavaScript including jQuery to trigger a callback upon form submit, that callback will never be fired.</p>
<p><span id="more-334"></span>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
That problem is easy enough to fix by making all BUTTON elements trigger form submit, but the second problem which is a tad more difficult to work around is that IE7 will submit the incorrect value of the BUTTON because it uses the innerHTML of the pair of &lt;BUTTON&gt;&lt;/BUTTON&gt; tags rather than the value=&#8221;&#8221; attribute. Consider the following form:</p>
<pre>
&lt;form method="post" action=""&gt;
  &lt;!-- ... your form fields go here ... --&gt;

  &lt;button name="proceed" value="save"&gt;Update Record&lt;/button&gt;
  &lt;button name="proceed" value="undo"&gt;Cancel&lt;/button&gt;
&lt;/form&gt;
</pre>
<p>The easiest fix, which might be your best option, would be to simply replace those BUTTON elements with INPUT elements:</p>
<pre>
  &lt;input type="submit" name="proceed" value="Update Record"/&gt;
  &lt;input type="submit" name="proceed" value="Cancel"/&gt;
</pre>
<p>Again, this is a simple fix, and if it satisfies your requirements, you should definitely stick with it. The problems with this, however, are:</p>
<ol>
<li>You may be dealing with legacy or third-party code and you don&#8217;t want to go fumbling through thousands of lines of someone else&#8217;s code to change their HTML. (This could also break other parts of the system that make assumptions about the fields being of type BUTTON or having a specific value attribute.)</li>
<li>The other issue is that you cannot specify an arbitrary value for the fields because the value attribute also doubles as the user-friendly display value.</li>
</ol>
<p><br/>So, to tackle both of our issues, we&#8217;ll need to bind a click handler to every BUTTON on a page contained within a FORM element. We can do this with jQuery by using the following code:</p>
<pre name="code" class="js:nocontrols:nogutter">
$(document).ready(function(){
  // use live() to handle dynamically added buttons (pre jQuery v1.7)
  $("form button").live('click',function(){
    var f = $(this).get(0).form;

    if (typeof(f) !== 'undefined') {
      if (this.type &#038;&#038; this.type != 'submit')
        return;

      if (this.name) {
        this.trueName = this.name;
        this.name = '';
      }

      $("input[type='hidden'][name='"+this.trueName+"']", f).remove();

      if (typeof(this.attributes.value) !== 'undefined')
        $(f)
          .append('<input type="hidden" name="'+this.trueName+
            '" value="'+this.attributes.value.value+'"/>');

      $(f).trigger('submit');
      return false;
    }
  });
});
/*
Note: As of jQuery v1.7, live() has been deprecated. You can replace
that line above with the following if you're using the latest jQuery:
  $("form").on("click", "button", function(){
*/
</pre>
<p>Note that we don&#8217;t want this code to be executed in other browsers than IE7 and older, so you should put it into a file, let&#8217;s call it <b>ie7.js</b>, and use Microsoft&#8217;s conditional comments in your HTML file to import it only if the user is using a version of Internet Explorer before version 8:</p>
<pre>
&lt;!--[if lt IE 8]&gt;
&lt;script type="text/javascript" src="ie7.js"&gt;&lt;/script&gt;
&lt;![endif]--&gt;
</pre>
<p>Now, if you&#8217;re interested, let&#8217;s consider how that code works. It will cause any click of a BUTTON element contained within a FORM element to trigger the callback we defined. The callback does two important things:</p>
<ol>
<li>It <i>appends</i> a hidden INPUT element to the FORM using the name of the clicked BUTTON and its real value attribute (rather than the display label).</li>
<li>It triggers the submit event on the FORM element, so any callbacks you&#8217;ve bound on form submission will get executed.</li>
</ol>
<p><br/>Side note: Fetching the actual &#8220;value&#8221; attribute can seem a tricky thing to figure out. If you&#8217;re just trying to use $button.attr(&#8216;value&#8217;) you&#8217;ll always get the button label. Instead, we use the &#8220;attributes&#8221; value of the element.</p>
<p>That should be all you need to get your BUTTON elements working properly in IE7.</p>
<p>As an added bonus, you may want to add a handler to submit your form when the user presses enter while focused on an entry field. To do so, you can use this to trigger the click event on the first non-disabled button in the form:</p>
<pre name="code" class="js:nocontrols:nogutter">
$(document).ready(function(){
  $("form").on("keypress", "input,select", function(e){
    if (e.keyCode == 13)
      $("button:not(disabled):first", this.form).trigger('click');
  });
});
</pre>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('html:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2012/03/12/fixing-the-ie7-submit-value/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Generate UUID in PHP</title>
		<link>https://rommelsantor.com/clog/2012/02/23/generate-uuid-in-php/</link>
		<comments>https://rommelsantor.com/clog/2012/02/23/generate-uuid-in-php/#comments</comments>
		<pubDate>Thu, 23 Feb 2012 17:47:02 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[uuid]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=313</guid>
		<description><![CDATA[I posted this last year to PHP.net and thought I&#8217;d just share it here as well. It&#8217;s a short write-up and demonstration of a PHP class you can use to generate various versions of a Universally-Unique Identifier, or UUID. The php5-uuid functions could definitely use some documentation to clarify how they should be used, but [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I posted this last year to PHP.net and thought I&#8217;d just share it here as well. It&#8217;s a short write-up and demonstration of a PHP class you can use to generate various versions of a Universally-Unique Identifier, or UUID.</p>
<p>The php5-uuid functions could definitely use some documentation to clarify how they should be used, but here&#8217;s what I&#8217;ve gleaned by examining the OSSP source code (found here: <a href="http://ossp-uuid.sourcearchive.com/documentation/1.5.1-1ubuntu1/php_2uuid_8c-source.html" target="_blank">http://ossp-uuid.sourcearchive.com/documentation/1.5.1-1ubuntu1/php_2uuid_8c-source.html</a>).</p>
<p>The uuid_make() function takes two arguments when generating v1 or v4, but four arguments are required when generating v3 or v5. The first two arguments have been thoroughly demonstrated and are straightforward, so I&#8217;ll skip to the as-yet non-described arguments.</p>
<p><span id="more-313"></span>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
The third argument to uuid_make() is: $namespace<br />
  &#8211; this is a secondary resource created with uuid_create(); it is apparently used to generate an internal UUID, which is used as the namespace of the output UUID</p>
<p>The fourth argument to uuid_make() is: $url<br />
  &#8211; this is the value that is to be hashed (MD5 for v3, SHA-1 for v5); it may be any string or even null</p>
<p>Here&#8217;s a simple class illustrating the proper usage (note that if php5-uuid is not installed on your system, each function call will just return false):</p>
<pre>
class UUID {
  /**
   * Generates version 1: MAC address
   */
  public static function v1() {
    if (!function_exists('uuid_create'))
      return false;

    $context = $uuid = null;
    uuid_create($context);
    uuid_make($context, UUID_MAKE_V1);
    uuid_export($context, UUID_FMT_STR, $uuid);
    return trim($uuid);
  }

  /**
   * Generates version 3 UUID: MD5 hash of URL
   */
  public static function v3($i_url) {
    if (!function_exists('uuid_create'))
      return false;

    if (!strlen($i_url))
      $i_url = self::v1();

    $context = $namespace = $uuid = null;
    uuid_create($context);
    uuid_create($namespace);

    uuid_make($context, UUID_MAKE_V3, $namespace, $i_url);
    uuid_export($context, UUID_FMT_STR, $uuid);
    return trim($uuid);
  }

  /**
   * Generates version 4 UUID: random
   */
  public static function v4() {
    if (!function_exists('uuid_create'))
      return false;

    $context = $uuid = null;
    uuid_create($context);

    uuid_make($context, UUID_MAKE_V4);
    uuid_export($context, UUID_FMT_STR, $uuid);
    return trim($uuid);
  }

  /**
   * Generates version 5 UUID: SHA-1 hash of URL
   */
  public static function v5($i_url) {
    if (!function_exists('uuid_create'))
      return false;

    if (!strlen($i_url))
      $i_url = self::v1();

    $context = $namespace = $uuid = null;
    uuid_create($context);
    uuid_create($namespace);

    uuid_make($context, UUID_MAKE_V5, $namespace, $i_url);
    uuid_export($context, UUID_FMT_STR, $uuid);
    return trim($uuid);
  }
}
</pre>
<p>And here&#8217;s a demonstration:</p>
<pre>
for ($i = 1; $i <= 3; ++$i) {
  echo 'microtime = ' . microtime(true) . '<br/>';
  echo "V1 UUID: " . UUID::v1() . '<br/>';
  echo "V3 UUID of URL='abc': " . UUID::v3('abc') . '<br/>';
  echo "V4 UUID: " . UUID::v4() . '<br/>';
  echo "V5 UUID of URL=null: " . UUID::v5(null) . '<br/>';
  echo '<hr/>';
}
</pre>
<p>And the output:</p>
<p><code>microtime = 1306620716.0457<br />
V1 UUID: 7fddae8e-8977-11e0-bc11-003048c3b1f2<br />
V3 UUID of URL='abc': 522ec739-ca63-3ec5-b082-08ce08ad65e2<br />
V4 UUID: b3851ec7-4871-4527-92b5-ef5616bae1e6<br />
V5 UUID of URL=null: e129f27c-5103-5c5c-844b-cdf0a15e160d<br />
-------------------<br />
microtime = 1306620716.0465<br />
V1 UUID: 7fddb83e-8977-11e0-9e6e-003048c3b1f2<br />
V3 UUID of URL='abc': 522ec739-ca63-3ec5-b082-08ce08ad65e2<br />
V4 UUID: 7e78fe0d-59b8-4637-af7f-e88d221a7d1e<br />
V5 UUID of URL=null: e129f27c-5103-5c5c-844b-cdf0a15e160d<br />
-------------------<br />
microtime = 1306620716.0467<br />
V1 UUID: 7fddbfb4-8977-11e0-a2bc-003048c3b1f2<br />
V3 UUID of URL='abc': 522ec739-ca63-3ec5-b082-08ce08ad65e2<br />
V4 UUID: 12a940c7-0f3f-46a1-bb5f-bdd602e10654<br />
V5 UUID of URL=null: e129f27c-5103-5c5c-844b-cdf0a15e160d</code></p>
<p>As you can see, the calls to v3() always return the same UUID because the same URL parameter, &#8220;abc&#8221;, is always supplied. The same goes for the v5() function which is always supplied a null URL.</p>
<p>The v4() UUIDs are always entirely different because they are (pseudo)random. And the v1() calls are very similar but just slightly different because it&#8217;s based on the computer&#8217;s MAC address and the current time.</p>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('php:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2012/02/23/generate-uuid-in-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Text Beautify WordPress Plugin</title>
		<link>https://rommelsantor.com/clog/2012/02/09/text-beautify-wordpress-plugin/</link>
		<comments>https://rommelsantor.com/clog/2012/02/09/text-beautify-wordpress-plugin/#comments</comments>
		<pubDate>Thu, 09 Feb 2012 17:44:57 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=304</guid>
		<description><![CDATA[I&#8217;ve just submitted my first ever plugin to the WordPress repository. It&#8217;s called Text Beautify and can be found at the following URL: http://wordpress.org/extend/plugins/text-beautify/ The purpose of the plugin is to beautify post titles, post contents, and comments of your WordPress blog. In post contents and comments, the text is made sentence case. In post [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve just submitted my first ever plugin to the WordPress repository. It&#8217;s called Text Beautify and can be found at the following URL:<br />
<a href="http://wordpress.org/extend/plugins/text-beautify/" target="_blank">http://wordpress.org/extend/plugins/text-beautify/</a></p>
<p>The purpose of the plugin is to beautify post titles, post contents, and comments of your WordPress blog. In post contents and comments, the text is made sentence case. In post titles, it is made title case, so all words are capitalized except for a user-defined list of exceptions, such as: of, an, the, etc. It is really targeted at persons with a refined sense of text aesthetics and people who just want their content to look nicer.</p>
<p><span id="more-304"></span>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
The plugin will also disallow the posting of bothersome repetitive characters. For example, consider someone who uses excessive exclamation marks!!!!! Those will be trimmed down to just a single one! You can define the list of characters that should not be repeated.</p>
<p>Another aesthetic improvement it offers is converting quotation marks, apostrophes, and commas into their &#8220;curly&#8221; equivalents. You can enable or disable any one, so if you only want double quotes made curly, it is supported.</p>
<p>There are a couple of string user customizations allowed regarding full strings. First, you can define a list of terms for which the case must be preserved. One of the issues with beautifying a body of text is that it may turn lowercase or uppercase terms that are supposed to be capitalized or lowercase, respectively. Some examples are: iPhone, Los Angeles, PHP. The second type of customization is to replace any string with another. If you, for example, wanted to expand any occurrence of &#8220;Dr.&#8221; to &#8220;Doctor&#8221; or from &#8220;vs&#8221; to &#8220;versus&#8221; that would be possible. (These are pretty mundane examples, but I&#8217;m sure you can imagine lots of possibilities for this feature.)</p>
<p>Anyway, I hope you check it out and find it useful. If so, let me know with a comment below. Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2012/02/09/text-beautify-wordpress-plugin/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>PHP Human File Size Function</title>
		<link>https://rommelsantor.com/clog/2011/11/19/php-human-file-size-function/</link>
		<comments>https://rommelsantor.com/clog/2011/11/19/php-human-file-size-function/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 08:16:59 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[language]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=281</guid>
		<description><![CDATA[Just found myself needing to display bytes in a human readable format. There are countless examples that use a lot of complex techniques to achieve this, but I wanted a simpler solution. This is the method that came to mind. Rather than basing my algorithm on the numeric value, it is based on the length [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Just found myself needing to display bytes in a human readable format. There are countless examples that use a lot of complex techniques to achieve this, but I wanted a simpler solution. This is the method that came to mind. Rather than basing my algorithm on the numeric value, it is based on the length of the bytes.</p>
<p><span id="more-281"></span>
<pre>
function human_filesize($bytes, $decimals = 2) {
  $sz = 'BKMGTP';
  $factor = floor((strlen($bytes) - 1) / 3);
  return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
}
</pre>
<p>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br />
This will return the number with the appropriate initial (B for bytes, K for kilobytes, M for megabytes, etc.) appended and the numeric with the specified number of decimal digits. It&#8217;s obviously pretty straightforward, but I always like coming up with a new way to do things and this is a faster solution than probably most if not all I&#8217;ve come across.</p>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('php:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/11/19/php-human-file-size-function/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP Uppercase Sentences</title>
		<link>https://rommelsantor.com/clog/2011/11/14/php-uppercase-sentences/</link>
		<comments>https://rommelsantor.com/clog/2011/11/14/php-uppercase-sentences/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 18:25:44 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[grammar]]></category>
		<category><![CDATA[language]]></category>
		<category><![CDATA[sentence]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[ucfirst]]></category>
		<category><![CDATA[uppercase]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=248</guid>
		<description><![CDATA[I&#8217;ve never really had a need to write code to uppercase only sentences in a string, but I now am dealing with large blocks of text content that is often written all uppercase by the author. So I popped on over to the PHP manual. I was pretty certain no such function existed in the [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve never really had a need to write code to uppercase only sentences in a string, but I now am dealing with large blocks of text content that is often written all uppercase by the author. So I popped on over to the <a href="http://php.net/manual/en/function.ucfirst.php" target="_blank" rel="nofollow">PHP manual</a>. I was pretty certain no such function existed in the language, but thought I&#8217;d check if one was added in a newer version.</p>
<p>Alas, no such function existed, so I wrote one myself<span id="more-248"></span>, but in the process of looking at the manual, I noticed a lot of different, very lengthy implementations of functions to make sentences uppercase. For example, this snippet was posted by <a href="http://www.php.net/manual/en/function.ucfirst.php#86902" target="_blank" rel="nofollow">mattalexxpub</a>:</p>
<pre>
function sentence_case($string) {
    $sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
    $new_string = '';
    foreach ($sentences as $key => $sentence) {
        $new_string .= ($key &#038; 1) == 0?
            ucfirst(strtolower(trim($sentence))) :
            $sentence.' ';
    }
    return trim($new_string);
}

print sentence_case('HMM. WOW! WHAT?');

// Outputs: "Hmm. Wow! What?"
</pre>
<p>And this snippet was posted by <a href="http://www.php.net/manual/en/function.ucfirst.php#76384" target="_blank" rel="nofollow">adefoor</a>:</p>
<pre>
function sentence_cap($impexp, $sentence_split) {
    $textbad=explode($impexp, $sentence_split);
    $newtext = array();
    foreach ($textbad as $sentence) {
        $sentencegood=ucfirst(strtolower($sentence));
        $newtext[] = $sentencegood;
    }
    $textgood = implode($impexp, $newtext);
    return $textgood;
}

$text = "this is a sentence. this is another sentence! this is the fourth sentence? no, this is the fourth sentence.";
$text = sentence_cap(". ",$text);
$text = sentence_cap("! ",$text);
$text = sentence_cap("? ",$text);

echo $text; // This is a sentence. This is another sentence! This is the fourth sentence? No, this is the fourth sentence.
</pre>
<p>The long examples continue. I don&#8217;t know if there are any better examples in the manual because there was too much to read through, but here&#8217;s my solution, which does the sentence uppercasing completely and in a single line of code:</p>
<pre>
function ucsentence($i_str, $i_lowercase = false) {
  $i_lowercase &#038;&#038; ($i_str = strtolower($i_str));
  return preg_replace('/(^|[\.!?]"?\s+)([a-z])/e', '"$1" . ucfirst("$2")', $i_str);
}
</pre>
<p>You can pass any string as an argument and it will properly uppercase the first letter of each sentence, including if punctuation is contained within quotes. If you specify a non-empty second argument, the function will first make the entire input string lowercase. This is useful when the string is all uppercase, but the default is to not touch the rest of the string.</p>
<p>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br />
It&#8217;s pretty straightforward, but for the less familiar with regular expressions, I&#8217;ll explain. The function uses a regular expression to match either of two cases:
<ol>
<li>the beginning of the string followed by a lowercase alphabetic</li>
<li>a period (.), exclamation (!), or question mark (?) optionally followed by a quotation mark (&#8220;), followed by a lowercase alphabetic</li>
</ol>
<p>If either of those cases is matched, preg_replace will execute the code in its second argument, which prepends the leading character(s), if any, to the uppercase version of alphabetic.</p>
<p>Et voila. Your string is sentence-cased. There are, of course, some caveats. For instance, there are many cases where your string could contain proper nouns, initials, or abbreviations and those such cases might not be handled as you&#8217;d like. Here are a couple examples with undesired output:</p>
<pre>
$str = 'A FOX NAMED MURPHY BROWN JUMPED OVER THE LAZY DOGS.';
echo ucsentence($str, true);// make it lowercase first because it's all upper
// desired output: A fox named Murphy Brown jumped over the lazy dogs.
// actual output: A fox named murphy brown jumped over the lazy dogs.
</pre>
<pre>
$str = 'the bottle contained five oz. of water.';
echo ucsentence($str);
// desired output: The bottle contained five oz. of water.
// actual output: The bottle contained five oz. Of water.
</pre>
<p>There&#8217;s unfortunately nothing much we can do about things like that except building an extensive list of special circumstances where we wouldn&#8217;t want a period to be considered the end of a sentence. I think we&#8217;ll survive with it as-is.</p>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('php:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/11/14/php-uppercase-sentences/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>jQuery Placeholder Fallback</title>
		<link>https://rommelsantor.com/clog/2011/08/01/jquery-placeholder-fallback/</link>
		<comments>https://rommelsantor.com/clog/2011/08/01/jquery-placeholder-fallback/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 16:36:15 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[HTML5]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[attribute]]></category>
		<category><![CDATA[degradation]]></category>
		<category><![CDATA[fallback]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[placeholder]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=209</guid>
		<description><![CDATA[One of the handy new features for &#60;input&#62; elements in HTML5 is the &#8220;placeholder&#8221; attribute. If you&#8217;re unfamiliar with this attribute, it allows you to pre-populate a text input with instructions which disappear when the element receives focus or there is any entry in the element. For example, if you had a field prompting a [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>One of the handy new features for &lt;input&gt; elements in HTML5 is the &#8220;placeholder&#8221; attribute. If you&#8217;re unfamiliar with this attribute, it allows you to pre-populate a text input with instructions which disappear when the element receives focus or there is any entry in the element.</p>
<p>For example, if you had a field prompting a user to enter their username, the placeholder text might be &#8220;Enter your username here.&#8221; With the introduction and support of the &#8220;placeholder&#8221; attribute, all that would be required is the use of an input tag like &lt;input type=&#8221;text&#8221; placeholder=&#8221;Enter your username here.&#8221;/&gt; and the browser will automatically display your text whenever there is no entry in the field and it does not have the keyboard focus.</p>
<p>The only problem is that older web browsers (and even those that are not-so-old, such as IE8) lack support for placeholders, so a standalone solution is required. After contemplating a couple of different fallback implementations, I decided that for my requirements, an extremely simple implementation would be best.</p>
<p><span id="more-209"></span>Other people have designed jQuery plugins mainly in one of two ways: 1) use the input&#8217;s own value to display the placeholder text when there is no user entry, and 2) float the placeholder text in front of the input.</p>
<p>Option 1 seems like the most obvious solution, but after brief contemplation, it is obviously a very sloppy one considering that overriding the input value means you&#8217;d have to design special handling to carry the true user entry. It also mucks things up that the input might be of type &#8220;password&#8221; which means you can&#8217;t just set the placeholder text as its value, since it will just show up obscured. Furthermore, if the input has a &#8220;maxlength&#8221; attribute that is shorter than the length of your placeholder text, you&#8217;d have to work around that as well. And as far as styling goes, if you wanted your placeholder text to appear differently than the input text, you&#8217;d need to also keep track of the styles of both. Clearly, a complete solution this isn&#8217;t.</p>
<p>Option 2 seems to be the much better implementation. Unfortunately, most all such solutions I&#8217;ve been able to find out there seem to be poorly designed, overlooking several key requirements for half-decent functionality. For example, they ignore the fact that the browser window might be resized (in which case the placeholder needs to move with the input) or the input might become hidden (in which case the placeholder should also be hidden).</p>
<p>And finally, here is the solution I came up with. You should be able to just drop it into your own page as-is, or minify it first if you&#8217;d like. (It&#8217;s a bit bloated here for readability and documentation.)<br />

<pre class="js:nocontrols:nogutter">&lt;script type="text/javascript"&gt;
$(document).ready(function(){// wait until the DOM is ready
  $(function(){// encapsulate our variables into their own scope
    // test if HTML5 placeholder is supported; if so, quit
    var el = document.createElement('input');
    if ('placeholder' in el)
      return;

    // traverse all inputs with a placeholder attribute
    $("input[placeholder],textarea[placeholder]").each(function(){
      var $ip = $(this),// the input itself (in a jQuery object)
          tx = $ip.attr('placeholder');// placeholder text

      // create a label and a span within it
      var $lb = $('<label></label>'),
          $sp = $('<span class="placeholder">'+tx+'</span>').appendTo($lb);

      // the label surrounds the input
      $lb.insertBefore($ip).append($ip);

      // try getting the input's size
      var w = $ip.width(),
          h = $ip.height();

      // if it fails, it's likely because the input is not visible
      if (!w || !h) {
        // clone the input and make it have size/shape without showing it
        var $clone = $ip.clone().appendTo('body').css({
          position : 'absolute',
          visibility : 'hidden',
          display : 'block'
        });

        // fetch the correct size (hopefully)
        w = $clone.width();
        h = $clone.height();

        $clone.remove();
      }

      // copy the position, size, and font into the
      // placeholder text's span
      $sp.css({
        position : 'absolute',
        display : 'block',
        width : w+'px',
        height : h+'px',
        lineHeight : $ip.css('line-height'),
        paddingLeft : $ip.css('padding-left'),
        paddingTop : $ip.css('padding-top'),
        marginLeft : $ip.css('margin-left'),
        marginTop : $ip.css('margin-top'),
        fontSize : $ip.css('font-size'),
        fontWeight : $ip.css('font-weight'),
        overflow : 'hidden',
        cursor : 'text'
      });

      // in MSIE 7 the text is vertically misaligned
      if ($.browser.msie &amp;&amp; parseInt($.browser.version) &lt;= 7)
        $sp.css({marginTop:parseInt($sp.css('margin-top'))+2+'px'});

      // if the input is hidden or shown, so should the placeholder be
      $ip.bind('hide', function(){ $sp.hide(); });
      // when showing, ensure the text is the right size
      $ip.bind('show', function(){
        $sp.show().css({
          width:$ip.width()+'px',
          height:$ip.height()+'px'
        });
      });

      // if the input is starting out hidden or there is a default value in
      // the input already, hide the placeholder
      if (!$ip.is(':visible') || $ip.val().length)
        $sp.hide();

      // when input gets focus, hide the placeholder and
      // when we leave the input, if it has no user entry
      // show the placeholder
      $ip.focus(function(){ $sp.hide(); });
      $ip.blur(function(){ if ($(this).val() == '') $sp.show(); });

      // if the placeholder is focused, send focus to the input
      $sp.focus(function(){ $ip.focus(); });
    });

    // override jQuery.hide() to trigger the 'hide' event
    var hide = $.fn.hide;
    $.fn.hide = function() {
      $(this).trigger('hide');
      return hide.apply(this, arguments);
    };

    // override jQuery.show() to trigger the 'show' event
    var show = $.fn.show;
    $.fn.show = function() {
      $(this).trigger('show');
      return show.apply(this, arguments);
    };
  });
});
&lt;/script&gt;</pre>
<br />
To style the placeholder text, just use CSS selector .placeholder. Keep in mind that if you are specifying any style attributes that have been assigned in the JS above, you must include !important in your CSS for the style to take effect.</p>
<pre class="css:nocontrols:nogutter">
.placeholder { color: #bbb; margin-top: 5px !important; }
/* you should use it alongside, and identically to, your style rules for HTML5
placeholder text, which as of this writing can be done in Mozilla and Webkit
browsers as follows: */
::-webkit-input-placeholder { color: #bbb; margin-top: 5px !important; }
/* single-colon for older Mozilla */
:-moz-placeholder { color: #bbb; margin-top: 5px !important; }
/* double-colon for newer Mozilla */
::-moz-placeholder { color: #bbb; margin-top: 5px !important; }
</pre>
<p>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">// <![CDATA[

// ]]&gt;</script></div>
<br />
Three notes about my implementation:</p>
<p>1) I could obviously make it into a plugin, but for my purposes, I&#8217;m just using it as-is.</p>
<p>2) I opted to override hide() and show() in jQuery. This might not be preferable and could possibly conflict with any other overrides of those same functions that might be present in your scripts. If this is an issue, you can just remove them.</p>
<p>3) The issue with some inputs is they may start out hidden when the page is loaded. If so, the width/height will not be known. To help mitigate this issue, we clone the input and make it take shape so we can determine its size. This helps, but it can still be inaccurate when the size of the input depends on CSS specific to its hierarchy (because we&#8217;re appending the clone to &#8220;body&#8221;, not to the input&#8217;s parent, who might also be non-visible due to some ancestor).</p>
<p>For example, if the CSS for your input is something like:</p>
<pre class="css:nocontrols:nogutter">#some-panel { display: none; }
#some-panel .some-box input { width: 500px; }</pre>
<p>Then we&#8217;ll clone the input, append the clone to &#8220;body&#8221;, and apply its width to the placeholder text. But since the CSS width depends on the input being a descendant of #some-panel and then .some-box, the width of our clone will very certainly not be the 500px we&#8217;re after.</p>
<p>The complete solution is: when showing the container of the input, always explicitly call something like <code>$("#some-panel .some-box input[placeholder]").show()</code> to trigger our input&#8217;s show() event, which triggers its placeholder&#8217;s show() event, which in turn adjusts the text to match the input&#8217;s size. It&#8217;s not elegant, but it works.</p>
<p>As always, if you encounter any issues or have any questions. Please comment below.<br />
<script type="text/javascript">// <![CDATA[
//< ![CDATA[
$("pre").attr({name:'code'});
// ]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/08/01/jquery-placeholder-fallback/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>PHP 5.3 Class Friendship Support</title>
		<link>https://rommelsantor.com/clog/2011/04/23/php-5-3-class-friendship-support/</link>
		<comments>https://rommelsantor.com/clog/2011/04/23/php-5-3-class-friendship-support/#comments</comments>
		<pubDate>Sun, 24 Apr 2011 00:56:27 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=186</guid>
		<description><![CDATA[One of the useful features of OOP languages like C++ is class friendship via the friend keyword. What this allows you to do is define a class that permits other explicitly named classes to touch its private parts. For an overly simple example, let&#8217;s say you have a User class that carries its user info [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>One of the useful features of OOP languages like C++ is class friendship via the friend keyword. What this allows you to do is define a class that permits other explicitly named classes to touch its private parts.</p>
<p>For an overly simple example, let&#8217;s say you have a User class that carries its user info privately, but you also have a Logger class for writing error and info message to a log. If you tried the following, you&#8217;d hit errors telling you that the User properties &#8220;id&#8221; and &#8220;nick&#8221; are private:
<pre>class User {
  private $id;
  private $nick;
  // ...
}

class Logger {
  // ...
  public static function write($str) {
    $user = User::get_current_user();
    fwrite(self::$handle, "User: {$user->nick} ({$user->id}): {$str}\n");
  }
}</pre>
<p>In C++ you could add a simple line to class User like:</p>
<pre>friend class Logger;</pre>
<p>This would permit the Logger class to access any of its private or protected properties and methods. Despite there being numerous people who demand that you should redesign your code instead of using class friendship, there are many cases where friendship is not only useful but necessary. This is all good and fine except for the fact that the PHP language does not have support for friend classes, nor do its developers have any intention of adding it (the last I heard from the PHP team is they long ago decided against such functionality).</p>
<p>This led me to develop a workaround, which wouldn&#8217;t have been possible in the past, but with the flexibility of PHP5.3 and late-static binding, it is now possible. So, without further ado, here&#8217;s my implementation of class Friendship.<br />
<span id="more-186"></span></p>
<pre>class Friendship {
  private static function friend_error($i_type, $i_name, $i_sep = '-&gt;') {
    $bt = debug_backtrace();
    $caller = $bt[1];

    $msg = array();
    !empty($caller['file']) &#038;&#038; $msg[] = $caller['file'];
    !empty($caller['line']) &#038;&#038; $msg[] = "(Line {$caller['line']})";
    $msg[] = "attempted to access inaccessible {$i_type}:";
    $msg[] = get_called_class() . "{$i_sep}{$i_name}";
    $msg = implode(' ', $msg);

    trigger_error($msg, E_USER_ERROR);
  }

  private static function backtrace_test($i_callee = null) {
    $db = debug_backtrace();
    $i = 2;
    do {
      $bt = @$db[$i++];

      if (empty($bt['file']))
        $bt = null;
      else if (preg_match('#^(' . __NAMESPACE__ . ')?\\\\?(call_user_func|call_user_func_array)$#i', @$bt['function']))
        $bt = null;
      else if (@$bt['file'] == __FILE__ || __CLASS__ == @$bt['class'])
        $bt = null;
      else if ($i_callee) {
        if (0 == strcasecmp(get_called_class(), @$bt['class']) &#038;&#038;
            0 == strcasecmp($i_callee, @$bt['function']))
        {
          $bt = @$db[$i];
          break;
        }
      }
    } while ($i &lt; count($db) &#038;&#038; empty($bt));

    $class = @$bt['class'];
    $func = @$bt['function'];

    if (is_subclass_of(get_called_class(), $class))
      return true;

    $prep = function($s) {
		$ns = function($i_name) {
		  if (!is_scalar($i_name))
			return $i_name;
		  return strpos($i_name, '\\') !== false ? $i_name : (__NAMESPACE__ . '\\' . $i_name);
		};
		return strtolower($ns($s));
	};

    $friends = array_map($prep, static::get_friend_classes());

    if (strpos($class, '\\') === false)
      $class = '\\' . $class;
    return in_array(strtolower($class), $friends);
  }

  protected static function get_friend_classes() {
    return array();
  }
  
  public function __call($i_name, $i_args) {
    if (!method_exists($this, $i_name)) {
      $bt = debug_backtrace();
      $bt = $bt[1];
      trigger_error($bt['file'] . ' (Line ' . $bt['line'] . ') ' .
        'call to non-existent method ' . get_called_class() . '-&gt;' .
        $i_name . '()', E_USER_WARNING);
      return null;
    }

    !$this-&gt;backtrace_test($i_name) &#038;&#038; self::friend_error('method', $i_name . '()');

    $rm = new \ReflectionMethod($this, $i_name);
    $accessible = $rm-&gt;isPrivate() || $rm-&gt;isProtected();
    $rm-&gt;setAccessible(true);
    $ret = $rm-&gt;invokeArgs($this, $i_args);
    $rm-&gt;setAccessible($accessible);
    return $ret;
  }

  public static function __callStatic($i_name, $i_args) {
    if (!method_exists(get_called_class(), $i_name)) {
      $bt = debug_backtrace();
      $bt = $bt[1];
      trigger_error($bt['file'] . ' (Line ' . $bt['line'] . ') ' .
        'call to non-existent static method ' . get_called_class() . '::' .
        $i_name . '()', E_USER_WARNING);
      return null;
    }

    !self::backtrace_test($i_name) &#038;&#038; self::friend_error('static method', $i_name . '()', '::');

    $rm = new \ReflectionMethod(get_called_class(), $i_name);
    $accessible = $rm-&gt;isPrivate() || $rm-&gt;isProtected();
    $rm-&gt;setAccessible(true);
    $ret = $rm-&gt;invokeArgs(null, $i_args);
    $rm-&gt;setAccessible($accessible);
    return $ret;
  }

  public function __get($i_var) {
    if (!property_exists($this, $i_var)) {
      $bt = debug_backtrace();
      $bt = $bt[1];
      trigger_error($bt['file'] . ' (Line ' . $bt['line'] . ') ' .
        'attempted to access to non-existent property ' . get_called_class() . '-&gt;' .
        $i_var, E_USER_NOTICE);
      return null;
    }

    !self::backtrace_test() &#038;&#038; self::friend_error('property', '$' . $i_var);
    return $this-&gt;$i_var;
  }

  public function __set($i_var, $i_value) {
    if (property_exists($this, $i_var))
      !self::backtrace_test() &#038;&#038; self::friend_error('property', '$' . $i_var);

    $rp = new \ReflectionProperty($this, $i_var);
    $accessible = $rp-&gt;isPrivate() || $rp-&gt;isProtected();
    $rp-&gt;setAccessible(true);
    $rp-&gt;setValue($this, $i_value);
    $rp-&gt;setAccessible($accessible);
    return $i_value;
  }

  public function __isset($i_var) {
    if (!property_exists($this, $i_var))
      return false;

    !self::backtrace_test() &#038;&#038; self::friend_error('property', '$' . $i_var);

    $rp = new \ReflectionProperty($this, $i_var);
    $accessible = $rp-&gt;isPrivate() || $rp-&gt;isProtected();
    $rp-&gt;setAccessible(true);
    $value = $rp-&gt;getValue($this);
    $rp-&gt;setAccessible($accessible);
    return $value !== null;
  }

  public function __unset($i_var) {
    if (property_exists($this, $i_var))
      !self::backtrace_test() &#038;&#038; self::friend_error('property', '$' . $i_var);

    // we are not able to truly unset private properties, so we'll just make them null
    $rp = new \ReflectionProperty($this, $i_var);
    $accessible = $rp-&gt;isPrivate() || $rp-&gt;isProtected();
    $rp-&gt;setAccessible(true);
    $rp-&gt;setValue($this, null);
    unset($this-&gt;$i_var);
    $rp-&gt;setAccessible($accessible);
  }

  //
  // the functions below are for a future version of PHP
  //
  /*
  public static function __getStatic($i_var) {
  }

  public static function __setStatic($i_var, $i_value) {
  }

  public static function __issetStatic($i_var) {
  }

  public static function __unsetStatic($i_var) {
  }
  */
}</pre>
<p>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br />
Just derive from Friendship and override the get_friend_classes() method. The latter is for global functions, not class methods. I designed it to take into consideration the current namespace and will adjust the specified friends accordingly.</p>
<p>Here&#8217;s an example of how you can use class Friendship:</p>
<pre>class Restricted extends Friendship {
  private $priv_var;
  protected $prot_var;
  public $pub_var;

  protected static function get_friend_classes() {
    return array('Buddy');
  }

  private static function private_static_func() {
    echo __CLASS__ . '::' . __FUNCTION__ . '()&lt;br&gt;';
  }

  private function private_func() {
    echo __CLASS__ . '::' . __FUNCTION__ . '()&lt;br&gt;';
    echo 'I am a ';
    print_r($this);
  }
}

class Buddy {
  public static function touch_privates() {
    Restricted::private_static_func();

    $r = new Restricted();
    $r-&gt;priv_var = 'I changed this private property';
    $r-&gt;prot_var = 'Now a protected one';
    $r-&gt;pub_var = 'Public... not so special';

    $r-&gt;private_func();

    unset($r-&gt;priv_var);
    unset($r-&gt;prot_var);
    unset($r-&gt;pub_var);

    $r-&gt;private_func();

    echo "After unset()'ing, the public property is gone, but private and protected still exist as nulls.&lt;br&gt;";
  }
}

class Stranger {
  public static function deny_privates() {
    // none of these statements will work
    Restricted::private_static_func();

    $r = new Restricted();
    $r-&gt;priv_var = 'I cannot change this private property';
    $r-&gt;prot_var = 'Nor a protected one';
    $r-&gt;private_func();
  }
}

Buddy::touch_privates();
echo '&lt;hr/&gt;';
Stranger::deny_privates();</pre>
<p>The output of the above example is:<br />
<tt><br />
MyNS\Restricted::private_static_func()<br />
MyNS\Restricted::private_func()</p>
<p>I am a MyNS\Restricted Object<br />
(<br />
    [priv_var:MyNS\Restricted:private] =&gt; I changed this private property<br />
    [prot_var:protected] =&gt; Now a protected one<br />
    [pub_var] =&gt; Public... not so special<br />
)</p>
<p>MyNS\Restricted::private_func()</p>
<p>I am a MyNS\Restricted Object<br />
(<br />
    [priv_var:MyNS\Restricted:private] =&gt;<br />
)</p>
<p>After unset()'ing, the public property is gone, but private and protected still exist as nulls.</p>
<p>2011-04-23 17:32:28 -0700 - *E_USER_ERROR*<br />
  /var/www/index.php (Line 52) attempted to access inaccessible static method: MyNS\Restricted::private_static_func()<br />
  /var/www/friendship.php (Line 17)<br />
</tt></p>
<p>Some limitations are:
<ul>
<li>setting/getting static properties is not possible due to PHP&#8217;s lack of __getStatic(), __setStatic(), __issetStatic(), and __unsetStatic() magic methods</li>
<li>private properties cannot be unset(), so they&#8217;re just made null</li>
</ul>
<p><br/>I haven&#8217;t fully tested this in a great variety of examples, but at the very least, it does work as desired in all obvious, simple cases. I&#8217;m not pleased that I had to resort to using a lot of Reflection functionality, but I did just want some way to make any kind of friendship possible in PHP and I believe I&#8217;ve accomplished that. If you notice any issues or have any suggestions for improvement, please do let me know. Thanks for reading!</p>
<p><script type="text/javascript">//< ![CDATA[
/*$("pre").attr({name:'code'}).addClass('php:nocontrols:nogutter');*/
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/04/23/php-5-3-class-friendship-support/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 5.3 Dynamic Namespace Resolution</title>
		<link>https://rommelsantor.com/clog/2011/04/10/php-5-3-dynamic-namespace-resolution/</link>
		<comments>https://rommelsantor.com/clog/2011/04/10/php-5-3-dynamic-namespace-resolution/#comments</comments>
		<pubDate>Mon, 11 Apr 2011 05:52:23 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[namespace]]></category>
		<category><![CDATA[php 5.3]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=176</guid>
		<description><![CDATA[As PHP continues evolving, it just keeps getting better and better. One of the features added in version 5.3 is support for namespaces. If you&#8217;ve started trying to actually use PHP namespaces, you&#8217;ve probably run into some of the more obvious quirks that require you to either retrofit your code or implement a workaround. I [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As PHP continues evolving, it just keeps getting better and better. One of the features added in version 5.3 is support for <a href="http://www.php.net/manual/en/language.namespaces.rationale.php">namespaces</a>. If you&#8217;ve started trying to actually use PHP namespaces, you&#8217;ve probably run into some of the more obvious quirks that require you to either retrofit your code or implement a workaround. I started with the former before realizing that thanks to the namespace feature itself, a simple set of workarounds could do the job.</p>
<p>Specifically, I&#8217;m referring to the fact that namespace resolution happens at compile time, which means that if you attempt to reference a namespaced class or method as a string, it won&#8217;t be recognized unless that string explicitly includes the namespace name. The most apparent case is when calling <code>class_exists()</code>. For example, let&#8217;s say you define class Settings in namespace OssumCMS:</p>
<pre>namespace OssumCMS;

class Settings {
  const MEMCACHED_ADDR = 'none';
  public static function do_something() {
  }
}</pre>
<p>In your code, you might want to do some things like:</p>
<pre>// ...
if (class_exists('Settings'))
  if (@constant('Settings::MEMCACHED_ADDR') != 'none')
    call_user_func(array('Settings', 'do_something'));</pre>
<p>But that would never work because class Settings is defined within namespace OssumCMS. PHP resolves namespaces at compile time, so when class_exists(), constant(), and call_user_func() are called at run time, they won&#8217;t ever find class Settings because it&#8217;s checking only the global namespace.<span id="more-176"></span> The obvious fix is to include the namespace name before every occurrence of the class name:</p>
<pre>// ...
if (class_exists('OssumCMS\Settings'))
  if (@constant('OssumCMS\Settings::MEMCACHED_ADDR') != 'none')
    call_user_func(array('OssumCMS\Settings', 'do_something'));</pre>
<p>Now PHP will know to check for the class within the namespace in which it&#8217;s actually defined. Small victory, especially when you&#8217;re dealing with thousands of lines of pre-existing code. You definitely don&#8217;t want to find every occurrence of every class and prefix it with the namespace. Another small step in the right direction would be to use a function to automatically prefix a string with the current namespace if needed by using a function:</p>
<pre>namespace OssumCMS;

function ns($i_name) {
  if (!is_scalar($i_name))
    return $i_name;
  return strpos($i_name, '\\') !== false ? $i_name : (__NAMESPACE__ . '\\' . $i_name);
}</pre>
<p>This would allow you to simply wrap all your class name strings in that function call, for example:</p>
<pre>if (class_exists(ns($class_name)))
  do_something();</pre>
<p>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br />
But that would still require you to traverse all line of all your source code files doing a search/replace. Wouldn&#8217;t it be easier if instead of manipulating your class name references, you could override the built-in PHP functions? In the old days, you wouldn&#8217;t be able to do something like that, but thanks to namespaces, it&#8217;s entirely possible. All we have to do is create our own class_exists(), constant(), and call_user_func() type functions within our own namespace and add to string arguments the namespace prefix whenever necessary, then call the corresponding global functions.</p>
<pre>namespace OssumCMS;

function ns($i_name) {
  if (!is_scalar($i_name))
    return $i_name;
  return strpos($i_name, '\\') !== false ? $i_name : (__NAMESPACE__ . '\\' . $i_name);
}

function un_ns($i_name) {
  if (!is_scalar($i_name))
    return $i_name;
  return preg_replace('#^' . preg_quote(__NAMESPACE__, '#') . '\\#i', '', $i_name);
}

function constant($i_name)        { return @\constant(ns($i_name)); }
function class_exists($i_name)    { return \class_exists(ns($i_name)); }

function call_user_func_array($i_func, $i_args) {
  is_array($i_func)
    ? (!is_object($i_func[0]) &#038;&#038; ($i_func[0] = ns($i_func[0])))
    : (!is_object($i_func) &#038;&#038; !function_exists($i_func) &#038;&#038; ($i_func = ns($i_func)));
  return \call_user_func_array($i_func, $i_args);
}

function call_user_func($i_func) {
  return call_user_func_array($i_func, array_shift($args = func_get_args()));
}</pre>
<p>Given these overrides, our example block of code would be evaluated as follows</p>
<pre>// ...
if (OssumCMS\class_exists(OssumCMS\ns('Settings')))
  if (OssumCMS\constant(OssumCMS\ns('Settings::MEMCACHED_ADDR')) != 'none')
    OssumCMS\call_user_func(array(OssumCMS\ns('Settings'), 'do_something'));</pre>
<p>There are surely other functions that need overriding, but these are the most obvious suspects. This was a useful little hack for me and I hope you find it useful as well.</p>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('php:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/04/10/php-5-3-dynamic-namespace-resolution/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Automated PDF Manipulation</title>
		<link>https://rommelsantor.com/clog/2011/03/27/automated-pdf-manipulation/</link>
		<comments>https://rommelsantor.com/clog/2011/03/27/automated-pdf-manipulation/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 19:31:17 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[imagemagic]]></category>
		<category><![CDATA[pdf]]></category>
		<category><![CDATA[poppler utils]]></category>
		<category><![CDATA[tesseract]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=170</guid>
		<description><![CDATA[I recently found myself on a project involving PDF file organization. I&#8217;ve always known there to be countless open source PDF manipulation tools, but I&#8217;ve never really used many myself, and especially not via a Linux shell. Specifically what I needed to do is: split multiple pages into each individual page create a thumbnail image [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I recently found myself on a project involving PDF file organization. I&#8217;ve always known there to be countless open source PDF manipulation tools, but I&#8217;ve never really used many myself, and especially not via a Linux shell.</p>
<p>Specifically what I needed to do is:</p>
<ol>
<li>split multiple pages into each individual page</li>
<li>create a thumbnail image to preview each page</li>
<li>extract all readable text from each page for searching</li>
</ol>
<p><span id="more-170"></span></p>
<h2>Splitting PDF Pages</h2>
<p>For this job, I decided to use PDFTK (PDF Tool Kit). The syntax is a little muddy, but easy enough to figure out. For example, given input file blah.pdf:<br />
<code>  pdftk A=blah.pdf cat A1 output blah-pg1.pdf</code></p>
<p>This snippet assigns handle &#8220;A&#8221; to the input file, then issues the &#8220;cat&#8221; command for page 1 of file A (i.e., &#8220;A1&#8243;), then instructs to output that to a new file, blah-pg1.pdf.</p>
<p>This is fine for a single page, but if you want to split every page out of the input file, you will have to execute that command repeatedly, once for each page. There are various ways to determine the number of pages automatically, and one way is to use another PDFTK command:<br />
<code>  pdftk blah.pdf dump_data</code></p>
<p>This will dump various info about the specified file, including the number of pages, so this can be captured into a string and parsed.</p>
<h2>PDF Page to Thumbnail</h2>
<p>Now that each PDF page has been created, this is one of the more obvious, straightforward jobs. With ImageMagick installed, you can issue a command like the following to create a 200px tall JPEG for a single PDF page:<br />
<code>  convert -resize x200 blah-pg1.pdf blah-pg1.jpg</code></p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<h2>Extracting Text &#8211; Text-Based</h2>
<p>If the PDF file was created with digital text (e.g., printed from a text editing application), then the full source text can be extracted easily. One of the packages you will find very useful is Poppler-Utils, which among a few other utilities includes an app called pdftotext.<br />
<code>  pdftotext blah-pg1.pdf blah-pg1.txt</code></p>
<p>This dumps any available text from the PDF file into a text file. If there is no text available, the text file will be almost empty. In this case you&#8217;d need to&#8230;</p>
<h2>Extracting Text &#8211; Image-Based / Scanned OCR</h2>
<p>If the text content is unavailable, it&#8217;s usually because the PDF was created by a scanner or other image generating source. In this case, OCR (optical character recognition) will need to be used to visually scan the image and attempt to recognize each character. There are a few options available, but most of them do a pretty terrible job at recognizing a lot of content. The best option which is under heavy development, in part by Google, is Tesseract OCR.</p>
<p>Tesseract does a really great job at recognizing most all characters in an image. The only trick is converting the source file into a format accepted by Tesseract because it is very specific about the file format it will accept. (It only likes TIFF files with file extension .tif and maximum bpp of 8). For that conversion, we go back to ImageMagick.<br />
<code>  convert -background white -flatten +matte -colorspace Gray -depth 8 -density 600x600 -resample 300x300 blah-pg1.pdf blah-pg1.tif</code></p>
<p>This command will convert the source PDF page into a grayscale TIFF image with 8 bpp and 300 dpi. Now that we have that, we can invoke Tesseract as follows:<br />
<code>  tesseract blah-pg1.tif blah-pg1</code></p>
<p>This will create file blah-pg1.txt containing all the characters it recognized (alphanumeric and otherwise). Thus far, I haven&#8217;t been able to figure out Tesseract&#8217;s configuration options, but there are things I&#8217;d like to modify, such as only accepting alphanumeric and punctuation characters.</p>
<h2>Summary</h2>
<p>All the applications I&#8217;ve discussed above are available across most all Linux distributions, including as packages in Ubuntu (installable via apt-get). There is a lot more that can be done with these tools (such as extraction of embedded images from PDFs and other things), but given just the uses I described above, you should be able to create very powerful software to upload, manage, and index PDF files.</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/03/27/automated-pdf-manipulation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fancy Opts jQuery Plugin &#8211; Custom Radio and Checkbox Inputs</title>
		<link>https://rommelsantor.com/clog/2011/03/16/fancy-opts-jquery-plugin-custom-radio-checkbox-inputs/</link>
		<comments>https://rommelsantor.com/clog/2011/03/16/fancy-opts-jquery-plugin-custom-radio-checkbox-inputs/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 20:57:47 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[checkbox]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[radio button]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=164</guid>
		<description><![CDATA[I was in need of a quality jQuery plugin that would allow me to customize radio buttons and checkboxes. After a bit of googling, I was only able to find offerings that weren&#8217;t fully featured. Specifically, they lacked graceful degradation, required custom HTML, and/or just functioned far too much unlike a native input. As is [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I was in need of a quality jQuery plugin that would allow me to customize radio buttons and checkboxes. After a bit of googling, I was only able to find offerings that weren&#8217;t fully featured. Specifically, they lacked graceful degradation, required custom HTML, and/or just functioned far too much unlike a native input.</p>
<p>As is usually the case, I couldn&#8217;t find what I needed so I decided to create it myself, and so the Fancy Opts plugin was born. It allows you to simply create flexible and completely unique radio button and checkbox inputs.<span id="more-164"></span></p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>I compiled the info, download, and demo info here: <a href="http://rommelsantor.com/jquery/fancyopts" title="Fancy Radio Checkbox Opts jQuery Plugin">Fancy Opts jQuery Plugin</a>. It&#8217;s really simple to use, degrades gracefully, and acts very much like a traditional input.</p>
<p>If you have any comments, suggestions, or problems with the plugin, please feel free to let me know!</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/03/16/fancy-opts-jquery-plugin-custom-radio-checkbox-inputs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>TH Float jQuery Plugin &#8211; Fixed THEAD and TFOOT</title>
		<link>https://rommelsantor.com/clog/2011/03/03/th-float-jquery-plugin-fixed-thead-tfoot-table/</link>
		<comments>https://rommelsantor.com/clog/2011/03/03/th-float-jquery-plugin-fixed-thead-tfoot-table/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 18:39:07 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[tables]]></category>
		<category><![CDATA[tfoot]]></category>
		<category><![CDATA[thead]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=156</guid>
		<description><![CDATA[I recently found myself in need of an elegant, simple solution allowing users to know which column in a table contained which value once the table header has scrolled out of view. A quick google lead me to believe that no such plugin for jQuery currently exists. I did find a few table-centric plugins that [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I recently found myself in need of an elegant, simple solution allowing users to know which column in a table contained which value once the table header has scrolled out of view.</p>
<p>A quick google lead me to believe that no such plugin for jQuery currently exists. I did find a few table-centric plugins that (maybe) include the kind of functionality that I wanted, but nothing looked to provide just what I had in mind. So, I started working on the plugin myself.</p>
<p>I call the plugin TH Float, but it could also aptly be named Sticky Table TH or Fixed THEAD / TFOOT. What it does is make the &lt;thead&gt; or &lt;tfoot&gt; of a table remain floating in view at the top or bottom, respectively, of the scrollable container until the table is completely out of view.<span id="more-156"></span></p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>I&#8217;ve thrown together a simple info page and demo: <a href="http://rommelsantor.com/jquery/thfloat" title="Fixed THEAD jQuery Plugin">TH Float jQuery Plugin</a>. It&#8217;s really simple to use and from my tests works identically and flawlessly in (most?) all browsers (though, interestingly, I did discover <a href="http://rommelsantor.com/clog/2011/03/02/ie8-crash-inline-block-scroll-dom-append/">an obscure bug in IE8</a> while creating the demo page).</p>
<p>If you have any comments, suggestions, or problems with the plugin, please feel free to let me know!</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/03/03/th-float-jquery-plugin-fixed-thead-tfoot-table/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>IE8 Crash &#8211; Inline-Block Scroll with DOM Append</title>
		<link>https://rommelsantor.com/clog/2011/03/02/ie8-crash-inline-block-scroll-dom-append/</link>
		<comments>https://rommelsantor.com/clog/2011/03/02/ie8-crash-inline-block-scroll-dom-append/#comments</comments>
		<pubDate>Wed, 02 Mar 2011 09:15:35 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[Bugs]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[ie8]]></category>
		<category><![CDATA[iesucks]]></category>
		<category><![CDATA[internet explorer]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[scroll]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=148</guid>
		<description><![CDATA[Was struggling for many hours today to figure out what has turned out to be a really stupid bug in IE8. In the hopes I can prevent even a single person from wasting their day like I have trying to figure out what is wrong with my code, I&#8217;ll explain below how the bug presents [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Was struggling for many hours today to figure out what has turned out to be a really stupid bug in IE8. In the hopes I can prevent even a single person from wasting their day like I have trying to figure out what is wrong with my code, I&#8217;ll explain below how the bug presents itself with examples.<span id="more-148"></span></p>
<p>I&#8217;m not 100% certain of every variable required to cause the bug, but it definitely works in this example:<br />
<a href="http://rommelsantor.com/iesucks/ie8-inlineblock-scroll-dom.php">IE8 crash</a></p>
<p>The general structure of the page is:<br />
<pre>
&lt;body&gt;
&lt;div id="outer" style="display:inline-block;overflow:auto;height:100px;"&gt;
  ... any multi-line content that forces the div to have a scrollbar ...
&lt;/div&gt;
&lt;/body&gt;
&lt;script&gt;
$("#outer").scroll(function(){
  $("&lt;div&gt;&lt;/div&gt;").appendTo("body");
});
&lt;/script&gt;
</pre></p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>In that example &lt;body&gt; has only the one direct child element and if you scroll it causing the appendTo() function to be called, IE8 crashes. (I&#8217;ve only tested this on Windows 7 machines. IE7 does not crash.)</p>
<p><a href="http://rommelsantor.com/iesucks/ie8-inlineblock-scroll-dom-fixed.php">This is the same example</a>, but it works. The only difference is that a second &lt;div&gt; child was included within &lt;body&gt; but with that one change, the bug vanishes. Note that I&#8217;ve also tested this with multiple scrolling divs in body and the bug persists. It seems there <i>must</i> be at least one block element in &lt;body&gt; to prevent the bug.</p>
<p>Fortunately, it&#8217;s not often that one would create a page with just scrollable divs in the body.</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/03/02/ie8-crash-inline-block-scroll-dom-append/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
