Archive for the 'Code snippets' Category

Handy little function

Quite often I find myself wanting to run the same script by either cli or through a browser. But I don’t want to fill my echo statements with <br /> tags if I’m on cli because that’d just look ugly, but at the same time I don’t just want to use \n when outputting in the browser because everything would be on the same line.

This handy little function helps to do simple output that will be readable in the browser as well as the command line:

$_ = function($str) {
    if (PHP_SAPI == 'cli') {
        echo $str;
    } else {
        echo nl2br(str_replace("\t", str_repeat('&nbsp;', 6), $str))."\n";
        flush();
    }
};

Then when I want to echo something I just do:

$_("This is a test\n");
$_("\tTime:" . time() . "\n\n");

Simple but handy.

Did you like this? Share it:

Merge two urls

This is a handy function for combining two urls. The urls could be strings or parts in an array (as you’d get from the parse_url function), or you can mix-and-match. Check out the examples in the docblock below to see what I mean.

/**
 * Combine two urls.
 *
 * The urls can be either a string or url parts that consist of:
 *
 *     scheme, host, port, user, pass, path, query, fragment
 *
 * If passed in as parts in an array, the query parameter can be either
 * a string or an array of name/value key pairs.  The query parameters
 * will be added on to the ones from the original url.  If you want to
 * remove query parameters, or any other parts of the url, you need to
 * pass the value in as null.
 *
 * Examples:
 *
 *     urlMerge(
 * 	       '/tests/section/people?id=9405',
 *         array('query' => array('found' => true, 'id' => null))
 *     );
 *
 *     urlMerge(
 * 	       'http://www.example.com/',
 *         array('scheme' => 'https', 'query' => 'foo=bar&test=1'
 *     );
 *
 *     urlMerge(
 * 	       array('path' => '/tests/item', 'query' => 'id=9405'),
 *         'http://www.example.com'
 *     );
 *
 * @param  string|array $original
 * @param  string|array $new
 * @return string
 */
function urlMerge($original, $new)
{
    if (is_string($original)) {
        $original = parse_url($original);
    }
    if (is_string($new)) {
        $new = parse_url($new);
    }
    $qs = null;
    if (!empty($original['query']) && is_string($original['query'])) {
        parse_str($original['query'], $original['query']);
    }
    if (!empty($new['query']) && is_string($new['query'])) {
        parse_str($new['query'], $new['query']);
    }
    if (isset($original['query']) || isset($new['query'])) {
        if (!isset($original['query'])) {
            $qs = $new['query'];
        } elseif (!isset($new['query'])) {
            $qs = $original['query'];
        } else {
            $qs = array_merge($original['query'], $new['query']);
        }
    }
    $result = array_merge($original, $new);
    $result['query'] = $qs;
    foreach ($result as $k => $v) {
        if ($v === null) {
            unset($result[$k]);
        }
    }
    if (!empty($result['query'])) {
        $result['query'] = http_build_query($result['query']);
    }
    return (isset($result['scheme']) ? "{$result['scheme']}://" : '')
		. (isset($result['user']) ? $result['user']
		    . (isset($result['pass']) ? ":{$result['pass']}" : '').'@' : '')
		. (isset($result['host']) ? $result['host'] : '')
		. (isset($result['port']) ? ":{$result['port']}" : '')
		. (isset($result['path']) ? $result['path'] : '')
		. (!empty($result['query']) ? "?{$result['query']}" : '')
		. (isset($result['fragment']) ? "#{$result['fragment']}" : '');
}
Did you like this? Share it:

Sorting an array of objects by one or more object property

Quite often I find myself having an array of objects and needing to sort that array by one or more of the properties in the objects… Imagine, for example, getting a large result set from Zend_Db, or something similar, and ordering in the query just takes too long. Or perhaps you’re getting results from a web service and that service doesn’t return the results in the order you’d like to use. Have you ever found yourself in that situation, too? On looking at the usort documentation one day I came across a comment by someone called Will Shaver that did almost what I wanted. With a little adaptation for my own use (being able to change the sort order, for example), it has become one of my favourite functions to use for sorting.

    /**
     * Sort an array of objects.
     *
     * You can pass in one or more properties on which to sort.  If a
     * string is supplied as the sole property, or if you specify a
     * property without a sort order then the sorting will be ascending.
     *
     * If the key of an array is an array, then it will sorted down to that
     * level of node.
     *
     * Example usages:
     *
     * osort($items, 'size');
     * osort($items, array('size', array('time' => SORT_DESC, 'user' => SORT_ASC));
     * osort($items, array('size', array('user', 'forname'))
     *
     * @param array $array
     * @param string|array $properties
     */
    public static function osort(&$array, $properties)
    {
        if (is_string($properties)) {
            $properties = array($properties => SORT_ASC);
        }
        uasort($array, function($a, $b) use ($properties) {
            foreach($properties as $k => $v) {
                if (is_int($k)) {
                    $k = $v;
                    $v = SORT_ASC;
                }
                $collapse = function($node, $props) {
                    if (is_array($props)) {
                        foreach ($props as $prop) {
                            $node = (!isset($node->$prop)) ? null : $node->$prop;
                        }
                        return $node;
                    } else {
                        return (!isset($node->$props)) ? null : $node->$props;
                    }
                };
                $aProp = $collapse($a, $k);
                $bProp = $collapse($b, $k);
                if ($aProp != $bProp) {
                    return ($v == SORT_ASC)
                        ? strnatcasecmp($aProp, $bProp)
                        : strnatcasecmp($bProp, $aProp);
                }
            }
            return 0;
        });
    }

Now a few cools things about the function:

  1. It uses anonymous/lambda functions (or closures, whatever your prefer to call them), and that’s just plain fun
  2. You can sort on more than one property and because the sorting is recursive, it’ll sort the second property within the confines of the first, the third within the confines of the second, and so on. Think sorting in SQL
  3. You can sort in ascending or descending order for any of the properties
  4. It retains key associations so you could use this on an associative array of objects
  5. If the parameter you want to sort on is an array itself then you can use any value (by specifying it’s key) in that array as the sorting value
Did you like this? Share it:

Quick and easy email encoding view helper

Here’s a quick and easy view helper for Zend Framework that will encode an email address. It will encode just an email address or return a whole mailto link. The encoding is basically the same as in the Smarty template engine.

Obviously there’s a lot of room for improvement; javascript encoding, representation as an image, and so on… but then it wouldn’t be quick an easy – it’d be slightly longer and just a little more complex. ;-)

Continue reading ‘Quick and easy email encoding view helper’

Did you like this? Share it:

Tag cloud view helper

Here’s a little view helper to display a tag cloud. All you have to do is supply an array of tags, with the tag name being the index and how many times it’s used as the value, and the url you’d like the tags to go to.

Continue reading ‘Tag cloud view helper’

Did you like this? Share it:

Auto generating basic models for a Zend Framework app

Do you have a database with foreign keys and just wish you could have something automatically create your ZF models from it? Well, today that was me. So as a little proof of concept, this is the code I came up with to do it for me…

But before we get to that, a few caveats:

  • It’s just a proof of concept
  • The output needs updating for proper reference names, etc.
  • Outputs everything to screen in one go and doesn’t save the files.

However, it might be handy to someone, so I post it up for your comments.
Continue reading ‘Auto generating basic models for a Zend Framework app’

Did you like this? Share it:

Force a file download

Here’s a small function that will allow you to force a file download.

/**
 * Force a file download via HTTP.
 *
 * File is required to be on the same server and accessible via a path.
 * If the file cannot be found or some other error occurs then a
 * '204 No content' header is sent.
 *
 * @param string $path Path and file name
 * @param string $name Name of file when saved on user's computer,
 *                     null for basename from path
 * @param string $type Content type header info (e.g., 'application/vnd.ms-excel')
 * @return void
 * @access public
 */
/* public static */ function download($path, $name = null, $type = 'binary/octet-stream')
{
    if (headers_sent()) {
        echo 'File download failure: HTTP headers have already been sent and cannot be changed.';
        exit;
    }
    
    $path = realpath($path);
    if ($path === false || !is_file($path) || !is_readable($path)) {
        header('HTTP/1.0 204 No Content');
        exit;
    }

    $name = (empty($name)) ? basename($path) : $name;
    $size = filesize($path);

    header('Expires: Mon, 20 May 1974 23:58:00 GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Cache-Control: post-check=0, pre-check=0', false);
    header('Cache-Control: private');
    header('Pragma: no-cache');
    header("Content-Transfer-Encoding: binary");
    header("Content-type: {$type}");
    header("Content-length: {$size}");
    header("Content-disposition: attachment; filename=\"{$name}\"");
    readfile($path);
    exit;
}

Very easy to use, too! Here are some examples of how you might call the function:

download('./myfile.txt');

download(__FILE__, 'a file for you.php');

download('/home/you/files/spreadsheet.xml', 'ssheet_' . date('Ymd'), 'application/vnd.ms-excel');
Did you like this? Share it:

Simple image view helper for Zend Framework

Here’s a simply view helper for the Zend Framework that can be used to display image tags. It checks to see if the image file exists and if not then it’ll use the data url scheme to output a very simple image that, ironically, says ‘NO IMG’ on it. :-) Please note, though, that I’ve only seen Firefox support this scheme, as wonderful as it is!

Continue reading ‘Simple image view helper for Zend Framework’

Did you like this? Share it:

Robust email address validator – with address suggestions!

I’m sure you’ve seen the simple email address format validation function; they’re usually a simple regular expressing that just check the address portion (the user@example.org bit). That’s really only a bit of the validation that should be done. The RFC822 specs detail that the format of email addresses can be much larger, for example, it could be something like “Andrew Collington & Co.” <a.collington@example.org>, and, of course, the simple regex on that would fail. But even a check on the address format isn’t often enough… The user could enter a correctly formatted email address but simply have mis-spelled the address… they may accidentally type in user@yahooo.com, or user@hitmail.co.uk rather than hotmail.co.uk, and things like that. In which case you may want to check the MX and/or A record to see if its a valid domain. And whilst you’re doing that, why not check to see if it’s a commonly used email host that maybe they’ve typed in wrong?

So here is a class that will allow you to do all that in one easy method call:

Continue reading ‘Robust email address validator – with address suggestions!’

Did you like this? Share it:

Getting a list of project tags from Subversion

So there you are nicely tagging your project in Subversion, but for some reason you need to get a list of all the tags being used… That situation came up for me today. I thought it was going to be some really complex way of getting the tags, involving the use of hook scripts and the like. But it turns out that with some command line goodness it’s actually much more simple. Here’s how to do it:

svnlook tree --full-paths /home/path/to/svn/project | \
egrep -a '/?tags/.+' | \
sed -re 's!.*/?tags/([^/]*).*!\1!' | \
sort -u
Did you like this? Share it: