diff --git a/backend/.gitignore b/backend/.gitignore
new file mode 100644
index 0000000..bc3d175
--- /dev/null
+++ b/backend/.gitignore
@@ -0,0 +1 @@
+/database.sqlite
diff --git a/backend/bin/doctrine.php b/backend/bin/doctrine.php
index 90aef89..df24c7a 100644
--- a/backend/bin/doctrine.php
+++ b/backend/bin/doctrine.php
@@ -27,7 +27,9 @@
use Volkszaehler\Util;
// TODO replace by state class
-const VZ_BACKEND_DIR = '/home/steffen/workspace/volkszaehler.org/backend';
+define('VZ_VERSION', 0.2);
+define('VZ_DIR', realpath(__DIR__ . '/../..'));
+define('VZ_BACKEND_DIR', VZ_DIR . '/backend');
// class autoloading
require VZ_BACKEND_DIR . '/lib/Util/ClassLoader.php';
@@ -44,7 +46,7 @@ foreach ($classLoaders as $loader) {
// load configuration
Util\Configuration::load(VZ_BACKEND_DIR . '/volkszaehler.conf');
-$em = Volkszaehler\Dispatcher::createEntityManager();
+$em = Volkszaehler\Router::createEntityManager();
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
diff --git a/backend/index.php b/backend/index.php
index 0cf7d98..581b3bb 100644
--- a/backend/index.php
+++ b/backend/index.php
@@ -30,13 +30,12 @@ use Volkszaehler\Util;
use Volkszaehler\Controller;
// enable strict error reporting
-error_reporting(E_ALL);
+error_reporting(E_ALL | E_STRICT);
// TODO replace by state class
define('VZ_VERSION', 0.2);
define('VZ_DIR', realpath(__DIR__ . '/..'));
define('VZ_BACKEND_DIR', VZ_DIR . '/backend');
-define('DEV_ENV', TRUE);
// class autoloading
require VZ_BACKEND_DIR . '/lib/Util/ClassLoader.php';
@@ -44,7 +43,6 @@ require VZ_BACKEND_DIR . '/lib/Util/ClassLoader.php';
$classLoaders = array();
$classLoaders[] = new Util\ClassLoader('Volkszaehler', VZ_BACKEND_DIR . '/lib');
$classLoaders[] = new Util\ClassLoader('Doctrine', VZ_BACKEND_DIR . '/lib/vendor/Doctrine');
-//$classLoaders[] = new Util\ClassLoader('Symfony', VZ_BACKEND_DIR . '/lib/vendor/Symfony'); // only required for the cli
foreach ($classLoaders as $loader) {
$loader->register(); // register on SPL autoload stack
@@ -52,7 +50,8 @@ foreach ($classLoaders as $loader) {
Util\Configuration::load(VZ_BACKEND_DIR . '/volkszaehler.conf');
-$fc = new Dispatcher; // spawn frontcontroller / dispatcher
-$fc->run(); // execute controller and sends output
+$r = new Router();
+$r->run();
+$r->view->send();
?>
diff --git a/backend/lib/Interpreter/AggregatorInterpreter.php b/backend/lib/Interpreter/AggregatorInterpreter.php
index 911c5c1..267e45d 100644
--- a/backend/lib/Interpreter/AggregatorInterpreter.php
+++ b/backend/lib/Interpreter/AggregatorInterpreter.php
@@ -56,7 +56,7 @@ class AggregatorInterpreter {
foreach ($aggregator->getChannels() as $channels) {
if (isset($indicator) && $indicator != $channel->getIndicator()) {
- throw new \Exception('we only can aggregate channels of the same indicator');
+ throw new \Exception('Can\'t aggregate entities of mixed types!');
}
else {
$indicator = $channel->getIndicator();
diff --git a/backend/lib/Interpreter/Interpreter.php b/backend/lib/Interpreter/Interpreter.php
index 448d83c..9e36054 100644
--- a/backend/lib/Interpreter/Interpreter.php
+++ b/backend/lib/Interpreter/Interpreter.php
@@ -115,7 +115,7 @@ abstract class Interpreter implements InterpreterInterface {
return new Iterator\DataAggregationIterator($stmt, $rowCount, $tuples);
}
else {
- throw new \Exception('invalid groupBy parameter');
+ throw new \Exception('Invalid parameter: "groupBy"');
}
}
diff --git a/backend/lib/Interpreter/MeterInterpreter.php b/backend/lib/Interpreter/MeterInterpreter.php
index 735b478..7790f29 100644
--- a/backend/lib/Interpreter/MeterInterpreter.php
+++ b/backend/lib/Interpreter/MeterInterpreter.php
@@ -130,7 +130,7 @@ class MeterInterpreter extends Interpreter {
$delta = $next[0] - $last[0];
return array(
- (int) ($next[0] - $delta / 2), // timestamp
+ ($next[0] - $delta / 2), // timestamp
$next[1] * (3600000 / (($this->channel->getProperty('resolution')->getValue() / 1000) * $delta)), // value
(isset($next[2])) ? $next[2] : 1
);
diff --git a/backend/lib/Logger/Logger.php b/backend/lib/Logger/Logger.php
index 07a8cb2..d3ada4d 100644
--- a/backend/lib/Logger/Logger.php
+++ b/backend/lib/Logger/Logger.php
@@ -76,9 +76,6 @@ abstract class Logger implements LoggerInterface {
$data = array($data);
}
- foreach ($data as $reading) {
- $this->em->persist($reading);
- }
$this->em->flush();
}
}
diff --git a/backend/lib/Model/Data.php b/backend/lib/Model/Data.php
index 438493b..d93e711 100644
--- a/backend/lib/Model/Data.php
+++ b/backend/lib/Model/Data.php
@@ -34,7 +34,12 @@ use Volkszaehler\Model;
* @todo rename? Bsp: DataSample, Sample, Reading
*
* @Entity
- * @Table(name="data")
+ * @Table(
+ * name="data",
+ * uniqueConstraints={
+ * @UniqueConstraint(name="unique_timestamp", columns={"timestamp", "channel_id"})
+ * }
+ * )
*/
class Data {
/**
diff --git a/backend/lib/Model/Definition.php b/backend/lib/Model/Definition.php
index 737b79b..ed6a6de 100644
--- a/backend/lib/Model/Definition.php
+++ b/backend/lib/Model/Definition.php
@@ -50,7 +50,7 @@ abstract class Definition {
$this->$name = $value;
}
else {
- throw new \Exception('unknown definition syntax: ' . $name);
+ throw new \Exception('Unknown definition syntax: ' . $name);
}
}
}
@@ -63,8 +63,12 @@ abstract class Definition {
* @return Util\Definition
*/
public static function get($name) {
+ if (is_null(static::$definitions)) {
+ static::load();
+ }
+
if (!static::exists($name)) {
- throw new \Exception('unknown definition');
+ throw new \Exception('Unknown definition');
}
return static::$definitions[$name];
diff --git a/backend/lib/Model/Entity.php b/backend/lib/Model/Entity.php
index dc8a182..da209bd 100644
--- a/backend/lib/Model/Entity.php
+++ b/backend/lib/Model/Entity.php
@@ -23,6 +23,8 @@
namespace Volkszaehler\Model;
+use Doctrine\ORM;
+
use Doctrine\Common\Collections;
use Volkszaehler\Util;
@@ -63,7 +65,7 @@ abstract class Entity {
/**
* @OneToMany(targetEntity="Property", mappedBy="entity", cascade={"remove", "persist"})
- * @OrderBy({"name" = "ASC"})
+ * @OrderBy({"key" = "ASC"})
*/
protected $properties = NULL;
@@ -71,77 +73,103 @@ abstract class Entity {
* Constructor
*
* @param string $type
- * @param array $properties of Model\Property
*/
public function __construct($type) {
if (!EntityDefinition::exists($type)) {
- throw new \Exception('unknown entity type');
+ throw new \Exception('Unknown entity type');
}
$this->type = $type;
- $this->uuid = Util\UUID::mint();
+ $this->uuid = (string) Util\UUID::mint();
$this->tokens = new Collections\ArrayCollection();
$this->properties = new Collections\ArrayCollection();
}
+
/**
- * Checks for optional and required properties according to share/entities.json
- *
- * Throws an exception if something is incorrect
+ * Checks for required and invalid properties
*
* @PrePersist
- * @PreUpdate
- * @PostLoad
- * @todo to be implemented
*/
- protected function validate() {
+ public function checkProperties() {
+ $missingProperties = array_diff($this->getDefinition()->getRequiredProperties(), array_keys($this->getProperties()));
+ $invalidProperties = array_diff(array_keys($this->getProperties()), $this->getDefinition()->getValidProperties());
+ if (count($missingProperties) > 0) {
+ throw new \Exception('Entity "' . $this->getType() . '" requires propert' . ((count($missingProperties) == 1) ? 'y' : 'ies') . ': "' . implode(', ', $missingProperties) . '"');
+ }
+
+ if (count($invalidProperties) > 0) {
+ throw new \Exception('Propert' . ((count($invalidProperties) == 1) ? 'y' : 'ies') . ' "' . implode(', ', $unallowedProperties) . '" ' . ((count($unallowedProperties) == 1) ? 'is' : 'are') . ' not allowed for entity "' . $this->getType() . '"');
+ }
}
/**
* Get a property by name
*
- * @param string $name
- * @return Model\Property
+ * @param string $key
+ * @return mixed
*/
- public function getProperty($name) {
- return $this->properties->filter(function($property) use ($name) {
- return $property->getName() == $name;
- })->first();
+ public function getProperty($key) {
+ return $this->findProperty($key)->getValue();
}
/**
* Get all properties or properties by prefix
*
* @param string $prefix
+ * @return array
*/
public function getProperties($prefix = NULL) {
- if (is_null($prefix)) {
- return $this->properties;
+ $properties = array();
+ foreach ($this->properties as $property) {
+ if (substr($property->getKey(), 0, strlen($prefix)) == $prefix) {
+ $properties[$property->getKey()] = $property->getValue();
+ }
}
- else {
- return $this->properties->filter(function($property) use ($prefix) {
- return substr($property->getName(), 0, strlen($prefix) + 1) == $prefix . ':';
- });
+ return $properties;
+ }
+
+ /**
+ *
+ * @param string $key
+ * @return Model\Property
+ */
+ protected function findProperty($key) {
+ foreach ($this->properties as $property) {
+ if ($property->getKey() == $key) {
+ return $property;
+ }
}
}
/**
- * @param string $name of the property
- * @param string|integer|float $value of the property
- * @todo check if already set for this entity
+ * Set property
+ *
+ * @param string $key name of the property
+ * @param mixed $value of the property
*/
- public function setProperty(Property $property) {
- $this->properties->add($property);
+ public function setProperty($key, $value) {
+ if ($property = $this->findProperty($key)) { // property already exists; just change value
+ $property->setValue($value);
+ }
+ else { // create new property
+ $property = new Property($this, $key, $value);
+ $this->properties->add($property);
+ }
}
/**
+ * Unset property
+ *
* @param string $name of the property
- * @todo to be implemented
+ * @param Doctrine\EntityManager $em
*/
- public function unsetProperty($name) {
-
+ public function unsetProperty($key, ORM\EntityManager $em) {
+ $property = $this->findProperty($key);
+ $em->remove($property);
+ $this->properties->remove($index);
}
/*
@@ -161,8 +189,8 @@ abstract class Entity {
* @return Interpreter
*/
public function getInterpreter(\Doctrine\ORM\EntityManager $em, $from, $to) {
- $interpreterClassName = 'Volkszaehler\Interpreter\\' . $this->getDefinition()->getInterpreter();
- return new $interpreterClassName($this, $em, $from, $to);
+ $class = 'Volkszaehler\Interpreter\\' . $this->getDefinition()->getInterpreter();
+ return new $class($this, $em, $from, $to);
}
}
diff --git a/backend/lib/Model/Property.php b/backend/lib/Model/Property.php
index 48461e3..8fdb9ad 100644
--- a/backend/lib/Model/Property.php
+++ b/backend/lib/Model/Property.php
@@ -36,7 +36,7 @@ use Volkszaehler\Model;
* @Table(
* name="properties",
* uniqueConstraints={
- * @UniqueConstraint(name="unique_properties", columns={"id", "name"})
+ * @UniqueConstraint(name="unique_keys", columns={"entity_id", "`key` "})
* }
* )
* @HasLifecycleCallbacks
@@ -51,8 +51,8 @@ class Property {
*/
protected $id;
- /** @Column(type="string", nullable=false) */
- protected $name;
+ /** @Column(name="`key`", type="string", nullable=false) */
+ protected $key;
/** @Column(type="string", nullable=false) */
protected $value;
@@ -66,11 +66,11 @@ class Property {
* @param string $key
* @param string $value
*/
- public function __construct(Model\Entity $entity, $name, $value) {
- $this->setName($name);
- $this->setValue($value);
-
+ public function __construct(Model\Entity $entity, $key, $value) {
$this->entity = $entity;
+
+ $this->key = $key;
+ $this->value = $value;
}
/**
@@ -78,14 +78,14 @@ class Property {
*
* @PostLoad
*/
- public function castValue() {
+ public function cast() {
if ($this->getDefinition()->getType() != 'multiple') {
settype($this->value, $this->getDefinition()->getType());
}
}
/**
- * Validate property name & value
+ * Validate property key & value
*
* Throws an exception if something is incorrect
*
@@ -93,24 +93,43 @@ class Property {
* @PreUpdate
*/
public function validate() {
- if (!PropertyDefinition::exists($this->name)) {
- throw new \Exception('invalid property name: ' . $this->name);
+ if (!PropertyDefinition::exists($this->key)) {
+ throw new \Exception('Invalid property key: ' . $this->key);
}
+ $this->cast(); // TODO not safe
+
if (!$this->getDefinition()->validateValue($this->value)) {
- throw new \Exception('invalid property value: ' . $this->value);
+ throw new \Exception('Invalid property value: ' . $this->value);
+ }
+ }
+
+ /**
+ * @PreRemove
+ */
+ public function checkRemove() {
+ if (in_array($this->key, $this->entity->getDefinition()->getRequiredProperties())) {
+ throw new \Exception('"' . $this->key . '" is a required property for the "' . $this->entity->getType() . '" entity');
+ }
+ }
+
+ /**
+ * @PrePersist
+ */
+ public function checkPersist() {
+ if (!in_array($this->key, $this->entity->getDefinition()->getValidProperties())) {
+ throw new \Exception('"' . $this->key . '" is not a valid property for the "' . $this->entity->getType() . '" entity');
}
}
/*
* Setter & Getter
*/
- public function getName() { return $this->name; }
+ public function getKey() { return $this->key; }
public function getValue() { return $this->value; }
- public function getDefinition() { return PropertyDefinition::get($this->name); }
+ public function getDefinition() { return PropertyDefinition::get($this->key); }
public function setValue($value) { $this->value = $value; }
- protected function setName($name) { $this->name = $name; }
}
?>
diff --git a/backend/lib/Model/Token.php b/backend/lib/Model/Token.php
index 7fc973f..4865ad6 100644
--- a/backend/lib/Model/Token.php
+++ b/backend/lib/Model/Token.php
@@ -25,8 +25,6 @@ namespace Volkszaehler\Model;
use Volkszaehler\Util;
-use Volkszaehler\Model;
-
/**
* Token entity
*
diff --git a/backend/lib/Util/ClassLoader.php b/backend/lib/Util/ClassLoader.php
index e705e49..b86ce07 100644
--- a/backend/lib/Util/ClassLoader.php
+++ b/backend/lib/Util/ClassLoader.php
@@ -108,15 +108,15 @@ class ClassLoader {
/**
* Loads the given class or interface.
*
- * @param string $classname The name of the class to load.
+ * @param string $class The name of the class to load.
* @return boolean TRUE if the class has been successfully loaded, FALSE otherwise.
*/
- public function loadClass($className) {
- if ($this->namespace !== NULL && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) {
+ public function loadClass($class) {
+ if ($this->namespace !== NULL && strpos($class, $this->namespace . $this->namespaceSeparator) !== 0) {
return FALSE;
}
- $subNamespace = substr($className, strlen($this->namespace));
+ $subNamespace = substr($class, strlen($this->namespace));
$parts = explode($this->namespaceSeparator, $subNamespace);
$path = implode(DIRECTORY_SEPARATOR, $parts);
@@ -128,15 +128,15 @@ class ClassLoader {
* Asks this ClassLoader whether it can potentially load the class (file) with
* the given name.
*
- * @param string $className The fully-qualified name of the class.
+ * @param string $class The fully-qualified name of the class.
* @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise.
*/
- public function canLoadClass($className) {
- if ($this->namespace !== NULL && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) {
+ public function canLoadClass($class) {
+ if ($this->namespace !== NULL && strpos($class, $this->namespace . $this->namespaceSeparator) !== 0) {
return FALSE;
}
- $subNamespace = substr($className, strlen($this->namespace));
+ $subNamespace = substr($class, strlen($this->namespace));
$parts = explode($this->namespaceSeparator, $subNamespace);
$path = implode(DIRECTORY_SEPARATOR, $parts);
@@ -161,11 +161,11 @@ class ClassLoader {
* for its existence. This is not the case with a ClassLoader, who separates
* these responsibilities.
*
- * @param string $className The fully-qualified name of the class.
+ * @param string $class The fully-qualified name of the class.
* @return boolean TRUE if the class exists as per the definition given above, FALSE otherwise.
*/
- public static function classExists($className) {
- if (class_exists($className, FALSE)) {
+ public static function classExists($class) {
+ if (class_exists($class, FALSE)) {
return TRUE;
}
@@ -173,20 +173,20 @@ class ClassLoader {
if (is_array($loader)) { // array(???, ???)
if (is_object($loader[0])) {
if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName')
- if ($loader[0]->canLoadClass($className)) {
+ if ($loader[0]->canLoadClass($class)) {
return TRUE;
}
- } else if ($loader[0]->{$loader[1]}($className)) {
+ } else if ($loader[0]->{$loader[1]}($class)) {
return TRUE;
}
- } else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName')
+ } else if ($loader[0]::$loader[1]($class)) { // array('className', 'methodName')
return TRUE;
}
- } else if ($loader instanceof \Closure) { // function($className) {..}
- if ($loader($className)) {
+ } else if ($loader instanceof \Closure) { // function($class) {..}
+ if ($loader($class)) {
return TRUE;
}
- } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
+ } else if (is_string($loader) && $loader($class)) { // "MyClass::loadClass"
return TRUE;
}
}
@@ -198,13 +198,13 @@ class ClassLoader {
* Gets the ClassLoader from the SPL autoload stack that is responsible
* for (and is able to load) the class with the given name.
*
- * @param string $className The name of the class.
+ * @param string $class The name of the class.
* @return The ClassLoader for the class or NULL if no such ClassLoader exists.
*/
- public static function getClassLoader($className) {
+ public static function getClassLoader($class) {
foreach (spl_autoload_functions() as $loader) {
if (is_array($loader) && $loader[0] instanceof ClassLoader &&
- $loader[0]->canLoadClass($className)) {
+ $loader[0]->canLoadClass($class)) {
return $loader[0];
}
}
diff --git a/backend/lib/Util/Configuration.php b/backend/lib/Util/Configuration.php
index 5db1cf1..85a329f 100644
--- a/backend/lib/Util/Configuration.php
+++ b/backend/lib/Util/Configuration.php
@@ -38,7 +38,7 @@ class Configuration {
*/
static public function write($var, $value) {
if (!is_scalar($value) && !is_array($value)) {
- throw new \Exception('sry we can\'t store this datatype in the configuration');
+ throw new \Exception('Can\'t store this datatype in the configuration');
}
$values =& self::$values;
@@ -94,13 +94,13 @@ class Configuration {
$filename .= '.php';
if (!file_exists($filename)) {
- throw new \Exception('configuration file not found: ' . $filename);
+ throw new \Exception('Configuration file not found: ' . $filename);
}
include $filename;
if (!isset($config)) {
- throw new \Exception('no variable $config found in ' . $filename);
+ throw new \Exception('No variable $config found in ' . $filename);
}
self::$values = $config;
diff --git a/backend/lib/Util/Debug.php b/backend/lib/Util/Debug.php
index e39c8f4..0dcc55d 100644
--- a/backend/lib/Util/Debug.php
+++ b/backend/lib/Util/Debug.php
@@ -24,7 +24,6 @@
namespace Volkszaehler\Util;
use Doctrine\ORM;
-
use Doctrine\DBAL\Logging;
/**
@@ -62,7 +61,7 @@ class Debug {
$em->getConnection()->getConfiguration()->setSQLLogger($this->sqlLogger);
if (isset(self::$instance)) {
- throw new \Exception('debugging has already been started. please use the static functions!');
+ throw new \Exception('Debugging has already been started. please use the static functions!');
}
self::$instance = $this;
diff --git a/backend/lib/Util/UUID.php b/backend/lib/Util/UUID.php
index 1f59e67..7ed154f 100644
--- a/backend/lib/Util/UUID.php
+++ b/backend/lib/Util/UUID.php
@@ -94,7 +94,7 @@ class UUID {
return new self(self::mintTime($node));
case 2:
// Version 2 is not supported
- throw new \Exception("Version 2 is unsupported.");
+ throw new \Exception('Version 2 is unsupported.');
case 3:
return new self(self::mintName(self::MD5, $node, $ns));
case 4:
@@ -102,19 +102,42 @@ class UUID {
case 5:
return new self(self::mintName(self::SHA1, $node, $ns));
default:
- throw new \Exception("Selected version is invalid or unsupported.");
+ throw new \Exception('Selected version is invalid or unsupported.');
}
}
/**
* Import an existing UUID
*
- * @param unkown_type $uuid
+ * @param unknown_type $uuid
*/
public static function import($uuid) {
return new self(self::makeBin($uuid, 16));
}
+ /**
+ * Performant validation of UUID's
+ *
+ * Replaces preg_match('/[a-f0-9\-]{36}/', $uuid);
+ *
+ * @param string $uuid
+ * @param boolen $short whether to allow abbreviated form of UUID's or not
+ */
+ public static function validate($uuid, $short = FALSE) {
+ $len = strlen($uuid);
+
+ for ($i = 0; $i < $len; $i++) {
+ $char = $uuid[$i];
+ $ord = ord($char);
+
+ if (($ord > 57 || $ord < 48) && ($ord > 70 || $ord < 65) && ($ord > 102 || $ord < 97) && $ord != 45) {
+ return FALSE; // char not allowed
+ }
+ }
+
+ return ($short) ? $len <= 36 : $len == 36; // check for strlen
+ }
+
/**
* Compares the binary representations of two UUIDs.
* The comparison will return TRUE if they are bit-exact,
@@ -133,43 +156,42 @@ class UUID {
public function __get($var) {
switch($var) {
- case "bytes":
+ case 'bytes':
return $this->bytes;
- case "hex":
+ case 'hex':
return bin2hex($this->bytes);
- case "string":
+ case 'string':
return $this->__toString();
- case "urn":
- return "urn:uuid:".$this->__toString();
- case "version":
+ case 'urn':
+ return 'urn:uuid:' . $this->__toString();
+ case 'version':
return ord($this->bytes[6]) >> 4;
- case "variant":
+ case 'variant':
$byte = ord($this->bytes[8]);
- if ($byte >= self::varRes)
- return 3;
- if ($byte >= self::varMS)
- return 2;
- if ($byte >= self::varRFC)
- return 1;
- else
- return 0;
- case "node":
- if (ord($this->bytes[6])>>4==1)
- return bin2hex(substr($this->bytes,10));
- else
- return NULL;
- case "time":
+ if ($byte >= self::varRes) return 3;
+ if ($byte >= self::varMS) return 2;
+ if ($byte >= self::varRFC) return 1;
+ else return 0;
+ case 'node':
+ if (ord($this->bytes[6])>>4==1) {
+ return bin2hex(substr($this->bytes,10));
+ }
+ else {
+ return NULL;
+ }
+ case 'time':
if (ord($this->bytes[6])>>4==1) {
// Restore contiguous big-endian byte order
$time = bin2hex($this->bytes[6].$this->bytes[7].$this->bytes[4].$this->bytes[5].$this->bytes[0].$this->bytes[1].$this->bytes[2].$this->bytes[3]);
// Clear version flag
- $time[0] = "0";
+ $time[0] = '0';
// Do some reverse arithmetic to get a Unix timestamp
$time = (hexdec($time) - self::interval) / 10000000;
return $time;
}
- else
- return NULL;
+ else {
+ return NULL;
+ }
default:
return NULL;
}
@@ -177,76 +199,104 @@ class UUID {
protected function __construct($uuid) {
if (strlen($uuid) != 16) {
- throw new \Exception("Input must be a 128-bit integer.");
+ throw new \Exception('Input must be a 128-bit integer.');
}
$this->bytes = $uuid;
// Optimize the most common use
$this->string =
- bin2hex(substr($uuid,0,4))."-".
- bin2hex(substr($uuid,4,2))."-".
- bin2hex(substr($uuid,6,2))."-".
- bin2hex(substr($uuid,8,2))."-".
+ bin2hex(substr($uuid,0,4)).'-'.
+ bin2hex(substr($uuid,4,2)).'-'.
+ bin2hex(substr($uuid,6,2)).'-'.
+ bin2hex(substr($uuid,8,2)).'-'.
bin2hex(substr($uuid,10,6));
}
+ /**
+ * Generates a Version 1 UUID.
+ * These are derived from the time at which they were generated.
+ *
+ * @param $node
+ */
protected static function mintTime($node = NULL) {
- /* Generates a Version 1 UUID.
- These are derived from the time at which they were generated. */
// Get time since Gregorian calendar reform in 100ns intervals
// This is exceedingly difficult because of PHP's (and pack()'s)
// integer size limits.
// Note that this will never be more accurate than to the microsecond.
- $time = microtime(1) * 10000000 + self::interval;
+ $time = microtime(TRUE) * 10000000 + self::interval;
+
// Convert to a string representation
- $time = sprintf("%F", $time);
- preg_match("/^\d+/", $time, $time); //strip decimal point
+ $time = sprintf('%F', $time);
+ preg_match('/^\d+/', $time, $time); //strip decimal point
+
// And now to a 64-bit binary representation
$time = base_convert($time[0], 10, 16);
- $time = pack("H*", str_pad($time, 16, "0", STR_PAD_LEFT));
+ $time = pack('H*', str_pad($time, 16, '0', STR_PAD_LEFT));
+
// Reorder bytes to their proper locations in the UUID
$uuid = $time[4].$time[5].$time[6].$time[7].$time[2].$time[3].$time[0].$time[1];
+
// Generate a random clock sequence
$uuid .= Random::getBytes(2);
+
// set variant
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
+
// set version
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version1);
+
// Set the final 'node' parameter, a MAC address
- if ($node)
- $node = self::makeBin($node, 6);
- if (!$node) {
+ if ($node) {
+ $node = self::makeBin($node, 6);
+ }
+ else {
// If no node was provided or if the node was invalid,
// generate a random MAC address and set the multicast bit
$node = Random::getBytes(6);
- $node[0] = pack("C", ord($node[0]) | 1);
+ $node[0] = pack('C', ord($node[0]) | 1);
}
+
$uuid .= $node;
return $uuid;
}
+ /**
+ * Generate a Version 4 UUID.
+ * These are derived soly from random numbers.
+ */
protected static function mintRand() {
- /* Generate a Version 4 UUID.
- These are derived soly from random numbers. */
// generate random fields
$uuid = Random::getBytes(16);
+
// set variant
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
+
// set version
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version4);
+
return $uuid;
}
+ /**
+ * Generates a Version 3 or Version 5 UUID.
+ * These are derived from a hash of a name and its namespace, in binary form.
+ *
+ * @param integer $ver the version (MD5 or SHA1)
+ * @param string $node the name string
+ * $param string $ns the namespace
+ */
protected static function mintName($ver, $node, $ns) {
- /* Generates a Version 3 or Version 5 UUID.
- These are derived from a hash of a name and its namespace, in binary form. */
- if (!$node)
- throw new \Exception("A name-string is required for Version 3 or 5 UUIDs.");
+ if (!$node) {
+ throw new \Exception('A name-string is required for Version 3 or 5 UUIDs.');
+ }
+
// if the namespace UUID isn't binary, make it so
$ns = self::makeBin($ns, 16);
- if (!$ns)
- throw new \Exception("A binary namespace is required for Version 3 or 5 UUIDs.");
+ if (!$ns) {
+ throw new \Exception('A binary namespace is required for Version 3 or 5 UUIDs.');
+ }
+
switch($ver) {
case self::MD5:
$version = self::version3;
@@ -257,27 +307,43 @@ class UUID {
$uuid = substr(sha1($ns.$node,1),0, 16);
break;
}
+
// set variant
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
+
// set version
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | $version);
+
return ($uuid);
}
+ /**
+ * Insure that an input string is either binary or hexadecimal.
+ * Returns binary representation, or FALSE on failure.
+ *
+ * @param unkown_type $str
+ * @param integer $len
+ */
protected static function makeBin($str, $len) {
- /* Insure that an input string is either binary or hexadecimal.
- Returns binary representation, or FALSE on failure. */
- if ($str instanceof self)
- return $str->bytes;
- if (strlen($str)==$len)
- return $str;
- else
- $str = preg_replace("/^urn:uuid:/is", "", $str); // strip URN scheme and namespace
- $str = preg_replace("/[^a-f0-9]/is", "", $str); // strip non-hex characters
- if (strlen($str) != ($len * 2))
- return FALSE;
- else
- return pack("H*", $str);
+ if ($str instanceof self) {
+ return $str->bytes;
+ }
+
+ if (strlen($str) == $len) {
+ return $str;
+ }
+ else {
+ $str = preg_replace('/^urn:uuid:/is', '', $str); // strip URN scheme and namespace
+ }
+
+ $str = preg_replace('/[^a-f0-9]/is', '', $str); // strip non-hex characters
+
+ if (strlen($str) != ($len * 2)) {
+ return FALSE;
+ }
+ else {
+ return pack('H*', $str);
+ }
}
}
diff --git a/share/tests/ajax.php b/share/tests/ajax.php
index 884cad7..0eb796e 100644
--- a/share/tests/ajax.php
+++ b/share/tests/ajax.php
@@ -36,7 +36,7 @@