Files
Metadata_PHP/metadata/include/class_table.php
2020-02-27 09:40:17 +06:00

381 lines
13 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

<?php
/*
* Класс таблицы для обмена данными в двоичном виде (по HTTP в zip)
*/
//Альтернатива unpack
function getBin($t,$v)
{
$v=unpack($t, $v);
return $v[1];
}
class TCField //Класс описания типа и названия столбцов
{ //Идентификаторы типов данных
static $BD_UINT1 = 0; //1 байт без знаковый
static $BD_UINT2 = 1; //2 байта без знаковый
static $BD_UINT4 = 3; //4 байта без знаковый
static $BD_INT1 = 10; //1 байт со знаковый
static $BD_INT2 = 11; //2 байта со знаковый
static $BD_INT4 = 13; //4 байта со знаковый
static $BD_INT8 = 17; //8 байт со знаковый
static $BD_FLOAT4 = 20; //4 байта
static $BD_FLOAT8 = 22; //8 байт double
static $BD_UTF8_1 = 100; //100 - utf8_1 string 1й байт размер строки в байтах
static $BD_UTF8_2 = 101; //101 - utf8_2 string 1х 2 байта размер строки в байтах
static $BD_UTF8_4 = 102; //101 - utf8_4 string 1х 4 байта размер строки в байтах
static $BD_BLOB_2 = 141;
static $BD_BLOB_4 = 143; //Двоичные данные uint4 количество байт
public $name=''; //Название столбца
public $type=-1; //Тип данных
public $value=''; //Запакованые данные
function TCField($name, $type)
{
//Преобразования для типов из PostgreSQL и MySQL
if($type=='bool' || $type=='tinyint') { $type=TCField::$BD_UINT1; } else
if($type=='int4' || $type=='int' || $type=='bigint') { $type=TCField::$BD_INT4; } else //bigint немного неправильно потому что это 64 бита но для андрод приложения не сделал
if($type=='int8') { $type=TCField::$BD_INT8; } else
if($type=='float4' || $type=='float') { $type=TCField::$BD_FLOAT4; } else
if($type=='float8' || $type=='NUMBER') { $type=TCField::$BD_FLOAT8; } else
if($type=='varchar' || $type=='VARCHAR2') { $type=TCField::$BD_UTF8_2; } else
if($type=='text') { $type=TCField::$BD_UTF8_4; } else
if($type=='bytea' || $type=='longblob') { $type=TCField::$BD_BLOB_4; } else
if($type=='timestamptz') { $type=TCField::$BD_UTF8_1; } else
if($type=='timestamp') { $type=TCField::$BD_UTF8_1; } else
if($type=='date') { $type=TCField::$BD_UTF8_1; }
$this->name=$name;
$this->type=$type;
}
//Получить PDO тип
function getPDOType()
{
if($this->type==TCField::$BD_UINT1) return PDO::PARAM_BOOL;
if($this->type==TCField::$BD_INT4) return PDO::PARAM_INT;
if($this->type==TCField::$BD_INT8) return PDO::PARAM_INT;
if($this->type==TCField::$BD_FLOAT4) return PDO::PARAM_STR;
if($this->type==TCField::$BD_FLOAT8) return PDO::PARAM_STR;
if($this->type==TCField::$BD_UTF8_1) return PDO::PARAM_STR;
if($this->type==TCField::$BD_UTF8_2) return PDO::PARAM_STR;
if($this->type==TCField::$BD_UTF8_4) return PDO::PARAM_STR;
if($this->type==TCField::$BD_BLOB_4) return PDO::PARAM_LOB;
return PDO::PARAM_STR;
}
//Прочитать значение из файла в соответствии с типом
function ReadValue($fileHandle)
{
if($this->type==TCField::$BD_UINT1)
{ $this->value=fread($fileHandle, 1);
}else
if($this->type==TCField::$BD_UINT2)
{ $this->value=fread($fileHandle, 2);
}else
if($this->type==TCField::$BD_UINT4)
{ $this->value=fread($fileHandle, 4);
}else
if($this->type==TCField::$BD_INT1)
{ $this->value=fread($fileHandle, 1);
}else
if($this->type==TCField::$BD_INT2)
{ $this->value=fread($fileHandle, 2);
}else
if($this->type==TCField::$BD_INT4)
{ $this->value=fread($fileHandle, 4);
}else
if($this->type==TCField::$BD_INT8)
{ $this->value=fread($fileHandle, 8);
}else
if($this->type==TCField::$BD_FLOAT4)
{ $this->value=fread($fileHandle, 4);
}else
if($this->type==TCField::$BD_FLOAT8)
{ $this->value=fread($fileHandle, 8);
}else
if($this->type==TCField::$BD_UTF8_1)
{ $s=getBin('C',fread($fileHandle, 1));
if($s==0) $this->value='';
else $this->value=fread($fileHandle, $s);
}else
if($this->type==TCField::$BD_UTF8_2)
{ $s=getBin('S',fread($fileHandle, 2));
if($s==0) $this->value='';
else
{ //В цикле так как из зип потока читало порциями
$this->value='';
while($s>strlen($this->value))
$this->value.=fread($fileHandle, $s-strlen($this->value));
}
}else
if($this->type==TCField::$BD_UTF8_4)
{ $s=getBin('I',fread($fileHandle, 4));
if($s==0) $this->value='';
else
{ //В цикле так как из зип потока читало порциями
$this->value='';
while($s>strlen($this->value))
$this->value.=fread($fileHandle, $s-strlen($this->value));
}
}else
if($this->type==TCField::$BD_BLOB_4)
{ $s=getBin('I',fread($fileHandle, 4));
if($s==0) $this->value='';
else
{ //В цикле так как из зип потока читало порциями
$this->value='';
while($s>strlen($this->value))
$this->value.=fread($fileHandle, $s-strlen($this->value));
}
}
}
function pack($value)
{
if($value===NULL){ return NULL; }
if($this->type==TCField::$BD_UINT1)
{ return pack("C",$value);
}else
if($this->type==TCField::$BD_UINT2)
{ return pack("S",$value);
}else
if($this->type==TCField::$BD_UINT4)
{ return pack("I",$value);
}else
if($this->type==TCField::$BD_INT1)
{ return pack("c",$value);
}else
if($this->type==TCField::$BD_INT2)
{ return pack("s",$value);
}else
if($this->type==TCField::$BD_INT4)
{ return pack("i",$value);
}else
if($this->type==TCField::$BD_INT8)
{
/*$str='0000000000000000000000000000000000000000000000000000000000000000'.decbin($value); //TODO decbin c 64 битами не работает на 32 битном php только 32 unpack('H*', '01010101');
$str=substr($str,-64,64);
for($ii=0;$ii<8;$ii++)//побайтно записываем все 8 байт
{ $szRez=$szRez.pack("C",bindec(substr($str,-8,8)));
$str=substr($str,0,-8);
}*/
}else
if($this->type==TCField::$BD_FLOAT4)
{
$value=str_replace(',','.',$value); //Чтоб не зависело от настроек оракла
return pack("f",$value);
}else
if($this->type==TCField::$BD_FLOAT8)
{
$value=str_replace(',','.',$value); //Чтоб не зависело от настроек оракла
return pack("d",$value);
}else
if($this->type==TCField::$BD_UTF8_1)
{ //$str=iconv('WINDOWS-1251', 'UTF-8', $value);
return pack("C",strlen($value)).$value;
}else
if($this->type==TCField::$BD_UTF8_2)
{ //$str=iconv('WINDOWS-1251', 'UTF-8', $value);
return pack("S",strlen($value)).$value;
}else
if($this->type==TCField::$BD_UTF8_4)
{ //$str=iconv('WINDOWS-1251', 'UTF-8', $value);
return pack("I",strlen($value)).$value;
}else
if($this->type==TCField::$BD_BLOB_4)
{ return pack("I",strlen($value)).$value;
}
}
function setValue($value) //пакуем данные в соответствии с типом
{
$this->value=$this->pack($value);
}
//Распаковываем данные в соответствии с типом
function getValue()
{
if($this->value===NULL) return NULL;
if($this->type==TCField::$BD_UINT1)
{ return getBin ("C", $this->value);
}else
if($this->type==TCField::$BD_UINT2)
{ return getBin ("S", $this->value);
}else
if($this->type==TCField::$BD_UINT4)
{ return getBin ("I", $this->value);
}else
if($this->type==TCField::$BD_INT1)
{ return getBin ("c", $this->value);
}else
if($this->type==TCField::$BD_INT2)
{ return getBin ("s", $this->value);
}else
if($this->type==TCField::$BD_INT4)
{ return getBin ("i", $this->value);
}else
if($this->type==TCField::$BD_INT8)
{ //return getBin ("S", $this->value);
}else
if($this->type==TCField::$BD_FLOAT4)
{ return getBin ("f", $this->value);
}else
if($this->type==TCField::$BD_FLOAT8)
{ return getBin ("d", $this->value);
}else
if($this->type==TCField::$BD_UTF8_1 || $this->type==TCField::$BD_UTF8_2 || $this->type==TCField::$BD_UTF8_4)
{ return $this->value;
}else
if($this->type==TCField::$BD_BLOB_2 || $this->type==TCField::$BD_BLOB_4)
{ return $this->value;
}
return '';
}
}
class TCTable
{
public $id=0; //Идентификатор таблицы
public $name=''; //Название таблицы
public $fields = array(); //Массив полей
private $nc=0; //Байтов под NULL значения
private $m_NULL; //NULL значения
private $m_file;
/**
* Конструктор
* @param string $name Название таблицы
* @param integer $id Идентификатор таблицы
*/
function TCTable($name,$id)
{ $this->name=$name;
$this->id=$id;
}
//Открыть таблицу по названию файла
function OpenTableF($file)
{
if(file_exists($file))
{
$this->OpenTableH(fopen($file,'r'));
}
}
//Открыть таблицу из HANDLE (файла)
function OpenTableH($handle)
{
$this->m_file=$handle;
if(getBin('S',fread($this->m_file, 2))!=65500) return false; //id файла
if(getBin('S',fread($this->m_file, 2))!=1) return false; //Версия файла
$this->id=getBin('I',fread($this->m_file, 4)); //ID таблицы или запроса (4 байта можно сделать 2)
if(getBin('C',fread($this->m_file, 1))!=0) return false; //Только плотные таблицы
$this->name=fread($this->m_file, getBin('C',fread($this->m_file, 1))); //Название таблицы
//Считываем столбцы
$count=getBin('C',fread($this->m_file, 1)); //Количество столбцов
for($i=0;$i<$count;$i++)
{
$field=new TCField (fread($this->m_file, getBin('C',fread($this->m_file, 1))),getBin('C',fread($this->m_file, 1)));
$this->addField($field);
//echo $field->name.'<br/>';
}
return true;
}
//Открыть таблицу из потока
//OpenTable
//Прочитать следующую запись из таблицы
function ReadNextRecord()
{
if(feof($this->m_file)) return; //Неработает
$this->m_NULL='';
for($j=0;$j<$this->nc;$j++) //Побайтно
{
$v=fread($this->m_file, 1);
if(strlen($v)==0) return; //Проверка конца файла
$v=getBin('C',$v);
$v=decbin($v);
for($i=strlen($v);$i<8;$i++) $v='0'.$v;
$this->m_NULL.=$v;
}
$this->clearRows();
for($i=0;$i<count($this->fields);$i++)
{
if($this->m_NULL[$i]=="1")
{
$this->fields[$i]->ReadValue($this->m_file);
}
}
return true;
}
//Добавить поле к таблице
function addField($field)
{ if($field!=NULL)
{ $this->fields[]=$field;
$this->nc=ceil(count($this->fields)/8.0); //Байтов под NULL
}
}
//Получить заголовок плотной таблицы в виде двоичной строки
function getHeader()
{
$szRez=''; //Данные из таблицы в двоичном формате
$szRez=$szRez.pack("S",65500); //id файла (2 байта)
$szRez=$szRez.pack("S",1); //Версия файла (2 байта)
$szRez=$szRez.pack("I",$this->id); //ID таблицы или запроса (4 байта)
$szRez=$szRez.pack("C",0); //Тип таблицы 0-"Плотная" 1-"Мягкая" (1 байт)
$szRez=$szRez.pack("C",strlen($this->name)).$this->name; //UTF8_1 строка
$szRez=$szRez.pack("C",count($this->fields)); //Колво столбцов (1 байт)
//Записываем id типов столбцов
for($i=0;$i<count($this->fields);$i++)
{
$szRez.=pack("C",strlen($this->fields[$i]->name)).$this->fields[$i]->name;
$szRez.=pack("C",$this->fields[$i]->type);
}
return $szRez;
}
//Получить данные 1 записи в виде строки
function getCol()
{ $szRez='';
//Запишем NULL значения побайтно (1-есть данные 0-нету данных)
$str='';
for($i=0;$i<$this->nc*8;$i++)
{
if($i>=count($this->fields)) $str.='0'; else
if($this->fields[$i]->value===NULL) $str.='0'; else $str.='1';
if(strlen($str)==8)
{ $szRez=$szRez.pack("C",bindec($str));
$str='';
}
}
//Запишем сами данные в строку
for($i=0;$i<count($this->fields);$i++)
{
$szRez.=$this->fields[$i]->value;
}
return $szRez;
}
//Row очистить запись
function clearRows()
{ for($i=0;$i<count($this->fields);$i++)
{ $this->fields[$i]->value=null;
}
}
//Получить обьект столбца по имени
function getRowByName($name)
{ for($i=0;$i<count($this->fields);$i++)
{ if($this->fields[$i]->name==$name) return $this->fields[$i];
}
}
//Получить объект столбца по номеру
function getRowByNum($num)
{ return $this->fields[$num];
}
}
?>