<?php
/*
* TxtXtrator é uma classe PHP que oferece ferramentas para extração, tratamento
* e conversão de arquivos texto com dados no formato de colunas com largura fixa,
* CSV (texto separados por vÃrgula ou ponto-e-vÃrgula) ou relatórios em modo texto.
*
* @author Everton da Rosa
* @e-mail hide@address.com
* @version 1.0
*/
class TxtXtrator {
//config properties
protected $outputType;//Tipo da saÃda de dados: array|json|csv|sql|html
protected $firstRow;//Número da primeira linha a ser processada por xtract()
protected $countRow;//Número de linhas a serem processadas por xtract()
protected $rowLen;//Tamanho exigido da linha para que ela seja processada por xtract()
protected $fileType;//Tipo do arquivo a ser processado: fixed|csv
protected $csvSeparator;//Caractere que separa os campos em cada linha da saÃda CSV
protected $lineBreak;//Caractere de quebra de linha
protected $lineBreakType;//Tipo do caractere de quebra de linha: linux|windows|html
protected $sqlTable;//Nome da tabela SQL para o método outputToSql()
//staff properties
protected $result;//Resultado de xtract()
protected $output;//SaÃda de dados resultante de output()
protected $error;//Erros relatados
protected $source;//Conteúdo do arquivo texto recebido de loadFile()
protected $cm;//Modelo de colunas do template, definido por loadTpl()
protected $export;//Dados para serem exportados para arquivo via download() ou file(), export()
//constructor
public function __construct($config = false) {
if($config){
if($config['outputType']){
$this->setOutputType($config['outputType']);
}
if($config['fistRow']){
$this->setFirstRow($config['firstRow']);
}
if($config['countRow']){
$this->setCountRow($config['countRow']);
}
if($config['rowLen']){
$this->setRowLen($config['rowLen']);
}
if($config['fileType']){
$this->setFileType($config['fileType']);
}
if($config['csvSeparator']){
$this->setCsvSeparator($config['csvSeparator']);
}
if($config['lineBreakType']){
$this->setLineBreakType($config['lineBreakType']);
}
if($config['sqlTable']){
$this->setSqlTable($config['sqlTable']);
}
}
}
public function loadFile($filename){
/*
* Lê o arquivo texto $filename e armazena seu conteúdo em $this->source
*/
if(!is_string($filename)){
$this->error('$filename em loadFile() não é uma string', 'error');
return false;
}
$content = @file($filename, FILE_IGNORE_NEW_LINES);
if(!$content){
$this->error('file_get_contents() não leu o arquivo', 'error');
return false;
}else{
$this->source = $content;
return true;
}
}//END loadFile()
public function loadTpl($tpl){
/*
* Carrega em $this->$tpl o template passado em $tpl
* Template armazena as definições de layout do arquivo texto fonte dos
* dados, além de conter parâmetros para interpretação dos dados.
*/
if(!is_string($tpl)){
$this->error('$tpl em loadTpl() não é uma string', 'error');
return false;
}
$json = @file_get_contents($tpl);
if(!$json){
$this->error('Não foi possÃvel ler $tpl em loadTpl()', 'error');
return false;
}else{
$template = json_decode($json, true);
$this->fileType = $template['fileType'];
$this->firstRow = $template['firstRow'];
$this->rowLen = $template['rowLen'];
$this->countRow = $template['countRow'];
$this->cm = $template['cm'];
$this->sqlTable = $template['sqlTable'];
$this->csvSeparator = $template['csvSeparator'];
return true;
}
}//END loadTpl()
public function xtract(){
/*
* Processa $this->source de acordo com $this->tpl e demais parâmetros
* de configuração e salva em $this->result
*/
switch($this->fileType){
case 'fixed':
$result = $this->fromFixed();
return $result;
break;
case 'csv':
$result = $this->fromCsv();
return $result;
break;
default:
$this->error('$this->fileType não tem valor válido em xtract()', 'error');
return false;
break;
}
}//END xtract()
public function output(){
/*
* Processa $this->result e transforma em saÃda formatada conforme
* $this->outputType
*/
if(!is_array($this->result)){
$this->error('$this->result não é um array em output()', 'error');
return false;
}
if(count($this->result) == 0){
$this->error('$this->result não tem linhas em output()', 'error');
return false;
}
switch ($this->outputType){
case 'array':
$this->output = $this->result;
return true;
break;
case 'json':
$this->output = json_encode($this->result);
return true;
break;
case 'csv':
return $this->outputToCsv();
break;
case 'sql':
return $this->outputToSql();
break;
case 'html':
return $this->outputToHtml();
break;
default:
$this->error('$this->outputType não tem valor válido em output()', 'error');
return false;
break;
}
}//END output()
protected function error($error, $type){
/*
* Salva em $this->error os erros recebidos por $error
*/
$this->error[][$type] = $error;
return true;
}//END error()
public function getLastError(){
/*
* Retorna o últiom erro armazenado em $this->error por error()
*/
if(is_array($this->error)){
$num_errors = count($this->error)-1;
return $this->error[$num_errors];
}else{
return false;
}
}//END getLastError()
public function getErrors(){
/*
* Retorna o log de erros de $this->error
*/
return $this->error;
}//END getErrors()
protected function fromFixed(){
/*
* Extrai dados do tipo coluna com largura fixa
*/
if(!$this->rowLen){
$this->error('$this->rowLen não está definida para fromFixed()', 'error');
return false;
}
if(!$this->firstRow){
$this->firstRow = 0;
}
if(!$this->countRow){
$this->countRow = count($this->source);
}
$num_row = 0;
for($i = $this->firstRow; $i <= $this->countRow; $i++){
$row = $this->source[$i];
if(strlen($row) != $this->rowLen){
$this->error('O tamanho da linha '.$i.' é '.strlen($row), 'alert');
}else{
reset($this->cm);
foreach ($this->cm as $prop){
$value = substr($row, $prop['start'], $prop['len']);
if($prop['fn']){
$fn = $prop['fn'];
$value = $fn($value);
}
$this->result[$num_row][$prop['ref']] = $value;
}
$num_row++;
}
}
return true;
}//END fromFixed()
protected function fromCsv(){
/*
* Extrai dados do tipo CSV
*/
if(!$this->firstRow){
$this->firstRow = 0;
}
if(!$this->countRow){
$this->countRow = count($this->source);
}
$num_row = 0;
for($i = $this->firstRow; $i <= $this->countRow; $i++){
$row = $this->source[$i];
$data = str_getcsv($row, $this->csvSeparator);
$fld = $this->getFieldNames();
if(count($data) == count($fld)){
$rows[$num_row] = array_combine($fld, $data);
}
$num_row++;
}
$this->result = $rows;
return true;
}//END fromCsv()
protected function outputToCsv(){
/*
* Formata $this->result como uma string CSV
*/
if(!$this->csvSeparator){
$this->error('$this->csvSeparator não definido em outputToCsv()', 'error');
return false;
}
reset($this->result);
foreach($this->result as $row){
$csv[] = implode($this->csvSeparator, $row);
}
$this->output = $csv;
return true;
}//END outputToCsv()
protected function outputToSql(){
/*
* Formata $this->result como uma string SQL do tipo INSERT
*/
if(!$this->sqlTable){
$this->error('$this->sqlTable não definido em outputToSql()', 'error');
return false;
}
$fld_names = $this->getSqlFieldNames();
if($fld_names === false){
return false;
}else{
$fld_names = implode(',', $fld_names);
}
$str = 'INSERT INTO `'.$this->sqlTable.'` ('.$fld_names.') VALUES ';
foreach($this->result as $row){
foreach($row as $value){
$values[] = "'$value'";
}
$values = implode(',', $values);
$sql[] = $str.'('.$values.');';
unset($values);
}
$this->output = $sql;
return true;
}//END outputToSql()
protected function outputToHtml(){
/*
* Formata $this->result como uma tabela HTML
*/
$fld_names = $this->getFieldNames();
if($fld_names === false){
return false;
}else{
foreach($fld_names as $name){
$header .= "<th>$name</th>";
}
$header = "<thead><tr>$header</tr></thead>";
}
$num_cols = count($fld_names)-1;
$num_rows = count($this->result);
$footer = "<tfoot><tr><td colspan='$num_cols'>Total de registros:</td><td>$num_rows</td></tr></tfoot>";
foreach($this->result as $row){
$rows .= "<tr>";
foreach($row as $value){
$rows .= "<td>$value</td>";
}
$rows .= '<tr>';
}
$tbody = "<tbody>$rows</tbody>";
$html = "<table border='1'>".$thead.$tbody.$tfoot."</table>";
$this->output = $html;
return true;
}//END outputToHtml()
protected function getSqlFieldNames(){
/*
* Retorna os nomes dos campos SQL (colunas) existentes em $this->cm
*/
if(!$this->cm){
$this->error('$this->cm não definido em getfieldNames()', 'error');
return false;
}
reset($this->cm);
foreach($this->cm as $field){
if($field['sqlName']){
$fields[] = $field['sqlName'].'`';
}else{
$fields[] = '`'.$field['ref'].'`';
}
}
return $fields;
}//END getSqlFieldNames()
protected function getFieldNames(){
/*
* Retorna os nomes dos campos (colunas) existentes em $this->cm
*/
if(!$this->cm){
$this->error('$this->cm não definido em getfieldNames()', 'error');
return false;
}
reset($this->cm);
foreach($this->cm as $field){
$fields[] = $field['ref'];
}
return $fields;
}//END getFieldNames()
public function get(){
/*
* Retorna o conteúdo de $this->output
*/
if(!$this->output){
$this->error('$this->output não definido em get()', 'error');
return false;
}else{
return $this->output;
}
}//END get()
public function show(){
/*
* Escreve o conteúdo de $this->output
*/
if(!$this->output){
$this->error('$this->output não definido em show()', 'error');
return false;
}else{
if(is_array($this->output)){
$show = implode('<br />', $this->output);
echo $show;
return true;
}elseif(is_string($this->output)){
echo $this->output;
return true;
}else{
$this->error('$this->output não é um array ou string em show()', 'error');
return false;
}
}
}//END show()
public function download(){
/*
* Oferece download de $this->export conforme $this->outputType
*/
$this->export();
switch ($this->outputType){
case 'json':
$type = 'application/x-javascript';
break;
case 'csv':
$type = 'text/plain';
break;
case 'sql';
$type = 'text/plain';
break;
case 'html';
$type = 'text/html';
break;
default:
$this->error('$this->outputType não definido em download()', 'error');
return false;
break;
}
if(count($this->export) == 0){
$this->error('$this->export não tem conteúdo válido em download()', 'error');
return false;
}
header('Content-type: '.$type);
header('Content-Disposition: attachment; filename="output.'.$this->outputType.'"');
foreach($this->export as $row){
echo $row;
}
return true;
}//END download()
public function file($filename){
/*
* Grava o conteúdo de $this->export em um arquivo texto
*/
$this->export();
switch ($this->outputType){
case 'array':
$this->error('$this->outputType tem valor inválido em file()', 'error');
return false;
break;
case 'html':
$this->error('$this->outputType tem valor inválido em file()', 'error');
return false;
break;
}
if(count($this->export) == 0){
$this->error('$this->export não tem conteúdo válido em file()', 'error');
return false;
}
if(!is_string($filename)){
$this->error('$filename em file() não foi definido', 'error');
return false;
}else{
if(!is_array($this->export)){
$this->error('$this->export não é um array em file()', 'error');
return false;
}else{
if($this->lineBreakType == 'html'){
$this->error('$this->lineBreakType não tem valor válido em file()', 'error');
return false;
}else{
if(file_exists($filename)){
unlink($filename);
}
file_put_contents($filename, $this->export, FILE_APPEND);
}
return true;
}
}
}//END file()
protected function export(){
/*
* Transforma $this->output para $this->export possibilitando exportação por download() ou file()
*/
switch ($this->outputType){
case 'array':
$this->error('$this->outputType tem valor inválido em export()', 'error');
return false;
break;
case 'html':
$this->error('$this->outputType tem valor inválido em export()', 'error');
return false;
break;
}
if(!is_array($this->output)){
$this->error('$this->output não é um array em export()', 'error');
return false;
}else{
if($this->lineBreakType == 'html'){
$this->error('$this->lineBreakType não tem valor válido em export()', 'error');
return false;
}else{
foreach ($this->output as $row){
switch ($this->lineBreakType){
case 'linux':
$this->export[] = $row."\n";
break;
case 'windows':
$this->export[] = $row."\r\n";
break;
}
}
}
return true;
}
}//END export()
public function setOutputType($str){
/*
* Define o valor de $this->outputType
*/
if(!is_string($str)){
$this->error('$str em setOutputType() não é uma string', 'error');
return false;
}else{
switch ($str){
case 'array':
break;
case 'json':
break;
case 'csv':
break;
case 'sql':
break;
case 'html':
break;
default:
$this->error('$str não tem valor válido em setOutputType()', 'error');
return false;
}
$this->outputType = $str;
return true;
}
}//END setOutputType()
public function getOutputType(){
/*
* Retorna o valor de $this->outputType
*/
return $this->outputType;
}//END getOutputType()
public function setFirstRow($int){
/*
* Define o valor de $this->firstRow
*/
if(!is_int($int)){
$this->error('$int não é um inteiro em setFirstRow()', 'error');
return false;
}else{
$this->firstRow = $int;
return true;
}
}//END setFirstRow()
public function getFirstRow(){
/*
* Retorna o valor de $this->firstRow
*/
return $this->firstRow;
}//END getFirstRow()
public function setCountRow($int){
/*
* Define o valor de $this->countRow
*/
if(!is_int($int)){
$this->error('$int não é um inteiro em setCountRow()', 'error');
return false;
}else{
$this->countRow = $int;
return true;
}
}//END setCountRow()
public function getCountRow(){
/*
* Retorna o valor de $this->countRow
*/
return $this->countRow;
}//END getCountRow()
public function setRowLen($int){
/*
* Define o valor de $this->rowLen
*/
if(!is_int($int)){
$this->error('$int não é um inteiro em setRowLen()', 'error');
return false;
}else{
$this->rowLen = $int;
return true;
}
}//END setRowLen()
public function getRowLen(){
/*
* Retorna o valor de $this->rowLen
*/
return $this->rowLen;
}//END getRowLen()
public function setFileType($str){
/*
* Define o valor de $this->fileType
*/
if(!is_string($str)){
$this->error('$str em setfileType() não é uma string', 'error');
return false;
}else{
switch ($str){
case 'fixed':
break;
case 'csv':
break;
default:
$this->error('$str não tem valor válido em setFileType()', 'error');
return false;
}
$this->fileType = $str;
return true;
}
}//END setFileType()
public function getFileType(){
/*
* Retorna o valor de $this->fileType
*/
return $this->fileType;
}//END getFileType()
public function setCsvSeparator($str){
/*
* Define o valor de $this->csvSeparator
*/
if(!is_string($str)){
$this->error('$str não é uma string em setCsvSeparator()', 'error');
return false;
}else{
$this->csvSeparator = $str;
return true;
}
}//END setCsvSeparator()
public function getCsvSeparator(){
/*
* Retorna o valor de $this->csvSeparator
*/
return $this->csvSeparator;
}//END getCsvSeparator()
public function setLineBreakType($str){
/*
* Define o valor de $this->LineBreakType e $this->lineBreak
*/
if(!is_string($str)){
$this->error('$str em setLineBreakType() não é uma string', 'error');
return false;
}else{
switch ($str){
case 'html':
$this->lineBreakType = $str;
$this->lineBreak = '<br />';
return true;
break;
case 'linux':
$this->lineBreakType = $str;
$this->lineBreak = '\n';
return true;
break;
case 'windows':
$this->lineBreakType = $str;
$this->lineBreak = '\r\n';
return true;
break;
default:
$this->error('$str não tem valor válido em setLineBreakType()', 'error');
return false;
}
}
}//END setLineBreakType()
public function getLineBreakType(){
/*
* Retorna o valor de $this->LineBreakType
*/
return $this->lineBreakType;
}//END getLineBreakType()
public function setSqlTable($str){
/*
* Define o valor de $this->sqlTable
*/
if(!is_string($str)){
$this->error('$str não é uma string em setSqlTable()', 'error');
return false;
}else{
$this->sqlTable = $str;
return true;
}
}//END setSqlTable()
public function getSqlTable(){
/*
* Retorna o valor de $this->sqlTable
*/
return $this->sqlTable;
}//END getSqlTable()
}//END TxtXtrator
?>