Category: Computers

  • Search Snafu

    This article on Gadgetopia links to my content management post I made yesterday (er, today?) and brings up a drawback to my system that I forgot to include: searching.

    Within the relational database world, you can do precise, structured queries against specific fields in your tables. In a properly normalized database, this is all-powerful.

    However, when you bundle a bunch of content up in an XML package, and stuff that into a single field, you lose this functionality of doing atomic searches against those fields. In the example I wrote up—a geocaching XML record with latitude, longitude, etc.—there would be no way to this type of query:

    SELECT * FROM content WHERE longitute BETWEEN -122.5 AND -120.5;

    So, a problem. A big problem, since searching data is a pretty fundamental concept in content management—hell, in any application. I have some ideas that address this, but they’re still percolating. More to come.

  • Thoughts on Content Management

    I’ve been thinking a long time about content management systems (which isn’t surprising considering developing various types of website CMSes is what I do for a living), how they pertain to weblogs and similar types of content, how to implement them in PHP and MySQL, and what type of system I would really like to have. Now, content management is a big topic, so let me clarify and narrow down what I’m talking about before I go on.

    Some definitions
    A piece of content can be anything—a blog entry, a fragment of text, a photo, an MP3 file, a recipe for carrot cake, a Palm Reader ebook, a scrap of a note written on a yellow sticky pad. A lot of what defines and contextualizes the content is the metadata that goes along with it—the date it was created, the size of the file, the author, the image format, where it was created, etc. Now, granted, different types of content can have vastly different types of metadata; for instance, a JPEG image taken with a digital camera will have attributes attached to it describing its resolution, compression quality, file size, camera specs, and date and time it was taken, while a piece of GIS data will have, say, latitude and longitude attributes, elevation, and place name information (which could be any or all of street name, city name, county name, etc.).

    Some requirements
    After using and extending my own homebrewed blog software for over a year and half, examining other systems like Movable Type, and getting lots of ideas from other blogs and smart folks online, I’ve decided that what I’m thinking about is what I call a Personal Publishing System (PPS?), which could be considered a subset of a CMS. The PPS should have some features of a CMS, but certainly doesn’t need all of them; allowing multiple users to manage content is okay, for instance, but a comprehensive workflow system is unnecessary—just being able to flag a content item as a draft or final version, and perhaps an approval tag, is all that’s needed. Here’s a list of some requirements I’d like to see in my PPS:

    • Web based.
    • Any type of content and its metadata can be handled.
    • Each piece of content has a globally unique identifier (“guid”) of some kind.
    • Each piece of content can be access/retrieved via a URL (probably incorporating the guid).
    • Content can be published in any format: HTML (browsers), RSS (syndication/aggregators), PDF, etc. etc.
    • Content can be categorized based on a hierarchical tree of categories. In fact, content can be assigned to multiple categories.

    My general philosophy here is that I want to challenge my own notions about what constitutes a blog and see how far I can take it. Hubris, probably.

    Database theory
    A well-formed and normalized database would rightly split different types of content into their own properly modeled tables, which is the sane, efficient and right thing to do. I love data normalization, and I take a particular joy in modeling a data structure to a relational database and normalizing the hell out of its elements.

    In fact, as any Web application developer using a relational database will tell you, this is critical; the database is one of the biggest bottlenecks in the entire system, and it can be Web suicide for even a moderately-loaded site to have unoptimized tables behind your code.

    On the other hand, there is a drawback in trying to run a content management system this way: for every new type of content you want the system to handle, you have to create a new table (or several, depending on how normalized you want to get) and then add code into your system for handling the new table(s). (Okay, astute PHP programmers will realize you could create a master table that contains information and metadata about the new tables, and have PHP code that automagically handles the new tables based on this master table info—so you would only have to create the new tables and the system auto-populates the master table info and knows how to deal with that content in a general way. You wouldn’t have to recode for new additions. I’ve done this. It works reasonably well, considering.) Pretty soon, you’ve got so many tables handling every different case you can think of, that database performance degrades regardless of how optimized each table is. And managing potentially hundreds of tables becomes a nightmare in logistics.

    Left field
    So of course, in imagining a theoretical structure for my PPS, I went slightly insane and threw this stuff out the window. Here’s the gist of it:

    Treat every piece of content as the same as every other, and store it all in a single table. Preposterous? Probably. But bear in mind that there will be a common set of metadata attributes that every piece of content will have (at least in this context): a unique name or identifier (the guid), a date it was created, a title, a description. And of course, there would have to be a “body” field for the content itself. Roll those into the table structure.

    What about different types of content—text versus images? Easy—include a MIME type field in the table, that defines the content type—”text/html” or “image/jpeg,” for instance. (You could store the actual binary data of an image in a file somewhere, linked to by the guid stored in the name field.)

    Let’s look at this real quick in the context of a MySQL table:

       content_id -> Primary key
       name -> varchar (unique key)
       title -> varchar
       description -> text (probably will be >255 characters)
       date_created -> datetime
       mime_type -> varchar (possibly enum?)
       body -> mediumtext (large data sets, up to 16MB)
    

    That handles the basic metadata, and could be sufficient for something like a weblog. But what if I want to add some content that has additional metadata that the table doesn’t account for—like a geocaching record, and I want to track latitude and longitude coordinates somewhere? I can’t add more fields to the table—that’s a loser’s game for (I hope) obvious reasons. Once I had settled on the idea of a MIME type field, the answer seemed clear: XML. Bake XML into the database structure as content.

    To be clearer: set the MIME type of that piece of content to “text/xml” and the populate the body field with XML data of the content in question, with the extra metadata fields rolled into it as part of its XML definition. So, you might populate the body field with something like:

       <content type="geocache">
          <latitude>45.6684776</latitude>
          <longitude>-121.3394771</longitude>
          <dateHidden>2003-12-05</dateHidden>
          <cache type="traditional" name="coffee can">
             <item>Spiral-bound logbook</item>
             <item>Yo-yo</item>
             <item>Deck of cards</item>
          </cache>
       </content>
    

    What I like about this idea is its object-oriented analogy: start with a basic definition for content—a “class”—and each instance of content inherits from the base class and, via XML, can extend the base class for itself.

    There’s limitations to account for, as well. Not all types of data can be easily shoehorned into this model, so it shouldn’t be attempted. For instance, a voting system: you need a table to store the poll topics, one to store each option/answer, and at least one more for storing user votes. There would be no sense in trying to hack this into the content table, and the system would suffer if it was. So there’s always room for specialized functionality.

    And, I’ve modeled some compromises. Rather than trying to manage the category system as just another type of content (so that you’d end up with parent-child content relationships), I pulled the categories out into another table. It’s cleaner and there’s more benefit to the system this way—I can add a many-to-many lookup table to allow for multiple categorization. (Incidentally, in my PPS, I call these channels, because they might fulfill a purpose beyond that of a traditional category system.)

    Another compromise is the concept of content nodes. A content node is basically a grouping that content can be classified into—another lookup table. All the content I write for my blog would be assigned to the “chuggnutt.com blog” node, for instance.

    Oops, and don’t forget about a commenting system—user comments (and perhaps ratings?) are a valuable source of metadata for any given piece of content. So I’ve allowed for another table to store comments, rather than making them another type of content, because I want to stay away from the parent-child relationship situation I alluded to above.

    Will it all work? I don’t know. The proof is in the pudding, though—I’m working to convert my own blog to this system, so I’ll find out firsthand just how good (or bad) my ideas are. I really don’t think this system is viable to run as a large-scale, enterprise-style content management solution—hence the reason I’m calling this a Personal Publishing System. Incidentally, the working name (or code name, if you will) in the back of my mind for this system is “Spokane.”

    I’m making this an open process, too, to solicit comments on my ideas, and hopefully to give ideas to any other people out there looking to write their own systems in PHP. To that end, the next article I’ll post on this topic will move from theory to practice, and I’ll publish the MySQL database schema I’ve been developing (with comments). Exciting stuff!

  • NetOffice

    Installed NetOffice, PHP project management software, this morning to better manage my various Web projects. Once it’s up and working, it’s a pretty slick piece of software. Had some trouble installing it and getting it to work initially, though.

    First, after it’s installed, it prompts to you log in to start using the software—with a username and password. The only password I gave it was an administrator password, and the documentation I had didn’t indicate what the username is to log in with. I correctly guessed the username was “admin,” but then the system wouldn’t let me in, it kept giving me a “Session error” message. I was finally able to make that go away by disabling NetOffice’s custom session management routines and letting the system default to PHP’s native session handling. The files I had to modify for this were includes/library.php, general/login.php, and projects_site/index.php.

    Pain in the ass, but that fixed it, and now it works pretty well.

  • Beer Brewing Software

    For some reason that I now forget I started digging around online tonight to see what the current state of beer brewing software looks like. The last time I’d played with any such software, I installed the evaluation version of ProMash on my old computer and tried it out. It’s probably the best piece of software for brewing out there, and to be sure it worked well and did a good job, but when you look at it you can’t help but notice the Visual Basic GUI-clutter-itis that prevents it from breaking through to the best-in-show program it wants to be. (See a screenshot here to see what I mean.)

    The two lists I found are Lee’s Brewery Guide to Brewing Software and the Open Directory beer software category, and I’m disappointed to report that the state of brewing software is right about where I left it. Even ProMash looks the same.

    Here’s a bit of a wishlist of features I’d like to see in brewing software:

    • Simple layout and navigation.
    • Visual color indicator—I want to see what color the 30+ SRM porter will be.
    • Staggered complexity by usage—if I’m brewing from extract, I’m not worried about seeing all-grain stats and figures to tweak on the recipe formulation screen.
    • Open source—open code, open databases.
    • Perhaps web-based. (I tend to see everything as having a web-based solution these days, go figure.)
    • Custom report generation.
    • XML data transfer. Data storage in a database is great, but I want to be able to export to XML for whatever I might need.

    To be sure, ProMash covers most or all of this quite nicely—its layouts and colors make my eyes bleed, though, and it’s not open source.

    Of course, complaining about the current state of affairs for a particular genre of software, accompanied by listing a bunch of desired features for said software, is usually followed by the self-same person announcing that they’re going to develop the ultimate version themselves. What can I say? I’d be tempted to do it, but I really don’t have the time—there’s too many other irons in the fire right now. Plus, I haven’t even brewed a batch of beer in over a year, so I’m not even qualified. Sometimes, though, you just gotta vent. :-)

  • C-64 Emulator for PalmOS

    It had to happen, read about it here—there’s a free Commodore 64 emulator for PalmOS. I’d love to download this for my Clié, but alas, it requires PalmOS version 5 and my Clié only has a version 4 variant.

  • More PHP Errata

    Again reading Larry Ullman’s PHP Advanced and finding it okay, but I came across another glaring error.

    On page 169, in the discussion about variable order, Ullman’s got the variable order entirely backwards. The out-of-the-box order for PHP variables is EGPCS (which refer to Environment, Get, Post, Cookie, and Server variables), meaning that PHP processes input into variables from those sources in that order. The book incorrectly lists these in reverse while claiming it’s the proper order.

    The funniest part is there’s a graphic of a screen shot from the php.ini file, which clearly shows the EGPCS ordering, contrary to the text.

    Hello? Editors? Anyone?

  • MySQL’s SET

    I was just thinking today that MySQL’s SET datatype has to be the most underused feature of MySQL, and how I could implement a multiple category system for my ebooks using it, when I got the MySQL AB Newsletter and lo and behold, it has an article on using SET.

    I love fun coincidences like that.

  • From the Trenches

    My day at work was certainly a tech support nightmare. Get this: as soon as I walk in, I’m told the server is down. Thinking (hoping) they meant the connection to the internet is down, I clarified the issue.

    Nope. The server. Damn.

    This is the main file/print server that everyone in the office uses to store their work on. Excel, Word, Publisher, QuickBooks, you name it, it’s there. Plus, it houses the intranet I developed (and the MySQL database that backs it), Microsoft Mail server (which thankfully no one much uses anymore), and the Intuit Master Builder server software the company relies on.

    (I know, I know, words of caution about putting all your eggs in one basket, I know.)

    There had been a power outage the night before, and now the server was completely dead, no power at all; but the server had been plugged into a UPS, which was still on and working. Odd. Tried plugging it into several other outlets, nothing. Tried a different power cord, nothing. At this point I deduce it’s the power supply, and that’s hopeful because if that’s all it is, nothing’s lost except some productivity time.

    Unfortunately, I don’t have a spare, so I have to wait til the local computer store (who originally built the server, so we have an account with them) opens at 9am to get one. Luckily, I get through to someone in the store at about 8:40 when I’m calling to leave a message, and they’re sending the tech right over with a new power supply.

    And guess what? I was right—the power supply died, and everything else was intact and fine. We got the server up and running again by 9:10 tops.

    Talk about sweating bullets. Even though we had a full backup of everything important made the night before, there’s still nothing quite like that head-pounding, sweat-behind-the-eyeballs, bowel-clenching feeling that you get when something like this happens.

  • Errata

    I was reading through PHP Advanced this evening and on page 63, came across something incorrect (regarding objects in PHP):

    PHP does not support multiple levels of inheritance, so you could not make a Grandchild class that extends a Child class that in itself is an extension of the Parent class.

    Actually, PHP does support multiple levels of inheritance, and you can see the proof yourself by browsing the source code of the PEAR DB class found here. The inheritance path for the DB_mysql object looks like this:

    PEAR -> DB_common -> DB_mysql

    And even the PHP website’s documentation confirms this (found here):

    You create a class, parent, and use extends to create a new class based on the parent class: the child class. You can even use this new child class and create another class based on this child class.

    Now, what is true is that PHP doesn’t support multiple inheritance in general— i.e. inheriting from multiple sources simultaneously. But chaining a string of class definitions singly is okay.

  • Kon-Tiki

    We’re heading up for a day trip to Portland tomorrow for Kaitlyn’s post-op visit to the eye doctor to check how her eyes have progressed since surgery. Have to get up at 6 am though, that’s a bummer.

    Here’s a link too geeky/cool to pass up: The Contiki Operating System and Desktop Environment. It’s an operating system with built in web server and web browser originally written for the good ol’ Commodore 64. This may not seem like such an accomplishment given today’s advanced systems and seemingly limitless power, but for those familiar with the C64— or especially anyone who owned/used one— all I can say is: Damn.