How to know that your PHP is borked before your clients kill you

Maybe it’s just me, but every now and then I make a quick change to a PHP script, don’t bother checking it, then a few hours/days/months later either realise that I missed a vital semicolon, or mismatched a bracket. This started to get on my nerves, as now this has happened a couple of times I’d like to prevent it from happening again.

After thinking about this a little, and asking the wonderful stackoverflow.com, a person known as okoman suggested using the cli version of PHP to test parse the code using the -l flag.

I quickly wrapped it into a parcel of (ugly) code, set up a cron job to run it as frequently as I estimate I make errors and can now sleep peacefully knowing that all semicolons are in place, and all if’s have the right number of brackets.

So, here’s the delicious file which I’ve placed on my server. You can edit it not to produce output if you’d like and just to send emails/tweets.

<?
function list_dir($dir) {
 
	if (is_dir($dir)) {
		if ($dh = opendir($dir)) {
			while (($file = readdir($dh)) !== false) {
				if (substr("$file", 0, 1) != ".") {
					$files[] = $file;
				}
			}
			closedir($dh);
		}
	}
	sort($files);
	return $files;
}
 
$dir = "/path/to/code//";
$files = list_dir($dir);
$num_files = count($files);
 
for($i=0;$i<$num_files;$i++) {
	if (strpos($files[$i],".php") !== false) {
		$path = $dir.$files[$i];
		$result = `php -l $path`;
 
		if (strpos($result, "Errors parsing") !== false) {
			//tweet_error("Syntax",$files[$i]); //Function in my last post
			mail("emailaddress@example.com","Syntax Error",$files[$i]);
			echo "Syntax error in $files[$i]\n";
		}
	}
}
 
?>

And that’s all there is to it.

To check that it’s working OK, try making a file such as:

<?
if () {
?>

and run the error checking file.

This could be extended by parsing out line numbers and error types, but this minimum setup works for me.

Categories: PHP Tags: , ,

How to use Twitter as an error log

Sure this has been done before, but I had a brainwave today – why not use Twitter as an error log for web apps?

I already have error handling on my functions, so surely this shouldn’t be a difficult addition… turns out it’s not.

First, you’ll need a twitter account. I’d recommend setting one up, then protecting the updates. Keep the username and password, you’ll need them in a minute. I’d then follow the new account you set up, as well as anyone else on your team.

Then, define a function as follows in PHP, preferably in a global include or some such thing.

function tweet_error ($error, $description) {
	$username = 'yourusername';
	$password = 'yourpassword';
	$status = "#$error - $description";
 
	$update_url = 'http://www.twitter.com/statuses/update.xml'; // http://identi.ca/api/statuses/update.xml will use identi.ca instead.
 
	$curl = curl_init();
	curl_setopt($curl, CURLOPT_URL, "$update_url");
	curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($curl, CURLOPT_POST, 1);
	curl_setopt($curl, CURLOPT_POSTFIELDS, "status=$status");
	curl_setopt($curl, CURLOPT_USERPWD, "$username:$password");
 
	$result = curl_exec($curl);
	$resultArray = curl_getinfo($curl);
 
	curl_close($curl);
 
	return ($resultArray['http_code'] == 200);
}

My function here takes two parameters, the error code as well as a description. You could generalise this and rejig it a bit, as well as perhaps changing the $status variable to look different.

For instance,

$status = "d username #$error - $description";

or

$status = "@username #$error - $description";

to send it to you. You could even define different usernames for different types of errors, if you are in a team.

In your code, then call it like this:

tweet_error ("404", $_SERVER[SCRIPT_URL]);

to log a 404, as well as the page it came from, or:

tweet_error ("DB-Connect", "Failed");

In your database connection script, or even:

tweet_error ("Possible spam", "From user XXXX");

in your comment/email form handling.

Hope this comes in useful!

Categories: PHP, tips Tags:

Using Texter to speed up web design/development

Lifehacker’s Texter let’s you define short macros that allow you type a little, and get a lot back. I’ve not used this before, but am constantly finding myself typing the same bits over and over and over, so this is a very neat and helpful little tool.

Basically, you just define a command, then specify what that should expand to. The command %| inserts the cursor in that location after the replacement. A few macros that I’ve actually found myself using are:

Hotstring Replacement
$g $_GET['%|']
$p $_POST['$|']
<> <?= %| ?>
£ &pound;
l” &ldquo;
r” &rdquo;
msre mysql_real_escape_string(%|)

All nice simple things that make a big difference through the day, particularly <> and the Get and Post ones!

Any more useful ideas for this tool?

Categories: PHP, software Tags: , , ,

Enable better caching on your website using PHP

Just a quick snippet to help you tell useragents accessing your site that the content hasn’t changed.

function caching_headers ($file, $timestamp) {
	$gmt_mtime = gmdate('r', $timestamp);
	header('ETag: "'.md5($timestamp.$file).'"');
 
	if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
		if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
			header('HTTP/1.1 304 Not Modified');
			exit();
		}
	}
 
	header('Last-Modified: '.$gmt_mtime);
	header('Cache-Control: public');
	return 1;
}

Then call this in the top of your code like this:

caching_headers ($_SERVER['SCRIPT_FILENAME'], filemtime($_SERVER['SCRIPT_FILENAME']));

This sets an Etag based on the filename and modification date, and just returns a 304 header without any content if the browser already as the content.

You can also supply a different unix timestamp as the second argument allowing the timestamp to come from a database if applicable.

Hope this comes in useful!

Categories: PHP Tags:

7 differences between Linux and Windows

Background

Having mainly used various linuxes over the last few years, I’ve returned to using Windows 7 on my main desktop (out of curiosity) and XP on my work laptop (out of the fact it’s not mine!). Thought I’d share somethings I’ve noticed now I’m moving between them daily.

Read more…

Categories: linux, software Tags: ,

Friendfeedifying your feeds

Although these tips are designed for feeds used with Friendfeed, the first two aren’t just for that – it’s just that Friendfeed exposes the extra functions in it’s interface. The third tip regarding SUP currently is only really relevant for Friendfeed.

Read more…

Categories: PHP Tags: , , , , ,

5 terrible SEO ideas

Having looked at many small businesses websites, I’ve compiled a list here of 5 things that many of them are doing wrong with regards to SEO. I’m not saying that SEO isn’t important, but some techniques just don’t work. So, here goes… Read more…

Categories: tips Tags: , ,

5 ways to make using bash more productive

Screenshot of a sample Bash session, taken on ...

Image via Wikipedia

If you are using Linux or a Mac these days, then you likely have bash as your default shell. It generally comes with a few nice features (tab-completion, history etc.), but there are a few tips and tricks which will make it much nicer to use. Here’s a run down of my favourite 5.
Read more…

Categories: linux Tags: , , ,

Writing dynamic XML sitemaps using PHP

Graphic representation of a minute fraction of...

Since Google introduced sitemaps in 2005, they have grown to be accepted by the 4 main search engines: Google, Live Search, Yahoo and Ask.

As the offical sitemaps page describes:

Sitemaps are an easy way for webmasters to inform search engines about pages on their sites that are available for crawling. In its simplest form, a Sitemap is an XML file that lists URLs for a site along with additional metadata about each URL (when it was last updated, how often it usually changes, and how important it is, relative to other URLs in the site) so that search engines can more intelligently crawl the site.

So, basically it’s an XML file that simply describes what pages you have, when they were modified and how important you think they are.

An example would be:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
                            http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
        <url>
                <loc>http://bradshawenterprises.com/blog</loc>
                <lastmod>2008-09-07T10:21:52+00:00</lastmod>
                <changefreq>weekly</changefreq>
                <priority>1.0</priority>
        </url>
</urlset>

In this example, all fields are used, but you can get away with just the loc information. lastmod is an ATOM type date, changefreq can be always, hourly, daily, weekly, monthly, yearly or never, and the priority goes from 0.0 to 1.0. This, and the rest of the protocol are described at the official webpage.

Publishing a sitemap lets the search engines examine deeper parts of your site that may not be linked to that well, as well as providing data on what’s new without them having to crawl the whole site.

Each search engine provides an interface to register your sitemap and check it’s status. The best of these in my experience is Google Webmaster Tools, though the others have something equivalent as well.

Dynamically generating a sitemap

This tutorial will go through reading urls from a database rather than from the file system. This is because the key point here is describing things that have changed or are new. In my sitemaps I manually type in the static pages, and then dynamically write in the rest for simplicity and speed. Why read through numerous directories if we know that things haven’t changed.

So, we start off with a connection to a database:

include("assets/dbconnect.php");
$blogs = mysql_query("SELECT * FROM blog_posts ORDER BY timestamp DESC");

Here, I’m just using a stock database connection script and then really simply querying for the blog posts. I’m ordering them by timestamp so it’s easy to check it’s working, as the newest post will be first.

Next, we sort out a content type header, and the xml prologue.

header ("Content-type: text/xml");
echo ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");

The header just tells the user agent that this is some xml so that it knows how to process it. If your browser gets confused and wants to download it, just comment this out whilst testing. Most modern browsers won’t do this anyway.

I’m echoing out the prologue, as PHP gets confused by the symbols.

Next, we set up the XML file and it’s namespaces:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">

This describes the XML to the user agent so that it knows how to interpret the various fields in the file.

Now we get to the bulk of the file:

<? while($current_post = mysql_fetch_array($blogs)) { ?>
<url>
	<loc><?= $current_post[url]) ?></loc>
	<lastmod><?= gmdate(DATE_ATOM, $current_post[timestamp]) ?></lastmod>
</url>
<? } ?>

This just loops through my blog file and spits out the url and a nicely formatted timestamp. I’m using gmdate here because my server is in a different timezone.

Underneath this, I just hand type the remaining files:

<url>
	<loc>http://YOURDOMAIN/about.php</loc>
	<priority>0.5</priority>
</url>
<url>
	<loc>http://YOURDOMAIN/contact.php</loc>
	<priority>0.5</priority>
</url>

Right at the bottom, just place a

</urlset>

To signify the end of the file.

That’s all you need for your sitemap file. Place it in a file in the root of your domain and call it sitemap.php.

Let search engines know it exists

Either create a file in the root of your domain called robots.txt, or open the existing one. At the bottom just add a line that says:

Sitemap: http://YOURDOMAIN/sitemap.php

and save it. This lets search engines find the file.

This is all good so far, now we have a map that updates as the site updates without any real hassle. The next step is to make sure that search engines are told every time a new file is added. For this, you need to find the code where you are saving new posts in a database. I’m using curl here because it seems to be available everywhere.

Add this code as soon as you’ve checked that the entry has been saved properly.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "THEURLYOUNEEDTOPING");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);

Each search engine mentioned above has an address you can use here, here’s a quick summary:

Google: http://www.google.com/webmasters/tools/ping?sitemap=
Yahoo: http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap=
Ask: http://submissions.ask.com/ping?sitemap=
Live Search : http://webmaster.live.com/ping.aspx?siteMap=

All you do is add the full URL to your site map at the end, and use it in the code above. This will ensure that whenever you post anything, all the search engines are notified immediately.

I’d loop through these to do them all in one go like this:

$sitemap = "http://YOURDOMAIN/sitemap.php";

$pingurls = array(
	"http://www.google.com/webmasters/tools/ping?sitemap=",
	"http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap=",
	"http://submissions.ask.com/ping?sitemap=",
	"http://webmaster.live.com/ping.aspx?siteMap="
);

foreach ($pingurls as $pingurl) {
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $pingurl.$sitemap);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	$output = curl_exec($ch);
	curl_close($ch);
}

An alternative is to use a site such as PingMyMap, they provide an URL for you to use that they then use to ping the same search engines. The benefit here is that if the addresses change then it will still work. Your call really!

Any more ideas on how to implement this? Let me know below!

Categories: PHP Tags:

3 Ways Google Applications can enhance teaching

Having recently started working at a school where email, calendars, documents etc are hosted by Google Applications, I felt that it would be worth while incorporating these into my teaching and planning. This post describes the benefits I have found from this in the first few weeks, and will outline some plans that I have for the future. If you haven’t used Google Applications in a workplace before, then here’s a quick outline of what’s included in the free version.

  • Gmail (7+ GB of storage)
  • Google Calendar
  • Google Documents
  • Google Sites
  • Google Talk
  • A version of iGoogle called Start Page

Read more…

Categories: software Tags: