Vou aproveitar o post pra postar os códigos que eu estou fazendo pra interpretação de BBCodes e estatísticas do blog que eu, o Hélio e o Gustavo começamos a desenvolver semana passada e queremos acabar até no máximo o final de novembro (pretendemos acabar perto do dia 15/11).
Expressões Regulares
< ?php
/* A parte de regex de códigos precisa do GeSHi Highlighter. Includando-o... */
include("geshi.php");
/* Essa classe serve para ser usada com "extends", ela sozinha "não é nada". */
class Regex {
/* Função que interpreta emoticons */
function Emoticons() {
$origem=Array(":)", ":(", ":D", ":P", ":O", ":S", ":lol:", ":blink:");
$destino=Array("feliz.gif", "triste.gif", "sorriso.gif", "lingua.gif", "espantado.gif", "confuso.gif", "riso.gif", "confuso.gif");
// EM DESENVOLVIMENTO!
}
/* Função que interpreta BBCodes...
* Totalmente desenvolvida por mim. (nem parece de tão linda, né?) */
function InterpretaBBCodes() {
/* Vamos começar pelos [codes], porque só o que tá fora deles deve ser
interpretado depois. */
preg_match_all("/\[code language=([a-z]+)\](.*)\[\/code\]/sU", $this->texto, $matches_com_linguagens);
preg_match_all("/\[code\](.*)\[\/code\]/sU", $this->texto, $matches_sem_linguagens);
/* - A parte dos códigos é $matches_com_linguagens[$i][2] e $matches_sem_linguages[$i][1].
- A parte que diz em que linguagem os códigos $matches_com_linguagens[$i][2] foi escrita
é $matches_com_linguagens[$i][1].
- Para facilitar os códigos abaixo, vou trocar matches_com_linguagens para mcl e
matches_sem_linguagens para msl. Só não fiz em cima pra quem tá de fora entender o que
eu tô fazendo nessa parte do código. ;)
*/
$mcl=$matches_com_linguagens;
$msl=$matches_sem_linguagens;
$con=0;
for ($i=0; $i
$g=new GeSHi($mcl[2][$i], $mcl[1][$i], "./geshi/");
$geshi_mcl[$i]=$g->parse_code();
$mcl_md5[$i]=md5(time()*$con++);
$this->texto=str_replace($mcl[0][$i], $mcl_md5[$i], $this->texto);
}
for ($i=0; $i
/* Aqui, vocês vão perguntar: "Por que passar no GeSHi, se não sei highlightear essa linguagem?
A resposta é que o GeSHi não só highlighta, mas formata o código de forma que ele fique
legível (por exemplo, troca < por <. */
$g=new GeSHi($msl[1][$i], "", "./geshi/");
$geshi_msl[$i]=$g->parse_code();
$msl_md5[$i]=md5(time()*$con++);
$this->texto=str_replace($msl[0][$i], $msl_md5[$i], $this->texto);
}
/* Beleza, agora precisamos sempre lembrar de não highlightear o que estiver entre
.
E também não podemos deixar nada fora dos padrões XHTML Strict. */
$this->texto=str_replace("&", "&", $this->texto);
$this->texto=str_replace("< ", "<", $this->texto);
$this->texto=str_replace(">", ">", $this->texto);
$this->texto=str_replace("\"", """, $this->texto);
// Aqui tá o meu "nl2br" semântico! =)
$this->texto="
".$this->texto."
";
$this->texto=preg_replace("/\n\n\n*/", "
", $this->texto);
/*
vazios não são semânticos. Mas estive pensando depois de fazer isso e acho que
algumas pessoas podem querer dar um grande espaço entre os
, por isso estou
pensando em fazer uma ER que a cada \n a mais de dois \n's adicione 10px ao
margin-bottom do último
. O que vocês acham? */
$this->texto=preg_replace("/\n/", "\n", $this->texto);
$this->texto=preg_replace("/< \/p>
/", "
\n
", $this->texto);
// Formatação básica (negrito, itálico, sublinhado, cores, cabeçalhos)
$this->texto=preg_replace("/\[b\](.*)\[\/b\]/sU", "\\1", $this->texto);
$this->texto=preg_replace("/\[i\](.*)\[\/i\]/sU", "\\1", $this->texto);
$this->texto=preg_replace("/\[u\](.*)\[\/u\]/sU", "\\1", $this->texto);
$this->texto=preg_replace("/\[color=([^\]]+)\](.*)\[\/color\]/sU", "\\2", $this->texto);
$this->texto=preg_replace("/\[h([1-6])\](.*)\[\/h\\1\]/sU", "\\2< \/h\\1>\n", $this->texto);
// Citações
$this->texto=preg_replace("/\[quote\](.*)\[\/quote\]/sU", "\\1
\n", $this->texto);
$this->texto=preg_replace("/\[quote=([^\]]+)\](.*)\[\/quote\]/sU", "\\2
\n\\1", $this->texto);
// URLs
$this->texto=preg_replace("/([^\"\/=\]])(www\.[^[:blank:]\"< ]+)/", "\\1\\2", $this->texto);
$this->texto=preg_replace("/([^\"=\]])(http:\/\/[^[:blank:]\"< ]+)/", "\\1\\2", $this->texto);
$this->texto=preg_replace("/\[url\]([^\"]*)\[\/url\]/sU", "\\1", $this->texto);
$this->texto=preg_replace("/\[url=([^[:blank:]\"]+)[[:blank:]]+title=([^\]\"]+)\](.*)\[\/url\]/sU", "\\3", $this->texto);
$this->texto=preg_replace("/\[url=([^\]\"]+)\](.*)\[\/url\]/sU", "\\2", $this->texto);
preg_match_all("//U", $this->texto, $matches);
for ($i=0; $itexto=str_replace($matches[0][$i], "", $this->texto);
}
// Imagens
$this->texto=preg_replace("/\[img=([^\]]+)\]([^\"]*)\[\/img\]/U", "
", $this->texto);
$this->texto=preg_replace("/\[img\]([^\"]*)\[\/img\]/U", "
", $this->texto);
// Listas
$this->texto=preg_replace("/\[list\](.*)\[\/list\]/sU", "
", $this->texto);
$this->texto=preg_replace("/\[li\](.*)\[\/li\]/sU", "
\\1
", $this->texto);
// Limpando besteiras... Alguém tem alguma idéia melhor do que esse FOR feio?
for ($count=0; $count<10; $count++) {
$this->texto=preg_replace("/
< \/li>/", "", $this->texto);
$this->texto=preg_replace("/
", $this->texto);
$this->texto=preg_replace("/< (\/?)li>
/", "< \\1li>", $this->texto);
$this->texto=preg_replace("/
/", "
", $this->texto);
$this->texto=preg_replace("/< \/q>
/", "
", $this->texto);
}
// Emoticons
// $this->Emoticons();
/* Lembram que o código tinha sido transformado em md5s com o tempo, pros
bbcodes não entrarem em ação dentro deles? Então vamos transformar de
volta em códigos agora... */
for ($i=0; $itexto=str_replace($mcl_md5[$i], $geshi_mcl[$i], $this->texto);
}
for ($i=0; $itexto=str_replace($msl_md5[$i], $geshi_msl[$i], $this->texto);
}
// Limpando as besteiras que não precisam ser repetidas (e coloquei depois dos codes porque
// aqui corrijo o negócio com os
s.
$this->texto=preg_replace("/
[[:blank:]]*
(.*)< \/pre>[[:blank:]]*< \/p>/sU", "
\\1
", $this->texto);
$this->texto=preg_replace("/
[[:blank:]]*
(.*)< \/ul>[[:blank:]]*< \/p>/sU", "
", $this->texto);
$this->texto=preg_replace("/
[[:blank:]]*(.*)< \/h\\1>[[:blank:]]*< \/p>/sU", "\\2", $this->texto);
$this->texto=preg_replace("/< ([^>]+)>[[:blank:]]?< \/\\1>/", "", $this->texto);
// E pra finalizar, o mais mala de todos... =)
$this->texto.="\n";
}
}
?>
Tá bem comentado e queria pedir pra quem puder, dar uma testada com ele (coloquem uns BBCodes errados e coisas que vocês acham que eu não iria prever). Aí embaixo então a parte das estatísticas, para as quais estou usando um pouco do código do Shortstat. Ela tá assim por enquanto:
Estatísticas
< ?php
class Estatisticas {
var $ip, $pais, $codigopais, $referer, $url, $dominio, $res, $useragent, $navegador, $versaonavegador, $plataforma, $unixtime;
/* Função que descobre o IP real do visitante
* Copiada de: www.foo.com.br
*/
function IpReal() {
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 para descobrir navegador, sistema operacional, etc. com base no User Agent.
* "SI_parseUserAgent()" do Shortstat, levemente modificada.
*/
function ParseUserAgent($ua) {
$plataforma="Desconhecida";
$navegador="Desconhecido";
$versao="";
if (eregi("Win", $ua)) {
$plataforma="Windows";
} else if (eregi("Mac", $ua)) {
$plataforma="Macintosh";
} else if (eregi("Linux", $ua)) {
$plataforma="Linux";
} else if (eregi("W3C", $ua)) {
$plataforma="W3C Validator";
$navegador="W3C Validator";
$versao="-";
} else if (eregi("Googlebot", $ua)) {
$plataforma="Googlebot";
} else if (eregi("msnbot", $ua)) {
$plataforma="MSNBot";
} else if (eregi("Cynthia", $ua)) {
$plataforma="Cynthia";
$navegador="Cynthia";
$versao="0";
}
if (eregi("Mozilla/4", $ua)&&!eregi("compatible", $ua)) {
$navegador="Netscape";
eregi('Mozilla/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Mozilla/5", $ua)||eregi("Gecko", $ua)) {
$navegador="Mozilla";
eregi('rv(:| )([[:digit:]\.]+)', $ua, $b);
$versao=$b[2];
}
if (eregi("Safari", $ua)) {
$navegador="Safari";
$plataforma="Macintosh";
eregi('Safari/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("iCab", $ua)) {
$navegador="iCab";
eregi('iCab/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Firefox", $ua)) {
$navegador="Firefox";
eregi('Firefox/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Firebird", $ua)) {
$navegador="Firebird";
eregi('Firebird/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Phoenix", $ua)) {
$navegador="Phoenix";
eregi('Phoenix/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Camino", $ua)) {
$navegador="Camino";
eregi('Camino/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Chimera", $ua)) {
$navegador="Chimera";
eregi('Chimera/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Netscape", $ua)) {
$navegador="Netscape";
eregi('Netscape[0-9]?/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("MSIE", $ua)) {
$navegador="Internet Explorer";
eregi('MSIE ([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Opera", $ua)) {
$navegador="Opera";
eregi('Opera( |/)([[:digit:]\.]+)', $ua, $b);
$versao=$b[2];
}
if (eregi("OmniWeb", $ua)) {
$navegador="OmniWeb";
eregi('OmniWeb/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
if (eregi("Konqueror", $ua)) {
$navegador="Konqueror";
$plataforma="Linux";
eregi('Konqueror/([[:digit:]\.]+', $ua, $b);
$versao=$b[1];
}
if (eregi('Crawl', $ua) || eregi('bot', $ua) || eregi('slurp', $ua) || eregi('spider', $ua)) {
$navegador="Crawler/Search Engine";
$versao="-";
}
if (eregi('Lynx', $ua)) {
$navegador="Lynx";
eregi('Lynx/([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
$plataforma="Linux";
}
if (eregi('Links', $ua)) {
$navegador="Links";
eregi('\(([[:digit:]\.]+)', $ua, $b);
$versao=$b[1];
}
$array=Array($navegador, $versao, $plataforma);
return $array;
}
/* Função para determinar o país do visitante
* "SI_determineCountry()", do Shortstat, bem modificada por mim.
*/
function DeterminarPais($ip) {
global $BASE;
$ip=sprintf("%u", ip2long($ip));
$db=new $BASE['TYPE'];
$db->Conecta();
$db->Query("SELECT nome, codigo FROM ".$BASE['TABELA_PAISES']." WHERE ip_from < = $ip AND ip_to >= $ip");
$array=$db->FetchRow();
$db->Desconecta();
/* Agora um monte de linhas por causa da incompetência do PHP 5.0.5... Hehehe... */
$tmp1=preg_replace("/([A-Z\xC0-\xDF])/e", "chr(ord('\\1')+32)", $array[0]);
$tmp2=ucwords($tmp1);
$array[0]=trim($tmp2);
return $array;
}
/* Função para "increase stats"
* O arquivo "inc.stats.php" do Shortstat, bem modificado por mim.
*/
function IncStats() {
global $BASE;
$this->ip=$this->IpReal();
list($this->pais, $this->codigopais)=$this->DeterminarPais($this->ip);
$this->referer=$_SERVER["HTTP_REFERER"];
$this->url=parse_url($this->referer);
$this->dominio=eregi_replace("^www", "", $this->url["host"]);
$this->resource=$_SERVER["REQUEST_URI"];
$this->useragent=$_SERVER["HTTP_USER_AGENT"];
list($this->navegador, $this->versaonavegador, $this->plataforma)=ParseUserAgent($this->useragent);
$this->unixtime=time();
$db=new $BASE['TYPE'];
$db->Conecta();
$db->Query("INSERT INTO ".$BASE['TABELA_ESTATISTICAS']." (ip, pais, codigopais, dominio,
referer, resource, useragent, plataforma, navegador, versao, unixtime) VALUES ('{$this->ip}',
'{$this->pais}', '{$this->codigopais}', '{$this->dominio}', '{$this->referer}', '{$this->resource}',
'{$this->useragent}', '{$this->plataforma}', '{$this->navegador}', '{$this->versaonavegador}',
'{$this->unixtime}')");
$db->Desconecta();
}
}
?>
Bom... Esses dois códigos estão em desenvolvimento ainda, mas acho que com o tempo vão melhorando. Tem umas coisas na parte de Regex que eu queria tornar mais simples mas ainda não descobri como! :blink: Quem quiser sugerir, sinta-se a vontade.