$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 } ?>