Tag Archives: tips - Page 2

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!

Better Forking for PHP

I recently needed to update a cron job written for CakePHP to make it multi-threaded, so that a job that would take months otherwise could finish in a reasonable amount of time. I originally planned to simply use pcntl_fork() to do this, but upon reading the comments on the function, I quickly realized it would be a major headache to write properly due to database and other socket connections involved in the process.
Read more »

Randomized .signature file

Here’s a quicky. I like to have a random quote in my signature, but most mail clients only read a static file, and trying to fool them with a command pipe socket is tricky, and often has other issues. So I wrote this little bit of magic:

#!/usr/bin/perl
 
my $fortune = '';
 
do {
	$fortune = `fortune -e -s -n 480 bofh-excuses calvin chalkboard chucknorris computers cookie definitions discworld dune firefly fortunes hitchhiker homer kids law linux magic mormon paradoxum perl pets riddles science scriptures smac startrek starwars taow work`;
} while ($fortune =~ /filter|these|words|out/);
 
print "Matthew Walker                      h: (xxx) xxx-xxxx\n";
print "Software Architect                  m: (xxx) xxx-xxxx\n";
print "Marketecture                        e: fake_email\@domain.com\n\n";
 
print $fortune;

Replace the ‘filter|these|words|out’ bit with a | seperated list of words you don’t want to show up in your fortunes, and adjust the fortune command however you want to tune the type of quotes you get. Then install it as a cron job like this:


* * * * * perl ~/.signature.pl > ~/.signature

There you go! Your .signature file will get regenerated once a minute with a new random quote. Enjoy.