Solução simples para um problema simples

October 31, 2008 at 11:32

É impressionante como alguns desenvolvedores muitas vezes não procuram uma forma mais simples de fazer certas tarefas do dia-a-dia, um exemplo clássico: Deixar apenas números em uma string, nesse caso, o número de uma agência bancária.

Primeiro a forma que vejo normalmente (em C#)

    string agency = plan.Agency.Replace("-", "");
    agency = agency.Replace(".", "");
    agency = agency.Replace("/", "");
    agency = agency.Replace("\", "");
    

Forma simplificada (C# também)

    Regex.Replace(plan.Agency, "[^0-9]+", "")
    

Não é muito mais simples? Basta procurar! ;)

Desabilitando validadores do .NET com Javascript

October 27, 2008 at 14:08

Mexendo com .NET hoje (eu sei, mas faz parte) tive que descobrir como desabilitar uns validadores com Javascript, e a resposta é bem simples:

    var myVal = document.getElementById('<%= myValidator.ClientID %>');
    ValidatorEnable(myVal, false);
    

Tirado daqui: http://geekswithblogs.net/jonasb/archive/2006/08/11/87708.aspx

Fonte para Linux

October 08, 2008 at 00:17

Para quem está procura de uma boa fonte para Linux pode dar uma experimentada na Liberation, é uma fonte que fica muito bem com um tamanho pequeno.

Para instalar no Arch Linux

    pacman -S ttf-liberation
    

Adicionando e removendo um usuário de um grupo no Linux

October 07, 2008 at 13:33

Hoje precisei definir uns grupos para um usuário e achei os comandos abaixo

Para adicionar um usuário em um grupo:

    useradd -G nome_do_grupo nome_do_usuario
    

Você pode passar vários grupos também, basta separar a lista por vírgula:

    usermod -G nome_do_grupo,nome_de_outro_grupo nome_do_usuario
    

Para remover um usuário de um grupo:

    usermod -G nome_do_grupo nome_do_usuario
    

Note que a sintaxe para remover é a mesma para adicionar, porém a lista de grupos terá apenas os grupos em que você deseja manter o usuário.

Outra forma de remover todos os grupos secundários (adicionados com os comandos acima) é usando '' (vazio)

    usermod -G '' nome_do_usuario
    

Mais detalhes aqui e aqui

Apache ouvindo em duas (ou mais) portas diferentes

September 23, 2008 at 19:43

É muito simples, basta colocar quantas diretivas Listen você precisar

    Listen 80
    Listen 81
    Listen 82
    

Retirado daqui

Eu estou usando isso para poder diferenciar quando estou rodando a aplicação via Selenium ou não.

PHP, PDO e ... Sei lá o que!

September 16, 2008 at 10:57

Eu não ainda não consegui achar explicação para o código

Gerar a saída

    /home/rafael/>php pdo_fetchmode.php
    setting: id with 18
    setting: client_id with 48
    setting: is_active with 1
    setting: name with Site v1
    setting: proposal with 1626
    setting: description with
    setting: created_at with 0000-00-00 00:00:00
    setting: updated_at with
    setting: created_by with
    calling constructor
    setting: id with 17
    setting: client_id with 13
    setting: is_active with 1
    setting: name with Supra v1
    setting: proposal with 1593
    setting: description with
    setting: created_at with 0000-00-00 00:00:00
    setting: updated_at with
    setting: created_by with
    calling constructor
    setting: id with 19
    setting: client_id with 56
    setting: is_active with 1
    setting: name with Atualizacao
    setting: proposal with
    setting: description with
    setting: created_at with 0000-00-00 00:00:00
    setting: updated_at with 2008-09-15 10:02:34
    setting: created_by with
    calling constructor
    

Tenho o costume de sempre retornar objetos em resultados de banco de dados, acho mais fácil de trabalhar do que com arrays.

Ontem eu estava implementando algumas funcionalidades no ORM que fizemos aqui e me deparei com esse problema, eu precisava usar nos métodos __get e __set uma variável setada no construtor, mas começou a gerar um outro erro, causado pelo fato de que a variável não estava setada.

Procurei na documentação do PHP e só achei esse comentário, onde no final diz

Note also that the constructor is called AFTER the data is set on the object.

AFTER?! Isso vai contra toda e qualquer lógica de OOP que eu conheça!! Como que ele cria um objeto, seta todos os atributos nele e só chama o construtor depois de tudo?

Se alguém puder me explicar o motivo, razão ou circunstância, por favor, sinta-se mais do que a vontade.

Problemas com o blog

September 07, 2008 at 20:20

Esse final de semana tive uma batalha, batalha contra os spammers. De sexta (05/09) até hoje (07/09) eu estava tentando encontrar uma forma de bloqueá-los, acho que consegui.

Primeiro, um trecho do access_log do apache:

    61.139.105.163 - - [06/Sep/2008:15:44:16 -0400] "GET http://www.esavingsnet.com/adscript_contextual.php?addcode=CD2049&bannerid=3377&optionalinfo=&deploy_id=0&landing_id=0 HTTP/1.1" 302 - "http%3A%2F%2Fwww.popflashgames.com%2Findex.html" "Mozilla/4.75 [en] (Win98; U)"
    60.168.227.97 - - [06/Sep/2008:15:44:16 -0400] "GET http://ad.yieldmanager.com/pixel?id=79470&t=2 HTTP/1.0" 302 - "http://ad.103092804.com/st?ad_type=iframe&ad_size=728x90&section=334436" "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 98; DigExt)"
    221.224.78.254 - - [06/Sep/2008:15:44:16 -0400] "GET http://afe.specificclick.net/?l=1212015023&sz=300x250&wr=j&t=j&u=http%3A//www.autoefax.com/best_deals/bestdeals/index.php&r= HTTP/1.0" 200 4736 "http://www.autoefax.com/best_deals/bestdeals/index.php" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)"
    72.52.146.79 - - [06/Sep/2008:15:44:16 -0400] "GET http://ad.yieldmanager.com/imp?Z=0x0&y=29&s=289946&_salt=3097474688&B=2&u=http%3A%2F%2Fwww.vafq.com%2Findex.html HTTP/1.1" 200 6663 "http%3A%2F%2Fwww.vafq.com%2Findex.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 2.0.40"
    72.52.146.79 - - [06/Sep/2008:15:44:16 -0400] "GET http://ad.adserverplus.com/rw?title=&qs=iframe3%3Fks9PAJpsBABbCBIA%2Eo0FAAIAAAAAAP8AAAAHEAICAAMsnQUActkEAKJNCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgzmzM2z8AAAAAAAAAAAAA4CUp2%2DM%2EAAAAAAAAAAAAAJCf94vwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtAncswPCCwWKJq27l%2Dt%2EpvPxUBCN1rTpsKxzOgAAAAA%3D%2C%2Chttp%3A%2F%2Fwww%2Evafq%2Ecom%2Findex%2Ehtml HTTP/1.1" 200 542 "http%3A%2F%2Fwww.vafq.com%2Findex.html" "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)"
    61.139.105.166 - - [06/Sep/2008:15:44:16 -0400] "GET http://banner.addlvr.com/cpi.jsp?&pvr=84&p=112839&aid=29606&partnerMin=0&ron=on&ronMin=0&cpviw=160&cpvih=600&url=http%3A//www.freeaddictinggame.net/&context= HTTP/1.0" 302 - "http://www.freeaddictinggame.net/" "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)"
    

Como minha VPS tem apenas 160MB de RAM, tenho que ficar controlando o consumo de memória, e sexta veriquei que o blog estava muito lento, quase inacessível. Parei o apache, instalei o nginx e o consumo baixou.

Mas o negócio não estava 100% ainda, fui ver os logs e descobri que ele tinha todas aquelas requisições partindo do meu server, então, hoje (07/09), depois de muito pensar para tentar entender o que estava acontecendo e solucionar o problema, fiz um script para testar se era possível usar meu servidor para fazer essas requisições, e descobri que é possível :(

Qualquer pessoa pode abrir uma conexão com um servidor na porta 80 (usando socket por exemplo), e fazer uma requisição assim:

    GET http://www.terra.com.br/capa/ HTTP/1.1
    

Fácil assim, sem dificuldade nenhuma, como é possível ver no log do apache ali em cima, todas as requisições retornam status 302, funcionando normalmente, porém quando troquei para o nginx, a coisa mudou, ficando assim:

    221.224.78.234 - - [07/Sep/2008:18:48:53 -0400] 221.224.78.234 "GET http://221.224.78.234:51317/was-pv.dll HTTP/1.0" 502  529 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" "-"
    221.224.78.234 - - [07/Sep/2008:18:48:53 -0400] www.google.com "GET http://www.google.com/ HTTP/1.0" 502  529 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" "-"
    118.248.1.167 - - [07/Sep/2008:18:49:04 -0400] uk.vortal.com "GET http://uk.vortal.com/xml.php?Terms=Jewelry&strict=1&affiliate=lookfree&IP=69.89.12.138&rpp=10 HTTP/1.1" 502  529 "-" "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 4.0)" "-"
    118.248.1.167 - - [07/Sep/2008:18:49:04 -0400] uk.vortal.com "GET http://uk.vortal.com/xml.php?Terms=Jewelry&strict=1&affiliate=woonkrant&IP=69.89.12.138&rpp=10 HTTP/1.1" 502  529 "-" "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 4.0)" "-"
    222.184.123.6 - - [07/Sep/2008:18:49:04 -0400] www.linkbucks.com "GET http://www.linkbucks.com/link/f88c0a49 HTTP/1.0" 502  529 "http://www.google.com/" "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0; Alexa Toolbar)" "-"
    118.248.1.167 - - [07/Sep/2008:18:49:05 -0400] uk.vortal.com "GET http://uk.vortal.com/xml.php?Terms=Jewelry&strict=1&affiliate=woonkrant&IP=69.89.12.138&rpp=10 HTTP/1.1" 502  529 "-" "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 4.0)" "-"
    118.248.1.167 - - [07/Sep/2008:18:49:05 -0400] uk.vortal.com "GET http://uk.vortal.com/xml.php?Terms=Jewelry&strict=1&affiliate=lookfree&IP=69.89.12.138&rpp=10 HTTP/1.1" 502  529 "-" "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 4.0)" "-"
    

Status 502, Bad Gateway, o nginx trata esse tipo de requisição de um jeito diferente do apache, que na minha opnião, é muito mais inteligente.

Resolvi procurar como bloquear essas requisições mais explicitamente, deixando claro que essas requisições não eram permitidas. Então configurei o nginx para bloquear requisições que partirem de um host diferente que não o meu.

    if ($host !~* ^www\.joeh\.com\.br$) {
        return 403;
    }
    

Veremos agora se terei mais problemas com os spammers do mal :)

Closures no PHP 5.3

September 02, 2008 at 13:24

Dias desses publiquei no Gist um trecho de código que faz uso de Closures do PHP 5.3, mostrando um pouco do que é possível com essa nova versão.

Esses dias estava eu mexendo com Malline e Haml quando me surgiu a idéia, poderia eu fazer algo parecido usando PHP 5.3 e Closures? A resposta é o código abaixo:

A saída será essa:

    <html><head><title>Titulo da Pagina</title></head><body><p>Hello World</p><p>Outro Paragrafo<p>Um subparagrafo agora</p></p></body></html>
    

Isso mostra que será possível fazer um linguagem de template usando PHP puro, muito parecido com o que Malline faz para o Ruby/Rails.

Teste com o Sinatra

August 27, 2008 at 21:28

Esses dias vi alguém no Twitter falando do Sinatra (não me lembro quem, e também fiquei com preguiça de procurar :P ) e resolvi testar. Fiz um script que monta um select com todos os episódios do Rails Podcast Brasil, e ainda dando a possibilidade de ver o show notes de cada um deles.

Para instalar o Sinatra basta um simples

    sudo gem install sinatra
    

Para ver se está funcionando basta criar um arquivo muito simples como esse: (test_sinatra.rb)

    require 'rubygems'
    require 'sinatra'
    
    get '/' do
        "Funciona muuuito esse Sinatra"
    end
    

Botar o webserver a rodar

    ruby test_sinatra.rb
    

E rodar no browser

    http://localhost:4567/
    

Se aparecer na sua tela: Funciona muito esse Sinatra então tudo funcionou como deveria :)

Agora vamos a parte mais "complicada". Vamos pegar o nosso arquivo test_sinatra.tb e colocar o código abaixo:

    require 'rubygems'
    require 'sinatra'
    require 'hpricot'
    require 'open-uri'
    
    get '/' do
      body = '<form method="post" action="/"><select name="link">'
    
      doc = Hpricot(open("http://podcast.rubyonrails.pro.br/"))
      (doc/'div.sub').each do |sub|
        a = sub.next_sibling.search('a').last
        if a
          (sub/'h1').each do |h1|
            number = h1.children[0].inner_text
            puts number.to_s
            if number[0] == 35 # igual a #
              body << '<option value="' + a[:href] + '">Episódio ' + number + ' - ' + h1.children[2].inner_text + '</option>'
            end
          end
        end
      end
      body << '</select><button>Ok</button></form>'
    end
    
    post '/' do
      body = '<form method="post" action="/"><select name="link">'
    
      doc = Hpricot(open("http://podcast.rubyonrails.pro.br/"))
      (doc/'div.sub').each do |sub|
        a = sub.next_sibling.search('a').last
        if a
          (sub/'h1').each do |h1|
            number = h1.children[0].inner_text
            if number[0] == 35 # igual a #
              body << '<option value="' + a[:href] + '">Episódio ' + number + ' - ' + h1.children[2].inner_text + '</option>'
            end
          end
        end
      end
      body << '</select><button>Ok</button></form>'
    
      doc = Hpricot(open("http://podcast.rubyonrails.pro.br#{params[:link]}"))
      body << (doc/'div.content ul').last.to_html
    end
    

Pelo código podemos ver que temos uma chamada para get '/' e outra post '/'. Elas tratam da mesma URL, porém dependendendo do método HTTP atual ele chama um ou outro, isso é bom para separar alguma lógica que seja diferente entre eles.

Mas temos um problema, o nosso código não está DRY, tem muito código duplicado. Para resolver isso o Sinatra possui helpers também, que podem ser criados facilmente usando o método helpers, assim:

    helpers do
        def meu_helper
            # faz alguma coisa e retorna o resultado
        end
    end
    

Depois é só usar onde quiser

    get '/minha_pagina' do
        meu_helper
    end
    

Simples assim. Abaixo o script atualizado usando um helper

    require 'rubygems'
    require 'sinatra'
    require 'hpricot'
    require 'open-uri'
    
    helpers do
      def episodes_form
        body = '<form method="post" action="/"><select name="link">'
    
        doc = Hpricot(open("http://podcast.rubyonrails.pro.br/"))
        (doc/'div.sub').each do |sub|
          a = sub.next_sibling.search('a').last
          if a
            (sub/'h1').each do |h1|
              number = h1.children[0].inner_text
              puts number.to_s
              if number[0] == 35 # igual a #
                body << '<option value="' + a[:href] + '">Episódio ' + number + ' - ' + h1.children[2].inner_text + '</option>'
              end
            end
          end
        end
        body << '</select><button>Ok</button></form>'
      end
    end
    
    get '/' do
      episodes_form
    end
    
    post '/' do
      body = episodes_form
    
      doc = Hpricot(open("http://podcast.rubyonrails.pro.br#{params[:link]}"))
      body << (doc/'div.content ul').last.to_html
    end
    

Para coisas muito simples, frameworks como o Sinatra ajudam bastante, deixando tudo mais prático, mas obviamente tudo tem um limite, não recomendaria ele para aplicações maiores, então, caso precise de algo "mais sério", vá de Rails :)

OBS: O código está usando Hpricot, um parser HTML, bem rápido e fácil de usar, caso você não tenha ele instalado basta fazer como sempre

    sudo gem install hpricot
    

OBS 2: Eu tinha colocado os códigos no gist, mas parece que ele não permite "embedar" diferentes revisões de um mesmo código, então resolvi tirar e colocar somente o link para lá, caso alguem queira dar uma fuçada.

http://gist.github.com/7610

Adicionando tipos de arquivo ao gedit

August 20, 2008 at 21:15

Estou testando agora o Malline, que está sendo assunto na lista rails-br, e precisei editar os templates no gedit, porém conforme eu ia renomeando os arquivos de .erb para .mn, que é a extensão do Malline, os arquivos iam desaparecendo do File Browser. Para resolver isso é simples, basta adicionar o mime-type no arquivo:

    /usr/share/mime/packages/rails.xml*
    

assim:

    <mime-type type="application/x-ruby">
        <comment xml:lang="en">Malline Template</comment>
        <glob pattern="*.mn"/>
    </mime-type>
    

salve o arquivo, feche o gedit e rode:

    sudo update-mime-database /usr/share/mime
    

abra o gedit e veja que os arquivos aparecem novamente no File Browser :)

* Não sei se esse arquivo já vem com o gedit ou se alguma extensão/plugin colocou ele ali.