Monthly Archives: October 2010

Screening files on push in a git repo

I recently had the need to make sure that files that were pushed to a git repository had a required string in them. It took a few hours, but here’s what I came up with to do it:

#!/bin/sh
 
refname="$1"
oldrev="$2"
newrev="$3"
 
paths="path/in/repo/"
required="REQUIRED_STRING"
 
hashes=( $(git diff-tree -r $newrev -- $paths | awk '{if ($5 == "A" || $5 == "M") print $4}') )
files=( $(git diff-tree -r $newrev -- $paths | awk '{if ($5 == "A" || $5 == "M") print $6}') )
 
error=0
errors=()
 
for (( c = 0; c < ${#hashes[@]}; c++ ))
do
	check=$(git show ${hashes[$c]} | grep $required | wc -l)
 
	if [ "$check" == "0" ] 
	then
		errors=( "${errors[@]}" ${files[$c]} )
		error=1
	fi
done
 
if [ "$error" == "1" ]
then
	echo
	echo "The following SQL scripts do not have the required string '$required':"
 
	for (( c = 0; c < ${#errors[@]}; c++ ))
	do
		echo "    ${errors[$c]}"
	done
 
	echo 
fi
 
exit $error

Save this as ‘update’ in the ‘hooks’ directory of your bare repo, make it executable, and enjoy. Any files in the paths specified that don’t contain the required text will result in a rejected push.

Simple NaNoWriMo API Class

As anyone who knows me probably realizes (because I talk about it incessantly) it’s NaNoWriMo time again. Which means I’m revamping my wordwar tool for this year. This time, I’m giving it a complete overhaul. In the process, I looked at how I was using the API provided by NaNoWriMo, and decided I needed to improve it. After all the coding I’ve done in CakePHP in the last year, I realized there was a very very simple way to do this. Not much to say about it, so here’s the code:

<?php
class WordCountApiComponent extends Object {
	function __call($name, $arguments) {
		if (count($arguments) == 1) {
			$xml = $this->_request("http://www.nanowrimo.org/wordcount_api/".$name."/".$arguments[0]);
		} else {
			$xml = $this->_request("http://www.nanowrimo.org/wordcount_api/".$name);
		}
 
		return $xml;
	}
 
	private function _request($url) {
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$output = curl_exec($ch);
		curl_close($ch);
 
		return new SimpleXMLElement($output);
	}
}

That’s it. Just two methods. (And I could reduce it to 1, but I prefer to keep the CURL logic in it’s own method.)

Using it is just as simple. All NaNoWriMo API methods use either 0 or 1 arguments, and the method names are simply part of the URL. So, to call the ‘wc’ API, that returns the current wordcount for a single user, taking their UID as it’s only parameter, you’d do this:

$uid = 78110; // My UID
$api = new WordCountApiComponent();
$wc = $api->wc($uid);
 
echo $wc->uname; // "utoxin"
echo $wc->user_wordcount; // '0'

Hope this helps someone! It’s certainly a nice simple way to interface with the API.

More Correct Email from CakePHP

One problem a lot of people have with sending email from PHP in general is properly setting the envelope sender of the message, so that it’s correct in all the headers. This is important because it affects spam filtering rather drastically. Also, some ISPs and other email providers won’t even accept a message if the envelope header is set to an invalid address.

In regular PHP, this is simple to fix. Consider the following example, that sets the from address properly:

<?php
$headers = 'From: webmaster@example.com' . "\r\n" .
    'Reply-To: webmaster@example.com' . "\r\n" .
    'X-Mailer: PHP/' . phpversion();
);
mail(
    "example@example.com", 
    "Test Message", 
    "This is a test message", 
    $headers, 
    "-fwebmaster@example.com"
);

The key here is that last parameter we pass to the function: ‘-fwebmaster@example.com’. That passes a command-line option to sendmail that properly sets the envelope sender. Most people leave that off, because they don’t even realize the need it there.

Okay, so now we know how to do it in raw PHP. How do we do this using CakePHP’s email component? After all, the documentation doesn’t mention anything about that ‘additional parameters’ argument, does it? Or maybe it does. You just have to read the full API docs very carefully. It turns out, if you set the ‘additionalParams’ property of the Email Component, it will pass it on to the mail() function when it calls it. Perfect! So, here’s how to properly initialize the Email Component in CakePHP:

<?php
$this->Email->to = 'example@example.com';
$this->Email->subject = 'Test Message';
$this->Email->replyTo = 'webmaster@example.com';
$this->Email->from = 'webmaster@example.com';
$this->Email->additionalParams = '-fwebmaster@example.com';
$this->Email->template = 'test_message';
$this->Email->sendAs = 'both';

And there you have it! The correct way to send email with proper envelope headers from CakePHP. Enjoy the lower spam score that results!