Первая копия
This commit is contained in:
381
metadata/include/class_table.php
Normal file
381
metadata/include/class_table.php
Normal file
@ -0,0 +1,381 @@
|
||||
<?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 Строка $name Название таблицы
|
||||
* @param Целое $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];
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user