Geekery

If you’re reading this blog post, then chances are, you’ve discovered the wonderful PEAR package called System_Daemon. This well-done package offers the ability to turn any PHP script into a daemon and does a good job of making sure there aren’t memory leaks or problems along the way.

There’s a great demo of the package and an explanation of how to get it up and running on the blog of the creator, Kevin von Zonneveld.

The source code for the demo in the post seems complete enough, but it was missing one major component that seems like it would be common for users. The post unfortunately leaves out how one can set the location of the log file or the PID file for the daemon to run. This is a common necessity for many “shared system”-esque environments that exist out there or for those who just happen to be working under restricted permissions. The documentation for the class doesn’t present this information in an easy-to-find manner either.

So, I’m here to let you know that it’s easy as pie… as long as you know the name of the option you’re looking for. By default, the system seemed to want to use the following for the defaults:

/var/run/{appName}/{appName}.pid

and

/var/log/{appName}.log

There’s a couple steps that you’ll want to take so you can get a System_Daemon up and running under the proper user, using files in locations that are accessible by your user.

First, you’ll want to grab the UID and GID of the user you’d like your daemon to run as. This can be achieved by the following command:

id

Once you’ve got your UID and GID, you can get to setting the options for your System_Daemon.

<?php
// Setup
$options = array(
    'appName' => ... 
    ...
    ...
    'appRunAsGID' => your UID,
    'appRunAsUID' => your GID,
    // This sets where you want the log file to be located
    'logLocation' => '/home/uesrname/daemon.log',
    /**
       * This sets where you want the pid file to be created. 
       * Be careful, there's an undocumented restriction on 
       * the naming convention for where the pid file can be 
       * written. It must be in a directory by the same name 
       * as the pid file like the example below. I don't know 
       * why, but it will throw an error if you try to set it 
       * otherwise.
       */
    'appPidLocation' => '/home/username/daemon/daemon.pid'
);
?>

There you have it. By setting the logLocation and appPidLocation options, you can tell the daemon where you’d like the log files to write to and where the pid should be created. Then, by setting your appRunAsGID and appRunAsUID properly, you’ll be up and running scripts as daemons in no time. While the GID and UID settings may have been evident in the aforementioned demo from the author, the logLocation and appPidLocation options may not have been so clear.

If you enjoyed this post, then please consider subscribing to my feed.

Technology

While hanging out in the Freenode ##php channel, a user came along asking how to create a table of contents from an HTML string by extracting the header elements. Many suggestions came through including using Regex or a jQuery solution. Using Regex to parse HTML in PHP is a bad idea and can get quite messy. You can see what I mean by looking at the PHP implementation section towards the bottom of this page. While it may be effective, and might have previously been the only option available, we now have better tools available to get this job done cleanly, elegantly, and with far fewer lines of code than before.

So, what’s our new alternative? It’s called the Document Object Model and it’s powerful, easy to use, and a great alternative to Regex or functions designed for XML.

So, you want to parse all the H2 tags from a website and generate a table of contents? No sweat! Check it out:

/**
   * Use whatever method you like to grab your HTML string. We'll use a site I mentioned in this post
   * as an example.
   */
$remote_site_data = file_get_contents('http://www.10stripe.com/articles/automatically-generate-table-of-contents-php.php');
$dom_document = new DOMDocument();
@$dom_document->loadHTML($remote_site_data);
$headers = $dom_document->getElementsByTagName('h2');
foreach ($headers as $header) {
   $table_of_contents[] = trim($header->nodeValue);
}
var_dump($table_of_contents);
/**
array(5) {
  [0]=>
  string(10) "Motivation"
  [1]=>
  string(11) "This script"
  [2]=>
  string(12) "How it works"
  [3]=>
  string(3) "Fin"
  [4]=>
  string(17) "About the Author"
}
*/

You can do whatever you’d like with the array of contents. It’s likely that you may want to only grab H2 elements of a particular class. It’s easy to alter our code to do just that. Just add a conditional before you add it to your array:

foreach ($headers as $header) {
   if ($header->getAttribute('class') == 'specialclassname') {
      $table_of_contents[] = trim($header->nodeValue);
   }
}

As you can see, DOMDocument is a powerful and flexible tool and can really allow you to get a hold of some HTML and manipulate it however you like.

If you liked this post, then please consider subscribing to my feed.

Geekery

After receiving an update today to push my Chrome version to 5.0.322.2 dev, I noticed that I could no longer log in to the web site that I had open when the update was done. I happened to be developing a website when I received notification for the update so, like always, I just continued developing and let the new version of Chrome install in the background.

When it was finished, I closed all my browser windows, re-opened Chrome and navigated back to the site I had open that I was working on. Try as I might, I couldn’t seem to get my $_SESSION information working for PHP. This was first noticeable when I tried to log in and it didn’t appear to work correctly. I tried another web site and it worked fine. I tried another browser on my development site and that worked fine too. I decided to go ahead and use the session_id() function and noticed that I was getting a new session ID with every page load.

I finally did some digging around and realized Chrome wasn’t setting any cookies for the domain. I tried other websites and they all worked fine. For some reason, the site I had open when the browser upgraded just wasn’t creating cookies for me.

I checked my configuration settings. I cleared all my personal information. In the “Under the Hood” menu in the Google Chrome options, I set my cookies to “Accept All” and still, no luck. Cookies were working just fine everywhere else except for where I needed to do work.

Frustrated, I decided to click the “Reset to defaults” button and it worked!

So, if you’re having troubles getting Chrome to create cookies for just one domain, try resetting defaults in your “Under the Hood” menu and see if that works for you.

I hope this helps others experiencing this annoying problem.

If you liked this post, then please consider subscribing to my feed.