Subversion Repositories oidinfo_api

Compare Revisions

No changes between revisions

Regard whitespace Rev 2 → Rev 3

/trunk/csv_lookup_server_example/Makefile
1,0 → 0,0
link ../../confidential/jobs/0077_csv_lookup_server/v2/Makefile
 
all: oid_lookup_srv
 
oid_lookup_srv: oid_lookup_srv.cpp
g++ -std=c++11 -lgmpxx -Wall -fopenmp -O3 -mtune=native -pipe -O3 -mtune=native -o oid_lookup_srv oid_lookup_srv.cpp
 
clean:
rm -f *.o
# TODO: if [ -f ... ] then rm
rm oid_lookup_srv
Property changes:
Deleted: svn:special
-*
\ No newline at end of property
/trunk/csv_lookup_server_example/oid_lookup_srv
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:executable
+*
\ No newline at end of property
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
Deleted: svn:special
-*
\ No newline at end of property
/trunk/csv_lookup_server_example/oid_lookup_srv.cpp
1,0 → 0,0
link ../../confidential/jobs/0077_csv_lookup_server/v2/oid_lookup_srv.cpp
// **************************************************
// ** OID CSV Lookup Server 1.1 **
// ** (c) 2016-2019 ViaThinkSoft, Daniel Marschall **
// **************************************************
 
// todo: log verbosity + datetime
// todo: publish at codelib
// todo: server hat sich einfach so beendet... "read: connection reset by peer"
// todo: 2019-02-24 service was booted together with the system, and i got "0 OIDs loaded". why???
// todo: create vnag monitor that checks if this service is OK
 
#include "oid_lookup_srv.h"
 
unordered_set<string> lines;
 
int loadfile(const string &filename) {
int cnt = 0;
 
ifstream infile(filename);
string line;
while (getline(infile, line)) {
lines.insert(line);
++cnt;
}
infile.close();
 
fprintf(stdout, "Loaded %d OIDs from %s\n", cnt, filename.c_str());
 
return cnt;
}
 
bool stringAvailable(const string &str) {
return lines.find(str) != lines.end();
}
 
// Template of this code: http://www.gnu.org/software/libc/manual/html_node/Server-Example.html
// http://www.gnu.org/software/libc/manual/html_node/Inet-Example.html#Inet-Example
 
struct con_descriptor {
time_t last_activity;
struct sockaddr_in clientname;
int queries;
time_t connect_ts;
};
 
con_descriptor cons[FD_SETSIZE];
 
int read_from_client(int filedes) {
char buffer[MAXMSG];
int nbytes;
 
nbytes = read(filedes, buffer, MAXMSG);
if (nbytes < 0) {
/* Read error. */
//perror("read");
//exit(EXIT_FAILURE);
return -1;
} else if (nbytes == 0) {
/* End-of-file. */
return -1;
} else {
/* Data read. */
 
for (int i=0; i<MAXMSG; ++i) {
if ((buffer[i] == 13) || (buffer[i] == 10)) buffer[i] = 0;
}
 
if (strcmp(buffer, "bye") == 0) {
fprintf(stdout, "%s:%d[%d] Client said good bye.\n", inet_ntoa(cons[filedes].clientname.sin_addr), ntohs(cons[filedes].clientname.sin_port), filedes);
return -1;
} else {
cons[filedes].queries++;
 
// fprintf(stdout, "%s:%d[%d] Query #%d: %s\n", inet_ntoa(cons[filedes].clientname.sin_addr), ntohs(cons[filedes].clientname.sin_port), filedes, cons[filedes].queries, buffer);
 
if (stringAvailable(buffer)) {
write(filedes, "1\n", 2);
} else {
write(filedes, "0\n", 2);
}
return 0;
}
}
}
 
int fd_set_isset_count(const fd_set &my_fd_set) {
int cnt = 0;
for (int fd = 0; fd < FD_SETSIZE; ++fd) {
if (FD_ISSET(fd, &my_fd_set)) {
++cnt;
}
}
return cnt;
}
 
int loadCSVs() {
return loadfile("oid_table.csv");
}
 
void initConsArray() {
for (int i=0; i<FD_SETSIZE; ++i) {
cons[i].last_activity = 0;
memset(&cons[i].clientname, 0, sizeof(sockaddr_in));
cons[i].queries = 0;
}
}
 
int make_socket(uint16_t port) {
int sock;
struct sockaddr_in name;
 
/* Create the socket. */
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
 
int enable = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
fprintf(stderr, "ERROR: setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
}
 
/* Give the socket a name. */
name.sin_family = AF_INET;
name.sin_port = htons (port);
name.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
 
return sock;
}
 
int main(void) {
// extern int make_socket(uint16_t port);
int sock;
fd_set active_fd_set, read_fd_set;
 
fprintf(stdout, "OID CSV Lookup Server 1.0 (c)2016-2019 ViaThinkSoft\n");
fprintf(stdout, "Listening at port: %d\n", PORT);
fprintf(stdout, "Max connections: %d\n", FD_SETSIZE);
 
initConsArray();
 
int loadedOIDs = loadCSVs();
time_t csvLoad = time(NULL);
 
/* Create the socket and set it up to accept connections. */
sock = make_socket(PORT);
if (listen(sock, 1) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
 
/* Initialize the set of active sockets. */
FD_ZERO(&active_fd_set);
FD_SET(sock, &active_fd_set);
 
while (1) {
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
 
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0; // Not init'ing this can cause strange errors
 
int retval = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tv);
 
if (retval < 0) {
perror("select");
exit(EXIT_FAILURE);
} else if (retval == 0) {
// fprintf(stdout, "Nothing received\n");
} else {
/* Service all the sockets with input pending. */
for (int i=0; i < FD_SETSIZE; ++i) {
if (FD_ISSET (i, &read_fd_set)) {
if (i == sock) {
/* Connection request on original socket. */
int new_fd;
struct sockaddr_in clientname;
socklen_t size = sizeof(clientname);
new_fd = accept(sock, (struct sockaddr *) &clientname, &size);
if (new_fd < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
FD_SET(new_fd, &active_fd_set);
 
cons[new_fd].clientname = clientname;
cons[new_fd].connect_ts = time(NULL);
 
if (loadedOIDs == 0) {
loadedOIDs = loadCSVs();
if (loadedOIDs == 0) {
fprintf(stderr, "%s:%d[%d] Service temporarily unavailable (OID list empty)\n", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_fd);
close(new_fd);
FD_CLR(new_fd, &active_fd_set);
}
}
 
if (fd_set_isset_count(active_fd_set)-1 > MAX_CONNECTIONS) { // -1 is because we need to exclude the listening socket (i=sock) which is not a connected client
fprintf(stderr, "%s:%d[%d] Rejected because too many connections are open\n", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_fd);
close(new_fd);
FD_CLR(new_fd, &active_fd_set);
} else {
fprintf(stdout, "%s:%d[%d] Connected\n", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_fd);
}
 
cons[new_fd].last_activity = time(NULL);
cons[new_fd].queries = 0;
} else {
/* Data arriving on an already-connected socket. */
cons[i].last_activity = time(NULL);
if (read_from_client(i) < 0) {
fprintf(stdout, "%s:%d[%d] Connection closed after %d queries in %lu seconds.\n", inet_ntoa(cons[i].clientname.sin_addr), ntohs(cons[i].clientname.sin_port), i, cons[i].queries, time(NULL)-cons[i].connect_ts);
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
}
}
 
/* Check if we need to reload the CSV */
if (time(NULL)-csvLoad >= CSVRELOADINTERVAL) {
loadCSVs();
csvLoad = time(NULL);
}
 
/* Check if we can close connections due to timeout */
for (int i=0; i < FD_SETSIZE; ++i) {
if (FD_ISSET(i, &active_fd_set)) {
if (i == sock) continue;
if (time(NULL)-cons[i].last_activity >= CONNECTION_TIMEOUT) {
fprintf(stdout, "%s:%d[%d] Connection timeout.\n", inet_ntoa(cons[i].clientname.sin_addr), ntohs(cons[i].clientname.sin_port), i);
fprintf(stdout, "%s:%d[%d] Connection closed after %d queries in %lu seconds.\n", inet_ntoa(cons[i].clientname.sin_addr), ntohs(cons[i].clientname.sin_port), i, cons[i].queries, time(NULL)-cons[i].connect_ts);
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
}
}
Property changes:
Added: svn:mime-type
+text/x-c++src
\ No newline at end of property
Deleted: svn:special
-*
\ No newline at end of property
/trunk/csv_lookup_server_example/oid_lookup_srv.h
1,0 → 0,0
link ../../confidential/jobs/0077_csv_lookup_server/v2/oid_lookup_srv.h
 
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <netdb.h>
#include <unistd.h>
#include <sstream>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <cstring>
 
#define PORT 49500 // TODO: konfigurierbar machen / command line
#define MAXMSG 512
 
#define MAX_CONNECTIONS 100
#define CONNECTION_TIMEOUT 60
 
// In seconds. 21600 = 6 hours
#define CSVRELOADINTERVAL 21600
 
#include <unordered_set>
 
using namespace std;
 
Property changes:
Added: svn:mime-type
+text/x-chdr
\ No newline at end of property
Deleted: svn:special
-*
\ No newline at end of property
/trunk/oid_utils.inc.phps
1,0 → 0,0
link ../../code/php/oid_utils.inc.phps
<?php
 
/*
* OID-Utilities for PHP
* Copyright 2011-2019 Daniel Marschall, ViaThinkSoft
* Version 2019-03-25
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
// All functions in this library are compatible with leading zeroes (not recommended) and leading dots
 
// TODO: change the function names, so that they have a uniform naming schema, and rename "oid identifier" into "asn.1 alphanumeric identifier"
// TODO: Function for finding a shared ancestor, e.g. oid_shared_ancestor('2.999.1.2.3', '2.999.4.5') == '2.999'
 
define('OID_DOT_FORBIDDEN', 0);
define('OID_DOT_OPTIONAL', 1);
define('OID_DOT_REQUIRED', 2);
 
/**
* Checks if an OID has a valid dot notation.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $oid (string)<br />
* An OID in dot notation.
* @param $allow_leading_zeroes (bool)<br />
* true of leading zeroes are allowed or not.
* @param $allow_leading_dot (bool)<br />
* true of leading dots are allowed or not.
* @return (bool) true if the dot notation is valid.
**/
function oid_valid_dotnotation($oid, $allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) {
$regex = oid_validation_regex($allow_leading_zeroes, $allow_leading_dot, $min_len);
 
return preg_match($regex, $oid, $m) ? true : false;
}
 
/**
* Returns a full regular expression to validate an OID in dot-notation
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $allow_leading_zeroes (bool)<br />
* true of leading zeroes are allowed or not.
* @param $allow_leading_dot (bool)<br />
* true of leading dots are allowed or not.
* @return (string) The regular expression
**/
function oid_validation_regex($allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) {
$leading_dot_policy = $allow_leading_dot ? OID_DOT_OPTIONAL : OID_DOT_FORBIDDEN;
 
$part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy);
 
return '@^'.$part_regex.'$@';
}
 
/**
* Returns a partial regular expression which matches valid OIDs in dot notation.
* It can be inserted into regular expressions.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $min_len (int)<br />
* 0="." and greater will be recognized, but not ""<br />
* 1=".2" and greater will be recognized<br />
* 2=".2.999" and greater will be recognized (default)<br />
* etc.
* @param $allow_leading_zeroes (bool)<br />
* true: ".2.0999" will be recognized<br />
* false: ".2.0999" won't be recognized (default)
* @param $leading_dot_policy (int)<br />
* 0 (OID_DOT_FORBIDDEN): forbidden<br />
* 1 (OID_DOT_OPTIONAL) : optional (default)<br />
* 2 (OID_DOT_REQUIRED) : enforced
* @return (string) A regular expression which matches OIDs in dot notation
**/
function oid_part_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL) {
switch ($leading_dot_policy) {
case 0: // forbidden
$lead_dot = '';
break;
case 1: // optional
$lead_dot = '\\.{0,1}';
break;
case 2: // enforced
$lead_dot = '\\.';
break;
default:
assert(false);
break;
}
 
$lead_zero = $allow_leading_zeroes ? '0*' : '';
$zero_till_thirtynine = '(([0-9])|([1-3][0-9]))'; // second arc is limited to 0..39 if root arc is 0..1
$singledot_option = ($min_len == 0) && ($leading_dot_policy != OID_DOT_FORBIDDEN) ? '|\\.' : '';
$only_root_option = ($min_len <= 1) ? '|('.$lead_dot.$lead_zero.'[0-2])' : '';
 
$regex = '
(
(
(
('.$lead_dot.$lead_zero.'[0-1])
\\.'.$lead_zero.$zero_till_thirtynine.'
(\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-2).',}
)|(
('.$lead_dot.$lead_zero.'[2])
(\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-1).',}
)
'.$only_root_option.'
'.$singledot_option.'
)
)';
 
// Remove the indentations which are used to maintain this large regular expression in a human friendly way
$regex = str_replace("\n", '', $regex);
$regex = str_replace("\r", '', $regex);
$regex = str_replace("\t", '', $regex);
$regex = str_replace(' ', '', $regex);
 
return $regex;
}
 
/**
* Searches all OIDs in $text and outputs them as array.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $text (string)<br />
* The text to be parsed
* @param $min_len (int)<br />
* 0="." and greater will be recognized, but not ""<br />
* 1=".2" and greater will be recognized<br />
* 2=".2.999" and greater will be recognized (default)<br />
* etc.
* @param $allow_leading_zeroes (bool)<br />
* true: ".2.0999" will be recognized<br />
* false: ".2.0999" won't be recognized (default)
* @param $leading_dot_policy (int)<br />
* 0 (OID_DOT_FORBIDDEN): forbidden<br />
* 1 (OID_DOT_OPTIONAL) : optional (default)<br />
* 2 (OID_DOT_REQUIRED) : enforced
* @param $requires_whitespace_delimiters (bool)<br />
* true: "2.999" will be recognized, as well as " 2.999 " (default)<br />
* false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates)
* @return (array<string>) An array of OIDs in dot notation
**/
function parse_oids($text, $min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) {
$regex = oid_detection_regex($min_len, $allow_leading_zeroes, $leading_dot_policy, $requires_whitespace_delimiters);
 
preg_match_all($regex, $text, $matches);
return $matches[1];
}
 
/**
* Returns a full regular expression for detecting OIDs in dot notation inside a text.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $min_len (int)<br />
* 0="." and greater will be recognized, but not ""<br />
* 1=".2" and greater will be recognized<br />
* 2=".2.999" and greater will be recognized (default)<br />
* etc.
* @param $allow_leading_zeroes (bool)<br />
* true: ".2.0999" will be recognized<br />
* false: ".2.0999" won't be recognized (default)
* @param $leading_dot_policy (int)<br />
* 0 (OID_DOT_FORBIDDEN): forbidden<br />
* 1 (OID_DOT_OPTIONAL) : optional (default)<br />
* 2 (OID_DOT_REQUIRED) : enforced
* @param $requires_whitespace_delimiters (bool)<br />
* true: "2.999" will be recognized, as well as " 2.999 " (default)<br />
* false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates)
* @return (string) The regular expression
**/
function oid_detection_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) {
if ($requires_whitespace_delimiters) {
// A fully qualified regular expression which can be used by preg_match()
$begin_condition = '(?<=^|\\s)';
$end_condition = '(?=\\s|$)';
} else {
// A partial expression which can be used inside another regular expression
$begin_condition = '(?<![\d])';
$end_condition = '(?![\d])';
}
 
$part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy);
 
return '@'.$begin_condition.$part_regex.$end_condition.'@';
}
 
/**
* Returns the parent of an OID in dot notation or the OID itself, if it is the root.<br />
* Leading dots and leading zeroes are tolerated.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-16
* @param $oid (string)<br />
* An OID in dot notation.
* @return (string) The parent OID in dot notation.
**/
function oid_up($oid) {
$oid = sanitizeOID($oid, 'auto');
if ($oid === false) return false;
 
$p = strrpos($oid, '.');
if ($p === false) return $oid;
if ($p == 0) return '.';
 
return substr($oid, 0, $p);
}
 
/**
* Outputs the depth of an OID.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $oid (string) An OID in dot notation (with or without leading dot)
* @return (int) The depth of the OID, e.g. 2.999 and .2.999 has the length 2.
**/
function oid_len($oid) {
if ($oid == '') return 0;
if ($oid[0] == '.') $oid = substr($oid, 1);
return substr_count($oid, '.')+1;
}
function oid_depth($oid) {
return oid_len($oid);
}
 
/**
* Lists all parents of an OID.
* This function tolerates leading dots. The parent of '.' stays '.'.
* The OID will not be checked for validity!
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-17
* @param $oid (string)<br />
* An OID in dot notation.
* @return (array<string>) An array with all parent OIDs.
**/
function oid_parents($oid) {
$parents = array();
 
while (oid_len($oid) > 1) {
$oid = oid_up($oid);
$parents[] = $oid;
}
 
if (substr($oid, 0, 1) == '.') $parents[] = '.';
 
return $parents;
}
 
/*
assert(oid_parents('.1.2.999') == array('.1.2', '.1', '.'));
assert(oid_parents('1.2.999') == array('1.2', '1'));
assert(oid_parents('.') == array('.'));
assert(oid_parents('') == array());
*/
 
/**
* Sorts an array containing OIDs in dot notation.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $ary (array<string>)<br />
* An array of OIDs in dot notation.<br />
* This array will be changed by this method.
* @param $output_with_leading_dot (bool)<br />
* true: The array will be normalized to OIDs with a leading dot.
* false: The array will be normalized to OIDs without a leading dot. (default)
* @return Nothing
**/
function oidSort(&$ary, $output_with_leading_dot=false) {
$out = array();
 
$none = $output_with_leading_dot ? '.' : '';
 
$d = array();
foreach ($ary as &$oid) {
if (($oid == '') || ($oid == '.')) {
$out[] = $none;
} else {
$oid = sanitizeOID($oid, 'auto'); // strike leading zeroes
$bry = explode('.', $oid, 2);
$firstarc = $bry[0];
$rest = (isset($bry[1])) ? $bry[1] : '';
$d[$firstarc][] = $rest;
}
}
unset($oid);
ksort($d);
 
foreach ($d as $firstarc => &$data) {
oidSort($data);
foreach ($data as &$rest) {
$out[] = ($output_with_leading_dot ? '.' : '')."$firstarc" . (($rest != $none) ? ".$rest" : '');
}
}
unset($data);
 
$ary = $out;
}
 
/**
* Removes leading zeroes from an OID in dot notation.
* @author Daniel Marschall, ViaThinkSoft
* @version 2015-08-17
* @param $oid (string)<br />
* An OID in dot notation.
* @param $leading_dot (bool)<br />
* true: The OID is valid, if it contains a leading dot.<br />
* false (default): The OID is valid, if it does not contain a leading dot.
* 'auto: Allow both
* @return (mixed) The OID without leading dots, or <code>false</code> if the OID is syntactically wrong.
**/
$oid_sanitize_cache = array();
function sanitizeOID($oid, $leading_dot=false) {
if ($leading_dot) $leading_dot = substr($oid,0,1) == '.';
 
// We are using a cache, since this function is used very often by OID+
global $oid_sanitize_cache;
$v = ($leading_dot ? 'T' : 'F').$oid;
if (isset($oid_sanitize_cache[$v])) return $oid_sanitize_cache[$v];
 
if ($leading_dot) {
if ($oid == '.') return '';
} else {
if ($oid == '') return '';
}
 
$out = '';
$ary = explode('.', $oid);
foreach ($ary as $n => &$a) {
if (($leading_dot) && ($n == 0)) {
if ($a != '') return false;
continue;
}
 
if (!ctype_digit($a)) return false; // does contain something other than digits
 
// strike leading zeroes
$a = preg_replace("@^0+@", '', $a);
if ($a == '') $a = 0;
 
if (($leading_dot) || ($n != 0)) $out .= '.';
$out .= $a;
}
unset($a);
unset($ary);
 
$oid_sanitize_cache[$v] = $out;
return $out;
}
 
/**
* Shows the top arc of an OID.
* This function tolerates leading dots.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-16
* @param $oid (string)<br />
* An OID in dot notation.
* @return (mixed) The top arc of the OID or empty string if it is already the root ('.')
**/
function oid_toparc($oid) {
$leadingdot = substr($oid,0,1) == '.';
 
$oid = sanitizeOID($oid, $leadingdot);
if ($oid === false) return false;
 
if (!$leadingdot) $oid = '.'.$oid;
 
$p = strrpos($oid, '.');
if ($p === false) return false;
$r = substr($oid, $p+1);
 
if ($leadingdot) {
# if ($r == '') return '.';
return $r;
} else {
return substr($r, 1);
}
}
 
/**
* Calculates the distance between two OIDs.
* This function tolerates leading dots and leading zeroes.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-20
* @param $a (string)<br />
* An OID.
* @param $b (string)<br />
* An OID.
* @return (string) false if both OIDs do not have a child-parent or parent-child relation, e.g. oid_distance('2.999.1.2.3', '2.999.4.5') = false, or if one of the OIDs is syntactially invalid<br />
* >0 if $a is more specific than $b , e.g. oid_distance('2.999.1.2', '2.999') = 2<br />
* <0 if $a is more common than $b , e.g. oid_distance('2.999', '2.999.1.2') = -2
**/
function oid_distance($a, $b) {
if (substr($a,0,1) == '.') $a = substr($a,1);
if (substr($b,0,1) == '.') $b = substr($b,1);
 
$a = sanitizeOID($a, false);
if ($a === false) return false;
$b = sanitizeOID($b, false);
if ($b === false) return false;
 
$ary = explode('.', $a);
$bry = explode('.', $b);
 
$min_len = min(count($ary), count($bry));
 
for ($i=0; $i<$min_len; $i++) {
if ($ary[$i] != $bry[$i]) return false;
}
 
return count($ary) - count($bry);
}
 
/*
assert(oid_distance('2.999.1.2.3', '2.999.4.5') === false);
assert(oid_distance('2.999.1.2', '2.999') === 2);
assert(oid_distance('2.999', '2.999.1.2') === -2);
*/
 
/**
* Adds a leading dot to an OID.
* Leading zeroes are tolerated.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-20
* @param $oid (string)<br />
* An OID.
* @return (string) The OID with a leading dot or false if the OID is syntactially wrong.
**/
function oid_add_leading_dot($oid) {
$oid = sanitizeOID($oid, 'auto');
if ($oid === false) return false;
 
if ($oid[0] != '.') $oid = '.'.$oid;
return $oid;
}
 
/**
* Removes a leading dot to an OID.
* Leading zeroes are tolerated.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-20
* @param $oid (string)<br />
* An OID.
* @return (string) The OID without a leading dot or false if the OID is syntactially wrong.
**/
function oid_remove_leading_dot($oid) {
$oid = sanitizeOID($oid, 'auto');
if ($oid === false) return false;
 
if (substr($oid,0,1) == '.') $oid = substr($oid, 1);
return $oid;
}
 
 
# === OID-IRI NOTATION FUNCTIONS ===
 
if (!function_exists('mb_ord')) {
# http://stackoverflow.com/a/24755772/3544341
function mb_ord($char, $encoding = 'UTF-8') {
if ($encoding === 'UCS-4BE') {
list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char);
return $ord;
} else {
return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE');
}
}
}
 
function iri_char_valid($c, $firstchar, $lastchar) {
// see Rec. ITU-T X.660, clause 7.5
 
if (($firstchar || $lastchar) && ($c == '-')) return false;
 
if ($c == '-') return true;
if ($c == '.') return true;
if ($c == '_') return true;
if ($c == '~') return true;
if (($c >= '0') && ($c <= '9') && (!$firstchar)) return true;
if (($c >= 'A') && ($c <= 'Z')) return true;
if (($c >= 'a') && ($c <= 'z')) return true;
 
$v = mb_ord($c);
 
if (($v >= 0x000000A0) && ($v <= 0x0000DFFE)) return true;
if (($v >= 0x0000F900) && ($v <= 0x0000FDCF)) return true;
if (($v >= 0x0000FDF0) && ($v <= 0x0000FFEF)) return true;
if (($v >= 0x00010000) && ($v <= 0x0001FFFD)) return true;
if (($v >= 0x00020000) && ($v <= 0x0002FFFD)) return true;
if (($v >= 0x00030000) && ($v <= 0x0003FFFD)) return true;
if (($v >= 0x00040000) && ($v <= 0x0004FFFD)) return true;
if (($v >= 0x00050000) && ($v <= 0x0005FFFD)) return true;
if (($v >= 0x00060000) && ($v <= 0x0006FFFD)) return true;
if (($v >= 0x00070000) && ($v <= 0x0007FFFD)) return true;
if (($v >= 0x00080000) && ($v <= 0x0008FFFD)) return true;
if (($v >= 0x00090000) && ($v <= 0x0009FFFD)) return true;
if (($v >= 0x000A0000) && ($v <= 0x000AFFFD)) return true;
if (($v >= 0x000B0000) && ($v <= 0x000BFFFD)) return true;
if (($v >= 0x000C0000) && ($v <= 0x000CFFFD)) return true;
if (($v >= 0x000D0000) && ($v <= 0x000DFFFD)) return true;
if (($v >= 0x000E1000) && ($v <= 0x000EFFFD)) return true;
 
// Note: Rec. ITU-T X.660, clause 7.5.3 would also forbid ranges which are marked in ISO/IEC 10646 as "(This position shall not be used)"
// But tool implementers should be tolerate them, since these limitations can be removed in future.
 
return false;
}
 
function iri_arc_valid($arc, $allow_numeric=true) {
if ($arc == '') return false;
 
if ($allow_numeric && preg_match('@^(\\d+)$@', $arc, $m)) return true; # numeric arc
 
// Question: Should we strip RTL/LTR characters?
 
if (mb_substr($arc, 2, 2) == '--') return false; // see Rec. ITU-T X.660, clause 7.5.4
 
$array = array();
preg_match_all('/./u', $arc, $array, PREG_SET_ORDER);
$len = count($array);
foreach ($array as $i => $char) {
if (!iri_char_valid($char[0], $i==0, $i==$len-1)) return false;
}
 
return true;
}
 
/**
* Checks if an IRI identifier is valid or not.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-17
* @param $iri (string)<br />
* An OID in OID-IRI notation, e.g. /Example/test
* @return (bool) true if the IRI identifier is valid.
**/
function iri_valid($iri) {
if ($iri == '/') return true; // OK?
 
if (substr($iri, 0, 1) != '/') return false;
 
$ary = explode('/', $iri);
array_shift($ary);
foreach ($ary as $a) {
if (!iri_arc_valid($a)) return false;
}
 
return true;
}
 
/*
assert(iri_arc_valid('ABCDEF'));
assert(!iri_arc_valid('-ABCDEF'));
assert(!iri_arc_valid('ABCDEF-'));
assert(!iri_arc_valid(' ABCDEF'));
assert(!iri_arc_valid('2 ABCDEF'));
assert(!iri_arc_valid(''));
 
assert(!iri_valid(''));
assert(iri_valid('/'));
assert(iri_valid('/hello/world'));
assert(iri_valid('/123/world'));
assert(!iri_valid('/hello/0world'));
assert(!iri_valid('/hello/xo--test'));
assert(!iri_valid('/hello/-super-/sd'));
*/
 
/**
* Returns an associative array in the form 'ASN.1' => '/2/1' .
* @author Daniel Marschall, ViaThinkSoft
* @version 2018-01-05
* @see http://itu.int/go/X660
* @return (array) An associative array in the form 'ASN.1' => '/2/1' .
**/
function iri_get_long_arcs() {
$iri_long_arcs = array();
$iri_long_arcs['ASN.1'] = '/2/1';
$iri_long_arcs['Country'] = '/2/16';
$iri_long_arcs['International-Organizations'] = '/2/23';
$iri_long_arcs['UUID'] = '/2/25';
$iri_long_arcs['Tag-Based'] = '/2/27';
$iri_long_arcs['BIP'] = '/2/41';
$iri_long_arcs['Telebiometrics'] = '/2/42';
$iri_long_arcs['Cybersecurity'] = '/2/48';
$iri_long_arcs['Alerting'] = '/2/49';
$iri_long_arcs['OIDResolutionSystem'] = '/2/50';
$iri_long_arcs['GS1'] = '/2/51';
$iri_long_arcs['Example'] = '/2/999'; // English
$iri_long_arcs['Exemple'] = '/2/999'; // French
$iri_long_arcs['Ejemplo'] = '/2/999'; // Spanish
$iri_long_arcs["\u{0627}\u{0644}\u{0645}\u{062B}\u{0627}\u{0644}"] = '/2/999'; // Arabic
$iri_long_arcs["\u{8303}\u{4F8B}"] = '/2/999'; // Chinese
$iri_long_arcs["\u{041F}\u{0440}\u{0438}\u{043C}\u{0435}\u{0440}"] = '/2/999'; // Russian
$iri_long_arcs["\u{C608}\u{C81C}"] = '/2/999'; // Korean
$iri_long_arcs["\u{4F8B}"] = '/2/999'; // Japanese
$iri_long_arcs['Beispiel'] = '/2/999'; // German
return $iri_long_arcs;
}
 
/**
* Tries to shorten/simplify an IRI by applying "long arcs", e.g. /2/999/123 -> /Example/123 .
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-28
* @param $iri (string)<br />
* An OID in OID-IRI notation, e.g. /Example/test
* @return (string) The modified IRI.
**/
function iri_add_longarcs($iri) {
$iri_long_arcs = iri_get_long_arcs();
 
// TODO: $iri valid?
 
$ary = explode('/', $iri);
 
$ary_number_iri = $ary;
if ($ary_number_iri[1] == 'Joint-ISO-ITU-T') $ary_number_iri[1] = '2';
/*
if ($ary_number_iri[1] == '2') {
// TODO: /2/Example -> /2/999 -> /Example
} else {
// Currently, only long arcs inside .2 are defined
// return $iri;
}
*/
$number_iri = implode('/', $ary_number_iri);
 
foreach ($iri_long_arcs as $cur_longarc => $cur_iri) {
// TODO: $cur_iri valid?
 
if (strpos($number_iri.'/', $cur_iri.'/') === 0) {
$cnt = substr_count($cur_iri, '/');
for ($i=1; $i<$cnt; $i++) {
array_shift($ary);
}
$ary[0] = '';
$ary[1] = $cur_longarc;
$iri = implode('/', $ary);
break;
}
}
 
return $iri;
}
 
# === FUNCTIONS FOR OIDS IN ASN.1 NOTATION ===
 
/**
* Checks if an ASN.1 identifier is valid.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $id (string)<br />
* An ASN.1 identifier, e.g. "example". Not "example(99)" or "99" and not a path like "{ 2 999 }"
* Note: Use asn1_path_valid() for validating a whole ASN.1 notation path.
* @return (bool) true, if the identifier is valid: It begins with an lowercase letter and contains only 0-9, a-z, A-Z and "-"
**/
# TODO: umbenennen in asn1_alpha_id_valid
function oid_id_is_valid($id) {
return preg_match('/^([a-z][a-zA-Z0-9-]*)$/', $id);
}
 
/**
* Checks if the ASN.1 notation of an OID is valid.
* This function does not tolerate leading zeros.
* This function will fail (return false) if there are unresolved symbols, e.g. {iso test} is not valid while { iso 123 } is valid.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-17
* @param $asn (string)<br />
* An OID in ASN.1 notation.
* @return (bools) true if the identifier is valid.
**/
function asn1_path_valid($asn1) {
return asn1_to_dot($asn1) != false;
}
 
/**
* Returns an array of standardized ASN.1 alphanumeric identifiers which do not require a numeric identifier, e.g. { 2 example }
* The array has the form '0.0.a' -> '0.0.1'
* @author Daniel Marschall, ViaThinkSoft
* @version 2019-03-25
* @see http://www.oid-info.com/name-forms.htm
* @return (array) Associative array of standardized ASN.1 alphanumeric identifiers
**/
function asn1_get_standardized_array() {
 
// Taken from oid-info.com
// http://www.oid-info.com/name-forms.htm
$standardized = array();
$standardized['itu-t'] = '0';
$standardized['ccitt'] = '0';
$standardized['iso'] = '1';
$standardized['joint-iso-itu-t'] = '2';
$standardized['joint-iso-ccitt'] = '2';
$standardized['0.recommendation'] = '0.0';
$standardized['0.0.a'] = '0.0.1';
$standardized['0.0.b'] = '0.0.2';
$standardized['0.0.c'] = '0.0.3';
$standardized['0.0.d'] = '0.0.4';
$standardized['0.0.e'] = '0.0.5';
$standardized['0.0.f'] = '0.0.6';
$standardized['0.0.g'] = '0.0.7';
$standardized['0.0.h'] = '0.0.8';
$standardized['0.0.i'] = '0.0.9';
$standardized['0.0.j'] = '0.0.10';
$standardized['0.0.k'] = '0.0.11';
$standardized['0.0.l'] = '0.0.12';
$standardized['0.0.m'] = '0.0.13';
$standardized['0.0.n'] = '0.0.14';
$standardized['0.0.o'] = '0.0.15';
$standardized['0.0.p'] = '0.0.16';
$standardized['0.0.q'] = '0.0.17';
$standardized['0.0.r'] = '0.0.18';
$standardized['0.0.s'] = '0.0.19';
$standardized['0.0.t'] = '0.0.20';
$standardized['0.0.u'] = '0.0.21';
$standardized['0.0.v'] = '0.0.22';
$standardized['0.0.w'] = '0.0.23'; // actually, this OID does not exist
$standardized['0.0.x'] = '0.0.24';
$standardized['0.0.y'] = '0.0.25';
$standardized['0.0.z'] = '0.0.26';
$standardized['0.question'] = '0.1';
$standardized['0.administration'] = '0.2';
$standardized['0.network-operator'] = '0.3';
$standardized['0.identified-organization'] = '0.4';
$standardized['1.standard'] = '1.0';
$standardized['1.registration-authority'] = '1.1';
$standardized['1.member-body'] = '1.2';
$standardized['1.identified-organization'] = '1.3';
return $standardized;
}
 
/**
* Converts an OID in ASN.1 notation into an OID in dot notation and tries to resolve well-known identifiers.<br />
* e.g. {joint-iso-itu-t(2) example(999) 1 2 3} --> 2.999.1.2.3<br />
* e.g. {iso 3} --> 1.3
* This function does not tolerate leading zeros.
* This function will fail (return false) if there are unresolved symbols, e.g. {iso test} will not be resolved to 1.test
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-17
* @param $asn (string)<br />
* An OID in ASN.1 notation.
* @return (string) An OID in dot notation without leading dot or false if the path is invalid.
**/
function asn1_to_dot($asn) {
$standardized = asn1_get_standardized_array();
 
// Clean up
$asn = preg_replace('@^\\{(.+)\\}$@', '\\1', $asn, -1, $count);
if ($count == 0) return false; // { and } are required. The asn.1 path will NOT be trimmed by this function
 
// If identifier is set, apply it (no check if it overrides a standardized identifier)
$asn = preg_replace('|\s*([a-z][a-zA-Z0-9-]*)\s*\((\d+)\)|', ' \\2', $asn);
$asn = trim($asn);
 
// Set dots
$asn = preg_replace('|\s+|', '.', $asn);
 
// Apply standardized identifiers (case sensitive)
$asn .= '.';
foreach ($standardized as $s => $r) {
$asn = preg_replace("|^$s|", $r, $asn);
}
$asn = substr($asn, 0, strlen($asn)-1);
 
// Check if all numbers are OK
// -> every arc must be resolved
// -> numeric arcs must not have a leading zero
// -> invalid stuff will be recognized, e.g. a "(1)" without an identifier in front of it
$ary = explode('.', $asn);
foreach ($ary as $a) {
if (!preg_match('@^(0|([1-9]\\d*))$@', $a, $m)) return false;
}
 
return $asn;
}
 
/*
assert(asn1_to_dot('{2 999 (1)}') == false);
assert(asn1_to_dot('{2 999 test}') == false);
assert(asn1_to_dot('{2 999 1}') == '2.999.1');
assert(asn1_to_dot(' {2 999 1} ') == false);
assert(asn1_to_dot('2 999 1') == false);
assert(asn1_to_dot('{2 999 01}') == false);
assert(asn1_to_dot('{ 0 question 123 }') == '0.1.123');
assert(asn1_to_dot('{ iso }') == '1');
assert(asn1_to_dot('{ iso(1) }') == '1');
assert(asn1_to_dot('{ iso(2) }') == '2');
assert(asn1_to_dot('{ iso 3 }') == '1.3');
*/
 
/**
* "Soft corrects" an invalid ASN.1 identifier.<br />
* Attention, by "soft correcting" the ID, it is not authoritative anymore, and might not be able to be resolved by ORS.
* @author Daniel Marschall, ViaThinkSoft
* @version 2014-12-09
* @param $id (string)<br />
* An ASN.1 identifier.
* @param $append_id_prefix (bool)<br />
* true (default): If the identifier doesn't start with a-Z, the problem will be solved by prepending "id-" to the identifier.<br />
* false: If the identifier doesn't start with a-Z, then the problem cannot be solved (method returns empty string).
* @return (string) The "soft corrected" ASN.1 identifier.<br />
* Invalid characters will be removed.<br />
* Uncorrectable start elements (0-9 or "-") will be either removed or solved by prepending "id-" (see <code>$append_id_prefix</code>)<br />
* If the identifier begins with an upper case letter, the letter will be converted into lower case.
**/
function oid_soft_correct_id($id, $append_id_prefix = true) {
// Convert "_" to "-"
$id = str_replace('_', '-', $id);
 
// Remove invalid characters
$id = preg_replace('/[^a-zA-Z0-9-]+/', '', $id);
 
// Remove uncorrectable start elements (0-9 or "-")
if ($append_id_prefix) {
$id = preg_replace('/^([^a-zA-Z]+)/', 'id-$1', $id);
} else {
$id = preg_replace('/^([^a-zA-Z]+)/', '', $id);
}
 
// "Correct" upper case beginning letter by converting it to lower case
if (preg_match('/^[A-Z]/', $id)) {
$id = strtolower($id[0]) . substr($id, 1);
}
 
return $id;
}
 
Property changes:
Deleted: svn:special
-*
\ No newline at end of property
/trunk/uuid_utils.inc.phps
1,0 → 0,0
link /home/daniel-marschall/public_html/tools/uuid_mac_decoder/includes/uuid_utils.inc.phps
<?php
 
/*
* UUID utils for PHP
* Copyright 2011-2019 Daniel Marschall, ViaThinkSoft
* Version 2019-03-19
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
@include_once __DIR__ . '/mac_utils.inc.phps';
 
define('UUID_NAMEBASED_NS_DNS', '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
define('UUID_NAMEBASED_NS_URL', '6ba7b811-9dad-11d1-80b4-00c04fd430c8');
define('UUID_NAMEBASED_NS_OID', '6ba7b812-9dad-11d1-80b4-00c04fd430c8');
define('UUID_NAMEBASED_NS_X500_DN', '6ba7b814-9dad-11d1-80b4-00c04fd430c8');
 
function gen_uuid_md5_namespace($namespace_uuid, $name) {
$namespace_uuid = str_replace('-', '', $namespace_uuid);
$namespace_uuid = hex2bin($namespace_uuid);
 
$hash = md5($namespace_uuid.$name);
 
$hash[12] = '3'; // MD5
$hash[16] = hexdec($hash[16]) & 0x3 | 0x8; // name based
 
return substr($hash, 0, 8).'-'.
substr($hash, 8, 4).'-'.
substr($hash, 12, 4).'-'.
substr($hash, 16, 4).'-'.
substr($hash, 20, 12);
}
 
function gen_uuid_sha1_namespace($namespace_uuid, $name) {
$namespace_uuid = str_replace('-', '', $namespace_uuid);
$namespace_uuid = hex2bin($namespace_uuid);
 
$hash = sha1($namespace_uuid.$name);
 
$hash[12] = '5'; // SHA1
$hash[16] = hexdec($hash[16]) & 0x3 | 0x8; // name based
 
return substr($hash, 0, 8).'-'.
substr($hash, 8, 4).'-'.
substr($hash, 12, 4).'-'.
substr($hash, 16, 4).'-'.
substr($hash, 20, 12);
}
 
function uuid_valid($uuid) {
$uuid = str_replace(array('-', '{', '}'), '', $uuid);
$uuid = strtoupper($uuid);
 
if (strlen($uuid) != 32) return false;
 
$uuid = preg_replace('@[0-9A-F]@', '', $uuid);
 
return ($uuid == '');
}
 
# TODO: nicht echo
function uuid_info($uuid) {
if (!uuid_valid($uuid)) return false;
 
# $uuid = str_replace(array('-', '{', '}'), '', $uuid);
$uuid = strtoupper($uuid);
$uuid = preg_replace('@[^0-9A-F]@', '', $uuid);
 
$x = hexdec(substr($uuid, 16, 1));
if ($x >= 14 /* 1110 */) $variant = 3;
else if ($x >= 12 /* 1100 */) $variant = 2;
else if ($x >= 8 /* 1000 */) $variant = 1;
else if ($x >= 0 /* 0000 */) $variant = 0;
 
 
switch ($variant) {
case 0:
echo sprintf("%-24s %s\n", "Variant:", "[0xx] NCS (reserved for backward compatibility)");
 
/*
* Internal structure of variant #0 UUIDs
*
* The first 6 octets are the number of 4 usec units of time that have
* passed since 1/1/80 0000 GMT. The next 2 octets are reserved for
* future use. The next octet is an address family. The next 7 octets
* are a host ID in the form allowed by the specified address family.
*
* Note that while the family field (octet 8) was originally conceived
* of as being able to hold values in the range [0..255], only [0..13]
* were ever used. Thus, the 2 MSB of this field are always 0 and are
* used to distinguish old and current UUID forms.
*
* +--------------------------------------------------------------+
* | high 32 bits of time | 0-3 .time_high
* +-------------------------------+-------------------------------
* | low 16 bits of time | 4-5 .time_low
* +-------+-----------------------+
* | reserved | 6-7 .reserved
* +---------------+---------------+
* | family | 8 .family
* +---------------+----------...-----+
* | node ID | 9-16 .node
* +--------------------------...-----+
*
*/
 
// Example of an UUID: 333a2276-0000-0000-0d00-00809c000000
 
# TODO: See https://github.com/cjsv/uuid/blob/master/Doc
 
# Timestamp: Count of 4us intervals since 01 Jan 1980 00:00:00 GMT
# 1/0,000004 = 250000
# Seconds between 1970 and 1980 : 315532800
# 250000*315532800=78883200000000
$timestamp = substr($uuid, 0, 12);
$ts = gmp_init($timestamp, 16);
$ts = gmp_add($ts, gmp_init("78883200000000"));
$ms = gmp_mod($ts, gmp_init("250000")); # TODO: gibt es kein divmod?
$ts = gmp_div($ts, gmp_init("250000"));
$ts = gmp_strval($ts);
$ms = gmp_strval($ms);
$ts = gmdate('Y-m-d H:i:s', $ts);
echo sprintf("%-24s %s\n", "Timestamp:", "[0x$timestamp] $ts'".str_pad($ms, 6, '0', STR_PAD_LEFT).' GMT');
 
$reserved = substr($uuid, 12, 4);
echo sprintf("%-24s %s\n", "Reserved:", "0x$reserved");
 
# Family 13 (dds) looks like node is 00 | nnnnnn 000000.
# Family 2 is presumably (ip).
# Not sure if anything else was used.
$family_hex = substr($uuid, 16, 2);
$family_dec = hexdec($family_hex);
if ($family_dec == 2) {
$family_ = 'IP';
} else if ($family_dec == 13) {
$family_ = 'DDS (Data Link)';
} else {
$family_ = "Unknown ($family_dec)"; # TODO: Find out all families [0..13]
}
echo sprintf("%-24s %s\n", "Family:", "[0x$family_hex = $family_dec] $family_");
 
$nodeid = substr($uuid, 18, 14);
echo sprintf("%-24s %s\n", "Node ID:", "0x$nodeid");
# TODO: interprete node id (the family specifies it)
 
break;
case 1:
echo sprintf("%-24s %s\n", "Variant:", "[10x] RFC 4122 (Leach-Mealling-Salz)");
 
$version = hexdec(substr($uuid, 12, 1));
switch ($version) {
case 1:
echo sprintf("%-24s %s\n", "Version:", "[1] Time-based with unique random host identifier");
 
# Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
# 1/0,0000001 = 10000000
$timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).substr($uuid, 0, 8);
$ts = gmp_init($timestamp, 16);
$ts = gmp_sub($ts, gmp_init("122192928000000000"));
$ms = gmp_mod($ts, gmp_init("10000000")); # TODO: gibt es kein divmod?
$ts = gmp_div($ts, gmp_init("10000000"));
$ts = gmp_strval($ts);
$ms = gmp_strval($ms);
$ts = gmdate('Y-m-d H:i:s', $ts);
echo sprintf("%-24s %s\n", "Timestamp:", "[0x$timestamp] $ts'".str_pad($ms, 7, '0', STR_PAD_LEFT).' GMT');
 
$x = hexdec(substr($uuid, 16, 4));
$x = $x ^ 0x8000;
$y = dechex($x);
echo sprintf("%-24s %s\n", "Clock ID:", '0x'.strtoupper($y)." = $x");
 
$x = substr($uuid, 20, 12);
$nodeid = '';
for ($i=0; $i<6; $i++) {
$nodeid .= substr($x, $i*2, 2);
if ($i != 5) $nodeid .= ':';
}
echo sprintf("%-24s %s\n", "Node ID:", "$nodeid");
 
if (function_exists('decode_mac')) {
echo "\nIn case that this Node ID is a MAC address, here is the interpretation of that MAC address:\n";
echo decode_mac($nodeid);
}
 
break;
case 2:
echo sprintf("%-24s %s\n", "Version:", "[2] DCE Security version (with POSIX UIDs)");
 
# TODO: is that correct???
 
# The time_low field (which represents an integer in the range [0, 232-1]) is interpreted as a local-ID; that is, an identifier (within the domain specified by clock_seq_low) meaningful to the local host. In the particular case of a POSIX host, when combined with a POSIX UID or POSIX GID domain in the clock_seq_low field (above), the time_low field represents a POSIX UID or POSIX GID, respectively.
$x = substr($uuid, 0, 8);
echo sprintf("%-24s %s\n", "Local ID:", "0x$x");
 
 
# The clock_seq_low field (which represents an integer in the range [0, 28-1]) is interpreted as a local domain (as represented by sec_rgy_domain_t; see sec_rgy_domain_t ); that is, an identifier domain meaningful to the local host. (Note that the data type sec_rgy_domain_t can potentially hold values outside the range [0, 28-1]; however, the only values currently registered are in the range [0, 2], so this type mismatch is not significant.) In the particular case of a POSIX host, the value sec_rgy_domain_person is to be interpreted as the "POSIX UID domain", and the value sec_rgy_domain_group is to be interpreted as the "POSIX GID domain".
$x = substr($uuid, 0, 18, 2);
echo sprintf("%-24s %s\n", "Local Domain:", "0x$x");
 
 
# Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
# 1/0,0000001 = 10000000
$timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'00000000'; # TODO: ist das OK so????
$ts = gmp_init($timestamp, 16);
$ts = gmp_sub($ts, gmp_init("122192928000000000"));
$ms = gmp_mod($ts, gmp_init("10000000")); # TODO: gibt es kein divmod?
$ts = gmp_div($ts, gmp_init("10000000"));
$ts = gmp_strval($ts);
$ms = gmp_strval($ms);
$ts = gmdate('Y-m-d H:i:s', $ts);
echo sprintf("%-24s %s\n", "Timestamp:", "[0x$timestamp] $ts'".str_pad($ms, 7, '0', STR_PAD_LEFT).' GMT');
 
$x = hexdec(substr($uuid, 16, 2).'00'); # TODO: ist das OK so????
$x = $x ^ 0x8000;
$y = dechex($x);
echo sprintf("%-24s %s\n", "Clock ID:", "0x$y = $x");
 
$x = substr($uuid, 20, 12);
$nodeid = '';
for ($i=0; $i<6; $i++) {
$nodeid .= substr($x, $i*2, 2);
if ($i != 5) $nodeid .= ':';
}
echo sprintf("%-24s %s\n", "Node ID:", "$nodeid");
 
if (function_exists('decode_mac')) {
echo "\nIn case that this Node ID is a MAC address, here is the interpretation of that MAC address:\n";
echo decode_mac($nodeid);
}
 
break;
case 3:
echo sprintf("%-24s %s\n", "Version:", "[3] Name-based (MD5 hash)");
 
# TODO
 
break;
case 4:
echo sprintf("%-24s %s\n", "Version:", "[4] Random");
 
$rand = '';
for ($i=0; $i<16; $i++) {
$bin = base_convert(substr($uuid, $i*2, 2), 16, 2);
$bin = str_pad($bin, 8, "0", STR_PAD_LEFT);
 
if ($i == 6) {
$bin[0] = 'x';
$bin[1] = 'x';
} else if ($i == 8) {
$bin[0] = 'x';
$bin[1] = 'x';
$bin[2] = 'x';
$bin[3] = 'x';
}
 
$rand .= "$bin ";
}
 
echo sprintf("%-24s %s\n", "Random bits:", trim($rand));
 
break;
case 5:
echo sprintf("%-24s %s\n", "Version:", "[5] Name-based (SHA-1 hash)");
 
# TODO
 
break;
default:
echo sprintf("%-24s %s\n", "Version:", "[$version] Unknown");
break;
}
 
break;
case 2:
echo sprintf("%-24s %s\n", "Variant:", "[110] Reserved for Microsoft Corporation");
 
# TODO
 
break;
case 3:
echo sprintf("%-24s %s\n", "Variant:", "[111] Reserved for future use");
break;
}
}
 
function uuid_canonize($uuid) {
if (!uuid_valid($uuid)) return false;
return oid_to_uuid(uuid_to_oid($uuid));
}
 
function oid_to_uuid($oid) {
if (!is_uuid_oid($oid)) return false;
 
if ($oid[0] == '.') {
$oid = substr($oid, 1);
}
$ary = explode('.', $oid);
$val = $ary[2];
 
$x = gmp_init($val, 10);
$y = gmp_strval($x, 16);
$y = str_pad($y, 32, "0", STR_PAD_LEFT);
return substr($y, 0, 8).'-'.
substr($y, 8, 4).'-'.
substr($y, 12, 4).'-'.
substr($y, 16, 4).'-'.
substr($y, 20, 12);
}
 
function is_uuid_oid($oid, $only_allow_root=false) {
if ((substr($oid, 0, 5) != '2.25.') && (substr($oid, 0, 6) != '.2.25.')) return false;
 
if ($oid[0] == '.') $oid = substr($oid, 1);
 
$ary = explode('.', $oid);
 
if ($only_allow_root) {
if (count($ary) != 3) return false;
}
 
for ($i=2; $i<count($ary); $i++) {
$v = $ary[$i];
if (!is_numeric($v)) return false;
if ($v < 0) return false;
}
 
return true;
}
 
function uuid_to_oid($uuid) {
if (!uuid_valid($uuid)) return false;
 
$uuid = str_replace(array('-', '{', '}'), '', $uuid);
$x = gmp_init($uuid, 16);
return '2.25.'.gmp_strval($x, 10); # TODO: parameter mit oder ohne leading dot
}
 
function _gen_uuid_v4() {
// http://rogerstringer.com/2013/11/15/generate-uuids-php
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0x0fff ) | 0x4000,
mt_rand( 0, 0x3fff ) | 0x8000,
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
 
function gen_uuid($prefer_timebased = true) {
$out = array();
 
# On Debian: aptitude install php-uuid
# extension_loaded('uuid')
if (function_exists('uuid_create')) {
# OSSP uuid extension like seen in php5-uuid at Debian 8
/*
$x = uuid_create($context);
if ($prefer_timebased) {
uuid_make($context, UUID_MAKE_V1);
} else {
uuid_make($context, UUID_MAKE_V4);
}
uuid_export($context, UUID_FMT_STR, $uuid);
return trim($uuid);
*/
 
# PECL uuid extension like seen in php-uuid at Debian 9
return trim(uuid_create($prefer_timebased ? UUID_TYPE_TIME : UUID_TYPE_RANDOM));
}
 
# On Debian: aptitude install uuid-runtime
if ($prefer_timebased) {
exec('uuidgen -t', $out, $ec);
} else {
exec('uuidgen -r', $out, $ec);
}
if ($ec == 0) return $out[0];
 
if (!$prefer_timebased) {
return _gen_uuid_v4();
}
 
// At this point we cannot fulfil the caller's wish in regards to $prefer_timebased or not
 
if (file_exists('/proc/sys/kernel/random/uuid')) {
// On Debian Jessie: UUID V4 (Random)
return file_get_contents('/proc/sys/kernel/random/uuid');
}
 
return _gen_uuid_v4();
}
 
function uuid_numeric_value($uuid) {
$oid = uuid_to_oid($uuid);
if (!$oid) return false;
return substr($oid, strlen('2.25.'));
}
 
function uuid_c_syntax($uuid) {
$uuid = str_replace('{', '', $uuid);
return '{ 0x' . substr($uuid, 0, 8) .
', 0x' . substr($uuid, 9, 4) .
', 0x' . substr($uuid, 14, 4) .
', { 0x' . substr($uuid, 19, 2).
', 0x' . substr($uuid, 21, 2) .
', 0x' . substr($uuid, 24, 2) .
', 0x' . substr($uuid, 26, 2) .
', 0x' . substr($uuid, 28, 2) .
', 0x' . substr($uuid, 30, 2) .
', 0x' . substr($uuid, 32, 2) .
', 0x' . substr($uuid, 34, 2) . ' } }';
}
 
# ---
 
// http://php.net/manual/de/function.hex2bin.php#113057
if ( !function_exists( 'hex2bin' ) ) {
function hex2bin( $str ) {
$sbin = "";
$len = strlen( $str );
for ( $i = 0; $i < $len; $i += 2 ) {
$sbin .= pack( "H*", substr( $str, $i, 2 ) );
}
 
return $sbin;
}
}
Property changes:
Deleted: svn:special
-*
\ No newline at end of property
/trunk/xml_utils.inc.phps
1,0 → 0,0
link ../../code/php/xml_utils.inc.phps
<?php
 
/*
* XML Encoding Utilities
* Copyright 2011-2019 Daniel Marschall, ViaThinkSoft
* Version 1.7
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
// http://www.viathinksoft.de/?page=codelib&showid=89
 
// Unicode-proof htmlentities.
// Returns 'normal' chars as chars and weirdos as numeric html entites.
// Source: http://www.php.net/manual/en/function.htmlentities.php#107985 ; modified
// Modified by Daniel Marschall, ViaThinkSoft
function htmlentities_numeric($str, $allow_html=false, $encode_linebreaks=false) {
// Convert $str to UTF-8 if it is not already
if (mb_detect_encoding($str, "auto", true) != 'UTF-8') {
# $str = mb_convert_encoding($str, 'UTF-8', 'Windows-1252');
# $str = mb_convert_encoding($str, 'UTF-8', 'auto');
$str = mb_convert_encoding($str, 'UTF-8');
}
 
// get rid of existing entities else double-escape
// DM 24.08.2016 Auskommentiert wegen oid+ xml export
// $str = html_entity_decode(stripslashes($str),ENT_QUOTES,'UTF-8');
 
$ar = preg_split('/(?<!^)(?!$)/u', $str); // return array of every multi-byte character
$str2 = '';
foreach ($ar as $c) {
$o = ord($c);
if (
(strlen($c) > 1) || /* multi-byte [unicode] */
($o < 32 || $o > 126) || /* <- control / latin weirdos -> */
($o > 33 && $o < 40) || /* quotes + ampersand */
($o > 59 && $o < 63) /* html */
) {
// convert to numeric entity
$c = mb_encode_numericentity($c, array(0x0, 0xffff, 0, 0xffff), 'UTF-8');
 
if ($allow_html) {
if ($c == '&#60;') $c = '<';
if ($c == '&#62;') $c = '>';
if ($c == '&#61;') $c = '=';
if ($c == '&#34;') $c = '"';
if ($c == '&#39;') $c = '\'';
if ($c == '&#38;') $c = '&'; // DM 24.08.2016 Re-Aktiviert wegen oid+ xml export
}
 
if (!$encode_linebreaks) {
if ($allow_html) {
if ($c == "&#10;") $c = "<br />";
if ($c == "&#13;") $c = "<br />";
} else {
if ($c == "&#10;") $c = "\n";
if ($c == "&#13;") $c = "\r";
}
}
}
$str2 .= $c;
}
return $str2;
}
 
function ordUTF8($c, $index = 0, &$bytes = null) {
// http://de.php.net/manual/en/function.ord.php#78032
 
$len = strlen($c);
$bytes = 0;
 
if ($index >= $len) {
return false;
}
 
$h = ord($c{$index});
 
if ($h <= 0x7F) {
$bytes = 1;
return $h;
} else if ($h < 0xC2) {
return false;
} else if ($h <= 0xDF && $index < $len - 1) {
$bytes = 2;
return ($h & 0x1F) << 6 | (ord($c{$index + 1}) & 0x3F);
} else if ($h <= 0xEF && $index < $len - 2) {
$bytes = 3;
return ($h & 0x0F) << 12 | (ord($c{$index + 1}) & 0x3F) << 6
| (ord($c{$index + 2}) & 0x3F);
} else if ($h <= 0xF4 && $index < $len - 3) {
$bytes = 4;
return ($h & 0x0F) << 18 | (ord($c{$index + 1}) & 0x3F) << 12
| (ord($c{$index + 2}) & 0x3F) << 6
| (ord($c{$index + 3}) & 0x3F);
} else {
return false;
}
}
 
function utf16_to_utf8($str) {
// http://betamode.de/2008/09/08/php-utf-16-zu-utf-8-konvertieren/
// http://www.moddular.org/log/utf16-to-utf8
 
$c0 = ord($str[0]);
$c1 = ord($str[1]);
if ($c0 == 0xFE && $c1 == 0xFF) {
$be = true;
} else if ($c0 == 0xFF && $c1 == 0xFE) {
$be = false;
} else {
return $str;
}
$str = substr($str, 2);
$len = strlen($str);
$dec = '';
for ($i = 0; $i < $len; $i += 2) {
$c = ($be) ? ord($str[$i]) << 8 | ord($str[$i + 1]) :
ord($str[$i + 1]) << 8 | ord($str[$i]);
if ($c >= 0x0001 && $c <= 0x007F) {
$dec .= chr($c);
} else if ($c > 0x07FF) {
$dec .= chr(0xE0 | (($c >> 12) & 0x0F));
$dec .= chr(0x80 | (($c >> 6) & 0x3F));
$dec .= chr(0x80 | (($c >> 0) & 0x3F));
} else {
$dec .= chr(0xC0 | (($c >> 6) & 0x1F));
$dec .= chr(0x80 | (($c >> 0) & 0x3F));
}
}
return $dec;
}
 
function html_named_to_numeric_entities($str) {
if (!function_exists('decodeNamedEntities')) {
function decodeNamedEntities($string) {
// https://stackoverflow.com/questions/20406599/how-to-encode-for-entity-igrave-not-defined-error-in-xml-feed
static $entities = NULL;
if (NULL === $entities) {
$entities = array_flip(
array_diff(
get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML401, 'UTF-8'),
get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_XML1, 'UTF-8')
)
);
}
return str_replace(array_keys($entities), $entities, $string);
}
}
 
if (!function_exists('mb_convert_encoding')) {
// https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php
function mb_convert_encoding($str, $to_encoding, $from_encoding = NULL) {
return iconv(($from_encoding === NULL) ? mb_internal_encoding() : $from_encoding, $to_encoding, $str);
}
}
 
if (!function_exists('mb_ord')) {
// https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php
function mb_ord($char, $encoding = 'UTF-8') {
if ($encoding === 'UCS-4BE') {
list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char);
return $ord;
} else {
return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE');
}
}
}
 
if (!function_exists('mb_htmlentities')) {
// https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php
function mb_htmlentities($string, $hex = true, $encoding = 'UTF-8') {
return preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) use ($hex) {
return sprintf($hex ? '&#x%X;' : '&#%d;', mb_ord($match[0]));
}, $string);
}
}
 
if (!mb_detect_encoding($str, 'UTF-8', true)) $str = utf8_encode($str);
return mb_htmlentities(decodeNamedEntities($str));
}
Property changes:
Deleted: svn:special
-*
\ No newline at end of property