RSS Feed
Jun 19

[PagSeguro] Faça log do retorno automático

Postado em Friday, June 19, 2009 em Dia-a-dia, pagseguro, php

Você deve conhecer o PagSeguro, já venho falando dele por aqui há um tepinho. Existe uma biblioteca de retorno automático para PHP gerada pela Visie, só que o pessoal geralmente tem dúvidas sobre verificar o que o PaSeguro ou quando o PagSeguro irá mandar os dados para validação.

O código básico de implementação é este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Aqui vai seu Token
define('TOKEN','0123456789abcdef0123456789abcdef');
 
// Incluindo o arquivo da biblioteca
include('retorno.php');
 
// Função que captura os dados do retorno
function retorno_automatico ( $VendedorEmail, $TransacaoID, 
  $Referencia, $TipoFrete, $ValorFrete, $Anotacao, $DataTransacao,
  $TipoPagamento, $StatusTransacao, $CliNome, $CliEmail, 
  $CliEndereco, $CliNumero, $CliComplemento, $CliBairro, $CliCidade,
  $CliEstado, $CliCEP, $CliTelefone, $produtos, $NumItens) {
 
  // AQUI VOCÊ TEM OS DADOS RECEBIDOS DO PAGSEGURO, JÁ VERIFICADOS.
  // CONFIRA A LISTA DE PRODUTOS E O VALOR COM O QUE VOCÊ TEM NO
  // BANCO DE DADOS E, SE ESTIVER TUDO CERTO, ATUALIZE O STATUS
  // DO PEDIDO.
 
}
 
// A partir daqui, é só HTML:

Como você pode ver, você escreve uma função básica onde você fará tudo o que você precisa fazer no seu banco de dados, como atualizar a quantidade de produtos de uma loja, cancelar ou efetuar um pedido.

Normalmente o pessoal pergunta, como ver o que o PagSeguro está mandando, como fazer para escrever um código não vendo o que está vindo. Bem, você não vai ver nunca o que está acontecendo na tela do seu navegador. Para você ver o que está acontecendo, escreva em um arquivo de texto os dados que estão chegando no seu POST e também se ele foi validado ou não.

Vamos definir uma função de Log bem simples.

1
2
3
4
5
function pgs_log($msg)
{
  $msg = date('[d/m/Y H:i:s] ') . $msg . "\n\n---\n";
  file_put_contents ('pagseguro.log', $msg);
}

Agora, vamos implementar o nosso log.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function pgs_log($msg)
{
  $msg = date('[d/m/Y H:i:s] ') . $msg . "\n\n---\n";
  file_put_contents ('pagseguro.log', $msg);
}
if ($_POST) {
  pgs_log('Recebendo dados via POST, estes dados serão verificados pelo PagSeguro: '.print_r($_POST, true));
}
// Aqui vai seu Token
define('TOKEN','0123456789abcdef0123456789abcdef');
 
// Incluindo o arquivo da biblioteca
include('retorno.php');
 
// Função que captura os dados do retorno
function retorno_automatico ( $VendedorEmail, $TransacaoID, 
  $Referencia, $TipoFrete, $ValorFrete, $Anotacao, $DataTransacao,
  $TipoPagamento, $StatusTransacao, $CliNome, $CliEmail, 
  $CliEndereco, $CliNumero, $CliComplemento, $CliBairro, $CliCidade,
  $CliEstado, $CliCEP, $CliTelefone, $produtos, $NumItens)
{
    $data = func_get_args();
    pgs_log('Dados verificados com sucesso! Dados formatados no retorno: '.print_r($data, true));
 
    // AQUI VOCÊ TEM OS DADOS RECEBIDOS DO PAGSEGURO, JÁ VERIFICADOS.
    // CONFIRA A LISTA DE PRODUTOS E O VALOR COM O QUE VOCÊ TEM NO
    // BANCO DE DADOS E, SE ESTIVER TUDO CERTO, ATUALIZE O STATUS
    // DO PEDIDO.
}

E voilà! Você verá no seu arquivo pagseguro.log o seguinte resultado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
[19/06/2009 16:53:08] Recebendo dados via POST, estes dados serão verificados pelo PagSeguro: Array
(
    [TransacaoID] => e9b6ef2f4b0f873e6f2a5831d39d803b
    [TipoFrete] => FR
    [ValorFrete] => 0,00
    [Anotacao] => Pagamento gerado pelo ambiente de testes
    [DataTransacao] => 19/06/2009 
    [VendedorEmail] => email_cobranca@teste.gov.br
    [Referencia] => AFB-580
    [CliNome] => nome
    [CliEmail] => email@cliente.com.br
    [CliEndereco] => Rua dos Bobos
    [CliNumero] => 0
    [CliComplemento] => 
    [CliBairro] => Paytown
    [CliCidade] => Payland
    [CliEstado] => AC
    [CliCEP] => 01234567
    [CliTelefone] => 99 55555555
    [NumItens] => 4
    [ProdID_1] => A27
    [ProdDescricao_1] => Mapa da cidade
    [ProdQuantidade_1] => 1
    [ProdFrete_1] => 0,00
    [ProdExtras_1] => 0,00
    [ProdValor_1] => 27,90
    [ProdID_2] => B720
    [ProdDescricao_2] => Bala Freegells
    [ProdQuantidade_2] => 12
    [ProdFrete_2] => 0,00
    [ProdExtras_2] => 0,00
    [ProdValor_2] => 0,80
    [ProdID_3] => A90
    [ProdDescricao_3] => Caderno decorado
    [ProdQuantidade_3] => 5
    [ProdFrete_3] => 0,00
    [ProdExtras_3] => 0,00
    [ProdValor_3] => 16,30
    [ProdID_4] => C230
    [ProdDescricao_4] => Tomada simples
    [ProdQuantidade_4] => 16
    [ProdFrete_4] => 0,00
    [ProdExtras_4] => 0,00
    [ProdValor_4] => 1,70
    [TipoPagamento] => Pagamento
    [StatusTransacao] => Completo
)
 
 
---
[19/06/2009 16:53:08] Dados verificados com sucesso! Dados formatados no retorno: Array
(
    [VendedorEmail] => email_cobranca@teste.gov.br
    [TransacaoID] => e9b6ef2f4b0f873e6f2a5831d39d803b
    [Referencia] => AFB-580
    [TipoFrete] => FR
    [ValorFrete] => 0.00
    [Anotacao] => Pagamento gerado pelo ambiente de testes
    [DataTransacao] => 19/06/2009 
    [TipoPagamento] => Pagamento
    [StatusTransacao] => Completo
    [CliNome] => nome
    [CliEmail] => email@cliente.com.br
    [CliEndereco] => Rua dos Bobos
    [CliNumero] => 0
    [CliComplemento] => 
    [CliBairro] => Paytown
    [CliCidade] => Payland
    [CliEstado] => AC
    [CliCEP] => 01234567
    [CliTelefone] => 99 55555555
    [produtos] => Array
        (
            [0] => Array
                (
                    [ProdID] => A27
                    [ProdDescricao] => Mapa da cidade
                    [ProdValor] => 27.9
                    [ProdQuantidade] => 1
                    [ProdFrete] => 0
                    [ProdExtras] => 0
                )
 
            [1] => Array
                (
                    [ProdID] => B720
                    [ProdDescricao] => Bala Freegells
                    [ProdValor] => 0.8
                    [ProdQuantidade] => 12
                    [ProdFrete] => 0
                    [ProdExtras] => 0
                )
 
            [2] => Array
                (
                    [ProdID] => A90
                    [ProdDescricao] => Caderno decorado
                    [ProdValor] => 16.3
                    [ProdQuantidade] => 5
                    [ProdFrete] => 0
                    [ProdExtras] => 0
                )
 
            [3] => Array
                (
                    [ProdID] => C230
                    [ProdDescricao] => Tomada simples
                    [ProdValor] => 1.7
                    [ProdQuantidade] => 16
                    [ProdFrete] => 0
                    [ProdExtras] => 0
                )
 
        )
 
    [NumItens] => 4
)
 
 
---

E com isso você já consegue desenvolver sua aplicação normalmente. Fora que fica mais prático de entender o que está acontecendo no seu servidor. :D

May 25

Função clone da jQuery e atributo name para IE

Postado em Monday, May 25, 2009 em Internet Explorer, Windows, cases, html, jQuery, javascript, plugin, xHTML

Aqui na ACSP, onde estamos desenvolvendo um mega-hiper-ultra-plus-and-is-the-maximun-software-of-the-solar-system sistema ultra-secreto nos deparamos com um problema cabuloso no Browser azul até a versão 7. A idéia é a seguinte: quando um usuário clicar em um determinado botão “adicionar uma cópia” do formulário ele deve copiar o fieldset anterior e colá-lo abaixo do mesmo. Obviamente, devemos alterar o name dos campos para conseguir tratá-los no PHP no server-side. Atente a este ponto, todas as ações aplicadas aos campos devem continuar funcionando, ou seja, se você aplicou um “click”, “change” “blur” ou seja lá o que for, deve continuar funcionando normalmente. Ah sim, vamos utilizar a biblioteca “coisinha bonitinha do papai” jQuery[bb].

JavaScript - Mais uma dica para você

JavaScript - Mais uma dica para você

A melhor forma de resolver esse problema é pensar antes de escrever o código. Mas algumas vezes não conseguimos prever coisas que nem a Microsoft[bb] explica. Então o ideal é fazer uma função que aplique as ações ao formulário assim, podemos usar um template para fazer o clone.

1
2
3
4
5
6
7
8
9
10
11
12
13
$(function(){
  aplica_acoes();
  $('button.duplicar').click('duplica_fieldset');
});
 
function duplica_fieldset() {
  $('fieldset:last').after ('------------ cole aqui o template -----------');
  aplica_acoes();
}
 
function aplica_acoes() {
  $('.campo').click(function (){alert("Hey! Ho!");});
}

O problema disso é ao alterarmos qualquer campo teriamos que alterar o javascript para que o template fique exatamente igual. Outro problema é que ao chamarmos a função aplica_funcoes ele adicionará duas vezes a ação click no campo.

Mas vamos por partes, primeiro o problema do click duplicado. Podemos resolver isso sem problema algum. Basta usar o unbind e bind.

11
12
13
14
15
16
17
18
19
function aplica_funcoes() {
  $('.campo')
    .unbind('click', heyho)
    .bind('click', heyho);
}
 
function heyho() {
  alert("Hey! Ho!");
}

Legal, o que isso faz é remover os eventos click e recoloca-os. Muito bem, também poderiamos usar o live, adicionado na jQuery desde a versão 1.3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(function(){
  aplica_acoes();
  $('button.duplicar').click('duplica_fieldset');
});
 
function duplica_fieldset() {
  $('fieldset:last').after ('------------ cole aqui o template -----------');
}
 
function aplica_funcoes() {
  $('.campo').live('click', heyho);
}
 
function heyho() {
  alert("Hey! Ho!");
}

Assim, todos os campos que forem criados após essa chamada do live, todas as vezes que um elemento com a classe .campo for criado ele já nascerá com a ação click.

Muy biem, compañeros! Vamos ao próximo problema. O template que não deve ficar aqui no javascript e sim clonar o dito cujo. Para isso vamos usar o método clone da jQuery, assim ele copiará o código escrito no próprio html, assim não precisamos dar manutenção no código duas vezes. Veja como é simples usar o clone.

6
7
8
9
function duplica_fieldset() {
  var fls = $('fieldset:last').clone();
  $('fieldset:last').after (fls);
}

Ok, com isso já podemos copiar um fieldset e colar logo abaixo do outro fieldset. Uma coisa muito interessante é que podemos passar o parametro true dentro do clone, assim ele já copia os eventos, fazendo essa alteração nosso script ficará mais ou menos assim (perceba como diminui a quantidade de código).

1
2
3
4
5
6
7
8
9
10
11
12
13
$(function(){
  aplica_acoes();
  $('button.duplicar').click('duplica_fieldset');
});
 
function duplica_fieldset() {
  var fls = $('fieldset:last').clone(true);
  $('fieldset:last').after (fls);
}
 
function aplica_funcoes() {
  $('.campo').click(function(){alert("Hey! Ho!");});
}

E o name?

Agora, vamos ao problema maior, vamos alterar o name para podermos trabalhar no server-side. Tomemos o seguinte template de html:

1
2
3
4
5
<fieldset>
   <label for="nome_123">Nome <input type="text" name="nome_123" id="nome_123" /></label>
   <label for="campo_123">Nome <input type="text" name="campo_123" id="campo_123" class="campo" /></label>
</fieldset>
<button class="duplicar">Nova Assinatura</button>

Perceba que usamos o padrão “123″ em todos os campos, seria o nosso ID temporário para podermos tratar sem problemas no server-side. Então, para alterar o campo deveriamos criar um número aleatório único e alterar via comando attr da jQuery. Algo como isto:

6
7
8
9
10
11
12
13
14
15
16
function duplica_fieldset() {
  var num = ''+(new Date().getTime())+(parseInt(Math.random()*100));
  var fls = $('fieldset:last').clone(true);
  $('[name]', fls).each(function(){
    var lastName = this.name;
    var base = lastName.split('_')[0];
    var newName = base+'_'+num;
    this.name=newName;
  });
  $('fieldset:last').after (fls);
}

Veja, para criar um número aleatório único usei o getTime do objeto Date, assim pegamos os microsegundos que aconteceram naquele momento, um momento único que não se repetirá. E então adicionamos a um número aleatório qualquer. O Math.random() gera um número aleatório entre zero e um, então é necessário multiplicá-lo com um valor multiplo de dez para termos o inteiro desejado. Então usamos o parseInt para converter esse float maluco para inteiro e obtermos apenas o desejado. Perceba que no inicio dessa linha adicionamos uma string vazia, isso para que os dois valores não sejam somados e sim concatenados.

Veja, que logo após chamamos todos os campos que tenham o campo name, isso apenas no nosso fls, clonado anteriormente. Podemos fazer isso com todos os atributos (id, for, class, etc). Aconselho a fazer um each só para não deixar sua aplicação lenta.

Tá, mas qual é o problema com o Internet Explorer?

Tudo bem? Tudo funcionando perfeitamente? Tudo tranquilo? Sim, com apenas um problema. No Internet Explorer. Até a versão sete esse problema existia, mas na versão oito o problema foi corrigido. O problema é o seguinte: EM RADIO BUTTONS E CHECKBOXES O NAME NÃO PODE SER ALTERADO DINAMICAMENTE VIA JAVSCRIPT! Aí já viu, né? Eles (os desenvolvedores do Internet Explorer) devem ter feito isso por que se alterar o name destes tipos de campos acabará com o grupo já instituido.

Então, o nosso código funciona perfeitamente em browsers. Então aquela história de escrever o template no JavaScript[bb] é a forma de resolver. Sim, é uma forma, o problema é que algumas vezes só nos deparamos com problemas quando a tela já está cheia de detalhes. Então o que temos que fazer é tentar resolver de outra forma, mais simples.

Vendo o código-fonte da jQuery, percebi que a função clone já faz um hack para IE, devido à forma como o dito cujo faz cópia com o comando cloneNode. Usando o método cloneNode do DOM, o Browser da Microsoft faz um clone dos eventos, então, se você remover o evento de um, ele remove o evento de todos ao mesmo tempo. Veja o trecho onde o clone é definido na jQuery.

301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
	clone: function( events ) {
		// Do the clone
		var ret = this.map(function(){
			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
				// IE copies events bound via attachEvent when
				// using cloneNode. Calling detachEvent on the
				// clone will also remove the events from the orignal
				// In order to get around this, we use innerHTML.
				// Unfortunately, this means some modifications to
				// attributes in IE that are actually only stored
				// as properties will not be copied (such as the
				// the name attribute on an input).
				var html = this.outerHTML;
				if ( !html ) {
					var div = this.ownerDocument.createElement("div");
					div.appendChild( this.cloneNode(true) );
					html = div.innerHTML;
				}
 
				return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
			} else
				return this.cloneNode(true);
		});
		// Copy the events from the original to the clone
		if ( events === true ) {
			var orig = this.find("*").andSelf(), i = 0;
 
			ret.find("*").andSelf().each(function(){
				if ( this.nodeName !== orig[i].nodeName )
					return;
 
				var events = jQuery.data( orig[i], "events" );
 
				for ( var type in events ) {
					for ( var handler in events[ type ] ) {
						jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
					}
				}
 
				i++;
			});
		}
 
		// Return the cloned set
		return ret;
          },

Bom, já que ele já hackeia, decidi fazer um plugin que seja igual ao clone só que interferindo nesse hack. Eis o código final.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * Extensão para jQuery clonar um elemento para corrigir o BUG do IE
 */
 
$.fn.clonar = function( events , manipulateForIE) {
// Do the clone
var ret = this.map(function(){
  if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
    var html = this.outerHTML;
    if ( !html ) {
      var div = this.ownerDocument.createElement("div");
      div.appendChild( this.cloneNode(true) );
      html = div.innerHTML;
    }
    // Isto foi adicionado à função de clonar
    if (manipulateForIE != undefined && $.isFunction(manipulateForIE))
      html=manipulateForIE(html)
 
    return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
  } else
    return this.cloneNode(true);
});
// Copy the events from the original to the clone
if ( events === true ) {
  var orig = this.find("*").andSelf(), i = 0;
  ret.find("*").andSelf().each(function(){
    if ( this.nodeName !== orig[i].nodeName ) return;
    var events = jQuery.data( orig[i], "events" );
    for ( var type in events )
      for ( var handler in events[ type ] )
        jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
    i++;
  });
}
// Return the cloned set
return ret;
}

Daí, basta passar uma função que interfirirá no meio do clone da jQuery clonar. O código deve ficar assim:

8
9
10
var fls=$('fieldset.'+classe+':last').clonar(true, function(html){
  return html.replace(/name="?(\w+)_\d+/ig, 'name="$1_'+r+'" ');
});

E este é o nosso código final, já com o plugin e tudo o que tem direito:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
$(function(){
  aplica_acoes();
  $('button.duplicar').click('duplica_fieldset');
});
 
function duplica_fieldset() {
  var fls = $('fieldset.'+classe+':last').clonar(true, function(html){
    return html.replace(/name="?(\w+)_\d+/ig, 'name="$1_'+r+'" ');
  });
  $('fieldset:last').after (fls);
}
 
function aplica_funcoes() {
  $('.campo').click(function(){alert("Hey! Ho!");});
}
 
/**
 * Extensão para jQuery clonar um elemento para corrigir o BUG do IE
 */
 
$.fn.clonar = function( events , manipulateForIE) {
// Do the clone
var ret = this.map(function(){
  if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
    var html = this.outerHTML;
    if ( !html ) {
      var div = this.ownerDocument.createElement("div");
      div.appendChild( this.cloneNode(true) );
      html = div.innerHTML;
    }
    // Isto foi adicionado à função de clonar
    if (manipulateForIE != undefined && $.isFunction(manipulateForIE))
      html=manipulateForIE(html)
 
    return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
  } else
    return this.cloneNode(true);
});
// Copy the events from the original to the clone
if ( events === true ) {
  var orig = this.find("*").andSelf(), i = 0;
  ret.find("*").andSelf().each(function(){
    if ( this.nodeName !== orig[i].nodeName ) return;
    var events = jQuery.data( orig[i], "events" );
    for ( var type in events )
      for ( var handler in events[ type ] )
        jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
    i++;
  });
}
// Return the cloned set
return ret;
}

Uma vez o professor me disse: “Não tenha medo do código.” E isso eu passo para todo mundo que eu converso. Como você pode ver, o código da jQuery é bem escrito e bem documentado, pare e leia alguma coisa para você aprender cada vez mais. Ah, e caso você precise de um lugar de consulta para o dia-a-dia você pode usar o JavaScript Cheat Sheet.

JavaScript Cheat Sheet

JavaScript Cheat Sheet

Apr 25

Lista CSS Hacks

Postado em Saturday, April 25, 2009 em Dia-a-dia

Calma! Eu sei que o certo é não usar CSS Hacks nem comentários condicionais, mas antes de me atirarem pedras eu tenho que me defender. Algumas vezes a pressa/pressão do cliente nos obriga a enfiar um hack ou outro, então temos que inserir mesmo assim. Hoje, quando termino um projeto meus arquivos CSS tem dois ou três hacks que acabo resolvendo após a entrega do material. Mas na hora do aperto, o cliente está contando os minutos, uma boa lista de CSS hacks pode salvar sua pele. Por isso essa lista de hacks para css que encontrei no AJAXIAN, originado pelo Paul Irish.

A lista definitiva pra resolver seus problemas mais comuns com CSS

A lista definitiva pra resolver seus problemas mais comuns com CSS

O Paul ainda fez uma página de teste e você ainda pode ver um screenshoot de cada browser com os resultados.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/***** Selector Hacks ******/
 
/* IE 6 e inferiores */
* html #uno { color: red }
 
/* IE 7 e superiores */
*:first-child+html #dos { color: red } 
 
/* IE 7 e browsers modernos */
html>body #tres { color: red }
 
/* Browsers modernos (exceto IE 7) */
html>/**/body #cuatro { color: red }
 
/* Opera 9.27 e inferiores */
html:first-child #cinco { color: red }
 
/* Safari */
html[xmlns*=""] body:last-child #seis { color: red }
 
/*safari 3+, chrome 1+, opera9+, ff 3.5+ */
body:nth-of-type(1) #siete { color: red }
 
/* safari 3+, chrome 1+, opera9+, ff 3.5+ */
body:first-of-type #ocho {  color: red }
 
/* saf3, chrome1+ */
@media screen and (-webkit-min-device-pixel-ratio:0) {
 #diez  { background: #FFDECE; border: 2px solid #ff0000  }
}
 
/***** Hacks para Atributos ******/
 
/* ie6 e inferiores */
#once { _color:blue }
 
/* ie7 e inferiores */
#doce { *color: blue } /* ou #color:blue */
 
/* 'Browsers Modernos' incluem IE8, se concorda ou não .. :) */

O cara é tão bom nesse negócio de distinguir os browsersque criou uma lista de como reconhecer seu browser via javascript (para você escrever um código para determinado browser por exemplo). Mas, se você usa jQuery em seus projetos, ele já tem isso tá?!

Apr 20

PHP+PagSeguro = Loja virtual de downloads

Postado em Monday, April 20, 2009 em Programação, Tecnologia, Trabalho, Tutorial, jQuery, javascript, pagseguro, php, sql

Voltamos a um assunto que interessa muitas pessoas: ganhar dinheiro. Talvez você não tenha nada físico para vender, mas você provavelmente tem talento (não, chocolate não) e sabe escrever um bom livro ou mesmo fazer ótimas fotografias[bb]. Você pode não saber, mas dá pra ganhar dinheiro com esse seu talento. Por que você não começa a vender arquivos para download? Sim! Por que não?! Comece a explorar o seu lado criativo e faça de seus dons uma forma de fazer lucros.

Crie uma loja virtual. Você pode começar com uma loja poderosa como o Magento ou mesmo uma coisa mais simples como OsCommerce, Joomla o mesmo WordPress. Mas, se você é programador como eu e prefere escrever seu próprio código ou mesmo entender como o sistema de sua loja (ou loja de seus clientes) funcionará, farei uma série de artigos para demonstrar como é simples criar uma loja virtual[bb] cujos produtos não são nada além de links para download.

Loja virtual com PagSeguro? Agora ficou fácil!

Loja virtual com PagSeguro? Agora ficou fácil!

Para você conseguir acompanhar este “curso” você deve entender um pouco dos seguintes assuntos:

  • PagSeguro: Vamos usar esta ferramenta de pagamento online para que nossos clientes se sintam seguros ao comprar em sua loja, então você já pode criar sua conta para podermos fazer a nossa loja virtual
  • PHP: Não precisa ser um expert, mas saber conceitos básicos de banco de dados e orientação a objetos já dão um gás
  • MySQL: Vamos trabalhar com a dobradinha mais conhecida da Web. Não usaremos o MySQL ao extremo mas iremos fazer um join ou outro
  • Ânimo: muitas vezes você irá errar. Podem ser erros básicos como não colocar um ponto-e-virgula/ no seu script, então não desanime e continue em frente

Ok, com os requisitos em mãos vamos por a mão na massa. A começar pela estruturação do nosso banco de dados.

O banco de dados

Vamos precisar basicamente de duas tabelas para organizar os produtos: categorias, produtos. Elas são descritas pelas seguintes queries:

CREATE TABLE `categoria` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `slug` VARCHAR(45) NOT NULL,
  `titulo` VARCHAR(100) NOT NULL,
  PRIMARY KEY (`id`)
);
 
CREATE TABLE `produto` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `categoria_id` INTEGER UNSIGNED NOT NULL,
  `slug` VARCHAR(45) NOT NULL,
  `titulo` VARCHAR(100) NOT NULL,
  `descricao` TEXT NOT NULL,
  `valor` FLOAT NOT NULL,
  `url` VARCHAR(32) NOT NULL,
  `imagem` CHAR(32) NOT NULL,
  PRIMARY KEY (`id`)
);

Usaremos os campos “slug” tanto de categoria quanto de produto para a url na loja virtual ficar mais fácil de enteder, é o que chamamos de URLs amigáveis. Repare também que temos “categoria_id” na tabela de produto, é nela que vamos basear a nossa organização, um produto deve ter uma categoria e uma categoria pode ter diversos produtos. Os campos de url e imagem da tabela de produtos conterá o endereço do arquivo físico (o arquivo que o usuário fará o download) e a imagem que aparecerá na loja virtual respectivamente. Eles receberão uma criptografia para a segurança de sua loja, usarei md5 como criptografia.

Muito bem, não vamos nos prender a criação de usuários no nosso sistema. Por quê?! Porque você realmete não precisa disso na sua loja. Se um usuário compra de sua loja ele terá os seus dados no PagSeguro, afinal, ele vai pagar por lá não é mesmo? Então para quê ter dados repetidos no seu sistema? Não vamos fazer também um sistema de login, tenho em mente que você é um programador experto e já sabe fazer isso de olhos fechados. Vamos colocar um sistema de login no nosso sistema sim, claro, mas com um usuário único e uma senha única. Isso para não perdermos o foco da loja virtual.

A outra tabela que iremos precisar é a tabela de compra, nela teremos a compra de cada usuário, assim poderemos reenviar um e-mail ao usuário com os links para onde ele pode efetuar o download dos produtos que ele comprou. Esta tabela também serve para sabermos que o produto foi enviado ao cliente, digo, a data de envio do e-mail. Essa tabela é regida pelo seguinte SQL.

CREATE TABLE `compra` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `email` VARCHAR(100),
  `produtos` TEXT NOT NULL,
  `transacao_id` VARCHAR(45),
  `status` VARCHAR(45) NOT NULL,
  `data_confirmacao` DATETIME NOT NULL,
  PRIMARY KEY (`id`)
);

Veja que produtos é um campo do tipo do tipo TEXT, nele vamos gravar os ids contidos na tabela produto, separados por virgula. Os campos transacao_id, status e data_confirmacao serão completados ao receber o retorno do PagSeguro.

Com isso já temos as tabelas básicas necessárias para a criação de nossa loja virtual. Fique ligado para a próxima parte dessa série onde vamos montar uma loja virtual voltada para downloads.

Apr 20

Pink Floyd Cover via @zamana

Postado em Monday, April 20, 2009 em Dia-a-dia

É, esta semana a animação rolou por conta do meu amigo Rafael @rzamana, acontece que o irmão dele veio passar alguns dias aqui em SP e como não poderia deixar de ser, a animação não pôde faltar. Ele procurou um bom lugar para ir e acabou encontrando um ótimo bar onde teria show da banda Pink Floyd[bb] Cover.

undefined

Algumas batidas de foto, umas doses de José Cuervo[bb] e a noite já estava no ponto. A noite foi regada ao som de uma banda que faz muito bem o seu trabalho. O som dos caras é muito arecido ao som dos pessoal da banda inglesa. Uma noite tranquila e muita agitação. Fica aqui também registrada a entrada de mais um membro na equipe PV: Luiza que está ajudando Alice com a programação front end.

Apr 14

WordPress fora da pasta raíz

Postado em Tuesday, April 14, 2009 em Programação, Tecnologia, Tutorial, php, video, video-tutorial, wordpress

Já teve vontade de xingar o WordPress[bb] por criar aquele monte de arquivos na home do seu site, dificultando assim a organização dos seus arquivos dentro do servidor. Bom, neste vídeo eu explico como fazer para colocar o WordPress do seu blog[bb] para rodar dentro de uma pasta e não na raíz do projeto[bb]. Assim você ter uma organização melhor dos seus arquivos.

Apr 9

WordPress: Adicionando um arquivo externo após o primeiro Post

Postado em Thursday, April 9, 2009 em Dia-a-dia

Como fazer para meu blog mostrar um video do CampusOnline ou qualquer outra coisa apenas após o primeiro Post do meu blog?

screenshot

Muito simples, basta adicionar uma variável que contará os seus posts mostrados (no nosso caso $contador) dentro da sua estrutura the loop. Se o $contator for igual ou menor que 1 mostre o que você deseja. Veja o código:

1
2
3
4
5
6
7
<?php $contador=0; if (have_posts()) : while (have_posts()) : the_post(); $contador++; ?>
  // seu loop
  <?php if ($contador <= 1) { include (STYLESHEETPATH . '/seu-arquivo.php'); } ?>
<?php endwhile; ?>
<?php else : ?>
 
<?php endif; ?>

Simples, né? Este é um artigo inspirado no “Adding a external file after the first post” do “WPCult“.

Apr 7

Rã descoberta no Peru tem cerca de 1 centímetro

Postado em Tuesday, April 7, 2009 em Dia-a-dia

Momento animal, estava vendo o meu RSS e acabei deparando com esta reportagem do Terra que achei muito interessante para postar aqui no meu Blog. Chega de rodeios, essa é a matéria na íntegra:

A espécie, que mede cerca de 1 cm, foi batizada de Noblella pygmaea

A espécie, que mede cerca de 1 cm, foi batizada de Noblella pygmaea

Uma nova espécie de rã foi encontrada no Parque Nacional Manu, perto de Cuzco, no sudeste do Peru. A descoberta foi anunciada pelo Instituto de Pesquisa e Museu de História Natural de Dresden. As informações são da agência AFP.

A espécie foi batizada de Noblella pygmaea e é a menor encontrada nos Andes, com cerca de 1 cm de comprimento. A rã é um dos menores vertebrados já encontrados acima de 3 mil metros de altitude e vive em ambientes úmidos, mas terrestres.

Edgar Lehr do Museu de História Natural de Dresden, na Alemanha, e Alessandro Catenazzi da Universidade da Califórnia, em Berkeley, afirmam que a Noblella pygmaea é apenas um dos muitos anfíbios ainda desconhecidos que vivem em zona montanhosa dos Andes.

Apr 4

Semana animada \o/

Postado em Saturday, April 4, 2009 em Dia-a-dia, Diversão

Não sou muito de sair de casa, mas esta semana foi uma semana em que me dediquei bastante ao lazer e à cultura. Desde teatro até festa de hip-hop. Mas, vamos por parte e vejam como esta semana foi interessante.

Semana passada (exatamente) fomos a uma peça de teatro chamada “A vida secreta de Batman e Robin“. Uma peça muito boa que conta a vida íntima do meu super-heroi favorito. Em suma o arqui-vilão “Charada” e a “mulher-gato” espalharam uma poção na caixa d’água do batman. Com isso, eles começam soltar a franga geral.

Inglessos para a peça que levei Alice no sábado passado

Inglessos para a peça que levei Alice no sábado passado

O espetáclo acontece com o batman dos anos 60, ou seja, fantasia cinza, todos os elementos são “bat-alguma-coisa”. Alguns erros como o batman cair no chão ao tentar dar um rodopio. O pessoal é muito bom com o improvisso e algumas vezes até achei que não era improvisso, mas isso não vem ao caso.

Para resolver o problema o Batman teve ajuda de suas amigas mulher maravilha e super mulher

Para resolver o problema o Batman teve ajuda de suas amigas mulher maravilha e super mulher

Logo, no meio da semana nosso amigo @rzamana e @paladino fomos à paulista comemorar o fechamento de um contrato. Fomos a um barzinho legal que fica atrás do MASP. Alguns salgadinhos e suco (parei com refrigerante) e fomos para a Starbucks. No mundo do café acabei pedindo um shake de morango. DAMMIT! Mas beleza! Estava tão bom quanto o café (@apocalypse me mataria agora). Quem quiser, pode ver a lista completa de fotos no meu álbum.

Starbucks! Café, café, café!

Starbucks! Café, café, café!

Hoje estamos saindo daqui a pouco de volta para a starbucks e indo para uma festa de hip hop. Quem estiver afim, basta dar um pulo na rua Augusta. O preço é 15 contos e mulher não paga nada até meia-noite. Fica aí a dica.

Zoeira SP 04 de abril

Zoeira SP 04 de abril

[update] HipHop FAIL. Pois é, como o @zamana contou em seu blog, eu acabei esquecendo de pegar o endereço correto do evento e acabamos indo parar em outra balada. Uma casa de shows chamada Inferno Club. Tocou rock anos 60/70. Não foi um show de hip hop como esperávamos mas foi rock e assim mesmo tá valendo.

Casa de shows Inferno Club

Casa de shows Inferno Club

O local é muito bom, @alice teve acesso privilegiado à entrada e lá dentro tem local para ela ficar sentada com umas mesinhas. A noite terminou umas quatro da manhã regado a três doses de tequilas e uma passada no Mc Donalds para recuperar as energias. Como estou de regime fiquei por conta do Chicken Crispy.

Apr 3

Campo DataTransacao no retorno do PagSeguro

Postado em Friday, April 3, 2009 em Dia-a-dia

Algumas vezes algumas pessoas me perguntam sobre o campo DataTransacao quando trabalhamos com boletos? Qual data vem nesse campo? A data em que o boleto foi emitido? A data em que o status foi alterado? Ou a data em que o POST foi enviado para você. (se quiser uma explicação sobre o que é esse tal de POST ou como funciona o PagSeguro, aconselho a ler meu artigo escrito no forum do iMasters)

No PagSeguro, o Boleto você pode gerar boletos para seus clientes de forma segura, mas atente para a data de compensação desse boleto. Nem você nem seu cliente querem erros nessas datas

No PagSeguro, o Boleto você pode gerar boletos para seus clientes de forma segura, mas atente para a data de compensação desse boleto. Nem você nem seu cliente querem erros nessas datas

Claro que isso é uma preocupação muito grande para quem trabalha com créditos que dependem da data em que a pessoa efetuou o pagamento. Cinco dias corridos de acesso a partir do pagamento por exemplo.

Então fui procurar uma resposta em meu log de dados, eis que me deparo com dois casos e verifiquei a seguinte sequencia de pagamentos via boletos (os IDs das tranações foram alterados para segurança dos clientes):

//-
Thu Apr 2 21:04:17 2009

‘StatusTransacao’: ‘Aguardando Pagto’,
‘DataTransacao’: ‘02/04/2009 21:08:58‘,
‘TipoPagamento’: ‘Boleto’,
‘TransacaoID’: ‘XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXA’,

Fri Apr 3 06:27:04 2009

‘StatusTransacao’: ‘Aprovado’,
‘DataTransacao’: ‘02/04/2009 21:08:58‘,
‘TipoPagamento’: ‘Boleto’,
‘TransacaoID’: ‘XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXA’,
-//

//-
Thu Apr 2 11:04:38 2009

‘StatusTransacao’: ‘Aguardando Pagto’,
‘DataTransacao’: ‘02/04/2009 11:09:18‘,
‘TipoPagamento’: ‘Boleto’,
‘TransacaoID’: ‘XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXB’,

Fri Apr 3 06:02:47 2009

‘StatusTransacao’: ‘Aprovado’,
‘DataTransacao’: ‘02/04/2009 11:09:18‘,
‘TipoPagamento’: ‘Boleto’,
‘TransacaoID’: ‘XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXB’,
-//

Como podemos perceber, o campo “DataTransacao” não é alterado e provavelmente se refere à data em que a compra foi efetuada, logo aconselho a alterar a data do seu banco de dados com a data atual do sistema. Em mysql você pode usar NOW() (faz um “SELECT NOW()” para ver o que estou falando).

Abraços, espero que isso retire a dúvida de uma ou duas pessoas =D

SEO Powered by Platinum SEO from Techblissonline