Internet Strategy Guide

Together we can defeat the internet

Wednesday, December 17, 2008

Zend_Log quickstart

Lately, I've found that I need to create a more robust logging system for both audits and debugging. I found a great logging primer from DevShed that offers some good insight into going about making a more robust system. Other than the theory, you shouldn't really take much more away from it since, as one comment points out, the implementation is poor aka globals are bad. Caveat: my implementation probably won't be all that great either but I hope to avoid making beginner's mistakes.

That being said, the reason this particular article is centered on Zend is because I'm pretty much in love with Zend right now. The main reason for writing this article is that, while the Zend documentation on Zend_Log is thorough and easy to understand when you read it, I hate back and forth between the sections of Zend_Log to make sure I understand what I'm needing to do.

I'm assuming you have at least gone through the Zend Quickstart before reading on. For my filesystem and db configuration, I use Zend_Config to load up settings such as the logfile name and log database adapter. I could've set the path for the file but I want a certain degree of flexibility.

At this point, I have the logger configuration from zend config  and the db adapter so let's move on to some code examples. This is partially taken from my in-progress class.

making a full filepath:

$filepath=(isset($options['FilePath'])) ? $options['FilePath'] : INC_PATH."/".$this->_systemConfig->system->logfile;
$writer = new Zend_Log_Writer_Stream($filepath);

the filepath is used with the Zend_Log_Writer. Next we set a format for the writer and then instantiate Zend_Log with the writer

$formatter=new Zend_Log_Formatter_Simple($format);
// specify format
$writer->setFormatter($formatter);
$logger=new Zend_Log($writer);

Note: $format is a text string that indicates how each log entry will appear.

The important things to remember here is that Zend_Log creates an associative array with all the basic useful log information. This array can be accessed in a variety of ways. For my purposes, knowing what is accessible by the stream and database writers are important.
If you have read the documentation thoroughly, you will have found that in section 30.1.6 Zend documents this array expressly. Unfortunately, unlike some most of their other documentation, this useful bit of information is almost secreted away. I've scoured the docs a lot to find the keys created by Log so here they are as a quick reference.

  • timestamp
  • message
  • priority
  • priorityName

These little gems are pretty much the keys to the Kingdom of Zend_Log.
If you want to reference them for formatting in a stream, you can do something like:

$format = (isset($options['LogFormat'])) ? $options['LogFormat'] : '%timestamp% '
.PHP_EOL.'%priorityName% (%priority%)'
.PHP_EOL.'%message%' . PHP_EOL.PHP_EOL
.str_repeat("=",100). PHP_EOL;

or if you need to use them for your db, you can use set column mapping like so:

$columnMapping = array('lvl' => 'priority','Priority'=>'priorityName', 'msg' => 'message');
$writer = new Zend_Log_Writer_Db($db, 'log_table_name', $columnMapping);

That should cover the basics.

Pro-tip discussion: For auditing, you may want to make separate log files for access,create,and changes made to your app/system. Error logging should log everything into files, but a separate debug copy would probably out in the development environment. I usually do a tail -f on debug/log file. It seems obvious to, me that any logging/exception system you make should have a simple outside error handling function to alert you of that logging broke. I believe this can be done by setting the error handler in the constructor. Haven't played with this yet. It seems to me that any robust logging system you implement will run into a chicken vs the egg type problem

posted by chance at 10:54 am  

Friday, November 14, 2008

INSERT INTO `table` (`column`,`col2`) VALUES isn’t completely worthless

In most cases, when doing an insert statement I use SET to increase readability. It is also nice because I can make dynamic statements with insert/update. It is because of these two reasons I never saw any value (for lack of a better term that isn't punny) to using VALUES. That is until I ran into a situation where I wanted to have a database level solution as opposed to making an application layer solution. The situation is as follows:
- create an entry in the parent table
- create entries in the child table that depends on the last insert id of the parent table.

Now that I think about it, there may have been a way to do it procedurally in SQL but the first solution I was stuck on how to make my next INSERT statement fulfill my criteria and be readable. This is where VALUES comes in. By using VALUES instead of SET, you can do a multi-row insert statement.

example:

INSERT INTO Resource SET ModuleID=LAST_INSERT_ID(), Name='contact', Description='Contact resource in the default module';
/* multi-row insert */
INSERT INTO Privilege (ResourceID,Name,Description) VALUES
	(LAST_INSERT_ID(),'*','All privileges for this resource'),
	(LAST_INSERT_ID(),'browse','Browse only privilege for this resource'),
	(LAST_INSERT_ID(),'read','Read only privilege for this resource'),
	(LAST_INSERT_ID(),'edit','Edit only privilege for this resource'),
	(LAST_INSERT_ID(),'add','Add only privilege for this resource'),
	(LAST_INSERT_ID(),'delete','Delete only privilege for this resource');

So now, VALUES isn't completely useless after all.

posted by chance at 1:03 pm  

Friday, November 7, 2008

stupid *nix tricks

[Edit: Seems like the -u flag is on debian systems such as Ubuntu. Did a man on a FreeBSD system and saw it didn't have the flag available.]
I use the cp and mv a lot that the -r and -f flags almost always accompany them. I also now realize I've used them for so long with so little thought that I forgot that there were other flags. My newest infatuation is the -u flag.

Basically -u lets you do a merge, which came in handy when I had to manually update wordpress for the first time. I could tell you more or you could RTFM

posted by chance at 11:38 am  

Tuesday, October 21, 2008

understanding zend ini (Zend_Config_Ini)

So I just spent the past half hour reading and sorting through documentation on Zend_Db, Zend_Config and Zend_Config_Ini so that I could set my driver options in my config file.

I could've set the options in the bootstrap but figured there had to be a way to set things up in my ini file. After all, what would the point of an ini file be if you can't set your configuration options in them?

The key to my issue ended up being Zend_Db. The bootstrap (if you followed the quickstart like i did) uses Zend_Db::factory() to set up your database connection. It does this by loading the configuration ini that you made. What the quickstart fails to mention is how to decipher your ini file. Or maybe it's some kind of Zend right of passage to figure out how to go beyond setting up your environemnt host/dbname/username/password. Or maybe I'm just incredibly dumb. I'm more prone to believing the latter.

So for the sake of anyone else like me that possesses the curiousity to know why things work the way they do but don't possess the patience to root documentation while doing a quickstart, here is a brief "wft is going on here".


Zend_Db::factory($configuration->database);

gives us a database adapter. It does this by parsing a Zend_Config object. If you're using an ini, then Zend_Config_Ini parses your ini file by replacing creating arrays by (to extremely simplify) exploding the dots (.). So

database.adapter=PDO_MySQL
database.params.host=localhost
database.params.dbname=kittens

becomes equivalent to

$database=array(
  "adapter"=>"PDO_MySQL",
  "params"=>array(
         "host"=>"localhost",
         "dbname"=>"kittens"
          )
    )

Sidenote: I found that if you have a password that contains non-alphanumeric values, it's best to encapsulate them in double-quotes. (i.e. database.params.password="kittens!") otherwise it cause Zend to hate you (short version of the outcome).
This basic understanding on how the ini file is parsed lead me to being able to do all sorts of fun stuff. In particular, was setting the driver options.
At first I thought I could do something like database.driver_options or database.driver.options to set things up. It made sense to me since the adapter is set outside of the connection parameters. What I eventually discovered was that according to Zend_Db, the params key isn't limited to the connection. It also encompasses the driver settings. So in order to set my PDO driver settings to the way I want them to be, I ended up doing:

database.params.driver_options.PDO::ATTR_PERSISTENT=true
database.params.driver_options.PDO::ATTR_ERRMODE=PDO::ERRMODE_EXCEPTION
database.params.driver_options.PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=true
database.params.driver_options.PDO::ATTR_DEFAULT_FETCH_MODE=PDO::FETCH_ASSOC

I think I'm going to have a lot of fun with my config ini in the future.

posted by chance at 12:21 pm  

Friday, September 12, 2008

iPhone 2.1 firmware impressions

Update: so far the battery life is holding out to be good. I'm getting less call fails but not sure if that's just a coincidence. Installs are definitely faster. Mail seems the same. Genius is awesome. Texting and contacts seem the same. Going to keep checking things out over the weekend.

Like anyone else who owns an iPhone 3G, I've been excited about today. I would like to right a full review on this but need to get work done so impressions will have to do. I did find a 2.1 firmware review at iSmashPhone.com.

Let's start with what this update is according to the apple site, we get the following:

  • Decrease in call set-up failures and dropped calls
  • Significantly better battery life for most users
  • Dramatically reduced time to backup to iTunes
  • Improved email reliability, notably fetching email from POP and Exchange accounts
  • Faster installation of 3rd party applications
  • Fixed bugs causing hangs and crashes for users with lots of third party applications
  • Improved performance in text messaging
  • Faster loading and searching of contacts
  • Improved accuracy of the 3G signal strength display
  • Repeat alert up to two additional times for incoming text messages
  • Option to wipe data after ten failed passcode attempts
  • Genius playlist creation

The big thing (for me) out of this update is the "Dramatically reduced time to backup to iTunes" and OMG it is amazing. It still takes a while to back up but comparatively to before, it is like comparing a 28.8 modem to a T1. As for everything else, I haven't had time to test and will probably play with things over the weekend. Below is a quick overview of what I noticed.

My reception at works sucks so can't really say much on the "Decrease in call set-up failures and dropped calls" part until I get to a good area, even then, it would be best to test over the week end. The same goes with the battery claim, time will tell if that holds true. Actually everything else would also require a brief test period to have a proper impression. Though one thing I can 'test' is the Genius playlist, which I'm going to play with now and will update this post later.

posted by chance at 10:56 am  

Tuesday, September 9, 2008

jQuery+AJAX+JSON

update: I really should RTFM. dataType can go in any place when listing options. If I had read the docs a bit more carefully, I would've noticed that the reason I started getting a JSON object back instead of a XMLHttpRequest is that I specificed 'success' with a callback instead of 'complete'.

Though I did figure out a better way of parsing the returned object

var myCallback=function(jsonObj){
for (k in jsonObj) {
if (iWantToCheck(k)) {
useValueOfK(jsonObj[k]);
}
}
}

Found out something interesting today. I normally try to stick to a simple AJAX return such as html or xml that is easy to manipulate. Today, I couldn't accomplish my task without the help of JSON. I'm sure there's other ways I could've told JS how to react on different succeed or fail conditions but JSON was the first one that came to mind. On to the story...I set the dataType on my ajax options to 'json' and was surprised to find that I was still getting a XMLHttpRequest object instead of the expected JSON object. I tried sending 'Content-Type: application/json' header, tried a bunch of other things I can't remember at the moment.
(more...)

posted by chance at 9:50 pm  

Wednesday, August 20, 2008

SXSW

So after reading this post, I want to go. There's a list of other things that seem interesting to. At a glance this guy seems cool and oddly familiar. The name reminds me of some of the DJs I knew in PBS when I was at Purdue. So if anyone is going, vote for them. I want to hear audio on this at the very least.

posted by chance at 4:49 am  

Tuesday, March 18, 2008

Pwning your MySQL

How to find out if a specific column exists:

SHOW COLUMNS FROM TableName WHERE Field LIKE ('ColName')

posted by chance at 10:13 am  

Tuesday, March 18, 2008

Use regex to find the source of an image

Recently, I needed to find the source of an image in a blob of text. Since the text was out of my control, the exact location of the tag was unknown. So to solve this problem, I buckled down and finally learned some regex. Regex has been my nemesis for years up until this point. Below is the result.

/src=[\"](.*?)[\"]/i

Looking at it now, I think it could be improved upon to be

/\<img.*?src\=[\"|\']?(.*?)[\"|\']?/i

[Edit: I'm dumb. the first one works. can't figure out how to make quotes optional. They really shouldn't be because your shit should be well-formed.]

Basically, my original expression looks for the first src property it finds and returns the text within. Looking back on it, this makes a few assumptions.

1) the first src property is within an image tag

2) the property is surrounded in double quotes

The second one (redone just now and therefore untested), should be better. Namely because It doesn't make any assumptions.

Point is that I'm now learning regex and am excited. Plus wanted to put this somewhere on the web in case there's someone like me who needs this and doesn't understand regex quite yet. Maybe one day I'll come back and break it down into how and why it does what it does but as of now, I don't think I can put my understanding of regex into a form someone who isn't me would understand.

posted by chance at 9:47 am  
« Previous Page

Powered by WordPress