Made of Everything You're Not

Personal blog of PHP programmer Eric Lamb.
  • Blog
  • Portfolio

Archive for April, 2009

A Look at Tweetizen

Posted in Code, Programming on April 29th, 2009 by Eric Lamb – 0 Comments

For those of you living under a rock for the past couple years Twitter is all the rage; for what I have no idea though. As I've said previously, Twitter's pretty stupid, but fuck man, the clients like it so what are you gonna do.

Tweetizen

As part of my research into all things Twitter I recently took a look at Tweetizen. According the Tweetizen website:

Tweetizen is a simple web-based tool designed to help you filter the daily influx of tweets, and easily find the ones that are relevant to you.

It's basically a site that uses the Twitter API to aggregate tags and keywords. Tweetizen doesn't have an API of it's own though I suspect this is would be a simple thing for them to implement; unless they're pussies that is.

Are you pussies Tweetizen?

Instead of an API they do offer a cheap JavaScript widget that can be embedded into a website if you're into half-assing the concept of "sharing". Just embed the below into the head of your website:

<style type="text/css">@import "http://embed.tweetizen.com/embed.css";</style>

And embed the below somewhere in your site:

<div id="twtzn" class="tweetizen_embed"></div>
 
<script type="text/javascript" src="http://embed.tweetizen.com/tweetizen.embed.js"></script>
<script type="text/javascript" src="http://embed.tweetizen.com?id=twtzn&g=Breaking+News"></script>

It looks just like every other widget they offer but you can style it using CSS if you wish. I imagine it would be incredibly tedious to really make the widget stand apart from the pack with just CSS but it's all they offer. They do provide a sample CSS file for usage along with instructions on the Tweetizen FAQ page to help the process along.

For me Tweetizen is a lose; but as mentioned above the clients love this shit so I'm in whether I like it or not.

Arc90 Twitter API Service Part 1

Posted in Code, Programming on April 27th, 2009 by Eric Lamb – 9 Comments

Twitter is all the rage these days; everyone's on it and everyone seems to love it. Not me, of  course. Like most social networking tools and services I find the whole thing pretty stupid.

Twitter

And, again, I'm apparently wrong because I've done some digging into manipulating the Twitter API so I can use it on my client's sites.

There are a few different libraries available for accessing the API, in all the popular programming languages, but the one I chose was the PHP Twitter API Client. Unlike all the other php libraries available this one has sick documentation. We're talking full phpdocumentor documentation; pure geak porn here.

I wanted to document the client but it's a really, REALLY, exhaustive codeset so I'm going to break it up into 2 different posts.

The Basics

The Arc90 API client requires the entire library be in the php include path so you'll have to either modify the php.ini directly or use ini_set to include the library. Kinda sucks, but whatever.

The client can also return the response in a few different data formats: XML, JSON and sometimes even RSS and ATOM depending on how you call the API and whether that format is available. For the purposes of this article all the examples will be returned in JSON format.

In order for the client to work you  have to have CURL installed and available to php. Most hosts already do but you never know so it's best to check with your host if you're not sure.

It's also important to familiarize yourself with all the ins and outs of the Twitter API. They employ rate limiting and have some useful information for developers that'll help make the API a little less painful.

Basic Example

The client is a full OOP service with exceptions so the basic layout of the algorithm is like the below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
//echo ini_get('include_path');
require_once 'Arc90/Service/Twitter.php';
 
$username = 'YOUR_USERNAME';
$password = 'YOUR_PASSWORD';
 
$twitter = new Arc90_Service_Twitter($username, $password);
 
try
{ 
 
	$response = $twitter->getFriendsTimeline('json');
	$return = $response->getData();
 
	// If Twitter returned an error (401, 503, etc), print status code
	if($response->isError())
	{
		echo $response->http_code;
	}
	print_r( json_decode($return) );
}
catch(Arc90_Service_Twitter_Exception $e)
{
	// Print the exception message (invalid parameter, etc)
	print $e->getMessage();
}
?>

For all additional examples I'll only be displaying exactly what's necessary; take that into account.

End Session

Ends the session of the authenticating user, returning a null cookie. Use this method to sign users out of client-facing applications like widgets.

1
2
3
<?php
$response = $twitter->endSession();
?>

Get Public Timeline

Returns the 20 most recent statuses from non-protected users who have set a custom user icon. This method can return JSON, XML, ATOM and RSS.

1
2
3
4
5
<?php
$response = $twitter->getPublicTimeline('json');
$return = $response->getData();
print_r( json_decode($return) );
?>

Get Friends Timeline

Returns the 20 most recent statuses posted by the authenticating user and that user's friends. This method can return JSON, XML, ATOM and RSS.

If the optional $params are passed you can pare down the results.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$params = array();
$params = mktime(date("H")-4, date("i"), date("s")); //unix timestamp
$params = 'POST_ID_TO_USE_SINCE'; //id of post
$params = '10'; //must be < 200
$params = '1';
$response = $twitter->getFriendsTimeline('json',$params);
 
// Print the XML response
$return = $response->getData();
 
print_r( json_decode($return) );
?>

Get User Timeline

Returns the most recent statuses posted from the authenticating user based on the set options. This method can return JSON, XML, ATOM and RSS.

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$params = array();
$params = mktime(date("H")-4, date("i"), date("s")); //unix timestamp
$params = 'ID_OF_USER_TO_CHECK'; //id of user to look up
$params = '902529454'; //id of post
$params = '10'; //must be < 200
$params = '1';
$response = $twitter->getUserTimeline('json',$params);
 
// Print the XML response
$return = $response->getData();
?>

Show Status

Returns the status for a single user based on the provided id. This method can return XML and JSON.

1
2
3
4
5
<?php
$response = $twitter->showStatus('ID_OF_USER_TO_CHECK','json');
$return = $response->getData();
print_r( json_decode($return) );
?>

Update Status

Updates the authenticating user's status and returns the posted status in the requested format when successful.

1
2
3
4
5
6
<?php
$status = 'My Script Sent This Status';
$response = $twitter->updateStatus($status, $in_reply_to_status_id = 0, $format = 'json');
$return = $response->getData();
print_r( json_decode($return) );
?>

Get Replies

Returns the 20 most recent @replies (status updates prefixed with @username) for the authenticating user. Returns JSON, XML, ATOM and RSS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$params = array();
/*
$params = '0';
$params = mktime(date("H")-4, date("i"), date("s")); //unix timestamp 4 hours ago;
$params = '0';
*/
$response = $twitter->getReplies('json', $params);
 
// Print the XML response
$return = $response->getData();
 
print_r( json_decode($return) );
 
?>

Destroy Status

Destroys the status specified by the required ID parameter. The authenticating user must be the author of the specified status.

1
2
3
4
5
6
<?php
$id = 'ID_OF_STATUS_TO_DESTROY';
$response = $twitter->destroyStatus($id, 'json');
$return = $response->getData();
print_r( json_decode($return) );
?>

Get Friends

Returns the 20 most recent statuses from non-protected users who have set a custom user icon. This method can return ATOM and RSS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$params = array();
/*
$params = 'ID_OF_USER_TO_GET_FRIENDS_FOR';
$params = '0';
$params = mktime(date("H")-4, date("i"), date("s")); //unix timestamp;
$params = TRUE; //removes status
*/
$response = $twitter->getFriends('json', $params);
 
// Print the XML response
$return = $response->getData();
print_r( json_decode($return) );
?>

Get Followers

Returns the authenticating user's followers, each with current status inline. They are ordered by the order in which they joined Twitter (this is going to be changed). This method can return ATOM and RSS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$params = array();
/*
$params = 'ID_OF_USER_TO_GET_FRIENDS_FOR';
$params = '0';
$params = TRUE; //removes status
*/
$response = $twitter->getFollowers('json', $params);
 
// Print the XML response
$return = $response->getData();
 
print_r( json_decode($return) );
 
?>

Show User

According to the source code on this method:

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
/**
 * Returns extended information for a given user, specified by ID, screen name, or email.
 *
 * This information includes design settings, so third party developers can theme their widgets
 * according to a given user's preferences.
 *
 * You must be properly authenticated to request the page of a protected user.
 *
 * The API allows a user to be identified by ID, screen name, or email.
 * Any of these fields may be provided using the $id parameter.
 *
 * A user ID must be passed as an integer.
 * A screen name or an email address must be passed as a string.
 *
 * Show data for a user with an ID of 123: showUser(123)
 * Show data for a user with a screen name of 123: showUser("123")
 */

Can return in XML or JSON.

1
2
3
4
5
6
7
8
9
<?php
$id = 'SCREEN_NAME_ID_OR_EMAIL_OF_USER_TO_CHECK';
$response = $twitter->showUser($id, 'json');
 
// Print the XML response
$return = $response->getData();
 
print_r( json_decode($return) );
?>

Be sure to check out Part 2 of the series for details on the remaining methods and functionality.

How to Own a Mistake

Posted in Rant on April 24th, 2009 by Eric Lamb – 0 Comments

I wasn't going to post anything today, I've been pretty busy and am getting out of the habit of posting on Fridays, but this just has to be noted.

Today, I received an email from Emma Email Marketing about a special offer where they will plant 10 trees in my honor if I sign up with them.

In an annoying twist the email was sent with the personalization set to the wrong name. Check out the below screenshot. Oops...

Wrong Name...

They probably flipped their shit when it was discovered but they handled it in a really classy way. They owned up to it. Imagine that; actually admitting your mistake.

They promptly sent a followup email apologizing for the error and making me aware that they were aware.

Owning the Issue

Too many times I've seen companies just brush this sort of thing under the rug, just hoping no one calls them on it. It's nice to see that Emma, at least, has the integrity to call themselves out and deal with the issue immediately.

Now, it should probably be mentioned that I don't do business of any kind with Emma. I've only done research into their company and didn't really find them to be the perfect fit for my needs at the time. Now that I see their integrity though, I'm going to take a second look.

What does 99.99% mean?

Posted in Brain Dump, IT, Programming on April 22nd, 2009 by Eric Lamb – 1 Comments

Earlier this month my department was, finally, able to get approval for an upgraded Internet line for the office. Previously we were using a business level DSL line that just SUCKED. Whenever someone was uploading anything the download and upload would just grind to a halt and we'd have to find out who was doing what. This happened everyday and it was just painful.

New Internet Line

If you've never had the pleasure of using business level DSL in an Internet company count yourself lucky.

Anyway, after literally a whole year of research and proposals and meetings and compromises and revisions we finally got the new line approved.

Halle-Fucking-lujah!!

Of course there's the increased speeds for both up and download, which really can't be understated in it's coolness, but there's also a Service Level Agreement (SLA) which guarantees us an uptime of 99.99%. Having just come from the world of DSL, where the word "reliability" isn't a part of the vernacular, this was a requirement.

Of course this begged the question of just how much downtime is allowed with a 99.99% SLA. Not really wanting to do the math myself I turned to Google and came across a post on John D. Mitchell's Blog with the fortuitous title "What does 99.999% reliability really mean?".

John went to all the trouble of writing a script in Java that quickly outputs the correct time based on the amount of 9s. Since I don't work in Java I thought I'd take a shot at porting his script to php (what else?).

Here's my take on it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
$sp = array();
$sp = 60;
$sp = $sp*60;
$sp = $sp*24;
$sp = $sp*365;
 
function determine_nines($num_nines, $seconds){
	global $sp;
 
	$seconds = (double)$seconds;
	$str =  $num_nines." 9's (";
	for ($i = 0; $i < $num_nines; $i++) {
		if (2 == $i) {
			$str .= '.';
		}
		$str .= '9';
	}
 
	$str .= '%) = up to ';
	$str .= ($seconds / $sp).'h / ';
	$str .= ($seconds / $sp).'m / ';
	$str .= $seconds.' seconds of downtime per year.';
	$str .= '';
	return $str;
}
 
echo "Nines of Reliability: (Hours / Minutes / Seconds)";
$base = 100.0;
for($i=2;$i<=7;$i++){
	if($i != 2){
		$base = $base*10;
	}
	echo determine_nines ($i, $sp / $base);
}
?>

So using my SLA of 99.99% I get a maximum downtime of 0.876 hours or 52.56 minutes of downtime per year.

Cool.

For comparison here's the complete output of the above script (it matches exactly what John had; so that's nice).


Nines of Reliability: (Hours / Minutes / Seconds)
2 9's (99%) = up to 87.6h / 5256m / 315360 seconds of downtime per year.
3 9's (99.9%) = up to 8.76h / 525.6m / 31536 seconds of downtime per year.
4 9's (99.99%) = up to 0.876h / 52.56m / 3153.6 seconds of downtime per year.
5 9's (99.999%) = up to 0.0876h / 5.256m / 315.36 seconds of downtime per year.
6 9's (99.9999%) = up to 0.00876h / 0.5256m / 31.536 seconds of downtime per year.
7 9's (99.99999%) = up to 0.000876h / 0.05256m / 3.1536 seconds of downtime per year.

Fix for Vista Folder View Fail

Posted in Brain Dump on April 21st, 2009 by Eric Lamb – 0 Comments

In Windows Vista, when you're looking at files in a folder, sometimes the layout (the tabs and fields and such) are just plain wrong for the type of folder you're viewing. This bugs the crap out of me so I'm posting it so I won't forget.

You're viewing a folder on your Vista computer when the folder view switches to a different view type. For example; viewing a folder with text files in it will use the Music folder type:

Music Folder View

This can be fixed by backing out of the directory you're looking at and right clicking on it's folder and going to properties.

Click on the "Customize" tab and change the folder type template to the proper one:

Folder Properties

You can choose between Music Details, Music Icons, Documents, Pictures and Videos and All Items.

Easy; if only it wouldn't change randomly now...

Developing Web Sites for Blackberry

Posted in Code, Programming on April 20th, 2009 by Eric Lamb – 6 Comments

The other day I read an article on Sitepoint called iPhone Development: 12 Tips To Get You Started that I thought was going to go into the details of iPhone App development. Instead it's an article about how to make your website render properly on an iPhone. Not what I was expecting but since I am a web developer it was still worth while.

Blackberry Browser

I don't have an iPhone so I couldn't get too excited about the content though. After reading the article I started thinking about how to get web sites to render nicely on the Blackberry.

RIM (the makers of the Blackberry) provides some extensive documentation on how best to develop web sites for the Blackberry. The topics include:

  1. BlackBerry Browser - Fundamentals Guide
  2. CSS for the BlackBerry Browser - Reference Guide
  3. HTML for the BlackBerry Browser - Reference Guide
  4. BlackBerry Browser - JavaScript Reference

One of the easiest thing you can do to play nice with the Blackberry browser is to use the Viewport and / or HandheldFriendly meta values.

The HandheldFriendly meta value tells the Blackberry browser the website is exactly what the name implies: handheld friendly. This allows the browser to make some assumptions about layout and structure.

<meta name="HandheldFriendly" content="True" />

The viewport meta value works similarly to the HandheldFriendly meta value but provides for some basic customization of the default view settings.

<meta name="viewport" content="initial-scale=1.0" />
<meta name="viewport" content="user-scalable=false" />

It's important to recognize the screen resolution of the Blackberry model you're aiming for. Like regular web development hand held devices operate at different screen resolutions and with different color counts. For example the Blackberry Bold has a resolution screen size of 480 x 320 with 65,000 colors. Take heed on this if you want your sites to look good.

For the ecommerce sites out there, especially Blackberry application / theme / game sites, there's documentation on how to integrate Blackberry Wallet into your website payment processing routine. I wasn't too familiar with this but according to RIM:

The BlackBerry® Wallet is a BlackBerry device application that is designed to securely store information such as a BlackBerry device user's name, shipping and billing addresses, credit card information, and login credentials for web sites and other BlackBerry device applications. After a user saves information in the BlackBerry Wallet, the BlackBerry Wallet can populate web forms and fields in applications to reduce the effort required by the user to complete data entry tasks.

So it essentially allows Blackberry users to shop online with their Blackberry but saves them the pain of entering credit card information over and over again. Nice idea.

Unfortunately, to utilize the Blackberry Wallet takes a lot of work; you have to edit all your forms to allow Blackberry Wallet to manipulate them. Kind of a crappy integration strategy...

So far that's all I've been able to discover but I'm sure I'll post more soon.

How to Exploit an Online Poll

Posted in Brain Dump, Programming on April 15th, 2009 by Eric Lamb – 0 Comments

UPDATE April 20th 2009: Once again Jeff Atwood has read my mind and posted his own version of how to conduct an online poll. As usual he provides an interesting take on the subject, and it's definitely worth a read.

Not that many people talk about it but there's a dark side to freelancing. It's amazing how many people out there are looking for a hired gun to do something illicit to somebody else. I've been asked to do everything from installing cracked software to hacking websites and everything in between.

Stupid Cheater

I'm sure the proper thing to do when approached for this type of work would be to politely decline, but freelancing can get a little boring, so I've always heard the client out in the hope of finding something interesting.

One such request that I'm guilty of was to exploit an online poll.

(Cymbal Crash!!!)

Basically, the client company was up for some award, where voting was done online, and I was tasked with making sure they won. I made sure they did, and in the process I learned a few thing about how NOT to create an online poll.

First, a disclaimer. blah, blah, blah. don't sue me. blah, blah, blah. Use at your own risk. blah, blah, blah.

Anyway, to do any sort of an exploit the first thing you need to do is recon. You need to find out as much about the target as possible. In this case we're talking about a poll on a website so this usually entails visiting the site and absorbing everything.

You want to read the terms of service and any sort of rules for the poll to find out what's allowed and what isn't. Not so you can follow the rules but because knowing what the site allows will tell you what they're protecting against. For example, if the terms of service says something like "one entry per IP" you know they're tracking IP addresses of registrants.

It's also important to take a look at the actual HTML code of the form so you know how it's built. Nine times out of ten the poll's going to be a radio group. You also want to grab the form action URL as well as any hidden form values.

You're going to need to know the HTML of the target site like you wrote it.

There's also the need to cover your tracks. Most, if not all, online polls will record as much information about each transaction as they can. It's actually easier to record everything, like IP address, referer and the date than it is not to.

What I did, which may not be the best idea I admit, was to create a text file of proxies in order to mask the IP address of the server the script was on. I then set the script to choose a random proxie on every "submit" with a different, random, referrer after waiting a random amount of time between transaction with sending a random user agent.

All this in the hopes of throwing off a manual inspection of the database. A little extreme but if anyone actually looks at the data they shouldn't see too obvious of a pattern.

Below is an example script that should help highlight the above.

<?php
//the amount of votes to cast in this batch
$amount_of_votes_to_cast = 10000;
 
//the minimum amount of time, in seconds, to wait in between runs.
$wait_time = 60; 
 
//URL to visit (don't forget the "http://"!)
$submit_url = "http://CHANGE_ME"; 
 
//name and value of the form field
$submit_vars = "1";
 
$proxy_file = '/path/to/proxy/file';
$agent_file = '/path/to/agent/file';
 
$proxy_hosts = file($proxy_file);
$agents = file($agent_file);
 
include "snoopy/Snoopy.class.php";
$snoopy = new Snoopy;
 
for($i=0;$i<=$amount_of_votes_to_cast;$i++){
 
	$snoopy->agent = $agents;
	$snoopy->referer = $referrers;
	$snoopy->proxy_host = $proxy_hosts;
	$snoopy->rawheaders = "no-cache";
 
	if($snoopy->submit($submit_url,$submit_vars))
	{
		while(list($key,$val) = each($snoopy->headers)) {
			echo $key.": ".$val."<br>\n";
		}
		echo htmlspecialchars($snoopy->results);
	} else {
		echo "error fetching document: ".$snoopy->error."\n";
		sleep($wait_time);
	}
	sleep(rand(0,$wait_time);
}
?>

So, it's pretty easy to do something like this but it kind of begs the question: what do you do if you're building a poll? How should you protect yourself?

Unfortunately, it's all in the data. It's important to actually look at your data and verify the integrity.

Look for patterns.

Take solace in the knowledge that if a programmer did exploit your script it's a safe bet to say he's pretty lazy (we all, pretty much, are). If it looks like your poll was only taken primarily by Linux users on a Sunday during the hours of 10AM to 2AM on Monday with all submissions posted within a minute or less of each other, you might want to flag those votes.

Basically, there's a finite amount of proxy servers, user agents and referrers your average programmer will be able to compile. In my example, I only used 150 proxie servers with 20 user agents; even a basic look at the data would have revealed some anomalies. It was pretty half-assed on my part.

But the target in the above story didn't bother doing any diligence and I was rewarded with a nice paycheck and box full of clothes from the client for just a couple hours of work.

Suckers.

Scrub Your Bulkmail List NOW!

Posted in Brain Dump, IT on April 13th, 2009 by Eric Lamb – 11 Comments

In How to Not Suck at Email Campaigns I completely left out a HUGE part of not sucking; scrubbing your email list.

Sanitize email list

Scrubbing an email list before sending it out is something that rarely gets done but is actually pretty crucial.

See, email providers, the organizations that provide email like yahoo, gmail and hotmail, and some spam filters, actually look at the email addresses you send to and flag those they deem to be either role accounts or spam traps and they use that to determine part of your spam score. If your spam score is too high; you're a spammer.

This assumes you have an honest list to begin with. If you're buying lists of email addresses from people and sending emails to them you're a spammer and nothing here is going to help you. Oh yeah, everyone else knows you're a spammer too.

Fuck you.

Anyway, I first learned of the importance of scrubbing a list while preparing one of my clients email databases for a blast (they hired StreetWise to send email on their behalf). During the import process into the mailing solution we were using our account was put in lock down which essentially stopped the entire project dead in it's tracks. After contacting the mailing solution I got the below response:

I do want to be clear that the list both contains spamtraps, role accounts (such as admin@) and other addresses with aspects that indicate that some part of the list may not be completely opt-in. Spamtrap addresses are those addresses that have generally been retired or are known by the domains postmaster to be inactive and as a result unlikely to be signing up for new mailing lists. These addresses may also be ones planted on a website specifically for email harvesting purposes. Sending to them indicates a lack of an opt-in process, the ideal option being a double opt-in confirmation method where members must both submit their email address and respond to a follow-up email before receiving regular mailings from the list.

Mail sent to spam traps, as with non opt-in mail in general, may result in a loss of deliverability for a sender. This may include domain blocks (refusal of the senders mail by a domain) or blacklisting by spam prevention agenies and further hurts the reputation of the sender.

Combined with negative feedback from the recipients (sent either to the sender, its ESP, or the users postmaster), not honoring opt-out requests, sending to a large amount of non-existent members, spamtrap addresses call into question the entire lists credibility.

So just what do you need to scrub for? Well, duplicates, MX records for the domain and syntax issues obviously but, more importantly, specific keywords in emails.

To start you want to get rid of any email address containing the keywords below (* is wildcard):

junk*
admin@*
root@*
postmaster@*
blackhole*
confirm@*
fuck*
donotreply*
help@*
nobody@*
*@poop.com
support@*
sysadmin@*
*spam*
dev@*
devnull@*

That's not a complete list of course; just the ones I've personally discovered to date. I plan on compiling a database of them once I get more and so should anyone who's serious about not sucking at bulk email blasts.

There's also spam trap email addresses. These are email addresses people sign up for that allow them to sign up for accounts and other services without actually giving their real email address.

They are insanely popular (and pretty annoying too).

So far I've only had to deal with a few though. You want to remove any email address from the below domain:

*@spamgourmet.com
*@sneakemail.com
*@mailinator.com
*@trashymail.com
*@mailexpire.com
*@temporaryinbox.com
*@spambox.us
*@spamhole.com
*@pookmail.com
*@spamfree24.*
*@kasmail.com

This is especially important on lists you're sending on behalf of your clients. I have yet to have a client freely admit to having email addresses that haven't been opted into properly; they always swear that their list is clean. I've seen HUGE corporations, we're talking hundreds of millions of dollar companies, hand over lists that decreased over 20% once it's scrubbed.

Cool thing is, though, that the client usually has no idea. Usually, someone told them they have a list of email addresses somewhere and, odd as this may sound, they're actually thrilled to be told their list isn't "good". Makes you look like you know your shit smile

Looking Back on 6 Months of Blogging

Posted in Brain Dump on April 08th, 2009 by Eric Lamb – 14 Comments

My first post was on October 21st 2008 and after 6 months my blog is still not getting much traffic. On average I get about 50 hits a day, mostly to the wp-click-track page and not the actual blog, and as of the time I posted this I only have 6 Feedburner subscriptions (and I'm pretty sure I work with all 6 people).

Blogging for 6 Months

Doing a quick inventory of my blog leads to the below stats:

  1. 80 posts published
  2. 20 drafts (I work on a few posts at a time)
  3. A crap load (that's the technical term; crap load) of code released.

It was my initial goal to use my blog as a repository of all the cool stuff I do on a day to day basis and on that front the blog has been a success. I have a nice database of cool php and IT related posts; everything from working with social networking sites to manipulating zip files with php to how to not suck at email marketing.

It's pretty apparent, that at this moment in my blogs life, NO ONE CARES.

Check this out:

Boobs.

Nothing. No outcry. The world is still here.

Nice.

Apparently this isn't out of the ordinary though. According to Jeff Atwood it's important to be patient:

The blog is no different. I often give aspiring bloggers this key piece of advice: if you're starting a blog, don't expect anyone to read it for six months. If you do, I can guarantee you will be sorely disappointed. However, if you can stick to a posting schedule and produce one or two quality posts every week for an entire calendar year... then, and only then, can you expect to see a trickle of readership. I started this blog in 2004, and it took a solid three years of writing 3 to 5 times per week before it achieved anything resembling popularity within the software development community.

So it looks like I shouldn't really care about people reading my blog until October 2010 and it may take as long as 2012 until my blog reall starts to matter. Bummer...

That doesn't mean I should just sit back and wait; that's never a good idea. To help the process along, I started looking at submitting my blog to a few of the blog aggregators. Supposedly, Wordpress already does this for a bunch of blog aggregators but the only incoming links I have are to wp-click-track. I wasn't so sure a ping was all that's required.

I registered my blog with syndic8, Technorati, Yahoo, LinkedIn, WeBlogAlot, Blogged to name a few. Some of the sites required that I prove ownership of my blog by either including a graphic, adding a new meta tag or creating a temporary file on your blog.

Really, a HUGE pain in the ass that didn't do a thing for me. Let me be clear: There's been ZERO impact from having my blog on those sites. Maybe, maybe, I get a couple hits a day from all the sites combined, but that's it.

Lesson: if you're just a random guy starting a blog don't worry about submitting to those sites.

I also released quite a bit of code. This has been where the majority of my traffic comes from. So far, I've released only 2 "official" projects (both WordPress plugins). Considering it's only been half a year and they've both been downloaded, collectively, over 1,000 times I'd say it's been a bit of a success.

What's the next 6 months going to be like? Can't wait to find out.

Manipulate Zip Files with PHP

Posted in Code, Programming on April 06th, 2009 by Eric Lamb – 0 Comments

Back in the olden days the easiest way to create zip files using php was to have the operating system (OS) do it. Sure, there were modules you could compile php with but really affected portability. So using the OS wasn't too big of an issue but it still wasn't optimal.

Zip Files

The Old Way

Assuming the OS was Linux, and if you were doing php web development it probably was, you'd execute a call like the below to create a gzipped archive:

<?php
exec(tar cfvz ".$WhereBackup."/".$Name.".tar.gz ".$whatBackup.");
?>

The above sucks for a couple reasons. For one, it requires a pretty large security hole to not be plugged; exec allows piping commands to the OS directly. For another, the above method will only work on Linux; Windows doesn't have a "tar" command.

The biggest reason the above sucked, for me at least, was that the layman doesn't understand the tar.gz file extension. I can't count the number of times I've had to explain to a client or colleague that tar.gz is, as far as their needs go, that tar.gz is ok. "You can open it in WinZip or WinRar.", I'd say. Sigh...

Enter PclZip

PclZip is a php class that creates and manage ZIP formatted archives. PclZip works on both Windows and Linux and is pretty easy to use. There's a pretty extensive user manual too.

I first heard about it while writing the WordPress plugin iTunes-Data. I wanted to allow the upload of the iTunes XML files but mine was over 10MB so testing was becoming... inconvenient. I knew WordPress could manipulate zip archives so I took a look under the hood and the was PclZip.

Anyway, you can create zip files, remove files from existing zip files and extract zip files using the PclZip class. Below are a couple examples of how to do each.

The Basics

The most important thing to know about using PclZip is that the PclZip object must be instantiated with a ".zip" file being passed. It doesn't matter if you're creating, extracting or modifying, you have to pass the file you want to manipulate before you do anything else.

<?php
require_once('pclzip.lib.php');
$archive = new PclZip('tmp/archive.zip');
?>

Optional Arguments

PclZip allows for detailed control over archives through the use of optional arguments that get passed at the tail end of functions. According to the official site:

The optional arguments are identified by a name, which is in reality a static integer value. The value of the argument can be a single value or a list of values. In some cases they does not take a value, their name is enought to indicate a specific action to the method.

There's far too many arguments you can use so I won't bother listing them all here but there's a complete list at the end of the article.

Create a Zip File

To create a zip file you have to pass the name of the archive you want to create to the object. The file passed will be where to the archive will be created.

You can include multiple files by either passing the directory, if you want the entire directory or by using a couple different methods to pass individual files and directories; arrays or a csv string.

<?php
require_once('pclzip.lib.php');
$archive = new PclZip('tmp/archive.zip');
 
//includes the file "debug.cl" and the directory "logs"
$files = './debug.cl,./logs/';
if ($archive->create($files) == 0) {
	die('Error : '.$archive->errorInfo(true));
}
?>

or

<?php
require_once('pclzip.lib.php');
$archive = new PclZip('tmp/archive.zip');
 
//same as above
$files = array('./debug.cl','./logs/');
if ($archive->create($files) == 0) {
	die('Error : '.$archive->errorInfo(true));
}
?>

Extracting Files from Archive

There are quite a few options for extracting files from a zip archive. PclZip contains a pretty extensive filtering mechanism that allows for some pretty selective extractions.

By default when extracting the files from an archive PclZip puts the files relative to where the script is executed.

$archive = new PclZip('tmp/archive.zip');
if ($archive->extract() == 0) {
	die("Error : ".$archive->errorInfo(true));
}

You can explicitly state where the archive files are extracted by setting a value to the "PCLZIP_OPT_PATH" parameter. The below extracts all the files to the "./tmp" directory:

$archive = new PclZip('tmp/archive.zip');
if ($archive->extract(PCLZIP_OPT_PATH, "./tmp") == 0) {
	die("Error : ".$archive->errorInfo(true));
}

Optional Argument List

PCLZIP_OPT_PATH

PCLZIP_OPT_ADD_PATH

PCLZIP_OPT_REMOVE_PATH

PCLZIP_OPT_REMOVE_ALL_PATH

PCLZIP_OPT_SET_CHMOD

PCLZIP_OPT_BY_NAME

PCLZIP_OPT_BY_EREG

PCLZIP_OPT_BY_PREG

PCLZIP_OPT_BY_INDEX

PCLZIP_OPT_EXTRACT_AS_STRING

PCLZIP_OPT_EXTRACT_IN_OUTPUT

PCLZIP_OPT_NO_COMPRESSION

PCLZIP_OPT_COMMENT

PCLZIP_OPT_ADD_COMMENT

PCLZIP_OPT_PREPEND_COMMENT

PCLZIP_OPT_REPLACE_NEWER

PCLZIP_OPT_EXTRACT_DIR_RESTRICTION

PCLZIP_OPT_ADD_TEMP_FILE_ON

PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD

PCLZIP_OPT_ADD_TEMP_FILE_OFF

« Older Entries
  • Subscribe: Entries | Comments
  • About Me

    Email Email
    Twitter Twitter
    310.739.3322
  • Categories

    • Brain Dump
    • Business
    • Code
    • IT
    • Programming
    • Rant
    • Servers
  • Archives

    • February 2012
    • October 2011
    • August 2011
    • July 2011
    • June 2011
    • May 2011
    • April 2011
    • March 2011
    • February 2011
    • January 2011
    • December 2010
    • November 2010
    • October 2010
    • September 2010
    • August 2010
    • July 2010
    • June 2010
    • May 2010
    • April 2010
    • March 2010
    • February 2010
    • January 2010
    • December 2009
    • November 2009
    • October 2009
    • September 2009
    • August 2009
    • July 2009
    • June 2009
    • May 2009
    • April 2009
    • March 2009
    • February 2009
    • January 2009
    • December 2008
    • November 2008
    • October 2008
  • Advertisement

Copyright © 2008 - 2013 Eric Lamb - All rights reserved