Saturday, May 30, 2009
iConvert
I've made no bones over the years about not being excessively fond of Microsoft solutions. They have some great products -- Office, SQL Server, and Media Center being just a few -- but for the majority of my needs (okay, geeky wants), most of their products are simply lacking. Or worse.
By this point, we all know how much I love my iPhone. I purchased it after my intense bouts of frustration over a couple years of using PalmOS and Windows Mobile devices. Apple hit it out of the park with the iPhone. Period.
Today, I further fell in love with Apple. I have all my music sitting on a network share attached to my primary desktop PC, and wanted to hear it over my home theater setup instead. Add to that, a recently downloaded iPhone app, which I'll cover in a moment.
So I installed iTunes on my HTPC, pointed it to the network share, and waited a few moments while iTunes indexed my library. I then fired up the aforementioned iPhone app, simply called "Remote" which asked me to select a library. I did, and was shown a little 4-digit code to key into iTunes. Once I did that, I had access to my full music library. I chose a song, and the house started rocking. I slid the little slider on my phone, and the volume magically dropped. Fast forward, rewind, play, pause, access to my pre-built playlists as well as the Genius...
It Just Friggin' Works. Every time I try something new, it's like happy magic invading my electronic devices.
My next computer purchase will most assuredly be a Mac. Period.
[iPhone post]
Tuesday, May 19, 2009
Sometimes I Could Just explode()
Every once in a while, a fella in a hurry to get somewhere drives a little faster than his brain can handle, and said fella ends up veering off the road and into a ditch somewhere. That's sort of what happened to me this morning.
I have a function that pulls debugging information and spits it out to a div element, and I wanted that div to have a limited scrollback buffer defined by lines rather than characters. Since a line break is used to end each log entry, I figured a simple .split("<br>") would do the handiwork of creating an array of log items that I could then reverse sort, trim, and spit back out into the div (so my newest items appeared at the top).
Oh, nay nay.
Unbeknownst to me, there's something funny about that self-closing line break, however, that split() didn't like. In fact, it just so happens that HTML tags in general require a bit of attention. I eventually discovered that this was all I needed:
.split(/<\s*br\s*\/?\s*>/gi)
This expression works on variations of <br>, including my <br />, and is not case sensitive, so it works equally well in Firefox as it does IE, which tends to force HTML tags to uppercase in the DOM. (This is important since I'm setting the innerHTML attribute of the div.)
However, I wasn't aware of any of this stuff when I ran into my little problem. So I struck out to create a mimic of PHP's explode() function, except as a prototype extension to string objects. This is the result:
Interestingly enough, however, this failed to handle my HTML tags, just as split() failed, presumably for the same reasons. So my time perfecting this little gem ended up being all for naught, since I had to research why this function wouldn't handle the HTML tags either. What a colossal waste of time.
The function itself works, and quite well, from what I can tell based on my limited testing, so if you want it, you're more than welcome to it.
Be warned, however, that split() really is the only way to go. I'm only sharing it for its intrinsic humorous and edutainment value.
I have a function that pulls debugging information and spits it out to a div element, and I wanted that div to have a limited scrollback buffer defined by lines rather than characters. Since a line break is used to end each log entry, I figured a simple .split("<br>") would do the handiwork of creating an array of log items that I could then reverse sort, trim, and spit back out into the div (so my newest items appeared at the top).
Oh, nay nay.
Unbeknownst to me, there's something funny about that self-closing line break, however, that split() didn't like. In fact, it just so happens that HTML tags in general require a bit of attention. I eventually discovered that this was all I needed:
.split(/<\s*br\s*\/?\s*>/gi)
This expression works on variations of <br>, including my <br />, and is not case sensitive, so it works equally well in Firefox as it does IE, which tends to force HTML tags to uppercase in the DOM. (This is important since I'm setting the innerHTML attribute of the div.)
However, I wasn't aware of any of this stuff when I ran into my little problem. So I struck out to create a mimic of PHP's explode() function, except as a prototype extension to string objects. This is the result:
// Javascript prototype that mimics PHP's explode function
String.prototype.explode = function(delimiter, limit) {
// Make 'limit' an optional parameter with a default of 0 (unlimited)
if (typeof limit == 'undefined') limit = 0;
// Create an empty array, the temp buffer, and a copy of the source string
var elements = [];
var temp_el = '';
var temp_str = new String(this);
// Loop through the local copy, removing each slice and pushing it to the array
// Note that we check here to see if we've reached our array element limit
while ((temp_str.indexOf(delimiter) > 0) && ((limit == 0) || (elements.length < limit))) {
temp_el = temp_str.substr(0, temp_str.indexOf(delimiter));
temp_str = temp_str.substr(temp_str.indexOf(delimiter) + delimiter.length, temp_str.length - temp_str.indexOf(delimiter) + 1);
elements.push(temp_el);
}
// If we have any remaining characters, and we haven't yet reached our
// element limit, push the remaining string to another element in the array
if ((temp_str.length > 0) && (elements.length < limit)) elements.push(temp_str);
// Return the array
return elements;
}
Interestingly enough, however, this failed to handle my HTML tags, just as split() failed, presumably for the same reasons. So my time perfecting this little gem ended up being all for naught, since I had to research why this function wouldn't handle the HTML tags either. What a colossal waste of time.
The function itself works, and quite well, from what I can tell based on my limited testing, so if you want it, you're more than welcome to it.
Be warned, however, that split() really is the only way to go. I'm only sharing it for its intrinsic humorous and edutainment value.
Monday, May 11, 2009
Portable database calls in PHP
It's been a while since I've posted real code, so I thought I'd share a little snippet from a PHP database class that has been my bread and butter for a couple years now.
It started out simple enough, just a nice little wrapper for some of the more repetitious database calls. It has been growing in recent months, however, as I found myself wishing for expanded functionality.
One of the most recent additions to that wishlist is that I want a class property set after every database query that holds either the number of rows returned or affected, depending on the type of query passed to the class function. What complicates this is that I've been writing the class to handle multiple types of databases. I didn't want to have a bunch of switch() statements to cover mysql_num_rows(), mssql_num_rows(), mysql_affected_rows(), and so forth. So this is my answer.
First, a class property is set by the user defining the type of database transport: mssql, mysql, &c. The format of this is important, in that it must match one of the database vendor groups that PHP recognizes. Simple enough. (This could be an enumerated list of constant values, I suppose, but I'll worry about that another day.)
Now here's where things get fun. Inside our class query function, we do the following:
Make sure the property is lower case, and keep it local, just for cleaner-looking code.
$transport = strtolower($this->transport);
Also set our default row count to something that represents an error value (we'll set it to a real value once we complete a valid database call).
$this->rowcount = -1;
Now we define the function used for the query. This will translate to mysql_query() or mssql_query() and so on, depending on the value of the $transport variable.
$query_string = $transport.'_query($this->query_string)';
Finally, we can make the query call and get the result set. This is the real magic, and shortens a rather long list of case statements into one simple call. Note that to get anything back from eval(), we have to explicitly make it pass a return value. That's why we're wrapping the call inside a return() statement.
$result = eval('return('.$query_string.');');
We follow the same sort of logic to build an associative array containing the entire result set. This saves us the trouble of doing it in our application, keeping it all neatly contained in this function.
$row_fetch = $transport.'_fetch_assoc($result)';
while($row = eval('return('.$row_fetch.');')) {
$recordset[] = $row;
}
To get the number of records either returned or affected, we need to determine whether this was a SELECT statement, or if it was an UPDATE, INSERT, DELETE, &c. We're forced to do this because there are two different functions that handle this counting function, depending on the type of SQL transaction. So, we'll just see if it's a SELECT statement, and if it isn't, assume that we need to make an x_affected_rows() call. All we need is the first word, and hope that the user didn't do anything really silly with the query.
$query_type = explode(" ", strtoupper(trim($this->query_string)), 1);
switch($query_type[0]) {
case 'SELECT':
$count_string = $transport.'_num_rows($this->db_handle)';
break;
default:
$count_string = $transport).'_affected_rows($this->db_handle)';
break;
}
$this->rowcount = eval('return('.$count_string.');');
That's pretty much it. Now we have the recordset if one was returned from the query, as well as the number of rows affected by the query. We can pass the recordset back in a return() call, or return null if none exists, and the user can take action based on either the recordset or the record count.
Best of all, it's pretty portable. PostgreSQL, MySQL, MSSQL, Sybase, and on down the line. So long as the transport property is properly defined, we can use this just about anywhere. In my experience, other database types are rare enough that I don't need to worry about them, so I'm not going to bother with any special conditions for them.
I am aware that eval() isn't the most popular way of handling things, and it does come with a performance cost and security risk, but in the applications I'm working with, neither are really an issue, as the performance requirements are rather low, and the userbase is limited in experience and located on an isolated intranet. If you're going to use this code, I would strongly suggest that you take measures to ensure that any SQL query passed to the class function meets your security requirements.
One Less Excuse
Since a lot of my time is spent on the road or away from home, I figure I might as well find ways to make more productive use of my time. Until I can devise a practical way to write code on the iPhone, my guess is putting ideas and commentary into electronic form is the next best thing.
So, I'm testing out an app called BlogPress to let me do just that. Sure, I could edit in a web browser, but that lacks a lot of extra functionality, and doesn't do a very good job (if any, in some cases) of saving and editing drafts.
I'll let you all know how it goes.
-- Post From My iPhone
So, I'm testing out an app called BlogPress to let me do just that. Sure, I could edit in a web browser, but that lacks a lot of extra functionality, and doesn't do a very good job (if any, in some cases) of saving and editing drafts.
I'll let you all know how it goes.
-- Post From My iPhone
Sunday, May 3, 2009
Was 5 Years Long Enough?
Somewhere in the ballpark of five years ago, I wrote that Linux was five years away from being a viable, mainstream, desktop operating system. I distinctly remember fighting with various driver issues at the time, from wireless NICs to display adapters, as well as being frustrated that the method of distribution and installation for even the most popular applications was inconsistent, obscure, and at times impossible.
For a life-long computer geek like myself to be overwhelmed with its complexity said a lot.
Mind you, this has nothing to do with server environments. I have been running my web, e-mail, and what-have-you servers on Linux machines for the better part of ten years now, and you'd be hard pressed to get me to switch to a Microsoft-based solution for them.
Regardless, I've not given up on Linux-based operating systems for the desktop. In fact, I just recently installed the latest Ubuntu distribution (9.04) in a virtual machine on my primary home office computer, and have spent the past week playing around with some of the newer features that I missed in the 8.x round of updates. (My current server runs 7.10.)
I decided today to take the plunge, reformatting my home theater PC (which is underutilized because the options for a home theater PC running Windows XP .. well .. suck). I had been running into driver conflict issues anyway, causing Windows lock-ups, and I wanted to begin using this PC again for software development while sitting in my cozy recliner. There's nothing quite like software development in a recliner pointed squarely at a 50" plasma, I'm here to tell you.
The installation went well enough, and with the exception of a driver issue with my ATI card, everything has gone smooth as silk. (ATI, I discovered long ago, is horrible when it comes to drivers under ANY operating system, so I can't fault the Ubuntu team for this). All of my semi-obscure hardware seems to work flawlessly, all the basic stuff flies right out of the box, and I'm pleasantly surprised to find that just about any application I've wanted to install can now be easily located in the Synaptic Package Manager.
Synaptic was the one thing Linux really needed to make a good case for itself. Locating and installing any given application or utility is infinitely more simple than ever before, and I would dare say is even easier than on a Windows box.
The selection of mature applications for Linux has grown exponentially in recent years, and with the exception of off-the-shelf game titles, can do anything your heart desires with a lot fewer headaches than in Windows. (For the brave, there are options available to get most Windows entertainment titles running as well, for a price, of course.)
Overall, I'd say the time for Linux has finally arrived. It's fast, stable, reliable, and is only as complicated as you choose to make it. I'll be taking more time to be critical in the coming weeks, but the way things stand now, I would have no reservations at all installing this on my mother's PC.
For a life-long computer geek like myself to be overwhelmed with its complexity said a lot.
Mind you, this has nothing to do with server environments. I have been running my web, e-mail, and what-have-you servers on Linux machines for the better part of ten years now, and you'd be hard pressed to get me to switch to a Microsoft-based solution for them.
Regardless, I've not given up on Linux-based operating systems for the desktop. In fact, I just recently installed the latest Ubuntu distribution (9.04) in a virtual machine on my primary home office computer, and have spent the past week playing around with some of the newer features that I missed in the 8.x round of updates. (My current server runs 7.10.)
I decided today to take the plunge, reformatting my home theater PC (which is underutilized because the options for a home theater PC running Windows XP .. well .. suck). I had been running into driver conflict issues anyway, causing Windows lock-ups, and I wanted to begin using this PC again for software development while sitting in my cozy recliner. There's nothing quite like software development in a recliner pointed squarely at a 50" plasma, I'm here to tell you.
The installation went well enough, and with the exception of a driver issue with my ATI card, everything has gone smooth as silk. (ATI, I discovered long ago, is horrible when it comes to drivers under ANY operating system, so I can't fault the Ubuntu team for this). All of my semi-obscure hardware seems to work flawlessly, all the basic stuff flies right out of the box, and I'm pleasantly surprised to find that just about any application I've wanted to install can now be easily located in the Synaptic Package Manager.
Synaptic was the one thing Linux really needed to make a good case for itself. Locating and installing any given application or utility is infinitely more simple than ever before, and I would dare say is even easier than on a Windows box.
The selection of mature applications for Linux has grown exponentially in recent years, and with the exception of off-the-shelf game titles, can do anything your heart desires with a lot fewer headaches than in Windows. (For the brave, there are options available to get most Windows entertainment titles running as well, for a price, of course.)
Overall, I'd say the time for Linux has finally arrived. It's fast, stable, reliable, and is only as complicated as you choose to make it. I'll be taking more time to be critical in the coming weeks, but the way things stand now, I would have no reservations at all installing this on my mother's PC.
Subscribe to:
Posts (Atom)