segunda-feira, 8 de setembro de 2008

DbLookup na Web

Quem de nós, desenvolvedores web, nunca precisou utilizar um Dblookup em uma pagina de web? E quando utilizava tinha que colocar em um campo para e fazer o famoso refresh da pagina? Pois caro amigo, passei por esse problema. Agora, venho aqui facilitar a vida dos colegas que precisa de uma solução rápida para o dblookup na web. Pense no seguinte: você precisa atualizar um campo ou fazer um innerHtml em um elemento através de um valor selecionado em um bendito campo combo. Mas isso sem fazer um refresh da pagina, pois vc sabe que quando dependendo do dado é perdido tudo que foi digitado. Vou aqui se utilizar de uma técnica parecida que vi no site CODESTORE, mas não irei utilizar o codigo que existe lá, só a ideia.
Para começar temos que criar uma Page com o nome doDBLookup. Pode ser qualquer, mas esse é como uma referencia para o que vamos fazer. Nessa page vamos adicionar um Computed Value com a seguinte formula:


server:=@UrlQueryString("server");
database:=@UrlQueryString("file");
view:=@UrlQueryString("view");
key:=@UrlQueryString("key");

fetch:=@If(@UrlQueryString("field")=""; @TextToNumber(@UrlQueryString("column"));@UrlQueryString("field"));

list := @DbLookup(""; server:database; view; key; fetch);

@If(@IsError(list); "Error"; @Implode(@Text(list);@NewLine))

Salve a page, pois ela será nossa pagina de pesquisa atravéz de QueryString.

Calma que você vai entender.

Agora, vamos a nossa biblioteca de scripts e criar uma nova biblioteca em JavaScript e adicionar o seguinte código:

function doLookup(oServer, oDb, oView, oKey, oColumn, oField){
/*
oServer = Servidor de Pesquisa
oDb = Bando de Dados de Pesquisa
OView = View que deseja pesquisar
oKey = Chave de pesquisa na view
oColumn = Numero da coluna de retorno;
oField = Nome do Campo que deseja o retorno;
*/
var x, objXMLHTTP, URL, postVars;
var f = document.forms[0];
try{
if(window.XMLHttpRequest){
objXMLHTTP = new XMLHttpRequest();
}else if(window.ActiveXObject){
try{
objXMLHTTP = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
objXMLHTTP = new ActiveXObject("Microsoft.XMLHTTP")
}catch(e){
return false;
}
}
}else{
return false;
};

URL = 'doDBLookup?openpage';
postVars = '&server=' + oServer+'&file='+oDb+'&view='+oView+'&key='+oKey+'&field='+oField+'&column='+oColumn;

objXMLHTTP.open('GET', URL+postVars, false);
objXMLHTTP.setRequestHeader("Content-type", "text/html; charset=iso-8859-1");
objXMLHTTP.setRequestHeader("Content-Language", "pt-br");
objXMLHTTP.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
objXMLHTTP.setRequestHeader("Connection", "close");

objXMLHTTP.send();

//responseText sendo atribuido a um campo
f.Result.value = objXMLHTTP.responseText;

x = null; objXMLHTTP = null; f = null, URL = null, postVars = null;
}catch(x){
alert('Erro ao carregar a página, tente novamente.');
x = null; objXMLHTTP = null; f = null, URL = null, postVars = null;
};
}

Meu amigo Thiago Diniz me ajudou a projetar esse código.
Salve a biblioteca, pois é atravéz dela que iremos instanciar na pagina onde faremos a busca. Esse código é reponsavel por receber os parametros e adiciona em um campo no código conforme comentário. No caso da consulta não for utilizar campo deixe o parametro vazio (''), agora se for utilizar campo deixe o parametro Coluna vazio ('').

Faça a chamada dessa biblioteca em seu formulário no HTML Head Content:

"< src =" \" language =" \" type =" \"> < /script > " + @NewLine

A função será disparada pelo campo que será a chave de pesquisa no onBlur:

doLookup(document.forms[0].Server.value, document.forms[0].Database.value, 'vocTipoDespesa', getSelectValue('dlgDespesa'), '2', '')


Segue a função getSelectValue:

function getSelectValue(name){
var indice = eval("document.forms[0]."+name+".selectedIndex");
var valor = eval("document.forms[0]."+name+".options["+indice+"].value");
return(valor);
}

quinta-feira, 17 de abril de 2008

Proteção Contra SQL Injection

Como é de comum a todos, ou deveria ser, os maiores ataques dos hackers aos sites são através de SQL Injection, venho por meio desse post ensinar a se defender desses ataques.

Se engana quem pense que os ataques são sempre feitos em formulários, os ataques mais fortes são feitos pela url, a famosa querystring.

Ex: www.dominio.com.br/index.asp?id=4

Isso é um perigo se estiver sem proteção, e a maioria dos sites hoje em dia estão desprotegidos a esse tipo de ataque, parece mentira, mas com esse ataque é possível dar updates e drops no banco, criar procedures e até mesmo copiar arquivos executaveis para dentro do servidor e executá-los! Mas é claro que não vou ensinar a fazer isso aqui, hehehe, esse artigo é para a proteção.

Uma das melhores proteções, é criar usuários diferentes no banco, um usuário para selects e outro para update/drop/delete, e usar nas páginas de consulta o usuario de select.

Mas vou mostrar também uma função bem útil quem ajuda muito a pegar os espertinhos, segue ela abaixo:


Sub Valida_Request()

Set objRegExpr = New RegExp
objRegExpr.Global = True
objRegExpr.IgnoreCase = True
objRegExpr.Pattern = """|'|;| delete |drop|insert|select|update|upload"

For Each obj In Request.Form
If objRegExpr.Test(Request.Form(obj)) Then
Response.Write "A palavra ou caractere "& Request.Form(obj) &" é invalido para o Campo " & obj & " favor substituí-lo ou retirá-lo."
Response.End
End If
Next

For Each obj In Request.QueryString
If objRegExpr.Test(Request.QueryString(obj)) Then
Response.Write "A palavra ou caractere "& Request.Form(obj) &" é invalido para o Campo " & obj & " favor substituí-lo ou retirá-lo."
Response.End
End If
Next

Set objRegExpr = Nothing

End Sub



Essa função deve ser chamada no topo de todas as paginas, ela evita que a comandos como delete|drop|insert|select|update|upload e caracteres como "|'|; sejam inseridos nos formularios e querystrings, esses são os principais comandos e caracteres usados pelos hackers para esse tipo de ataque.

Espero que tenham gostado da dica.

Abs a todos!

quarta-feira, 16 de abril de 2008

FrameWork Ajax no Domino

A muito quando descobri o Ajax e me interessei pelo assunto passava por maus "bocados" para utilizar a biblioteca de scripts dentro do domino.
Primeiro anexava dentro de uma base NSF os arquivos um a um para poder referencia-los dentro dos elementos de designer da aplicação. Depois em uma matéria do CODESTORE vi que poderia utilizar o WEBDAV para que através de um FTP anexar os arquivos transferindo como se fosse uma pasta normal. Achei isso um máximo. Sem falar nas possibilidade de um designer em outro local poder alterar uma aplicação.
Posso até estar atrasado no assunto, mais garanto que muitos colegas que trabalham com o Lotus Notes não sabe que podemos utilizar o recurso que vou explicar agora.
Para melhor utilizar a biblioteca de scripts seja ela qual for (Dojo, Yahoo! UI, scriptaculus e etc.) basta colocar a pasta de arquivos abaixo do seguinte caminho do servidor Domino: \Data\domino\html\
Assim podemos referenciar qualquer biblioteca que desejamos utilizar. Claro que é importante a organização dentro do diretório e muito cuidado para não acontecer acidentes. ;)

Veja como fiz com o DOJO.

Depois que adicionar a biblioteca na pasta html do servidor Domino podemos fazer referência aos arquivos dentro da pasta html.

E agora mãos a obra. Podemos brincar com as bibliotecas conforme nossa necessidade e utilizar duas ou mais bibliotecas dentro de uma mesma aplicação.

Download de algumas Bibliotecas:
Dojo ToolKit
Yahoo! UI
Scriptaculos
Ext JS

segunda-feira, 31 de março de 2008

Alternativa ao Embedded View

Todo desenvolvedor Lotus Notes sabe o quanto é demorado o refresh no browser quando tem que utilizar Embedded View. Especialmente em um formulário que precisamos armazenar uma tabela dinâmica. Pois é, também tive esse problema e procurei alternativas para resolver esse problema. No meu caso eu precisava fazer uma tabela dinâmica, mas não me interessava armazenar separadamente como um documento response já que iria ser visualizado somente no documento quando aberto. Claro que as boas idéias, são inspiradas em outras pré-existente e comigo não foi diferente. Navegando no site do CODESTORE tive a luz em uma solução que pra mim foi o pulo do gato.

1. Como quero que fique:
- No Formulário

- Dialogo de Inclusão















2. Como Faço:
Primeiramente crie no formulário os campos referente as colunas da tabela, pois cada coluna será armazenado por um campo multi-valor. Esses campos serão ocultos.
Agora crie a estrutura da tabela em HTML com a propriedade de texto Pass-Thru HTML marcada. Onde será o conteúdo da tabela adicione o Texto Computado. Conforme as imagens a seguir.


- No Formulário:

- No Texto Computado:

- Botão "Incluir"

DisableSelect(); //Desabilita os campo selected
//Ativa a DIV
PutClass('opacity','geral_opacity');
On('opacity');
On('dlgPassageiro'); // Exibe a DIV para adicionar os dados da linha a ser incluído.


- No Botão "OK"

var objForm = document.forms[0];
if(objForm.EditaAtividadeAtual.value != ''){
doAlteraAtividadeAtual(objForm.EditaAtividadeAtual.value);
}else if(objForm.EditaAtividadeProposta.value != ''){
doAddAtividadeAtual();
}

objForm.Atividade.value = '';
objForm.EditaAtividadeAtual.value = '';
objForm.EditaAtividadeProposta.value = '';

EnableSelect();
Off('opacity');
Off('dlgAtividades');


3. As Funções JavaScript:Todas as funções utilizadas são chamadas no HTML HEAD do Formulário. Segue abaixo:

- Global.js

/*
Objetivo: Funções globais da aplicação.
Autor: Renato Dalforne
Alterado: Ailton Nunes
Ajuda: Thiago Diniz (função lerCarcPos)
*/

function PutClass(campo, classe){
document.getElementById(campo).className=classe;
return;}
//==============================================================
function On(div) {
document.getElementById(div).style.visibility='visible';}
function Off(div) {
document.getElementById(div).style.visibility='hidden';}
function getID(id) {
return document.getElementById(id);}
function getTag(name) {
return document.getElementsByTagName(name);}
function makeElem(name){
return document.createElement(name);}
//==============================================================
//Implementa o método trim() no objeto String.
String.prototype.trim = trim;
function trim(){
return(this.replace(/^\s+|\s+$/gi,"").replace(/\s{2,}/gi," "))
}
//==============================================================
function DisableSelect(){
var a = getTag('select');
for(var i=0,b; b=a[i]; i++) b.style.visibility='hidden';
a=b=i=null;}
//==============================================================
function EnableSelect(){
var a = getTag('select');
for(var i=0,b; b=a[i]; i++) b.style.visibility='visible';
a=b=i=null;}
//==============================================================
function lerCarcPos(campo, marcador, Pos){
var x;
try{
var field = campo.value.split(marcador);
var retorno = field[Pos];
return(retorno);
}catch(x){
return(false);
};
}
//==============================================================

- addTabelaAtividade.js
  • doAddAtividadeAtual

/*
Objetivo: Adicionar, Remover e Alterar uma linha de uma tabela de atividades.
Autor; Ailton Nunes
*/
//==============================================================
function doAddAtividadeAtual(){

var f = document.forms[0];

caminho = (window.location.pathname.split('.nsf/'))[0];
servidor = (window.location.href.split(caminho))[0];

var currTotal=f.AtualAtividade.value.split(';').length;

if (f.dlgAtividade.value ==''){
f.AtualAtividade.value+='; -';
var txt1 = document.createTextNode('-');
}else{
f.AtualAtividade.value+='; '+ f.dlgAtividade.value;
var txt1 = document.createTextNode(f.dlgAtividade.value);
}

if (f.dlgAtor.value == ''){
f.AtualAtor.value+='; =';
var txt2 = document.createTextNode('-');
}else{
f.AtualAtor.value+='; '+ f.dlgAtor.value;
var txt2 = document.createTextNode(f.dlgAtor.value);
}

if (f.dlgRecurso.value == ''){
f.AtualRecurso.value+='; -';
var txt3 = document.createTextNode('-');
}else{
f.AtualRecurso.value+='; '+ f.dlgRecurso.value;
var txt3 = document.createTextNode(f.dlgRecurso.value);
}

if (f.dlgEntradas.value == ''){
f.AtualEntrada.value+='; -';
var txt4 = document.createTextNode('-');
}else{
f.AtualEntrada.value+='; '+ f.dlgEntradas.value;
var txt4 = document.createTextNode(f.dlgEntradas.value);
}

if (f.dlgSaidas.value == ''){
f.AtualSaida.value+='; -';
var txt5 = document.createTextNode('-');
}else{
f.AtualSaida.value+='; '+ f.dlgSaidas.value;
var txt5 = document.createTextNode(f.dlgSaidas.value);
}

var tr = document.createElement('tr');
var td0 = document.createElement('td');
var td1 = document.createElement('td');
var td2 = document.createElement('td');
var td3 = document.createElement('td');
var td4 = document.createElement('td');
var td5 = document.createElement('td');
var td6 = document.createElement('td');
var img = document.createElement('img');
var img2 = document.createElement('img');
var rem = document.createElement('a');
var edi = document.createElement('a');

img.setAttribute('src', servidor+caminho+'.nsf/remove.gif');
img.setAttribute('border', '0');

img2.setAttribute('src', servidor+caminho+'.nsf/edit.gif');
img2.setAttribute('border', '0');

rem.setAttribute("href","JavaScript:void(doRemoveAtividadeAtual("+currTotal+"));");
rem.appendChild(img);

edi.setAttribute("href","JavaScript:void(doEditaAtividadeAtual("+currTotal+"));");
edi.appendChild(img2);

var txt2 = document.createTextNode(f.dlgAtor.value);
var txt3 = document.createTextNode(f.dlgRecurso.value);
var txt4 = document.createTextNode(f.dlgEntradas.value);
var txt5 = document.createTextNode(f.dlgSaidas.value);*/

td0.appendChild(rem);
td1.appendChild(edi);

td2.appendChild(txt1);
td3.appendChild(txt2);
td4.appendChild(txt3);
td5.appendChild(txt4);
td6.appendChild(txt5);

tr.appendChild(td0);
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tr.appendChild(td4);
tr.appendChild(td5);
tr.appendChild(td6);

tr.setAttribute('id','atividades-atual-'+currTotal);
tr.setAttribute('class','atividades-atual');

var container = document.getElementById('tab-atividades-atual');

container.appendChild(tr);

//Limpa os campos
f.dlgAtividade.value = '';
f.dlgAtor.value = '';
f.dlgRecurso.value = '';
f.dlgEntradas.value = '';
f.dlgSaidas.value = '';
}
  • doRemoveAtividadeAtual

function doRemoveAtividadeAtual(idx){
if (!confirm('Você tem certeza que deseja remover essa atividade?')) return;

var f = document.forms[0];

var currFiles1=f.AtualAtividade.value.split('; ');
var currFiles2=f.AtualAtor.value.split('; ');
var currFiles3=f.AtualRecurso.value.split('; ');
var currFiles4=f.AtualEntrada.value.split('; ');
var currFiles5=f.AtualSaida.value.split('; ');

//removes file
currFiles1[idx]="";
currFiles2[idx]="";
currFiles3[idx]="";
currFiles4[idx]="";
currFiles5[idx]="";

f.AtualAtividade.value = currFiles1.join('; ');
f.AtualAtor.value = currFiles2.join('; ');
f.AtualRecurso.value = currFiles3.join('; ');
f.AtualEntrada.value = currFiles4.join('; ');
f.AtualSaida.value = currFiles5.join('; ');

//remove tr container
tr=document.getElementById("atividades-atual-"+idx);

tr.parentNode.removeChild(tr);

}
  • doEditaAtividadeAtual

function doEditaAtividadeAtual(idx){
DisableSelect();
PutClass('opacity','geral_opacity');
On('opacity');
On('dlgAtividades');

var f = document.forms[0];

f.dlgAtividade.value = lerCarcPos(f.AtualAtividade, ';', idx).trim();
f.dlgAtor.value = lerCarcPos(f.AtualAtor, ';', idx).trim();
f.dlgRecurso.value = lerCarcPos(f.AtualRecurso, ';', idx).trim();
f.dlgEntradas.value = lerCarcPos(f.AtualEntrada, ';', idx).trim();
f.dlgSaidas.value = lerCarcPos(f.AtualSaida, ';', idx).trim();

f.EditaAtividadeAtual.value = idx;
}
  • doAlteraAtividadeAtual

function doAlteraAtividadeAtual(idx){
if (!confirm('Você tem certeza que deseja alterar essa atividade?')) return;

var f = document.forms[0];

caminho = (window.location.pathname.split('.nsf/'))[0];
servidor = (window.location.href.split(caminho))[0];

var currFiles1=f.AtualAtividade.value.split('; ');
var currFiles2=f.AtualAtor.value.split('; ');
var currFiles3=f.AtualRecurso.value.split('; ');
var currFiles4=f.AtualEntrada.value.split('; ');
var currFiles5=f.AtualSaida.value.split('; ');

if (document.forms[0].dlgAtividade.value ==''){
var txt1 = document.createTextNode('-');
}else{
var txt1 = document.createTextNode(document.forms[0].dlgAtividade.value);
}

if (document.forms[0].dlgAtor.value == ''){
var txt2 = document.createTextNode('-');
}else{
var txt2 = document.createTextNode(document.forms[0].dlgAtor.value);
}

if (document.forms[0].dlgRecurso.value == ''){
var txt3 = document.createTextNode('-');
}else{
var txt3 = document.createTextNode(document.forms[0].dlgRecurso.value);
}

if (document.forms[0].dlgEntradas.value == ''){
var txt4 = document.createTextNode('-');
}else{
var txt4 = document.createTextNode(document.forms[0].dlgEntradas.value);
}

if (document.forms[0].dlgSaidas.value == ''){
var txt5 = document.createTextNode('-');
}else{
var txt5 = document.createTextNode(document.forms[0].dlgSaidas.value);
}

//var txt = document.createTextNode(title);
var tr = document.createElement('tr');
var td0 = document.createElement('td');
var td1 = document.createElement('td');
var td2 = document.createElement('td');
var td3 = document.createElement('td');
var td4 = document.createElement('td');
var td5 = document.createElement('td');
var td6 = document.createElement('td');
var img = document.createElement('img');
var img2 = document.createElement('img');
var rem = document.createElement('a');
var edi = document.createElement('a');

//Atualiza linha
currFiles1[idx]=f.dlgAtividade.value;
currFiles2[idx]=f.dlgAtor.value;
currFiles3[idx]=f.dlgRecurso.value;
currFiles4[idx]=f.dlgEntradas.value;
currFiles5[idx]=f.dlgSaidas.value;

f.AtualAtividade.value = currFiles1.join('; ');
f.AtualAtor.value = currFiles2.join('; ');
f.AtualRecurso.value = currFiles3.join('; ');
f.AtualEntrada.value = currFiles4.join('; ');
f.AtualSaida.value = currFiles5.join('; ');

//remove tr container
tr=document.getElementById("atividades-atual-"+idx);

var count = tr.childNodes.length;
for (var i=0;i<count;i++){
var oChild=tr.children(0);
tr.removeChild(oChild);
}

img.setAttribute('src', servidor+caminho+'.nsf/remove.gif');
img.setAttribute('border', '0');

img2.setAttribute('src', servidor+caminho+'.nsf/edit.gif');
img2.setAttribute('border', '0');

rem.setAttribute("href","JavaScript:void(doRemoveAtividadeAtual("+idx+"));");
rem.appendChild(img);

edi.setAttribute("href","JavaScript:void(doEditaAtividadeAtual("+idx+"));");
edi.appendChild(img2);
td0.appendChild(rem);
td1.appendChild(edi);

td2.appendChild(txt1);
td3.appendChild(txt2);
td4.appendChild(txt3);
td5.appendChild(txt4);
td6.appendChild(txt5);

tr.appendChild(td0);
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tr.appendChild(td4);
tr.appendChild(td5);
tr.appendChild(td6);

//Limpa os campos
f.dlgAtividade.value = '';
f.dlgAtor.value = '';
f.dlgRecurso.value = '';
f.dlgEntradas.value = '';
f.dlgSaidas.value = '';
f.EditaAtividadeAtual.value = ''}

Atenção:

Os campos adicionados para receberem as informações de cada coluna tem que ser campo Multi-Valor para armazenar os dados separadamente e explodir em cada linha.
Para garantir que isso ocorra adicione a formula @Trim(@ThisValue) no Input Translation de cada campo que irá compor a tabela.

Vou deixar o CSS por conta dos senhores. ;)

Imagens: