Álbum em PHP utilizando a API do Picasa, JQuery e FancyBox

Esses dias surgiu a oportunidade de um trabalho, o cliente precisava reformular o site, melhorar o processo de publicação de conteúdo, entre outros… Ao acessar o site para dar uma olhada no tipo de conteúdo, me deparo com o link álbum, cliquei pra conferir e fui parar no picasa, no álbum do cara.

Muito empolgado com as funções de XML do PHP resolvi aproveitar a API do picasa para implementar um álbum com a cara do site do meu cliente mas com a infraestrutura do picasa 😀 .

O código é bem simples, coloquei comentários onde pudesse gerar dúvidas.

Segue:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Álbum usando a API do Picasa + JQuery + FancyBox</title>
    <style type="text/css" media="all">
        html, body {margin: 0px;    padding: 0px;}
        body {background: #EAEAEA; font-family: "Trebuchet MS",Verdana,Arial,sans-serif; font-size: 14px; line-height: 1.6;}
        a {outline: none; margin-right: 20px;}
        a img {border: 1px solid #CCC; padding: 2px; margin: 10px 5px 10px 0;}
    </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://fancybox.net/js/fancybox/jquery.fancybox-1.2.6.css" media="screen" />
    <script type="text/javascript" src="http://fancybox.net/js/fancybox/jquery.fancybox-1.2.6.pack.js"></script>
    <script type="text/javascript">
        $(document).ready(function() {
            $("a.zoom").fancybox();
        });
    </script>
</head>
<body>
<?php
 /* Álbum usando API do Picasa... :D v. 0.1
  *
  * Auhor: Felipe Furst
  * email: [email protected]
  */
    $picasaUser = "mobilemechanics"; // usuário do picasa
    /* ----------------- daqui só mexa se souber oq está fazendo ---------------- */
    if(!$_GET["id"]) {
        $tt = file_get_contents("http://picasaweb.google.com/data/feed/api/user/{$picasaUser}"); // busca os álbuns
        $xml = simplexml_load_string($tt);
        echo "<div id="albuns" align="center">";
        for($i = 0; $i < count($xml->{"entry"}); $i++) {
            $gphoto = $xml->{"entry"}[$i]->children("http://schemas.google.com/photos/2007"); // pega os nodos filhos do namespace http://schemas.google.com/photos/2007
            $media = $xml->{"entry"}[$i]->children("http://search.yahoo.com/mrss/"); // semelhante à linha acima
            echo "<a href="".$_SERVER["PHP_SELF"]."?id=".$gphoto->{"id"}.""><img src="".$media->{"group"}->{"thumbnail"}->attributes()->url."" alt="" /></a>";
        }
        echo "</div>";
    }
    else {
        $tt = file_get_contents("http://picasaweb.google.com/data/feed/api/user/{$picasaUser}/albumid/{$id}"); // busca as fotos de um determinado álbum passado por parâmetro
        $xml = simplexml_load_string($tt);
        echo utf8_decode($xml->{"title"})."<br>".utf8_decode($xml->{"subtitle"})."<br>";
        echo "<div id="album" align="center">";
        for($i = 0; $i < count($xml->{"entry"}); $i++) {
            $media = $xml->{"entry"}[$i]->children("http://search.yahoo.com/mrss/"); // esse cara aqui vc já conhece ...
            echo "<a class="zoom" rel="group" title="".utf8_decode($media->{"group"}->{"description"})."" href="".$media->{"group"}->{"content"}->attributes()->url.""><img src="".$media->{"group"}->{"thumbnail"}[1]->attributes()->url."" alt="" /></a>";
        }
        echo "</div>";
    }
?>
</body>

O bom disso tudo é que você organiza tuas fotos em uma aplicação específica para esta função, não consome tempo desenvolvendo, não consome espaço no servidor e mantém a identidade visual do site.

Claro, há o que melhorar, mas o básico tá aí. Até…

Links de APIs e bibliotecas utilizados:
http://code.google.com/intl/pt-BR/apis/picasaweb/overview.html
http://br.php.net/manual/en/book.simplexml.php
http://fancybox.net/
 

Sorteio no Twitter com PHP

Semana passada ganhei cinco seriais do Mind Meister Premium (um aplicativo web para construção de mapas mentais) para distribuir e dois deles resolvi distribuir no Twitter.

Questionado pelo @fefurst sobre os próximos prêmios, falei que não sabia como iria fazer o sorteio e ele, monstrinho programador que é, prontamente respondeu que "ia dar uma olhadinha na API do Twitter".

Dito e feito, na mesma manhã ele me envia a primeira versão de um script em PHP (já viu as novidades do PHP 5.3?)que utiliza a API Serch do Twitter procurando por uma mensagem específica (a da promoção, que você pode setar no script) para sortear entre os participantes…

 

Features

  1. Configuração da frase a ser buscada
  2. Pode sortear vários participantes
  3. Lista todos os tweets que estão participando
  4. Não sorteia o responsável pela promoção
  5. Não sorteia mais de uma vez um usuário
  6. Elimina RT´s duplicados
  7. Permite filtrar a data inicial e final dos tweets que participarão do sorteio

 

O código

Agora está na versão 0.3, tudo na agilidade do Furst para publicar um código bonitinho e corrigir alguns bugs. O código está como deve ser: enxuto e fácil de entender, não ousei nem adicionar mais comentários, pois está bastante legível.

 

 

<?php
/*
 * Sorteio no twitter... :D v. 0.3 RC1
 *
 * Auhor: Felipe Furst
 * email: [email protected]
 *
 */
// login de onde origina o sorteio
$login = "gserrano";
// início do perído para avaliação de RT
$data_inicio = strtotime("2009-11-13 08:00");
// fim do perído para avaliação de RT
$data_fim = strtotime("2009-11-18 12:00");
// msg q foi retwitada, atenção as vezes alguém pode retwitar uma msg e ela icar cortada, interessante colocar um código junto da msg ou cortar alguma palavras do final
$rt_string = "@gserrano";
// número de pessoas para sortear
$num_premios = 2;
// ------------------ a partir daqui não se mexe -----------------------
// ------------------ a partir daqui não se mexe -----------------------
// ------------------ a partir daqui não se mexe -----------------------
// ------------------ a partir daqui não se mexe -----------------------
$str = Array("á", "à", "â", "ã", "ä", "é", "è", "ê", "ë", "í", "ì", "î", "ï", "ó", "ò", "ô", "õ", "ö", "ú", "ù", "û", "ü");
$rep = Array("a", "a", "a", "a", "a", "e", "e", "e", "e", "i", "i", "i", "i", "o", "o", "o", "o", "o", "u", "u", "u", "u");
$rt_string = str_replace($str, $rep, strtolower($rt_string));
$search_str = "{$login}";
if(strlen($rt_string) > 0) {
	$temp = explode(" ", $rt_string);
	foreach($temp as $t) {
		$search_str.="+{$t}";
	}
}
$page=1;
$sorteio = Array();
echo "Sorteio de {$num_premios} pr&ecirc;mios.<br><br>";
echo "Twittadas:<br>";
while(true) {
	$twtr_search = "http://search.twitter.com/search.atom?q={$search_str}&rpp=100&page={$page}"; // busca todos os registros possíveis ...
	$str_xml = file_get_contents($twtr_search);
	$xml = new SimpleXMLElement($str_xml);
	$page++;
	if($page > 1500) // a api do twitter só retorna 1500 páginas
		break;
	if(count($xml->{"entry"}) > 0) {
		foreach($xml->{"entry"} as $e) {
			if(strtotime($e->{"published"}) <= $data_fim && strtotime($e->{"published"}) >= $data_inicio) { // tem que estar dentro da data do sorteio
				if(array_search(utf8_decode($e->{"author"}->{"name"}), $sorteio) === false) { // verifica se o cara retwittou mais de uma vez para não aumentar a chance de vitória
					echo date("m.d.y H:i:s", strtotime($e->{"published"})). " - ";
					echo utf8_decode($e->{"author"}->{"name"}).": ".str_replace(Array("<b>", "</b>"), "", utf8_decode($e->{"content"}))."<br>";
					if(strrpos($e->{"author"}->{"name"}, $login) === false) { // não sorteia quem proporciona o sorteio
						$sorteio[] = utf8_decode($e->{"author"}->{"name"});
					}
				}
			}
		}
	}
	else {
		break;
	}
}
if(!empty($sorteio)) {
	echo "<br><br>Sorteado(s):";
	for($i=0; $i<$num_premios; $i++) {
		if(empty($sorteio)) {
			echo "<br><br>sobraram ".($num_premios-$i)." pr&ecirc;mios.";
			break;
		}
		srand(strtotime("now"));
		$randval = rand(0, count($sorteio)-1);
		echo "<br>O vencedor do pr&ecirc;mio n&uacute;mero ".($i+1)." &eacute;: {$sorteio[$randval]}";
		unset($sorteio[$randval]); // não sortei o cara mais de uma vez ...
		$sorteio = array_values($sorteio); // refaz o vetor eliminando a posição nula do maluco removido
	}
}
else {
	echo "<br><br>Não houve twittadas para o sorteio.";
}

 

 

Testei ele aqui e está funcionando perfeitamente. Com essa base dá para implenetar mais coisas, como um reply automático para os vencedores, adicionar periodicamente os concorrentes em um BD para gerar uma "lista" de quem está participando da promoção (caso ela dure vários dias, por exemplo)… criatividade, programadores deste mundo!

 

A base está aí, valeu @fefurst!

Formatação de datas – Java

Ontem eu estava apanhando para fazer formatação de data no Velocity (leia o que é Velocity?) para um template e antes de implementar uma POG com vários elseif´s, pedi uma ajuda para o Chris para saber se já existia alguma classe ou função disponível para formatação de datas em texto (em número já estava funcionando).

Danger!

Antecipo que qualquer coisa relacionada a Java ainda é uma novidade para mim, escrevi este post baseado na documentação da Sun (de uma classe) mas mesmo assim caso tenha alguma bobagem no conteúdo comentem, a internet está aí para possibilidades de correção e melhoria do conteúdo! 😉

O Chris me enviou um ótimo link de referência sobre a classe SimpleDateFormat do Java (me corrijam se estiver errado), que como o nome diz é para formatação de datas.

Não acho necessário a tradução da tabela, o funcionamento é simples: ao chamar a função para formatar data você segue os padrões indicado pela primeira coluna, que irá retornar o elemento indicado pela segunda coluna.

 

Letter Date or Time Component Examples
G Era designator AD
y Year 1996; 96
M Month in year July; Jul; 07
w Week in year 27
W Week in month 2
D Day in year 189
d Day in month 10
F Day of week in month 2
E Day in week Tuesday; Tue
a Am/pm marker PM
H Hour in day (0-23) 0
k Hour in day (1-24) 24
K Hour in am/pm (0-11) 0
h Hour in am/pm (1-12) 12
m Minute in hour 30
s Second in minute 55
S Millisecond 978
z Time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone -0800

 Tabela  da classe SimpleDateFormat (site da Sun)

 

Dicas para formatação e exibição das datas

Ainda existe algumas dicas para selecionar como será exibido o resultado, por extenso, número ou texto. Segue uma explicação rápida e algumas dicas para formatar e exibir a data:

Texto

Para formatar o texto, se a letra do padrão se repetir 4 vezes ou mais, a forma completa é utilizada, caso contrário a forma abreviada é exibida (se existir).

Número

Para a formatação, o número de repetição da letra padrão (primeira coluna da tabela) indica o número mínimo de dígitos do número, as casas que "faltaram" são preenchidas com zeros.

Year (ano)

Para a formatação, 2 repetições da letra truncam o ano para 2 dígitos.

Mês

Se a letra repetir por 3 vezes ou mais é exibido como texto, caso contrário como número.

 

 

Exemplos

Acho que a formatação de data é complicada de explicar, mas com exemplos -> resultados prontos fica masi fácil, então segue uma tabelinha que utiliza os padrões SimpleDateFormat.

Date and Time Pattern Result
"yyyy.MM.dd G "at" HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ""yy" Wed, Jul 4, "01
"h:mm a" 12:08 PM
"hh "o""clock" a, zzzz" 12 o"clock PM, Pacific Daylight Time
"K:mm a, z" 0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ" 010704120856-0700

 Tabela  da classe SimpleDateFormat (site da Sun)

 

É isso, espero ter ajudado! Para mais informações sobre formatação de data no Java leia a documentação completa da classe citada neste post.

Ordenando dados JSON em javascript

Trabalho com javascript há mais de 5 anos, e nunca tive que usar o método sort() da classe Array.
Porque? Em todos projetos que participei os dados já vinham ordenados pelo backend.

Ai, essa semana apareceu uma demanda para fazer a ordenação de dados que vêm através de uma requisição assíncrona no formato JSON. Pensei em alterar o backend, mas ia ter impacto em outros lugares e não daria tempo de validar se iria quebrar em outros pontos… então, procurei uma forma de como fazer isso, e encontrei, usando o método sort(). É possível usá-lo, passando uma função como parâmetro e nela criando a lógica para ordenar por uma determinada chave (lembrando que dados JSON são uma sequencia de chaves/valores).

Parece complexo, mas não é. Por exemplo, tendo dados nesse formato:

var featureData = [{name:"chris",description:"description 1}, {name:"guilherme",description:"description 2"},{name:"bianca",descrip tion:"description 3"}];

Digamos que você queira organizar esses dados pela cahe name, em ordem alfabética. Simples:

featureData.sort(function (obj1, obj2) {
return obj1.name < obj2.name ? -1 :
(obj1.name > obj2.name ? 1 : 0);
});

Referência: http://www.highdots.com/forums/javascript/re-sorting-json-data-270187.html

Como pegar dimensões da janela e da barra de rolagem por javascript

Isso seria efetivamente fácil, se todos os browsers seguissem o padrão da ECMA… mas não é assim que funciona, e ontem um dos meninos que trabalha aqui comigo estava tentando implementar um código javascript que utiliza tanto a altura útil da tela, como a altura visível da janela (window) e a posição das scrollbars.

Papo vai, papo vem, procura na API da Prototype aqui, da jQuery ali, abre o Google acolá… e me deparo com uma página muito completa, que lista os browsers (inclusive por sistema operacional) e qual é o objeto e atributo que está disponível nele.

browser platform mode window.innerWidth
window.innerHeight
window.pageXOffset
window.pageYOffset
document.documentElement.clientWidth
document.documentElement.clientHeight
document.documentElement.scrollLeft
document.documentElement.scrollTop
document.body.clientWidth
document.body.clientHeight
document.body.scrollLeft
document.body.scrollTop
IE Win32 w. DTD undef
undef
undef
undef
ok
ok
ok
ok
doc. width
doc. height
0
0
IE Win32 w/o. DTD undef
undef
undef
undef
0
0
0
0
ok
ok
ok
ok
IE Mac all undef
undef
undef
undef
undef
undef
undef
undef
ok
ok
ok
ok
Firefox Win32/Mac w. DTD +scroller
+scroller
ok
ok
ok
ok
ok
ok
ok
doc. height.
ok
ok
Firefox Win32/Mac w/o. DTD + scroller
+scroller
ok
ok
doc.width
doc.height
0
0
ok
ok
ok
ok
Netscape Win32 w. DTD + scroller
+scroller
ok
ok
ok
ok
ok
ok
ok
doc. height.
ok
ok
Netscape Win32 w/o. DTD + scroller
+scroller
ok
ok
0
0
0
0
ok
ok
ok
ok
Opera Win32/Mac all + scroller
+scroller
ok
ok
ok
doc.height
ok
ok
ok
ok
ok
ok
Safari Mac all ok
ok
ok
ok
ok
doc.height
0
0
ok
doc.height
ok
ok

Ou seja, não existe um método que funcione para todos os browser… :(

Mas, o autor criou uma implementação cross-browser que funciona para calcular todos esses atributos (altura e largura da janela, posição da scrollbar horizontal e vertical). Fica a dica!

function f_clientWidth() {
	return f_filterResults (
		window.innerWidth ? window.innerWidth : 0,
		document.documentElement ? document.documentElement.clientWidth : 0,
		document.body ? document.body.clientWidth : 0
	);
}
function f_clientHeight() {
	return f_filterResults (
		window.innerHeight ? window.innerHeight : 0,
		document.documentElement ? document.documentElement.clientHeight : 0,
		document.body ? document.body.clientHeight : 0
	);
}
function f_scrollLeft() {
	return f_filterResults (
		window.pageXOffset ? window.pageXOffset : 0,
		document.documentElement ? document.documentElement.scrollLeft : 0,
		document.body ? document.body.scrollLeft : 0
	);
}
function f_scrollTop() {
	return f_filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		document.body ? document.body.scrollTop : 0
	);
}
function f_filterResults(n_win, n_docel, n_body) {
	var n_result = n_win ? n_win : 0;
	if (n_docel && (!n_result || (n_result > n_docel)))
		n_result = n_docel;
	return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
}

Segue o link da página, para referência: http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html