Login   Register  
PHP Classes
elePHPant
Icontem

File: dContaVivo.inc.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  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:
Date: 1 year ago
Size: 13,051 bytes
 

Contents

Class file image Download
<?php
// Documentação:
// $conta = new dContaVivo('conta_eletronica.txt');
// $conta->doParse(callbackLinha, callbackResumo);
// 
// callbackLinha($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:
			// --> Não tenho interesse nisso.
			// --> Quem quiser desenvolver, a documentação está na planilha do excel.
			return Array();
		}
		
		$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(
						'tarifa'   =>substr($line, 510, 3),
						'valor'    =>round(substr($line, 306, 13), 2),
						'tipo'     =>rtrim(substr($line, 278, 21)),
						'data'     =>$this->_parseData($line, 212),
						'hora'     =>$this->_parseHora($line, 220),
						'duracao'  =>round(substr($line, 229, 10), 2),
						'servico'  =>rtrim(substr($line, 328, 33)),
						'numero'   =>rtrim(substr($line, 361, 20)),
					);
					$data['linhaLigacoes'][] = $tmpItem;
				}
				elseif($unidade == 'KB'){
					$tmpItem = Array(
						'valor'     =>round(substr($line, 306, 13), 2),
						'tipo'      =>rtrim(substr($line, 278, 21)),
						'data'      =>$this->_parseData($line, 212),
						'hora'      =>$this->_parseHora($line, 220),
						'quantidade'=>round(substr($line, 229, 10), 2),
						'servico'   =>rtrim(substr($line, 328, 33)),
					);
					$data['linhaInternet'][] = $tmpItem;
				}
				elseif($unidade == 'EVENTO' && $info['typeA'][3] == 'M'){
					$tmpItem = Array(
						'valor'     =>round(substr($line, 306, 13), 2),
						'tipo'      =>rtrim(substr($line, 278, 21)),
						'data'      =>$this->_parseData($line, 212),
						'hora'      =>$this->_parseHora($line, 220),
						'quantidade'=>round(substr($line, 229, 10), 2),
						'servico'   =>rtrim(substr($line, 328, 33)),
						'numero'    =>rtrim(substr($line, 361, 20)),
					);
					$data['linhaMensagens'][] = $tmpItem;
				}
				elseif($unidade == 'EVENTO' && $info['typeA'][3] == 'V'){
					$tmpItem = Array(
						'valor'     =>round(substr($line, 306, 13), 2),
						'tipo'      =>rtrim(substr($line, 278, 21)),
						'data'      =>$this->_parseData($line, 212),
						'hora'      =>$this->_parseHora($line, 220),
						'quantidade'=>round(substr($line, 229, 10), 2),
						'servico'   =>rtrim(substr($line, 328, 33)),
						'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]}";
	}
}