HOWTO Install MongoDB for PHP on Mac OS X

15 Aug, 2011 — Apple, HOWTO

MongoDB is a document-oriented database (among other things), and it’s especially convenient that the native document format is JSON. For various ongoing pet projects, I figured I’d give it a try to avoid the overhead of creating/maintaining schemas and having to flatten down my JSON objects to fit a relational model.

These instructions work for 10.7 Lion, 10.6 Snow Leopard and 10.5 Leopard. The steps outlined here ensure that your MongoDB installation integrates well with the rest of the system (Apache, PHP & launchd), is started automatically when the machine starts up, and makes it easy to upgrade later.

I read a lot of conflicting instructions on the Web about how to install MongoDB, and they’re either incomplete (most of them skip the part about making MongoDB run automatically at startup), and none of them satisfied the following requirements I had:

  • I should not need to install any software that’s already present on a stock Mac OS X installation (Lion, Snow Leopard or Leopard, at the very least.)
  • It should be relatively easy to upgrade the base version of MongoDB, so installing it via a package manager would be preferable to installing it from source.
  • The MongoDB server should be started up automatically through system-standard tools such as launchd — not manually every time I need to test something.

This tutorial assumes a virgin Mac OS X installation. If you already have a component installed, simply skip that step.

  1. Install XCode from the Mac App Store. It’s needed for MacPorts.

  2. Install MacPorts from macports.org. MacPorts is a package manager for Mac OS X that makes it easy to install and configure a lot of open-source software.

    Although MongoDB binaries are available from the MongoDB web site, I strongly recommend using the MacPorts MongoDB port. MacPorts ensures dependencies are installed correctly, and provides an easy way to upgrade all outdated packages at once.

Install and configure MongoDB


  1. Install MongoDB. Open a Terminal, ensure you’re using an account with Administrator privileges, and type:

          sudo port install mongodb

    That’s it, MongoDB is now installed. But there’s lots more to do to get it working.

  2. Create directories required by MongoDB.

          # The data directory.
          sudo mkdir -p /var/lib/mongodb/
    
          # The logs directory.
          sudo mkdir -p /var/log/mongodb/
  3. Create a config file. Put this in a new file at /etc/mongodb.conf:
          # This is an example config file for MongoDB.
          # Place it at /etc/mongodb.conf
          # Based on a sample provided at
          # http://www.mongodb.org/display/DOCS/File+Based+Configuration
          dbpath = /var/lib/mongodb
          bind_ip = 127.0.0.1
          noauth = true
  4. Configure a launchd LaunchDaemon. Put this in a new file at /Library/LaunchDaemons/org.mongo.mongod.plist.

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
            "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
          <plist version="1.0">
          <dict>
            <key>Label</key>
            <string>org.mongodb.mongod</string>
            <key>ProgramArguments</key>
            <array>
              <string>/opt/local/bin/mongod</string>
              <string>run</string>
              <string>--config</string>
              <string>/etc/mongodb.conf</string>
            </array>
            <key>RunAtLoad</key>
            <true/>
            <key>KeepAlive</key>
            <true/>
            <key>WorkingDirectory</key>
            <string>/var/log/mongodb/</string>
            <key>StandardErrorPath</key>
            <string>/var/log/mongodb/output.log</string>
            <key>StandardOutPath</key>
            <string>/var/log/mongodb/output.log</string>
          </dict>
          </plist>
  5. Start MongoDB via launchd. Type in a Terminal window:

          sudo launchctl load /Library/LaunchDaemons/org.mongo.mongod.plist

You can stop reading now if all you need is MongoDB and don’t plan to use PHP with it. The MongoDB server will be automatically launched at startup.

Enable Apache and PHP5

  1. Start Apache. In System Preferences, go to Sharing, and then check the box next to “Web Sharing”.


  2. Enable PHP5 support in Apache. Open the Apache config file, /etc/apache2/httpd.conf, and locate the following line.

          # LoadModule php5_module

    Uncomment that line, so it reads:

          LoadModule php5_module
        
  3. Restart Apache. Type in a Terminal window:

          sudo apachectl graceful
        
  4. Test if PHP is working correctly. Create a new PHP file at /Library/WebServer/Documents/phpinfo.php and put in it:

          <?php
            phpinfo();
          ?>

    Browse to http://localhost/phpinfo.php, and you should see a long page showing your PHP configuration.

    Apache and PHP5 are now configured.

Install and Configure the PHP5 MongoDB driver.

  1. Install PEAR. PEAR is the PHP Extension and Application Repository, from which we’ll install the PHP5 MongoDB driver.

          $ cd /tmp
          $ wget http://pear.php.net/go-pear.phar
          $ sudo php -d detect_unicode=0 go-pear.phar

    You’ll be prompted with a default file layout. I changed this to install it in /usr/local/pear instead of under /Users/Admin.

          Below is a suggested file layout for your new PEAR installation.  To
          change individual locations, type the number in front of the
          directory.  Type 'all' to change all of them or simply press Enter to
          accept these locations.
    
           1. Installation base ($prefix)                   : /Users/Admin/pear
           2. Temporary directory for processing            : /tmp/pear/install
           3. Temporary directory for downloads             : /tmp/pear/install
           4. Binaries directory                            : /Users/Admin/pear/bin
           5. PHP code directory ($php_dir)                 : /Users/Admin/pear/share/pear
           6. Documentation directory                       : /Users/Admin/pear/docs
           7. Data directory                                : /Users/Admin/pear/data
           8. User-modifiable configuration files directory : /Users/Admin/pear/cfg
           9. Public Web Files directory                    : /Users/Admin/pear/www
          10. Tests directory                               : /Users/Admin/pear/tests
          11. Name of configuration file                    : /Users/Admin/.pearrc
    
          1-11, 'all' or Enter to continue:

    At this prompt, type 1

          (Use $prefix as a shortcut for '/Users/Admin/pear', etc.)
          Installation base ($prefix) [/Users/Admin/pear] :

    At this prompt, type /usr/local/pear

          Below is a suggested file layout for your new PEAR installation.  To
          change individual locations, type the number in front of the
          directory.  Type 'all' to change all of them or simply press Enter to
          accept these locations.
    
           1. Installation base ($prefix)                   : /usr/local/pear
           2. Temporary directory for processing            : /tmp/pear/install
           3. Temporary directory for downloads             : /tmp/pear/install
           4. Binaries directory                            : /usr/local/pear/bin
           5. PHP code directory ($php_dir)                 : /usr/local/pear/share/pear
           6. Documentation directory                       : /usr/local/pear/docs
           7. Data directory                                : /usr/local/pear/data
           8. User-modifiable configuration files directory : /usr/local/pear/cfg
           9. Public Web Files directory                    : /usr/local/pear/www
          10. Tests directory                               : /usr/local/pear/tests
          11. Name of configuration file                    : /Users/Admin/.pearrc
    
          1-11, 'all' or Enter to continue:

    At this prompt, type 11

          (Use $prefix as a shortcut for '/usr/local/pear', etc.)
          Name of configuration file [/Users/Admin/.pearrc] :

    At this prompt, type /etc/pearrc

          Below is a suggested file layout for your new PEAR installation.  To
          change individual locations, type the number in front of the
          directory.  Type 'all' to change all of them or simply press Enter to
          accept these locations.
    
           1. Installation base ($prefix)                   : /usr/local/pear
           2. Temporary directory for processing            : /tmp/pear/install
           3. Temporary directory for downloads             : /tmp/pear/install
           4. Binaries directory                            : /usr/local/pear/bin
           5. PHP code directory ($php_dir)                 : /usr/local/pear/share/pear
           6. Documentation directory                       : /usr/local/pear/docs
           7. Data directory                                : /usr/local/pear/data
           8. User-modifiable configuration files directory : /usr/local/pear/cfg
           9. Public Web Files directory                    : /usr/local/pear/www
          10. Tests directory                               : /usr/local/pear/tests
          11. Name of configuration file                    : /etc/pearrc
    
          1-11, 'all' or Enter to continue:

    At this prompt, type <Enter>

          Would you like to alter php.ini </private/etc/php.ini>? [Y/n] :

    At this prompt, type Y.

  2. Install the PHP MongoDB driver.

          sudo /usr/local/pear/bin/pecl install mongo
  3. Configure the system PHP to load that extension. Add this line to your php.ini. (If you don’t know where your php.ini file is located, go back to the phpinfo page that you created earlier, and you’ll find it on that page.)

          extension=mongo.so
  4. Restart Apache. To enable PHP5 with MongoDB support, restart Apache.

          sudo apachectl graceful

Test your installation.

  1. Create a simple test script. Create a PHP file at /Library/WebServer/Documents/mongodb.php

          <?php
            $mongoDB = new Mongo();
            $database = $mongoDB->selectDB("example");
            $collection = $database->createCollection('TestCollection');
            $collection->insert(array(test => 'Test OK'));
    
            $retrieved = $collection->find();
            foreach ($retrieved as $obj) {
              echo($obj['test']);
            }
          ?>
  2. Test the installation. Browse to http://localhost/mongodb.php. If you see the following output, then congratulations, MongoDB is properly installed and configured to work with PHP on your Mac. Happy developing!

          Test OK

If this worked well for you, or if it doesn’t work for your specific configuration, please let me know via the comments, and perhaps we can troubleshoot.

Oh, c’mon, it’s right there in my email address

9 Aug, 2011 — Trail

View on Google+And in my From: header too. You’re just one letter away—you can do it!

Beyond Yak Shaving

5 Aug, 2011 — Trail

I’m now somewhere in the middle of forging iron to make razors to shave those yaks.

View post on Google+

If you have an Android, you have …

20 Mar, 2011 — Design & Usability, Google

Disclosure: I work at Google, but I’m unaffiliated with the Android team. This blog post reflects my own personal opinions, not my employer’s.

Better Apps

  • Native Gmail. Which means you can get Conversation View, colored labels, stars, search and spam reporting right from within the app. Apple’s draconian rules prevent any other email client from being accepted into the App Store.
  • Turn-by-turn Navigation. This has got to be the killer feature on Android. Using the in-built Google Maps app, pick a destination, and ask Android to navigate to it. Then keep doing other things such as checking email, or viewing Facebook — of course, only if you’re the passenger, not the driver. The app speaks directions as the car drives, and uses text-to-speech technology to speak names of streets and cities, so you don’t have to ever look at the phone — focus on the road. The iPhone’s Maps app is terrible in this regard.
  • Full Google Voice integration. Android allows any application to hook into its innards. So when you use the Google Voice app, it replaces the actual telephone dialer completely. The iPhone app is not permitted to integrate fully, so it does what it can as a second-class citizen on iOS. (If you’ve ever used Google Voice on the iPhone, check your call log: it’s littered with the behind-the-scenes numbers that Google Voice connects to, not your actual contacts’ phone numbers. There is nothing that the Google Voice app can do about this.)
  • Widgets on the home screen tell you important bits of information with a quick glance. I use the Pure Calendar widget to see my daily events without having to start up the calendar app. It’s there, it’s ready, and it’s opportunistically visible even when I didn’t pull out my phone to check my schedule.
  • Crop your photos before posting them. The default photos app lets you crop your photos before you post them via email or to Facebook.
  • Double-click to reflow text in the browser means that you no longer need to scroll horizontally to read articles formatted for larger screens. Double-clicking in a block of text doesn’t just zoom into it (like the iPhone also does), but it also reflows the text maintaining a minimum readable font size to fit within the horizontal dimensions available (which the iPhone does not do.) You have to experience this to see what I’m talking about.
  • You don’t have to wait for an app to update its data. Apps such as Twitter and Facebook can run in the background and update their data, so when you pull out your phone, they already have the latest tweets and status updates up on the screen. On the iPhone, these apps can fetch data only after they’re fired up, which means you must wait until they’re done fetching before you see the updates.
  • Sync photos from Twitter & Facebook Contacts. Just enable Contacts Syncing, and start seeing your contacts’ photos from their Twitter and Facebook profiles when you dial their phones.
  • Bluetooth-related apps can do amazing things! I use the Car Locator app which comes with a Bluetooth plugin; once you pair it with your car, it will auto-detect your car’s location the moment the Bluetooth connection is lost — i.e., as soon as you park and shut off the car. Apple does not allow apps to do things like this on iOS.
  • Barcodes scan quickly with live video capture. On Android, the barcode scanner app has full access to live video when you fire it up. This way, it can constantly refine its view and try to locate a barcode within the field of view. On the iPhone, you have to fire up the app, then 1) take a picture 2) crop it 3) click a button to acknowledge that this is indeed the picture you’d like to use 4) wait to see if the app recognizes a barcode 5) rinse, repeat until code is recognized. On Android, you keep waving the phone at the barcode for a few seconds until it recognizes the code. Zero button presses.
  • Switch out of Silent Mode automatically after a preset interval: I have missed several calls because I forgot to switch out of silent mode when leaving the office. Phone Silencer is an app that shows up when you put your phone in silent mode using the usual way (power button, or turn ringer all the way down), and asks if and when you’d like to revert to normal mode. You can pick a time and a volume setting, and the app makes sure you don’t miss a call (well, at least for this one reason.) iOS will not and cannot let apps do such a thing, because silent mode is controlled by a hardware button.

A True Post-PC Device

  • Contacts sync over the air. Because a true post-PC device does not require to be synced with a computer every time. On Android, I edit my contacts within Gmail on my desktop, and a few seconds later (yes, seconds; usually about 2 to 5), the contacts on my phone are updated automatically. And vice-versa.
  • Apps are installed over the air. With the new Android Market, if someone shares a link to an app while you’re using your computer, simply login and click to have the app sent to your phone. When you take your phone out of your pocket eventually, your shiny new app is there, waiting for you. No connecting to iTunes (or other desktop software) required.
  • Sync your photos online as soon as they are taken. You can have an app upload your photos to PicasaWeb as soon as they are taken, so you never have to connect your phone to a computer to get them off it. Lose the cable.
  • Full multi-tasking. If you click a link in your email app that opens the browser, clicking ‘back’ will take you back to your email app. If you click a link to a map from within the browser instead, then clicking ‘back’ twice will take you exactly where you expect it to.
  • You can skip carrying a laptop. Android lets you download, copy, move and send files by email. Any type. This means that you can actually skip carrying your laptop on trips, and have a device that will let you do all that you want with it. No artificial limitations. If someone sends you an archived file, you can open it, browse it, email it, move it into your Dropbox, …
  • Data is easy to get in and out. iTunes not required. If you’ve ever tried to copy music to your iPod/iPhone from a computer other than the one it’s synced with, you know what I’m talking about. I could never get a file out of an iPhone unless it was a photo. Android lets me move, copy, delete, do whatever with any file on the phone with a standard USB cable.
  • Not really about being a post-PC device, but: Charge your Kindle and Android phone with the same cable. Depending on the manufacturer of your Android phone, you might just be able to charge it with the same charger as the Kindle (Micro USB) so you need to carry one fewer charger while traveling.

User Interface Niceties

  • A consistent, global back button.. You know exactly how to get back to the previous screen in any application, and don’t have to rely on the developer of every single app putting a Back button in a consistent position. Ditto with the ‘menu’ button — it’s always where you expect it.
  • Instant previews of incoming notifications. It’s better than a cryptic numeric badge on top of an app icon. You don’t have to fire up an app to see the new email or text message you just received, or a notification when someone mentions you on Twitter. The pull-down notifications area scrolls a quick preview once, and after that, it is available to scan quickly.
  • You can tell if you’re typing in upper case or lower case, because the keyboard keys change accordingly.
  • Unlock your phone with a pattern instead of using a PIN. Of course, if you’d rather use a PIN, you have that choice too. You, as the user, are in complete control of your experience.

And finally …

  • Freedom. I cannot stress this enough. With Android, your phone is yours. It is not rented from a corporation who decides what you can and cannot install on it. If you don’t want to upload your app to Google’s Android Market, upload it to Amazon’s Android Market. Or put an .apk file on your server, and distribute it yourself. You don’t have to pay anybody 30% for the privilege of dictating to you what you are allowed to do with your phone.

URL Design Sins: 16 things that don’t belong in URLs

5 Mar, 2011 — Design & Usability, HCI, Thoughts

(Because 16 is as good a number as any.)

Much has been said for a long time about making your URLs easy to use, remember, type, hack, and spread virally. There is still no dearth of ugly URLs all over the Web. A few very popular content management systems also engage in dirty URL practices, and it’s a shame. To aid you in cleaning up your URLs, here’s a list of specific things that do not belong in a URL.

  1. www. We’ve spent enough time with the World Wide Web to know that web pages reside on the WWW. Adding those four characters to the beginning of every single URL not only requires users to type them in every time, but also requires 4 extra bytes in every single database that stores URLs. Think for a moment how many bytes that would be. Get rid of them! And after you do that, make sure all your www. URLs redirect to the non-www. version.
  2. Port numbers. Unless your site is under test, there is no valid reason for hosting it on a non-default port (i.e., a port other than 80.) Apache on Mac OS X has a performance cache that runs on port 16080, and makes every URL of the form http://your-site.com:16080/. Unless you find a mechanism to run the performance cache on port 80, it is a good idea to dump the cache. It’s not worth the confusing URL (to most users, if not to you.) Standard well-known port numbers are there for a reason.
  3. Index filenames. Filenames such as index.php and default.asp do not give us any more information than the rest of the URL. Drop them.
  4. Details of the server-side technology. Your users don’t need to know what software you’re running behind the scenes. They couldn’t care less about whether your pages are .php, .jsp, .aspx or .do. It’s best to configure your server to hide these extensions, and then make sure none of your URLs contain them.
  5. Special directories for special scripts. You no longer need to place your scripts in a cgi-bin. Get rid of that directory and any others like that. If your server requires you to do something like that, either find a way to configure it correctly, or upgrade to one that will let you do that.
  6. Document maintainers’ names. Often, when each document has an assigned maintainer for some duration of time, those documents end up being in that particular person’s web space. Later, when the maintainer moves on or someone else takes over the maintenance, you’re left with a different URL than what you started with. To avoid this, it’s best to categorize documents by topic and subject instead of under ~username/document.html.
  7. Internal database IDs. Sure, your content management system needs those IDs to locate your content, but your users don’t need to know. If it takes an extra database lookup to get the ID from the URL, then so be it.
  8. CMS Module Names. Use a CMS that is intelligent enough to render a page without needing all sorts of information stored in the URL. Joomla is particularly notorious at this. What does this URL tell you about where it will take you?

    http://www.joomla.org/content/section/1/74/

    Now what if it were:

    http://joomla.org/news

  9. MiXeD-CaSe NaMeS. Don’t confuse your users by-Mixing-Upper-case-and-Lower-case-Characters-in-the-URL. Stick to lower-case letters, and don’t make them guess. If your user actually types in a URL in mixed case, normalize it on the server and serve the appropriate case.
  10. Random gunk. Unless you are a URL-compressor service such as Tiny URL or SnipURL, forget using random characters in your URL. Nobody wants to visit http://yourdomain.com/WijHyYQnVPWNs and guess what it might lead to.
  11. Session IDs. Make sure no user-session-specific identifiers end up in your URLs. This makes sure that users can pass on URLs to other users via email or IM, be able to bookmark them, and be sure that they represent a single resource. There are better places to keep session state in.
  12. Punctuation. Avoid punctuation that might make it difficult for people to tell others about your wonderful site over the phone. The only punctuation you may have is a hyphen ("-") and HTML entities that have special meaning (e.g. ?, #, :, + and @). No underscores, commas, periods, brackets, parentheses, braces, quotes, less-than, greater-than, equals, or pipes.
  13. Database query details. If your web pages have even a hint of database query language in the URLs, you should be on The Daily WTF.
  14. Repeated domain name. If the address of your web site looks like http://your-site.com/your-site/your-page.html, then you should have a chat with your web hosting provider about how to shorten it to http://your-site.com/your-page.html.
  15. Inconsistent naming. If you sell several products, then make the subdirectories below each product name exactly identical. If someone were to replace a product name by another, the rest of the URL structure should still continue to function. In other words, strive for consistency in naming.
  16. Missing content at each level. When a URL is several levels deep, users should be able to chop off parts at the end ("hack the URL") and still be able to get to a usable page. E.g. if you’re a news site, and if an example URL looks like: http://my-news-site.com/2008/05/21/news-story.html, make sure you include a list of news articles from 21 May 2008 at http://my-news-site.com/2008/05/21/, and a list of links to daily articles for the entire month of May 2008 at http://my-news-site.com/2008/05/.

There are some easy technological solutions to make this work. Many of these do not require you to change the underlying file system structure or database structure.

But most of this comes with discipline: there is nothing here that is technology magic. It is just an application of common sense to a common domain (no pun intended.) Google mod_rewrite and content negotiation to get started.

Next Page »