A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Tutoriais e Programação

Weblinks com checagem

Sab

18

Out

2008


00:00

(2 votos, média 5.00 de 5) 


Maluco beleza Cuidado! Este é um tutorial maluco beleza!

O componente WebLinks do Joomla é instalado por default. Legalzinho, mas não é nada daquelas coisas. Um dos inconvenientes que mais me incomodavam era a apresentação de links "bichados", que não levavam a lugar algum. Como não tem como correr atrás para verificar constantemente se os links que disponibilizei ainda estão ativos ou não, resolvi criar um mecanismo de controle para informar os visitantes. Se este também é um problema que anda te atazanando, então este tutorial deve ajudar.

A idéia

Sei que não é uma solução muito elegante, mas não vi outra saída. Se quisermos testar se um determinado endereço na web está disponível, não tem outro jeito: precisamos tentar acessar o endereço para verificar se está "vivo". Isto pode levar alguns segundos e, se tivermos uma lista enorme de endereços, os segundos vão se somando e tomam um tempo que nem sempre está de acordo com a expectativa do internauta.

Mesmo assim, pensei... o que é pior, esperar um pouco mais até que a página de links carregue ou ficar se frustrando com links que estejam "bichados"? Resolvi optar pela primeira opção, esperar um pouco mais para a página carregar.

Decisão tomada, faltava encontrar um mecanismo para testar links e depois inserir um pouco de código no componente WebLinks do Joomla para que ele fizesse o que eu pretendia. Vai aqui a receita.

Alterando a tabela de dados weblinks

Para não penalizar demais os usuários da Aldeia e as páginas que precisam ser checadas, resolvi fazer uma conferência apenas uma vez por semana. Para poder verificar o prazo da validade do link é preciso criar um campo para guardar datas e também será preciso um campo para indicar se o link é válido ou não.

Se você não estiver familiarizado com bancos de dados, é melhor NÃO fazer esta alteração - você pode acabar detonando sua base de dados. Outro impedimento é se você não tem acesso à base de dados. Nestes dois casos, o melhor a fazer é desistir desta empreitada.

Fazendo as alterações na unha

Todas as tabelas do Joomla possuem um prefixo. Como cada usuário pode escolher o prefixo que quiser, vou indicá-lo por xxx.

ALTER TABLE xxx_weblinks ADD COLUMN check_date DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00'; ALTER TABLE xxx_weblinks ADD COLUMN status TINYINT(1) NOT NULL DEFAULT 0;

Você também pode fazer estas alterações usando, por exemplo, o phpMyAdmin. Bem, tabela pronta, vamos ao código.

Onde inserir o código

Apesar de vir como componente default na instalação do Joomla 1.5, o componente Weblinks não é um autêntico MVC (Model-View-Controller). Mesmo assim é possível identificar quais arquivos fazem o que. Existem três pontos nos quais poderíamos acrescentar código: em /models/category.php, em /views/category/view.html.php e /views/category/tmpl/default_items.php, todos no diretório /components/com_weblinks.

Nos dois primeiros, todos os links da tabela precisariam passar pelo mecanismo de checagem. Já imaginaram se a tabela de links possuir um zilhão de registros? O usuário que quisesse acessar uma página que mostra apenas meia dúzia de links teria que ficar a vida inteira esperando até que todos os links da tabela fossem validados :blush: Não dá! Foi exatamente o que pensei e, neste caso, só sobrou o arquivo default_items.php porque neste arquivo só são processados os links de uma página.

Antes de dar uma espiada no código que inseri, é bom conhecer um pouco das principais funções utilizadas.

Apelando para funções do PHP

As principais funções do PHP que permitem fazer uma conexão com um endereço da web são as seguintes:

  • parse_url: dado um endereço, a função parse_url devolve as partes do endereço num array nominado.
  • fsockopen: inicia uma conexão socket com o hospedeiro indicado.
  • fclose: fecha uma conexão socket.
  • fputs: é sinônimo da função fwrite e serve para enviar uma string para o arquivo apontado pelo socket.
  • stream_set_timeout: para indicar o tempo máximo de conexão.
  • socket_get_status: para verificar o estado da conexão.

Modificações no arquivo default_items.php

A primeira coisa a fazer é acertar o cabeçalho, onde colocaremos uma coluna a mais para mostrar o status dos links. Logo depois da linha 34, onde está o seguinte trecho de código

lists['order_Dir'], $this->lists['order'] ); ?>

defina a nova coluna com:

Status

Depois deste trecho há um loop que cria todas a linhas da tabela necessárias para mostrar os links. É exatamente neste loop que colocaremos uma chamada para a função que irá testar a validade de cada um dos links se o prazo estiver vencido. Logo depois da linha 56 (que agora ocupa esta posição depois que inserimos o código acima), onde está

hits; ?>

vamos fazer a chamada para a função que denominei de check:


Bem, se a função foi chamada, então precisamos colocá-la em algum lugar. Coloquei-a no final do arquivo. Observe que a função leva como parâmetro o objeto $item. Isto é necessário para que possamos acessar alguns atributos deste objeto como, por exemplo, a URL.

renova ) { if( $item->status == 0 ) { echo ''; } else { echo ''; } return; } $url = $item->url; if( ( !eregi( "http", $url ) ) && ( !eregi( "https", $url ) ) ){ $url = 'http://' . $url; } $urlArray = parse_url( $url ); $timeout = 7; $return['code'] = ''; $return['status'] = ''; if( $urlArray['scheme'] == 'http' ) { $urlArray['port'] = 80; $sock = @fsockopen( $urlArray['host'], $urlArray['port'], $errnum, $errstr, $timeout ); } else if( $urlArray['scheme'] == 'https' ) { $urlArray['port'] = 443; $sock = @fsockopen( $urlArray['host'], $urlArray['port'], $errnum, $errstr, $timeout ); } else { echo ''; } if( !isset( $sock ) || $sock === false || $sock == "" ) { echo ''; } // HTTP use HEAD Method getHTTP($sock, $urlArray, 'HEAD', $return, $timeout); @fclose( $sock ); if ($return['code'] == '405') { // HTTP "HEAD" não aceito ou em Error => usar método "TRACE" $sock = @fsockopen($urlArray['host'], $urlArray['port'], $errnum, $errstr, $timeout ); // Definir espera em segundos para proteger o socket getHTTP($sock, $urlArray, 'TRACE', $return, $timeout); @fclose( $sock ); } if (!$return['code'] || $return['code'] >= '400' ) { // HTTP nada retornou com "HEAD" ou "TRACE" // ou método não permitido => usar método "GET" $sock = @fsockopen($urlArray['host'], $urlArray['port'], $errnum, $errstr, $timeout); // Espera em segundos para proteger o socket getHTTP($sock, $urlArray, 'GET', $return, $timeout); @fclose( $sock ); } if (!$return['code']) { $return['code'] = '404'; $return['status'] = "Página não encontrada Erro 404 (No code returned)"; } $model =& JModel::getInstance('category', 'weblinksmodel'); if( $return['code'] != '200' ) { echo ''; $model->setCheck( $item->id, 0 ); } else { echo ''; $model->setCheck( $item->id, 1 ); } }

Esta função chama uma outra, a function getHTTP. Coloquei-a logo a seguir no final do mesmo arquivo:

function getHTTP(&$sock, &$urlArray, $HTTPmethod, &$return, $timeout=7) { $return['code'] = ''; $return['status'] = ''; $urlquery = (isset($urlArray['query'])) ? "?".$urlArray['query'] : ""; $useragent = "Mozilla/5.0 (compatible; weblinks 1.5.7; Link Checker)"; $dump = $HTTPmethod . " " . $urlArray['path'] . $urlquery. " HTTP/1.1\r\n"; $dump .= "User-Agent: " . $useragent . "\r\n"; $dump .= "Host: " . $urlArray['host'] . "\r\n"; $dump .= "Connection: close\r\n\r\n"; if( !@fputs( $sock, $dump ) ) { $result['code'] = '404'; return; } stream_set_timeout( $sock, $timeout ); $status = socket_get_status( $sock ); $str = '-vazio-'; $closed = false; while( ( !feof($sock) ) && ( !$status['timed_out'] ) && ( $str != "" ) && ( !$closed ) ) { $str = @fgets( $sock, 1024 ); $status = socket_get_status( $sock ); if (eregi("^http/[0-9]+.[0-9]+ ([0-9]{3})", $str) ) { $return['code'] = trim(eregi_replace("^http/[0-9]+.[0-9]+ ([0-9]{3}) [a-z ]*", "\\1", $str)); if ( substr(strtoupper($return['code']),0,4) == 'HTTP') { // Código começa com "HTTP" => há apenas código HTTP sem descrição. $return['code'] = trim(eregi_replace("^http/[0-9]+.[0-9]+ ([0-9]{3})[a-z ]*", "\\1", $str)); } // Manter apenas os primeiros 3 dígitos... $return['code'] = substr($return['code'],0,3); $return['status'] = $str; } if (eregi("^Content-Type: ", $str)) { $return['contentType'] = trim(eregi_replace("^Content-Type: ", "", $str)); } if (eregi("^User-Agent: ", $str)) { $return['userAgent'] = trim(eregi_replace("^User-Agent: ", "", $str)); } if (eregi("^Location: ", $str)) { $return['location'] = trim(eregi_replace("^Location: ", "", $str)); } if (eregi("^Content-Length: ", $str)) { $return['contentLength'] = trim(eregi_replace("^Content-Length: ", "", $str)); } $closed = ( $HTTPmethod == "GET" && ( $str == "\r\n" && ($return['code']=="200" || $return['code']=="404")) ); } } ?>

Atualizando a base de dados

As informações colhidas por estas duas funções colocadas no arquivo /components/com_weblinks/views/category/tmpl/default_items.php precisam ser colocadas no banco de dados. Como sabemos, quem lida com a base de dados são os modelos que estão no diretório /components/com_weblinks/models. Bem, neste caso o que nos interessa é o arquivo /models/category.php que define a classe WeblinksModelCategory. Esta classe foi "adornada" com duas funções, colocadas também no seu final (mania minha colocar os hacks no final dos arquivos).

A primeira delas é chamada pela função getData() original deste arquivo. Ela serve para verificar se está na hora de reavaliar o estado do link. Para isto, altere a função original inserindo uma nova linha para atualizar $item->renova:

function getData() { // Lets load the content if it doesn't already exist if (empty($this->_data)) { $query = $this->_buildQuery(); $this->_data = $this->_getList($query, $this->getState('limitstart'), $this->getState('limit')); $total = count($this->_data); for($i = 0; $i < $total; $i++) { $item =& $this->_data[$i]; $item->slug = $item->id.':'.$item->alias; $item->renova = $this->_novoCheck( $item->id ); } } return $this->_data; }

E aqui estão as duas novas funções do modelo que podem ser colocadas no final deste arquivo:

function _novoCheck( $id ) { $query = 'SELECT TO_DAYS( NOW() )'; $this->_db->setQuery( $query ); $hoje = $this->_db->loadResult(); $query = 'SELECT TO_DAYS( check_date ) FROM #__weblinks WHERE id='.$id; $this->_db->setQuery( $query ); $ultimo = $this->_db->loadResult(); if( $ultimo == NULL || ($hoje - $ultimo) > 6 ) { return true; } else { return false; } } function setCheck( $id, $status ) { $query = "UPDATE #__weblinks SET check_date=NOW(), status=$status WHERE id=$id"; $this->_db->setQuery( $query ); $this->_db->query(); }

Finalmentes

Se você quiser conferir o resultado deste hack, dê uma chegada na seção de Links (espero que não encontre muitos links órfãos smile ).

Se tiver dúvidas ou precisar de orientação, faça contato. Estou pronta para ajudar no que for preciso.

Se você detonar seu site Joomla tentando fazer o que sugeri, não me culpe. Tudo o que você alterar é por sua conta e risco!

info NÃO SE ESQUEÇA. Quando você for atualizar sua versão do Joomla, lembre-se de que o componente WebLinks foi alterado. Sugiro renomear o diretório do componente para alguma coisa como /components/com_weblinks.ALTERADO antes de fazer a atualização e depois dar um trato especial no bacaninha.

Desejo sucesso a todos os intrépidos

vovo

broker mfxсковорода гриль чугунная с прессом купитьдать отзывпокупка видеокамерытехника днрновости украины атоbroker mfx

Informações adicionais