Posts Tagged ‘php’

Pegando a temperatura de qualquer cidade

julho 29th, 2010

Me surgiu um trabalho aqui pelo qual preciso exibir a temperatura atual da cidade, e como estava com insônia decidi brincar um pouco e criar uma solução para isso, fui para o google e pesquisei por “Previsão do Tempo“, me surgiram alguns resultados, porém, gostei mais do UOL.

Depois disso foi correr para a criação do script para ler o HTML e retornar um objeto contendo as informações da temperatura no momento, segue o código escrito em php:

function loadTemp($cidade='Palmas-TO'){
	// variavel para dados de retorno
	$ret = array('url' => "http://tempoagora.uol.com.br/previsaodotempo.html/brasil/$cidade/");
 
	// carrega o html do tempoagora
	$html = file_get_contents($ret['url']);
 
	// Pegamos apenas a parte que interessa do html
	$iniflag = '<!-- Insere dados Atuais de AeroPortos ou Est. Meteorologica -->';
	$fimflag = '<!-- FIM Insere dados Atuais de AeroPortos ou Est. Meteorologica -->';
	$ini = strrpos($html, $iniflag ) + strlen($iniflag);
	$fim = strpos($html, $fimflag, $ini);
	$html = substr($html, $ini, ($fim-$ini));
 
	// pegamos a url do icone
	preg_match('@<img src="/(imagens/icones/[a-zA-Z\-]+.gif)"@', $html, $mat);
	$ret['icone'] = 'http://tempoagora.uol.com.br/' . $mat[1];
 
	// Limpa o código html
	$content = strip_tags($html);
	$content = str_replace('&nbsp;', ' ', $content);
 
	// quebra o que sobrou em um vetor
	$content = explode("\n", $content);
 
	// limpa espaços e linhas em branco
	foreach ($content as $k => &$v){
		$v = trim($v);
		if ($v==='') unset($content[$k]);
	}
 
	// pega horário da verificação
	$lin = array_shift($content);
	preg_match('@[0-9]{1,2}:[0-9]{1,2}@', $lin, $mat);
	$ret['verificado']  = $mat[0];
 
	// pega insidência de nuvens
	$ret['nuvens'] = array_shift($content);
 
	// define nomes melhores para as próximas propriedades
	$keys = array('temperatura', 'sensacao', 'vento', 
			'pressao', 'umidade', 'visibilidade');
 
	// reseta as chaves do vetor
	$content = array_unique($content);
 
	// percorre chaves impares e aplica as propriedades definidas acima
	for ($x=1; $x<=11; $x=$x+2){
		$ret[array_shift($keys)] = $content[$x];
	}
 
	// retorna os dados como um objeto
	return (object)$ret;
}

Analisando o site deles, notei que a temperatura é atualizada de hora em hora, então a melhor forma de utilizar essa solução é utilizando o crontab, que executa a cada hora, eu escolhi executar no quinto minuto de cada hora cheia (5:05, 6:05, etc).

segue o código php que o crontab executa:

require 'loadTemp.php';
// define nome do arquivo de cache
$cache_file = sys_get_temp_dir() . '/temp';
 
// carrega a temperatura
$temp = loadTemp();
 
// salva em cache
file_put_contents($cache_file, serialize($temp));

E para exibir no sistema eu fiz uma funçãozinha:

function temp(){
	$cache_file = sys_get_temp_dir() . '/temp';
	// se o cache existe, retorna o objeto
	if (file_exists($cache_file)) 
		return unserialize(file_get_contents($cache_file));
 
	// senão cria o cache e retorna =)
	$temp = loadTemp();
	file_put_contents($cache_file, serialize($temp));
	return $temp;
}

depois, no local específico, ficou algo mais ou menos assim:

<?php $temp = temp() ?>
<img src="<?php echo $temp->icone ?>" alt="<?php echo $temp->nuvens ?>" />
<span><?php echo $temp->temperatura ?> (<a rel="external" href="<?php echo $temp->url ?>">saiba mais</a>)</span>

Minha forma de pagar por esse uso é manter um link para o Tempoagora, o que é bastante interessante, pois meu visitante pode querer obter mais informações

É isso ai, abraço a todos

Classe, WebService e RSS para rastreamento de encomendas nos Correios em PHP

abril 10th, 2010

Olá, depois de meses sem escrever estou voltando com uma classe muito útil e simples que nunca vi em lugar nenhum. É uma classe para rastrear encomendas nos correios que eu escrevi em PHP, que retorna um vetor com cada modificação de status lá.

Vamos direto ao ponto, confira o exemplo:

http://ferrari.eti.br/correios/samples/class.php

E para deixar a brincadeira mais divertida, fiz também um webservice com suporte a Json (padrão), phpserialize, XML e um modo dump, para visualização:

http://ferrari.eti.br/correios/webservice/?q=PB151832535BR
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&f=dump
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&f=serial
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&f=xml
e claro, para quem usa Ajax:
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&callback=minhaFuncJs

Disponibilizei tanto a classe quanto o código do webservice (que tem suporte a caching!) “de grátis” e com licença BSD no github:

http://github.com/caferrari/correios/

*UPDATE* Adicionado um gerador de RSS, assim é possível usar o proprio agregador para fazer o tracking!

http://ferrari.eti.br/correios/rss/?PB151832535BR

e em homenagem aos atendentes de telemarketing: Estarei esperando forks e colaborações para a classe, além de comentários!.

Até a próxima.

nginx – webserver, proxy reverso e perfeito!

outubro 15th, 2009

Nosso departamento é responsável por manter a identidade visual dos sites do Governo do Estado e ainda fazemos os sites dos orgãos que não possuem um.

No trabalho sempre tivemos um constante problema para hospedar nossos sites: hardware!. Contamos hoje com dois incríveis servidores IBM Pentium4 3Ghz com 2gb de memória e HDs scsi, um para hospedar mais de 40 sites e o outro onde fica postgres com os bancos de dados desses sites.

Ultimamente nosso problema tem crescido bastante, pois, a demanda por sites aumentou e ao mesmo tempo o número de visitas veio aumentando e, como não conseguimos de forma alguma (até agora) investimento em equipamento novo estavamos chegando em uma situação crítica, nosso servidor começava a sentar morrer com 200 conexões simultaneas!

Lembrei-me de um post do boo-box onde vi um servidor web chamado nginx (lê-se engineX) e decidi pesquisar mais e fazer testes em casa onde rodando um servidor e servindo uma página php com um usleep de meio segundo consegui mais de 2000 conexões simultaneas! uau!..

nginx_performance

Na segunda feira seguinte, sem pensar muito, fui para o nosso servidor de produção e apliquei a seguinte política de funcionamento:

  • nginx recebe todas as conexões pela porta 80
  • nginx faz proxy para o apache (que roda em outra porta) se a solicitação for para uma página php
  • nginx resolve sozinho usando php-cgi caso a requisição seja para:
    • uma fotografia
    • um arquivo
    • uma requisição para o webservice
    • um download do diário oficial
    • um banner do Governo
    • a barra padrão do Estado
    • ou um arquivo na nossa lib

Como resultado da experiência, nossos sites continuam morrendo, porém, aguentando 700 conexões simultaneas e esse valor só é alcançado quando tem muita pesquisa no banco de dados (Dias que sai algo sobre algum concurso público ou muita demissão no Diário Oficial) logo, fica claro, que o problema não é mais do webserver e sim do nosso servidor de Banco. Bom, o nosso webserver atualmente mal chega a 5% de uso, mesmo com as 700 conexões. Só espero conseguir uma maquina nova e mais eficiente para os nossos Bancos de Dados logo!.

Update:
Fomos atendidos, estamos com um Xeon Quad Core com 4Gb de memória para o Banco de dados, e, associado com uma otimização do cache do webservice alcançamos mais de 1000 conexões simultâneas sem nenhuma degradação na performance. Detalhe que o webserver ainda é um P4 3ghz com 1gb de memória em que a utilização de processamento não passa de 5%.

Criando Tweets pelo PHP

março 4th, 2009

Sou responsável por um site de notícias e hoje precisei criar um meio de que quando uma notícia for inserida no site, ser criado automaticamente um tweet no twitter lincando para ela, a solução foi essa classe abaixo:

class Tweet{
	var $user;
	var $pass;
	var $json = false;
 
	function __construct($user, $pass, $texto=false){
		$this-&gt;user = $user;
		$this-&gt;pass = $pass;
		if ($texto) $this-&gt;send($texto);
	}
 
	private function testTweet($texto, $match){
		foreach ($match as $m){
			$url = $m[0];
			if (ereg("^www", $url)) $url = "http://$url";
			if (strlen($url) &gt; 19) $url = str_repeat("x", 19);
			$texto = str_replace($m[0], $url, $texto);
		}
		$texto = ereg_replace("http://(x{19,})", "\\1", $texto);
		if (strlen($texto) &gt; 140) return false;
		return true;
	}
 
	public function makeUrl($url){
		if (ereg("^www", $url)) $url = "http://$url";
		if (strlen($url) &lt;= 19) return $url;
		$url = "http://migre.me/atalho/" . urlencode($url);
		$ch = curl_init();
		curl_setopt_array($ch, array(
			CURLOPT_URL =&gt; $url,
			CURLOPT_RETURNTRANSFER =&gt; true
		));
		$o = curl_exec($ch);
		ereg ("value=\"(http://migre.me/[a-zA-Z0-9/:]+)\"", $o, $mat);
		return $mat[1];
	}
 
	public function send($texto){
		if (function_exists("curl_init")){
			// Localiza as URLs
			preg_match_all("/((https?:\/\/)|(www))([a-zA-Z0-9\/:%&amp;\?\.=\-\+]+)/", $texto, $match, PREG_SET_ORDER );
 
			// Testa se o tamanho do twitter é aceitavel
			if (!$this-&gt;testTweet($texto, $match)) throw new Exception ("Postagem muito longa!");
 
			// Cria as URLs finais
			foreach ($match as $m) $texto = str_replace($m[0], $this-&gt;makeUrl($m[0]), $texto);
			$texto = str_replace("http://http://", "http://", $texto);
 
			// Testa novamente pelo comprimento do tweet
			if (strlen($texto) &gt; 140) throw new Exception ("Postagem muito longa!");
 
			// Envia o tweet
			$ch = curl_init();
			curl_setopt_array($ch, array(
				CURLOPT_URL =&gt; "http://twitter.com/statuses/update.json",
				CURLOPT_HTTPHEADER =&gt; array('Expect:'),
				CURLOPT_POST =&gt; 1,
				CURLOPT_POSTFIELDS =&gt; array("status" =&gt; "{$texto}"),
				CURLOPT_HTTPAUTH =&gt; CURLAUTH_ANY,
				CURLOPT_RETURNTRANSFER =&gt; true,
				CURLOPT_USERPWD =&gt; "{$this-&gt;user}:{$this-&gt;pass}")
			);
			return $this-&gt;json = curl_exec($ch);
		}
		return $this-&gt;json = false;
	}
}
 
$tmp = new Tweet("username", "password");
echo $tmp-&gt;send("Eu não gosto das URLs do site da Microsoft: http://search.microsoft.com/results.aspx?form=MSHOME&amp;setlang=en-us&amp;q=office+templates&amp;mkt=en-US");

Ela faz a análise do seu texto e converte as URLs, caso necessário, para um formato resumido usando o migre.me e caso passe os 140 caracteres uma exception é jogada.

Links encriptados no PHP

junho 11th, 2008

Nesse post vou exemplificar como utilizar a classe XOR exemplificada no post Operador XOR no PHP para criação de URLs encriptadas usando uma espécie de checksum que irá impedir que alguem possa alrera-la. as vantagens dessa técnica são:

  • URLs camufladas
  • PHP camuflado
  • Variáveis passadas pela URL sempre válidas
  • Impossibilidade de Modificação da querystring manualmente

Aqui está o exemplo de hoje: http://ferrari.eti.br/exemplos/fw1

Esse exemplo utiliza jSon, se você não sabe o que é, veja aqui.

Para começar, vamos criar o arquivo: includes/classes/crypt.php e colocar o código do post: Operador XOR no PHP.

Depois criaremos a nossa classe mais importante: includes/classes/link.php e vamos edita-lá:

// incluímos a classe de criptografia
require_once "crypt.php";
 
// Variavel global similar a $_POST, porém sua função é
// armazenar os valores passados pela querystring
$_PAR = array();
 
class Link {
     // Variável que armazena a chave do checksum
     static $chave = "chavedockecksum";
 
     // Variável que armazena o link
     var $link = '';
 
     // construtor, os parâmetros são simples
     // pagina = arquovo php a ser chamado
     // parametros: parâmetros da chamada ex: "id=10&amp;tipo=noticia"
     function Link($pagina='', $parametros=''){
          // chama o método responsável pela criação do link
          // repassando os parâmetros
          $this-&gt;link = $this-&gt;criaLink($pagina, $parametros);
 
          // retorna o link encriptado
          return $this-&gt;link;
     }
 
     static function criaLink($pagina='', $parametros=''){
          // transforma os parâmetros em um array associativo
          parse_str($parametros, $p);
 
          // adiciono nesse array na posição "_pagina" o arquivo php
          $p["_pagina"] = $pagina;
 
          // Aqui eu adiciono uma chave calculada a partir do que tem no array $p
          // porém adiciono somente os 5 primeiros caracteres para encurtar a chave
          // esse será o parâmetro responsável por garantir a integridade
          // da informação passada
          $p["_check"] = substr(crypt(json_encode($p), Link::$chave), 0, 5);
 
         // retornamos a URL encriptando a versão codificada em json dela.
         // rootvirtual é a constante que diz qual o root do site,
         // explicarei mais abaixo de onde ela vem
         return rootvirtual . "?" . Crypt::Encrypt(json_encode($p));
     }
 
     static function trataQuery(){
          // verifica a existência de query-string e adiciona ela na variável $q
          if ($q = $_SERVER['QUERY_STRING']){
               // decodifica a string
               $p = json_decode(Crypt::Decrypt($q), true);
                    // se o retorno for um array, quer dizer que a query é parcialmente válida
                    if (is_array($p) &amp;&amp; isset($p["_check"])){
                        // carrega a chave do vetor
                        $chave = $p["_check"];
                        // remove a chave do vetor
                        unset($p["_check"]);
                        // recalcula a chave e verifica se é diferente a chave passada
                        if (substr(crypt(json_encode($p), Link::$chave), 0, 5) != $chave)
                             // Se for, a requisição eh redirecionada para o index.
                             header ("Location: " . rootvirtual);
                        else{
                             // se for válida é criada a variável global _PAR e o vetor
                             // de parâmetros é jogado nela
                             $GLOBALS["_PAR"] = $p;
                             // sai da função
                             return true;
                        }
               }else {
                     // se não for um vetor, houve modificação da url, e a requisição
                     // é enviada para o index
                     header ("Location: " . rootvirtual);
               }
               // termina a execução e redireciona
               die();
          }
     }
}

Agora vamos para a criação de três arquivos base do site e partir para um exemplo funcional.

o arquivo: includes/config.php irá armazenar as configurações básicas do site:

// Root no servidor do site
define ("rootfisico", "/var/www/fw/");
 
// Pasta do site no servidor
define ("rootvirtual", "/fw/");
 
// As linhas abaixo são a parte interessante do sistema, pra que usar chaves
// fixas se podemos definidas randomicamente a cada acesso ao sistema?
// assim, uma url usada por uma pessoa só será valida pra ela naquele acesso
 
if (!isset($_SESSION["cryptKey"])) $_SESSION["cryptKey"] = crypt(uniqid());
if (!isset($_SESSION["cryptKey2"])) $_SESSION["cryptKey2"] = crypt(uniqid());
 
Crypt::$chave = $_SESSION["cryptKey"];
Link::$chave =  $_SESSION["cryptKey2"];

Arquivo: includes/funcoes.php

// Essa função irá retornar valores de $_POST['var'] ou $_PAR['$var']
function p($v){
	global $_POST, $_PAR;
	return isset($_POST[$v]) ? $_POST[$v] : (isset($_PAR[$v]) ? $_PAR[$v] : '');
}

Arquivo: includes/inicio.php

// Definimos o charset e inicializamos a session
header('Content-type: text/html; charset=UTF-8');
@session_start();
 
// incluímos as classes e os outros arquivos
include "funcoes.php";
include "classes/link.php";
include "config.php";
 
// agora tratamos a URL atual
Link::trataQuery();

Ufs. finalmente chegou a hora, vamos botar o sistema de Links para funcionar e vamos brincar com ele um pouco. vamos criar o arquivo /index.php

Exemplo de Link:
 
<a href="&lt;? echo Link::criaLink('') ?&gt;">Página inicial</a>
 
<a href="&lt;? echo Link::criaLink('usuarios.php', 'id=10') ?&gt;">Exemplo 1</a>
 
<a href="&lt;? echo Link::criaLink('principal.php') ?&gt;">Exemplo 2</a>
 
<a href="&lt;? echo Link::criaLink('noticia.php', 'id=10&amp;tipo=ultima&amp;skin=azul') ?&gt;">Exemplo 3</a>
 
Parabéns, a página  foi passada
<h2>Página Inicial</h2>
Nenhuma página passada, ou alguem tentou mudar a URL
 
Resultados:
 
<strong>Página:</strong>
 
<strong>Parametros:</strong>

Bom, é isso. espero que tenha sido bem explicado um exemplo funcional e arquivo para download está aqui: http://ferrari.eti.br/exemplos/fw1