Sep 012011
 

I was asked to come into a project very late in the game. We had 4 1/2 hours until we were to show off a prototype of the company’s new “portfolio” site. We were five days behind with minimal functionality accomplished. I was asked to save the day.

A little nervous, and completely in the dark still about what this WordPress theme we’d bought was all about, I agreed to give it my best shot. I’ve worked with WordPress plenty of times, I had a decent understanding of how the API sorta worked, and I know PHP like the back of my hand. Still, tearing into someone’s code often times translates into hours of just figuring out their style and where everything is laid out.

Continue reading »

 Posted by at 1:34 AM
Jul 092011
 

I found myself in an environment where a framework wasn’t going to be option. We had a cluster of web servers and I needed to run sessions across a database. Sure, I could have just written a simple function for doing so, but I thought it would be better to PHP’s session_set_save_handler() function.

Using session_set_save_handler() will allow you preserve and use the built in PHP sessions functions and variables, while attaching your own custom class to handle anything from Database sessions, to reading file sessions from one source. You can even get fancy with things and write in your own custom tracking. There really are no limits.

The first thing you’ll need to do is design a class with a few specific public functions. Those are:

  • open
  • close
  • read
  • write
  • destroy
  • gc

I this lesson, we’ll be connecting our sessions to a database.  So I’ll need to also setup a constructor to handle the database connect, and I also like to throw in destructor and call a session_write_close().  There are also ini_set items you can throw at the top of your code to setup certain session items the way you like them:

ini_set( 'session.gc_probability', 50 );
ini_set( 'session.save_handler', 'user' );
ini_set( 'session.gc_maxlifetime', 28800 );

gc_probability is something I had to play around with. This is used to manage the probability that the garbage collection process is started. I found that 50 worked best for me.

save_handler simply defines the name of the handler. The default is ‘files’.

gc_maxlifetime tells PHP how many seconds old something is before it is considered garbage. I set our’s for 8 hours to accommodate the shift length of the people using the system I was building. They didn’t like to be logged out for idling. This is usually something you’ll want to match your company’s IT policy.

Let’s now take a look at the Sessions class.

class Session
{
    /**
     * a database connection resource
     */
    private $_sess_db;

    function __construct( $db )
    {
        $this->_sess_db = $db;

        return true;
    }

    function __destruct()
    {
        session_write_close();
    }

    /**
     * Open the session
     */
    public function open()
    {
        return true;
    }

    /**
     * Close the session
     */
    public function close()
    {
        return true;
    }

    /**
     * Read the session
     */
    public function read( $id )
    {
        $sql  = "EXEC GetSessionData @SessionID=N'" . $id . "'";

        $results = $this->_sess_db->prepare( $sql );
        $data    = $this->_sess_db->fetchrow( $results );

        return $data['SessionData'];
    }

    /**
     * Write the session
     */
    public function write( $id, $data )
    {
        $sql = "EXEC WriteSession @SessionID = N'" . $id . "', @SessionData = N'" . $data . "'";
        $res  = $this->_sess_db->prepare( $sql );

        return true;
    }

    /**
     * Destoroy the session
     */
    public function destroy( $id )
    {
        $sql = "EXEC DestroySession @SessionID = N'" . $id . "'";

        if ( $res = $this->_sess_db->execute( $sql ) )
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Garbage Collector
     */
    public function gc( $max )
    {
        $back = date( "Y-m-d H:m:s A", mktime( date("H")-(($max/60)/60) , 0, 0, date("m"), date("d"), date("Y") ) );

        $sql = "EXEC DeleteOldSessions @Timeout = N'" . $back . "'";

        $this->_sess_db->execute( $sql );

        return true;
    }
}

I wrote a database class for this particular system, so I have passed that into my constructor. You can do the same, or simply put your database connection code in there. I used the tables ‘SessionID, SessionData, TimeIn, LastActivity, and TimeOut’. You can use most any method you want, as long as you track your data and the PHP Session ID, and Time In and Out columns. I used LastActivity to determine if the session had been abandoned or not.

As you go through the class, you’ll quickly notice that my open() and close() functions do nothing more than return true. You can put custom code in here to track things or log things if you want. You can even have it e-mail you a picture of a duck. The point is, these functions are all open for you to customize how you see fit. I’d suggest playing around with them to get a feel for what you can do.

Now onto the read and write functions. PHP is always going to handle the Session ID. It will pass it into these functions so you can use them. For me, I was using it to plug into a Stored Procedure to read and write my sessions. In here you can do the same, or read/write to flat files, or any other method you maybe want/need to use.

Next is destroy. This is where end a session. For my particular destroy, I would simple add a timestamp to the TimeOut field in my database.

Finally my gc function. This would do some math to see how long a session has been closed for, or idling for, and based on that, I would erase the session from the database. You can choose to leave the sessions in for as you’d like. Perhaps you want to use the Sessions table to track history, and make it a much more beefy database table. That’s fine, but in my application, we did activity tracking in a different place. Either way is fine.

Now, how do I tell PHP to use this?

session_set_save_handler( array( $session, 'open'    ),
                          array( $session, 'close'   ),
                          array( $session, 'read'    ),
                          array( $session, 'write'   ),
                          array( $session, 'destroy' ),
                          array( $session, 'gc'      )  );

You’ll see that each function included is in an array, with a variable before its name. That variable is my session class. $session = new Session( $db );

From here its pretty much PHP 101. session_start() to start your session on each page. The $_SESSION array will still hold all of your session data. This makes things nice if you ever have to revert back to standard sessions, and ditch your class and handler. You won’t have to rewrite all of your session handling code. You’ll just have to remove your class instantiation, and your session_set_save_handler call.

So if you find yourself in a situation where you can’t use a framework, or don’t want to use a framework, but still need a way to better control your sessions, or through them into a database, consider the session_set_save_handler method.

Jul 062011
 

It isn’t often I take up some blog space to brag about myself in the past. Today I had a phone call from someone interested in one of my past projects, TeaserLeague.com.

Teaser League is a game that I often describe as a football survival pool with a team based rotisserie element to it. Aside from the sports element, there was a lot of database and back end architecture that I got to contribute to the project:

  • Database Design
  • Database Performance Tuning
  • Automation Process for standings, new membership, and real-time NFL scores.

One of my favorite resources for tuning our MySQL database was the MySQL Performance Blog. They have a lot of information on just about any topic you need. For us, it was how to make the database run as fast as possible, with a lot of heavy queries, and a lot of simultaneous connections. We were gearing up for a 250,000 member web site, with most everyone active all day Sunday.

I had my first chance at writing production C code. We decided to write our first breed of automation scripts in C in an attempt to pull the most performance possible out of our linux servers. I didn’t know Python, and C seemed a better route than Perl. Nothing against Perl, but we could have just as easily used PHP, and not accomplished what we wanted. I should note that in the end, we had mostly PHP scripts, and just a couple C scripts pushing the back end.

Another aspect that I really enjoyed was the chance to interact with the community. I was asked if I would handle our social media aspects, and setup a Facebook fan page and a Twitter account for the site. I pushed those pretty good, and built a pretty decent following. I was even able to get Ochocinco to read one my responses to him, but couldn’t get him to RT me. My guess is he was restricted from anything that resembled a gambling site, even though we were for entertainment only.

I miss working with a community. It was a nice break form the hectic and sometime grueling task of coding. I’m still working on getting LivingPoetic.com up and running, and hope to break back into some community management this fall.

Speaking of social networking, I could use a few followers in Twitter. Please follow me: @iamdanjoseph — I promise I’ll follow back.

 Posted by at 11:13 PM