<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Colin McCann Dot Com</title>
	<atom:link href="http://colinmccann.com/feed" rel="self" type="application/rss+xml" />
	<link>http://colinmccann.com</link>
	<description>Optimized for 320x200, 8-bit color</description>
	<lastBuildDate>Thu, 17 Jun 2010 08:36:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Automated off-site MySQL backups with cron and PHP</title>
		<link>http://colinmccann.com/code/automated-off-site-mysql-backups-with-cron-and-php</link>
		<comments>http://colinmccann.com/code/automated-off-site-mysql-backups-with-cron-and-php#comments</comments>
		<pubDate>Sun, 07 Feb 2010 09:20:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://colinmccann.com/?p=19</guid>
		<description><![CDATA[I am the technical administrator for a decently sized vBulletin forum that is hosted on a system offering a lot of performance at the cost of some storage space. I also have hosting and a number of domains on a system that offers less performance, but ridiculous amounts of bandwidth and storage. Lastly, I have [...]]]></description>
			<content:encoded><![CDATA[<p>I am the technical administrator for <a href="http://www.talkglass.com" title="The GLDG / Melting Pot">a decently sized vBulletin forum</a> that is hosted on a system offering <a href="http://modwest.com" title="Modwest: Professional PHP Hosting">a lot of performance</a> at the cost of some storage space. I also have hosting and a number of domains on a system that offers less performance, but <a href="http://www.dreamhost.com" title="Dreamhost! They're good with computers">ridiculous amounts of bandwidth and storage</a>. Lastly, I have a strong need for peace of mind, and off-site database backups seem like a nice way of getting a bit of that back.<span id="more-19"></span></p>
<p>The following script is run by this cron job:</p>
<pre class="jush-php">
# runs at 3:30am every day
30 3 * * * /backup/backup_db.sh
</pre>
<p>This script only does a few things. First, it creates a &#8216;filename&#8217; variable consisting of &#8216;database_&#8217; and then the date. Next it runs mysqldump on the database in question, outputting to /backup/$filename.sql. It sleeps for a bit (gzip didn&#8217;t seem to want to work immediately) and then compresses the .sql file into a more manageable size. From there, it opens a connection to an off-site server where I&#8217;ve got a ton of storage and bandwidth, and uses a server-to-server connection to transfer this gigantic file in a few minutes. Once that&#8217;s complete, it removes the file it created and waits until 3:30 the next morning to do it all over again.</p>
<pre class="jush-php">
#!/bin/sh
# Remember to chmod this file to 755 so it can be executed
filename="backup_"`eval date +%Y-%m-%d`
echo "Beginning MySQL dump."
mysqldump databasename --host=db.yourdomain.com --user=username --pass=password > /backup/$filename.sql
echo "MySQL dump complete. Beginning file compression."
sleep 3
gzip /backup/$filename.sql
echo "Compression complete. Beginning SCP transfer."
scp /backup/$filename.sql.gz username@offsitestorage.com:/home/username/backup
sleep 3
echo "File transfer complete. Cleaning up and exiting..."
rm /backup/$filename.sql.gz
</pre>
<p>To get the scp command to work without user input, you have to add the RSA key fingerprint to the list of known hosts. You can do this manually by editing the appropriate file, or you can do it the easy way: Open a terminal and SSH into your web server, and from that session, SSH into your backup server. You will get a warning claiming that &#8220;the authenticity of host &#8230; can&#8217;t be established &#8212; are you sure you want to continue connecting?&#8221;. Type &#8220;yes&#8221; and hit enter, and you will see a warning stating that this RSA key was added to the list of known hosts.</p>
<p>When your database backup is a 450MB file, you&#8217;ll find that space starts filling up quickly and the directory starts becoming needlessly cluttered. So again, we turn to crontab:</p>
<pre class="jush-php">
# database cleanup script; runs at 4am (the backup process only takes a few minutes)
0 4 * * * /home/username/db_backup/clean.php
</pre>
<p>&#8230;which dutifully executes the following cleanup script. This scans a directory for all files but itself, checks their &#8216;last-modified&#8217; date against the current date and if it&#8217;s more than 7 days old, deletes them. This ensures that I&#8217;ve always got the most recent week&#8217;s worth of backups.</p>
<pre class="jush-php">
// /home/username/db_backup/clean.php
// If there are any files older than one week in this directory, nuke 'em
$dir = $_SERVER['DOCUMENT_ROOT'].'db_backup/';

/// Don't scan for yourself <img src='http://colinmccann.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />
$script_name = pathinfo($_SERVER['SCRIPT_NAME']);
$script_name = $script_name['basename'];
$script_name = substr($script_name, 0, strrpos($script_name, '.'));

// Get your numbers straight
$time = mktime();
$one_week = 60 * 60 * 24 * 7;

// See how many backups already exist in this directory
$count = count(glob($dir."*.sql.gz"));

// Don't see them all? We should probably send an email...
if ($count < 7) {
	$to = 'my-email@my-domain.com';
	$subject = 'ERROR: SITE BACKUP FAILED!';
	$message = 'Deleted files have been detected. Check to assure script is running properly.';
	mail($to, $subject, $message);
	die();
// There's enough files? Trim them.
} else {
	if (is_dir($dir)) {
		if ($dh = opendir($dir)) {
			while (($file = readdir($dh)) !== false) {
				if ((substr($file, 0, 1) != '.') &#038;&#038; (substr($file, 0, (strlen($script_name))) != $script_name) &#038;&#038; (filetype($dir.$file) != 'dir')) {
					$filetime = filemtime($dir.$file);
					if (($time-$filetime) > $one_week) {
						unlink($dir.$file);
					}
				}
			}
			closedir($dh);
		}
	}
}
</pre>
<p>So, that&#8217;s it. Automated off-site MySQL backups using cron and PHP. Enjoy the peace of mind.</p>
]]></content:encoded>
			<wfw:commentRss>http://colinmccann.com/code/automated-off-site-mysql-backups-with-cron-and-php/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Javascript/PHP Linkerizer (link creator)</title>
		<link>http://colinmccann.com/utility/linkerizer</link>
		<comments>http://colinmccann.com/utility/linkerizer#comments</comments>
		<pubDate>Tue, 19 May 2009 18:22:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Utility]]></category>

		<guid isPermaLink="false">http://colinmccann.com/?p=137</guid>
		<description><![CDATA[Why would you need a linkerizer? Well, some stuff is hard to directly download. This makes it easy. You can also send requests to this page via either POST or GET. Go ahead and give it a try. Click the button to generate a link Also, if you&#8217;re using Firefox, you can make using this [...]]]></description>
			<content:encoded><![CDATA[<p>Why would you need a linkerizer? Well, some stuff is hard to directly download. This makes it easy.  You can also send requests to this page via either POST or GET. Go ahead and <a href="/utility/linkerizer?url=www.google.com/intl/en_ALL/images/logo.gif">give it a try</a>.</p>
<div class="linkerize_box">
<form onsubmit="return false;" method="get" action="/utility/linkerize">
<input type="submit" id="link_submit" class="submitbutton" value="Linkerize" onclick="linkerize();" /></p>
<input type="text" id="link_input" onkeyup="linkerize();" name="url" value="http://example.com/hard-to-download.wmv" />
</form>
<div id="link_output">
Click the button to generate a link
</div>
</div>
<p>Also, if you&#8217;re using <a href="/utility/firefox-quick-pack">Firefox</a>, you can make using this little script even easier. Right-click in the text-entry field and select the option &#8220;Add a <u>K</u>eyword for this Search&#8221; &#8212; The Name can be whatever you like, and I&#8217;ve found &#8220;link&#8221; to be a good value for the Keyword. Hit &#8220;Add&#8221; and you can use it right from your address bar. Prepending any location on the web with the word &#8220;link&#8221; will route that location to this script.</p>
<p>For example: &#8220;link http://www.google.com/intl/en_ALL/images/logo.gif&#8221; will take you to:</p>
<p>http://colinmccann.com/utility/linkerizer?url=http://www.google.com/intl/en_ALL/images/logo.gif</p>
<p>Enjoy. If you&#8217;ve got any suggestions as to how this could be improved, feel free to say so in the comments.</p>
<p><script type="text/javascript">
function linkerize() {
var href = document.getElementById('link_input').value.replace('\\','');
var linkbox = document.getElementById('link_output');
if (href.substr(0, 7) != 'http://') { href = 'http://'+href; }
var a = document.createElement('a');
a.setAttribute('href', href);
a.innerHTML = href;
linkbox.innerHTML = '';
linkbox.appendChild(a);
}
</script></p>
]]></content:encoded>
			<wfw:commentRss>http://colinmccann.com/utility/linkerizer/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automated Email-to-SMS gateway PHP script</title>
		<link>http://colinmccann.com/code/automated-email-to-sms-gateway-php-script</link>
		<comments>http://colinmccann.com/code/automated-email-to-sms-gateway-php-script#comments</comments>
		<pubDate>Thu, 07 May 2009 17:06:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://colinmccann.com/?p=24</guid>
		<description><![CDATA[I&#8217;ll cut right to the awesome. This script runs every minute, checks an IMAP mailbox (that happens to be my work email), and detects if any new messages have been received. If so, all HTML and special characters are stripped (leaving plain ASCII text) from the message body, and truncated to 150 characters. Next, the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll cut right to the awesome. This script runs every minute, checks an IMAP mailbox (that happens to be my work email), and detects if any new messages have been received. If so, all HTML and special characters are stripped (leaving plain ASCII text) from the message body, and truncated to 150 characters. Next, the script sends me a text message through Verizon&#8217;s email gateway &#8220;from&#8221; the original sender&#8217;s email address.<span id="more-24"></span></p>
<p>This is cool for a number of reasons. One, I don&#8217;t have to run an IMAP application on my phone; updates are pushed to me from an external source. Two, I don&#8217;t need a data plan to use it (although I may need to increase the number of texts I can receive without additional charges). Three, I can reply directly from my phone (although the message is received from a different address, depending on your carrier). Four, it&#8217;s got an accuracy of around one minute, and so far that has been more than adequate.</p>
<p>You need to create a web-writable file (chmod 755) called timestamp.txt in the same directory. I&#8217;ll include the cron script at the end of this post.</p>
<pre class="jush-php">// filename: sms.php
$debug = false; // false = no output
$error = '';

// Define SMS parameters; your gateway may vary
$sms_to   = '4065551234@vtext.com';

// Define IMAP parameters
$imap_user = 'my.gmail.account';
$imap_pass = 'Secret-Password!';
$imap_host = '{imap.gmail.com:993/imap/ssl}INBOX';

// Define SMTP parameters
$smtp_host = 'smtp.mymailserver.com';
$smtp_port = '25';
$smtp_user = 'sms@mydomain.com'; // a valid user must exist
$smtp_pass = 'Another-Password!';

// Open a pointer to the mailbox
if ($debug) { $error = 'error: imap connection failed'; }
$imap = imap_open ($imap_host, $imap_user, $imap_pass) or die ($error);

// Quick exit
if (imap_num_msg ($imap) == 0) {
	imap_close ($imap);
	if ($debug) { $error = 'error: no messages in mailbox'; }
	die ($error);
}

// What was the last new message?
$old_timestamp = file_get_contents ('./timestamp.txt');

// Get last message
$msg_id = imap_num_msg ($imap);

// Gather IMAP message headers
$headers = imap_headerinfo ($imap, $msg_id);

// What's the timestamp on the most recent message?
$new_timestamp = $headers->udate;

// If it's the same message, get out of here.
if ($new_timestamp <= $old_timestamp) {
	imap_close ($imap);
	if ($debug) { $error = 'error: timestamp match'; }
	die ($error);
}

// Write timestamp of new message to external file
$handle = fopen ('timestamp.txt', 'w');
fwrite ($handle, $new_timestamp);
fclose ($handle);

// Let's look at that email we grabbed
$message = imap_get_message ($imap, $msg_id);

// Close IMAP Connection
imap_close ($imap);

// Okay, who's it from? Let's just do the email address...
// This needs cleaned up a bit; not all addresses include brackets.
$from = trim ($message['from']);
$b1 = strpos ($from, '<') + 1;
$b2 = strpos ($from, '>');
$from = substr ($from, $b1, ($b2 - $b1) );
// Here's an oddity -- gmail doesn't work. Go figure.
$from = str_replace ('gmail.com', 'g-mail.com', $from);

// And what's it say? Get rid of everything except alphanumerics and basic punctuation
$body = $message['body'];
$body = strip_tags ($body);
$body = preg_replace ('/[^A-Za-z0-9!-~]/', ' ', $body);
$body = preg_replace ('/\s\s+/', ' ', $body);

// Cut it off at 150 characters; seems to be the max for Verizon, anyway
$body = (strlen ($body) > 150) ? substr ($body, 0, 147).'...' : $body ;

// Set mail parameters; this sets the 'Return-Path' value
$param   = '-r '.$from;
$subject = '';
$headers = '';

// Send it off!
mail ($sms_to, $subject, $body, $headers, $param);

// IMAP message retrieval; returns a basic array
function imap_get_message ($imap_connection, $msg_no) {

	$header  = imap_header($imap_connection, $msg_no);
	$message = array();
	$message['subject'] = $header->subject;
	$message['from']    = $header->fromaddress;
	$message['to']      = $header->toaddress;
	$message['date']    = $header->date;

	$struct = imap_fetchstructure($imap_connection, $msg_no);
	@$parts = $struct->parts;
	$i = 0;

	if (!$parts) {
		$message['body'] = imap_body ($imap_connection, $msg_no);
	} else {
		$endwhile = false;

		$stack = array(); // Stack while parsing message
		$message['body'] = ''; // Content of message

		while (!$endwhile) {
			if (@!$parts[$i]) {
				if (count ($stack) > 0) {
					$parts = $stack[count ($stack) - 1]["p"];
					$i     = $stack[count ($stack) - 1]["i"] + 1;
					array_pop($stack);
				} else {
					$endwhile = true;
				}
			}

			if (!$endwhile) {
				// Create message part first (example '1.2.3')
				$partstring = '';
				foreach ($stack as $s) {
					$partstring .= ($s["i"]+1) . ".";
				}
				$partstring .= ($i+1);
				if (strtoupper ($parts[$i]->subtype) == "PLAIN") {
					$message['body'] .= imap_fetchbody ($imap_connection, $msg_no, $partstring); // Message
				}
			}

			if (@$parts[$i]->parts) {
				$stack[] = array("p" => $parts, "i" => $i);
				$parts = $parts[$i]->parts;
				$i = 0;
			} else {
				  $i++;
			}
		} // While loop
	}
	return $message;
}
</pre>
<p>Cron script:</p>
<pre class="jush-php"># add to your crontab with 'crontab -e'
* * * * * /home/username/sms-gateway/sms.php
</pre>
]]></content:encoded>
			<wfw:commentRss>http://colinmccann.com/code/automated-email-to-sms-gateway-php-script/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Aberrant behavior with single-input forms in IE7</title>
		<link>http://colinmccann.com/code/aberrant-behavior-with-single-input-forms-in-ie7</link>
		<comments>http://colinmccann.com/code/aberrant-behavior-with-single-input-forms-in-ie7#comments</comments>
		<pubDate>Tue, 14 Apr 2009 17:02:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://colinmccann.com/?p=22</guid>
		<description><![CDATA[These examples show the difference in handling form submissions between Internet Explorer (version 7 tested) and probably any competent browser on the web (read: everything else). Never mind the fact that this sort of browser behavior is contrary to everything you&#8217;d expect. Hope this saves someone the three hours it wasted for me. Submitted form [...]]]></description>
			<content:encoded><![CDATA[<p>These examples show the difference in handling form submissions between Internet Explorer (version 7 tested) and probably any competent browser on the web (read: everything else). Never mind the fact that this sort of browser behavior is contrary to everything you&#8217;d expect.  Hope this saves someone the three hours it wasted for me.<span id="more-22"></span></p>
<div id="ie_forms">
<div>
<h2>Submitted form data</h2>
<pre class="jush-php">
$_POST Array
(
)
</pre>
</div>
<div>
<h2>Apparently this is wrong</h2>
<p>This form has two inputs; a text input named &#8220;text&#8221; and a submit input named &#8220;submit&#8221;. Pressing enter while the text field has focus submits the form, but only the text field &#8212; the submit button is left behind.  If you click the submit button, both fields are properly submitted.</p>
<form action="/feed" method="post">
<input type="text" name="text" class="text" value="Hit enter in this text field" />
<input type="submit" name="submit" class="submit" value="Click this submit button" />
</form>
</div>
<div>
<h2>You&#8217;d think this would work</h2>
<p>Apparently this fantastic bug stems from single-input forms, although there doesn&#8217;t really seem to be a lot more information than that on the topic.  A logical human, when confronted with this altogether idiotic fact, would attempt to do something like add another input field.</p>
<p>This form is identical to the one above, only with the addition of a hidden field &#8220;extra&#8221; with a blank value. Pressing enter while in the text field acts similar to above, in that both &#8220;extra&#8221; and &#8220;text&#8221; are submitted, while &#8220;submit&#8221; is not.  Again, pressing the submit button resolves this issue.</p>
<form action="/feed" method="post">
<input name="extra" type="hidden" value="" />
<input type="text" name="text" class="text" value="Hit enter in this text field" />
<input type="submit" name="submit" class="submit" value="Click this submit button" />
</form>
</div>
<div>
<h2>The ugly hack solution</h2>
<p>Instead of a hidden field as in the above example, the &#8220;extra&#8221; field is a type=&#8221;text&#8221; that is hidden via CSS. Now look what happens: Pressing enter in the text field submits <em>all three fields</em>, exactly as it should.  Functionality is identical when clicking the submit button.</p>
<form action="/feed" method="post">
<input name="extra" type="text" value="" style="display: none;" />
<input type="text" name="text" class="text" value="Hit enter in this text field" />
<input type="submit" name="submit" class="submit" value="Click this submit button" />
</form>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://colinmccann.com/code/aberrant-behavior-with-single-input-forms-in-ie7/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Firefox Quick Pack</title>
		<link>http://colinmccann.com/utility/firefox-quick-pack</link>
		<comments>http://colinmccann.com/utility/firefox-quick-pack#comments</comments>
		<pubDate>Wed, 04 Feb 2009 07:15:29 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Utility]]></category>

		<guid isPermaLink="false">http://colinmccann.com/?p=36</guid>
		<description><![CDATA[First, let me say that Firefox is totally awesome. My favorite part is that it lets you customize it until the cows come home (or you manage to crash your system). I&#8217;ve also set up this wonderful bit of software on a number of computers, and usually give it at least a subset of the [...]]]></description>
			<content:encoded><![CDATA[<p>First, let me say that <a href="http://www.firefox.com">Firefox</a> is totally awesome. My favorite part is that it lets you <a href="https://addons.mozilla.org/">customize it</a> until the cows come home (or you manage to crash your system). I&#8217;ve also set up this wonderful bit of software on a number of computers, and usually give it at least a subset of the following options. This list is mostly for me, but hey, why not put it out there?<span id="more-36"></span></p>
<p>Before we get too far, feel free to grab this totally sweet icon to put in your <a href="http://rocketdock.com" title="RocketDock">totally sweet dock</a> (or <a href="http://do.davebsd.com/" title="Gnome-Do">GnomeDo / Docky</a>, if you can get it to work right):<br />
<img src="http://colinmccann.com/wp-content/uploads/2009/02/firefox-172x172.png" title="Firefox 172x172px" style="margin:0;" /></p>
<h2>Critical</h2>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/1865">AdBlock Plus</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/1027">All-In-One Sidebar</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/4925">AutoPager</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/26">Download Statusbar</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/636">PDF Download</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/2324">Session Manager</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/4810">Speed Dial</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/1122">Tab Mix Plus</a></p>
<h2>Webdev</h2>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/532">Linkchecker</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/3336">ErrorZilla Mod</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/539">MeasureIt</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/249">HTML Validator</a></p>
<h2>Communication</h2>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/1320">Gmail Manager</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/7757">Blank Canvas Gmail Signatures</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/3615">Delicious Bookmarks</a></p>
<h2>Look n&#8217; Feel</h2>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/743">CustomizeGoogle</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/4014">Locationbar<sup>2</sup></a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/3895">Personal Menu</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/5846">Yet Another Smooth Scrolling</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/3780">FaviconizeTab</a></p>
<h2>While I&#8217;m talking about it&#8230;</h2>
<p>&#8230;does anyone out there know how to do a bulk add-on installation? All-In-One-Sidebar used to be able to do it, but now the Open dialog only lets you select a single file instead of multiple. This would turn the initial setup from a fifteen minute job into a sixty second job.</p>
<h2>Greasemonkey Scripts</h2>
<p><a href="http://userstyles.org/styles/7582">Wikipedia: Simple Research</a> // a very clean and lightweight wikipedia skin<br />
<a href="http://userstyles.org/styles/7592">Gmail Air Skin 2</a> // takes gmail and makes everything better<br />
<a href="http://userscripts.org/scripts/show/44459">Facebook Purity</a> // Removes all ads and application messages</p>
<h2>about:config settings</h2>
<p>browser.urlbar.clickSelectsAll = <strong>true</strong> // first click on address bar highlights everything<br />
security.dialog_enable_delay = <strong>0</strong> // removes countdown on extension installations<br />
layout.word_select.stop_at_punctuation = <strong>true</strong> // double-click in address bar selects individual url segments</p>
]]></content:encoded>
			<wfw:commentRss>http://colinmccann.com/utility/firefox-quick-pack/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick administrative access in PHP</title>
		<link>http://colinmccann.com/code/quick-administrative-access-in-php</link>
		<comments>http://colinmccann.com/code/quick-administrative-access-in-php#comments</comments>
		<pubDate>Sat, 06 Dec 2008 10:44:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://colinmccann.com/?p=7</guid>
		<description><![CDATA[I recently got this all polished up, and it's working so well I decided I had to share. This little gem allows me to completely do away with setting up a dev server to make changes on a live site, as the functionality is basically created on an as-needed basis. It's easy, but oh so useful:]]></description>
			<content:encoded><![CDATA[<p>I recently got this all polished up, and it&#8217;s working so well I decided I had to share. This little gem allows me to completely do away with setting up a dev server to make changes on a live site, as the functionality is basically created on an as-needed basis. It&#8217;s easy, but oh so useful. <span id="more-7"></span></p>
<pre class="jush-php">// I put this in my session class, as it's guaranteed to be called on each and every page
function is_admin() {
    $ip = array(
        file_get_contents('/secret/text/file.txt'),
        '123.45.678.90',
        );
    return (in_array($_SERVER['REMOTE_ADDR'], $ip));
}
</pre>
<p>So, what does it do? Simple. It checks to see if the IP address of the computer making the request is the same as the predefined IP address it&#8217;s got in 1) the hard-coded array and 2) the /secret/text/file.txt I&#8217;ve set up elsewhere on the site. What text file? Oh, yes, almost forgot.</p>
<p>This function worked great for a while, but one client in particular had an IP address that changed fairly rapidly. Every other week I&#8217;d get a request to change the embedded IP, and eventually I just got sick of it. The solution was the following:</p>
<pre class="jush-php">// Save as /super/secret/ip/reset.php, or whatever suits your fancy.
$ip = $_SERVER['REMOTE_ADDR'];
$filename = '/secret/text/file.txt';
if (is_writable($filename)) {
    if (!$handle = fopen($filename, 'w')) {
        echo "Cannot open file ($filename)";
        exit;
    }
    if (fwrite($handle, $ip) === FALSE) {
        echo "Cannot write to file ($filename)";
        exit;
    }
    fclose($handle);
    header('Location: /');
    die();
} else {
    echo "The file $filename is not writable";
}
</pre>
<p>Now control was back in the clients&#8217; hands. Each time their IP changes, they just click a bookmark that accesses the above script. It opens the aforementioned text file, grabs the current IP address, and writes a single line of text. This is followed immediately by a redirect to home (/), but you could just as easily have it point anywhere.</p>
<p>So, now the function works. How do you use it? The short answer would be &#8220;everywhere&#8221; &#8212; at least, that&#8217;s been my experience:</p>
<pre class="jush-php">
if (is_admin()) {
    echo 'content that only admins can see';
} else {
    echo 'content that everyone else sees';
}
</pre>
<p>This can be used anywhere you want to make changes to a site, but leave everything completely intact for anyone that&#8217;s not on your VIP list. I&#8217;ve managed to complete some pretty extensive modifications by simply wrapping everything I was working on in this function. Clients love it because they can see changes and know that customers aren&#8217;t seeing development in progress. As for the amount of time I&#8217;ve saved by not hassling with copying files, making changes, reuploading, renaming, etc., well, it&#8217;s safe to say that I&#8217;m never going back to the old ways.</p>
<p>edit 2/8/10:</p>
<p>For quick deployment, this can be easily memorized and typed in about ten seconds:</p>
<pre class="jush-php">
function is_admin() {
    return ($_SERVER['REMOTE_ADDR'] == '123.45.678.90');
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://colinmccann.com/code/quick-administrative-access-in-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
