PHP Classes

File: dContaVivo.inc.php

Recommend this page to a friend!
  Classes of Alexandre Tedeschi (d)   Conta Vivo On Line   dContaVivo.inc.php   Download  
File: dContaVivo.inc.php
Role: Class source
Content type: text/plain
Description: Classe principal, responsável por todo o trabalho
Class: Conta Vivo On Line
Get details of an account of Vivo phone operator
Author: By
Last change: Atualizado para permitir a leitura do cabeçalho completo da fatura (data de vencimento, número da fatura, valor total, descontos e parcelamentos)...
Date: 9 years ago
Size: 15,816 bytes
 

Contents

Class file image Download
<?php // Documentação: // $conta = new dContaVivo('conta_eletronica.txt'); // $conta->doParse (function($n_linha, $dados){ ... }); // // function($dados): // data_inicio: dd/mm/yyyy // data_fim: dd/mm/yyyy // // // // function($n_linha, $dados): // $n_linha: Apenas números // $dados = Array: // data_ativacao: dd/mm/yyyy // linhaServicoFlags[]: (servico, yesno, param, data_inicio, data_fim) // linhaServicos[]: (servico, plano, unidade, incluso, utilizado, valor, periodos[]: (titulo, valor, data_inicio, data_fim, incluso, utilizado)) // linhaLigacoes[]: (servico, valor, tipo, data, hora, duracao, numero, tarifa) // linhaInternet[]: (servico, valor, tipo, data, hora, quantidade) // linhaMensagens[]: (servico, valor, tipo, data, hora, quantidade, numero) // linhaAdicionais[]: (servico, valor, tipo, data, hora, quantidade, numero) // linhaResumo[]: (descricao, valor) // // callbackResumo($dados) // --> Não implementado, sempre retornará um Array vazio. // class dContaVivo{ private $fh; private $file; private $stop; Function __construct($file){ $this->setFile($file); } Function __destruct(){ $this->close(); } Function setFile($file){ $this->file = $file; } Function doParse($cbEachLine, $cbHeader=false){ // To-handle: // --> Multas? // --> Ligações internacionais? // --> Serviços adicionais (Clube ZERO9?) // --> MMS? Vídeo-chamadas? Serviços 0900? $this->stop = false; $buffer = Array(); $lastLinha = false; $fh = $this->fh = $this->_getFh(); while(!feof($fh)){ $line = rtrim(fgets($fh), "\r\n"); if(!strlen($line)) continue; $info = $this->_parseBasic($line); if($lastLinha != $info['n_linha']){ if($cbHeader && $buffer && !$lastLinha){ $ret = $this->_parseBuffer($lastLinha, $buffer); if($ret !== false) call_user_func($cbHeader, $ret); if($this->stop){ return false; } } elseif($cbEachLine && $buffer && $lastLinha){ $ret = $this->_parseBuffer($lastLinha, $buffer); if($ret !== false) call_user_func($cbEachLine, $lastLinha, $ret); if($this->stop){ return false; } } $buffer = Array(); $lastLinha = $info['n_linha']; } $buffer[] = $info; } fclose($this->fh); $this->fh = false; if($buffer){ if($cbHeader && $buffer && !$lastLinha){ $ret = $this->_parseBuffer($lastLinha, $buffer); if($ret !== false) call_user_func($cbHeader, $this->_parseBuffer($lastLinha, $buffer)); } elseif($cbEachLine && $buffer && $lastLinha){ $ret = $this->_parseBuffer($lastLinha, $buffer); if($ret !== false) call_user_func($cbEachLine, $lastLinha, $ret); } $buffer = Array(); } return true; } Function stop(){ $this->stop = true; } Function close(){ if($this->fh){ fclose($this->fh); $this->fh = false; } } Function _getFh(){ if(!$this->fh){ $this->fh = fopen($this->file, "r"); } if(!$this->fh){ die("contaVivo: Arquivo não encontrado."); } return $this->fh; } Function _parseBuffer($n_linha, $buffer){ # $dh = fopen("debug.txt", "w"); # echo "Processando buffer para número '{$n_linha}'. São ".sizeof($buffer)." linhas para processar.\r\n"; # echo "------------------------------------------------------------------------------\r\n"; if(!$n_linha){ // Processar o cabeçalho. $data = Array(); $data['data_inicio'] = false; $data['data_fim'] = false; $data['data_emissao'] = false; $data['n_conta'] = false; $data['valor_total'] = false; foreach($buffer as $idx=>$info){ $typeA = &$info['typeA']; $typeB = &$info['typeB']; $line = &$info['line']; $_appendTo = false; if ($typeA == '010' && $typeB == '010D'){ $data['data_inicio'] = $this->_parseData($line, 353); // Também poderia ser o offset 1074 $data['data_fim'] = $this->_parseData($line, 205); // Também poderia ser o offset 361 $data['data_emissao'] = $this->_parseData($line, 229); $data['data_vcto'] = $this->_parseData($line, 247); $data['n_conta'] = substr($line, 0, 10); $data['valor_total'] = round(substr($line, 552, 13), 2); // Offset: 552, 594, 929, 1158 $data['n_linhas'] = intval(substr($line, 224, 5)); } elseif($typeA == '120R' && $typeB == '162D'){ // Descontos diversos $data['descontos'][] = Array( 'linha' =>trim(substr($line, 424, 15)), // linha relacionada 'valor' =>round(substr($line, 181, 13), 2), 'descricao'=>trim (substr($line, 212, 100)), 'servico' =>trim(substr($line, 399, 25)), // '402_DSS_DESCONTO SERVICO', '403_DSV_DESCONTO VOLUME' ); } elseif($typeA == '050R' && $typeB == '185D'){ // Créditos de valores contestados $data['contestacoes'][] = Array( 'valor' =>round(substr($line, 179, 13), 2), 'descricao' =>trim(substr($line, 206, 50)), 'data_contestacao'=>$this->_parseData($line, 326), 'periodo_inicio' =>$this->_parseData($line, 445).' '.$this->_parseHora($line, 453), 'periodo_fim' =>$this->_parseData($line, 459).' '.$this->_parseHora($line, 467), 'servico' =>trim(substr($line, 398, 45)) ); } elseif($typeA == '110' && $typeB == '190D'){ // Parcelamentos $data['parcelamentos'][] = Array( 'linha' =>trim(substr($line, 280, 15)), 'valor' =>round(substr($line, 192, 14), 2), 'descricao' =>trim(substr($line, 210, 50)), 'servico' =>trim(substr($line, 451, 10)), 'parcela' =>intval(substr($line, 272, 2)).'/'.intval(substr($line, 274, 2)), ); } } return $data; } $data['data_ativacao'] = false; $data['linhaServicoFlags'] = Array(); $data['linhaServicos'] = Array(); $data['linhaLigacoes'] = Array(); $data['linhaInternet'] = Array(); $data['linhaMensagens'] = Array(); $data['linhaAdicionais'] = Array(); $data['linhaResumo'] = Array(); foreach($buffer as $idx=>$info){ # $dump = false; $typeA = &$info['typeA']; $typeB = &$info['typeB']; $line = &$info['line']; $callTypes = Array(); $smsTypes = Array(); // Cabeçalho básico: if($info['typeA'] == '095' && $info['typeB'] == '200D'){ $data['data_ativacao'] = $this->_parseData($line, 347); if($data['data_ativacao'] == ' / / ') return false; } elseif($idx==0){ // Primeira linha TINHA que ser o cabeçalho. // Então é um registro inválido. return false; } // Serviços e flags elseif($info['typeA'] == '270' && $info['typeB'] == '205D'){ // Informação básica sobre serviços e flags ativas: $data['linhaServicoFlags'][] = Array( 'servico' =>rtrim(substr($line, 178, 50)), 'yesno' =>substr($line, 228, 1), 'param' =>rtrim(substr($line, 230)), 'data_inicio'=>false, 'data_fim' =>false, ); } elseif($info['typeA'] == '270' && $info['typeB'] == '206D'){ // Informações avançadas sobre flags e serviços (ex: data de início/fim do comodato) $tmpItem = Array( 'servico' =>rtrim(substr($line, 178, 50)), 'data_inicio'=>$this->_parseData($line, 228), 'data_fim' =>$this->_parseData($line, 236), ); $merged = false; foreach($data['linhaServicoFlags'] as $idx=>$item){ if($item['servico'] == $tmpItem['servico']){ $data['linhaServicoFlags'][$idx]['data_inicio'] = $tmpItem['data_inicio']; $data['linhaServicoFlags'][$idx]['data_fim'] = $tmpItem['data_fim']; $merged = true; break; } } if(!$merged){ $tmpItem['yesno'] = false; $tmpItem['param'] = false; $data['linhaServicoFlags'][] = $tmpItem; } } // Montagem do linhaServicos: elseif($info['typeA'] == '100' && $info['typeB'] == '225T'){ $inServicoKey = sizeof($data['linhaServicos']); $data['linhaServicos'][$inServicoKey] = Array( 'servico' =>rtrim(substr($line, 182,46)), 'plano' =>false, 'unidade' =>'Unknown', 'incluso' =>0, 'utilizado'=>0, 'valor' =>0, 'periodos'=>Array(), ); } elseif($info['typeA'] == '100' && $info['typeB'] == '225D'){ $tmpItem = Array( 'titulo' =>rtrim(substr($line, 210, 50)), 'valor' =>round(substr($line, 185, 10), 2), 'data_inicio'=>$this->_parseData($line, 260), 'data_fim' =>$this->_parseData($line, 268), 'incluso' =>round(substr($line, 463, 15), 2), 'utilizado' =>round(substr($line, 526, 14), 2), ); // Preenche o nome do plano, de acordo com a descrição. if(!$data['linhaServicos'][$inServicoKey]['plano']){ $data['linhaServicos'][$inServicoKey]['plano'] = rtrim(substr($line, 210, 50)); } // Soma os sub-totais, caso não haja uma linha com o sub-total. $data['linhaServicos'][$inServicoKey]['valor'] += $tmpItem['valor']; $data['linhaServicos'][$inServicoKey]['incluso'] += $tmpItem['incluso']; $data['linhaServicos'][$inServicoKey]['utilizado'] += $tmpItem['utilizado']; $data['linhaServicos'][$inServicoKey]['periodos'][] = $tmpItem; } elseif($info['typeA'] == '100' && $info['typeB'] == '225B'){ $tmpItem = Array( 'titulo' =>rtrim(substr($line, 210, 50)), 'unidade' =>substr($line, 459, 3), // 001=Minutos, 003=Kbytes 'incluso' =>round(substr($line, 463, 15), 2), 'utilizado' =>round(substr($line, 526, 14), 2) ); if(!$data['linhaServicos'][$inServicoKey]['plano']){ $data['linhaServicos'][$inServicoKey]['plano'] = $tmpItem['titulo']; } $data['linhaServicos'][$inServicoKey]['incluso'] = $tmpItem['incluso']; $data['linhaServicos'][$inServicoKey]['utilizado'] = $tmpItem['utilizado']; if($tmpItem['unidade'] == '001') $data['linhaServicos'][$inServicoKey]['unidade'] = 'Minutos'; if($tmpItem['unidade'] == '002') $data['linhaServicos'][$inServicoKey]['unidade'] = 'Eventos'; if($tmpItem['unidade'] == '003') $data['linhaServicos'][$inServicoKey]['unidade'] = 'Kbytes'; } // Detalhamento das ligações, mensagens e conexões: // --> Todos iniciam com 159X:XXXT e tem dados em 150X:XXXD. // // Podemos filtrar pelo dígito em TypeA e a unidade, tal como: // V:MINUTOS --> 570 Caracteres - Ligação // C:MINUTOS --> 570 Caracteres - Ligação para caixa postal // C:KB --> 481 Caracteres - Tarifação da internet // M:EVENTO --> 529 Caracteres - Mensagem (SMS) // V:EVENTO --> 447 Caracteres - Adicional por ligações (efetuadas/recebidas em roaming) // // Para informações mais precisas, também poderíamos filtrar por TypeB, sendo: // 265 --> Ligação // 270 --> Caixa postal // 282 --> Internet // 340 --> Roaming, para celulares de outras operadoras // 287 --> Torpedo SMS // 315 --> Longa distância para dentro do Estado // 318 --> Longa distância para outros Estados // 365 --> No brasil, em roaming, adicional por ligações realizadas // 370 --> No brasil, em roaming, adicional por ligações recebidas // 375 --> No brasil, em roaming, ligações recebidas em roaming // xxx --> Deve haver vários outros tipos que não temos informações. // elseif(substr($info['typeA'], 0, 3) == '159' && $info['typeB'][3] == 'T'){ // $dump = true; // Vamos ignorar o header, que contém apenas os subtotais. // Muita informação duplicada, vamos pegar apenas informações detalhadas, // e depois somar os subtotais diretamente na programação. } elseif(substr($info['typeA'], 0, 3) == '150' && $info['typeB'][3] == 'D'){ $unidade = rtrim(substr($line, 242, 20)); if($unidade == 'MINUTOS'){ $tmpItem = Array( 'data' =>$this->_parseData($line, 212), 'hora' =>$this->_parseHora($line, 220), 'servico' =>rtrim(substr($line, 328, 33)), 'tarifa' =>substr($line, 510, 3), 'valor' =>round(substr($line, 306, 13), 2), 'tipo' =>rtrim(substr($line, 278, 21)), 'grupo' =>rtrim(substr($line, 64, 20)), 'originada' =>substr($line, 513, 2), // OR=Originada, CC=Recebida (A cobrar), RE=Adicional por chamada recebida 'roaming' =>substr($line, 528, 2), // HO=Home, RM=Roaming 'periodo' =>substr($line, 88, 1), // L=Período anterior, ' '=Período Atual 'duracao' =>round(substr($line, 229, 10), 2), 'ddd_origem'=>substr($line, 432, 3), 'numero' =>rtrim(substr($line, 361, 20)), // 'rawLinha' =>$line, ); $data['linhaLigacoes'][] = $tmpItem; } elseif($unidade == 'KB'){ $tmpItem = Array( 'data' =>$this->_parseData($line, 212), 'hora' =>$this->_parseHora($line, 220), 'servico' =>rtrim(substr($line, 328, 33)), 'tipo' =>rtrim(substr($line, 278, 21)), 'quantidade'=>round(substr($line, 229, 10), 2), 'valor' =>round(substr($line, 306, 13), 2), ); $data['linhaInternet'][] = $tmpItem; } elseif($unidade == 'EVENTO' && $info['typeA'][3] == 'M'){ $tmpItem = Array( 'data' =>$this->_parseData($line, 212), 'hora' =>$this->_parseHora($line, 220), 'servico' =>rtrim(substr($line, 328, 33)), 'tipo' =>rtrim(substr($line, 278, 21)), 'valor' =>round(substr($line, 306, 13), 2), 'quantidade'=>round(substr($line, 229, 10), 2), 'numero' =>rtrim(substr($line, 361, 20)), ); $data['linhaMensagens'][] = $tmpItem; } elseif($unidade == 'EVENTO' && $info['typeA'][3] == 'V'){ $tmpItem = Array( 'data' =>$this->_parseData($line, 212), 'hora' =>$this->_parseHora($line, 220), 'servico' =>rtrim(substr($line, 328, 33)), 'tipo' =>rtrim(substr($line, 278, 21)), 'valor' =>round(substr($line, 306, 13), 2), 'quantidade'=>round(substr($line, 229, 10), 2), 'numero' =>rtrim(substr($line, 361, 20)), ); $data['linhaAdicionais'][] = $tmpItem; } } // Resumo final: elseif($info['typeA'] == '080D' && $info['typeB'] == '560T'){ // Número da linha e subtotal, não precisamos disso. } elseif($info['typeA'] == '080D' && $info['typeB'] == '560D'){ $data['linhaResumo'][] = Array( 'descricao'=>rtrim(substr($line, 178, 100)), 'valor' =>round(substr($line, 278), 2) ); } // Dados não tratados: elseif(substr($info['typeB'], -1) == 'T' || substr($info['typeB'], -1) == 'D'){ # $dump = true; } # if($dump){ # fwrite($dh, $line."\r\n"); # } } return $data; } Function _parseBasic (&$line){ return Array( 'n_conta'=>trim(substr($line, 0, 10)), 'n_linha'=>trim(substr($line, 30, 10)), 'typeA' =>trim(substr($line, 84, 4)), 'typeB' =>trim(substr($line, 110, 4)), 'line' =>$line ); } Function _parseData(&$line, $offset){ $data = substr($line, $offset, 8); return "{$data[6]}{$data[7]}/{$data[4]}{$data[5]}/{$data[0]}{$data[1]}{$data[2]}{$data[3]}"; } Function _parseHora(&$line, $offset){ $data = substr($line, $offset, 6); return "{$data[0]}{$data[1]}:{$data[2]}{$data[3]}:{$data[4]}{$data[5]}"; } }