Files
cmp-php-util/cmpUtil.php
2024-03-21 17:43:16 +03:00

943 lines
19 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
trait cmpUtil {
var $gitStatus = "Unknown";
var $gitDate = "";
var $gitTime = "";
var $gitTimeStamp = "";
var $gitCommit = "";
var $gitComment = "";
var $maxFileSize = 104856;
function toArray($obj) {
$re = array();
$in = null;
if(is_array($obj))
$in = $obj;
if(is_object($obj))
$in = get_object_vars($obj);
if(is_string($obj)) return $obj;
if(is_float($obj)) return $obj;
if(is_bool($obj)) return $obj;
if(is_int($obj)) return $obj;
foreach((array) $in as $k => $v) {
if(is_array($in[$k])) {
// echo "$k array\n";
$re[$k] = $this->toArray($v);
continue;
}
if(is_object($in[$k])) {
// echo "$k object\n";
$re[$k] = $this->toArray($v);
continue;
}
// echo "$k string?\n";
$re[$k] = $v;
}
return $re;
}
function errorJSON($err, $f = 2) {
switch($err) {
case JSON_ERROR_NONE : $this->e('Ошибок нет' , $f); break;
case JSON_ERROR_DEPTH : $this->e('Достигнута максимальная глубина стека' , $f); break;
case JSON_ERROR_STATE_MISMATCH : $this->e('Некорректные разряды или не совпадение режимов' , $f); break;
case JSON_ERROR_CTRL_CHAR : $this->e('Некорректный управляющий символ' , $f); break;
case JSON_ERROR_SYNTAX : $this->e('Синтаксическая ошибка, не корректный JSON' , $f); break;
case JSON_ERROR_UTF8 : $this->e('Некорректные символы UTF-8, возможно неверная кодировка' , $f); break;
case JSON_ERROR_RECURSION : $this->e('Одна или несколько зацикленных ссылок в кодируемом значении' , $f); break;
case JSON_ERROR_INF_OR_NAN : $this->e('Одно или несколько значений NAN или INF в кодируемом значении' , $f); break;
case JSON_ERROR_UNSUPPORTED_TYPE : $this->e('Передано значение с неподдерживаемым типом' , $f); break;
case JSON_ERROR_INVALID_PROPERTY_NAME : $this->e('Имя свойства не может быть закодировано' , $f); break;
case JSON_ERROR_UTF16 : $this->e('Некорректный символ UTF-16, возможно некорректно закодирован' , $f); break;
default : $this->e('Неизвестная ошибка' , $f); break;
}
}
function decodeJSONRaw($str, $f = 2) {
$obj = json_decode(
$str , // string $json
true , // ?bool $associative = null
512 , // int $depth = 512
JSON_INVALID_UTF8_IGNORE // int $flags = 0
);
$err = json_last_error();
if($err === JSON_ERROR_NONE)
return $this->toArray($obj);
$this->errorJSON($err, $f + 1);
$this->d("Invalid JSON: " . $str, $f);
return null;
}
function decodeJSON($str, $d = 0) {
$m = array();
// eq '/[[:cntrl:]]/u';
// $re = '/[\x00-\x1F\x7F]/u';
// Add ignore 0x09, 0x0a, 0x0d
$re = '/[\x00-\x08\x0b-\x0c\x0e-\x1F\x7F]/u';
// $ign = array("0x09", "0x0a", "0x0d");
if(preg_match_all($re, $str, $m)) {
$tr = array();
for($i = 0; $i < count($m[0]); $i++) {
$bin = $m[0][$i];
if(isset($tr[$bin]))
continue;
$hex = "0x" . bin2hex($bin);
// if(in_array($hex, $ign))
// continue;
$tr[$bin] = $hex;
if($d)
$this->d("decodeJSON: Translate " . $hex);
}
$str = strtr($str, $tr);
}
return $this->decodeJSONRaw($str, 6);
}
function encodeJSON($obj) {
$text = json_encode($obj, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$err = json_last_error();
if($err === JSON_ERROR_NONE)
return $text;
$this->errorJSON($err);
return null;
}
function encodeJSONCompact($obj) {
$text = json_encode($obj, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$err = json_last_error();
if($err === JSON_ERROR_NONE)
return $text;
$this->errorJSON($err);
return null;
}
function readFile($file) {
return @file_get_contents(
$file , // string
false , // bool $use_include_path
null , // ?resource $context
0 , // int $offset
$this->maxFileSize , // ?int $length
);
}
function readJSON($file) {
$raw = $this->readFile($file);
if(!$raw) {
$this->e("Can't read '$file'");
return false;
}
$obj = $this->decodeJSON($raw, 1);
if(is_array($obj)) {
return $obj;
}
if(!$obj) {
$this->e("Invalid JSON file '$file'");
return false;
}
// var_export($obj);
return $obj;
}
function appendConf($arr) {
if(!$arr)
return false;
foreach($arr as $k => $v) {
// $this->d("Set parm .$k to $v");
$this->parm[$k] = $v;
}
return true;
}
function readJSONConf($file) {
$obj = $this->readJSON($file);
if(!$obj)
return false;
$this->appendConf($obj);
if(isset($this->parm["timezone"]) && $this->parm["timezone"]) {
$this->d("Set timezone '" . $this->parm["timezone"] . "'");
date_default_timezone_set($this->parm["timezone"]);
}
do {
if(!isset($this->parm["maxFileSize"]))
break;
if(!$this->parm["maxFileSize"])
break;
if(!is_numeric($this->parm["maxFileSize"])) {
$this->d("Not numeric maxFileSize");
break;
}
$this->maxFileSize = 1*$this->parm["maxFileSize"];
$this->d("Set maxFileSize '" . $this->maxFileSize . "'");
} while(0);
if(isset($this->parm["php_ini"]) && is_array($this->parm["php_ini"])) {
foreach($this->parm["php_ini"] as $k => $v) {
ini_set($k, $v);
}
}
return true;
}
function fgExec($cmd) {
$cmd .= " 2>/tmp/fgExec.err";
$this->d("fgExec: $cmd");
ob_start();
passthru($cmd, $ret);
$out = ob_get_contents();
ob_end_clean();
$a = array(
"return" => $ret,
"stderr" => array(),
"output" => $out
);
$ff = "/tmp/fgExec.err";
$err = @file($ff);
// var_export($err);
if(!is_array($err)) {
$a["stderr"][] = "Can't read file: $ff";
}
else for($i = 0; $i < count($err); $i++) {
$str = trim($err[$i], "\r\n");
// $this->d($str);
$a["stderr"][] = $str;
}
@unlink("/tmp/fgExec.err");
return $a;
}
function cmpShellEscStr($str) {
$ttr = array(
"\t" => "\\\t", "\$" => "\\\$",
"\\" => "\\\\", "\"" => "\\\"",
" " => "\\ " , "`" => "\\`",
"#" => "\\#" , "&" => "\\&",
"(" => "\\(" , ")" => "\\)",
"*" => "\\*" , "|" => "\\|",
"[" => "\\[" , "]" => "\\]",
"{" => "\\{" , "}" => "\\}",
";" => "\\;" , "'" => "\\'",
"<" => "\\<" , ">" => "\\>",
"?" => "\\?" , "!" => "\\!"
);
do {
if(!is_array($str))
break;
if(!isset($str[0]))
return null;
if($str[0] != "asis") {
$this->d("Unknown modifier '".$str[0]."'");
return null;
}
if(!isset($str[1]) || !$str[1]) {
$this->d("Invalid string '".$str[1]."'");
return null;
}
return $str[1];
} while(0);
return strtr($str, $ttr);
}
function cmpShellEscArr($cmaRaw) {
$cmaEsc = array();
for($i = 0; $i < count($cmaRaw); $i++) {
$str = $this->cmpShellEscStr($cmaRaw[$i]);
if(!$str) {
return null;
}
$cmaEsc[] = $str;
}
return $cmaEsc;
}
function cmpShellEsc($cmaRaw) {
if(is_array($cmaRaw)) {
$cmaEsc = $this->cmpShellEscArr($cmaRaw);
return join(" ", $cmaEsc);
}
return $this->cmpShellEscStr($cmaRaw);
}
function cmpSysExecEventString(&$prs, &$buf, &$opt) {
$fs = "/\n/";
if(isset($opt["eventStringDelimer"]) && $opt["eventStringDelimer"])
$fs = $opt["eventStringDelimer"];
$a = preg_split($fs, $buf);
if(!$a) {
$this->d("Can't split buffer");
return false;
}
$c = count($a) - 1;
if($c < 1)
return true;
for($i = 0; $i < $c; $i++) {
if(!isset($opt["silent"]) || !$opt["silent"])
$this->d($prs["streamCurrent"] . ": " . $a[$i]);
$callName = "";
if($prs["streamCurrent"] == "stdout") {
$callName = "eventStringStdOut";
}
else if($prs["streamCurrent"] == "stderr") {
$callName = "eventStringStdErr";
}
if(!isset($opt["eventStringStdOut"]))
continue;
if(!$opt["eventStringStdOut"])
continue;
if(!isset($opt[$callName]["call"])) {
$this->d("Unset $callName.call");
continue;
}
if(!is_callable($opt[$callName]["call"])) {
$this->d("Uncallable $callName.call");
continue;
}
$parm = null;
if(isset($opt[$callName]["parm"]))
$parm = $opt[$callName]["parm"];
try {
$ret = call_user_func(
$opt[$callName]["call"],
array(
"string" => $a[$i],
"parm" => $parm,
"prs" => $prs
)
);
} catch(Exception | Error $e) {
$this->e($e);
}
}
// $this->d("Stream tail: " . $a[$c]);
$buf = $a[$c];
return true;
}
function cmpSysExecEventListenner(&$ppsAll, &$opt) {
$prs = array();
while(!feof($ppsAll[1])) {
$read = [ $ppsAll[1], $ppsAll[2] ];
$write = null;
$except = null;
// $this->d("Add stream event listenner");
$cnt = stream_select(
$read,
$write,
$except,
1, // seconds
0 // microseconds
);
if(false === $cnt) {
$this->d("stream_select err");
return false;
}
// $this->d("Streams event count : " . $sel);
if(!$cnt) {
continue;
}
$out = stream_get_contents($ppsAll[1]);
if($out) {
$prs["streamCurrent"] = "stdout";
if(!$this->cmpSysExecEventString($prs, $out, $opt))
return false;
}
$err = stream_get_contents($ppsAll[2]);
if($err) {
$prs["streamCurrent"] = "stderr";
if(!$this->cmpSysExecEventString($prs, $err, $opt))
return false;
}
// while
}
return true;
}
function cmpSysExecEventSwo(&$ppsAll, &$opt) {
do {
if(!isset($opt["stdInEventAdd"]) || !$opt["stdInEventAdd"])
break;
if(!isset($opt["stdInEventAdd"]["call"])) {
$this->d("Unset callable stdInEventAdd");
break;
}
if(!is_callable($opt["stdInEventAdd"]["call"])) {
$this->d("Invalid callable stdInEventAdd");
break;
}
if(!isset($opt["silent"]) || !$opt["silent"])
$this->d("Call stdInEventAdd");
($opt["stdInEventAdd"]["call"]) (
$ppsAll[0],
$opt["stdInEventAdd"]
);
} while(0);
do {
if(!isset($opt["stdOutEventAdd"]) || !$opt["stdOutEventAdd"])
break;
if(!isset($opt["stdOutEventAdd"]["call"])) {
$this->d("Unset callable stdOutEventAdd");
break;
}
if(!is_callable($opt["stdOutEventAdd"]["call"])) {
$this->d("Invalid callable stdOutEventAdd");
break;
}
if(!isset($opt["silent"]) || !$opt["silent"])
$this->d("Call stdOutEventAdd");
($opt["stdOutEventAdd" ]["call"]) (
$ppsAll[1],
$opt["stdOutEventAdd"]
);
} while(0);
do {
if(!isset($opt["stdErrEventAdd"]) || !$opt["stdErrEventAdd"])
break;
if(!isset($opt["stdErrEventAdd"]["call"])) {
$this->d("Unset callable stdErrEventAdd");
break;
}
if(!is_callable($opt["stdErrEventAdd"]["call"])) {
$this->d("Invalid callable stdErrEventAdd");
break;
}
if(!isset($opt["silent"]) || !$opt["silent"])
$this->d("Call stdErrEventAdd");
($opt["stdErrEventAdd"]["call"]) (
$ppsAll[2],
$opt["stdErrEventAdd"]
);
} while(0);
do {
if(!isset($opt["eventWait"]) || !$opt["eventWait"])
break;
if(!isset($opt["eventWait"]["call"])) {
$this->d("Unset callable eventWait");
break;
}
if(!is_callable($opt["eventWait"]["call"])) {
$this->d("Invalid callable eventWait");
break;
}
if(!isset($opt["silent"]) || !$opt["silent"])
$this->d("Call eventWait");
($opt["eventWait"]["call"])();
} while(0);
return true;
}
function cmpSysExec($cmaRaw, $opt = []) {
$cmdStr = $this->cmpShellEsc($cmaRaw);
if(!isset($opt["silent"]) || !$opt["silent"]) {
$this->d("cmpSysExec: " . $cmdStr);
}
$fdsAll = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$workDir = "/tmp";
if(isset($opt["workDir"]) && $opt["workDir"])
$workDir = $opt["workDir"];
$envAll = null;
$ppsAll = array();
$prcRes = proc_open($cmdStr, $fdsAll, $ppsAll, $workDir, $envAll);
if(!is_resource($prcRes)) {
$this->e("Can't create process");
return null;
}
$blk = 1;
if(isset($opt["blocking"])) {
$blk = $opt["blocking"];
}
$retVal = 255;
$out = "";
$err = "";
if(isset($opt["eventString"]) && $opt["eventString"]) {
stream_set_blocking($ppsAll[1], 0);
stream_set_blocking($ppsAll[2], 0);
if(isset($opt["stdin"]) && $opt["stdin"]) {
fwrite($ppsAll[0], $opt["stdin"]);
fclose($ppsAll[0]);
}
$this->cmpSysExecEventListenner($ppsAll, $opt);
}
else if($blk) {
stream_set_blocking($ppsAll[1], $blk);
stream_set_blocking($ppsAll[2], $blk);
if(isset($opt["stdin"]) && $opt["stdin"]) {
fwrite($ppsAll[0], $opt["stdin"]);
fclose($ppsAll[0]);
}
$out = stream_get_contents($ppsAll[1], 1048576);
$err = stream_get_contents($ppsAll[2], 1048576);
}
else {
stream_set_blocking($ppsAll[1], $blk);
stream_set_blocking($ppsAll[2], $blk);
// $this->d("Nonblock");
$this->cmpSysExecEventSwo($ppsAll, $opt);
}
// $this->d("Close all pipe");
fclose($ppsAll[1]);
fclose($ppsAll[2]);
$retVal = proc_close($prcRes);
if(!isset($opt["return"]) || !$opt["return"] || $opt["return"] == "full") {
return array(
"retval" => $retVal,
"stdout" => $out,
"stderr" => $err
);
}
$val = 0;
if(isset($opt["retval"]) && $opt["retval"])
$val = $opt["retval"];
if(!isset($opt["noerror"]) || !$opt["noerror"]) {
if($retVal !== $val) {
if(!isset($opt["silent"]) || !$opt["silent"]) {
$this->d($err);
$this->d("Return code: " . $retVal);
}
return null;
}
if($err) {
$this->d($err);
}
}
if(isset($opt["return"]) && $opt["return"]) {
switch(@$opt["return"]) {
case "retval":
return 1*$retVal;
case "outstr":
return $out;
case "outarr":
default:
return explode("\n", $out);
}
}
return explode("\n", $out);
}
function cmpSysExecTest() {
$a = array(
"ping" ,
"-c" ,
"4" ,
"127.0.0.1" ,
);
$this->d("Launch");
$this->d($a);
$this->cmpSysExec($a, array(
"silent" => false,
"eventString" => true,
"eventStringStdOut" => array(
"call" => [$this, "d"],
"parm" => "testparm"
)
));
}
function getGitStatus($dir = ".") {
$a = array(
"git", "status", "--porcelain"
);
$gitStatus = $this->cmpSysExec($a, ["workDir" => $dir]);
if($gitStatus["retval"]) {
$this->d("GIT have errors");
$this->d($gitStatus["stderr"]);
return ;
}
if(!$gitStatus["stdout"]) {
return null;
}
$this->w("GIT have changes");
$arr = explode("\n", $gitStatus["stdout"]);
$ret = array();
for($i = 0; $i < count($arr); $i++) {
$arr[$i] = trim($arr[$i], "\n \r\t");
if(!$arr[$i])
continue;
$ff = explode(" ", $arr[$i], 2);
$this->d("flag=" . $ff[0] . " file=" . $ff[1]);
$ret[] = $ff;
}
// $this->d($ret);
return $ret;
}
function getGitLog1($dir = ".") {
// https://git-scm.com/docs/pretty-formats
$frmReq = array(
array("commitHash", "H" ),
array("commitDate", "ci"),
array("commitTStm", "ct"),
array("authorMail", "ae")
);
$frmArr = array();
for($i = 0; $i < count($frmReq); $i++)
$frmArr[] = "%" . $frmReq[$i][1];
$frmStr = join("%n", $frmArr);
$a = array(
"git", "log", "--pretty=format:$frmStr", "-1"
);
$gitCommit = $this->cmpSysExec($a, ["workDir" => $dir]);
if($gitCommit["retval"]) {
$this->d("GIT have errors");
$this->d($gitCommit["stderr"]);
return null;
}
$b = explode("\n", $gitCommit["stdout"]);
$frmRet = array();
for($i = 0; $i < count($frmReq); $i++)
$frmRet[ $frmReq[$i][0] ] = $b[$i];
return $frmRet;
}
function cmpTraitInit($obj, $lvl = 0) {
$listTrait = class_uses($obj);
foreach($listTrait as $trait) {
$this->d("Used trait $trait");
do {
$traitRoot = OUT_PROJ_DIR . "/" . $trait;
$traitGit = $traitRoot . "/.git";
if(!is_dir($traitGit))
break;
$ret = $this->getGitStatus($traitRoot);
$ret = $this->getGitLog1($traitRoot);
$this->d($ret);
} while(0);
$this->cmpTraitInit($trait, $lvl+1);
$initMeth = $trait . "Init";
if(!method_exists($this, $initMeth)) {
// $this->d("No method $initMeth");
continue;
}
$parm = null;
if(isset($this->parm[$trait])) {
// $this->d("Found parm");
$parm = $this->parm[$trait];
}
$this->swoSelfCall(array("func" => $initMeth, "parm" => $parm));
}
return true;
}
function isMD5($str) {
if(preg_match("/^[0-9a-f]{32}$/", $str))
return true;
return false;
}
function isUNID($str) {
return $this->isMD5($str);
}
function isDateFT($str) {
if(preg_match("/^(20[0-9]{2}-[01][0-9]-[0-3][0-9]) ([0-2][0-9]:[0-5][0-9]:[0-5][0-9])$/", $str))
return true;
return false;
}
function isP7Phone($str) {
if(preg_match("/^\+7(9[0-9]{2})([0-9]{7})$/", $str))
return true;
return false;
}
function isPxPhone($str) {
if(preg_match("/^\+7(9[0-9]{2})([0-9]+)$/", $str)) {
return true;
}
if(preg_match("/^\+([0-9]+)$/", $str)) {
$this->d("Wild number $str");
return true;
}
return false;
}
function normalizePhone($inp) {
if(preg_match("/^((\+7)|8)?(\d{3})(\d{7,8})$/", $inp, $m)) {
return "+7" . $m[3] . $m[4];
}
return null;
}
function isINN($inn) {
$inn = (string) $inn;
if(!preg_match("/^[0-9]{10,12}$/", $inn)) {
return null;
}
switch(strlen($inn)) {
case 10:
$n = 0;
foreach([2, 4, 10, 3, 5, 9, 4, 6, 8] as $i => $k) {
$n += $k * (int) $inn[$i];
}
$n10 = $n % 11 % 10;
if($n10 === (int) $inn[9])
return true;
return false;
case 12:
$n = 0;
foreach([7, 2, 4, 10, 3, 5, 9, 4, 6, 8] as $i => $k) {
$n += $k * (int) $inn[$i];
}
$n11 = $n % 11 % 10;
$n = 0;
foreach([3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8] as $i => $k) {
$n += $k * (int) $inn[$i];
}
$n12 = $n % 11 % 10;
if(($n11 === (int) $inn[10]) && ($n12 === (int) $inn[11]))
return true;
return false;
}
return false;
}
function isSnils($snils) {
$snils = (string) $snils;
if(!preg_match("/^[0-9]{11}$/", $snils)) {
return null;
}
$sum = 0;
for($i = 0; $i < 9; $i++) {
$sum += (int) $snils[$i] * (9 - $i);
}
$cs = 0;
if ($sum < 100) {
$cs = $sum;
} elseif ($sum > 101) {
$cs = $sum % 101;
if ($cs === 100) {
$cs = 0;
}
}
if($cs === (int) substr($snils, -2)) {
return true;
}
return false;
}
// END
}
?>