Google Suggest: Não é Ajax
maio 28, 2009
Como assim? Mas eu digito uma letra e aparece uma janelinha me dando sugestões em tempo de digitação!
Pois é, o Google Suggest utiliza sim requisições assíncronas mas não podemos chamar de Ajax.
O famoso Ajax ficou conhecido devido ao uso do objeto XMLHttpRequest e o nosso amigo Google não utiliza este objeto para fazer suas requisições assíncronas, ele utiliza simplesmente o fato de chamar scripts externos.
Essa é uma técnica antiga muito utilizada quando o XMLHttpRequest não era tão famoso, o pessoal já se virava com seus scripts dinâmicos e iframes.
Como funciona internamente o Google Suggest?
Na primeira letra digitada ele faz a criação dinâmica de uma tag <script> já setando seu atributo src para http://clients1.google.com.br/complete/search?hl=pt-BR&q= sendo que o parâmetro q equivale ao valor do campo de busca.
Então por exemplo, vou buscar sobre “futebol”, assim que digito a letra “f”, ele faz todo esse processo apontando para http://clients1.google.com.br/complete/search?hl=pt-BR&q=f
Na segunda letra digitada, visto que a tag <script> já foi criada anteriormente ele simplesmente muda o atributo src agora apontando para a nova url http://clients1.google.com.br/complete/search?hl=pt-BR&q=fu
Mas como através dessa requisição aparece a lista de sugestões ?
A resposta dessa requisição é simplesmente texto puro, mas por ser chamada na tag <script> ela acaba sendo reconhecida como JavaScript e sendo executada por quem a chamou, em nosso caso a página inicial do Google.
O retorno da requisição é simplesmente isso (Um exemplo para a busca da palavra fut):
window.google.ac.h(["fut",[["futebol ao vivo","5.880.000 resultados","0"], ["futebol","39.800.000 resultados","1"]
Somente essa linha de código é responsável por popular a lista de sugestões.
Segue abaixo uma screenshot no momento da “popularização” de dados:
Por que a Google não utilizou o XMLHttpRequest? Isso foi uma boa solução?
Não é interessante para o Google Suggest controlar o retorno da requisição, saber readyState, status, nada disso é interessante visto que uma requisição é feita a cada letra digitada, então cada requisição sobrescreve a outra.
Não estamos preocupados se a requisição foi feita corretamente, ele simplesmente faz a requisição e se concluir OK, se não der tempo de completar (Isso é bem provável pois se outra letra foi digitada uma nova requisição foi feita), então ele esquece a chamada anterior e vai para a próxima, assim até o usuário “descansar” o dedo e dar tempo para a requisição ser concluída, logo depois a conclusão será mostrado para o usuário os resultados de sua busca.
Outro ponto interessante é a compatibilidade entre browsers. Navegadores muito antigos não têm suporte a XMLHttpRequest e atuais como o IE podem desabilitar essa opção, então na minha opinião foi uma ótima sacada sendo que é garantido que rodará em praticamente qualquer navegador.
Ajax: Classe para múltiplas requisições assíncronas
maio 26, 2009
Ainda vejo muitos desenvolvedores tentando fazer duas requisições Ajax ao mesmo tempo e sofrendo muito com os problemas que isso pode causar. Lembrando que ao fazer a segunda requisição (junto com a primeira) você está simplesmente anulando a anterior. Outra opção é a criação de diversas instâncias de XMLHttpRequest, mas também não é viável devido a incompatibilidade e sobrecarregamento do browser.
Recentemente desenvolvi uma classe Ajax que suporta múltiplas requisições utilizando o conceito de fila e venho aqui compartilhar com vocês.
É uma classe simples responsável por encapsular toda a complexidade do Ajax (não que Ajax seja difícil, pelo contrário Ajax é muito fácil desde que seja utilizado corretamente).
Utilizando o padrão Singleton (lembrando que esse padrão não é 100% seguro em JavaScript) criamos uma única instância do objeto XMLHttpRequest para ser usado em todas as requisições.
Código de classe:
Clique aqui para ver
Modo de usar:
1 Ajax.doPost(“teste.php“, “param=1¶m=2″, function()
2 {
3 if (Ajax.getInstance().readyState == 4)
4 {
5 if (Ajax.getInstance().status == 200)
6 {
7 alert(Ajax.getInstance().responseText);
8 }
9 Ajax.next();
10 }
11 });
Código de exemplo:
Clique aqui para ver
Basta chamar o método Ajax.doPost() para executar uma nova requisição sem se importar se a requisição anterior foi concluída ou não, pois o próximo doPost() somente será executado se a requisição anterior foi concluída.
MySQL: Inserindo registro e recuperando ID gerado
abril 7, 2009
Um dos grandes problemas que costumo ver no MySQL é o seguinte: “Quero inserir um registro em uma tabela, recuperar o ID que foi gerado pelo AUTO_INCREMENT e inserir registros em outras tabelas.”
Vejo por aí muitas soluções, algumas interessantes e outras grandes gambiarras.
Esqueça MAX() +1 , ORDER BY chave DESC LIMIT 1, SHOW TABLE STATUS, entre outros…
Segue abaixo uma das melhores formas para se fazer isso:
2 SELECT LAST_INSERT_ID() INTO @ID;
3 INSERT INTO outratabela (chave_estrangeira, coluna3, coluna4) VALUES (@id, ‘xxx‘, ‘yyy‘);
4 INSERT INTO outratabela (chave_estrangeira, coluna3, coluna4) VALUES (@id, ‘www‘, ‘zzz‘);
5 INSERT INTO outratabela (chave_estrangeira, coluna3, coluna4) VALUES (@id, ‘uuu‘, ‘iiii‘);
Desta forma você tem 100% de eficiência na recuperação do ID, não tendo problemas em capturar um ID recém-inserido por outro usuário. Com LAST_INSERT_ID() você estará recuperando sempre o último ID gerado pela sua sessão.
Se você estiver usando INNODB engine, ainda pode trabalhar com transações adicionando os comandos START TRANSACTION e COMMIT para ter total integridade dos dados.
Java: Email autenticado com Log4J
abril 3, 2009
O Log4J
Com a famosa biblioteca Log4J é possível gerar diversos níveis de erro que vão desde simples informações de debug até erros de nível crítico. É possível também indicar como esses erros serão apresentados, você tem a opção de mostrá-los no console, armazená-los em arquivos ou até mesmo serem enviados por email.
Em alguns casos essa opção de envio por email é muito importante, principalmente quando é usada para informar ao programador ou administrador do sistema os erros mais críticos que ocorrem ocasionalmente com o usuário final.
O Problema
A classe SMTPAppender que é responsável por enviar email no Log4J (apesar de usar internamente as classes da Mail API javax.mail) não dá suporte a envio de emails autenticados, sendo que a maioria dos servidores obriga você a enviar um email utilizando um username e senha existente.
A Solução
A solução é a boa prática da linguagem Orientada a Objeto, isto é, reuso de classes e aprimoramento.
Criando uma nova classe herdada de SMTPAppender você pode sobrescrever o método activeOptions() para então fornecer o suporte ao envio autenticado.
Segue abaixo um modelo criado por Chris Butler que encontrei em um fórum americano.
Clique aqui e veja o código da classe
Seguindo este modelo é necessário incluir/alterar seu arquivo log4j.properties para as seguintes configurações:
log4j.appender.email=org.apache.log4j.net.AuthSMTPAppender
log4j.appender.email.SMTPHost=<smtp.somedomain.com>
log4j.appender.email.user=<your username>
log4j.appender.email.password=<your password>
Lembrando que para quem utilizar configurações em xml (log4j.xml) os parâmetros a serem alterados e adicionados serão os mesmos, só fazendo a diferença que lá são escritos em tags, por exemplo:
<param name="user" value="danilo" />
HTML: Codificação diferente no envio de dados
dezembro 3, 2008
Você já precisou enviar dados em um formulário com codificação diferente da sua página?
Como assim? Inicialmente é meio confuso, mas às vezes acontece.
Por exemplo:
No documento principal que está localizado meu <form>, utilizo o conjunto de caracteres UTF-8 (definido na meta tag)
Na página que irá processar o formulário utilizo o conjunto de caracteres iso-8859-1.
Geralmente isso acontece quando você apenas tem o poder de enviar dados, sendo que a ação do formulário é processada por outro site/servidor.
O atributo accept-charset especifica uma lista de conjuntos de caracteres para a entrada de dados que serão aceitas pelo servidor neste formulário.
Então com isso, resolvemos nosso problema.
Um pequeno exemplo:
form.php
2 <head>
3 <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″ />
4 </head>
5
6 <body>
7
8 <form action=”post.php” method=”post” accept-charset=”iso-8859-1″>
9 <input type=”text” name=”nome” value=”Avião faz vôo hoje às 9:30″ />
10 <input type=”submit” value=”Enviar”>
11 </form>
12
13 </body>
14 </html>
post.php
2 <head>
3 <meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″ />
4 </head>
5
6 <body>
7
9 echo $_POST['nome'];
10 ?>
11
12 </body>
13 </html>
Neste exemplo teremos como resposta o texto exatamente na mesma forma que foi escrito, sem nenhum erro de acentuação. Experimente remover o atributo accept-charset e veja o que acontece.
ou também conhecida como “‘Permission denied to set property XULElement.selectedIndex”…
Alguém já sofreu com este problema? Eu já ![]()
Esse erro do FireFox ocorre quando você tenta dar foco à um campo que possui auto-completar. Isso é muito estranho pois é um ato extremamente normal, essa “exceção” só ocorre em alguns campos e não pode ser capturada via try/catch.
Pesquisando, percebi que realmente se tratava de um bug, ele já foi postado no fórum de bugs da mozilla e já deram como resolvido, estranho pois utilizo a última versão do FF e continuo com esse erro, será mesmo que foi corrigido?
Enfim, como sempre há soluções para contornar o erro… Basta desativar o autocompletar do browser ou do campo específico utilizando o atributo autocomplete=”off”. Exemplo:
Infelizmente essa propriedade não é validada pela W3C, então os desenvolvedores costumam setar essa propriedade através de JavaScript.
PHP: Comparando arrays
setembro 22, 2008
Você já tentou comparar dois arrays utilizando os operadores == ou === ?
Em alguns casos esta comparação pode ser útil.
O operador == retorna true caso os dois arrays sejam iguais, isto é deve conter o mesmo número de elementos com as mesmas chaves e valores. Sem importar a ordem de como eles foram atribuídos.
O operador === retorna true caso os dois arrays sejam iguais, isto é deve conter o mesmo número de elementos com as mesmas chaves e valores. Porém, desta vez a ordem de como eles foram atribuídos também devem ser iguais.
Por exemplo:
2 $paises2 = array(0 => "brasil", 1 => "japao", 2 => "italia");
3
4 var_dump($paises1 == $paises2); // retorna true
Como podem ver, ele retorna true pois todas as verificações foram atendidas (mesmo número de elementos, chaves iguais e valores iguais).
Agora para uma comparação mais exigente:
2 $paises2 = array(1 => "japao", 2 => "italia", 0 => "brasil");
3
4 var_dump($paises1 === $paises2); // retorna false
Já neste caso iria retornar false, mesmo o array sendo igual sua ordem não foi definida da mesma forma.
PHP: session_start() no FPDF
julho 25, 2008
Sempre tive problemas com sessão na hora de gerar arquivos com a classe FPDF.
Era só colocar o session_start() no ínicio do arquivo que o Internet Explorer não abria mais o PDF, já no Firefox funcionava perfeitamente.
Achando a situação muito estranha, fui tentar achar a solução e como sempre os fóruns americanos me salvaram.
Basta colocar o seguinte comando antes da função session_start(), assim ficando:
2 session_start();
Pronto! Agora o Internet Explorer abrirá o PDF normalmente e entederá todas as variáveis de sessão ($_SESSION) normalmente.
[UPDATE]
Lembrando que isso forçará o cache do PDF, caso você não queira deixar o documento no cache é necessário fazer uma chamada diferente da anterior, por exemplo passando um parâmetro dinâmico e único (gerando um número aleatório ou chamando o timestamp são boas soluções).
Exemplo:
document.pdf?token=859859454
document.pdf?token=238142340
document.pdf?token=132984294
[/UPDATE]
Validação de CPF
julho 2, 2008
Eu tenho dó desta pessoa, GLEDE BERNACCI GOLLUSCIO.
Muito provavelmente esta pessoa não consegue se cadastrar na maioria dos sites que exigem CPF, mas por que?
Ele é dono do CPF 111.111.111-11
Muitos sites utilizam uma validação de CPF que restringe essas sequências de números (11111111111, 22222222222, 33333333333, etc) e muita gente não sabe que essas combinações são válidas no algoritmo do CPF.
Mas claro que nem todos estes números ainda têm um dono, porém são válidos.
Alguns outros casos:
Nº do CPF: 444.444.444-44
Nome da Pessoa Física: MARIA FERRO PERON
No do CPF: 888.888.888-88
Nome da Pessoa Física: SEBASTIAO LUIZ BATISTA
Então, tome cuidado ao validar CPF’s em formulários, você pode estar barrando algumas pessoas sem saber.
