gjerokrsteski/pimf-framework

View on GitHub
core/Pimf/Util/Uuid.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * Util
 *
 * @copyright Copyright (c)  Gjero Krsteski (http://krsteski.de)
 * @license   http://opensource.org/licenses/MIT MIT License
 */

namespace Pimf\Util;

/**
 * A class that generates RFC 4122 UUIDs
 *
 * <pre>
 * This specification defines a Uniform Resource Name namespace for
 * UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally
 * Unique IDentifier).  A UUID is 128 bits long, and requires no central
 * registration process.
 * </pre>
 *
 * @package Util
 * @author  Gjero Krsteski <gjero@krsteski.de>
 * @see     http://www.ietf.org/rfc/rfc4122.txt
 */
final class Uuid
{
    /**
     * 32-bit integer that identifies this host.
     *
     * @var integer
     */
    private static $node = null;

    /**
     * Process identifier.
     *
     * @var integer
     */
    private static $pid = null;

    private static $hostIp, $hostName;

    public static function setup($hostIp, $hostName)
    {
        self::$hostIp = $hostIp;
        self::$hostName = $hostName;
    }

    /**
     * Returns a 32-bit integer that identifies this host.
     *
     * The node identifier needs to be unique among nodes
     * in a cluster for a given application in order to
     * avoid collisions between generated identifiers.
     *
     * @return integer
     */
    private static function getNodeId()
    {
        if (self::$hostIp !== null) {
            return ip2long(self::$hostIp);
        }

        self::$hostIp = '127.0.0.1';

        if (self::$hostName !== null) {
            self::$hostIp = crc32(self::$hostName);
        }

        if (true === function_exists('php_uname')) {
            self::$hostName = php_uname('n');
            self::$hostIp = gethostbyname(self::$hostName);
        }

        if (true === function_exists('gethostname')) {
            self::$hostName = gethostname();
            self::$hostIp = gethostbyname(self::$hostName);
        }

        return ip2long(self::$hostIp);
    }

    /**
     * Returns a process identifier.
     *
     * In multi-process servers, this should be the system process ID.
     * In multi-threaded servers, this should be some unique ID to
     * prevent two threads from generating precisely the same UUID
     * at the same time.
     *
     * @return integer
     */
    private static function getLockId()
    {
        return getmypid();
    }

    /**
     * Generate an RFC 4122 UUID.
     *
     * This is pseudo-random UUID influenced by the system clock, IP
     * address and process ID.
     *
     * The intended use is to generate an identifier that can uniquely
     * identify user generated posts, comments etc. made to a website.
     * This generation process should be sufficient to avoid collisions
     * between nodes in a cluster, and between apache children on the
     * same host.
     *
     * @return string
     */
    public static function generate()
    {
        if (self::$node === null) {
            self::$node = self::getNodeId();
        }

        if (self::$pid === null) {
            self::$pid = self::getLockId();
        }

        list($time_mid, $time_lo) = explode(' ', microtime());

        $time_low = (int)$time_lo;
        $time_mid = (int)substr($time_mid, 2);

        $time_and_version = mt_rand(0, 0xfff);

        // version 4 UUID
        $time_and_version |= 0x4000;

        $clock_seq_low = mt_rand(0, 0xff);

        // type is pseudo-random
        $clock_seq_high = mt_rand(0, 0x3f);
        $clock_seq_high |= 0x80;

        $node_low = self::$pid;
        $node = self::$node;

        return sprintf(
            '%08x-%04x-%04x-%02x%02x-%04x%08x', $time_low, $time_mid & 0xffff, $time_and_version, $clock_seq_high,
            $clock_seq_low, $node_low,
            $node
        );
    }
}