My Honest Consumer Opinion of the iPad: Who Cares?
I can’t speak for the whole of technology consumers when I say that the Apple iPad, which debuted a few days ago in Apple’s Keynote, doesn’t seem terribly interesting. I’ll admit that I tend to roll on gut instinct when gauging the success of a potential product. I’ve done it as both a member of a startup and a tech industry observer. The question that always bugs me is: If Apple hadn’t set a price at $499, how much would I be willing to pay for such a device?
Maybe $200, and I’m not even sure about that.
The real issue at hand is not me being stingy. It’s me weighing the economical pros and cons of owning such a device over something like a laptop or netbook. What can I get out of something already being billed as “A Giant iPhone?”
I feel as if the iPad is making consumers think “that would be cool to have,” while in the past, the iPod Touch and iPhone Keynote was making people like me practically drool while screaming “I WANT THAT!” In fact, I own an iPod Touch, and it is every bit as spectacular as I thought it would be. But I digress, the point is that I was absolutely convinced that I needed an iPod Touch. It had WiFi built in, a web browser, mp3 player, video player, photo viewer, an endless library of applications, mobile iTunes — the list goes on! The iPad doesn’t offer much more, and it doesn’t fit in my pocket.
I will say this: It was probably the vibe that Steve Jobs was going for in his KeyNote (sitting in a comfortable looking chair with an iPad on his lap), but the iPad would probably make a great coffee table piece. You can pick it up at-will, check your email, surf the web, check the weather, watch videos, and oh — read an ebook. But I’ll be honest, the iPad isn’t going to really compare to a Kindle. The Kindle is easy on the eyes, has three times the battery life, and is easier to handle and take with you.
So you may be thinking, “well Kenny, there have been a lot of positive reviews for the iPad!” I don’t doubt it. In fact, everything that I’ve ever tried that has Apple’s logo on it has been awesome. Macbooks, iPods, Apple II’s, every piece of Apple software ever written (iLife), it’s all fantastic. But there was a certain sect of people that needed those devices or software. I’m just not sure that kind of need exists for the iPad.
It’s kind of like Google Wave. It was kind of cool, and still has a lot of potential. Hell, I was one the the first people signing up for a beta account just because I wanted to see what all the hype was about. But it seems as though the world just doesn’t need it.
Any technology like Wave or the iPad will have its share of mindless early-adopting brand zombies. Some people still insist that Google Wave is really useful and has a shot at changing the innerwebs. I don’t buy that one either, mainly because after I tried it, my instinct asked me, “how does it help me? how can it help you do what you do more efficiently?” I don’t know the answer to that yet, and that’s why I don’t quite believe in it as a product.
Like I said, I don’t speak for every consumer, so I will not truly know how the iPad (or Wave for that matter) will fair. But my own personal reaction to the Apple Keynote was “Hey, you can’t win’em all! They still have other great products. Maybe I’ll start looking into Amazon shares.”
Oh yea, the iPad is already the subject of internet hilarity:
MiFi – An Aircard Alternative for Linux, Mac & Windows
I intend to finish my previous post about fixing up caching in CodeIgniter, but I wanted to write a blurb about a device that I just picked up today — the MiFi. I thought I should mention some of the highlights of the product, some points that weren’t immediately apparent when I was researching it, and some tips that could save you thousands in overage charges.
I bought the MiFi, which was developed by Novatel Wireless, through Verizon. It’s a standalone mobile wireless router that acts like a traditional aircard. It uses Verizon’s 3G network for internet access, and puts out an 802.11b/g signal so up to five devices can connect to it at a time. Here’s a picture of it with my iPod Touch:

Area-wise, it is about the size of a credit card. In terms of thickness, it’s about 1/3 of an inch (~8.5 mm).
I’ve recently picked up a 6-month freelance contract at a design firm in Brooklyn, which is probably an hour and a half commute by train and subway. When thinking about the amount of time I’d be spending on the train, I immediately realized it would be wise to look into an aircard for my laptop so I could both browse and get some work done during the commute. There were a few big requirements that I had, but my initial research on the websites of wireless providers failed to answer all of my questions.
I’m writing this post to offer some answers to questions others might have about the MiFi.
When searching for an aircard, I had some requirements:
- It must play friendly with Windows, Mac, and Linux, because I use all three
- It must have some common connection interface like USB — Expansion cards won’t do
- It can’t have a goofy form factor, like a USB stick just asking to be knocked out of its slot
- I’d rather I didn’t have to install evil-ware to use it
- I can try before I buy
- I want to be able to easily check that I’m not exceeding my data plan allowance
- There must be positive reviews for the product
Does it sound like I had some seriously stringent requirements? Probably, but the MiFi passed most of those. Let me roll through each.
Win/Mac/Linux compatibility: This isn’t so much to ask, but Linux tends to be under-supported in the aircard world. Initially, I wanted to learn exactly what kind of computers could use the MiFi. The answer, of course, is any computer that is WiFi enabled. The only catch is that the card has to be activated using VZAccess Manager (VZAM) which only runs in Windows and Mac OSX. After you activate the card, you can take it anywhere, connecting any devices that talk WiFi to the web, neglecting the box that actually has the software installed.
I’m sure I could have done this on my linux box in a Windows VM, but I decided to take the easy route and stick it on my secondary box at home (Windows 7). Actually, that’s something that wasn’t noted anywhere: The software is compatible with Windows 7. Alternatively, I believe you can attempt to do this online if you have an account set up on your cell provider’s website, and forgo VZAM altogether.
I answered the “common interface” question with the last point, so I’ll talk about form factor. The MiFi is literally small enough to fit in your pocket, although I wouldn’t recommend doing that. When you plan to use it, turn it on, and sit it on a table or place it in your bag. Then you can turn on your laptop and connect to your MiFi network, which will named something like “MiFi2200xxxxxxxx”. When you are done, it might be wise to turn it off. The device can apparently go into standby for 40-something hours, but I have thought of some real issues which I will talk about. While being used, the device will last about 4 1/2 hours.
I was told by the sales rep that if I had an issue or was dissatisfied, I could return the MiFi for a refund within 30 days. This isn’t quite a “try before you buy,” because I shelled out ~$189 with a 1 year contract. But if I need to, I can return the item to get my $189 back and a premature exit from the contract.
As for positive reviews — I only buy items that have been positively reviewed. The MiFi is no exception.
In total, I paid $189 for the device, and received a $50 mail-in rebate. Verizon has two data plans: $39.99 for 250 MB, and $59.99 for 5GB. For the first, any overage is charged at 10 cents per MB. For the second, it’s 5 cents per MB. I selected the $59.99/month 5-GB data plan. You might be thinking, 5GB? That’s too low! Sadly, there aren’t any wireless providers that go above this threshold. As far as I know, Sprint, AT&T, and Verizon all have the exact same pricing and cap for their aircards. Sorry, we can’t get around this one.
That last point brings me to my next. Beware of processes on your machine which might use your internet connection in the background. The biggest offender I can think of it Windows Update. Consider the naive aircard customer who says to the Verizon sales rep, “Well, I will only be checking my email periodically while I work. That is the biggest reason I need it.” The Verizon rep then recommends the 250MB plan because it sounds like a good fit. Wrong!
You can’t really hold it against the two parties in this situation, because the customer it thinking her data usage will be light. The Verizon rep is not a computer expert in any sense of the term, and also thinks the plan would be fine. But think about the types of processes that exist (specifically for Windows), that take your internet connection for granted.
Windows update, for instance, will literally download hundreds of megabytes worth of data quietly in your system tray. Sun Microsystems’ Java updates will do the same. I certainly hope any aircard customers aren’t victims of spyware or malware, which will covertly send and receive data behind the scenes, eating up the usage allowance. Users will want to carefully check that any file sharing or torrent clients aren’t running in the background. Accidentally leaving one of those guys open can be a mistake worth thousands of dollars. And since you can connect up to 5 devices at a time, you might want to be wary of which computers you are sharing your connection with.
Luckily, if you point your browser to the standard router address http://192.168.1.1, you will find that you have a neat control panel that gives you information on your current connection. Here’s a screenshot below:
If you want to edit the default settings of your network, such as the SSID or network key, you need to login to the box on the top-right portion of the page. Verizon did not print the initial password for the administration section anywhere. So I went digging on the Novatel wireless website and found that the default password is admin. Funny, that used to be the standard default password for Linksys routers too.
There are a surprising number of options. For instance, you can filter out certain MAC addresses from using your network, set up port forwarding (albeit on a very limited scale), and change your security configurations:
In the end, the MiFi seems to be a pretty cool device. But I was watching my usage climb by kilobytes when logged into the admin panel, even when I wasn’t actively using my connection. Background processes? Maybe. But I sure hope it doesn’t run up my bill.
As a side note, before you take the plunge with one of these things, do your research online. I found that asking the sales people at the Verizon store questions on the technical side didn’t yield any answers. Although, when I asked one rep whether a USB aircard I was looking at would work with Linux, he said “Well, Linux is based on Windows, so yes.” I guess Dennis Richie and Ken Thompson of Bell Labs got in their ‘82 Dolorian and robbed the Windows source code from Bill Gates, then traveled back to 1969 and released Unix.
Convincing.. Just kidding. But do your research before you walk in the door. That’s all.
Flushing CodeIgniter’s URI-based Cache (Part I)
CodeIgniter’s output caching mechanism — at least in my opinion — has limited usefulness. It can be used to cache the final payload sent to the user for a given number of minutes. But sometimes clearing the cache for all pages or a specific page can be useful, especially if keeping the user from seeing stale data is important.
This post will discuss what caching is, and how it is used in CodeIgniter. The next post will provide a few helper methods for clearing caches for specific pages (or really, URIs). I think this will make CI’s caching feature a lot more usable.
In a nutshell, this is how (and why) output caching is typically implemented:
Suppose we have a page at http://mysite.com/stats/website which loads and shows all the statistics about the users on my site, activity, files posted, etc. In other words, a lot of SQL queries (maybe 40 or so) and calculations go into this page. That takes significant time and resources.
Now imagine that this page is particularly popular. Maybe a heavily-read blog or bookmarking service links to your website, and you receive an unexpected burst in traffic. All of those page loads are re-running your calculations and queries, and that is consuming serious memory and CPU cycles. The number of requests your website can serve per-minute is now falling through the floor!
The idea of caching involves using the fact that our page probably doesn’t need calculate those statistics or run those queries every time. Perhaps gathering all of that data once an hour would suffice.
“Caching” involves generating the statistics page like we normally would, but saving a copy of the output we were going to send to the user for a certain amount of time. During that time period, everyone who requests that page will get the same page output that we generated x minutes ago.
After that time period passes, and we receive another page request, we recalculate the stats, and send them to the user. Of course, we’ll save the newer stats for a given amount of time for subsequent requests.
This basic caching — “page caching” — is the kind that CodeIgniter offers.
When you are inside a controller, you can tell CodeIgniter that you want to cache any requests to the current URI for n minutes. For that time period, you only want to send the output your are about to generate.
This is how it looks:
class Stats extends Controller { function website() { // 40 SQL Queries (Maybe a little overboard) // Serious, ultra-precise calculations // More intensive code that isn't good for fast page loads // Tell CI you want to cache the output of this page for 10 minutes. // This means that for the next 10 minutes, when CodeIgniter receives // a request for stats/website, the CI system will not even consult this // method or instantiate this controller. It will serve a static page containing // the exact content that you output here. $this->output->cache(10); $this->load->view('stats/website', $data); } }
And that’s all you have to do! In this example, CodeIgniter’s output caching works great.
So then, what were the qualms I mentioned earlier?
Suppose we also cache user profile pages, which might be located at a URI similar to http://mysite.com/users/profile/kennyk. For whatever reason, we will assume that caching this page could be very beneficial due to heavy traffic on the site.
If a user profile is cached for 10 minutes, and a user updates his profile in some profile editing area, he will still see the older version of his profile page when he tries to view it. This can be confusing and inconvenient.
Other MVC frameworks (like Rails) handle this issue in a snap by allowing the developer to “sweep” caches at will. CodeIgniter does not offer any functionality similar to this.
My next post will document a cache helper I’ve whipped up to allow CodeIgniter to sweep caches for a given URI. Look out for “Flushing CodeIgniter’s URI-based Cache (Part II).”
Insert Multiple Rows Into A Database with CodeIgniter
When using a spiffy web application framework like CodeIgniter for PHP, I tend to start depending on the framework for a lot of functions.
For example, if I want to get the segments of the URI, I first think, “CodeIgniter must have that!” If I want a function to convert input from a <textarea> into correctly formatted html, I think, “CodeIgniter must have that!”
And when CodeIgniter doesn’t have a function that would be really useful, I tend to think, “Now what?”
One commonly found problem is that CodeIgniter doesn’t have a specific function for inserting multiple rows into a database at once. It’s obvious that if you need to insert over 10 rows — you should really be doing it in as few queries as possible. There have been some blog posts asking about this on the CI forums. It’s not a tough problem to solve by any stretch — but I wanted to write an extension of the Model class with a function to do this as quickly and efficiently as possible.
Right now I’m working on a webapp where I need to allow one user to send a message to potentially thousands of other users. That means I’ll need thousands of database inserts. Doing this with individual queries could take minutes. Inserting them in bulk would take under half of a second.
The code that I wrote has been tested and benchmarked to be as fast as I could possibly make it. I used PHP’s built in array_walk functions (which are written in C) over my own. A few other optimizations are present as well.
I posted this code over on the CodeIgniter wiki too.
The first thing you need to do is extend the model class (if it isn’t already extended), with the following code:
class MY_Model extends Model { function MY_Model() { parent::Model(); } /** * A method to facilitate easy bulk inserts into a given table. * @param string $table_name * @param array $column_names A basic array containing the column names * of the data we'll be inserting * @param array $rows A two dimensional array of rows to insert into the * database. * @param bool $escape Whether or not to escape data * that will be inserted. Default = true. * @author Kenny Katzgrau */ function insert_rows($table_name, $column_names, $rows, $escape = true) { /* Build a list of column names */ $columns = array_walk($column_names, array($this, 'prepare_column_name') ); $columns = implode(',', $column_names); /* Escape each value of the array for insertion into the SQL string */ if( $escape ) array_walk_recursive( $rows, array( $this, 'escape_value' ) ); /* Collapse each rows of values into a single string */ $length = count($rows); for($i = 0; $i < $length; $i++) $rows[$i] = implode(',', $rows[$i]); /* Collapse all the rows into something that looks like * (r1_val_1, r1_val_2, ..., r1_val_n), * (r2_val_1, r2_val_2, ..., r2_val_n), * ... * (rx_val_1, rx_val_2, ..., rx_val_n) * Stored in $values */ $values = "(" . implode( '),(', $rows ) . ")"; $sql = "INSERT INTO $table_name ( $columns ) VALUES $values"; return $this->db->simple_query($sql); } function escape_value(& $value) { if( is_string($value) ) { $value = "'" . mysql_real_escape_string($value) . "'"; } } function prepare_column_name(& $name) { $name = "`$name`"; } }
That file, My_Model.php, should be placed in your system/application/libraries folder. Next, you need to modify the model which needs to insert multiple rows. In my case, I want my Message model to be able to insert a lot of messages, so I’ll add ‘extends MY_Model’ to its class definition.
Note: The MY_ prefix is the default prefix used to extend a class in CodeIgniter. If you have modified this in your config.php, use your prefix as appropriate.
This is my new model, which contains an example usage of the method (but real usage would likely be a little more involved).
class Messages extends MY_Model { /* Code .. */ function InsertTestData() { /* Prepare some fake data (10000 rows, 40,000 values total) */ $rows = array_fill(0, 10000, array(34239, 102438, "Test Message!", '2009-12-12')); $columns = array('to_user_id', 'from_user_id', 'message', 'created'); $this->insert_rows('messages', $columns, $rows); } }
The insert_rows method will automatically escape your data for the query, which tends to take up a healthy portion of this script’s running time. After all, it has to check 40,000 values, and escape 10,000!
If you need to insert something like 10,000 or 20,000 rows, it is recommended that you page through the values you are inserting. Otherwise, you run the risk of exceeding memory limits, or MySQL’s maximum packet size.
Add Files to Subversion Recursively
Adding a directory and sub-directories to your subversion repo: I’ve seen some wacky solutions to this problem online, and a lot of people don’t know this is a built-in command (Google “add files to subversion recursively”).
Since CodeFury has been getting pretty high in the Google listings, I’ll post the real command. Hopefully subversion users will find my blog before running someone else’s 50 line perl script.
And here it is:
svn add * -- force
It would really be scary to consider what would happen if subversion didn’t have this in it’s toolbox. Rails developers would be in tears any time they ran
script/generate [something] # Generating n new files in n directories ... ;)
Of course, even that command isn’t as easy as git’s
git add .
I’ve been using git full force lately. I’m not entirely in agreement with Linus Torvalds’ quips on subversion, but I do agree that git is superior to svn in a lot of ways.
Anyway, I hope this post saves someone a lot of typing.
Enable Site-Wide Profiling With CodeIgniter
A very cool part of CodeIgniter is its ability to give you the ‘profiling’ information for page loads. That is, if you add:
$this->output->enable_profiler(true);
In your controller before you load a view, CodeIgniter will give you information regarding how fast the page loaded, how many SQL queries executed, the content of each query, and the running time of each query. This is incredibly useful when you are trying to debug your application, or simply see how quickly things are loading.
There’s only one problem: To enable profiling, that line of code above must be present. What if you want to profile several pages, or even your whole web application? In that case, you have to start thinking:
- I could put that line in the constructor of my controller, and then of of that controller’s methods will be profiled.
- I could put that line in each method I want to profile.
These methods start to get ugly. And of course, you don’t want to comment out each profiling line when you don’t need them.
My method to tackle this problem involves using CodeIgniter’s Hooks feature to enable or disable profiling for the entire web applications based on a value in the configuration file. In the end, I can turn on profiling for my entire website via a config value by setting it to true or false. This is my method:
1. Enable hooks in your CodeIgniter Application by going to config/config.php end setting the flag to true:
$config['enable_hooks'] = TRUE;
2. Create a file in the config directory named hooks.php if it does not already exist. Inside it, place:
$hook['post_controller_constructor'][] = array( 'class' => 'ProfilerEnabler', 'function' => 'EnableProfiler', 'filename' => 'hooks.classes.php', 'filepath' => 'hooks', 'params' => array() );
3. Create a folder in your application directory named hooks (If it does not already exist). Inside it, create a file named hooks.classes.php. Inside it, put:
class ProfilerEnabler { function EnableProfiler() { $CI = &get_instance(); $CI->output->enable_profiler( config_item('enable_profiling') ); } }
4. Finally, add this line to your application’s main configuration file:
$config['enable_profiling'] = false;
Setting this value to true will enable profiling across your entire website. Now, you can zip through pages, checking the load times of each without any trouble!
Note: I’ve always thought that an additional way to do this would be to extend the Controller class and enable profiling from there. But this method, I think, has the least impact on existing code.
A Fine Run, and Maybe A Little More
It’s been almost a year since I mentioned the last version of wpSearch!
I owe many faithful users of wpSearch an explanation of my whereabouts. After all, the internet does not need yet another dead blog, especially when it had been fairly well read. Here’s a recap of the last year:
- Figured out that I wasn’t going to figure out the wpSearch index corruption issue some users were having. I could duplicate it, but I couldn’t get to the root of it. Then Fall 2008 final exams took the rest of my time. I tend to be an extremely focused student.
- I continued working at LTech, which was sold by GetTheJob to Matlen-Silver, a company in Bridgewater NJ, where our office was subsequently moved. Company focus shifted from consulting to developing products for the Google cloud.
- I became infatuated with CodeIgniter, an MVC framework for PHP. I had used CakePHP and Zend with limited success, but CodeIgniter was light, fast, and had great documentation. It also lets me do things the way I want to (the forceful “best practice” nature of frameworks like Cake and Ruby on Rails can sometimes make things very difficult).
- I was offered a job, and almost moved to San Diego to work at BAE Systems as a Software Engineer. Then “nature’s changing course” (thanks, Shakespeare) got in the way. It would have been great to work with the people I met there, and I was really excited. But in the short time I was at their facility, they taught me how important tested, reusable design patterns were to their business. Then I decided to buy the famous Design Patterns book by the “Gang of Four”.
- I graduated from NJIT with a BS in Computer Science and a minor in Applied Math. Class rank? 12/858! Ye-uh! I’m not a bragger, but it’s a good feeling for a former apathetic high-schooler.
- Amidst the excitement, I lost a close family member in April. You are still very missed, my friend. Btw, if you can read the innerwebs, this is awesome.
- I left LTech (I was sad to go, but I had a mission) to work full time on my first entrepreneurial project, Teaches.it. Teaches.it is a service that helps teachers build websites via our own uber-easy-to-use content management system. I spent the majority of the summer working on, and launching that system. Teaches.it now has a small, but growing group of happy customers.
- I went on a month-long road trip stopping at Wilmington NC, Savannah GA, Pensacola FL, Baton Rouge LA, Houston TX, Van Horn TX, Carlsbad NM, Scottsdale AZ, Grand Canyon AZ, Las Vegas NV, San Diego CA, Los Angeles CA, San Fransisco CA, Elko NV, Salt Lake City UT, Nebraska, Iowa, Ohio, and Kutztown, PA. Lessons learned during the trip? The best Mexi-Cali food is not in Cali. It’s at 10th Ave Burrito in Belmar, NJ. Yeah, I said it.
I have been receiving quite a volume of support requests for wpSearch. I try and do my best to get to all of them, but I am aware that some slip through the cracks. This usually occurs when I read the email on my iTouch, and decide I want to reply at a full-sized keyboard. Sometimes, I get caught up in something else and forget.
KLogger has been receiving more than its fair share of users. After all, it is only a small logging class. Then again, I wrote it because I needed something like it and I couldn’t find it elsewhere. I’m glad it is being put to good use. Here’s a shout out to the University of Iowa, where it is currently being used in an internal project.
So what’s ahead? The first task is to see if the newest version of Zend Lucene is any better than the last. The next step is to start using it in wpSearch.
I also want to keep doing what I was supposed to do on CodeFury — document fixes to problems I have come across while coding. One of my recent trials is figuring out how to use swfUploader with CodeIgniter’s upload class when an authenticated session is required to upload.
Anyway, the next post shouldn’t be too far behind. Thanks to everyone for the comments and support of the projects!
Updates on KLogger, wpSearch 1.5.6, and More
Since my last post, I’ve been working on and off on the next version of wpSearch. The last version (1.5.5) stands as somewhat of an official release of the plugin, and I would consider previous versions to be ‘release candidates’ due to the growth wpSearch saw since then.
I’m in my second to last semester at school, so the lack of posts over the past two months are attributed to that — that doesn’t mean that nothing has happened.
Many of wpSearch’s users have made note of some very important issues in the current release. Because I have been recieiving feedback on wpSearch in pretty large quanities lately, I’ve been doing my best to reply to everyone — some, although, might not get a reply right away (Sorry!).
I’ve taken note of all reported issues so far, and a future release of wpSearch over the holidays is likely. I have also recieved a code submission from the folks at the Alpha-Beta-Release Blog for KLogger. They have written rolling log capabilities into the class, ensuring that log files never grow beyong a certain size, and begin writing to a new file when some preset limit is reached.
Also, I don’t know how many blog readers have any sort of interest in the Google Search Appliance, but I will be developing a PHP “Bridge” for easy code-wise communication with the Appliance. I am writing this library for LTech Consulting (A Google Partner) — they have already written a bridge in C#/.NET. If anyone is interested, I’ve written a lightweight blog post on LTech’s blog detailing the basics of the project.
Lastly, zinkk, a startup development company I am involved in, has grabbed its first couple of contracts over the past few months, and also has a real office. It’s a big step when a small company started by students actually moves into its first office — there are feelings of “Wow, we did it,” and “We are a bona-fide firm now,” and “Whoa, we better keep making money so we can pay the rent!”
Anyway, we have some very talented people at zinkk, and I’m excited to a part of it. John Bellone, one of our developers, works for CitiGroup in Manhattan. John Crepezzi works at Sun Microsystems. Dan Boston is a doctoral student at NJIT, and Tarcisio has worked for Johnson & Johnson. All of these guys have worked on some impressive projects — many of them open source or publicly licensed.
Oh yeah, Zend put a piece I wrote about writing a Stemming Analyzer for Zend_Lucene in the tutorial section of their website.
That’s it for now — I’m going to talk about a release of a MySQL management class for PHP next time.
wpSearch 1.5.0.5 Released With Features, Fixes
After an exhausting week and a half tracking down the source of a mysterious bug in wpSearch, I think I can finally close the book on the “null result” issue that had me pouring over the source code.
wpSearch 1.5.0.5, the first official release after the 1.5 landmark, brings to the forefront some of the features and fixes slated in the last post. wpSearch 1.5 has had the following features implemented:
- Comment Searching
- A behind-the-scenes event logger for easily figuring out user issues
- An upgrade to the underlying Lucene Search
- An upgrade to the underlying StandardAnalyzer (used for relevancy)
And these fixes:
- No more null results after a post is edited
- Foreign character support (or simply indexing content with ‘UTF-8′ encoding
- Memory issues for content-heavy posts
wpSearch 1.5.0.5 is a rock-solid release that is starting to make a name for itself in the Wordpress world. The new ‘Phone Home’ feature in wpSearch allows users to report their copy of wpSearch. A few of the blogs with wpSearch currently in use are listed here:
Patrick Cushing at the EnterVenture blog wrote a very detailed comparision of the default Wordpress search’s relevancy vs. wpSearch’s. This article ended up at digg.
Of course, as far as wpSearch has come in its short lifespan, there exists a set of users that deserve credit for pointing out issues and keeping me informed of bugs, needed features, etc.. So, in no particular order, I would like to thank:
- ComputerBob, at ComputerBob.com for pointing out the first instance of the empty result issue. He has thoroughly documented his usage with wpSearch at his blog, in a fair and balanced fashion. Furthermore, he has sent his index data back with detailed comments when most users would simply give up on wpSearch. Thanks ComputerBob.
- Robert Irizarry, who has kept the wpSearch thread at the Wordpress repository stuffed with feature ideas and issue notices.
- Olivier, who’s 6000 posts provided the first failed scalability test for wpSearch. His pointing out of this issue led to a change to allow for greater scalability — in other words, wpSearch 1.5 was tested successfully up to 7,000 posts. Great dedication to detailing these issues has helped wpSearch greatly.
- Karl Heigl, who first mentioned the fact the wpSearch was not handling German accents, and subsequently all foreign (to the U.S.) characters. This also ended up affecting Olivier. This bug was fixed in 1.5.0.5. Thanks Karl!
- A user named Brian, said, “Thanks for the update. If you need any other information or even help testing, I’d be happy to assist. Just let me know. ” Thanks for your support Brian.
- And to all those who have donated to this project so far!
So, wpSearch 1.5.0.5 wouldn’t be at it’s current status if it weren’t for those supporting it.
Features coming up for wpSearch include result highlighting, contextual snippets, and a progress meter for index building. I encourage everyone who is reading this but hasn’t installed wpSearch yet to try it out, and see the awesome blog search that you’ve been missing.
KLogger: A Simple Logging Class for PHP
Since the latest release of wpSearch, a couple issues have cropped up and are slated to be fixed shortly. Some of the issues, although, are a bit harder to catch without a good set of debugging tools for PHP. The classic example of such a tool would be a log file logger.
As soon as I realized the need for a logger while developing wpSearch, I decided to check to see if one had already existed on the internet — someone had surely created a simple logging class and made it available before .. I would think. I’m a believer in the C programmer’s motto “build upon the work of others”, so checking to see if someone else has done the same thing prior to starting a project comes naturally.
After a little browsing, I couldn’t find what I was looking for. Put plainly, I wanted a logging class that:
- Checked permissions prior to logging
- Had a priority heirarchy built in ( Debug, Info, Error, and Fatal Message Levels)
- Logged to plain old text files
- Managed file handling cleanly (Open the file once, close the file once)
- Managed resources (make sure the file gets closed)
Not too complicated. This logging class would require around 100 lines of code.
Another option involved using logging functions available in Zend, or the logging class provided in PEAR. These libraries were a little overkill for what I needed, so I passed.
I decided to write of the class myself, and it has turned out to be pretty handy. I figured someone else would probably find it useful as well, so I have posted it on it’s own project page. Click here to go to the KLogger project page.
Using KLogger is very straight-forward. Here’s an example:
require_once 'KLogger.php'; ... $log = new KLogger ( "log.txt" , KLogger::DEBUG ); // Do database work that throws an exception $log->LogError("An exception was thrown in ThisFunction()"); // Print out some information $log->LogInfo("Internal Query Time: $time_ms milliseconds"); // Print out the value of some variables $log->LogDebug("User Count: $User_Count");
Depending on the priority level that is used when instantiating a new KLogger, only certain messages are actually logged to the file. If the most verbose priority level is used, ( KLogger::DEBUG ), all messages are logged. If the least verbose level is used ( KLogger::FATAL ), only Fatal-level errors are logged. Here’s a breakdown of the most verbose level to the least-verbose level:
- Debug (Most Verbose)
- Info …
- Warn …
- Error …
- Fatal (Least Verbose)
A sixth level is also available: KLogger::OFF, so if you need to release a site without logging, you can simply set the priority level to Off, and not have a single message logged. (In fact, a log file will never be opened).
There isn’t too much documentation on the class right now, but it shouldn’t be too hard to figure out.
A couple comments on design: A few log class examples I’ve seen implement a singleton pattern, essentially locking the programmer into using one logger at all times. I usually lean towards letting the developer decide those things: If he wants to use a single logger, he can create a global log object in his application.
An screenshot of KLogger:
I think at this point I’ve actually done a better job describing KLogger in this post than on the project page. A few more details are listed there, along with the download. If you find it useful, leave a comment and let me know.
Click here to go to the KLogger project page.













