Legacy tiagomadeira.net

Archive for the ‘Sistema’ Category

Troca de Servidor e “Semantic Blog”

Sunday, October 2nd, 2005

Em primeiro lugar, quero pedir desculpa a quem entrou no meu site hoje e teve algum problema. Acontece que acabo de trocar de servidor. Depois de ver uma propaganda no Tableless.com.br, acessei o site da NerdHost e gostei dos preços e da qualidade do serviço. Por causa desses fatos e por eles estarem incentivando os padrões web (dão um mês gratuito pra quem desenvolve em tableless), fechei o contrato com eles no dia em que eu vi. :) Esse servidor usa CPanel, que eu acho bem melhor que o painel de controle da Metaweb e tem vantagens como um SSH que funciona SCP (acreditem! O da Metaweb não funcionava!), subdomínios ilimitados, PHP 5, MySql 4… Foi uma excelente troca! :D E ainda peguei o plano mais barato (limpei o servidor, consegui deixá-lo com 60mb), que custa R$ 5,67 (incrível a precisão do valor… hehehe).

Em segundo lugar: Eu, o Hélio e o Gustavo começamos a desenvolver um sistema de blog, em cima de classes, bastante parecido com o meu mas mais simples que tem como objetivo ser leve e possuir apenas o que é necessário. Ele já vai vir com um Shortstat bem modificado pra dar várias estatísticas (tipo, comentários por visitante, umas paradas assim) e com o GeSHi Highlighter. Os posts vão usar BBCodes e o blog vai ser baseado em templates. Resolvemos dar o nome “Semantic Blog”. Gostou? Deixe um comentário pra eu saber! Não gostou? Deixe um comentário também! :p Hehehe… Se você tiver qualquer sugestão de recurso interessante que ele deve ter, também fique a vontade para postar um comentário!

Mudanças no Site e Código do Blog

Sunday, September 25th, 2005

Ultimamente fiz várias alterações no site. Refiz quase que todas as páginas e deixei tudo um pouco mais leve e mais fácil para mudar depois. :D Depois de conhecer a POO, me viciei nela no final de semana e converti meu site inteiro para classes. E agora, que seu script tá um pouco melhor organizado, vou colocar aqui para quem quiser copiar, usar alguma idéia, saber como eu estou indo em POO, ver as besteiras que eu faço enquanto programo, etc. :lol: resolvi disponibilizar todo o código de meu blog aqui.

Já que meu blog tem alguns bugs (known bugs de pouca importância, como o caso de se alguém escreve CHARESPC no meio de um comentário ele deve criar um &;), peço somente que ninguém destrua-o sabendo disso. Se alguém descobrir algum bug, pode me enviar um e-mail que ficarei bastante grato. :)

Já que não passei a sessão de administração para POO não vou publicá-la aqui, mas depois de resolver alguns bugzinhos pretendo disponibilizar o código completo, inclusive com um arquivo de instalação que cria as tabelas no banco de dados, para todos poderem usar um sisteminha de blog simples e prático (só que acho que vai ser algo mais voltado a programadores, porque tem vantagens como o uso do GeSHi, e desvantagens como eu publicar todos os posts escrevendo em HTML – isso mesmo, até os & que eu escrevo são & que são & *e um loop infinito pela frente). Hmmm, aliás, quem quiser me ajudar a fazer parte desse projeto para tornar o meu blog um software livre, sinta-se livre para me mandar um e-mail também. :p

Então, uma última observação é que eu substituí todos os <code (note a ausência do > ) por tag code e todos os </code> por tag /code, porque senão minhas expressões regulares do código dariam bug (quer saber por que? Então leia os códigos!)

Funções e classes “includadas” em todos os arquivos

session_start();

// Syntax Highlight - GeSHi
if (!class_exists(GeSHi)) {
include("geshi.php");
}

// Objeto de conexão do MySql
class MySql {
var $host="servidor";
var $usuario="usuario";
var $senha="senha";
var $db="bancodedados";
var $conexao;

function conecta() {
$this->conexao=mysql_connect($this->host, $this->usuario, $this->senha);
mysql_select_db($this->db);
}

function desconecta() {
mysql_close($this->conexao);
}
}

// Classe com as funções de expressões regulares
class Regex {
function Replace($o, $d, $t, $codes=0) {
for ($i=0; $i $o[$i]=str_replace('(', '\(', $o[$i]);
$o[$i]=str_replace(')', '\)', $o[$i]);
$t=eregi_replace($o[$i], $d[$i], $t);
}
if ($codes==1) {
$t="tag /code".$t."tag code";
} else if ($codes==2) {
$t.="tag code";
} else if ($codes==3) {
$t="tag /code".$t;
}
return $t;
}

function Emoticons() {
$o[0]=":)";
$d[0]="feliz";
$o[1]=":(";
$d[1]="triste";
$o[2]=":o";
$d[2]="bocaaberta";
$o[3]=":p";
$d[3]="lingua";
$o[4]=":angry:";
$d[4]="raiva";
$o[5]=":s";
$d[5]="confuso";
$o[6]=":blink:";
$d[6]="inacreditavel";
$o[7]=";)";
$d[7]="piscando";
$o[8]=":lol:";
$d[8]="rindo";
$o[9]=":d";
$d[9]="sorriso";
$o[10]=":unsure:";
$d[10]="semgraca";

for ($i=0; $i $d[$i]="\"".$o[$i]."\"";
}

if (!ereg("tag code", $texto)) {
$this->texto=$this->Replace($o, $d, $this->texto);
} else {
preg_match_all("/<\/code>(.+)tag code/sU", $this->texto, $mat1);
for ($i=0; $i $this->texto=str_replace($mat1[1][$i], $this->Replace($o, $d, $mat1[1][$i]), $this->texto);
}
preg_match("/^(.+)tag code/sU", $this->texto, $mat2);
$texto=str_replace($mat2[1], $this->Replace($o, $d, $mat2[1]), $this->texto);
$rev=strrev($this->texto); //Tenho medo do PHP5.0.5
preg_match("/^(.+)>edoc\/ $rev=strrev($mat3[1]); //Repito... Tenho medo do PHP5.0.5
$this->texto=str_replace($rev, $this->Replace($o, $d, $rev), $this->texto); //Agora fuck PHP5.0.5!
}
}

function GeshiHighlight($codigo, $linguagem) {
$geshi=new GeSHi($codigo, $linguagem, "./geshi/");
return $geshi->parse_code();
}

function Codigos() {
preg_match_all("/tag code class=\"(.*)\">(.*)<\/code>/sU",
$this->texto,
$matches);
for ($i=0; $i $g=$this->GeshiHighlight($matches[2][$i], $matches[1][$i]);
if (eregi("MSIE", $_SERVER["HTTP_USER_AGENT"])) {
$g=ereg_replace("

", "
", $g);
}
$this->texto=str_replace($matches[0][$i],
$g,
$this->texto);
}
}

function QuebraLinha() {
$this->texto=nl2br($this->texto);
}
}

// Objeto "Artigo"
class Artigo extends Regex {
var $id;
var $data;
var $permalink;
var $titulo;
var $texto;
var $comentarios;

function Artigo($identificacao) {
$this->id=$identificacao;

$mysql=new MySql();
$mysql->conecta();

$query_post=mysql_query("SELECT data, permalink, titulo, texto FROM artigos WHERE id='{$this->id}'");
$post=mysql_fetch_row($query_post);
$this->data=date("d/m/Y", $post[0]);
$this->permalink=$post[1];
$this->titulo=$post[2];
$this->texto=$post[3];

$query_comentarios=mysql_query("SELECT count(id) FROM comentario WHERE idpost='{$this->id}'");
$comentarios=mysql_fetch_row($query_comentarios);
$this->comentarios=$comentarios[0];

$mysql->desconecta();
}

function AppendGoogleAds($ads) {
$this->texto.="\n\n".$ads;
}

function Mostra() {
echo "

permalink}\">{$this->titulo}

\n";
echo $this->texto."\n";
echo "

{$this->data} ";
echo "permalink}\" class=\"permalink\">permalink ";
echo "permalink}#comentarios\" class=\"comentarios\">";
echo "{$this->comentarios} comentário(s)

\n";
}

function MostraComentarios() {
if ($_POST["comenta"]&&(!$_SESSION["comentario"]||time()-30>$_SESSION["comentario"])) {
$_SESSION["comentario"]=time();
EscreveComentario($_POST["nome"], $_POST["email"], $_POST["texto"], $this->id);
}
$comentarios=new Comentarios($this->id);
$comentarios->Mostra();
}
}

// Objeto Artigos (serve para pegar vários artigos sem eu precisar fazer nada nas outras páginas)
class Artigos {
var $id;
var $titulo;
var $texto;
var $permalink;
var $data;
var $comentarios;

function Artigos($n=20, $start=0, $emoticons=0, $codigos=0, $mostrar=0, $comentarios=0) {
$mysql=new MySql();
$mysql->conecta();
$query=mysql_query("SELECT id FROM artigos ORDER BY data DESC, id DESC LIMIT $start,$n");
$mysql->desconecta();
for ($i=0; $array=mysql_fetch_array($query); $i++) {
$artigo=new Artigo($array["id"]);
if ($emoticons) {
$artigo->Emoticons();
}
if ($codigos) {
$artigo->Codigos();
}
if ($mostrar) {
$artigo->Mostra();
}
if ($comentarios) {
$artigo->MostraComentarios();
}
$this->id[$i]=$array["id"];
$this->titulo[$i]=$artigo->titulo;
$this->texto[$i]=$artigo->texto;
$this->permalink[$i]=$artigo->permalink;
$this->comentarios[$i]=$artigo->comentarios;
$this->data[$i]=$artigo->data;
}
}
}

// Objeto Comentário
class Comentario extends Regex {
var $id;
var $data;
var $nome;
var $email;
var $ip;
var $useragent;
var $texto;
var $numero;

function Comentario($identificacao, $numero) {
$this->id=$identificacao;
$this->numero=$numero;

$mysql=new MySql();
$mysql->conecta();

$query=mysql_query("SELECT data, nome, email, ip, useragent, texto FROM comentario WHERE id='{$this->id}'");
$comentario=mysql_fetch_row($query);

$this->data=date("d/m/Y", $comentario[0]);
$this->nome=$comentario[1];
if ($_SESSION["tiagomadeira"]) {
$this->email="
";
if ($comentario[2]) $this->email.="E-mail: ".$comentario[2]."
\n";
if ($comentario[3]) $this->ip="IP: ".$comentario[3]."
\n";
if ($comentario[4]) $this->useragent="User Agent: ".$comentario[4];
$this->useragent.="
";
} else {
$this->email="";
}
$this->texto=$comentario[5];

$mysql->desconecta();
}

function CharEspc($pos) {
if ($pos==1) {
$this->texto=preg_replace("/&([^;]+);/sU", "CHARESPC\\1/CHARESPC", $this->texto);
} else if ($pos==2) {
$this->texto=preg_replace("/CHARESPC(.+)\/CHARESPC/sU", "&\\1;", $this->texto);
}
}

function Mostra() {
echo "

id}\">\n";
echo "\t

id}\">#{$this->numero} | ";
echo "{$this->nome} ";
echo "{$this->data}{$this->email}{$this->ip}{$this->useragent}

\n";
echo "

{$this->texto}

";
echo "

\n";
}
}

// Objeto Comentários
class Comentarios {
var $idpost;
var $ids;
var $tamanho;

function Comentarios($idpost) {
$this->idpost=$idpost;

$mysql=new MySql();
$mysql->conecta();

$query=mysql_query("SELECT id FROM comentario WHERE idpost='{$this->idpost}' ORDER BY data ASC, id ASC");
for ($i=1; $array=mysql_fetch_array($query); $i++) {
$this->ids[$i]=$array["id"];
}

$this->tamanho=$i;
$mysql->desconecta();
}

function Mostra() {
echo "

Comentários

\n";
for ($i=1; $i<$this->tamanho; $i++) {
$comentario=new Comentario($this->ids[$i], $i);
$comentario->CharEspc(1);
$comentario->Emoticons();
$comentario->CharEspc(2);
$comentario->QuebraLinha();
$comentario->Mostra();
}

if ($this->tamanho <= 1) {
echo "

Nenhum comentário cadastrado.

\n";
}

FormularioComentario($this->idpost);
}
}

// Função para descobrir IP do visitante
function PegaIP() {
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "desconhecido")) {
$ip=getenv("HTTP_CLIENT_IP");
} else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "desconhecido")) {
$ip=getenv("HTTP_X_FORWARDED_FOR");
} else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "desconhecido")) {
$ip=getenv("REMOTE_ADDR");
} else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "desconhecido")) {
$ip=$_SERVER['REMOTE_ADDR'];
} else {
$ip="desconhecido";
}

return($ip);
}

// Função que escreve o formulário para envio de comentário
function FormularioComentario($idpost) {
$mysql=new MySql();
$mysql->conecta();
$query=mysql_query("SELECT permalink FROM artigos WHERE id='$idpost'");
$row=mysql_fetch_row($query);
$permalink=$row[0];
$mysql->desconecta();
?>

Escreva um comentário

#comentarios" method="post">




* - Ele não aparecerá em público. Serve apenas para eu te contatar,
caso queira responder seu comentário.

}

// Função que cadastra um comentário
function EscreveComentario($nome, $email, $texto, $idpost) {
$ip=PegaIP();
$useragent=$_SERVER["HTTP_USER_AGENT"];
$nome=purifica($nome);
$email=purifica($email);
$texto=purifica($texto);
$data=time();
$mysql=new MySql();
$mysql->conecta();
mysql_query("INSERT INTO comentario (id, idpost, nome, email, texto, data, ip, useragent) VALUES
('', '$idpost', '$nome', '$email', '$texto', '$data', '$ip', '$useragent')") or die(mysql_error());
$mysql->desconecta();
$email=($email)?$email:"contato@tiagomadeira.net";
$mensagem="No post de id $idpost, o $nome ($email) comentou em ".date("d/m/Y", $time)." dizendo:";
$mensagem.="\n\n";
$mensagem.="$texto";
mail("contato@tiagomadeira.net", "[tiagomadeira.net] Novo Comentário!", "$mensagem", "From: $nome <$email>");
}

// Função que cria escreve o título das seções
function titulo($titulo) {
$tit="$titulo [tiagomadeira.net]";
echo "\n";
}

// Função para purificar os comentários depois do envio
function purifica($texto) {
$t=ereg_replace("&", "&", $texto);
$t=ereg_replace("%", "%", $t);
$t=ereg_replace("<", "<", $t);
$t=ereg_replace(">", ">", $t);
$t=ereg_replace("\[", "[", $t);
$t=ereg_replace("\]", "]", $t);
$t=ereg_replace("\"", """, $t);
return $t;
}

// Função para editar artigos
function pra_textarea($texto) {
$texto=ereg_replace("&", "&", $texto);
$texto=ereg_replace("<", "<", $texto);
$texto=ereg_replace(">", ">", $texto);
$texto=ereg_replace("\"", """, $texto);
return $texto;
}

?>

E os arquivos que usam essas funções e classes...

/artigos (ou /blog)

$artigosporpagina=10; //Artigos Por Página
$p=($_GET["pg"])?$_GET["pg"]:1; //Página Atual

$mysql=new MySql();
$mysql->conecta();
$query=mysql_query("SELECT count(id) FROM artigos");
$row=mysql_fetch_row($query);
$np=ceil($row[0]/$artigosporpagina);
$mysql->desconecta();

$paginacao="";
for ($i=1; $i<=$np; $i++) {
$paginacao.=" ?PHPSESSID=9ec34c96b02b3755051aa682d1e02001
if ($i==$p) $paginacao.=" style=\"font-weight:bold; color:#c00;\"";
$paginacao.=">$i
";
}
$paginacao="\n\n

Ir para página: $paginacao

\n\n";

echo $paginacao;

$artigos=new Artigos($artigosporpagina, ($p-1)*$artigosporpagina);
echo "

\n";

echo $paginacao;
?>

/ (ou /ultimos)

$artigos=new Artigos(5, 0, 1, 1, 1);
?>

Para finalizar... .htaccess

RewriteEngine On

#Diretórios
RewriteRule ^link/?$ http://tableless.tiagomadeira.net
RewriteRule ^post/?$ http://tableless.tiagomadeira.net/blog
RewriteRule ^script/?$ http://tableless.tiagomadeira.net/scripts
RewriteRule ^downloadscript/?$ http://tableless.tiagomadeira.net/scripts

#Blog: A grande excessão
RewriteRule ^blog/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1
RewriteRule ^/link/blog/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1
RewriteRule ^artigos/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1
RewriteRule ^/link/artigos/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1

#Links
RewriteRule ^link/(.+)$ http://tableless.tiagomadeira.net/index.php?l=$1
RewriteRule ^([^/.]+)$ http://tableless.tiagomadeira.net/index.php?l=$1

#Posts
RewriteRule ^post/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=artigo&id=$1
RewriteRule ^post/(.+)$ http://tableless.tiagomadeira.net/index.php?l=artigo&permalink=$1

#Scripts
RewriteRule ^script/(.+)$ http://tableless.tiagomadeira.net/index.php?l=script&script=$1
RewriteRule ^downloadscript/(.+)$ http://tableless.tiagomadeira.net/downloadscript.php?script=$1

#Feeds
RewriteRule ^feed.rss$ http://tableless.tiagomadeira.net/rss.php
RewriteRule ^rss.xml$ http://tableless.tiagomadeira.net/rss.php
RewriteRule ^index.rss$ http://tableless.tiagomadeira.net/rss.php
RewriteRule ^sitemap.xml$ http://tableless.tiagomadeira.net/sitemap.php

Samba em Prelúdio

Friday, June 17th, 2005

GeSHi Highlight funcionando! Página “oficial” de testes…

#include
int main() {
printf("Eu sem você");
}

program continuacao;

begin
write('Não tenho porquê.');
end.

echo "Porque sem você...";
?>


Não sei nem chorar...


#!/bin/bash

echo "Sou chama sem luz..."

.jardim {
sem:luar;
luar:sem amor;
amor:sem se dar;
}

document.write("Eu sem você...");

print 'Sou só desamor.'

INSERT INTO musica (letra) VALUES ('Um barco sem mar...');

<%
response.write("Um campo sem flor.");
%>



E por aí vai… Heheh…

Novo site!

Friday, June 17th, 2005

Deixei o site fora do ar por dois dias para acabar de fazer esse design. E não refiz só o design. Refiz os bancos de dados, textos (links), adicionei a seção Portifólio e reprogramei todo o site. Agora eu cadastro posts em HTML, fazendo com que eu possa abusar mais de formatação nos artigos. Posso postar várias imagens tipo as da minha biografia (aliás, enchi minha biografia de fotos). Também fiz bastante mudanças nas expressões regulares do site.

GeSHi

Estou usando o GeSHi para sintaxe colorida dos códigos que posto aqui. O “teste oficial” é o post Samba em Prelúdio que traz trechos dessa música, do Vinicius de Moraes e Baden Powell, escritos em várias linguagens, de várias formas diferentes, com sintaxe colorida do GeSHi.

Ainda não tá pronto!

Já publiquei tudo aqui como oficial, mas o site ainda não está completamente pronto. Ainda não fiz o feed (embora ele esteja declarado no cabeçalho da página), não acabei a seção Portifólio e nem o sistema de emoticons aqui dos posts e comentários. Eu tinha feito, mas o problema é que tava colocando emoticons nos códigos… Por isso, ainda tô tentando descobrir como eu faço para só o que tá fora dos code passar pela função de emoticons e espero que tudo se normalize em breve.

Eu também não copiei todos os posts antigos para cá, mas estou fazendo isso, pela ordem da visualização e comentários dos posts. Os posts mais linkados em outros locais já foram copiados, como a falha no Fotolog.net, posts sobre permutação, etc.

Avaliação

Postei o site em alguns fóruns para ser avaliado. Ele é totalmente baseado em CSS, então eu posso vir a alterar alguns detalhes. Agora ele tá bem mais semântico e bem escrito do que o antigo, o que facilita essas mudanças. Postem suas críticas e sugestões aí nos comentários! ;)

Espero que gostem!

Estatísticas de Visita com Shortstat

Tuesday, February 1st, 2005

Comecei a usar o Shortstat para acompanhar as estatísticas do site. Porém, tive alguns problemas com ele (não exatamente problemas, mas coisas que eu acho melhor mudar). Exemplos:

  • As estatísticas de browser e sistema são contadas por hit… Eu acho muito mais sensato contar por visita (única), pois algumas pessoas contam vários hits (exemplo: eu) e daí as minhas estatísticas estavam dizendo que 80% dos visitantes usavam Linux!
  • Os webcrawlers e alguns browsers são registrados como sistema operacional desconhecido

Já que o sistema é feito em PHP, achei legal consertar estes problemas e até traduzir e colocar uma bandeira do lado dos países. emoticon Vou postar aqui um passo-a-passo de instalação e esas configuração do Shortstat para quem precisar. Achei ele um ótimo sistema de estatísticas (código super simples e bem direto) e tem tudo que eu preciso. :)

Introdução

O Shortstat é um programa de estatísticas da ShaunInman escrito em PHP que usa um banco de dados MySql para incluir os registros. O funcionamento é bastante simples. Em cada página, eu uso um include para um arquivo que conta visita e existe um arquivo que conta as estatísticas. Estou partindo do princípio que você já tem PHP e MySql configurados num servidor web.

Download

O download do programa .zip pode ser feito aqui:

http://www.shauninman.com/downloads/shortstat_v036b.zip

No Linux, use o comando unzip shortstat_v036b.zip para descompactar.

No Windows, use um programa como WinZip ou WinRar (ou o descompactador do Windows XP).

Arquivos Descompactados

  • configuration.php – Configuração do banco de dados
  • functions.php – Funções do programa (toda a parte de PHP)
  • inc.stats.php – Arquivo que deve ser incluído em cada página do site pra contar visita
  • index.php – Página onde se vê as estatísticas
  • styles.css – Estilos (css) da página index.php

E ainda tem os arquivos de instalação (que poderão ser deletados logo que acabar a instalação).

IP dos Países

O Shortstat vem com um arquivo de 2mb (_ip-to-country.txt) que tem um banco de dados com ip de vários países e outro php (_ip-to-country.php) que serve para instalar o suporte ao “ip-to-country”. Depois de instalar o Shortstat normal, nós vamos instalar também para saber de onde são os visitanets do site.

Instalação

Para instalar o Shortstat, edite o arquivo configuration.php colocando nas variáveis:

$SI_db['server']="servidor_do_mysql";
$SI_db['username']="username_do_mysql";
$SI_db['password']="senha_do_mysql";
$SI_db['database']="nome_do_banco_de_dados";
$tz_offset=seu_fuso_horario;
$shortstat=true;
?>

E rode o script de instalação (_install.php) no seu browser. Ele irá criar as tabelas no seu banco de dados. Daí basta acrescentar:

… no início de cada arquivo que você quer que sejam contadas as estatísticas.

Antes de instalar o ip-to-country, eu criei uma coluna chamada codigopais no banco de dados MySql e modifiquei o arquivo functions.php criando uma função chamada verCodigoPais:

function verCodigoPais($ip) {
if (!SI_isIPtoCountryInstalled()) return '';
global $SI_tables;
$ip = sprintf("%u",ip2long($ip));

$query="SELECT country_code2 AS codigo FROM $SI_tables[countries] WHERE ip_from <= $ip AND ip_to >= $ip";
if ($result=mysql_query($query)) {
if ($r = mysql_fetch_array($result)) {
return $r['codigo'];
}
}
}
?>

No arquivo inc.stats.php, depois de atribuir um valor para a variável $ip, coloquei:

$cd = verCodigoPais($ip);
?>

… e depois de colocar valor em todas as variáveis alterei a $query para:

$query = "INSERT INTO $SI_tables[stats] (remote_ip, country, codigopais,
domain, referer, resource, user_agent, platform, browser, version, dt)
VALUES ('$ip', '$cntry', '$cd', '$domain', '$ref', '$res', '$ua', '$br[platform]',
'$br[browser]', '$br[version]', $dt)";
?>

(a única mudança foi a adição da variável cd – que contém o código do país – no campo codigopais do banco de dados)

Agora basta imprimir a bandeira do país… Para isso, no arquivo functions.php alterei a função SI_getCountries:

function SI_getCountries() {
global $SI_tables,$_SERVER;

$query = "SELECT country, codigopais, COUNT(distinct(remote_ip)) AS 'total'
FROM $SI_tables[stats]
WHERE country!=''
GROUP BY country
ORDER BY total DESC";

if ($result = mysql_query($query)) {
$ul = "

\n";
$ul .= "\t

\n";
$i=0;
while ($r = mysql_fetch_array($result)) {
if ($i < 36) {
$url = parse_url($r[referer]);
$ul .= "\t

\n";
$i++;
}
}
$ul .= "

Country Visits
\"$r[codigopais]\" $r[country] $r[total]

";
}
return $ul;
}
?>

(note que a imagem é buscada direto do servidor do ip-to-country)

Então, agora é só instalar o ip-to-country, mas o arquivo de instalação só está servindo para colocar o nome do país no banco de dados (não o código). Basta modificar o arquivo _ip-to-country.php, alterando:

echo "

Mapping existing IPs to countries.

";
// Match existing ips to countries
$query = "SELECT id,remote_ip FROM $SI_tables[stats] WHERE country=''";
if ($result = mysql_query($query)) {
while ($r = mysql_fetch_array($result)) {
$country = SI_determineCountry($r[remote_ip]);
$query = "UPDATE $SI_tables[stats] SET country='$country' WHERE id=$r[id]";
mysql_query($query);
}
}
?>

… para…

echo "

Mapping existing IPs to countries.

";
// Match existing ips to countries
$query = "SELECT id,remote_ip FROM $SI_tables[stats] WHERE country=''";
if ($result = mysql_query($query)) {
while ($r = mysql_fetch_array($result)) {
$country = SI_determineCountry($r[remote_ip]);
$cd = verCodigoPais($r[remote_ip]);
$query = "UPDATE $SI_tables[stats] SET country='$country' AND codigopais='$cd' WHERE id=$r[id]";
mysql_query($query);
}
}
?>

Daí é só rodar o arquivo _ip-to-country.php e o ip-to-country estará funcionando junto com o shortstat com bandeira do lado do país! :)

Estatísticas por visitas, não por hits

Eu alterei a função SI_getPlatforms por:

function SI_getPlatforms() {
global $SI_tables;
$th = SI_getUniqueHits();
$query = "SELECT platform, COUNT(distinct(remote_ip)) AS 'total'
FROM $SI_tables[stats]
GROUP BY platform
ORDER BY total DESC";
if ($result = mysql_query($query)) {
$ul = "

\n";
$ul .= "\t

\n";
while ($r = mysql_fetch_array($result)) {
$ul .= "\t

\n";
}
$ul .= "

Platform %
$r[platform] ".number_format(($r[total]/$th)*100)."%

";
}
return $ul;
}
?>

A mudança foi o count usar distinct(remote_ip) e o $th ter o valor dos hits únicos (daí a porcentagem é contada a partir deles). A mudança na função SI_getBrowsers é semelhante:

function SI_getBrowsers() {
global $SI_tables;
$th = SI_getUniqueHits();
$query = "SELECT browser, version, COUNT(distinct(remote_ip)) AS 'total'
FROM $SI_tables[stats]
WHERE browser != 'Indeterminable'
GROUP BY browser, version
ORDER BY total DESC";
if ($result = mysql_query($query)) {
$ul = "

\n";
$ul .= "\t

\n";
while ($r = mysql_fetch_array($result)) {
$p = number_format(($r[total]/$th)*100);
// $p = ($p==0)?"<1":$p;
if ($p>=1) {
$ul .= "\t

\n";
}
}
$ul .= "

Browser Version %
$r[browser] $r[version] $p%

";
}
return $ul;
}
?>

Conclusão

Assim temos um Shortstat configurado para as minhas necessidades. Eu gosto assim, mas por ser um sistema de código bastante simples em PHP você pode configurar mais o que quiser. Eu traduzi (é só modificar as coisas no index.php) também (não tem uma grande utilidade, mas não custa…)

Espero que tenham gostado do “artigo” e qualquer dúvida ou crítica, postem um comentário ou enviem um e-mail.