JavaScript UTF-8 Decode

Como o Javascript não possui nenhuma função nativa para decodificar string no formato UTF-8, segue uma função que pode ser muito útil por exemplo se você estiver trabalhando com Cookie que não aceita este formato.

function utf8_decode ( str_data ) {
    var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0;
    str_data += '';
    while ( i < str_data.length ) {
        c1 = str_data.charCodeAt(i);
        if (c1 < 128) {
            tmp_arr[ac++] = String.fromCharCode(c1);
            i++;
        } else if ((c1 > 191) &amp;&amp; (c1 < 224)) {
            c2 = str_data.charCodeAt(i+1);
            tmp_arr[ac++] = String.fromCharCode(((c1 &amp; 31) << 6) | (c2 &amp; 63));
            i += 2;
        } else {
            c2 = str_data.charCodeAt(i+1);
            c3 = str_data.charCodeAt(i+2);
            tmp_arr[ac++] = String.fromCharCode(((c1 &amp; 15) << 12) | ((c2 &amp; 63) << 6) | (c3 &amp; 63));
            i += 3;
        }
    }
    return tmp_arr.join('');
}

Esta função foi feita com base na função utf8_decode do PHP.

Retirado do site: PHPJS.org

Google planeja tornar a Web duas vezes mais rápida

chromiumQue o Google investe milhões em pesquisas todo mundo sabe. Sempre somos surpreendidos por novidades. No entanto ninguém imagina até onde vai seus limites.

O Google anda fazendo pesquisas a um nível tão avançado, que estuda meios de substituir o protocolo HTTP que hoje é a base da Word Wide Web.

Recentemente em um post no blog oficial do Chrome, seu navegador, o Google revelou que andou realizando testes em um protocolo denominado “SPDY“, nome que veio da palavra “Speedy” do inglês. Bem apropriado para a ideia de deixar a Web duas vezes mais rápida.

O Protocolo HTTP vem alimentando a Web desde 1996, e o tom do post faz referência ao novo SPDY como um protocolo que irá aposentar o velho HTTP. Hoje em dia sabemos que o Google é uma das poucas empresas com cacife suficiente e recursos para estimular a evolução de sites e navegadores com um protocolo novo que visa acelerar a comunicação entre servidores web e clientes.

O Google revelou ainda que já tem um protótipo de um servidor Web e um cliente Chrome com suporte ao SPDY embutido e que foram testados em laboratório. Em testes, eles teriam conseguido um aumento de 55% na velocidade do carregamento da página.

Confiantes em seu protocolo, o google disponibilizou a documentação do SPDY, bem como o código fonte e deseja que a comunidade participe dando o feedback sobre este revolucionário projeto.

Classe PHP para gerar XML

Ano passado fiz uma classe simples para gerar arquivos XML a partir de um Array Associativo de um modo mais prático. Fiquei surpreso semana passada com o número de downloads e o feedback positivo que tive ao publica-la no phpclasses.org, por isso vou postar aqui também.

Exemplo de Uso

	header("Content-type:application/xml; charset=utf-8");
	$tmp = $this->Search("SELECT id, nome FROM usuarios");

	$objXml = new Xml();
	$objXml->addContent($tmp,'usuarios');
	echo $objXml->showXML();

Classe XML.Class.php

	/**
	* Classe responsável por formatar conteúdos em arquivos XMl
	*
	* @author Marcos Timm Rossow 
	* @version 0.1
	* @copyright Interwise
	* @access Public
	* @package ADM
	*/
	class Xml
	{
		/**
		* Variável com o nome do sistema
		* O nome do sistema é o root do documento xml
		* Por padrão define o sistema definido no arquivo de configuração
		* @access Private
		* @name $_root
		*/
		private $_root = "root";

		/**
		* Variável com o tipo de codificação
		* @access Private
		* @name $_root
		*/
		private $_codificacao = 'UTF-8';

		/**
		* Versão do documento de saída
		* @access Private
		* @name $_versao_xml
		*/
		private $_versao_xml = '1.0';

		/**
		* Objeto de construção do arquivo XML
		* @access Private
		* @name $_obj_xml
		*/
		private $_obj_xml;

		/**
		* Método construtor.
		* Inicia o objeto e cria o root com o nome do sistema especificado no arquivo de configuração
		* @access Public
		* @param String $_root possibilita definir outro nome ao root do documento diferente do informado no arquivo de configuração do sistema
		* @param String $_codificacao possibilita definir outro tipo de codificação. O padrão é UTF-8
		* @param String $_versao_xml possibilita alterar a versão de saída do arquivo XML. Por padrão, versão 1.0
		* @return bool
		*/
		public function __construct($_root = FALSE, $_codificacao = FALSE, $_versao_xml = FALSE)
		{
			// caso  tenha sido passado um nome para o sistema, define o mesmo
			if(isset($_root) AND "" != $_root)
				$this->_root = $_root;

			// caso  tenha sido passado a codificação do sistema, define o mesmo
			if(isset($_codificacao) AND "" != $_codificacao)
				$this->_codificacao = $_codificacao;

			// caso  tenha sido passado versão de saída do arquivo xml, define o mesmo
			if(isset($_versao_xml) AND "" != $_versao_xml)
				$this->_versao_xml = $_versao_xml;

			// inicia o objeto XmlWriter
			$this->_obj_xml = new XmlWriter();
			// inicia a memória
			$this->_obj_xml->openMemory();
			// inicia o documento passando como parâmetro a versão do documento xml e o tipo de codificação que será usada
			$this->_obj_xml->startDocument($this->_versao_xml, $this->_codificacao);
			// cria a raiz do documento com o nome do sistema
			$this->_obj_xml->startElement($this->_root);
			// habilita a identação do documento
			$this->_obj_xml->setIndent(TRUE);
			// define 3 espaços para serem utilizados como identação afim de ficar mais claro no debug
			$this->_obj_xml->setIndentString("   ");

			return true;
		}

		/**
		* Método para adicionar conteúdo ao XML
		* Inicia o objeto e cria o root com o nome do sistema especificado no arquivo de configuração
		* @access Public
		* @param String $_array_dados Array de forma associativa com dados a serem inseridos no objeto XML
		* @return bool
		*/
		public function addContent($_arr_dados, $_str_indice = FALSE)
		{
			// verifica se foi passado um array válido
			if(is_array($_arr_dados) AND 0 < count($_arr_dados))
			{
				// percorre os elementos do array
				foreach($_arr_dados as $chave => $valor)
				{
					// verifica se existem filhos para este array
					if(is_array($valor))
					{
						// abre o elemento
						$this->_obj_xml->startElement($_str_indice);
						// define o primeiro valor como atributo
						//$this->_obj_xml->writeAttribute("id", $valor[key($valor)]);

						// retira a chave
						//array_shift($valor);

						// recursividade para inserir um elemento interno
						$this->addContent($valor);

						// finaliza o elemento
						$this->_obj_xml->endElement();

						// continua percorrendo o array
						continue;
					}

					// insere elementos que não contenham mais filhos
					@$this->_obj_xml->writeElement($chave,$valor);
				}

				return true;
			}
			else
			{
				// debug
				// array inválido
			}
		}

		/**
		* Método para retornar o arquivo XML gerado
		* @access Public
		* @return string
		*/
		public function showXML()
		{
			// finaliza o objeto
			$this->_obj_xml->setIndent(true);
			$this->_obj_xml->endElement();

			// retorna o XML gerado
			return $this->_obj_xml->outputMemory(true);
		}
	}

Está bem comentada. Acho que é bem fácil de entender.

Quem preferir baixar diretamente do PHPClasses: Simple XML Generator

Em breve vou postar outras Classes PHP que ajudam a tornar a vida mais simples.

Menu em ExtJS com Permissões usando PHP e Mysql

Uma das coisas que mais me deu dor de cabeça quando comecei a trabalhar com ExtJS foi montar uma estrutura de Menu Dinâmico de acordo com as permissões do usuário logado. Por isso vou compartilhar minha solução:

Primeiro de tudo vamos criar o nosso banco de dados. Vamos precisar de duas tabelas: uma para o nosso menu e outra com as permissões de cada usuário.

A tabela do Menu terá os campos de id (o id do objeto no Extjs para facilitar manipulação posterior), o nome, o ícone, a pai (caso exista), a ordem e é claro a função que será chamada na ação do clique. Na segunda tabela vamos ter apenas duas chave, o id do usuário e o id do menu. Segue abaixo de exemplo a que eu utilizei:

MySQL

#
# Estrutura da Tabela Menu
#

CREATE TABLE /*!32312 IF NOT EXISTS*/ `menu` (
  `id_menu` int(3) NOT NULL AUTO_INCREMENT,
  `id` varchar(20) DEFAULT NULL,
  `menu` varchar(70) DEFAULT NULL,
  `ordem` int(3) DEFAULT NULL,
  `pai` int(3) DEFAULT NULL,
  `ico` varchar(50) DEFAULT NULL,
  `funcao` varchar(80) DEFAULT NULL,
  PRIMARY KEY (`id_menu`)
) TYPE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

#
# Estrutura da Tabela de Permissões
#

CREATE TABLE /*!32312 IF NOT EXISTS*/ `permissoes` (
  `id_usuario` int(3) NOT NULL DEFAULT '0',
  `id_menu` int(3) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id_menu`,`id_usuario`)
) TYPE=MyISAM DEFAULT CHARSET=latin1;

Dica: Vale lembrar que o ícone dos pais são definidos pelo nome da classe CSS e os filhos devemos especificar o caminho físico da imagem. Não sei por que, mas sub-menus não possuem o atributo “iconCls”. No PHP já vamos levar isso em conta.

A outra parte do nosso Menu é a montagem do Json que irá ser lido no ExtJS. Este método foi testado apenas com 1 sub-nível de menu, mas é fácil de modificar para funcionar com mais. Se alguém fizer, comente a experiência. O método é bem simples de entender. Basicamente buscamos os ítens do Menu principal e percorremos ele em busca de sub-menus alocando tudo em um array associativo.

PHP

		private function trataObjJson($strJson,$arrObjs)
		{
			foreach($arrObjs AS $obj)
				$strJson = str_replace(&amp;amp;amp;quot;\&amp;amp;amp;quot;&amp;amp;amp;quot; . $obj . &amp;amp;amp;quot;\&amp;amp;amp;quot;&amp;amp;amp;quot;,$obj,$strJson);
			return $strJson;
		}

		public function getMenu()
		{
			if($this-&amp;amp;amp;gt;Search(&amp;amp;amp;quot;SELECT id_usuario FROM usuarios WHERE id_usuario=&amp;amp;amp;quot; . $_SESSION['id_usuario']))
			{
				$menu = &amp;amp;amp;quot;&amp;amp;amp;quot;;
				$tmpMenuPai = $this-&amp;amp;amp;gt;Search(&amp;amp;amp;quot;SELECT A.id_menu,id,menu,ordem,pai,ico,funcao FROM menu A JOIN permissoes B ON A.id_menu=B.id_menu WHERE A.pai=0 AND B.id_usuario=&amp;amp;amp;quot; . $_SESSION['id_usuario'] . &amp;amp;amp;quot; ORDER By A.ordem&amp;amp;amp;quot;);
				$i=0;
				$funcoes = array();
				foreach($tmpMenuPai AS $item)
				{
					$menu[$i]['text'] 			= $item['menu'];
					$menu[$i]['iconCls'] 		= $item['ico'];
					$menu[$i]['tabIndex'] 		= $i;
					if($item['funcao']) {
						$menu[$i]['id'] 		= $item['id'];

						$menu[$i]['handler'] 	= $item['funcao'];
						$funcoes[] = $item['funcao'];
					}

					$tmpMenuFilho = $this-&amp;amp;amp;gt;Search(&amp;amp;amp;quot;SELECT A.id_menu,menu,id,ordem,ico,funcao FROM menu A JOIN permissoes B ON A.id_menu=B.id_menu WHERE A.pai=&amp;amp;amp;quot; . $item['id_menu'] . &amp;amp;amp;quot; AND B.id_usuario=&amp;amp;amp;quot; . $this-&amp;amp;amp;gt;_id . &amp;amp;amp;quot; ORDER By A.ordem&amp;amp;amp;quot;);
					$arrFilho = Array();
					$j=0;
					foreach($tmpMenuFilho AS $filho)
					{
						$arrFilho[$j]['text']			= $filho['menu'];
						$arrFilho[$j]['icon']			= $filho['ico'];
						if($filho['funcao']) {
							$arrFilho[$j]['id'] 		= $filho['id'];

							$arrFilho[$j]['handler'] 	= $filho['funcao'];
							$funcoes[] = $filho['funcao'];
						}
						$j++;
					}
					if($arrFilho)
						$menu[$i]['menu'] = $arrFilho;
					$i++;
				}
				header(&amp;amp;amp;quot;Content-Type: application/json&amp;amp;amp;quot;);
				echo $this-&amp;amp;amp;gt;trataObjJson(json_encode($menu),$funcoes);
			}
		}

Observe que precisamos de um método auxiliar para tratar as funções. Isso se deve pelo fato da função json_encode do PHP colocar áspas em tudo, então para o ExtJS não interpretar nossa função como uma string e gerar um erro, utilizamos uma função para retira-las.

Agora que já temos a nossa estrutura de menu em Json, bastam poucas linhas em ExtJS para finalizar:

ExtJS

Ext.onReady(function(){
 	var conn = new Ext.data.Connection();
	conn.request({
		url: 'inc/php/menu.class.php',
		success: function(a){Ext.getCmp('menuPrincipal').bottomToolbar.add(Ext.util.JSON.decode(a.responseText));},
		failure: function(){Ext.MessageBox.alert('Erro', 'Erro ao carregar menu. Atualize a página.');}
	});
});

Espero ter ajudado.

Traçando Rota com a API do Google Maps

mapsUm recurso bem interessante do Google Maps é poder traçar rotas a partir de um endereço ou CEP de algum para se chegar a algum lugar.

Neste exemplo vamos usar um destino fixo e solicitar ao usuário o endereço de partida.

Antes de mais nada, precisamos adquirir a chave API do Google Maps digitando a URL em que sua página será hospedada (você consegue gerar chave para http://localhost também).

De posse da chave, vamos criar uma página HTML simples e incluir a API do google maps já com a nossa chave:

<script type="text/javascript" src=http://maps.google.com/maps?file=api&v=2.x&key=sua-chave"></script>



Agora vamos ao JavaScript com as funções necessárias para carregar o mapa e traçar a rota:

			// declaração de variáveis
			var map;
			var marker;

			// função que carrega o mapa inicial marcando o nosso ponto de chegada
			function load() {
				// verifica a compatibilidade do google maps
			  if (GBrowserIsCompatible()) {

				// Instancia o objeto e aplica na div 'mapa'
				map = new GMap2(document.getElementById("mapa"));
				// Especifica as coordenadas do centro do mapa e o zoom
				map.setCenter(new GLatLng(-20.339884,-40.287469), 14);
				// Especifica o div em que será exibido o detalhamento da rota
				directionsPanel = document.getElementById("route");
				gdir = new GDirections(map, directionsPanel);
				// Adiciona o evento de erros a função handleErrors
				GEvent.addListener(gdir, "error", handleErrors);

				//Adiciona barra de zoom e setas para movimentação no mapa
				map.addControl(new GSmallMapControl());

				//Adiciona um marcador nas coordenadas de chegada
				var point = new GLatLng(-20.339884, -40.287469);
				marker = new GMarker(point);
				map.addOverlay(marker);
				marker.title = "Shopping Vitória";

			  }
			}

			// Traça a Rota
			function setDirections(fromAddress, toAddress, locale){
				gdir.load("from: " + fromAddress + " to: " + toAddress,{"locale": "pt_BR"});
				// Remove o marcador inicial
				map.removeOverlay(marker);
			}

			// Especifica a origem e o destino
			function tracarRota() {
				setDirections(document.getElementById('from').value, "Fernando Ferrari, 514, Goiabeiras, Vitória, ES");
			}

			// Função com tratamentos de erros
			function handleErrors()
			{
			   if (gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
				 alert("Não foi possível achar o endereço. Isso pode ter ocorrido porque o endereço digitado ainda não está inserido no googlemaps ou porque foi digitado incorretamente.\nCódigo do Erro: " + gdir.getStatus().code);
			   else if (gdir.getStatus().code == G_GEO_SERVER_ERROR)
				 alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Código do Erro: " + gdir.getStatus().code);
			   else if (gdir.getStatus().code == G_GEO_MISSING_QUERY)
				 alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Código do Erro: " + gdir.getStatus().code);
			   else if (gdir.getStatus().code == G_GEO_BAD_KEY)
				 alert("Key inválida. Procure a key correta para este domínio no site do google. \n Código do Erro: " + gdir.getStatus().code);
			   else if (gdir.getStatus().code == G_GEO_BAD_REQUEST)
				 alert("A directions request could not be successfully parsed.\n Código do Erro: " + gdir.getStatus().code);
			   else alert("Ocorreu um erro inesperado.");
			}



Lembrando que na Tag “Body” é necessários chamarmos a função Load() para carregar o mapa inicial com nosso ponto de chegada marcado:

Para finalizar, o nosso formulário HTML deverá chamar a função tracarRota() como no código abaixo:

Confira o exemplo funcional

The Ubuntu Counter Project - user number # 31874