/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 == '<') $c = '<'; |
if ($c == '>') $c = '>'; |
if ($c == '=') $c = '='; |
if ($c == '"') $c = '"'; |
if ($c == ''') $c = '\''; |
if ($c == '&') $c = '&'; // DM 24.08.2016 Re-Aktiviert wegen oid+ xml export |
} |
if (!$encode_linebreaks) { |
if ($allow_html) { |
if ($c == " ") $c = "<br />"; |
if ($c == " ") $c = "<br />"; |
} else { |
if ($c == " ") $c = "\n"; |
if ($c == " ") $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 |