diff --git a/.tgitconfig b/.tgitconfig new file mode 100644 index 0000000..e69de29 diff --git a/metadata/dbms/data.json b/metadata/dbms/data.json new file mode 100644 index 0000000..de1ebc9 --- /dev/null +++ b/metadata/dbms/data.json @@ -0,0 +1,78 @@ +{ + "type":{ + "n":"Terminals", + "d":"trt('Terminal')", + "ObjectID":"id", + "edit_object":{ + "columns":[ + {"d":"id", "n":"id", "vt":"i4", "visible":"0"}, + {"d":"trt('Company')", "n":"company_id", "vt":"object", "maybenull":"0", "ot":"Companies", "FieldCaption":"name", "selector":"combo"}, + {"d":"trt('Phone')", "n":"phone", "vt":"string", "size":"20"}, + {"d":"trt('Serial_number')", "n":"serial", "vt":"string", "size":"50"}, + {"d":"IMEI", "n":"imei", "vt":"string", "size":"50", "maybenull":"0"}, + {"d":"trt('Terminal model')", "n":"terminal_model_id", "vt":"object", "maybenull":"0", "ot":"TerminalsModels", "FieldCaption":"name", "selector":"combo"}, + {"d":"trt('Description')", "n":"description", "vt":"text", "size":"500"} + ], + "insert-query":"select * from main.p_Terminals_i(${_user_id},${company_id},${phone},${serial},${imei},${terminal_model_id},${description});", + "update-query":"select * from main.p_Terminals_u(${_user_id},${id},${company_id},${phone},${serial},${imei},${terminal_model_id},${description});", + "delete-query":"select * from main.p_Terminals_d(${_user_id},${id});", + "select-query":"select * from main.p_Terminals_s(${_user_id},${id},0,NULL);" + }, + "show-object":{ + "d":"trt('Terminals')", + "width":"1000", + "sql-query":"select * from main.p_terminals_ss(${_user_id},${id},${company_id},${terminal_id},${install},${imei},${serial});", + "filter":{ + "columns":[ + {"d":"id","n":"id","vt":"string","visible":"0"}, + {"d":"trt('Company')","n":"company_id","vt":"object","object":"Companies","FieldCaption":"name","selector":"combo"}, + {"d":"terminal_id","n":"terminal_id","vt":"i4","visible":"0"}, + {"d":"trt('Installed')","n":"install","vt":"b"}, + {"d":"trt('IMEI')","n":"imei","vt":"string"}, + {"d":"trt('Serial_number')","n":"serial","vt":"string"} + ] + }, + "columns":[ + {"d":"trt('Terminal_model')", "n":"terminal_model_name", "width":"150"}, + {"d":"trt('Company')", "n":"campany_name", "width":"150"}, + {"d":"trt('Installed_on')", "n":"object_name", "width":"150"}, + {"d":"trt('Phone')", "n":"phone", "width":"150"}, + {"d":"trt('Serial_number')", "n":"serial", "width":"120"}, + {"d":"IMEI", "n":"imei", "width":"300"}, + {"d":"trt('Description')", "n":"description", "width":"300"}, + {"d":"trt('Count_sensors')", "n":"tscnt", "width":"120", + "type":{ + "n":"TerminalsSensors", + "show-object":{ + "d":"trt('Sensors_types')", + "filter":{ + "height":"1", + "columns":[ + { + "n":"terminal_id", + "data":"${id}" + } + ] + } + } + } + }, + {"d":"Настройки", "n":"tstcnt", "width":"120", + "type":{ + "n":"TerminalsSettings", + "show-object":{ + "filter":{ + "columns":[ + { + "n":"terminal_id", + "data":"${id}" + } + ] + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/metadata/dbms/dbms.xyz b/metadata/dbms/dbms.xyz new file mode 100644 index 0000000..17deef9 --- /dev/null +++ b/metadata/dbms/dbms.xyz @@ -0,0 +1,1450 @@ +error_code=$code; + $obj->error_message=$error; + header('Content-Type: application/json'); + header("Cache-Control: no-cache, must-revalidate"); + echo json_encode($obj); + exit(); + } + + function getSQLValue($t,$v) + { + global $db_connection; + + if($t=='object' && gettype($v)=='string'){ + $t='string'; //Если id шники uuid + } + + if($t=='object'){ + if ($v=='-1'||$v=='' || $v==null) $v='NULL'; + }else + if($t=='i1' || $t=='i2' || $t=='i4' || $t=='integer'){ + if($v=='') $v='NULL'; + }else + if($t=='f8' || $t=='f4' || $t=='real' || $t=='double'){ + if($v=='')$v='NULL'; + $v=str_replace(',','.',$v); //Разделитель целой и дробной части точка + }else + if($t=='b'){ + if($v=='') $v='NULL'; else + if($v=='1') $v='true'; else + if($v=='0') $v='false'; + }else + if($t=='string' || $t=='html' || $t=='text' || $t=='dateTime' || $t=='time' || $t=='date' || $t=='file') { + if ($v == '') { + $v = 'NULL'; + } else { + if (strpos($db_connection, 'pgsql') !== false) + $v = str_replace("'", "''", $v); //так как в SQL строку вставляется + else + $v = str_replace('\'', '\\\'', $v); //так как в SQL строку вставляется + $v = '\'' . $v . '\''; + } + }else if($t=="NULL" || $t==null){ + if ($v == '') { + $v = 'NULL'; + } else { + $v='\''.$v.'\''; + } + }else{ + $v='\''.$v.'\''; + } + return $v; + } + + function getValue($t,$v) + { + if($t=='object' && gettype($v)=='string'){ + $t='string'; //Если id шники uuid + } + + if($t=='object'){ + if (($v=='-1')||($v=='')) $v=null; + }else + if($t=='i4' || $t=='integer'){ + if($v=='') $v=null; + }else + if($t=='f8'){ + if($v=='')$v=null; + $v=str_replace(',','.',$v); //Разделитель целой и дробной части точка + }else + if($t=='b'){ + if($v=='') $v=null; else + if($v=='1') $v=true; else + if($v=='0') $v=false; + }else + if($t=='string' || $t=='dateTime' || $t=='date'){ + if($v=='') $v=null; + } + return $v; + } + + function getPDOTypeParam($t) + { + //if($t=='object' && gettype($v)=='string') $t='string'; //Если id шники uuid + + if($t=='object') + { //return PDO::PARAM_INT; + return PDO::PARAM_STR; + }else + if($t=='i4' || $t=='integer') + { return PDO::PARAM_INT; + }else + if($t=='f8') + { return PDO::PARAM_STR; + }else + if($t=='b') + { return PDO::PARAM_BOOL; + }else + if($t=='string' || $t=='dateTime' || $t=='date') + { return PDO::PARAM_STR; + }else + if($t=='blob') + { return PDO::PARAM_LOB; + }else + return PDO::PARAM_STR; + } + + //Заменить все значения первого фильтра значениями из второго + function setFilter($n1,$n2) + { + if($n1==null || $n2==null) return; + $nc1=$n1->firstChild; + while ($nc1) + { + if ($nc1->nodeName=='column') + { + $nc2=findNodeOnAttribute($n2, 'column', 'n', $nc1->getAttribute("n")); + if($nc2) getCdata($nc1)->nodeValue=getCdata($nc2)->nodeValue; + } + $nc1 = $nc1->nextSibling; + } + } + + //Получить узел метаданных из базы данных + function getMetadataNode($name) + { + global $db,$Schema; + + $xmls=''; + $sql='select xml from '.$Schema.'_metadata where del=false and name=\''.$name.'\';'; + $resX = $db->query($sql); + while ($rowX = $resX->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmls=''.trts($rowX['xml']).''; + } + if($xmls!='') + { + //sendError(1,"Metadata node \"".$name."\" not find in database!"); + $objXMLDocument = new DOMDocument(); + try + { + $objXMLDocument->loadXML($xmls); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + $currNode=findNodeOnAttribute($objXMLDocument->documentElement, "type","n",$name); + return $currNode; + }else{ + return null; + } + } + + function special_handler($exception) + { + sendError(1,$exception->getMessage()); + } + set_exception_handler('special_handler'); //чтоб не пойманные исключения посылались в виде XML + + //Схема базы по умолчанияю + if(!isset($Schema)) { + $Schema=""; + } + //Тип идентификаторов + $idType="object"; + if(!isset($idType)) { + $idType="object"; + } + + $db = connectToDB(); + if($db==null) + sendError(1,trt('Error_connection_to_DB')); + + //Пытаемся автоматически залогинется по GUID из COOKIE (TODO авторизация должна быть в отдельном файле! Смотри директорию password ) + /*if($_SESSION['USER_ID']==null && $_COOKIE['GUID']!=null) + { + $res = $db->query("select * from ".$Schema."p__Login(null,null,null,'".$_COOKIE['GUID']."');"); + //$res = $db->query("select * from p__Login_1(null,null,null,'".$_COOKIE['GUID']."');"); + if($res->rowCount()>0) + { + $result = $res->fetch(PDO::FETCH_ASSOC); + $_SESSION['USER_ID']=$result['id']; + } + }*/ + + $fn=filter_input(INPUT_GET, 'fn', FILTER_VALIDATE_INT, array('options'=>array('default'=>-1))); + + $HTTP_INPUT=file_get_contents("php://input"); + if($HTTP_INPUT) + { + $doc = new DOMDocument(); + try + { + $doc->loadXML($HTTP_INPUT); + } catch (Exception $e) + { + sendError(1,$e->getMessage()); + } + $reqNode = $doc->documentElement; + + if ($reqNode) + { + $fn = $reqNode->getAttribute("fn"); //Номер функции + } + } + +//описание +//(fn==0) - отправить метаданные клиенту по запрошенному узлу +//(fn==1) - вставить одну запись в базу данных (результат id записи) +//(fn==2) - обновить запись +//(fn==3) - удалить запись +//(fn==4 || fn==11) - отправить данные клиенту соответствии с значением фильтра +//(fn==5) - взять данные для редактирования 1й записи по id +//(fn==6) - вернуть клиенту данные для заполнения обьекта SELECT выделенно в отдельную функцию для экономии трафика здесь могут также использоваться фильтры +//(fn==7) - залогинеться +//(fn==8) - отчёты почти тоже самое что и функция 4 +//(fn==9) - Сохранить двоичные данные в базу +//(fn==10) - Получить двоичные данные из базы + + if ($fn==0) //отправить метаданные клиенту по запрошенному узлу + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $typename=findFirstNode($reqNode, "type")->getAttribute("n"); + $currNode=getMetadataNode($typename); + + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + //Вернём значение прав доступа для запрошенного объекта + $allow_ins=false; + $allow_upd=false; + $allow_del=false; + $sql_query='select '.$Schema.'p_getaccess(:user_id1,:action_insert) as ins,'.$Schema.'p_getaccess(:user_id2,:action_update) as upd,'.$Schema.'p_getaccess(:user_id3,:action_delete) as del;'; + $stmt = $db->prepare($sql_query); + $stmt->bindValue(':user_id1', $_SESSION['USER_ID'], PDO::PARAM_INT); //getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']) + $stmt->bindValue(':user_id2', $_SESSION['USER_ID'], PDO::PARAM_INT); //getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']) + $stmt->bindValue(':user_id3', $_SESSION['USER_ID'], PDO::PARAM_INT); //getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']) + $stmt->bindValue(':action_insert', 'Insert_'.$typename, PDO::PARAM_STR); + $stmt->bindValue(':action_update', 'Update_'.$typename, PDO::PARAM_STR); + $stmt->bindValue(':action_delete', 'Delete_'.$typename, PDO::PARAM_STR); + $res=$stmt->execute(); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) + { + $allow_ins=$row['ins'] == 't'; + $allow_upd=$row['upd'] == 't'; + $allow_del=$row['del'] == 't'; + } + $xmlAttr = $objXMLDocument->createAttribute("ins"); //insert + $xmlAttr->nodeValue = $allow_ins ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + $xmlAttr = $objXMLDocument->createAttribute("upd"); //update + $xmlAttr->nodeValue = $allow_upd ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + $xmlAttr = $objXMLDocument->createAttribute("del"); //delete + $xmlAttr->nodeValue = $allow_del ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + + $allow=true; + $xmlAttr = $objXMLDocument->createAttribute("sel"); //select + $xmlAttr->nodeValue = $allow ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + + //Удаляем все запросы из узла + for($i=0;$i<5;$i++) + { $nsql=findFirstNode($currNode, "sql-query"); + if($nsql!=NULL) $nsql->parentNode->removeChild($nsql); + } + + $xmlstring=''.$objXMLDocument->saveXML($currNode).''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==1) //вставка записи (результат id записи) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $typename=findFirstNode($reqNode,"type")->getAttribute("n"); + $currNode=getMetadataNode($typename); + + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $sql_query=getCdataValue(findFirstNodeOnAttribute($currNode, "sql-query", "t", "i")); + + $nodeProp=findFirstNode($reqNode,"properties"); + //Представляем SQL в виде параметров + $nodePropData=$nodeProp->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + if($vt=='blob') + { $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',':'.$nodePropData->getAttribute("n"),$sql_query); + //Название файла запишем в указаное поле + $val=getCdataValue($nodePropData); + $cd=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("cd"); + $nd=findFirstNodeOnAttribute($nodeProp,'prop','n',$cd); + if($nd!=null) { getCdata($nd)->nodeValue=$val; } + }else if($vt=='file') + { + $val=getCdataValue($nodePropData); + $valSql=getSQLValue($vt, $val); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$valSql,$sql_query); + //Копируем файл из './temp/' в указанную папку относительно корня сайта + $flnm = afterLast($val,'_'); + $dir = "./temp/"; + if($val!='' && file_exists($dir.$flnm)) + { + $path= $_SERVER['DOCUMENT_ROOT'].'/'.findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("path"); + @mkdir($path); //Создаём папку если её нет + if(!rename($dir.$flnm, $path.$flnm)) + sendError(1,'Can\'t rename to "'.$path.$v.'"!'); + } + }else + { $v=getSQLValue($vt, getCdataValue($nodePropData)); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$v,$sql_query); + } + } + $nodePropData=$nodePropData->nextSibling; + } + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); //Потому что PostgreSQL не может хранить id пользователя привязаного к сесии + + $stmt = $db->prepare($sql_query); + if($stmt === false) sendError(1,'Error preparing Statement'); + + //присваеваем параметрам значения (В записи может быть только 1 двоичное поля см bindParam или сделать несколько переменных) + $nodePropData=$nodeProp->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + //Если тип blob то в качастве параметра приходит название файла переданого на сервер заранее + if($vt=='blob') + { $v=getCdataValue($nodePropData); + if($v!='' && file_exists('./temp/'.afterLast($v,'_'))) + { $v = fopen('./temp/'.afterLast($v,'_'), 'rb'); + } else $v=null; + $stmt->bindParam(':'.$nodePropData->getAttribute("n"), $v, PDO::PARAM_LOB); + } + } + $nodePropData=$nodePropData->nextSibling; + } + try + { + $res = $stmt->execute(); + } catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()); + } + $result = $stmt->fetch(PDO::FETCH_NUM); + if($result[0]=='') + { + if(strpos($db_connection, 'sqlite')!==false) { + $result[0] = $db->lastInsertId(); //Для SQLite + }else{ + sendError(1,trt('Failed_to_insert_record').'!'); + } + } + + $xmlstring=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==2) //редактирование (результат id записи) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $nodeType=findFirstNode($reqNode,"type"); + $typename=$nodeType->getAttribute("n"); + $obj_id=$nodeType->getAttribute("id"); + $node_properties=findFirstNode($nodeType,"properties"); + + $currNode=getMetadataNode($typename); + + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $sql_query=getCdataValue(findFirstNodeOnAttribute($currNode, "sql-query", "t", "u")); + //Представляем blob поля в SQL запросе в виде параметров + $nodeProps=findFirstNode($reqNode,"properties"); + $nodePropData=$nodeProps->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + if($vt=='blob') + { $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',':'.$nodePropData->getAttribute("n"),$sql_query); + //Название файла запишем в указаное поле + $val=getCdataValue($nodePropData); + $cd=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("cd"); //Имя поля с которого нужно брать название файла + $nd=findFirstNodeOnAttribute($nodeProps,'prop','n',$cd); + if($nd!=null) getCdata($nd)->nodeValue=$val; + }else if($vt=='file') //Файл который не загружается в базу а храниться в файловой системе + { + $val=getCdataValue($nodePropData); + $valSql=getSQLValue($vt, $val); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$valSql,$sql_query); + //Копируем файл в указанную папку относительно корня сайта + $flnm = afterLast($val,'_'); + $dir = "./temp/"; + if($val!='' && file_exists($dir.$flnm)) + { + $path= $_SERVER['DOCUMENT_ROOT'].'/'.findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("path"); + @mkdir($path);//Создаём папку если её нет + if(!rename($dir.$flnm, $path.$flnm)) + sendError(1,'Can\'t rename to "'.$path.$v.'"!'); + } + }else + { + $val=getSQLValue($vt, getCdataValue($nodePropData)); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$val,$sql_query); + } + } + $nodePropData=$nodePropData->nextSibling; + } + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); //Потому что PostgreSQL не может хранить id пользователя привязаного к сесии + $sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue(gettype($obj_id),$obj_id),$sql_query); //Так как пока идентификатор базы отдельно передаётся + +//sendError(1,$sql_query); + $stmt = $db->prepare($sql_query); + if($stmt === false) sendError(1,'Error preparing Statement'); + + //Присваеваем параметру двоичную информацию (Внимание! Только 1 параметр может быть в 1 записи (почему?)) + $pos_v = 0; + $mas_v[$pos_v]=null; //Чтобы данные не перекрывали друг друга при вставке + $nodePropData=$nodeProps->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + if($vt=='blob') + { + $path_v=getCdataValue($nodePropData); + if($path_v!='' && file_exists('./temp/'.afterLast($path_v,'_'))) + { $v = fopen('./temp/'.afterLast($path_v,'_'), 'rb'); + }else + { $v=null; + } + $mas_v[$pos_v]=$v; + $stmt->bindParam(':'.$nodePropData->getAttribute("n"), $mas_v[$pos_v], PDO::PARAM_LOB); + $pos_v++; + } + } + $nodePropData=$nodePropData->nextSibling; + } + + try + { $res = $stmt->execute(); + } catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) //If already sending short error text. + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()."\n".$sql_query); + } + $result = $stmt->fetch(PDO::FETCH_NUM); //$obj_id + if($result[0]==''){ $result[0]=$obj_id; } + $xmlstring=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==3) //удаление (результат id записи) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $nodeType=findFirstNode($reqNode,"type"); + $typename=$nodeType->getAttribute("n"); + $obj_id=$nodeType->getAttribute("id"); + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $sql_query=getCdataValue(findFirstNodeOnAttribute($currNode, "sql-query", "t", "d")); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); //Потому что PostgreSQL не может хранить id пользователя привязаного к сесии + $sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue(gettype($obj_id),$obj_id),$sql_query); + + //Выполняем + try + { $res = $db->query($sql_query); + }catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) //If already sending short error text. + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()."\n".$sql_query); + } + //записываем id удалённой записи для удаления без перезагрузки страницы через javascript + $xmlstring=""; + $xmlstring.="\n"; + $xmlstring.=''; + $xmlstring.=" \n"; + $xmlstring.="\n"; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==4 || $fn==11) //взять данные из базы по переданным значениям фильтра ($fn==11 для обновления записи у клиента после вставки или редактировании) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $rowspagecount = 100; //записей на страницу + $nTypeR=findFirstNode($reqNode,'type'); + $typename=$nTypeR->getAttribute("n"); + $pagepos=$nTypeR->getAttribute("pp"); //текущяя страница page pos + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $objListR = findFirstNode($nTypeR,'objects-list'); + //В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного + $f1=findNodeOnPath($currNode,'objects-list/filter'); + $f2=findNodeOnPath($nTypeR,'objects-list/filter'); + setFilter($f1,$f2);//заменить все значения первого фильтра значениями из второго + + $sql_query=getCdataValue(findNodeOnPath($currNode, "objects-list/sql-query")); + + if($f1!=null) + { + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $vt=$nextnode->getAttribute("vt"); + $val=getCdataValue($nextnode); + $val=getSQLValue($vt,$val); + $sql_query=str_replace('${'.$nextnode->getAttribute("n").'}',$val,$sql_query); + } + $nextnode = $nextnode->nextSibling; + } + } + $vType=gettype($_SESSION['USER_ID']); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + if($objListR!=null && $objListR->getAttribute('order')!='' && $objListR->getAttribute('order')!=null && $objListR->getAttribute('order')!='null') + { + $sql_query=str_replace('${_order}',getSQLValue('i4',findNodeOnAttribute(findFirstNode($currNode,'objects-list'), "column","n",$objListR->getAttribute("order"))->getAttribute("order")),$sql_query); + }else $sql_query=str_replace('${_order}','1',$sql_query); + + //sendError(1,$sql_query); + //Выполняем запрос + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage().' '.$sql_query); + } + //Формируем ответ + $pagecount=ceil($res->rowCount()/$rowspagecount); //Кол-во страниц + + //В месте с фильтром может прити и название полей которые нужно выбрать если есть хоть 1 поле то выберать только его + $columns = array(); + $nextnode=findNode($nTypeR,'objects-list'); + if($nextnode) + { $nextnode=$nextnode->firstChild;//Пытаемся заполнить из запроса + $i=0; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $columns[$i]=$nextnode->getAttribute("n"); + $i++; + } + $nextnode = $nextnode->nextSibling; + } + } + if(count($columns)==0)//Если нет ни одного столбца заполняем массив из серверного XML + { + $nextnode=findNode($currNode,'objects-list'); + if($nextnode) + { $nextnode=$nextnode->firstChild;//Пытаемся заполнить из запроса + $i=0; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $columns[$i]=$nextnode->getAttribute("n"); + $i++; + } + $nextnode = $nextnode->nextSibling; + } + } + } + + //перебираем RS и строим XML только из тех столбцов которые записанны в секци objects-list поля column в не зависимости от их видимости + $obj = new StdClass(); + $obj->error_code=0; + $obj->error_message = ''; + $obj->fn=$fn; + $obj->n=$typename; + $obj->pc=$pagecount; + $obj->pp=$pagepos; + //Перечисляю название выбираемых столбцов через запятую (почему в JAVA версии этого куска кода нет?) + $obj->objects_list=[]; + $nextnode=findNode($currNode,'objects-list')->firstChild; + while ($nextnode) + { + if ($nextnode->nodeName=='column') + { + array_push($obj->objects_list,$nextnode->getAttribute("n")); + } + $nextnode = $nextnode->nextSibling; + } + $obj->data=[]; + + $node=findFirstNode($reqNode,'objects-list'); + $pos=-1; + while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $pos++; + if (($pagepos!=-1)&&(($pos<($pagepos*$rowspagecount))||($pos>=$pagepos*$rowspagecount+$rowspagecount))) { continue; } + + array_push($obj->data,new StdClass()); + + //разрешать или запрещять редактировать запись надо проверять в хранимке а также запрещять либо разрешать редактировать колонку + //для каждой записи формируеться строка настроек со значениями что нужно запретить в таком виде "iuds" + $access=''; //u = enable update field, d = enable delete field + if(!array_key_exists("_u",$row)) { $access.="u"; } else { $access.=$row["_u"]; } + if(!array_key_exists("_d",$row)) { $access.="d"; } else { $access.=$row["_d"]; } + + if(array_key_exists($currNode->getAttribute("ObjectID"),$row)) { + end($obj->data)->id=$row[$currNode->getAttribute("ObjectID")]; + end($obj->data)->a=$access; + }else { + end($obj->data)->id=""; + end($obj->data)->a=$access; + } + + end($obj->data)->row=[]; + + $nextnode=findNode($currNode,'objects-list')->firstChild; + while ($nextnode) + { + if ($nextnode->nodeName=='column') + { + if(array_key_exists($nextnode->getAttribute("n"),$row)) + { + $field = $nextnode->getAttribute("n"); + array_push(end($obj->data)->row,$row[$field]); + }else + { + sendError(1,"Column \"".$nextnode->getAttribute("n")."\" not exists in \"$typename\" for select!"); + } + } + $nextnode = $nextnode->nextSibling; + } + } + $res->closeCursor(); + + header('Content-Type: application/json; charset=utf-8'); + header("Cache-Control: no-cache, must-revalidate"); + echo json_encode($obj); + exit; + }else + { + sendError(1,"Не найден запрошеный узел!"); + } + }else + if ($fn==5) //вернуть клиенту данные по id для редактирования одной записи + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $sql_query=''; + $node=findFirstNode($reqNode,'type'); + $typename=$node->getAttribute("n"); + $idval=$node->getAttribute("id"); //Значение идентификатора + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + //Тип поля с ObjectID + $nField=findFirstNodeOnAttribute(findNode($currNode, 'properties'), "prop", "n", $node->getAttribute('ObjectID')); + $csql=findNode(findFirstNodeOnAttribute($currNode, "sql-query", "t", "s"), "#cdata-section"); + if($csql!=NULL && $csql->nodeValue!="") //Есть ли SQL запрос + { + $sql_query=$csql->nodeValue; + $sql_query=str_replace('${'.$node->getAttribute("ObjectID").'}',getSQLValue($nField->getAttribute('vt'),$idval),$sql_query); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + } + } + //sendError(1,$sql_query); + try + { + $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + if(strpos($db_connection, 'sqlite')===false) //Для SQLite не работает rowCount() + { + if($res->rowCount()!=1) sendError(1,"Количество записей не равно одному!"); + } + + $xmls=''; + $resX = $db->query('select xml from '.$Schema.'_metadata where del=false and name=\''.$typename.'\';'); + while ($rowX = $resX->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmls=''.trts($rowX['xml']).''; + } + if($xmls=='') + { + sendError(1,"Metadata node \"".$name."\" is empty!"); + } + + //загружаем мета данные и смотрим какие поля должны передать клиенту + $mdoc = new DOMDocument(); + try + { + $mdoc->loadXML($xmls); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + //находим нужный узел + $node=findNodeOnAttribute($mdoc->documentElement, "type","n",$typename); + $node=findFirstNode($node,'properties'); + + $xmlstring=''."\n"; + $xmlstring.=''."\n"; + $xmlstring.=''."\n"; + while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { $xmlstring.=''; + $nextnode=$node->firstChild; + while($nextnode) + { + if($nextnode->nodeName=='prop') + { + try + { + if(array_key_exists ( $nextnode->getAttribute("n"), $row) || ($nextnode->getAttribute("vt")=="file" && array_key_exists ( $nextnode->getAttribute("cd"), $row))) + { + if($nextnode->getAttribute("vt")=="b") + { + if($row[$nextnode->getAttribute("n")]===false) + { + $row[$nextnode->getAttribute("n")]="0"; + } else if($row[$nextnode->getAttribute("n")]===true) + { + $row[$nextnode->getAttribute("n")]="1"; + } + } + + if($nextnode->getAttribute("vt")=="blob") { //Только blob не file так как file как обычная текстовая строка (100 символов) + if(array_key_exists($nextnode->getAttribute("cd"), $row)) { + $xmlstring .= 'getAttribute("cd")] . ']]>' . "\n"; + }else{ + sendError(1,'Поле "'.$nextnode->getAttribute("cd").'" не найдено в результирующем наборе!'); + } + } + else { + $xmlstring.='getAttribute("n")].']]>'."\n"; + } + }else + { + sendError(1,'Поле "'.$nextnode->getAttribute("n").'" не найдено в результирующем наборе!'); + } + + } catch (Exception $e) { sendError(1,$e->getMessage()); } + } + $nextnode = $nextnode->nextSibling; + } + $xmlstring.=''; + } + $xmlstring.=''; + $xmlstring.=''; + + header('Content-type: text/xml'); + echo $xmlstring; + }else + if ($fn==6) //вернуть клиенту данные колонки таблицы для заполнения выпадающего списка SELECT либо выборка названия поля типа object + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $tNodeR=findFirstNode($reqNode,'type'); + $typename=$tNodeR->getAttribute("n"); //Название принятого узла + $columnname=$tNodeR->getAttribute("c"); //Столбец для выбора (через , могут перечислятся) + $columns=explode(",",$columnname); + $propName=$tNodeR->getAttribute("pn"); //Название поля нигде не используется передаётся обратно в результат + //Теперь а нутри фильтра передаётся поэтому ненужно $propid=$tNodeR->getAttribute("id"); //-1 или '' то много записей иначе 1 должна вернуться + //if($propid==-1 || $propid=='') $propid='NULL'; + + + $currNode=getMetadataNode($typename); + if($currNode==null) sendError(1,"Not find \"".$typename."\"!"); + $objXMLDocument=$currNode->ownerDocument; + + $objListR = findFirstNode($tNodeR,'objects-list'); //Из запроса + $f1=findNodeOnPath($currNode, 'objects-list/filter'); + $f2=findNodeOnPath($tNodeR,'objects-list/filter'); + + setFilter($f1,$f2);//заменить все значения первого фильтра значениями из второго + + $sql_query=getCdataValue(findNodeOnPath($currNode, "objects-list/sql-query")); + if($f1!=NULL) + { + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $val=getSQLValue($nextnode->getAttribute("vt"),getCdata($nextnode)->nodeValue); + $sql_query=str_replace('${'.$nextnode->getAttribute("n").'}',$val,$sql_query); + } + $nextnode = $nextnode->nextSibling; + } + } + //$sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue(gettype($propid),$propid),$sql_query); //Чтоб вернулась 1 запись если это не выпадающий + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + if($objListR!=null && $objListR->getAttribute('order')!='' && $objListR->getAttribute('order')!=null && $objListR->getAttribute('order')!='null') + { + $sql_query=str_replace('${_order}',findNodeOnAttribute(findFirstNode($currNode,'objects-list'), "column","n",$objListR->getAttribute("order"))->getAttribute("order"),$sql_query); + }else $sql_query=str_replace('${_order}','1',$sql_query); + + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + + //выбираем данные из базы и отправляем клиенту + $xmlstring=''."\n"; + $xmlstring.=''."\n"; + $xmlstring.=''."\n"; + while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmlstring.=''; + $val=""; + for($i=0;$i'; + $xmlstring.=''."\n"; + } + $xmlstring.=''."\n";; + $xmlstring.=''."\n";; + header('Content-type: text/xml'); + echo $xmlstring; + }else + if ($fn==7)//Залогинеться + { + $cmd=getCdataValue(findFirstNode($reqNode,"cmd")); + $login=getCdataValue(findFirstNode($reqNode,"login")); + $password=getCdataValue(findFirstNode($reqNode,"password")); + $key=getCdataValue(findFirstNode($reqNode,"key")); + $time=getCdataValue(findFirstNode($reqNode,"time")); + $guid=getCdataValue(findFirstNode($reqNode,"guid")); //Зачем коментил? + + if($cmd==0) //Restore password by email + { + $recovery=false; + $res = $db->query("select email from ".$Schema."_Users where del=false and (email = '$login' or login = '$login');"); + if($res->rowCount()>0) + { + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + /*$pos++; + if (($pagepos!=-1)&&(($pos<($pagepos*$rowspagecount))||($pos>=$pagepos*$rowspagecount+$rowspagecount))) { continue; } + + //разрешать или запрещять редактировать запись надо проверять в хранимке а также запрещять либо разрешать редактировать колонку + //для каждой записи формируеться строка настроек со значениями что нужно запретить в таком виде "iuds" + //$access=$row["access"]; + $access=''; //u = enable update field, d = enable delete field + if(!array_key_exists("_u",$row)) { $access.="u"; } else { $access.=$row["email"]; }*/ + + $password = getPassword(6); + $sql = 'update ' . $Schema . '_users set password=md5(:password) where email=:email'; + $stmt = $db->prepare($sql); + $stmt->bindValue(':password', $password, PDO::PARAM_STR); + $stmt->bindValue(':email', $row["email"], PDO::PARAM_STR); + try { + $stmt->execute(); + if ($stmt->rowCount() > 0) { + //$result = $stmt->fetch(PDO::FETCH_NUM); + $recovery = true; + } + } catch (Exception $e) { + $db->rollBack(); + sendError(1, $e->getMessage()); + } + + $html = 'Message'; + $html .= '

New password:

'; + $html .= '' . $password . ''; + $html .= ''; + //mail($login,'rigor.kz','Not implement',"Content-type: text/html; charset=utf-8\r\nFrom: rigor Site "); + if (!mail($login, 'Password for monitoring', $html, "Content-type: text/html; charset=utf-8\r\nFrom: Transit Site ")) { + sendError(1,"Failed to send mail to: " . $row["email"]); + } + } + } + if($recovery) { + $xs = '' . "\n"; + $xs .= ''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + }else{ + $xs = '' . "\n"; + $xs .= ''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + } + + }elseif($cmd==1) //Logout + { + $sql='delete from '.$Schema.'_Logins where sessionid='.getSQLValue('string',$_COOKIE['GUID']).' and user_id='.getSQLValue('object',$_SESSION['USER_ID']).';'; + try + { $db->exec($sql); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + unset($_SESSION['USER_ID']); + + $xs=''."\n"; + $xs.=''."\n"; + $xs.=' '."\n"; + $xs.=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + + }elseif($cmd==2) //Проверить залогинен ли пользователь + { + $xs=''."\n"; + $xs.=''."\n"; + if(!isset($_SESSION['USER_ID']) || $_SESSION['USER_ID']=='') + { + $xs.=' '."\n"; + }else + { + $xs.=' '."\n"; + $res = $db->query('select * from '.$Schema.'p__Login('.getSQLValue($idType,$_SESSION['USER_ID']).',null,null,null,null,null);'); + if($row = $res->fetch(PDO::FETCH_ASSOC)) + { + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + } + } + $xs.=''; + + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + + }elseif ($cmd==3) //Авторизация по логину и паролю + { + //По идентификатору выбираем информацию о пользователе + $ans='0'; + $name=''; + $surname=''; + $patronymic=''; + $expiration=false; + $overdue=false; + $sql="select * from ".$Schema."p__Login(".getSQLValue($idType,$_SESSION['USER_ID']).",'$login','$password',null,null,null);"; + try + { + $res = $db->query($sql); + } catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()); + } + if($res->rowCount()>0) + { + $result = $res->fetch(PDO::FETCH_ASSOC); + $ans='1'; + $_SESSION['USER_ID']=$result['id']; + $name=$result['name']; + $surname=$result['surname']; + $patronymic=$result['patronymic']; + $expiration=$result['expiration']; //Дата смены пароля + $overdue=$result['overdue']; //Просрочен ли пароль + //Проверяю на соответствие токену TOPT если секретный ключ задан + if($result['secret']){ + $secret = Base32::decode($result['secret']); + $genkey = (new Totp('sha1',0,60))->GenerateToken($secret,$time); + if($key != $genkey) { + $ans = '0'; + $_SESSION['USER_ID'] = ''; + } + } + } + $xs=''."\n"; + $xs.=''."\n"; + $xs.=''; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + }else{ + sendError(1,'Command "'.$cmd.'" not find!'); + } + + }else + if ($fn==8)//Получить отчёт как Excel.xls файл (почти тоже самое что и функция 4) + { + $dir='./temp/'; + // отправка файла в отдельном файле download.php для совместимости с java версией + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + //Выбираем информацию о текущем пользователе + $name=''; + $sql="select Coalesce(surname,'') || ' ' || Coalesce(name,'') || ' ' || Coalesce(patronymic,'') as name from ".$Schema."_users where id=:user_id;"; + $stmt = $db->prepare($sql); + $stmt->bindValue(':user_id', $_SESSION['USER_ID'], PDO::PARAM_INT); + $res=$stmt->execute(); + if($res && $stmt->rowCount()>0) + { $result = $stmt->fetch(PDO::FETCH_ASSOC); + $name=''.$result['name'].'
'; + } + $res=null; //Чтоб сработал сборщик мусора, а то вываливается ошибка: "Cannot execute queries while other unbuffered queries are active". + + $nTypeR=findFirstNode($reqNode,'type'); + $typename=$nTypeR->getAttribute("n"); + $ext=$nTypeR->getAttribute("ext"); + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $objListR = findFirstNode($nTypeR,'objects-list'); + //В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного + $f1=findNodeOnPath($currNode,'objects-list/filter'); + $f2=findNodeOnPath($nTypeR,'objects-list/filter'); + setFilter($f1,$f2);//заменить все значения первого фильтра значениями из второго + + //Текстовые данные заполняются в поле caption и они вставляются в поля для информации что было заполнено + //Выбираем параметры фильтра (Для информирования что было заполнено) + $filter=''.trt('Filter_options').'
'; + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { + if($nextnode->getAttribute('visible')!='0') + { + $filter.=''.$nextnode->getAttribute("d").': '; + if($nextnode->getAttribute("vt")=='object') + { + if(getCdataValue($nextnode)=='') + { $filter.=''; + }else + { + //Ищем нужный узел и выполняем запрос + $nTypeO=getMetadataNode($nextnode->getAttribute("object")); + //$nTypeO=findNodeOnAttribute($objXMLDocument->documentElement,"type","n",$nextnode->getAttribute("object")); + $sql_query=getCdataValue(findNodeOnPath($nTypeO, "objects-list/sql-query")); + + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + + $nOID=findNodeOnAttribute(findNodeOnPath($nTypeO, "objects-list/filter"), 'column', 'n', $nTypeO->getAttribute('ObjectID')); + $sql_query=str_replace('${'.$nOID->getAttribute('n').'}',getSQLValue($nOID->getAttribute('vt'), getCdataValue($nextnode)),$sql_query); + + //Обнуляем остальные значения фильтра + $nCol=findNodeOnPath($nTypeO, "objects-list/filter")->firstChild; + while ($nCol) + { if ($nCol->nodeName=='column') + { $sql_query=str_replace('${'.$nCol->getAttribute("n").'}','NULL',$sql_query); + } + $nCol = $nCol->nextSibling; + } + + $res=null; + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + if($res->rowCount()!=1) sendError(1,trt('The number of records is not equal to one!').' '.$sql_query); + + + $columns=explode(",",$nextnode->getAttribute('FieldCaption')); + if($res->rowCount()>0) + { + $row = $res->fetch(PDO::FETCH_ASSOC); + for($i=0;$igetAttribute("vt")=='b') + { + if(getCdataValue($nextnode)=='1') $filter.='Да'; + if(getCdataValue($nextnode)=='0') $filter.='Нет'; + }else + { + $filter.=getCdataValue($nextnode); + } + $filter.='
'; + } + } + $nextnode = $nextnode->nextSibling; + } + + $sql_query=getCdataValue(findNodeOnPath($currNode, "objects-list/sql-query")); + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $vt=$nextnode->getAttribute("vt"); + $val=getCdataValue($nextnode); + $val=getSQLValue($vt,$val); + $sql_query=str_replace('${'.$nextnode->getAttribute("n").'}',$val,$sql_query); + } + $nextnode = $nextnode->nextSibling; + } + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + if($objListR!=null && $objListR->getAttribute('order')!='' && $objListR->getAttribute('order')!=null && $objListR->getAttribute('order')!='null') + { + $sql_query=str_replace('${_order}',findNodeOnAttribute(findFirstNode($currNode,'objects-list'), "column","n",$objListR->getAttribute("order"))->getAttribute("order"),$sql_query); + }else $sql_query=str_replace('${_order}','1',$sql_query); + + //Выполняем запрос + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage().$sql_query); + } + + //Сохраняем результсет в файл в виде HTML с расширением XLS + $num=rand(0,1000); + $file='file_'.$num.'.xls'; + $myFile = $dir.$file; + + if(($fh = @fopen($myFile, 'w')) !== FALSE){ + fwrite($fh, ''."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '.$currNode->getAttribute("d").''."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ''); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + + fwrite($fh, ''.trt('Time_and_date_of_generation').': '.date('H:i:s m.d.Y').'
'); + fwrite($fh, ''.trt('Creator').': '.$name); + fwrite($fh, $filter); + + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '); + fwrite($fh, ''); + $nextnode=findNode($currNode,'objects-list')->firstChild; + $col=0; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { fwrite($fh, '"); + } + $nextnode = $nextnode->nextSibling; + } + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + $pos=0; + while ($row = $res->fetch(PDO::FETCH_ASSOC)) + { + fwrite($fh, ' '); + fwrite($fh, ''); + $nextnode=findNode($currNode,'objects-list')->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { + fwrite($fh, ''); + } + $nextnode = $nextnode->nextSibling; + } + fwrite($fh, ''."\n"); + } + $res->closeCursor(); //Мож поможет избавиться от ошибки: "Cannot execute queries while other unbuffered queries are active." + + fwrite($fh, ' '."\n"); + fwrite($fh, '
'.findNode($currNode,'objects-list')->getAttribute("d").'
'.$nextnode->getAttribute("d")."
'.(++$pos).''.$row[$nextnode->getAttribute("n")].'
'."\n"); + + fwrite($fh, ' '."\n"); + fwrite($fh, ''."\n"); + + fclose($fh); + }else{ + sendError(1,trt('Failed_to_generate_report')); + } + + /*if($ext=="pdf") + { + //Если в виде PDF + $mpdf = new mPDF('utf-8', 'A4', '8', '', 10, 10, 7, 7, 10, 10); // задаем формат, отступы и.т.д. + $mpdf->list_indent_first_level = 0; + $mpdf->WriteHTML(file_get_contents($myFile)); // формируем pdf + + $dir='./temp/'; + $file='file_'.$num.'.pdf'; + $myFile = $dir.$file; + + $mpdf->Output($myFile, 'F'); + }*/ + //$myFile=getFullPath().'temp/'.$file; + + //отправляем ссылку на файл TODO переделать в JSON + header('Content-type: text/xml'); + echo ''; + + //deleteTempFiles($dir); + }else + { + sendError(1,trt('Not found the requested node:').' "'.$typename.'"!'); + } + + }else + if ($fn==9) //Сохранить файл во временную папку + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + $dir = "./temp/"; + if (!file_exists($dir)) { + mkdir($dir, 0777); + } + + //Так как у файлов могут быть одинаковые имена считаем CRC и переименовываем файл отправля пользователю новое название файла + //В базе данных название файла будет преобразовываться так: "файл.txt" -> "файл_crc32.txt" + if(isset($_FILES['file'])) + { + if(file_exists($_FILES['file']['tmp_name'])) + { + $hash = hash_file( 'crc32', $_FILES['file']['tmp_name'] ); + if(move_uploaded_file($_FILES['file']['tmp_name'],delPHPExt($dir.$hash.'.'.strtolower(getExtension($_FILES['file']['name']))))) + { + //Отправляем новое название файла клиенту + print "ok=".beforeLast($_FILES['file']['name'],'.').'_'.$hash.'.'.strtolower(getExtension($_FILES['file']['name']))."\n"; + } + }else { print "ok=\n File \"".$_FILES['file']['tmp_name']."\" not find"; } + } + + //Данный код загружается в iframe + print ''; + print ''; + print ' '; + print ' '; + print ' '; + print ' '; + print '
'; + print ' '; + print '
'; + print ' '; + print ' '; + print '
'; + print ' '; + print ''; + + //Отчищяем временные файлы которые больше суток на сервере + deleteTempFiles($dir); + + }else + if ($fn==10) //Отправить двоичные данные клиенту в виде файла (пока без докачки) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + //Клиент передаёт название таблицы, название поля, id поля + $typename = $_REQUEST['t']; //Тип + $field = $_REQUEST['f']; //Название поля с двоичными данными + $name = $_REQUEST['n']; //поле с названием файла + $idval = $_REQUEST['i']; //Идентификатор поля в базе + + $xmls=''; + $resX = $db->query('select xml from '.$Schema.'_metadata where del=false and name=\''.$typename.'\';'); + while ($rowX = $resX->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmls=''.trts($rowX['xml']).''; + } + if($xmls=='') + { + sendError(1,"Metadata node \"".$name."\" is empty!"); + } + + //Ищем поле в метаданных + $objXMLDocument = new DOMDocument(); + try + { + $objXMLDocument->loadXML($xmls); + } catch (Exception $e) + { echo $e->getMessage(); + } + + $currNode=findNodeOnAttribute($objXMLDocument->documentElement,"type","n",$typename); + if ($currNode!=null) + { + $pnode=findFirstNode($currNode,'properties'); + $fnode=findFirstNodeOnAttribute($pnode,"prop","n",$field); //Поле в metedata.xml файла + $nnode=findFirstNodeOnAttribute($pnode,"prop","n",$fnode->getAttribute("cd")); //Поле в metedata.xml с именем файла + + if($fnode->getAttribute("vt")=="blob") //Отправить файл клиенту из базы данных + { + $stmt = $db->prepare("SELECT \"$field\",length(\"$field\"),substring(\"$name\", position('_' IN \"$name\")+1) as name FROM $Schema\"$typename\" WHERE id='$idval'"); + $stmt->execute(); + $stmt->bindColumn(1, $blob, PDO::PARAM_LOB); + $stmt->bindColumn(2, $size, PDO::PARAM_INT); + $stmt->bindColumn(3, $name, PDO::PARAM_STR); + $stmt->fetch(PDO::FETCH_BOUND); + $data = stream_get_contents($blob); + + header("Content-type: application/octet-stream"); + header('Content-Disposition: attachment; filename="'.$name.'"'); + header('Content-Length: '.$size); + echo $data; + }else if($fnode->getAttribute("vt")=="file") //Отправить файл клиенту из файловой системы + { + //Тип поля с ObjectID + $nField=findFirstNodeOnAttribute(findNode($currNode, 'properties'), "prop", "n", $currNode->getAttribute('ObjectID')); + $csql=findNode(findFirstNodeOnAttribute($currNode, "sql-query", "t", "s"), "#cdata-section"); + if($csql!=NULL && $csql->nodeValue!="") //Есть ли SQL запрос + { + $sql_query=$csql->nodeValue; + $sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue($nField->getAttribute('vt'),$idval),$sql_query); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + } + + $res = $db->query($sql_query); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) + { + $fname = $row[$field]; + } + $dataFName = afterLast($fname,'_'); + $rezFName = beforeLast($fname,'_'); + $rezFName .= '.'.afterLast($fname,'.'); + + if(file_exists($_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName)) + { + header("Content-type: application/octet-stream"); + header('Content-Disposition: attachment; filename="'.$rezFName.'"'); + header('Content-Length: '.filesize($_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName)); + readfile($_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName); + exit(); + }else + { + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); + echo 'File "'.$_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName.'" not found!'; + exit; + } + } + } + }else + { + sendError(1,"Неизвестная функция \"$fn\"!"); + } + + diff --git a/metadata/dbms/edit_object.js b/metadata/dbms/edit_object.js new file mode 100644 index 0000000..e69de29 diff --git a/metadata/dbms/edit_object.vue b/metadata/dbms/edit_object.vue new file mode 100644 index 0000000..0c001fc --- /dev/null +++ b/metadata/dbms/edit_object.vue @@ -0,0 +1,40 @@ + + + + + \ No newline at end of file diff --git a/metadata/dbms/records.xyz b/metadata/dbms/records.xyz new file mode 100644 index 0000000..17deef9 --- /dev/null +++ b/metadata/dbms/records.xyz @@ -0,0 +1,1450 @@ +error_code=$code; + $obj->error_message=$error; + header('Content-Type: application/json'); + header("Cache-Control: no-cache, must-revalidate"); + echo json_encode($obj); + exit(); + } + + function getSQLValue($t,$v) + { + global $db_connection; + + if($t=='object' && gettype($v)=='string'){ + $t='string'; //Если id шники uuid + } + + if($t=='object'){ + if ($v=='-1'||$v=='' || $v==null) $v='NULL'; + }else + if($t=='i1' || $t=='i2' || $t=='i4' || $t=='integer'){ + if($v=='') $v='NULL'; + }else + if($t=='f8' || $t=='f4' || $t=='real' || $t=='double'){ + if($v=='')$v='NULL'; + $v=str_replace(',','.',$v); //Разделитель целой и дробной части точка + }else + if($t=='b'){ + if($v=='') $v='NULL'; else + if($v=='1') $v='true'; else + if($v=='0') $v='false'; + }else + if($t=='string' || $t=='html' || $t=='text' || $t=='dateTime' || $t=='time' || $t=='date' || $t=='file') { + if ($v == '') { + $v = 'NULL'; + } else { + if (strpos($db_connection, 'pgsql') !== false) + $v = str_replace("'", "''", $v); //так как в SQL строку вставляется + else + $v = str_replace('\'', '\\\'', $v); //так как в SQL строку вставляется + $v = '\'' . $v . '\''; + } + }else if($t=="NULL" || $t==null){ + if ($v == '') { + $v = 'NULL'; + } else { + $v='\''.$v.'\''; + } + }else{ + $v='\''.$v.'\''; + } + return $v; + } + + function getValue($t,$v) + { + if($t=='object' && gettype($v)=='string'){ + $t='string'; //Если id шники uuid + } + + if($t=='object'){ + if (($v=='-1')||($v=='')) $v=null; + }else + if($t=='i4' || $t=='integer'){ + if($v=='') $v=null; + }else + if($t=='f8'){ + if($v=='')$v=null; + $v=str_replace(',','.',$v); //Разделитель целой и дробной части точка + }else + if($t=='b'){ + if($v=='') $v=null; else + if($v=='1') $v=true; else + if($v=='0') $v=false; + }else + if($t=='string' || $t=='dateTime' || $t=='date'){ + if($v=='') $v=null; + } + return $v; + } + + function getPDOTypeParam($t) + { + //if($t=='object' && gettype($v)=='string') $t='string'; //Если id шники uuid + + if($t=='object') + { //return PDO::PARAM_INT; + return PDO::PARAM_STR; + }else + if($t=='i4' || $t=='integer') + { return PDO::PARAM_INT; + }else + if($t=='f8') + { return PDO::PARAM_STR; + }else + if($t=='b') + { return PDO::PARAM_BOOL; + }else + if($t=='string' || $t=='dateTime' || $t=='date') + { return PDO::PARAM_STR; + }else + if($t=='blob') + { return PDO::PARAM_LOB; + }else + return PDO::PARAM_STR; + } + + //Заменить все значения первого фильтра значениями из второго + function setFilter($n1,$n2) + { + if($n1==null || $n2==null) return; + $nc1=$n1->firstChild; + while ($nc1) + { + if ($nc1->nodeName=='column') + { + $nc2=findNodeOnAttribute($n2, 'column', 'n', $nc1->getAttribute("n")); + if($nc2) getCdata($nc1)->nodeValue=getCdata($nc2)->nodeValue; + } + $nc1 = $nc1->nextSibling; + } + } + + //Получить узел метаданных из базы данных + function getMetadataNode($name) + { + global $db,$Schema; + + $xmls=''; + $sql='select xml from '.$Schema.'_metadata where del=false and name=\''.$name.'\';'; + $resX = $db->query($sql); + while ($rowX = $resX->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmls=''.trts($rowX['xml']).''; + } + if($xmls!='') + { + //sendError(1,"Metadata node \"".$name."\" not find in database!"); + $objXMLDocument = new DOMDocument(); + try + { + $objXMLDocument->loadXML($xmls); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + $currNode=findNodeOnAttribute($objXMLDocument->documentElement, "type","n",$name); + return $currNode; + }else{ + return null; + } + } + + function special_handler($exception) + { + sendError(1,$exception->getMessage()); + } + set_exception_handler('special_handler'); //чтоб не пойманные исключения посылались в виде XML + + //Схема базы по умолчанияю + if(!isset($Schema)) { + $Schema=""; + } + //Тип идентификаторов + $idType="object"; + if(!isset($idType)) { + $idType="object"; + } + + $db = connectToDB(); + if($db==null) + sendError(1,trt('Error_connection_to_DB')); + + //Пытаемся автоматически залогинется по GUID из COOKIE (TODO авторизация должна быть в отдельном файле! Смотри директорию password ) + /*if($_SESSION['USER_ID']==null && $_COOKIE['GUID']!=null) + { + $res = $db->query("select * from ".$Schema."p__Login(null,null,null,'".$_COOKIE['GUID']."');"); + //$res = $db->query("select * from p__Login_1(null,null,null,'".$_COOKIE['GUID']."');"); + if($res->rowCount()>0) + { + $result = $res->fetch(PDO::FETCH_ASSOC); + $_SESSION['USER_ID']=$result['id']; + } + }*/ + + $fn=filter_input(INPUT_GET, 'fn', FILTER_VALIDATE_INT, array('options'=>array('default'=>-1))); + + $HTTP_INPUT=file_get_contents("php://input"); + if($HTTP_INPUT) + { + $doc = new DOMDocument(); + try + { + $doc->loadXML($HTTP_INPUT); + } catch (Exception $e) + { + sendError(1,$e->getMessage()); + } + $reqNode = $doc->documentElement; + + if ($reqNode) + { + $fn = $reqNode->getAttribute("fn"); //Номер функции + } + } + +//описание +//(fn==0) - отправить метаданные клиенту по запрошенному узлу +//(fn==1) - вставить одну запись в базу данных (результат id записи) +//(fn==2) - обновить запись +//(fn==3) - удалить запись +//(fn==4 || fn==11) - отправить данные клиенту соответствии с значением фильтра +//(fn==5) - взять данные для редактирования 1й записи по id +//(fn==6) - вернуть клиенту данные для заполнения обьекта SELECT выделенно в отдельную функцию для экономии трафика здесь могут также использоваться фильтры +//(fn==7) - залогинеться +//(fn==8) - отчёты почти тоже самое что и функция 4 +//(fn==9) - Сохранить двоичные данные в базу +//(fn==10) - Получить двоичные данные из базы + + if ($fn==0) //отправить метаданные клиенту по запрошенному узлу + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $typename=findFirstNode($reqNode, "type")->getAttribute("n"); + $currNode=getMetadataNode($typename); + + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + //Вернём значение прав доступа для запрошенного объекта + $allow_ins=false; + $allow_upd=false; + $allow_del=false; + $sql_query='select '.$Schema.'p_getaccess(:user_id1,:action_insert) as ins,'.$Schema.'p_getaccess(:user_id2,:action_update) as upd,'.$Schema.'p_getaccess(:user_id3,:action_delete) as del;'; + $stmt = $db->prepare($sql_query); + $stmt->bindValue(':user_id1', $_SESSION['USER_ID'], PDO::PARAM_INT); //getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']) + $stmt->bindValue(':user_id2', $_SESSION['USER_ID'], PDO::PARAM_INT); //getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']) + $stmt->bindValue(':user_id3', $_SESSION['USER_ID'], PDO::PARAM_INT); //getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']) + $stmt->bindValue(':action_insert', 'Insert_'.$typename, PDO::PARAM_STR); + $stmt->bindValue(':action_update', 'Update_'.$typename, PDO::PARAM_STR); + $stmt->bindValue(':action_delete', 'Delete_'.$typename, PDO::PARAM_STR); + $res=$stmt->execute(); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) + { + $allow_ins=$row['ins'] == 't'; + $allow_upd=$row['upd'] == 't'; + $allow_del=$row['del'] == 't'; + } + $xmlAttr = $objXMLDocument->createAttribute("ins"); //insert + $xmlAttr->nodeValue = $allow_ins ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + $xmlAttr = $objXMLDocument->createAttribute("upd"); //update + $xmlAttr->nodeValue = $allow_upd ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + $xmlAttr = $objXMLDocument->createAttribute("del"); //delete + $xmlAttr->nodeValue = $allow_del ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + + $allow=true; + $xmlAttr = $objXMLDocument->createAttribute("sel"); //select + $xmlAttr->nodeValue = $allow ? "1" : "0"; + $currNode->setAttributeNode($xmlAttr); + + //Удаляем все запросы из узла + for($i=0;$i<5;$i++) + { $nsql=findFirstNode($currNode, "sql-query"); + if($nsql!=NULL) $nsql->parentNode->removeChild($nsql); + } + + $xmlstring=''.$objXMLDocument->saveXML($currNode).''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==1) //вставка записи (результат id записи) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $typename=findFirstNode($reqNode,"type")->getAttribute("n"); + $currNode=getMetadataNode($typename); + + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $sql_query=getCdataValue(findFirstNodeOnAttribute($currNode, "sql-query", "t", "i")); + + $nodeProp=findFirstNode($reqNode,"properties"); + //Представляем SQL в виде параметров + $nodePropData=$nodeProp->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + if($vt=='blob') + { $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',':'.$nodePropData->getAttribute("n"),$sql_query); + //Название файла запишем в указаное поле + $val=getCdataValue($nodePropData); + $cd=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("cd"); + $nd=findFirstNodeOnAttribute($nodeProp,'prop','n',$cd); + if($nd!=null) { getCdata($nd)->nodeValue=$val; } + }else if($vt=='file') + { + $val=getCdataValue($nodePropData); + $valSql=getSQLValue($vt, $val); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$valSql,$sql_query); + //Копируем файл из './temp/' в указанную папку относительно корня сайта + $flnm = afterLast($val,'_'); + $dir = "./temp/"; + if($val!='' && file_exists($dir.$flnm)) + { + $path= $_SERVER['DOCUMENT_ROOT'].'/'.findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("path"); + @mkdir($path); //Создаём папку если её нет + if(!rename($dir.$flnm, $path.$flnm)) + sendError(1,'Can\'t rename to "'.$path.$v.'"!'); + } + }else + { $v=getSQLValue($vt, getCdataValue($nodePropData)); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$v,$sql_query); + } + } + $nodePropData=$nodePropData->nextSibling; + } + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); //Потому что PostgreSQL не может хранить id пользователя привязаного к сесии + + $stmt = $db->prepare($sql_query); + if($stmt === false) sendError(1,'Error preparing Statement'); + + //присваеваем параметрам значения (В записи может быть только 1 двоичное поля см bindParam или сделать несколько переменных) + $nodePropData=$nodeProp->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + //Если тип blob то в качастве параметра приходит название файла переданого на сервер заранее + if($vt=='blob') + { $v=getCdataValue($nodePropData); + if($v!='' && file_exists('./temp/'.afterLast($v,'_'))) + { $v = fopen('./temp/'.afterLast($v,'_'), 'rb'); + } else $v=null; + $stmt->bindParam(':'.$nodePropData->getAttribute("n"), $v, PDO::PARAM_LOB); + } + } + $nodePropData=$nodePropData->nextSibling; + } + try + { + $res = $stmt->execute(); + } catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()); + } + $result = $stmt->fetch(PDO::FETCH_NUM); + if($result[0]=='') + { + if(strpos($db_connection, 'sqlite')!==false) { + $result[0] = $db->lastInsertId(); //Для SQLite + }else{ + sendError(1,trt('Failed_to_insert_record').'!'); + } + } + + $xmlstring=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==2) //редактирование (результат id записи) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $nodeType=findFirstNode($reqNode,"type"); + $typename=$nodeType->getAttribute("n"); + $obj_id=$nodeType->getAttribute("id"); + $node_properties=findFirstNode($nodeType,"properties"); + + $currNode=getMetadataNode($typename); + + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $sql_query=getCdataValue(findFirstNodeOnAttribute($currNode, "sql-query", "t", "u")); + //Представляем blob поля в SQL запросе в виде параметров + $nodeProps=findFirstNode($reqNode,"properties"); + $nodePropData=$nodeProps->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + if($vt=='blob') + { $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',':'.$nodePropData->getAttribute("n"),$sql_query); + //Название файла запишем в указаное поле + $val=getCdataValue($nodePropData); + $cd=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("cd"); //Имя поля с которого нужно брать название файла + $nd=findFirstNodeOnAttribute($nodeProps,'prop','n',$cd); + if($nd!=null) getCdata($nd)->nodeValue=$val; + }else if($vt=='file') //Файл который не загружается в базу а храниться в файловой системе + { + $val=getCdataValue($nodePropData); + $valSql=getSQLValue($vt, $val); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$valSql,$sql_query); + //Копируем файл в указанную папку относительно корня сайта + $flnm = afterLast($val,'_'); + $dir = "./temp/"; + if($val!='' && file_exists($dir.$flnm)) + { + $path= $_SERVER['DOCUMENT_ROOT'].'/'.findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("path"); + @mkdir($path);//Создаём папку если её нет + if(!rename($dir.$flnm, $path.$flnm)) + sendError(1,'Can\'t rename to "'.$path.$v.'"!'); + } + }else + { + $val=getSQLValue($vt, getCdataValue($nodePropData)); + $sql_query=str_replace('${'.$nodePropData->getAttribute("n").'}',$val,$sql_query); + } + } + $nodePropData=$nodePropData->nextSibling; + } + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); //Потому что PostgreSQL не может хранить id пользователя привязаного к сесии + $sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue(gettype($obj_id),$obj_id),$sql_query); //Так как пока идентификатор базы отдельно передаётся + +//sendError(1,$sql_query); + $stmt = $db->prepare($sql_query); + if($stmt === false) sendError(1,'Error preparing Statement'); + + //Присваеваем параметру двоичную информацию (Внимание! Только 1 параметр может быть в 1 записи (почему?)) + $pos_v = 0; + $mas_v[$pos_v]=null; //Чтобы данные не перекрывали друг друга при вставке + $nodePropData=$nodeProps->firstChild; + while($nodePropData != null) + { + if (($nodePropData->nodeName=="prop")) + { + //$vt=findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n"))->getAttribute("vt"); + $nPropR = findFirstNodeOnAttribute($currNode,"prop","n",$nodePropData->getAttribute("n")); + if($nPropR!=NULL) { $vt=$nPropR->getAttribute("vt"); } else { $vt=''; } + + if($vt=='blob') + { + $path_v=getCdataValue($nodePropData); + if($path_v!='' && file_exists('./temp/'.afterLast($path_v,'_'))) + { $v = fopen('./temp/'.afterLast($path_v,'_'), 'rb'); + }else + { $v=null; + } + $mas_v[$pos_v]=$v; + $stmt->bindParam(':'.$nodePropData->getAttribute("n"), $mas_v[$pos_v], PDO::PARAM_LOB); + $pos_v++; + } + } + $nodePropData=$nodePropData->nextSibling; + } + + try + { $res = $stmt->execute(); + } catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) //If already sending short error text. + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()."\n".$sql_query); + } + $result = $stmt->fetch(PDO::FETCH_NUM); //$obj_id + if($result[0]==''){ $result[0]=$obj_id; } + $xmlstring=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==3) //удаление (результат id записи) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $nodeType=findFirstNode($reqNode,"type"); + $typename=$nodeType->getAttribute("n"); + $obj_id=$nodeType->getAttribute("id"); + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $sql_query=getCdataValue(findFirstNodeOnAttribute($currNode, "sql-query", "t", "d")); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); //Потому что PostgreSQL не может хранить id пользователя привязаного к сесии + $sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue(gettype($obj_id),$obj_id),$sql_query); + + //Выполняем + try + { $res = $db->query($sql_query); + }catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) //If already sending short error text. + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()."\n".$sql_query); + } + //записываем id удалённой записи для удаления без перезагрузки страницы через javascript + $xmlstring=""; + $xmlstring.="\n"; + $xmlstring.=''; + $xmlstring.=" \n"; + $xmlstring.="\n"; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xmlstring; + Exit(); + }else + { + sendError(1,'Не найден запрошенный узел: "'.$typename.'"!'); + } + }else + if ($fn==4 || $fn==11) //взять данные из базы по переданным значениям фильтра ($fn==11 для обновления записи у клиента после вставки или редактировании) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $rowspagecount = 100; //записей на страницу + $nTypeR=findFirstNode($reqNode,'type'); + $typename=$nTypeR->getAttribute("n"); + $pagepos=$nTypeR->getAttribute("pp"); //текущяя страница page pos + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $objListR = findFirstNode($nTypeR,'objects-list'); + //В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного + $f1=findNodeOnPath($currNode,'objects-list/filter'); + $f2=findNodeOnPath($nTypeR,'objects-list/filter'); + setFilter($f1,$f2);//заменить все значения первого фильтра значениями из второго + + $sql_query=getCdataValue(findNodeOnPath($currNode, "objects-list/sql-query")); + + if($f1!=null) + { + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $vt=$nextnode->getAttribute("vt"); + $val=getCdataValue($nextnode); + $val=getSQLValue($vt,$val); + $sql_query=str_replace('${'.$nextnode->getAttribute("n").'}',$val,$sql_query); + } + $nextnode = $nextnode->nextSibling; + } + } + $vType=gettype($_SESSION['USER_ID']); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + if($objListR!=null && $objListR->getAttribute('order')!='' && $objListR->getAttribute('order')!=null && $objListR->getAttribute('order')!='null') + { + $sql_query=str_replace('${_order}',getSQLValue('i4',findNodeOnAttribute(findFirstNode($currNode,'objects-list'), "column","n",$objListR->getAttribute("order"))->getAttribute("order")),$sql_query); + }else $sql_query=str_replace('${_order}','1',$sql_query); + + //sendError(1,$sql_query); + //Выполняем запрос + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage().' '.$sql_query); + } + //Формируем ответ + $pagecount=ceil($res->rowCount()/$rowspagecount); //Кол-во страниц + + //В месте с фильтром может прити и название полей которые нужно выбрать если есть хоть 1 поле то выберать только его + $columns = array(); + $nextnode=findNode($nTypeR,'objects-list'); + if($nextnode) + { $nextnode=$nextnode->firstChild;//Пытаемся заполнить из запроса + $i=0; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $columns[$i]=$nextnode->getAttribute("n"); + $i++; + } + $nextnode = $nextnode->nextSibling; + } + } + if(count($columns)==0)//Если нет ни одного столбца заполняем массив из серверного XML + { + $nextnode=findNode($currNode,'objects-list'); + if($nextnode) + { $nextnode=$nextnode->firstChild;//Пытаемся заполнить из запроса + $i=0; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $columns[$i]=$nextnode->getAttribute("n"); + $i++; + } + $nextnode = $nextnode->nextSibling; + } + } + } + + //перебираем RS и строим XML только из тех столбцов которые записанны в секци objects-list поля column в не зависимости от их видимости + $obj = new StdClass(); + $obj->error_code=0; + $obj->error_message = ''; + $obj->fn=$fn; + $obj->n=$typename; + $obj->pc=$pagecount; + $obj->pp=$pagepos; + //Перечисляю название выбираемых столбцов через запятую (почему в JAVA версии этого куска кода нет?) + $obj->objects_list=[]; + $nextnode=findNode($currNode,'objects-list')->firstChild; + while ($nextnode) + { + if ($nextnode->nodeName=='column') + { + array_push($obj->objects_list,$nextnode->getAttribute("n")); + } + $nextnode = $nextnode->nextSibling; + } + $obj->data=[]; + + $node=findFirstNode($reqNode,'objects-list'); + $pos=-1; + while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $pos++; + if (($pagepos!=-1)&&(($pos<($pagepos*$rowspagecount))||($pos>=$pagepos*$rowspagecount+$rowspagecount))) { continue; } + + array_push($obj->data,new StdClass()); + + //разрешать или запрещять редактировать запись надо проверять в хранимке а также запрещять либо разрешать редактировать колонку + //для каждой записи формируеться строка настроек со значениями что нужно запретить в таком виде "iuds" + $access=''; //u = enable update field, d = enable delete field + if(!array_key_exists("_u",$row)) { $access.="u"; } else { $access.=$row["_u"]; } + if(!array_key_exists("_d",$row)) { $access.="d"; } else { $access.=$row["_d"]; } + + if(array_key_exists($currNode->getAttribute("ObjectID"),$row)) { + end($obj->data)->id=$row[$currNode->getAttribute("ObjectID")]; + end($obj->data)->a=$access; + }else { + end($obj->data)->id=""; + end($obj->data)->a=$access; + } + + end($obj->data)->row=[]; + + $nextnode=findNode($currNode,'objects-list')->firstChild; + while ($nextnode) + { + if ($nextnode->nodeName=='column') + { + if(array_key_exists($nextnode->getAttribute("n"),$row)) + { + $field = $nextnode->getAttribute("n"); + array_push(end($obj->data)->row,$row[$field]); + }else + { + sendError(1,"Column \"".$nextnode->getAttribute("n")."\" not exists in \"$typename\" for select!"); + } + } + $nextnode = $nextnode->nextSibling; + } + } + $res->closeCursor(); + + header('Content-Type: application/json; charset=utf-8'); + header("Cache-Control: no-cache, must-revalidate"); + echo json_encode($obj); + exit; + }else + { + sendError(1,"Не найден запрошеный узел!"); + } + }else + if ($fn==5) //вернуть клиенту данные по id для редактирования одной записи + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $sql_query=''; + $node=findFirstNode($reqNode,'type'); + $typename=$node->getAttribute("n"); + $idval=$node->getAttribute("id"); //Значение идентификатора + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + //Тип поля с ObjectID + $nField=findFirstNodeOnAttribute(findNode($currNode, 'properties'), "prop", "n", $node->getAttribute('ObjectID')); + $csql=findNode(findFirstNodeOnAttribute($currNode, "sql-query", "t", "s"), "#cdata-section"); + if($csql!=NULL && $csql->nodeValue!="") //Есть ли SQL запрос + { + $sql_query=$csql->nodeValue; + $sql_query=str_replace('${'.$node->getAttribute("ObjectID").'}',getSQLValue($nField->getAttribute('vt'),$idval),$sql_query); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + } + } + //sendError(1,$sql_query); + try + { + $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + if(strpos($db_connection, 'sqlite')===false) //Для SQLite не работает rowCount() + { + if($res->rowCount()!=1) sendError(1,"Количество записей не равно одному!"); + } + + $xmls=''; + $resX = $db->query('select xml from '.$Schema.'_metadata where del=false and name=\''.$typename.'\';'); + while ($rowX = $resX->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmls=''.trts($rowX['xml']).''; + } + if($xmls=='') + { + sendError(1,"Metadata node \"".$name."\" is empty!"); + } + + //загружаем мета данные и смотрим какие поля должны передать клиенту + $mdoc = new DOMDocument(); + try + { + $mdoc->loadXML($xmls); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + //находим нужный узел + $node=findNodeOnAttribute($mdoc->documentElement, "type","n",$typename); + $node=findFirstNode($node,'properties'); + + $xmlstring=''."\n"; + $xmlstring.=''."\n"; + $xmlstring.=''."\n"; + while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { $xmlstring.=''; + $nextnode=$node->firstChild; + while($nextnode) + { + if($nextnode->nodeName=='prop') + { + try + { + if(array_key_exists ( $nextnode->getAttribute("n"), $row) || ($nextnode->getAttribute("vt")=="file" && array_key_exists ( $nextnode->getAttribute("cd"), $row))) + { + if($nextnode->getAttribute("vt")=="b") + { + if($row[$nextnode->getAttribute("n")]===false) + { + $row[$nextnode->getAttribute("n")]="0"; + } else if($row[$nextnode->getAttribute("n")]===true) + { + $row[$nextnode->getAttribute("n")]="1"; + } + } + + if($nextnode->getAttribute("vt")=="blob") { //Только blob не file так как file как обычная текстовая строка (100 символов) + if(array_key_exists($nextnode->getAttribute("cd"), $row)) { + $xmlstring .= 'getAttribute("cd")] . ']]>' . "\n"; + }else{ + sendError(1,'Поле "'.$nextnode->getAttribute("cd").'" не найдено в результирующем наборе!'); + } + } + else { + $xmlstring.='getAttribute("n")].']]>'."\n"; + } + }else + { + sendError(1,'Поле "'.$nextnode->getAttribute("n").'" не найдено в результирующем наборе!'); + } + + } catch (Exception $e) { sendError(1,$e->getMessage()); } + } + $nextnode = $nextnode->nextSibling; + } + $xmlstring.=''; + } + $xmlstring.=''; + $xmlstring.=''; + + header('Content-type: text/xml'); + echo $xmlstring; + }else + if ($fn==6) //вернуть клиенту данные колонки таблицы для заполнения выпадающего списка SELECT либо выборка названия поля типа object + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + $tNodeR=findFirstNode($reqNode,'type'); + $typename=$tNodeR->getAttribute("n"); //Название принятого узла + $columnname=$tNodeR->getAttribute("c"); //Столбец для выбора (через , могут перечислятся) + $columns=explode(",",$columnname); + $propName=$tNodeR->getAttribute("pn"); //Название поля нигде не используется передаётся обратно в результат + //Теперь а нутри фильтра передаётся поэтому ненужно $propid=$tNodeR->getAttribute("id"); //-1 или '' то много записей иначе 1 должна вернуться + //if($propid==-1 || $propid=='') $propid='NULL'; + + + $currNode=getMetadataNode($typename); + if($currNode==null) sendError(1,"Not find \"".$typename."\"!"); + $objXMLDocument=$currNode->ownerDocument; + + $objListR = findFirstNode($tNodeR,'objects-list'); //Из запроса + $f1=findNodeOnPath($currNode, 'objects-list/filter'); + $f2=findNodeOnPath($tNodeR,'objects-list/filter'); + + setFilter($f1,$f2);//заменить все значения первого фильтра значениями из второго + + $sql_query=getCdataValue(findNodeOnPath($currNode, "objects-list/sql-query")); + if($f1!=NULL) + { + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $val=getSQLValue($nextnode->getAttribute("vt"),getCdata($nextnode)->nodeValue); + $sql_query=str_replace('${'.$nextnode->getAttribute("n").'}',$val,$sql_query); + } + $nextnode = $nextnode->nextSibling; + } + } + //$sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue(gettype($propid),$propid),$sql_query); //Чтоб вернулась 1 запись если это не выпадающий + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + if($objListR!=null && $objListR->getAttribute('order')!='' && $objListR->getAttribute('order')!=null && $objListR->getAttribute('order')!='null') + { + $sql_query=str_replace('${_order}',findNodeOnAttribute(findFirstNode($currNode,'objects-list'), "column","n",$objListR->getAttribute("order"))->getAttribute("order"),$sql_query); + }else $sql_query=str_replace('${_order}','1',$sql_query); + + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + + //выбираем данные из базы и отправляем клиенту + $xmlstring=''."\n"; + $xmlstring.=''."\n"; + $xmlstring.=''."\n"; + while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmlstring.=''; + $val=""; + for($i=0;$i'; + $xmlstring.=''."\n"; + } + $xmlstring.=''."\n";; + $xmlstring.=''."\n";; + header('Content-type: text/xml'); + echo $xmlstring; + }else + if ($fn==7)//Залогинеться + { + $cmd=getCdataValue(findFirstNode($reqNode,"cmd")); + $login=getCdataValue(findFirstNode($reqNode,"login")); + $password=getCdataValue(findFirstNode($reqNode,"password")); + $key=getCdataValue(findFirstNode($reqNode,"key")); + $time=getCdataValue(findFirstNode($reqNode,"time")); + $guid=getCdataValue(findFirstNode($reqNode,"guid")); //Зачем коментил? + + if($cmd==0) //Restore password by email + { + $recovery=false; + $res = $db->query("select email from ".$Schema."_Users where del=false and (email = '$login' or login = '$login');"); + if($res->rowCount()>0) + { + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + /*$pos++; + if (($pagepos!=-1)&&(($pos<($pagepos*$rowspagecount))||($pos>=$pagepos*$rowspagecount+$rowspagecount))) { continue; } + + //разрешать или запрещять редактировать запись надо проверять в хранимке а также запрещять либо разрешать редактировать колонку + //для каждой записи формируеться строка настроек со значениями что нужно запретить в таком виде "iuds" + //$access=$row["access"]; + $access=''; //u = enable update field, d = enable delete field + if(!array_key_exists("_u",$row)) { $access.="u"; } else { $access.=$row["email"]; }*/ + + $password = getPassword(6); + $sql = 'update ' . $Schema . '_users set password=md5(:password) where email=:email'; + $stmt = $db->prepare($sql); + $stmt->bindValue(':password', $password, PDO::PARAM_STR); + $stmt->bindValue(':email', $row["email"], PDO::PARAM_STR); + try { + $stmt->execute(); + if ($stmt->rowCount() > 0) { + //$result = $stmt->fetch(PDO::FETCH_NUM); + $recovery = true; + } + } catch (Exception $e) { + $db->rollBack(); + sendError(1, $e->getMessage()); + } + + $html = 'Message'; + $html .= '

New password:

'; + $html .= '' . $password . ''; + $html .= ''; + //mail($login,'rigor.kz','Not implement',"Content-type: text/html; charset=utf-8\r\nFrom: rigor Site "); + if (!mail($login, 'Password for monitoring', $html, "Content-type: text/html; charset=utf-8\r\nFrom: Transit Site ")) { + sendError(1,"Failed to send mail to: " . $row["email"]); + } + } + } + if($recovery) { + $xs = '' . "\n"; + $xs .= ''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + }else{ + $xs = '' . "\n"; + $xs .= ''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + } + + }elseif($cmd==1) //Logout + { + $sql='delete from '.$Schema.'_Logins where sessionid='.getSQLValue('string',$_COOKIE['GUID']).' and user_id='.getSQLValue('object',$_SESSION['USER_ID']).';'; + try + { $db->exec($sql); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + unset($_SESSION['USER_ID']); + + $xs=''."\n"; + $xs.=''."\n"; + $xs.=' '."\n"; + $xs.=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + + }elseif($cmd==2) //Проверить залогинен ли пользователь + { + $xs=''."\n"; + $xs.=''."\n"; + if(!isset($_SESSION['USER_ID']) || $_SESSION['USER_ID']=='') + { + $xs.=' '."\n"; + }else + { + $xs.=' '."\n"; + $res = $db->query('select * from '.$Schema.'p__Login('.getSQLValue($idType,$_SESSION['USER_ID']).',null,null,null,null,null);'); + if($row = $res->fetch(PDO::FETCH_ASSOC)) + { + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + } + } + $xs.=''; + + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + + }elseif ($cmd==3) //Авторизация по логину и паролю + { + //По идентификатору выбираем информацию о пользователе + $ans='0'; + $name=''; + $surname=''; + $patronymic=''; + $expiration=false; + $overdue=false; + $sql="select * from ".$Schema."p__Login(".getSQLValue($idType,$_SESSION['USER_ID']).",'$login','$password',null,null,null);"; + try + { + $res = $db->query($sql); + } catch (Exception $e) + { + if(str_contains($e->getMessage(), ']]')) + sendError(1, $e->getMessage()); + else + sendError(1, '[['.trt("SQL_query_error").']]'.$e->getMessage()); + } + if($res->rowCount()>0) + { + $result = $res->fetch(PDO::FETCH_ASSOC); + $ans='1'; + $_SESSION['USER_ID']=$result['id']; + $name=$result['name']; + $surname=$result['surname']; + $patronymic=$result['patronymic']; + $expiration=$result['expiration']; //Дата смены пароля + $overdue=$result['overdue']; //Просрочен ли пароль + //Проверяю на соответствие токену TOPT если секретный ключ задан + if($result['secret']){ + $secret = Base32::decode($result['secret']); + $genkey = (new Totp('sha1',0,60))->GenerateToken($secret,$time); + if($key != $genkey) { + $ans = '0'; + $_SESSION['USER_ID'] = ''; + } + } + } + $xs=''."\n"; + $xs.=''."\n"; + $xs.=''; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=' '."\n"; + $xs.=''; + header('Content-type: text/xml'); + header("Cache-Control: no-cache, must-revalidate"); + echo $xs; + exit(); + }else{ + sendError(1,'Command "'.$cmd.'" not find!'); + } + + }else + if ($fn==8)//Получить отчёт как Excel.xls файл (почти тоже самое что и функция 4) + { + $dir='./temp/'; + // отправка файла в отдельном файле download.php для совместимости с java версией + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + + //Выбираем информацию о текущем пользователе + $name=''; + $sql="select Coalesce(surname,'') || ' ' || Coalesce(name,'') || ' ' || Coalesce(patronymic,'') as name from ".$Schema."_users where id=:user_id;"; + $stmt = $db->prepare($sql); + $stmt->bindValue(':user_id', $_SESSION['USER_ID'], PDO::PARAM_INT); + $res=$stmt->execute(); + if($res && $stmt->rowCount()>0) + { $result = $stmt->fetch(PDO::FETCH_ASSOC); + $name=''.$result['name'].'
'; + } + $res=null; //Чтоб сработал сборщик мусора, а то вываливается ошибка: "Cannot execute queries while other unbuffered queries are active". + + $nTypeR=findFirstNode($reqNode,'type'); + $typename=$nTypeR->getAttribute("n"); + $ext=$nTypeR->getAttribute("ext"); + + $currNode=getMetadataNode($typename); + if ($currNode!=null) + { + $objXMLDocument=$currNode->ownerDocument; + + $objListR = findFirstNode($nTypeR,'objects-list'); + //В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного + $f1=findNodeOnPath($currNode,'objects-list/filter'); + $f2=findNodeOnPath($nTypeR,'objects-list/filter'); + setFilter($f1,$f2);//заменить все значения первого фильтра значениями из второго + + //Текстовые данные заполняются в поле caption и они вставляются в поля для информации что было заполнено + //Выбираем параметры фильтра (Для информирования что было заполнено) + $filter=''.trt('Filter_options').'
'; + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { + if($nextnode->getAttribute('visible')!='0') + { + $filter.=''.$nextnode->getAttribute("d").': '; + if($nextnode->getAttribute("vt")=='object') + { + if(getCdataValue($nextnode)=='') + { $filter.=''; + }else + { + //Ищем нужный узел и выполняем запрос + $nTypeO=getMetadataNode($nextnode->getAttribute("object")); + //$nTypeO=findNodeOnAttribute($objXMLDocument->documentElement,"type","n",$nextnode->getAttribute("object")); + $sql_query=getCdataValue(findNodeOnPath($nTypeO, "objects-list/sql-query")); + + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + + $nOID=findNodeOnAttribute(findNodeOnPath($nTypeO, "objects-list/filter"), 'column', 'n', $nTypeO->getAttribute('ObjectID')); + $sql_query=str_replace('${'.$nOID->getAttribute('n').'}',getSQLValue($nOID->getAttribute('vt'), getCdataValue($nextnode)),$sql_query); + + //Обнуляем остальные значения фильтра + $nCol=findNodeOnPath($nTypeO, "objects-list/filter")->firstChild; + while ($nCol) + { if ($nCol->nodeName=='column') + { $sql_query=str_replace('${'.$nCol->getAttribute("n").'}','NULL',$sql_query); + } + $nCol = $nCol->nextSibling; + } + + $res=null; + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage()); + } + if($res->rowCount()!=1) sendError(1,trt('The number of records is not equal to one!').' '.$sql_query); + + + $columns=explode(",",$nextnode->getAttribute('FieldCaption')); + if($res->rowCount()>0) + { + $row = $res->fetch(PDO::FETCH_ASSOC); + for($i=0;$igetAttribute("vt")=='b') + { + if(getCdataValue($nextnode)=='1') $filter.='Да'; + if(getCdataValue($nextnode)=='0') $filter.='Нет'; + }else + { + $filter.=getCdataValue($nextnode); + } + $filter.='
'; + } + } + $nextnode = $nextnode->nextSibling; + } + + $sql_query=getCdataValue(findNodeOnPath($currNode, "objects-list/sql-query")); + $nextnode=$f1->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { $vt=$nextnode->getAttribute("vt"); + $val=getCdataValue($nextnode); + $val=getSQLValue($vt,$val); + $sql_query=str_replace('${'.$nextnode->getAttribute("n").'}',$val,$sql_query); + } + $nextnode = $nextnode->nextSibling; + } + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + if($objListR!=null && $objListR->getAttribute('order')!='' && $objListR->getAttribute('order')!=null && $objListR->getAttribute('order')!='null') + { + $sql_query=str_replace('${_order}',findNodeOnAttribute(findFirstNode($currNode,'objects-list'), "column","n",$objListR->getAttribute("order"))->getAttribute("order"),$sql_query); + }else $sql_query=str_replace('${_order}','1',$sql_query); + + //Выполняем запрос + try + { $res = $db->query($sql_query); + } catch (Exception $e) + { sendError(1,$e->getMessage().$sql_query); + } + + //Сохраняем результсет в файл в виде HTML с расширением XLS + $num=rand(0,1000); + $file='file_'.$num.'.xls'; + $myFile = $dir.$file; + + if(($fh = @fopen($myFile, 'w')) !== FALSE){ + fwrite($fh, ''."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '.$currNode->getAttribute("d").''."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ''); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + + fwrite($fh, ''.trt('Time_and_date_of_generation').': '.date('H:i:s m.d.Y').'
'); + fwrite($fh, ''.trt('Creator').': '.$name); + fwrite($fh, $filter); + + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '); + fwrite($fh, ''); + $nextnode=findNode($currNode,'objects-list')->firstChild; + $col=0; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { fwrite($fh, '"); + } + $nextnode = $nextnode->nextSibling; + } + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + fwrite($fh, ' '."\n"); + $pos=0; + while ($row = $res->fetch(PDO::FETCH_ASSOC)) + { + fwrite($fh, ' '); + fwrite($fh, ''); + $nextnode=findNode($currNode,'objects-list')->firstChild; + while ($nextnode) + { if ($nextnode->nodeName=='column') + { + fwrite($fh, ''); + } + $nextnode = $nextnode->nextSibling; + } + fwrite($fh, ''."\n"); + } + $res->closeCursor(); //Мож поможет избавиться от ошибки: "Cannot execute queries while other unbuffered queries are active." + + fwrite($fh, ' '."\n"); + fwrite($fh, '
'.findNode($currNode,'objects-list')->getAttribute("d").'
'.$nextnode->getAttribute("d")."
'.(++$pos).''.$row[$nextnode->getAttribute("n")].'
'."\n"); + + fwrite($fh, ' '."\n"); + fwrite($fh, ''."\n"); + + fclose($fh); + }else{ + sendError(1,trt('Failed_to_generate_report')); + } + + /*if($ext=="pdf") + { + //Если в виде PDF + $mpdf = new mPDF('utf-8', 'A4', '8', '', 10, 10, 7, 7, 10, 10); // задаем формат, отступы и.т.д. + $mpdf->list_indent_first_level = 0; + $mpdf->WriteHTML(file_get_contents($myFile)); // формируем pdf + + $dir='./temp/'; + $file='file_'.$num.'.pdf'; + $myFile = $dir.$file; + + $mpdf->Output($myFile, 'F'); + }*/ + //$myFile=getFullPath().'temp/'.$file; + + //отправляем ссылку на файл TODO переделать в JSON + header('Content-type: text/xml'); + echo ''; + + //deleteTempFiles($dir); + }else + { + sendError(1,trt('Not found the requested node:').' "'.$typename.'"!'); + } + + }else + if ($fn==9) //Сохранить файл во временную папку + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + $dir = "./temp/"; + if (!file_exists($dir)) { + mkdir($dir, 0777); + } + + //Так как у файлов могут быть одинаковые имена считаем CRC и переименовываем файл отправля пользователю новое название файла + //В базе данных название файла будет преобразовываться так: "файл.txt" -> "файл_crc32.txt" + if(isset($_FILES['file'])) + { + if(file_exists($_FILES['file']['tmp_name'])) + { + $hash = hash_file( 'crc32', $_FILES['file']['tmp_name'] ); + if(move_uploaded_file($_FILES['file']['tmp_name'],delPHPExt($dir.$hash.'.'.strtolower(getExtension($_FILES['file']['name']))))) + { + //Отправляем новое название файла клиенту + print "ok=".beforeLast($_FILES['file']['name'],'.').'_'.$hash.'.'.strtolower(getExtension($_FILES['file']['name']))."\n"; + } + }else { print "ok=\n File \"".$_FILES['file']['tmp_name']."\" not find"; } + } + + //Данный код загружается в iframe + print ''; + print ''; + print ' '; + print ' '; + print ' '; + print ' '; + print '
'; + print ' '; + print '
'; + print ' '; + print ' '; + print '
'; + print ' '; + print ''; + + //Отчищяем временные файлы которые больше суток на сервере + deleteTempFiles($dir); + + }else + if ($fn==10) //Отправить двоичные данные клиенту в виде файла (пока без докачки) + { + session_write_close(); //Разблокируем сессионный файл так как запросы могут быть достаточно долгими + //Клиент передаёт название таблицы, название поля, id поля + $typename = $_REQUEST['t']; //Тип + $field = $_REQUEST['f']; //Название поля с двоичными данными + $name = $_REQUEST['n']; //поле с названием файла + $idval = $_REQUEST['i']; //Идентификатор поля в базе + + $xmls=''; + $resX = $db->query('select xml from '.$Schema.'_metadata where del=false and name=\''.$typename.'\';'); + while ($rowX = $resX->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов + { + $xmls=''.trts($rowX['xml']).''; + } + if($xmls=='') + { + sendError(1,"Metadata node \"".$name."\" is empty!"); + } + + //Ищем поле в метаданных + $objXMLDocument = new DOMDocument(); + try + { + $objXMLDocument->loadXML($xmls); + } catch (Exception $e) + { echo $e->getMessage(); + } + + $currNode=findNodeOnAttribute($objXMLDocument->documentElement,"type","n",$typename); + if ($currNode!=null) + { + $pnode=findFirstNode($currNode,'properties'); + $fnode=findFirstNodeOnAttribute($pnode,"prop","n",$field); //Поле в metedata.xml файла + $nnode=findFirstNodeOnAttribute($pnode,"prop","n",$fnode->getAttribute("cd")); //Поле в metedata.xml с именем файла + + if($fnode->getAttribute("vt")=="blob") //Отправить файл клиенту из базы данных + { + $stmt = $db->prepare("SELECT \"$field\",length(\"$field\"),substring(\"$name\", position('_' IN \"$name\")+1) as name FROM $Schema\"$typename\" WHERE id='$idval'"); + $stmt->execute(); + $stmt->bindColumn(1, $blob, PDO::PARAM_LOB); + $stmt->bindColumn(2, $size, PDO::PARAM_INT); + $stmt->bindColumn(3, $name, PDO::PARAM_STR); + $stmt->fetch(PDO::FETCH_BOUND); + $data = stream_get_contents($blob); + + header("Content-type: application/octet-stream"); + header('Content-Disposition: attachment; filename="'.$name.'"'); + header('Content-Length: '.$size); + echo $data; + }else if($fnode->getAttribute("vt")=="file") //Отправить файл клиенту из файловой системы + { + //Тип поля с ObjectID + $nField=findFirstNodeOnAttribute(findNode($currNode, 'properties'), "prop", "n", $currNode->getAttribute('ObjectID')); + $csql=findNode(findFirstNodeOnAttribute($currNode, "sql-query", "t", "s"), "#cdata-section"); + if($csql!=NULL && $csql->nodeValue!="") //Есть ли SQL запрос + { + $sql_query=$csql->nodeValue; + $sql_query=str_replace('${'.$currNode->getAttribute("ObjectID").'}',getSQLValue($nField->getAttribute('vt'),$idval),$sql_query); + $sql_query=str_replace('${_user_id}',getSQLValue(gettype($_SESSION['USER_ID']),$_SESSION['USER_ID']),$sql_query); + } + + $res = $db->query($sql_query); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) + { + $fname = $row[$field]; + } + $dataFName = afterLast($fname,'_'); + $rezFName = beforeLast($fname,'_'); + $rezFName .= '.'.afterLast($fname,'.'); + + if(file_exists($_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName)) + { + header("Content-type: application/octet-stream"); + header('Content-Disposition: attachment; filename="'.$rezFName.'"'); + header('Content-Length: '.filesize($_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName)); + readfile($_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName); + exit(); + }else + { + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); + echo 'File "'.$_SERVER['DOCUMENT_ROOT'].'/'.$fnode->getAttribute('path').$dataFName.'" not found!'; + exit; + } + } + } + }else + { + sendError(1,"Неизвестная функция \"$fn\"!"); + } + + diff --git a/metadata/dbms/session.xyz b/metadata/dbms/session.xyz new file mode 100644 index 0000000..6863dd6 --- /dev/null +++ b/metadata/dbms/session.xyz @@ -0,0 +1,44 @@ + 43200,'cookie_secure' => true,'cookie_httponly' => true]); + echo session_id(); + exit; + }else + if($fn=='2') //Вернуть время до смерти сесии в секундах + { + if(isset($_GET[session_name()])) $id=$_GET[session_name()]; else exit; + + $sessionfile = ini_get('session.save_path') . DIRECTORY_SEPARATOR . 'sess_'.$id; + if ( file_exists($sessionfile) ) + { + //echo ini_get('session.gc_maxlifetime') - (time() - filemtime($sessionfile)); + echo '1'; //Чтоб только если файл удалился + + }else echo '-1'; + exit; + }else + { + echo 'error'; + } diff --git a/metadata/dbms/show_object.js b/metadata/dbms/show_object.js new file mode 100644 index 0000000..e69de29 diff --git a/metadata/dbms/show_object.vue b/metadata/dbms/show_object.vue new file mode 100644 index 0000000..331685b --- /dev/null +++ b/metadata/dbms/show_object.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/metadata/dbms/window.js b/metadata/dbms/window.js new file mode 100644 index 0000000..b9a6034 --- /dev/null +++ b/metadata/dbms/window.js @@ -0,0 +1,488 @@ +//Класс окна + +class TWin +{ + constructor(dialog,path) + { + this.dialog=dialog; //Показывать окно как диалог (без возможности изменения размеров) + if(typeof path !== 'undefined') + this.path=path; + else + this.path='../resources'; + + this.disableClosing=false; + + this.closed=false; //Закрыли (те. удалили из родителя и детей и из DOM) + this.onClose=null; //слушатель закрытия окна + this.childs=new Array(); //Подчинёные окна + this.parent=null; //родительское окно + this.name="TWin"; + this.tWinId=0; + this.dx=0; + this.dy=0; + this.sel=false; + this.obj=null; //user data + + this.div=document.createElement('div'); //Окно + this.divsh=document.createElement('div'); //Тень для модального окна + this.tbl=null; + this.h0=null; + this.ca=null; + this.co=null; + this.shadow = false; //Показывать ли тень вокруг окошка + this.uid=getUID(); //Уникальныйидентификатор + + this.pBarCnt=0; //Прогресс бар + this.pBarDiv=null; //Прогресс бар + + this.fnResizeListener=null; + } + + addResizeListener(func) + { + this.fnResizeListener=func; + this.fnResizeListener(); + } + + onResize(x,y) + { + let win=this; + return function(e){ + if(!e) e = window.event; + win.dx=e.pageX || e.x + win.dy=e.pageY || e.y + + document.onmousedown = function() { + + if(win.fnResizeListener!=null) win.fnResizeListener(); + + return false; + }; + document.onmousemove = function(e) { + if(!e) e = window.event; + let x2 = e.pageX || e.x; + let y2 = e.pageY || e.y; + let w=parseInt(win.div.style.width)-(win.dx-x2)*x; + let h=parseInt(win.div.style.height)-(win.dy-y2)*y; + if(w<0)w=0; + if(h<0)h=0; + win.setWidth(w+"px"); + win.setHeight(h+"px"); + if(x<0)win.div.style.left=parseInt(win.div.style.left)-(win.dx-x2)+"px"; + if(y<0)win.div.style.top=parseInt(win.div.style.top)-(win.dy-y2)+"px"; + win.dx=x2; + win.dy=y2; + + if(win.fnResizeListener!=null) win.fnResizeListener(); + + return false; + }; + document.onmouseup = function() { + document.onmousedown = null; + document.onmousemove = MMove//null; + + if(win.fnResizeListener!=null) win.fnResizeListener(); + + return false; + }; + return false; + }; + } + + Close() //Закрыть и удалить окно из родителя и менеджера + { + if(this.disableClosing) + return; + + //Переместил перед удалением компонент так как бывает нужно поработать с ними перед удалением + if(this.onClose!=null) + { + this.onClose(); + } + + this.hide(true); + this.setParent(null); + for(let i=0;i'; + hd+=' '; + hd+=' '; + //hd+='  '; + hd+=' '; + hd+=' '; + hd+=' X'; + hd+=' '; + hd+=' '; + hd+=''; + + let str=''; + str+=''; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+='
'+hd+'
 
'; +*/ +/* + let str=''; + str+=''; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+='
'; +*/ + + let str=''; + str+=''; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+=' '; + str+='
'+(this.disableClosing ? '' : '
')+'
'; + + //создаём невидемую тень + this.divsh.style.cssText="display: none; position: fixed; top:0; left:0; height: 100%; width: 100%; background: rgba(0,0,0,0.3);"; + this.divsh.onclick=function(win){return function(){ win.Close(); };}(this); + + document.body.appendChild( this.divsh ); + + //Создаём родительский элемент для окна + this.div = document.createElement('div'); + this.div.setAttribute("id","TWin_"+this.tWinId); + this.div.style.cssText="position:absolute; height:50px; width:640px;"; + this.div.innerHTML=str; + document.body.appendChild( this.div ); + this.tbl=document.getElementById('TWin_TBL_'+this.tWinId); + this.h0=document.getElementById('TWin_H0_'+this.tWinId); + this.co=document.getElementById('TWin_Co_'+this.tWinId); + this.ca=document.getElementById('TWin_Ca_'+this.tWinId); + this.setSel(); + + this.div.onmousedown=(e)=>this.setSel(); + //Кнопка закрыть окно + let obj=document.getElementById('TWin_CL_'+this.tWinId); + if(obj!=null){ + //obj.onclick=function(win){return function(){ win.Close(); };}(this); + obj.onclick=(function(){ this.Close(); }).bind(this); + } + + if(!this.dialog) + { + document.getElementById('TWin_B_'+this.tWinId).onmousedown=this.onResize(0,1); + document.getElementById('TWin_T_'+this.tWinId).onmousedown=this.onResize(0,-1); + document.getElementById('TWin_BR_'+this.tWinId).onmousedown=this.onResize(1,1); + document.getElementById('TWin_TL_'+this.tWinId).onmousedown=this.onResize(-1,-1); + document.getElementById('TWin_BL_'+this.tWinId).onmousedown=this.onResize(-1,1); + document.getElementById('TWin_R_'+this.tWinId).onmousedown=this.onResize(1,0); + document.getElementById('TWin_L_'+this.tWinId).onmousedown=this.onResize(-1,0); + document.getElementById('TWin_TR_'+this.tWinId).onmousedown=this.onResize(1,-1); + } + + this.setMove(document.getElementById('TWin_H0_'+this.tWinId)); + //this.setMove(document.getElementById('TWin_H1_'+this.tWinId)); + //this.setMove(document.getElementById('TWin_H2_'+this.tWinId)); + //this.setMove(document.getElementById('TWin_H3_'+this.tWinId)); + + this.setLeftTop(x,y); + } + + getCaption() + { + return document.getElementById('TWin_Ca_'+this.tWinId); + } + + setCaption(val) + { + if(val==null) val=''; + let obj=document.getElementById('TWin_Ca_'+this.tWinId); + if (typeof val === 'string' || val instanceof String) + obj.innerHTML=val; + else + obj.appendChild(val); + } + + //Присвоить содержимое в виде строки + setContent(html) + { + let obj=document.getElementById('TWin_Co_'+this.tWinId); + if(obj!=null) + { + obj.innerHTML=html; + if(this.tbl.offsetHeight>this.div.offsetHeight) this.div.style.height=this.tbl.offsetHeight+"px"; + if(this.tbl.offsetWidth>this.div.offsetWidth) this.div.style.width=this.tbl.offsetWidth+"px"; + } + } + //Выбрать (активизировать) окно + setSel() + { + for(let i=0;ithis.div.offsetWidth) this.div.style.width=this.tbl.offsetWidth+"px" + }; + + getWidth(){ + if(this.tbl!=null) + return parseInt(this.tbl.offsetWidth); + else + return 0; + }; + + setHeight(h) + { + if(h==null || h=='') return; + h=''+h; + if(h.indexOf('%')>-1) h=(this.div.parentNode.offsetHeight/100*parseInt(h)); + + this.co.style.height=(parseInt(h)-20-this.h0.offsetHeight)+"px"; + this.div.style.height=parseInt(h)+'px'; + + if(this.tbl.offsetHeight>this.div.offsetHeight) + this.div.style.height=this.tbl.offsetHeight+"px"; + }; + + //Подстроить размер окна по содержимому + /*adjustHeight() + { + + }*/ + + //Подгрузить содержимое окна из указаного места + //json - объект который передастца в виде JSON строки по URL + //func - функция которая выполниться после загрузки данных в форму + load(url,json,func,tr) + { + this.showProgressBar(); + var r=createRequestObject(); + r.onreadystatechange = function(r,w,thiz,func) + { + return function(){ + if(r.readyState == 4){ + if(tr) w.innerHTML=trts(r.responseText); + else w.innerHTML=r.responseText; + thiz.hideProgressBar(); + if(func !== undefined && func!=null) func(); + + //Для подстройки формы под новый размер, а то showProgressBar не по размеру было + thiz.div.style.width=thiz.tbl.offsetWidth+"px" + thiz.div.style.height=thiz.tbl.offsetHeight+"px"; + + thiz.setCenter(); + } + } + }(r,this.co,this,func,tr) + r.open( "POST", url, true ); + if(json!=null) + r.send(JSON.stringify(json)); + else + r.send(); + }; + + //Переместить окно на передний план (Обычно при щелчке на нём) + setWinZ(s) + { + let i; + this.setZ(g_wins.getMaxZ()+2); //+2 это для тени + if(s && this.parent!=null) //Переносим текущий элемент в 0й элемент массива детей родительского + { + var tmp=this.parent.childs[0]; + for(i=1;i0;i--) if(this.childs[i-1]!=null) this.childs[i-1].setWinZ(false) //Забыл зачем это делаю + } + setParent(w) + { + if(this.parent!=null) + { + for(let i=0;i'; + + //var eDiv=document.getElementById('eDiv'+this.uid); + this.div.appendChild(this.pBarDiv); + } + } + + //Спрятать прогрес бар + hideProgressBar() + { + this.pBarCnt--; + if(this.pBarCnt<=0) + { + if(this.pBarDiv!==null) deleteHTML(this.pBarDiv); + this.pBarCnt=0; + this.pBarDiv=null; + } + } + +} + +class TWins +{ + constructor() + { + this.mas = new Array(); + } + add(win) //Добавить окно в список + { + this.mas.push(win); + return this.mas.length-1; + }; + getMaxZ() //Получить максимальный Z индекс + { + var z=100; //По умолчанию + for(var i=0;iz) z=this.mas[i].getZ(); + return z; + }; + getSel() //Получить выделенное окно + { + for(var i=0;iobjects-list->filter" + setFilterColumn(xColumn, jColumn) { + + if (xColumn.hasAttribute("d")) + jColumn.d = xColumn.getAttribute("d"); + if (xColumn.hasAttribute("n")) + jColumn.n = xColumn.getAttribute("n"); + if (xColumn.hasAttribute("vt")) + jColumn.vt = xColumn.getAttribute("vt"); + if (xColumn.hasAttribute("object")) + jColumn.object = xColumn.getAttribute("object"); + if (xColumn.hasAttribute("FieldCaption")) + jColumn.FieldCaption = xColumn.getAttribute("FieldCaption"); + if (xColumn.hasAttribute("selector")) + jColumn.selector = xColumn.getAttribute("selector"); + if (xColumn.hasAttribute("visible")) + jColumn.visible = xColumn.getAttribute("visible"); + + jColumn.value = getCdataValue(xColumn); + + return jColumn; + } +} diff --git a/metadata/include/captcha.xyz b/metadata/include/captcha.xyz new file mode 100644 index 0000000..322fbee --- /dev/null +++ b/metadata/include/captcha.xyz @@ -0,0 +1,68 @@ + 43200,'cookie_secure' => true,'cookie_httponly' => true]); +//if(isset($_SESSION['REMOTE_ADDR']) && $_SESSION['REMOTE_ADDR'] != $_SERVER['REMOTE_ADDR']) unset($_SESSION["USER_ID"]); //Делаемся не авторизованным если зашли с другого ip адреса +if (isset($_REQUEST['id'])) $id = $_REQUEST['id']; else $id = ''; + + $width = 115; //Ширина изображения + $height = 40; //Высота изображения + $font_size = 14; //Размер шрифта + $let_amount = 5; //Количество символов, которые нужно набрать + $fon_let_amount = 40; //Количество символов, которые находятся на фоне + $path_fonts = getcwd().'/fonts/'; //Путь к шрифтам + + //$letters = array('a','b','c','d','e','f','g','h','j','k','m','n','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7','9'); + $letters = array('0','1','2','3','4','5','6','7','8','9'); + //$colors = array('100','200','150','170','190','210','190','160','170','190','210'); //для тёмного стиля + $colors = array('50','100','75','85','95','105','90','80','85','95','105'); //Для светлого стиля + + $src = imagecreatetruecolor($width,$height); + //$fon = imagecolorallocate($src,58,58,58); //Для тёмного стиля + $fon = imagecolorallocate($src,241,241,241); //Для светлого стиля + imagefill($src,0,0,$fon); + + $fonts = array(); + $dir=opendir($path_fonts); + while($fontName = readdir($dir)) + { + if($fontName != "." && $fontName != ".." && pathinfo($fontName, PATHINFO_EXTENSION)=='ttf') + { + $fonts[] = $fontName; + } + } + closedir($dir); + + for($i=0;$i<$fon_let_amount;$i++) + { + $color = imagecolorallocatealpha($src,rand(0,255),rand(0,255),rand(0,255),100); + $font = $path_fonts.$fonts[rand(0,sizeof($fonts)-1)]; + $letter = $letters[rand(0,sizeof($letters)-1)]; + $size = rand($font_size-2,$font_size+2); + imagettftext( + $src, + $size, + rand(0,45), + rand((int)($width*0.1),(int)($width-$width*0.1)), + rand((int)($height*0.2),$height), + $color, + $font, + $letter + ); + } + + for($i=0;$i<$let_amount;$i++) + { + $color = imagecolorallocatealpha($src,$colors[rand(0,sizeof($colors)-1)],$colors[rand(0,sizeof($colors)-1)],$colors[rand(0,sizeof($colors)-1)],rand(20,40)); + $font = $path_fonts.$fonts[rand(0,sizeof($fonts)-1)]; + $letter = $letters[rand(0,sizeof($letters)-1)]; + $size = rand((int)($font_size*2.1-2),(int)($font_size*2.1+2)); + $x = (int)(($i+0.9)*$font_size + rand(4,7)); + $y = (int)((($height*2.3)/3) + rand(0,5)); + $cod[] = $letter; + imagettftext($src,$size,rand(0,15),$x,$y,$color,$font,$letter); + } + + $_SESSION['secpic'.$id] = implode('',$cod); + + header ("Content-type: image/gif"); + imagegif($src); + diff --git a/metadata/include/session.xyz b/metadata/include/session.xyz new file mode 100644 index 0000000..be43caf --- /dev/null +++ b/metadata/include/session.xyz @@ -0,0 +1,25 @@ += $sessionLifetime ) + { + $t=$_SESSION['lastactivity']; + //session_unset(); Удалить все переменные сессии (устарела) + //$_SESSION = array(); + session_reset(); // Удалить все переменные сессии + $_SESSION['lastactivity']=$t; + return false; + } + return true; +} \ No newline at end of file diff --git a/metadata/include/tools.xyz b/metadata/include/tools.xyz new file mode 100644 index 0000000..878b4ae --- /dev/null +++ b/metadata/include/tools.xyz @@ -0,0 +1,514 @@ +'."\n"; + } + return ''; +} + +//Функция для перевода текста без применения GetText "trt(" +function trt($text) +{ + global $db,$Schema,$language_id; + + $result=''; + $sql='select translation from '.$Schema.'_translations where del=false and language_id='.$language_id.' and identifier=\''.$text.'\';'; + //$sql='select translation from main._translations where del=false and language_id=(select id from main._languages where short_name=\''.$language_id.'\') and identifier=\''.$text.'\';'; + $res = NULL; + try + { + $res = $db->query($sql); + }catch (Exception $e) + { + echo $e->getMessage(); + } + if($res!=NULL && $res->rowCount()>0) + { + while ($row = $res->fetch(PDO::FETCH_NUM)) + { + $result=$row[0]; + } + }else + { + $result=str_replace("_", " ", $text); + } + return $result; +} + +//Перевод для строки в которой встречаются подстроки вида: trt('') +function trts($text) +{ + $result=''; + $pLen=4; //Длина преамбулы trt( + $cut=0; + $from = 0; // Позиция поиска для итерации + while (true) + { + $pos1 = strpos($text, 'trt(', $from); //') + if($pos1 !== false) + { + $from = $pos1+$pLen+1; + $pos2 = false; + if($text[$pos1+$pLen] == '"') $pos2 = strpos($text, '")', $from); + if($text[$pos1+$pLen] == '\'') $pos2 = strpos($text, '\')', $from); + if($pos2 !== false) + { + $result.=substr($text, $cut, $pos1 - $cut ); + $toTranslate=substr($text, $pos1+$pLen+1, $pos2 - $pos1 - $pLen-1 ); + $result.=trt($toTranslate); + $cut=$pos2+2; + $from = $pos2; + } + }else break; + } + $result.=substr($text, $cut); //Копируем остатки + return $result; +} + +//Выбираю из текста ${конкретные} слова для перевода +function trs($text) +{ + if(!$text) return ''; + $pos1=0; + while(true) + { + $pos1 = strpos($text, '${',$pos1); + if($pos1 !== false) + { + $pos2 = strpos($text, '}', $pos1); + if($pos1 !== false) + { + $sub=substr($text,$pos1+2,$pos2-$pos1-2); + $text=substr($text,0, $pos1).trt($sub).substr($text,$pos2+1); + }else + { + break; + } + }else + { + break; + } + } + return $text; +} + +//Получить разрешения для текущего пользователя +function getAccess($key) +{ + global $db; + + $result=false; + $sql="select main.p_getaccess(:user_id,:key) as acc;"; + $stmt = $db->prepare($sql); + if(isset($_SESSION['USER_ID'])) + $stmt->bindValue(':user_id', $_SESSION['USER_ID'], PDO::PARAM_INT); + else + $stmt->bindValue(':user_id', 0, PDO::PARAM_INT); + $stmt->bindValue(':key', $key, PDO::PARAM_STR); + $res=null; + try + { + $res=$stmt->execute(); + }catch (Exception $e) + { + echo $e->getMessage(); + } + if($res && $stmt->rowCount()>0) + { + while ($row = $stmt->fetch(PDO::FETCH_NUM)) + { + $result=$row[0]; + } + } + return $result; +} + +function delPHPExt($fName) +{ + $pos = strrpos($fName, '.')+1; + if(strtolower(substr($fName,$pos))=='php') + { + return substr($fName,0,$pos).'VIRUS'; + }else { + return $fName; + } +} + +function getURLText($url,$data) +{ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, trim($url)); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); + curl_setopt($ch, CURLOPT_HEADER,0); //Change this to a 1 to return headers + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.12) Gecko/20050919 Firefox/1.0.7'); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + $data = trim(curl_exec($ch)); + curl_close($ch); + return $data; +} + +// array imageResize (string $src, string $dest, integer $width, integer $height); +// $src - имя исходного файла +// $dest - имя генерируемого файла +// $width, $height - максимальные ширина и высота генерируемого изображения +// возвращает массив (0=>$width, 1=>$height) с шириной и высотой получившегося изображения +function imageResize ($src, $dest, $width, $height) +{ + if (!file_exists($src)) return false; + if (($size=getimagesize($src))===false) return false; + $format=strtolower(substr($size['mime'],strpos($size['mime'],'/')+1)); + $icfunc='imagecreatefrom'.$format; + if (!function_exists($icfunc)) return false; + $x_ratio=$width/$size[0]; + $y_ratio=$height/$size[1]; + $ratio=min($x_ratio, $y_ratio); + $use_x_ratio=($x_ratio==$ratio); + $new_width=$use_x_ratio?$width:floor($size[0]*$ratio); + $new_height=!$use_x_ratio?$height:floor($size[1]*$ratio); + $new_left=$use_x_ratio?0:floor(($width-$new_width)/2); + $new_top=!$use_x_ratio?0:floor(($height-$new_height)/2); + $isrc=$icfunc($src); + $idest=imagecreatetruecolor($new_width, $new_height); + imagecopyresampled($idest, $isrc, 0, 0, 0, 0, $new_width, $new_height, $size[0], $size[1]); + + //Пишем в файл + if ($format=='jpeg') imagejpeg($idest, $dest, 70); + else if ($format=='gif') imagegif($idest, $dest); + else imagepng($idest, $dest, 7); + + imagedestroy($isrc); + imagedestroy($idest); + return array($new_width, $new_height); +} +//Залить недостающие края заданным цветом (использую для фото без прозрачности для удобства в HTML верстке) +function imageFillBorder($src, $dest, $width, $height){ + if (!file_exists($src)) return false; + if (($size=getimagesize($src))===false) return false; + $format=strtolower(substr($size['mime'],strpos($size['mime'],'/')+1)); + + // создание jpg изображения + if ($format=='jpeg') + { + if(!$oldImg = imagecreatefromjpeg($src)) + { + error_log('Error imagecreatefromjpeg '.$_SERVER['REQUEST_URI']); + } + }else if ($format=='gif') $oldImg = imagecreatefromgif($src); + else $oldImg = imagecreatefrompng($src); + + //Создаю новое изображение + $newImg=imagecreatetruecolor($width, $height); + $background_color = imagecolorallocate($newImg, 255, 255, 255); + imagefill($newImg, 0, 0, $background_color); + + //Ищем центр + $x = ($width - imagesx($oldImg)) / 2; + $y = ($height - imagesy($oldImg)) / 2; + + imagecopy($newImg, $oldImg, $x, $y, 0, 0, imagesx($oldImg), imagesy($oldImg)); + + //Пишем в файл + if ($format=='jpeg') imagejpeg($newImg,$dest); + else if ($format=='gif') imagegif($newImg,$dest); + else imagepng($newImg,$dest); + + // освобождаем память + imagedestroy($oldImg); + imagedestroy($newImg); +} + +//Водяной знак (размножит по поверхности одного изображения другое) +function watermark($src,$stm) +{ + if (!file_exists($src) || !file_exists($stm)) return false; + if (($size=getimagesize($src))===false) return false; + $format=strtolower(substr($size['mime'],strpos($size['mime'],'/')+1)); + + // создание водяного знака в формате png + $watermark = imagecreatefrompng($stm); + // получаем ширину и высоту + $watermark_width = imagesx($watermark); + $watermark_height = imagesy($watermark); + + // создание jpg изображения + if ($format=='jpeg') + { + if(!$image = imagecreatefromjpeg($src)) + { + error_log('Error imagecreatefromjpeg '.$_SERVER['REQUEST_URI']); + } + }else if ($format=='gif') $image = imagecreatefromgif($src); + else $image = imagecreatefrompng($src); + + + //Выясняем количество повторов по оси X и по Y + $dx=ceil($size[0] / $watermark_width); + $dy=ceil($size[1] / $watermark_height); + + imagealphablending($image, true); + imagealphablending($watermark, true); + + // создаём новое изображение + for($y=0;$y<$dy;$y++) + for($x=0;$x<$dx;$x++) + imagecopy($image, $watermark, $x * $watermark_width, $y * $watermark_height, 0, 0, $watermark_width, $watermark_height); + + //Пишем в файл + if ($format=='jpeg') imagejpeg($image,$src); + else if ($format=='gif') imagegif($image,$src); + else imagepng($image,$src); + + // освобождаем память + imagedestroy($image); + imagedestroy($watermark); +} + + + +//вернёт только цифры +function getInt($str) +{ + $res=''; + for($i=0;$i24*60*60) unlink($dir.$file); + } + closedir($dh); + } + } +} + +function getFilesTree($dir,$cut="",$result = null){ + if($result==null) + $result = new stdClass(); + + if (is_dir($dir)) + { + $result->list = array(); + + $dh = opendir($dir); + if ($dh) + { + while (($file = readdir($dh)) !== false) + { + if($file == '..' || $file == '.') continue; + + if(is_dir($dir.DIRECTORY_SEPARATOR.$file)){ + $sub = new stdClass(); + $sub->name=$file; + $sub->path=$dir.DIRECTORY_SEPARATOR.$file; + if($cut) $sub->path = str_replace($cut, "",$sub->path); + array_push($result->list, $sub); + getFilesTree($dir.DIRECTORY_SEPARATOR.$file, $cut, $sub); + }else{ + $sub = new stdClass(); + $sub->name=$file; + $sub->path=$dir.DIRECTORY_SEPARATOR.$file; + if($cut) $sub->path = str_replace($cut, "",$sub->path); + array_push($result->list, $sub); + } + + } + closedir($dh); + } + } + return $result; +} + +//Генерация пароля +function getPassword($max) +{ + $chars="qazxswedcvfrtgbnhyujmkiolp1234567890"; + $size=StrLen($chars)-1; + $password=''; + while($max--) + $password.=$chars[rand(0,$size)]; + return $password; +} + +//Полный путь к текущему URL включая http и название скрипта +function selfURL() +{ + if(!isset($_SERVER['REQUEST_URI'])){ $suri = $_SERVER['PHP_SELF']; } + else { $suri = $_SERVER['REQUEST_URI']; } + $s = empty($_SERVER["HTTPS"]) ? '' : (($_SERVER["HTTPS"] == "on") ? "s" : ""); + $sp=strtolower($_SERVER["SERVER_PROTOCOL"]); + $pr = substr($sp,0,strpos($sp,"/")).$s; + $pt = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]); + return $pr."://".$_SERVER['SERVER_NAME'].$pt.$suri; +} + +//Путь без файла пример: http://truemisha.ru +function selfDomain() +{ + //if(!isset($_SERVER['REQUEST_URI'])) $suri = $_SERVER['PHP_SELF']; + //else $suri = $_SERVER['REQUEST_URI']; + $s = empty($_SERVER["HTTPS"]) ? '' : (($_SERVER["HTTPS"] == "on") ? "s" : ""); + $sp=strtolower($_SERVER["SERVER_PROTOCOL"]); + $pr = substr($sp,0,strpos($sp,"/")).$s; + $pt = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]); + return $pr."://".$_SERVER['SERVER_NAME'].$pt;//.$suri; +} + +//Строка до последнего найденого символа если символа нет то всю строку +function beforeLast(&$str,$ch) +{ + return substr($str, 0, strrpos($str, $ch)); +} +//Строка после последнего найденого символа если символа нет то всю строку +function afterLast(&$str,$ch) +{ + return substr($str, strrpos($str, $ch)+strlen($ch)); +} +//Строка до первого попавшегося символа +function beforeFirst(&$str,$ch) +{ + return substr($str, 0, strpos($str, $ch)); +} +//Строка после первого попавшегося символа +function afterFirst(&$str,$ch) +{ + return substr($str, strpos($str, $ch)+strlen($ch)); +} +/** + * Вернёт подстроку если символа нет то всю строку + * @param string $str + * @param string $chr + * @return string Подстрока + */ +function cutStr(&$str,$chr) +{ + $pos = strpos($str, $chr); + if($pos===false) + { + return $str; + }else + { + $buf = substr($str, 0, $pos); + $str = substr($str, $pos + strlen($chr)); + return $buf; + } +} + +//Вырезаеи всё после заданого разделителя удаляя разделитель если разделителя нет возвращает всю строку +//$fstr - Разделитель +//$num - На каком разделителе остановиться +function cutAfterLast(&$sstr,$fstr,$num = 1) +{ + $sub=''; + $pos=strlen($sstr); + for($i=0;$i<$num;$i++) + { + $pos = strripos($sstr, $fstr, $pos-strlen($sstr)-1); + if($pos === false) { break; } + } + if($pos === false) + { + $sub=$sstr; + $sstr=''; + return $sub; + }else + { + $sub = substr( $sstr , $pos + strlen($fstr)); + $sstr = substr( $sstr , 0, $pos); + return $sub; + } +} + +//Зачем коментил? +//Отрезаем от строки всё до заданой подстроки если подстроки нет отрезается вся строка +function cutBeforeFirst(&$sstr,$fstr) +{ + $sub=''; + $pos = strpos($sstr, $fstr); + if($pos === false) + { + $sub=$sstr; + $sstr=''; + return $sub; + }else + { + $sub = substr( $sstr , 0, $pos); + $sstr = substr( $sstr , $pos + strlen($fstr)); + return $sub; + } +} diff --git a/metadata/include/xmltools.xyz b/metadata/include/xmltools.xyz new file mode 100644 index 0000000..99822c2 --- /dev/null +++ b/metadata/include/xmltools.xyz @@ -0,0 +1,172 @@ +ownerDocument->saveXML($node); + } + /** + * Найти первый попавшийся узел с заданным именем nodeName. + * @param DOMNode $node Узел. + * @param string $nodename Название узла. + * @return DOMNode Найденный узел либо null. + */ + function findNode($node, $nodename) + { + if($node==null) return null; + $nextNode = $node->firstChild; + while ($nextNode != null) + { + if($nextNode->nodeName==$nodename) + { + return $nextNode; + } + $nextNode=$nextNode->nextSibling; + } + return null; + } + /** + * Найти первый попавшийся узел с заданным именем nodeName и атрибутом $attribute со значением $val. + * @param $node + * @param $nodename + * @param $attribute + * @param $val + * @return + */ + function findNodeOnAttribute($node, $nodename,$attribute,$val) + { + if($node==null) return null; + $nextNode = $node->firstChild; + while ($nextNode != null) + { + if(($nextNode->nodeName==$nodename)&&($nextNode->getAttribute($attribute)==$val)) + { + return $nextNode; + } + $nextNode=$nextNode->nextSibling; + } + return null; + } + /** + * Вернуть первый попавшийся узел среди всех дочерних (без рекурсии). + * @param XMLNode $node Родительский узел. + * @param String $nodename Название узла. + * @return XMLNode Найденный узел + */ + function findFirstNode($node, $nodename) + { + $mas=array(); + $pos=0; + $mas[$pos] = $node->firstChild; + while ($mas[$pos]) + { + if($mas[$pos]->nodeName==$nodename) + { + return $mas[$pos]; + } + if($mas[$pos]->firstChild) + { + $pos++; + $mas[$pos]=$mas[$pos-1]->firstChild; + }else + { + //если не идёт дальше пытаемся подняться в верх по дереву + while (true) + { + $mas[$pos] = $mas[$pos]->nextSibling; + if (!$mas[$pos]) + { + if($pos>0){ $pos--; }else{ break; } + }else + { + break; + } + } + } + } + return ''; + } + + //рекурсию не буду использовать, обойдусь массивом вложенности + function findFirstNodeOnAttribute($node, $nodename,$attribute,$val) + { + $mas=array(); + $pos=0; + $mas[$pos] = $node->firstChild; + while ($mas[$pos]) + { + if(($mas[$pos]->nodeName==$nodename)&&($mas[$pos]->getAttribute($attribute)==$val)) + { + return $mas[$pos]; + } + if($mas[$pos]->firstChild) + { + $pos++; + $mas[$pos]=$mas[$pos-1]->firstChild; + }else + { + //если не идёт дальше пытаемся подняться в верх по дереву + while (true) + { + $mas[$pos] = $mas[$pos]->nextSibling; + if (!$mas[$pos]) + { + if($pos>0){ $pos--; }else{ break; } + }else + { + break; + } + } + } + } + return ''; + } + //найти узелы по пути "node1->node2" + function findNodeOnPath($node, $path) + { + if($node==null) return null; + $params=explode("/",$path); + for($i=0;$iownerDocument->createCDATASection(''); + $node->appendChild($result); + } + return $result; + } + + /** + * Получить строку данных из первой попавшейся CDATA. + * @param DOMNode $node Узел XML. + * @return String Строка результата + */ + function getCdataValue($node) + { + $n=findNode($node,'#cdata-section'); + if($n!=null) + { return $n->nodeValue; + } + return ''; + } + diff --git a/metadata/test.xyz b/metadata/test.xyz new file mode 100644 index 0000000..ee0bcc7 --- /dev/null +++ b/metadata/test.xyz @@ -0,0 +1,220 @@ + + + + + + Пример POST-запроса + + + + + + + + + + + + + + + + + + + + +
trt('Name')trt('Value')
trt('Name')trt('Value')
+ + +
+

{{ type.d }}

+
+
+
{{column.d}}
+ + + +
+
+
{{column.d}}
+ +
+
+
{{column.d}}
+ +
+
+
+
+ +
+
+
+ + +
+
+
+
+ +if (rpos%2==0) bgColor='var(--row-color-1)'; else bgColor='var(--row-color-2)'; + + + + + +