src/InfluxDB/Point.php
<?php
namespace InfluxDB;
use InfluxDB\Database\Exception as DatabaseException;
/**
* Class Point
*
* @package InfluxDB
*/
class Point
{
/**
* @var string
*/
protected $measurement;
/**
* @var array
*/
protected $tags = [];
/**
* @var array
*/
protected $fields = [];
/**
* @var string
*/
protected $timestamp;
/**
* The timestamp is optional. If you do not specify a timestamp the server’s
* local timestamp will be used
*
* @param string $measurement
* @param float $value
* @param array $tags
* @param array $additionalFields
* @param int $timestamp
* @throws DatabaseException
*/
public function __construct(
$measurement,
$value = null,
array $tags = array(),
array $additionalFields = array(),
$timestamp = null
) {
if (empty($measurement)) {
throw new DatabaseException('Invalid measurement name provided');
}
$this->measurement = (string) $measurement;
$this->setTags($tags);
$fields = $additionalFields;
if ($value !== null) {
$fields['value'] = $value;
}
$this->setFields($fields);
if ($timestamp && !$this->isValidTimeStamp($timestamp)) {
throw new DatabaseException(sprintf('%s is not a valid timestamp', $timestamp));
}
$this->timestamp = $timestamp;
}
/**
* @see: https://influxdb.com/docs/v0.9/concepts/reading_and_writing_data.html
*
* Should return this format
* 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
*/
public function __toString()
{
$string = $this->measurement;
if (count($this->tags) > 0) {
$string .= ',' . $this->arrayToString($this->escapeCharacters($this->tags, true));
}
$string .= ' ' . $this->arrayToString($this->escapeCharacters($this->fields, false));
if ($this->timestamp) {
$string .= ' '.$this->timestamp;
}
return $string;
}
/**
* @return string
*/
public function getMeasurement()
{
return $this->measurement;
}
/**
* @param string $measurement
*/
public function setMeasurement($measurement)
{
$this->measurement = $measurement;
}
/**
* @return array
*/
public function getTags()
{
return $this->tags;
}
/**
* @param array $tags
*/
public function setTags($tags)
{
foreach ($tags as &$tag) {
if ($tag === '') {
$tag = '""';
} elseif (is_bool($tag)) {
$tag = ($tag ? 'true' : 'false');
} elseif (is_null($tag)) {
$tag = 'null';
}
}
$this->tags = $tags;
}
/**
* @return array
*/
public function getFields()
{
return $this->fields;
}
/**
* @param array $fields
*/
public function setFields($fields)
{
foreach ($fields as &$field) {
if (is_int($field)) {
$field = sprintf('%di', $field);
} elseif (is_string($field)) {
$field = $this->escapeFieldValue($field);
} elseif (is_bool($field)) {
$field = ($field ? 'true' : 'false');
} elseif (is_null($field)) {
$field = $this->escapeFieldValue('null');
}
}
$this->fields = $fields;
}
/**
* @return string
*/
public function getTimestamp()
{
return $this->timestamp;
}
/**
* @param string $timestamp
*/
public function setTimestamp($timestamp)
{
$this->timestamp = $timestamp;
}
/**
* Escapes invalid characters in both the array key and optionally the array value
*
* @param array $arr
* @param bool $escapeValues
* @return array
*/
private function escapeCharacters(array $arr, $escapeValues)
{
$returnArr = [];
foreach ($arr as $key => $value) {
$returnArr[$this->addSlashes($key)] = $escapeValues ? $this->addSlashes($value) : $value;
}
return $returnArr;
}
/*
* Returns string double-quoted and double-quotes escaped per Influx write protocol syntax
*
* @param string $value
* @return string
*/
private function escapeFieldValue($value)
{
$escapedValue = str_replace('"', '\"', $value);
return sprintf('"%s"', $escapedValue);
}
/**
* Returns strings with space, comma, or equals sign characters backslashed per Influx write protocol syntax
*
* @param string $value
* @return string
*/
private function addSlashes($value)
{
return str_replace([
' ',
',',
'='
],[
'\ ',
'\,',
'\='
], $value);
}
/**
* @param array $arr
* @return string
*/
private function arrayToString(array $arr)
{
$strParts = [];
$origLocale = setlocale(LC_NUMERIC, 0);
// Use the POSIX locale which defines the `decimal_point` separator as `.`
setlocale(LC_NUMERIC, 'POSIX');
foreach ($arr as $key => $value) {
$strParts[] = sprintf('%s=%s', $key, $value);
}
setlocale(LC_NUMERIC, $origLocale);
return implode(',', $strParts);
}
/**
* @param int $timestamp
* @return bool
*/
private function isValidTimeStamp($timestamp)
{
// if the code is run on a 32bit system, loosely check if the timestamp is a valid numeric
if (PHP_INT_SIZE === 4 && is_numeric($timestamp)) {
return true;
}
if (!is_numeric($timestamp)) {
return false;
}
if ((int)$timestamp != $timestamp) {
return false;
}
if (!($timestamp <= PHP_INT_MAX && $timestamp >= ~PHP_INT_MAX)) {
return false;
}
return true;
}
}