<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>garotosopa</title>
	<atom:link href="http://garotosopa.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://garotosopa.wordpress.com</link>
	<description></description>
	<lastBuildDate>Fri, 27 Jan 2012 11:32:56 +0000</lastBuildDate>
	<language>pt-br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='garotosopa.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>garotosopa</title>
		<link>http://garotosopa.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://garotosopa.wordpress.com/osd.xml" title="garotosopa" />
	<atom:link rel='hub' href='http://garotosopa.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Curiosidade aleatória</title>
		<link>http://garotosopa.wordpress.com/2010/10/04/curiosidade-aleatoria/</link>
		<comments>http://garotosopa.wordpress.com/2010/10/04/curiosidade-aleatoria/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 11:46:50 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Diversos]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=1082</guid>
		<description><![CDATA[Durante um almoço recente, meu grande camarada Lawrence Lagerlof e eu tivemos uma dúvida de probabilidade, e resolvemos fazer o que qualquer homem da ciência faria: uma aposta boba. A questão girava em torno de 1 chance em 100 de algo acontecer. A declaração por si só já afirma quais as chances de acerto, mas, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=1082&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Durante um almoço recente, meu grande camarada <a href="http://twitter.com/llagerlof">Lawrence Lagerlof</a> e eu tivemos uma dúvida de probabilidade, e resolvemos fazer o que qualquer homem da ciência faria: uma aposta boba.<span id="more-1082"></span></p>
<p>A questão girava em torno de 1 chance em 100 de algo acontecer. A declaração por si só já afirma quais as chances de acerto, mas, em média, quantas tentativas realmente são necessárias pra tirar a sorte grande?</p>
<p>Eu achava que uma média não existia. Diferentes amostragens apontariam diferentes resultados, sem que fosse possível determinar com precisão a média de tentativas até conseguir um acerto.</p>
<p>Lawrence achava que não, que a média seria a metade do número de opções. Isto é, ao jogar um dado de 6 lados, seriam necessárias, em média, outras 3 jogadas pra conseguir tirar o mesmo lado.</p>
<p>Apostamos então que sortearíamos um número de 1 a 100 e calcularíamos a quantidade de vezes para achar o mesmo número, repetindo o cálculo 100.000 vezes para então tirar a média. Se a média ficasse na metade, entre 45 e 55 vezes, Lawrence ganharia a aposta. Qualquer outro resultado a vitória seria minha.</p>
<p>Assim que voltamos do almoço, preparamos o seguinte script:</p>
<div style="font-family:monaco,monospace,sans-mono,courier-new;background-color:#262626;color:#fff;border-left:2px solid #666;margin-bottom:15px;padding:.25em;"><span style="color:#bdb76b;">&lt;?php</span><br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">conjunto</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">100</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">testes</span>&nbsp;&nbsp; <span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">100000</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">numero</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">rand</span><span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">1</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">conjunto</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">soma_vezes</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;"><b>for</b></span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">i</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>; <span style="color:#ff0000;">$</span><span style="color:#fa8072;">i</span>&nbsp;<span style="color:#6495ed;"><b>&lt;</b></span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">testes</span>; <span style="color:#ff0000;">$</span><span style="color:#fa8072;">i</span><span style="color:#ff0000;">++</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;<span style="color:#6495ed;"><b>for</b></span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sorteado</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#6495ed;"><b>null</b></span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">vezes</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>; <span style="color:#ff0000;">$</span><span style="color:#fa8072;">sorteado</span>&nbsp;<span style="color:#6495ed;"><b>!==</b></span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">numero</span>; <span style="color:#ff0000;">$</span><span style="color:#fa8072;">vezes</span><span style="color:#ff0000;">++</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sorteado</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">rand</span><span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">1</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">conjunto</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">soma_vezes</span>&nbsp;<span style="color:#ff0000;">+=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">vezes</span>;<br />
<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">media</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">soma_vezes</span>&nbsp;<span style="color:#ff0000;">/</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">testes</span>;<br />
&nbsp;<br />
<span style="color:#ffd700;"><b>echo</b></span>&nbsp;&quot;<span style="color:#87ceeb;">Média: </span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">media</span><span style="color:#bdb76b;">\n</span>&quot;;</div>
<p>Para nossa surpressa, o resultado foi <strong>100</strong>.</p>
<p>Consistentemente, a quantidade média de tentativas para acertar um número dentro de um conjunto é o tamanho do próprio conjunto.</p>
<p>Logo que viu o resultado, Lawrence repensou sua aposta e concordou que realmente faz todo sentido, perdera por pura distração. Já eu estou sem entender até agora, realmente achava que não seria possível ter uma média fiel. Afinal, 1 chance em 100 pode ocorrer de primeira ou levar mil vezes pra acontecer.</p>
<p>Fizemos outros testes com conjuntos menores e maiores e o resultado era sempre 100% a quantidade de possibilidades, com apenas alguns décimos de diferença.</p>
<p>O curioso é que essa média é atingida rapidamente, nem precisa dos 100.000 testes, como demonstrado no gráfico abaixo.</p>
<p><img src="http://garotosopa.files.wordpress.com/2010/10/image_nova_editada.png?w=700" alt="" title="Média de vezes necessárias por testes realizados"   class="aligncenter size-full wp-image-1163" style="border:none;" /></p>
<p>Mas isso considerando a média aritmética, que é facilmente desequilibrada quando um teste azarado leva muito tempo para encontrar o número sorteado. Se considerarmos a moda dos resultados, ou seja, a quantidade de vezes tentadas mais observada, o gráfico fica mais favorável pro apostador.</p>
<p><img src="http://garotosopa.files.wordpress.com/2010/10/moda.png?w=700" alt="" title="Moda das vezes necessárias"   class="aligncenter size-full wp-image-1143" style="border:none;" /></p>
<p>Olhando por esse lado, sinto-me na obrigação de devolver os R$ 5 que ganhei. Até porque ele ainda acertou ao sugerir que o resultado seria previsível, enquanto eu insistia que seria sempre aleatório.</p>
<p>Devo declará-lo vencedor ou aposta é aposta?</p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/diversos/'>Diversos</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/1082/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/1082/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/1082/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/1082/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/1082/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/1082/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/1082/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/1082/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=1082&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/10/04/curiosidade-aleatoria/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2010/10/image_nova_editada.png" medium="image">
			<media:title type="html">Média de vezes necessárias por testes realizados</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2010/10/moda.png" medium="image">
			<media:title type="html">Moda das vezes necessárias</media:title>
		</media:content>
	</item>
		<item>
		<title>Vícios de linguagem (de programação)</title>
		<link>http://garotosopa.wordpress.com/2010/08/30/vicios-de-linguagem-de-programacao/</link>
		<comments>http://garotosopa.wordpress.com/2010/08/30/vicios-de-linguagem-de-programacao/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 11:41:23 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=1063</guid>
		<description><![CDATA[Esses dias o autor do PHPUnit comentou em seu blog sobre um recurso que seria adicionado ao framework que me chamou bastante atenção no aspecto da Orientação a Objetos, especialmente quanto à reação de algumas pessoas. Até então, os métodos para testar funcionalidades eram derivados da classe que o teste deve estender. Sendo assim, para [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=1063&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Esses dias o autor do <a href="http://www.phpunit.de/">PHPUnit</a> comentou em <a href="http://sebastian-bergmann.de/archives/896-PHPUnit-3.5-Less-this-Required.html">seu blog</a> sobre um recurso que seria adicionado ao framework que me chamou bastante atenção no aspecto da Orientação a Objetos, especialmente quanto à reação de algumas pessoas.<span id="more-1063"></span></p>
<p>Até então, os métodos para testar funcionalidades eram derivados da classe que o teste deve estender. Sendo assim, para acessá-los, utilizava-se <em>$this-&gt;métodoParaTestarAlgo()</em>. Um caso de teste ficava assim:</p>
<div style="background-color:#262626;color:#fff;font-family:Monaco,monospace,mono,sans;"><span style="color:#bdb76b;">&lt;?php</span><br />
<span style="color:#00ff00;">class</span>&nbsp;ExampleTest <span style="color:#00ff00;">extends</span>&nbsp;PHPUnit_Framework_TestCase <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;"><strong>public</strong></span>&nbsp;<span style="color:#ffd700;"><strong>function</strong></span>&nbsp;testEmptyArray<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">array</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#6495ed;"><strong>array</strong></span><span style="color:#bdb76b;">()</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>assertEquals<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffdead;">count</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">array</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>O novo recurso sugeria incluir um script que definia todas essas funções de teste como globais, de forma que não precisariam mais ser utilizadas no objeto <em>$this</em>, e sim diretamente:</p>
<div style="background-color:#262626;color:#fff;font-family:Monaco,monospace,mono,sans;"><span style="color:#bdb76b;">&lt;?php</span><br />
<span style="color:#ff0000;">require_once</span>&nbsp;&quot;<span style="color:#87ceeb;">PHPUnit/Framework/Assert/Functions.php</span>&quot;;<br />
&nbsp;<br />
<span style="color:#00ff00;">class</span>&nbsp;ExampleTest <span style="color:#00ff00;">extends</span>&nbsp;PHPUnit_Framework_TestCase <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;"><strong>public</strong></span>&nbsp;<span style="color:#ffd700;"><strong>function</strong></span>&nbsp;testEmptyArray<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">array</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#6495ed;"><strong>array</strong></span><span style="color:#bdb76b;">()</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffdead;">count</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">array</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>Uma das reações que surgiram nos comentários foi que esse recurso polui o escopo global, e existe uma regra santa que diz que isso não deve ser feito.</p>
<p>Na prática, o problema real é que o projeto que está sendo testado, alguma biblioteca dependente ou o próprio PHP também poderia definir funções globais com o mesmo nome, o que causaria problemas. No caso das bibliotecas não há muito o que falar, mas imagino que alguém que é contra o uso dessas funções globais no PHPUnit não teria funções globais no próprio projeto. Argumento válido, de qualquer forma.</p>
<p>O que mais me incomodou, na verdade, foram argumentos que davam a entender que os testes devem ser orientados a objetos, porque orientação a objetos é uma boa prática. Amém.</p>
<p>O problema é que esses métodos não são &#8220;orientados&#8221; ao &#8220;objeto&#8221;, no sentido literal do termo, e pra mim isso faz toda diferença &#8211; é basicamente o que distingue o certo do errado, o bem do mal, o Mestre dos Magos do Vingador, O Ryu do M. Bison, o Jacob do Monstro de Fumaça&#8230; Isso me levou a pensar que alguns autores imaginam que colocar funções numa classe e chamá-las com <em>$this</em> é uma boa prática por si só.</p>
<p>Analisando a classe PHPUnit_Framework_TestCase, ela estende a classe PHPUnit_Framework_Assert (que é onde os métodos de teste são definidos), apenas para permitir o uso destes através do <em>$this</em>. Aí que mora a raiz do problema.</p>
<p>Na verdade, TestCase não <em>é um</em> Assert, e a regra santa que proibe funções globais também diz que estende-se uma classe quando se tem um subtipo dela, e não quando se quer apenas aproveitar o funcionamento.</p>
<p>Para reafirmar este argumento, todo os métodos da classe Assert são estáticos. Isto é, o objeto <em>$this</em> não é utilizado em nenhum momento.</p>
<p>Olhando pelo aspecto da orientação a objetos, a classe TestCase <strong>não</strong> deveria estender Assert. Só que isso implicaria em chamar a função estaticamente com <em>PHPUnit_Framework_Assert::assertEquals()</em> ao invés de simplesmente <em>$this-&gt;assertEquals()</em>. <strong>Ter os métodos no objeto do caso de teste foi apenas uma praticidade, e não uma decisão de design</strong>.</p>
<p>Isso é resultado da forma como o PHP funciona, especialmente porque não havia outra forma de agrupar funções se não por classes. Em Perl, por exemplo, seria bastante válido ter o pacote PHPUnit::Framework::Assert exportando todas as funções que poderiam então ser chamadas diretamente pelo nome. Mas mesmo com o recurso recente de <a href="http://php.net/namespaces/">namespaces</a>, não seria a mesma coisa em PHP, já que <a href="http://php.net/manual/en/language.namespaces.faq.php#language.namespaces.faq.nofuncconstantuse">funções não são importadas</a>. Se bem que não parece tão ruim fazer <em>use PHPUnit\Framework\Assert</em> e chamar com <em>Assert\equals()</em>. Tá, é ruim, mas faz mais sentido que estender Assert.</p>
<p>Se alguém achar acoplado demais ter as chamadas estáticas, existem outras saídas quanto a isso. Até porque, escrever seu teste estendendo TestCase que estende Assert é igualmente acoplado. Você poderia, claro, estender outra classe que sobrescrevesse a lógica dos testes, mas seria necessário alterar a herança de todos os casos de teste, e ainda assim continuaria não tendo sentido em relação a TestCase não ser um tipo de Assert.</p>
<p>Pensando em baixo acoplamento, eu criaria uma interface <em>Assert</em> que deveria ter sua implementação injetada no caso de teste, de forma que as chamadas ficassem <em>$this-&gt;assert-&gt;equals()</em>, sem a necessidade de estender apenas para aproveitar o funcionamento. E já que estamos em uma linguagem dinâmica, seria possível inclusive que o objeto que implementa <em>Assert</em> disponibilizasse outros métodos de teste.</p>
<p>Além disso, existe um contador de testes estático na classe Assert, então fica até mais flexível que passe a ser um objeto instanciado reaproveitado em todos os casos de teste.</p>
<p>Outro argumento que li nos comentários foi sugerindo o uso de <em>fluent interfaces</em>; assim, as chamadas ficariam <em>$this-&gt;assertEquals()-&gt;assertEquals()</em>, economizando o <em>$this</em> do segundo teste em diante. Pra mim, é outro exemplo de vício da linguagem. As chamadas encadeadas, nesse caso, seriam utilizadas para esconder um problema que não deveria existir: as chamadas serem orientadas ao objeto &#8211; quando na verdade não são. Sem contar que hoje a classe é totalmente estática, então envolver <em>$this</em> no retorno para suprir a interface fluente parece fora de cogitação.</p>
<p>De qualquer forma, todos esses meus comentários são apenas uma reflexão superficial de como somos influenciados por características da linguagem. A estrutura do <a href="http://phpunit.de/">PHPUnit</a> é excelente, com ou sem funções globais, que são apenas detalhes da implementação.</p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/oop/'>OOP</a>, <a href='http://garotosopa.wordpress.com/category/php/'>PHP</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/1063/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/1063/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/1063/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/1063/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/1063/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/1063/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/1063/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/1063/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=1063&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/08/30/vicios-de-linguagem-de-programacao/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Information Schema do Oracle &#8211; Tabelas com determinada coluna</title>
		<link>http://garotosopa.wordpress.com/2010/08/06/information-schema-do-oracle-tabelas-com-determinada-coluna/</link>
		<comments>http://garotosopa.wordpress.com/2010/08/06/information-schema-do-oracle-tabelas-com-determinada-coluna/#comments</comments>
		<pubDate>Fri, 06 Aug 2010 19:09:03 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=1043</guid>
		<description><![CDATA[Dica rápida para quem precisa de algo no Oracle parecido com o Information Schema do MySQL, para consultar informações sobre a própria base de dados. No meu caso eu queria saber apenas quais tabelas tinham determinada coluna para me ajudar a identificar o impacto em cascata de apagar um registro, e a query foi bastante [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=1043&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Dica rápida para quem precisa de algo no Oracle parecido com o <a href="http://dev.mysql.com/doc/refman/5.1/en/information-schema.html">Information Schema do MySQL</a>, para consultar informações sobre a própria base de dados.<br />
<span id="more-1043"></span><br />
No meu caso eu queria saber apenas quais tabelas tinham determinada coluna para me ajudar a identificar o impacto em cascata de apagar um registro, e a query foi bastante simples:</p>
<div style="background:#eaeaea;border-left:3px solid #999;margin-bottom:1em;padding:.25em;"><span style="color:#a52a2a;"><strong>select</strong></span>&nbsp;table_name, column_name<br />
<span style="color:#6a5acd;">from</span>&nbsp;all_tab_columns<br />
<span style="color:#6a5acd;">where</span>&nbsp;owner=<span style="color:#ff00ff;">&#8216;EAD&#8217;</span>&nbsp;<span style="color:#a52a2a;"><strong>AND</strong></span>&nbsp;column_name=<span style="color:#ff00ff;">&#8216;ID_PESSOA&#8217;</span></div>
<p>Com esse resultado eu pude identificar todas as tabelas que têm a coluna <em>id_pessoa</em> e buscar pelo registro que eu viria a apagar da tabela principal.</p>
<p>Contudo, algumas tabelas referenciavam a <em>pessoa</em> mas utilizavam outro nome na coluna, como na tabela <em>mensagem</em> em que as colunas chamavam-se <em>id_remetente</em> e <em>id_destinatario</em>. Sendo assim, foi melhor buscar pela constraint em si, independente do nome da coluna:</p>
<div style="background:#eaeaea;border-left:3px solid #999;margin-bottom:1em;padding:.25em;"><span style="color:#a52a2a;"><strong>select</strong></span>&nbsp;cl1.owner, cl1.table_name, cl1.column_name<br />
<span style="color:#6a5acd;">from</span>&nbsp;all_cons_columns cl1<br />
<span style="color:#6a5acd;">join</span> all_constraints c1 <span style="color:#6a5acd;">on</span>&nbsp;cl1.constraint_name = c1.constraint_name<br />
<span style="color:#6a5acd;">join</span> all_constraints c2 <span style="color:#6a5acd;">on</span>&nbsp;c1.r_constraint_name = c2.constraint_name<br />
<span style="color:#6a5acd;">join</span> all_cons_columns cl2 <span style="color:#6a5acd;">on</span>&nbsp;c2.constraint_name = cl2.constraint_name<br />
<span style="color:#6a5acd;">where</span>&nbsp;cl2.table_name=<span style="color:#ff00ff;">&#8216;PESSOA&#8217;</span>&nbsp;<span style="color:#a52a2a;"><strong>and</strong></span>&nbsp;cl2.column_name=<span style="color:#ff00ff;">&#8216;ID&#8217;</span>&nbsp;</span></div>
<p>Como eu já havia consultado as tabelas com colunas <em>id_pessoa</em>, acabei acrescentando o critério <em>AND cl1.column_name != &#8216;ID_PESSOA&#8217;</em> para que retornasse apenas as constraints com a coluna com nome diferente apontando para a coluna <em>id</em> da tabela <em>pessoa</em>.</p>
<p>Infelizmente, tive que fazer as duas consultas separadamente, pois, tratando-se de um sistema legado, nem todas as referências tinham constraints. Agora, se alguma tabela fazia referência com uma coluna com nome diferente de <em>id_pessoa</em> e também não tinha constraint, já era :)</p>
<p>Se quiser, faça também um select na view <strong>DICT</strong> para saber tudo que tem disponível para consulta.</p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://garotosopa.wordpress.com/category/sql/'>SQL</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/1043/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=1043&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/08/06/information-schema-do-oracle-tabelas-com-determinada-coluna/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Ordem manual direto do banco</title>
		<link>http://garotosopa.wordpress.com/2010/05/10/ordem-manual-direto-do-banco/</link>
		<comments>http://garotosopa.wordpress.com/2010/05/10/ordem-manual-direto-do-banco/#comments</comments>
		<pubDate>Mon, 10 May 2010 16:36:42 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=957</guid>
		<description><![CDATA[Em determinadas consultas pode ser desejado ter os registros em ordem preestabelecida, então pra evitar fazer isso pelo código, segue uma dica rápida para ordenar manualmente com simples operadores no ORDER BY. Ao listar todos os estados do país, é possível ter o Rio de Janeiro como primeiro registro e os demais em ordem alfabética [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=957&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Em determinadas consultas pode ser desejado ter os registros em ordem preestabelecida, então pra evitar fazer isso pelo código, segue uma dica rápida para ordenar manualmente com simples operadores no <em>ORDER BY</em>.<br />
<span id="more-957"></span><br />
Ao listar todos os estados do país, é possível ter o <strong>Rio de Janeiro como primeiro registro e os demais em ordem alfabética</strong> da seguinte forma:</p>
<div style="background:#eaeaea;border-left:3px solid #ccc;font-family:Monaco,monospace,sans-mono;margin-bottom:15px;padding:.25em;"><code>SELECT * FROM estados ORDER BY <strong>uf="RJ" DESC</strong>, estado</code></div>
<div style="background:#eaeaea url('http://garotosopa.files.wordpress.com/2010/05/backbottom.png') bottom left repeat-x;border-left:3px solid #ccc;font-family:Monaco,monospace,sans-mono;margin-bottom:15px;padding:.25em .25em 20px;"><code>+----+---------------------+----------------+--------------+<br />
|&nbsp;uf&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;estado&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;capital&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;regiao&nbsp;&nbsp;&nbsp;&nbsp;|<br />
+----+---------------------+----------------+--------------+<br />
|&nbsp;RJ&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Rio&nbsp;de&nbsp;Janeiro&nbsp;&nbsp;&nbsp;|&nbsp;Rio&nbsp;de&nbsp;Janeiro&nbsp;|&nbsp;&nbsp;&nbsp;Sudeste&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;AC&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Acre&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;Rio&nbsp;Branco&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Norte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;AL&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Alagoas&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Maceió&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;Nordeste&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;AP&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Amapá&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Macapá&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Norte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;AM&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Amazonas&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manaus&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Norte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|</code></div>
<p>Observe que no <em>ORDER BY</em> foi utilizada a comparação da coluna <em>uf</em> com o texto <em>RJ</em>. Como o resultado desta operação é 1 para verdadeiro e 0 para falso e foi utilizada ordem decrescente, o Rio de Janeiro aparece no topo.</p>
<p>Também é possível ordenar todo um conjunto, como <strong>no caso de querer as regiões numa ordem específica</strong>:</p>
<div style="background:#eaeaea;border-left:3px solid #ccc;font-family:Monaco,monospace,sans-mono;margin-bottom:15px;padding:.25em;"><code>SELECT * FROM estados<br />
ORDER BY<br />
&nbsp;&nbsp;&nbsp;&nbsp;<strong>FIELD</strong>(regiao, "Sudeste", "Sul", "Centro-Oeste", "Norte", "Nordeste"),<br />
&nbsp;&nbsp;&nbsp;&nbsp;estado</code></div>
<div style="background:#eaeaea url('http://garotosopa.files.wordpress.com/2010/05/backbottom.png') bottom left repeat-x;border-left:3px solid #ccc;font-family:Monaco,monospace,sans-mono;margin-bottom:15px;padding:.25em .25em 20px;"><code>+----+---------------------+----------------+--------------+<br />
|&nbsp;uf&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;estado&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;capital&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;regiao&nbsp;&nbsp;&nbsp;&nbsp;|<br />
+----+---------------------+----------------+--------------+<br />
|&nbsp;ES&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Espírito&nbsp;Santo&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Vitória&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;Sudeste&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;MG&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Minas&nbsp;Gerais&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Belo&nbsp;Horizonte&nbsp;|&nbsp;&nbsp;&nbsp;Sudeste&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;RJ&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Rio&nbsp;de&nbsp;Janeiro&nbsp;&nbsp;&nbsp;|&nbsp;Rio&nbsp;de&nbsp;Janeiro&nbsp;|&nbsp;&nbsp;&nbsp;Sudeste&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;SP&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;São&nbsp;Paulo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;São&nbsp;Paulo&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;Sudeste&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;PR&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Paraná&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Curitiba&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sul&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;RS&nbsp;|&nbsp;&nbsp;Rio&nbsp;Grande&nbsp;do&nbsp;Sul&nbsp;&nbsp;|&nbsp;&nbsp;Porto&nbsp;Alegre&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sul&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;SC&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Santa&nbsp;Catarina&nbsp;&nbsp;&nbsp;|&nbsp;Florianópolis&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sul&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;GO&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Goiás&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;Goiânia&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Centro-Oeste&nbsp;|</code></div>
<p>Neste caso foi utilizada a função <a href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_field">FIELD</a> do MySQL. Para cada <em>regiao</em> é retornada sua posição na lista, então para Sudeste retorna 1, para Sul retorna 2, e assim por diante. Caso alguma região tivesse ficado de fora, receberia o valor 0, daí nesse caso bastaria controlar com <em>ASC</em> ou <em>DESC</em> se as não especificadas devem aparecer antes ou depois das outras.</p>
<p>Claro que é menos custoso ordenar por uma coluna já processada, mas às vezes essa forma quebra um galhão <strong>:)</strong></p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/mysql/'>MySQL</a>, <a href='http://garotosopa.wordpress.com/category/sql/'>SQL</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/957/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/957/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/957/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/957/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/957/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/957/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/957/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/957/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=957&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/05/10/ordem-manual-direto-do-banco/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Registro com resultado de GROUP BY</title>
		<link>http://garotosopa.wordpress.com/2010/05/04/registro-com-resultado-de-group-by/</link>
		<comments>http://garotosopa.wordpress.com/2010/05/04/registro-com-resultado-de-group-by/#comments</comments>
		<pubDate>Tue, 04 May 2010 18:56:00 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=868</guid>
		<description><![CDATA[Em diversos casos utilizamos GROUP BY com uma função de agregação, como MAX(), para calcular o valor dentro de cada grupo. Mas como fazer para recuperar toda linha, e não só a coluna calculada? Considerando o esquema e os dados como demonstrados na imagem abaixo, descobrir a maior quantidade de vezes que uma música de [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=868&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Em diversos casos utilizamos GROUP BY com uma função de agregação, como MAX(), para calcular o valor dentro de cada grupo. <strong>Mas como fazer para recuperar toda linha</strong>, e não só a coluna calculada?<br />
<span id="more-868"></span></p>
<p>Considerando o esquema e os dados como demonstrados na imagem abaixo, descobrir a maior quantidade de vezes que uma música de cada banda foi executada é bastante simples:</p>
<p><img src="http://garotosopa.files.wordpress.com/2010/05/tabela-artista-musica2.png?w=520&#038;h=282" alt="Artista (id, nome): (4, Epica), (8, Iron Maiden), (15, Thievery Corporation), (16, Agua de Annique); Musica (id, id_artista, nome, plays): (1, 4, Martyr of the Free World, 17), (2, 8, Lord of the Flies, 7), (3, 15, Air Batucada, 3), (5, 16, Sunny Side Up, 5), (6, 4, Unleashed, 28), (7, 8, Running Free, 9), (8, 15, Focus on Sight, 4), (9, 16, The World, 6)." title="Tabelas artista e musica" width="520" height="282" class="aligncenter" style="border:none;" /></p>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>SELECT id_artista, MAX(plays) FROM musica GROUP BY id_artista</code></div>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>+------------+------------+<br />
| id_artista | MAX(plays) |<br />
+------------+------------+<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;28&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;15&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;16&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;|<br />
+------------+------------+</code></div>
<p>O problema fica um pouco mais curioso quando queremos todo o registro de cada música, e não apenas o valor calculado de determinada coluna.</p>
<p>Intuitivamente, talvez alguém sugira incluir os outros campos na query, mas os resultados estarão <strong>incorretos</strong>:</p>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>SELECT id_artista, MAX(plays), <em><span style="color:#c00;">nome</span></em> FROM musica GROUP BY id_artista</code></div>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>+------------+------------+--------------------------+<br />
|&nbsp;id_artista&nbsp;|&nbsp;MAX(plays)&nbsp;|&nbsp;nome&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
+------------+------------+--------------------------+<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;28&nbsp;|&nbsp;Martyr&nbsp;of&nbsp;the&nbsp;Free&nbsp;World&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;|&nbsp;Lord&nbsp;of&nbsp;the&nbsp;Flies&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;15&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;|&nbsp;Air&nbsp;Batucada&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;16&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;|&nbsp;Sunny&nbsp;Side&nbsp;Up&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
+------------+------------+--------------------------+</code></div>
<p>Observe que <strong>os valores não batem</strong>. Não é <em>Martyr of the Free World</em> que tem 28 execuções; nem <em>Lord of the Flies</em> que tem 9 execuções, e assim por diante. Os valores são imprevisíveis e <strong>não representam o registro</strong> com o valor mostrado na coluna do <em>MAX(plays)</em>.</p>
<p>A solução pode ser dada de algumas formas diferentes no MySQL.</p>
<h3>Subquery dependente</h3>
<p>Uma solução simples é filtrar as músicas onde a coluna <em>plays</em> tenha o valor máximo de <em>plays</em> daquele artista, do método mais tradicional possível:</p>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>SELECT id_artista, nome, plays<br />
FROM musica AS m1<br />
WHERE plays = ( SELECT MAX(plays)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;musica&nbsp;AS&nbsp;m2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE&nbsp;m1.id_artista&nbsp;=&nbsp;m2.id_artista&nbsp;)</code></div>
<p>E o resultado é obtido como esperado:</p>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>+------------+----------------+-------+<br />
|&nbsp;id_artista&nbsp;|&nbsp;nome&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;plays&nbsp;|<br />
+------------+----------------+-------+<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;|&nbsp;Unleashed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;28&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;|&nbsp;Running&nbsp;Free&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;15&nbsp;|&nbsp;Focus&nbsp;on&nbsp;Sight&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;|<br />
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;16&nbsp;|&nbsp;The&nbsp;World&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;|<br />
+------------+----------------+-------+</code></div>
<p>Todavia, com um número grande de artistas a consulta ficará <strong>ineficiente</strong>, já que a subquery é <strong>processada para cada artista</strong>, retornando o <em>MAX(plays)</em> correspondente que então é utilizado para filtrar as músicas com este número de execuções.</p>
<h3>Tabela derivada</h3>
<p>Para não ter que calcular a subquery para cada artista, podemos calcular todos os <em>MAX(plays)</em> em uma query na cláusula <em>FROM</em> e fazer um relacionamento com o resultado, como se fosse uma tabela normal:</p>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>SELECT m1.id_artista, m1.nome, m1.plays<br />
FROM <span style="color:#00c;">musica AS m1</span><br />
<span style="color:#060;">JOIN</span> (<br />
&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;id_artista,&nbsp;<span style="color:#903;">MAX(plays)&nbsp;AS&nbsp;plays</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;musica<br />
&nbsp;&nbsp;&nbsp;&nbsp;GROUP&nbsp;BY&nbsp;id_artista&nbsp;)&nbsp;<span style="color:#060;">AS&nbsp;derivada</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ON&nbsp;<span style="color:#00c;">m1.id_artista</span>&nbsp;=&nbsp;<span style="color:#060;">derivada.id_artista</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AND&nbsp;<span style="color:#00c;">m1.plays</span>&nbsp;=&nbsp;<span style="color:#903;">derivada.plays</span></code></div>
<p>O resultado é o mesmo, mas neste caso a consulta é <strong>mais eficiente</strong>, pois o MySQL calcula todos os <em>MAX(plays)</em> em memória uma única vez e depois apenas relaciona os registros.</p>
<h3>Otimizando no caso de MIN() e MAX()</h3>
<p>O próprio <a href="http://dev.mysql.com/doc/refman/5.1/en/example-maximum-column-group-row.html">manual</a> do MySQL dá uma outra dica interessante quando o objetivo é pegar todo o registro com maior valor em determinada coluna.</p>
<p>A técnica utiliza <strong>LEFT JOIN na mesma tabela</strong> com critérios de ser o <strong>mesmo artista</strong> e ter o <strong>número de execuções maior</strong> do que o registro da tabela original.</p>
<p>Ao final, a consulta retorna <strong>apenas os registros que não foram relacionados</strong> (valor NULL no LEFT JOIN), que são os registros sem nenhum outro com número de execuções maior &#8211; ou seja, os que a coluna <em>plays</em> é na verdade <em>MAX(plays)</em> daquele artista.</p>
<div style="background-color:#eaeaea;color:#000;border-left:3px solid #ccc;margin-bottom:10px;margin-top:10px;padding:.25em;"><code>SELECT m1.id_artista, m1.nome, m1.plays<br />
FROM musica m1<br />
LEFT JOIN musica m2<br />
&nbsp;&nbsp;&nbsp;&nbsp;ON&nbsp;m1.id_artista&nbsp;=&nbsp;m2.id_artista<br />
&nbsp;&nbsp;&nbsp;AND&nbsp;m1.plays&nbsp;&lt;&nbsp;m2.plays<br />
WHERE m2.id IS NULL</code></div>
<p>Esta fica sendo então <strong>a forma mais eficiente</strong> de recuperar o registro com maior valor em determinada coluna, já que não é necessário nenhum tipo de subquery e nem mesmo GROUP BY. E se quiser o menor valor, basta trocar o sinal.</p>
<p>A dica não vale, entretanto, para outras funções de agregação, como AVG() para média. Neste caso não tem jeito senão com subquery.</p>
<h3>Referências</h3>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/example-maximum-column-group-row.html">The Rows Holding the Group-wise Maximum of a Certain Column</a></li>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/using-explain.html">Optimizing queries with EXPLAIN</a></li>
</ul>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/mysql/'>MySQL</a>, <a href='http://garotosopa.wordpress.com/category/sql/'>SQL</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/868/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/868/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/868/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/868/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/868/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/868/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/868/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/868/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=868&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/05/04/registro-com-resultado-de-group-by/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2010/05/tabela-artista-musica2.png" medium="image">
			<media:title type="html">Tabelas artista e musica</media:title>
		</media:content>
	</item>
		<item>
		<title>É contra certificação? Valeu, popstar!</title>
		<link>http://garotosopa.wordpress.com/2010/04/29/e-contra-certificacao-valeu-popstar/</link>
		<comments>http://garotosopa.wordpress.com/2010/04/29/e-contra-certificacao-valeu-popstar/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 12:00:16 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Diversos]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=771</guid>
		<description><![CDATA[De uns tempos pra cá têm surgido muitos artigos em blogs, tanto nacionais quanto estrangeiros, a respeito de como certificações são ruins, não garantem qualidade e que os profissionais não deveriam buscá-las. Cuidado! Ao ler um artigo desses, saiba quem está falando e para quem está falando. Você se encaixa no perfil de se dar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=771&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>De uns tempos pra cá têm surgido muitos artigos em blogs, tanto nacionais quanto estrangeiros, a respeito de como <strong>certificações são ruins</strong>, não garantem qualidade e que os profissionais não deveriam buscá-las.<br />
<span id="more-771"></span><br />
<strong>Cuidado!</strong></p>
<p>Ao ler um artigo desses, saiba quem está falando e para quem está falando. <strong>Você se encaixa no perfil</strong> de se dar ao luxo de não ter uma certificação?</p>
<p>Analisando um dos argumentos mais comuns dos manifestantes, está o fato de que <strong>você não gostaria de trabalhar para uma empresa que valoriza certificação</strong>. Uma empresa que provavelmente tem uma área de recursos humanos que vai contratar você como recurso e não como o artista tecnológico que você é, onde você trabalhará de 8 às 17 e terá que preencher relatórios semanalmente para gerentes que não escrevem em blogs.</p>
<p>Esse quadro diabólico geralmente está pintado junto ao seu herói, a falácia de Equipes Ágeis e <strong>empresas supostamente bacanas</strong> de se trabalhar, como Ggl<sup>*</sup> ou outras tantas modernas que avaliam o candidato tecnicamente, e não baseadas nas suas certificações e diplomas. Aqui no Brasil, dependendo do seu nicho, talvez você já tenha ouvido falar de como é legal trabalhar na Glb.com<sup>*</sup> e que lá os <strong>gerentes de TI não dão valor a certificação</strong>.</p>
<p>Ao ler um artigo desses, o profissional concorda com os argumentos por estar <strong>cansado de ser tratado como recurso</strong> em um ambiente corporativo e por ser óbvio o fato das certificações serem <strong>criadas por empresas de tecnologia a fim de ganharem mais dinheiro</strong> e terem mais valor no mercado. Sem contar quando o profissional conhece alguém certificado que não é tão bom quanto ele, que não tem certificação. <strong>O profissional se sente enganado</strong> e decide que o melhor é aderir a essa pseudo-anarquia, já que os que o fizeram estão tão felizes nos seus blogs e empregos maravilhosos.</p>
<p>Mas antes de dizer não a essa conspiração dos diplomas, sugiro que você <strong>reflita sobre quem você é</strong>. Você realmente acha que <strong>vai conseguir uma vaga nessas empresas bacanas?</strong></p>
<p>Porque o autor do tal artigo rebelde se parece com você apenas ao concordar que certificado não significa bom profissional. Mas você parou pra pensar no que ele, que é contra certificação, teve que fazer pra conseguir um bom emprego? <strong>Você tem feito o mesmo?</strong> Aliás, você parou pra pensar se ele é certificado? Porque muitos &#8211; e eu digo MUITOS! &#8211; dos que têm postado artigos contra certificação são, ironicamente, certificados em diversas tecnologias e metodologias, atendem a diversos workshops, fazem diversos cursos&#8230; E mesmo os que, de fato, não têm nenhum vínculo com a máfia dos selos geralmente são <strong>ícones na área</strong> e já conseguem provar capacidade de outras formas.</p>
<p><strong>E você?</strong> Você é líder ou pelo menos participante de alguma grande comunidade open source? Você é referência como solucionador de bugs nos maiores softwares do mercado? Você é autor de tecnologias que outras pessoas dependem? As pessoas reconhecem você em palestras? É brilhante ou tem pelo menos um portfolio impressionante?</p>
<p>Sinceramente, a maioria de nós não. <strong>Somos anônimos</strong> e só queremos um emprego, e nessas horas uma <strong>certificação pesa muito</strong> quando o RH da empresa chata vai escolher os currículos pra entrevista.</p>
<p>Então, ao invés de fechar os olhos e achar que está sendo malandro, pare e pense no que é melhor pra você. Claro que se você preferir se tornar um <strong>popstar da galerinha nerd</strong>, ótimo, vai conseguir o tal emprego bacana. <strong>Mas enquanto isso, fica esperto!</strong></p>
<p><sub>* empresas fictícias já que não respondo por nenhuma das que ouvi falar</sub></p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/diversos/'>Diversos</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/771/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/771/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/771/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/771/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/771/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/771/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/771/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/771/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=771&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/04/29/e-contra-certificacao-valeu-popstar/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>CSRF &#8211; Foi mesmo o usuário que executou isso?</title>
		<link>http://garotosopa.wordpress.com/2010/04/28/csrf-foi-mesmo-o-usuario-que-executou-isso/</link>
		<comments>http://garotosopa.wordpress.com/2010/04/28/csrf-foi-mesmo-o-usuario-que-executou-isso/#comments</comments>
		<pubDate>Wed, 28 Apr 2010 11:00:04 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Segurança]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=754</guid>
		<description><![CDATA[Cross Site Request Forgery, a técnica de submeter para outro site de forma que pareça que é o usuário autenticado que está executando a ação. Assunto já extensivamente explorado, mas pode ser novidade pra alguns. O problema ocorre da seguinte forma: 1 &#8211; usuário autentica no site alvo normalmente Imagine o funcionário chegando para trabalhar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=754&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em>Cross Site Request Forgery</em>, a técnica de submeter para outro site de forma que pareça que é o usuário autenticado que está executando a ação. Assunto já extensivamente explorado, mas pode ser novidade pra alguns.<br />
<span id="more-754"></span></p>
<p>O problema ocorre da seguinte forma:</p>
<p><strong>1 &#8211; usuário autentica no site alvo normalmente</strong></p>
<p>Imagine o funcionário chegando para trabalhar ou alguém em casa acessando seu site favorito.</p>
<p>Entra com login e senha e deixa autenticado.</p>
<p><strong>2 &#8211; link malicioso</strong></p>
<p>O usuário continua navegando até acessar um link preparado especialmente para explorar o sistema onde a vítima também está logada.</p>
<p>Neste caso, é imprescindível que o malfeitor conheça o funcionamento do sistema, o que não é difícil tratando-se de um sistema open source, algum ex-funcionário ou simplesmente alguém no mesmo sistema querendo se passar por outro usuário.</p>
<p><strong>3 &#8211; página redireciona para sistema protegido</strong></p>
<p>A página acessada pela vítima na verdade redireciona para o alvo. Algo como:</p>
<p><code>
<div style="background-color:#eaeaea;font-family:monospace,Helvetica,Arial;padding:.25em;">http://example.com/admin/delete?id=123</div>
<p></code></p>
<p>E não precisa ser um redirecionamento simples. Geralmente as ações são feitas apenas por POST, então um formulário com um submit automático também é utilizado.</p>
<p><strong>4 &#8211; ação realizada sem intenção do usuário</strong></p>
<p>Uma vez feita a requisição pelo navegador, as credenciais do usuário serão utilizadas, fazendo parecer que foi realmente o usuário que executou a ação.</p>
<p><strong>Solução? Bem, você pode utilizar tokens.</strong></p>
<h3>Tokens para evitar CSRF</h3>
<p>A idéia do token é criar uma <strong>chave</strong> no momento que a forma de acesso é oferecida e checar esta chave onde a ação é realizada.</p>
<p>Por exemplo, ao mostrar um formulário, uma chave qualquer é gerada (no controller ou alguma classe de formulários) e guardada na <strong>sessão</strong>:</p>
<p><code>
<div style="background-color:#eaeaea;font-family:monospace,Helvetica,Arial;padding:.25em;">$token = rand();<br />
$_SESSION['token'] = $token;</div>
<p></code></p>
<p>Essa mesma chave é passada para sua view e incluída no formulário como um <strong>campo oculto</strong>:</p>
<p><code>
<div style="background-color:#eaeaea;font-family:monospace,Helvetica,Arial;padding:.25em;">&lt;input type="hidden" name="token" value="&lt;?php echo $token ?&gt;" /&gt;</div>
<p></code></p>
<p>Desta forma, será possível checar se a chave guardada na sessão <strong>é a mesma submetida</strong> pelo formulário:</p>
<p><code>
<div style="background-color:#eaeaea;font-family:monospace,Helvetica,Arial;padding:.25em;">if ( ! isset($_SESSION['token'], $_POST['token']) || $_SESSION['token'] != $_POST['token'] ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;throw new Exception("Sua sessão neste formulário expirou, tente novamente.");<br />
}</div>
<p></code></p>
<p>Caso a chave esteja <strong>incorreta</strong>, notifique o usuário e <strong>mostre o formulário novamente</strong> (já preenchido, pra não ter que digitar tudo de novo). Observe que em nenhum momento a mensagem sugere que o usuário está tentando alguma fraude, até porque ele nunca faria algo do tipo contra ele mesmo.</p>
<p>No caso da chave ser <strong>válida</strong> e a ação ser executada, é importante <strong>limpar o token</strong> para exigir que o formulário seja acessado novamente e o ciclo recomece:</p>
<p><code>
<div style="background-color:#eaeaea;font-family:monospace,Helvetica,Arial;padding:.25em;">unset($_SESSION['token']);</div>
<p></code></p>
<p>Essa técnica leva em conta que o usuário <strong>primeiro acessa o formulário para depois submeter para o script</strong> que executa a ação, além de assumir que não é possível ler o conteúdo do input hidden com o token através de outro site, contando com a segurança do navegador neste ponto.</p>
<p>E sem querer, os tokens garantem ainda que <strong>a ação não será executada duas vezes</strong> caso o usuário clique em Atualizar ou Voltar e depois Avançar do navegador, já que o token resubmetido não existirá mais na sessão.</p>
<p>Se os formulários no sistema são gerados através de uma infraestrutura organizada, plugar uma validação de tokens é provavelmente <strong>transparente</strong>. Neste caso vale a pena pensar também numa forma de permitir vários formulários abertos (separando a sessão por formulário) ou até mesmo várias instâncias de um mesmo formulário, se isso for um requisito.</p>
<p>A implementação fica com você :)</p>
<h3>Um problema ao só checar o referer</h3>
<p>Outra forma de evitar esta vulnerabilidade é checar o <strong>referer</strong> (SIC) &#8211; o endereço enviado pelo navegador da página que originou o acesso. No PHP o valor está disponível na variável <i>$_SERVER['HTTP_REFERER']</i>.</p>
<p>O próprio manual sugere que esta variável <strong>não é muito confiável</strong>, pois pode não ser enviada ou ser trocada pelo usuário. Neste assunto não faz tanta diferença, já que o facínora não teria a possibilidade de alterar esta configuração na vítima.</p>
<p>Checando essa variável é possível permitir ações vindas apenas do seu <strong>próprio domínio</strong>, gerando uma mensagem de erro caso alguém em outro site clique em um botão que submeta para o seu. Inclusive, o próprio servidor web pode tratar isso, sem ter que mexer na aplicação.</p>
<p>Esta técnica, no entanto, <strong>não previne que alguém no próprio site</strong> faça algum outro usuário executar uma ação.</p>
<p>Se a ação for permitida <strong>por GET fica ainda mais fácil</strong>. Se o site permitir que usuários postem imagens, mesmo que por BBcode, o resultado é catastrófico, pois não é necessário <strong>nem clicar em nada</strong>, apenas visitar uma página comum, como um fórum, por exemplo:</p>
<p><code>
<div style="background-color:#eaeaea;font-family:monospace,Helvetica,Arial;padding:.25em;">[img]http://example.com/add_as_friend?user=diogo[/img]</div>
<p></code></p>
<p>O navegador vai fazer uma requisição GET para carregar uma imagem na url que na verdade é o script que adiciona o engraçadinho como amigo. Aparecerá a imagem quebrada, mas se o script não exigir POST e houver checagem apenas de referer, sem token, <strong>o sistema será explorado</strong>.</p>
<p>Caso todas as ações sejam executadas <strong>apenas pelo método POST</strong> (na verdade, qualquer um diferente de GET), o perigo é menor checando só o referer, já que seria necessário pelo menos um formulário manipulado no próprio site para ter sucesso no ataque. Ou javascript, mas aí existiriam problemas mais graves.</p>
<p>Então fica a dica: implemente uma arquitetura ou um framework em que seja transparente utilizar <strong>tokens para validar formulários</strong>.</p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/php/'>PHP</a>, <a href='http://garotosopa.wordpress.com/category/seguranca/'>Segurança</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/754/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/754/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/754/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/754/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/754/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/754/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/754/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/754/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=754&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/04/28/csrf-foi-mesmo-o-usuario-que-executou-isso/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Diretório criptografado com senha no Linux com EncFS</title>
		<link>http://garotosopa.wordpress.com/2010/04/24/diretorio-criptografado-com-senha-no-linux-com-encfs/</link>
		<comments>http://garotosopa.wordpress.com/2010/04/24/diretorio-criptografado-com-senha-no-linux-com-encfs/#comments</comments>
		<pubDate>Sun, 25 Apr 2010 01:47:24 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Segurança]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=739</guid>
		<description><![CDATA[Como eu venho usando apenas notebook e tenho uma tremenda cara de bobo, achei melhor criptografar alguns diretórios que merecem ser protegidos no caso de eu ser roubado &#8211; que deve acontecer, mais cedo ou mais tarde. Escolhi o EncFS ao invés de ter toda a partição home criptografada por três motivos: a home foi [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=739&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Como eu venho usando apenas notebook e tenho uma tremenda cara de bobo, achei melhor criptografar alguns diretórios que merecem ser protegidos no caso de eu ser roubado &#8211; que deve acontecer, mais cedo ou mais tarde.<br />
<span id="more-739"></span><br />
Escolhi o EncFS ao invés de ter toda a partição home criptografada por três motivos:</p>
<ul>
<li>a home foi criada sem criptografia e já está bastante cheia, não vale a pena ter que refazê-la;</li>
<li>poucos arquivos precisam de proteção, então não justifica ter toda a partição criptografada;</li>
<li>a home fica acessível se o notebook estiver em uso, então prefiro montar e desmontar um diretório protegido e torcer para não ser roubado nesse meio tempo.</li>
</ul>
<p>O EncFS funciona como uma camada entre o diretório no disco e o diretório onde ocorre a montagem com seus arquivos acessíveis, criptografando tanto o nome quanto o conteúdo ao salvar, e descriptografando ao ler.</p>
<p>Se você é nerd e acha isso interessante, leia sobre o módulo <a href="http://fuse.sourceforge.net/">FUSE</a>, que permite a criação de um sistema de arquivos virtual definido pelo seu programa.</p>
<p><strong>Instale o EncFS (como root):</strong><br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">aptitude install encfs</div>
<p></code></p>
<p><strong>Adicione o seu usuário ao grupo do FUSE (como root):</strong><br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">usermod -aG fuse <em>diogo</em></div>
<p></code></p>
<p><strong>Crie o diretório criptografado:</strong><br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">encfs ~/.crypt ~/crypt</div>
<p></code></p>
<p>O diretório <em>~/.crypt</em> é onde ficam os arquivos e diretórios criptografados, e <em>~/crypt</em> é onde você vai acessar os arquivos normalmente, ao montar com o <i>encfs</i>.</p>
<p>Talvez seja interessante utilizar um nome mais discreto pra que passe desapercebido por alguém que liste o conteúdo do seu diretório pessoal.</p>
<p>Na primeira chamada é realizada a configuração. Fiz conforme respondido abaixo:<br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">The directory "/home/diogo/.crypt/" does not exist. Should it be created? (y,n) <span style="color:#c00;"><strong>y</strong></span><br />
The directory "/home/diogo/crypt/" does not exist. Should it be created? (y,n) <span style="color:#c00;"><strong>y</strong></span><br />
Please choose from one of the following options:<br />
 enter "x" for expert configuration mode,<br />
 enter "p" for pre-configured paranoia mode,<br />
 anything else, or an empty line will select standard mode.<br />
?&gt; <span style="color:#c00;"><strong>p</strong></span></div>
<p></code></p>
<p>Em seguida é necessário digitar a senha de acesso, e pronto.</p>
<p>Pode ser que ocorra mensagem de permissão negada no FUSE:<br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">fuse: failed to open /dev/fuse: Permission denied</div>
<p></code></p>
<p>Isso porque o grupo foi adicionado e a sessão ainda não foi atualizada. Tente o seguinte com o seu nome de usuário:<br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">su - <em>diogo</em></div>
<p></code></p>
<p><strong>Para acessar o diretório criptografado:</strong><br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">encfs ~/.crypt ~/crypt</div>
<p></code></p>
<p>Nesse momento a senha de acesso é pedida; trate de não esquecer, pois não é possível recuperá-la.</p>
<p><strong>E para desmontar quando terminar de usar:</strong><br />
<code>
<div style="background-color:#bbb;font-family:monospace;padding:.25em;">fusermount -u ~/crypt</div>
<p></code></p>
<p>Repare que dentro do diretório criptografado ~/.crypt foi criado o arquivo <i><strong>.encfs6.xml</strong></i>. Guarde-o com sua própria vida, pois sem ele você não conseguirá mais acessar o diretório protegido.</p>
<p>E é isso. Talvez alguém argumente que pode não ser totalmente seguro no caso de um estudo direcionado, mas já é um alívio no caso de um roubo aleatório do equipamento.</p>
<br />Filed under: <a href='http://garotosopa.wordpress.com/category/linux/'>Linux</a>, <a href='http://garotosopa.wordpress.com/category/seguranca/'>Segurança</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/739/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=739&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2010/04/24/diretorio-criptografado-com-senha-no-linux-com-encfs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>C++ na web com FastCGI e Nginx</title>
		<link>http://garotosopa.wordpress.com/2009/12/31/cpp-na-web-com-fastcgi-e-nginx/</link>
		<comments>http://garotosopa.wordpress.com/2009/12/31/cpp-na-web-com-fastcgi-e-nginx/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 21:15:13 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[C++]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=717</guid>
		<description><![CDATA[Em tempos em que só se ouve falar em linguagens interpretadas, linguagens que rodam na JVM e linguagens funcionais, voltei um pouco ao básico. Como já estava muito tempo sem fazer nada durante o Natal, resolvi testar como seria hoje o desenvolvimento web com C++. O primeiro passo foi conseguir conectar a entrada e saída [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=717&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Em tempos em que só se ouve falar em linguagens interpretadas, linguagens que rodam na JVM e linguagens funcionais, voltei um pouco ao básico.<br />
<span id="more-717"></span><br />
Como já estava muito tempo sem fazer nada durante o Natal, resolvi testar como seria hoje o desenvolvimento web com C++.</p>
<p>O primeiro passo foi conseguir conectar a entrada e saída da aplicação com o servidor web, e é o que segue relatado abaixo.</p>
<h2>Biblioteca do FastCGI</h2>
<p>Em um ambiente mais alto nível, como PHP com mod_php, é natural que a saída seja pelo servidor web até um browser e que exista alguma interface para acesso aos dados de entrada.</p>
<p>Felizmente, utilizando a API do FastCGI essa comunicação não é nada trabalhosa.</p>
<p>Para instalar a biblioteca de desenvolvimento no Debian:</p>
<div style="background-color:#333;color:#fff;font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';margin:1em 0;padding:.5em;"><span style="color:#f00;">#</span> aptitude install libfcgi-dev</div>
<p>E para utilizá-la no programa C++:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">#include </span><span style="color:#87ceeb;">&quot;fcgio.h&quot;</span><br />
&nbsp;<br />
<span style="color:#6495ed;">int</span>&nbsp;main() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// Objeto da requisição</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;FCGX_Request request;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// Inicializa a biblioteca</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;FCGX_Init();<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// Inicializa o objeto de requisição</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// passando o file descriptor que vai utilizar para comunicação (stdin)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// e nenhuma flag de configuração</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;FCGX_InitRequest(&amp;request, <span style="color:#ffa0a0;">0</span>, <span style="color:#ffa0a0;">0</span>);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// Processa todas as requisições</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">while</span>&nbsp;( FCGX_Accept_r(&amp;request) == <span style="color:#ffa0a0;">0</span>&nbsp;) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// Constrói o buffer com base na estrutura de stream da requisição</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fcgi_streambuf cout_fcgi_streambuf(request.out);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// Altera o stream padrão para uso em toda aplicação</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout.rdbuf(&amp;cout_fcgi_streambuf);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#666666;">// E o tão esperado Oi</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout &lt;&lt; <span style="color:#87ceeb;">&quot;Content-type: text/html</span><span style="color:#bdb76b;">\r\n</span><span style="color:#87ceeb;">&quot;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#87ceeb;">&quot;</span><span style="color:#bdb76b;">\r\n</span><span style="color:#87ceeb;">&quot;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#87ceeb;">&quot;&lt;h1&gt;Hello world :)&lt;/h1&gt;&quot;</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
}</div>
<p>A alteração do buffer de saída teria que ser feita também para os buffers de entrada e erro, tão logo estes forem necessários.</p>
<p>Em uma aplicação web verdadeira, este programa funcionaria como front controller, distribuindo as requisições para as classes responsáveis.</p>
<p>Para compilar é preciso ainda linkar a biblioteca do FastCGI:</p>
<div style="background-color:#333;color:#fff;font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';margin:1em 0;padding:.5em;"><span style="color:#0c0;">$</span> g++ hello.cpp -lfcgi++ -o hello</div>
<h2>Iniciando o processo</h2>
<p>O programa compilado é capaz de receber requisições através da API do FastCGI, mas para isso ele precisa ser iniciado e conectado a um Unix Socket ou porta TCP.</p>
<p>O próprio FastCGI dispõe de um utilitário para esta tarefa chamado <em>cgi-fcgi</em>. No Debian ele é instalado pelo pacote <em>libfcgi0ldbl</em>, que já deve estar instalado como dependência da <em>libfcgi-dev</em>.</p>
<p>Antes de executar o utilitário, é importante ter certeza que o usuário tem permissão de execução no binário do programa compilado e que o usuário do servidor web (<em>www-data</em> no Debian) terá acesso ao arquivo de socket criado.</p>
<p>É uma boa idéia também que o processo seja executado com o usuário do servidor web para não expor a segurança do sistema, da mesma forma como funciona linguagens de script que rodam no Apache, por exemplo.</p>
<p>Então para iniciar o processo:</p>
<div style="background-color:#333;color:#fff;font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';margin:1em 0;padding:.5em;"><span style="color:#f00;">#</span> sudo -u www-data cgi-fcgi -start -connect /tmp/hello.sock ./hello</div>
<p>O comando utiliza o usuário do servidor web para iniciar o processo (<em>www-data</em>), criando o socket no caminho <em>/tmp/hello.sock</em> e assumindo que o binário do programa compilado está no diretório atual.</p>
<p>Observe ainda que esta etapa de criar a comunicação por socket ou porta TCP é referente a qualquer serviço FastCGI, como no caso do Rails, Django ou até mesmo PHP, que gerenciam os processos sem utilizar o utilitário acima.</p>
<h2>Configurando o Nginx</h2>
<p>Uma vez criado o socket é necessário que um servidor web disponibilize o serviço por HTTP.</p>
<p>Com o uso da biblioteca do FastCGI, qualquer servidor web compatível pode ser utilizado, como Apache, Lighttpd, IIS, e nesse caso, o Nginx.</p>
<p>Para instalá-lo no Debian:</p>
<div style="background-color:#333;color:#fff;font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';margin:1em 0;padding:.5em;"><span style="color:#f00;">#</span> aptitude install nginx</div>
<p>Caso já exista um servidor web instalado, talvez você queira remover a configuração do site padrão do Nginx que também utiliza a porta 80:</p>
<div style="background-color:#333;color:#fff;margin:1em 0;padding:.5em;"><span style="color:#f00;">#</span> rm /etc/nginx/sites-enabled/default</div>
<p>E para configurar o programa criado, crie o seguinte arquivo de configuração em <strong><em>/etc/nginx/sites-enabled/hello</em></strong>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#fa8072;">server</span>&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">listen</span>&nbsp;8800;<br />
<span style="background-color:#262626;"><span style="color:#ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="color:#6495ed;">location</span><span style="background-color:#262626;"><span style="color:#ffffff;">&nbsp;/ {</span></span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#fa8072;">fastcgi_pass</span>&nbsp;&nbsp;&nbsp;&nbsp;unix:/tmp/hello.sock;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">include</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /etc/nginx/fastcgi_params;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p>Em seguida, reinicie o Nginx:</p>
<div style="background-color:#333;color:#fff;font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';margin:1em 0;padding:.5em;"><span style="color:#f00;">#</span> /etc/init.d/nginx restart</div>
<p>E como a configuração foi na porta <em>8800</em>, basta acessar <em>http://localhost:8800</em> e pronto :)</p>
<h2>Próximos passos</h2>
<p>Agora que o programa já está na web, o próximo passo é achar as bibliotecas necessárias para uma aplicação web completa.</p>
<h3>Interface com HTTP</h3>
<p>Para simplificar a comunicação com o protocolo HTTP, o projeto <a href="http://www.gnu.org/software/cgicc/">Cgicc</a> provê uma boa API para acessar os parâmetros GET e POST, upload de arquivos e cookies, além de métodos para renderizar HTML da feiosa forma antiga.</p>
<h3>Templates</h3>
<p>Na saída de dados o ideal mesmo continua sendo algum template engine, especialmente porque recompilar o programa a cada mudança de layout seria um caos. Existem algumas opções como <a href="http://www.clearsilver.net/">ClearSilver</a>, <a href="http://code.google.com/p/google-ctemplate/">CTemplate</a> ou <a href="http://ctpp.havoc.ru/en/">CTPP</a>, sendo este último o mais parecido com o que se tem hoje em dia em outras linguagens.</p>
<h3>Sessão</h3>
<p>Para sessão não cheguei a procurar nenhuma biblioteca, até porque com acesso ao cookie para controle do SID e acesso a um backend como Memcached, a implementação é bastante simples.</p>
<h3>Banco de dados</h3>
<p>Em relaçao a ORM eu não cheguei a me preocupar, já que minhas experiências com C++ provavelmente serão muito breves, mas parece que são poucas as opções.</p>
<p>Nos testes que fiz, utilizei diretamente a <a href="http://tangentsoft.net/mysql++/">API do MySQL</a>.</p>
<h3>Framework</h3>
<p>E para os que buscam um framework completo, existe o <a href="http://www.webtoolkit.eu">Wt</a>. Não cheguei a testar mas parece bastante ativo.</p>
<h2>No final das contas</h2>
<p>Mesmo parecendo extremamente absurdo utilizar C++ na web, os únicos problemas numa empreitada dessas seriam falta de profissionais, falta de portabilidade e falta de bibliotecas, sendo esta última a mais preocupante. Na complexidade de código, parece bastante viável.</p>
<p>Contudo, pra quem precisa de performance, e eu diria que esse seria o maior motivo para utilizar C++, provavelmente todo mundo concordaria que Java é uma melhor opção, já que não apresenta os problemas citados acima. Exceto, claro, em um ambiente com recursos limitados como em desenvolvimento para embarcados.</p>
<p>De qualquer forma, vou deixar alguns programas pessoais em C++/FastCGI rodando localmente e ver no que vai dar. É impressionante <del>para um nerd</del> a velocidade de resposta com tão pouco uso de memória :)</p>
<br />Publicado em C++  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/717/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/717/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/717/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/717/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/717/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/717/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/717/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/717/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=717&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/12/31/cpp-na-web-com-fastcgi-e-nginx/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Flexibilidade não é gambiarra</title>
		<link>http://garotosopa.wordpress.com/2009/12/22/flexibilidade-nao-e-gambiarra/</link>
		<comments>http://garotosopa.wordpress.com/2009/12/22/flexibilidade-nao-e-gambiarra/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 13:49:37 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=707</guid>
		<description><![CDATA[Como a maioria dos programadores, já trabalhei com sistemas legados com um histórico de soluções rápidas não muito ortodoxas, mas comecei a tentar colocar ordem na casa. Numa época não muito distante, em um sistema de gestão acadêmica, era possível encontrar trechos como if ( $codi_cur == &#8216;PF&#8217; ) para diferenciar a lógica para determinado [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=707&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Como a maioria dos programadores, já trabalhei com sistemas legados com um histórico de soluções rápidas não muito ortodoxas, mas comecei a tentar colocar ordem na casa.<br />
<span id="more-707"></span><br />
Numa época não muito distante, em um sistema de gestão acadêmica, era possível encontrar trechos como if ( $codi_cur == &#8216;PF&#8217; ) para diferenciar a lógica para determinado curso.</p>
<p>Pensar nesses if&#8217;s nas reuniões de requisito era um caos, tanto para os programadores quanto para os gerentes de TI, já sabendo a dificuldade de manutenção. Sem contar a decepção do usuário que tinha que trabalhar com um sistema engessado quando a solicitação não podia ser atendida.</p>
<p>Mas de uns tempos pra cá, a abordagem das soluções tem mudado.</p>
<p>Vou tentar relatar resumidamente como tratamos uma dessas solicitações de forma que não parecesse uma gambiarra e facilitasse a manutenção, possibilitando novas lógicas sem acrescentar complexidade.</p>
<p>Imagino que ninguém vai se enquadrar no mesmo caso que o nosso, mas acho que a técnica pode ser útil em qualquer situação.</p>
<h3>A realidade</h3>
<p>Como parte de um sistema de gestão acadêmica, o relatório de desempenho escolar deve exibir os alunos da turma, suas notas em todas as avaliações do curso e a nota final de cada um deles.</p>
<p>Por longos anos, a nota final do aluno se resumia à média ponderada das notas de todas as suas avaliações.</p>
<p>Um exemplo de código simplificado para cálculo da média ponderada seria algo assim:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#666666;">// meio do código referente ao desempenho escolar</span><br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notas</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">pesos</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span><span style="color:#00ff00;">-&gt;</span>getAvaliacoes<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notas</span>&nbsp;<span style="color:#ff0000;">+=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span><span style="color:#00ff00;">-&gt;</span>getNota<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span>&nbsp;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">pesos</span>&nbsp;<span style="color:#ff0000;">+=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span><span style="color:#00ff00;">-&gt;</span>getPeso<span style="color:#bdb76b;">()</span>;<br />
<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notaFinal</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notas</span>&nbsp;<span style="color:#ff0000;">/</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">pesos</span>;<br />
&nbsp;<br />
<span style="color:#666666;">// continuação do código do desempenho escolar</span></div>
<h3>O requisito</h3>
<p>Certo dia, a coordenação decidiu que determinado curso não utilizaria média ponderada para atribuir a nota final do aluno, uma vez que a proposta pedagógica do curso era diferente.</p>
<p>Seis meses depois, com o curso já sendo concluído, a TI foi avisada que o sistema precisaria ser alterado.</p>
<p>Para simplificar o exemplo aqui, vamos assumir que a nota final do aluno deste curso, e somente no caso deste curso, devesse ser apenas sua melhor nota, e não a média das avaliações.</p>
<p>A idéia então é que SE for ESTE curso, utiliza a melhor nota, SENÃO calcula a média ponderada.</p>
<p>Implementar uma condição ali mesmo, e possíveis outras no futuro, deixaria esse trecho do código extremamente sujo, difícil de manter e mais chato para ser testado.</p>
<p>A solução então foi abstrair a lógica em uma interface de cálculo de nota final, de forma que este trecho do código não precisasse se importar com a implementação.</p>
<p>O mesmo código acima passou a ficar assim:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#666666;">// código referente ao desempenho escolar</span><br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notaFinal</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>calculoNotaFinal<span style="color:#00ff00;">-&gt;</span>getNotaFinal<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span>&nbsp;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#666666;">// continuação do código do desempenho escolar</span></div>
<p>Ou seja, a classe que trata o desempenho escolar passa a receber um objeto que calcula a nota final, dada a grade e o aluno. Estamos delegando a responsabilidade.</p>
<h3>A implementação</h3>
<p>O primeiro passo para tornar isso possível, na perspectiva de orientação a objetos, é definir a interface de cálculo da nota final:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#00ff00;">interface</span>&nbsp;CalculoNotaFinal <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;getNotaFinal<span style="color:#bdb76b;">(</span>Grade <span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span>, Aluno <span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Com essa interface, o objeto responsável por calcular a nota final deve implementar o método getNotaFinal, que recebe a grade e o aluno em questão, exatamente como utilizamos no código anterior.</p>
<p>Para receber o objeto já instanciado, nossa classe de desempenho escolar passa a ter:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#6495ed;">protected</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">calculoNotaFinal</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;setCalculoNotaFinal<span style="color:#bdb76b;">(</span>CalculoNotaFinal <span style="color:#ff0000;">$</span><span style="color:#fa8072;">calculoNotaFinal</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>calculoNotaFinal&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">calculoNotaFinal</span>;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Em seguida, criamos as implementações concretas, começando pelo código que foi removido no passo anterior:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#00ff00;">class</span>&nbsp;MediaPonderada <span style="color:#00ff00;">implements</span>&nbsp;CalculoNotaFinal <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;getNotaFinal<span style="color:#bdb76b;">(</span>Grade <span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span>, Aluno <span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notas</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">pesos</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span><span style="color:#00ff00;">-&gt;</span>getAvaliacoes<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notas</span>&nbsp;<span style="color:#ff0000;">+=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span><span style="color:#00ff00;">-&gt;</span>getNota<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span>&nbsp;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">pesos</span>&nbsp;<span style="color:#ff0000;">+=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span><span style="color:#00ff00;">-&gt;</span>getPeso<span style="color:#bdb76b;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">media</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">notas</span>&nbsp;<span style="color:#ff0000;">/</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">pesos</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">media</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>E depois a forma nova de calcular a nota final:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#00ff00;">class</span>&nbsp;MelhorNota <span style="color:#00ff00;">implements</span>&nbsp;CalculoNotaFinal <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;getNotaFinal<span style="color:#bdb76b;">(</span>Grade <span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span>, Aluno <span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">melhorNota</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">grade</span><span style="color:#00ff00;">-&gt;</span>getAvaliacoes<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">nota</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">aluno</span><span style="color:#00ff00;">-&gt;</span>getNota<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">avaliacao</span>&nbsp;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">if</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">nota</span>&nbsp;<span style="color:#6495ed;">&gt;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">melhorNota</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">melhorNota</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">nota</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">melhorNota</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>E pronto, as duas lógicas estão separadas em classes simples, fáceis de entender à primeira vista e fáceis de serem testadas com testes unitários e mock objects.</p>
<h3>Fabricando o objeto correto</h3>
<p>Fica faltando, entretanto, uma forma de determinar qual curso utiliza qual lógica de cálculo.</p>
<p>Voltando ao código legado, isso seria feito à base de if ( $codi_cur == &#8216;VS&#8217; ), else; mas queremos nos livrar desse tipo de solução e tornar o sistema mais plugável, sem precisar de gambiarra para implementações futuras.</p>
<p>Na implementação que fizemos, uma classe ficou responsável por receber o curso, instanciar e retornar o objeto correto, que em seguida era injetado onde precisamos, de forma que o script final ficasse assim:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">calculoNotaFinal</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;CalculoNotaFinalFactory<span style="color:#ff0000;">::</span>build<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">curso</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">desempenhoEscolar</span><span style="color:#00ff00;">-&gt;</span>setCalculoNotaFinal<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">calculoNotaFinal</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">desempenhoEscolar</span><span style="color:#00ff00;">-&gt;</span>processar<span style="color:#bdb76b;">()</span>;</div>
<p>Para identificar o objeto correto, criamos uma tabela no banco de dados com as classes que existem para cálculo de nota final e alteramos a tabela de cursos, para ter uma dessas classes associadas.</p>
<p>Considerando o uso de algum ORM, a idéia da classe é a seguinte:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#00ff00;">class</span>&nbsp;CalculoNotaFinalFactory <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#6495ed;">static</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;build<span style="color:#bdb76b;">(</span>Curso <span style="color:#ff0000;">$</span><span style="color:#fa8072;">curso</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">classe</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">curso</span><span style="color:#00ff00;">-&gt;</span>calculoNotaFinal<span style="color:#00ff00;">-&gt;</span>classe;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">include</span>&nbsp;&quot;<span style="color:#87ceeb;">class/</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">classe</span><span style="color:#87ceeb;">.php</span>&quot;;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">classe</span><span style="color:#bdb76b;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>Na prática, este código até poderia ficar direto no desempenho escolar, que é onde o objeto é utilizado, mas seria responsabilidade demais para a classe. Desta forma cada pequeno pedaço tem sua responsabilidade.</p>
<p>A tabela com as classes foi algo como:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#6495ed;">CREATE</span>&nbsp;<span style="color:#6495ed;">TABLE</span>&nbsp;calculo_nota_final (<br />
&nbsp;&nbsp;&nbsp;&nbsp;id <span style="color:#6495ed;">INT</span>&nbsp;<span style="color:#6495ed;">UNSIGNED</span>&nbsp;<span style="color:#6495ed;">NOT</span>&nbsp;<span style="color:#bdb76b;">NULL</span>&nbsp;<span style="color:#6495ed;">AUTO_INCREMENT</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;classe <span style="color:#6495ed;">VARCHAR(</span><span style="color:#ffa0a0;">64</span><span style="color:#6495ed;">)</span>&nbsp;<span style="color:#6495ed;">NOT</span>&nbsp;<span style="color:#bdb76b;">NULL</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;descricao <span style="color:#6495ed;">VARCHAR(</span><span style="color:#ffa0a0;">128</span><span style="color:#6495ed;">)</span>&nbsp;<span style="color:#6495ed;">NOT</span>&nbsp;<span style="color:#bdb76b;">NULL</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">PRIMARY</span>&nbsp;<span style="color:#6495ed;">KEY</span>&nbsp;(id),<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">UNIQUE</span>&nbsp;<span style="color:#6495ed;">KEY</span>&nbsp;(classe)<br />
);<br />
&nbsp;<br />
<span style="color:#6495ed;">INSERT</span>&nbsp;<span style="color:#6495ed;">INTO</span>&nbsp;calculo_nota_final (classe, descricao) <span style="color:#6495ed;">VALUES</span><br />
(<span style="color:#87ceeb;">&#039;MediaPonderada&#039;</span>, <span style="color:#87ceeb;">&#039;Média ponderada das notas de todas as avaliações&#039;</span>),<br />
(<span style="color:#87ceeb;">&#039;MelhorNota&#039;</span>, <span style="color:#87ceeb;">&#039;Utiliza a melhor nota do aluno como sua nota final&#039;</span>);</div>
<p>E a alteração na tabela de curso:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#6495ed;">ALTER</span>&nbsp;<span style="color:#6495ed;">TABLE</span>&nbsp;curso<br />
<span style="color:#6495ed;">ADD</span>&nbsp;<span style="color:#6495ed;">COLUMN</span>&nbsp;id_calculo_nota_final <span style="color:#6495ed;">INT</span>&nbsp;<span style="color:#6495ed;">UNSIGNED</span>,<br />
<span style="color:#6495ed;">ADD</span>&nbsp;<span style="color:#6495ed;">FOREIGN</span>&nbsp;<span style="color:#6495ed;">KEY</span>&nbsp;(id_calculo_nota_final) <span style="color:#6495ed;">REFERENCES</span>&nbsp;calculo_nota_final(id)<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">ON</span>&nbsp;<span style="color:#6495ed;">DELETE</span>&nbsp;<span style="color:#6495ed;">RESTRICT</span>&nbsp;<span style="color:#6495ed;">ON</span>&nbsp;<span style="color:#6495ed;">UPDATE</span>&nbsp;<span style="color:#6495ed;">CASCADE</span><br />
;</div>
<p>Feito isso, bastou configurar todos os cursos já existentes como média ponderada (que é como funcionava antes) e o curso novo com a classe de melhor nota.</p>
<p>Por último, a interface para cadastro de cursos foi alterada e agora tem uma opção para selecionar a forma que a nota final é calculada.</p>
<p>Caso um dia o pedagógico invente outra lógica de cálculo, basta criar a classe, inserir na tabela e configurar o curso pelo próprio sistema.</p>
<h3>Moral da história</h3>
<ul>
<li>Delegar lógicas diferentes para classes especializadas;</li>
<li>Tornar configurável a escolha da lógica;</li>
<li>Carregar as classes dinamicamente;</li>
<li>Injetar a implementação concreta onde apenas a interface é esperada.</li>
</ul>
<br />Publicado em OOP, PHP  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/707/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/707/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/707/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/707/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/707/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/707/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/707/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/707/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=707&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/12/22/flexibilidade-nao-e-gambiarra/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Alterando software livre do jeito Debian &#8211; Patch pro Transmission</title>
		<link>http://garotosopa.wordpress.com/2009/10/05/alterando-software-livre-jeito-debian-patch-transmission/</link>
		<comments>http://garotosopa.wordpress.com/2009/10/05/alterando-software-livre-jeito-debian-patch-transmission/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 12:00:34 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=682</guid>
		<description><![CDATA[Um dos argumentos dos evangelistas de software livre é que, tendo acesso ao código fonte do programa, você altera o que quiser. Mas quem tem o mínimo de experiência em desenvolvimento sabe que o processo é um pouquinho trabalhoso. Primeiro você baixa o código fonte do repositório oficial (às vezes tendo que baixar um programa [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=682&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Um dos argumentos dos evangelistas de software livre é que, tendo acesso ao código fonte do programa, você altera o que quiser. Mas quem tem o mínimo de experiência em desenvolvimento sabe que o processo é um pouquinho trabalhoso.<br />
<span id="more-682"></span></p>
<p>Primeiro você baixa o código fonte do repositório oficial (às vezes tendo que baixar um programa diferente de controle de versão), baixa todos os pacotes de desenvolvimento dependentes (quando eles dizem quais são), se familiariza com o código fonte (mesmo sem documentação), aprende uma nova linguagem e todas as APIs necessárias, tenta alterar e depois fica compilando até que tudo funcione (o que às vezes não ocorre).</p>
<p>Eu não sei vocês, mas só de imaginar tudo isso eu <strong><span style="font-weight:normal;background-color:#df8;">prefiro esperar</span></strong> e torcer pra que a funcionalidade que eu quero esteja disponível na versão seguinte.</p>
<p>Só que isso faz de você um <strong><span style="font-weight:normal;background-color:#df8;">mau menino</span></strong>, e os nerds olham feio pra você nos eventos de tecnologia e nas listas de discussão.</p>
<p>Abaixo você verá algumas <strong><span style="font-weight:normal;background-color:#df8;">etapas simples</span></strong> de como começar a <strong><span style="font-weight:normal;background-color:#df8;">alterar softwares</span></strong> utilizando os pacotes de <strong><span style="font-weight:normal;background-color:#df8;">source do Debian</span></strong> (Ubuntu ou qualquer derivado), através de passos reais que segui para adicionar uma pequena funcionalidade ao <a href="http://www.transmissionbt.com/">Transmission</a>, mesmo sem conhecer nada de C, Gtk ou do código fonte do programa (na verdade, ainda nem comecei, estou escrevendo o post e fazendo).</p>
<p>Prepare-se para <strong><span style="font-weight:normal;background-color:#df8;">impressionar as gatinhas</span></strong>!</p>
<h3>Baixando o código fonte e todas as dependências</h3>
<p>Antes de começar qualquer projeto de pacote Debian em C, é fundamental que você tenha o <em>essencial para construção</em> instalado, que inclui <strong><span style="font-weight:normal;background-color:#df8;">compilador e biblioteca para criar pacotes</span></strong>, além do pacote <em>fakeroot</em>, necessário ao montar o pacote no final de todas as etapas:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/home/diogo/transmission# <strong><span style="background-color:#df8;">aptitude install build-essential fakeroot</span></strong></pre>
</div>
<p>Em seguida, baixe o <strong><span style="font-weight:normal;background-color:#df8;">fonte do programa</span></strong> que deseja alterar; no meu caso, o Transmission:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong><span style="background-color:#df8;">apt-get source transmission</span></strong></pre>
</div>
<p>O comando <em>apt-get source</em> deve ser feito com o seu usuário mesmo, e não como root, apenas para baixar o código fonte no diretório atual.</p>
<p>Ao terminar, você terá os arquivos abaixo e todo o código fonte no diretório <em>transmission-1.75</em>:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>ls -l</strong>
total 6568
drwxr-x--- 15 diogo diogo    4096 2009-10-03 13:01 transmission-1.75
-rw-r-----  1 diogo diogo   17251 2009-09-20 19:30 transmission_1.75-1.diff.gz
-rw-r-----  1 diogo diogo    1519 2009-09-20 19:30 transmission_1.75-1.dsc
-rw-r-----  1 diogo diogo 6681496 2009-09-20 19:30 transmission_1.75.orig.tar.gz</pre>
</div>
<p>Depois, como root, é necessário instalar no sistema todas as <strong><span style="font-weight:normal;background-color:#df8;">bibliotecas necessárias para compilar</span></strong> o programa:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/home/diogo/transmission# <strong><span style="background-color:#df8;">apt-get build-dep transmission</span></strong></pre>
</div>
<p>Aqui foi necessário baixar 70 pacotes (27MB) com todos os cabeçalhos (arquivos .h) e demais dependências necessárias. Talvez você queira copiar a lista de pacotes que o <em>apt-get</em> mostrou para poder removê-los depois de compilar o programa.</p>
<p>Finalizando, apenas para concluir o fluxo, assim que quiser <strong><span style="font-weight:normal;background-color:#df8;">compilar o programa e montar um pacote</span></strong>, basta executar o comando abaixo, a partir do diretório dos arquivos fonte:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">dpkg-buildpackage -rfakeroot -uc -b</span></strong></pre>
</div>
<p>O <strong><span style="font-weight:normal;background-color:#df8;">pacote <em>.deb</em> será gerado</span></strong> no diretório acima e poderá ser instalado com <em>dpkg -i nomedopacote.deb</em>.</p>
<h3>Alterando o código fonte</h3>
<p>Já tenho o código fonte e já sei como montar o pacote, mas <strong><span style="font-weight:normal;background-color:#df8;">não faço a menor idéia de como alterar</span></strong> o programa. Tentemos assim mesmo.</p>
<p>Sabendo que o Transmission é um cliente de torrent, o recurso que quero adicionar é poder <strong><span style="font-weight:normal;background-color:#df8;">salvar os arquivos no mesmo diretório onde está localizado o .torrent</span></strong>. Para isso, a idéia é incluir uma opção na tela de configuração como na montagem abaixo em vermelho:</p>
<p><img src="http://garotosopa.files.wordpress.com/2009/10/samedirectory.png?w=700" alt="Included the checkbox: Save to the same directory as torrent file" title="Save to the same directory as torrent file"   class="size-full wp-image-685" /></p>
<p>Antes de começar a bagunçar o código fonte que baixamos, é interessante fazer uma cópia do original para facilitar a geração de um <em>patch</em> depois:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">cp -r transmission-1.75/ transmission-1.75-original</span></strong></pre>
</div>
<p>Dando uma olhada no diretório do código fonte, temos o seguinte:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong>ls -F</strong>
aclocal.m4     configure*    <strong><span style="font-weight:normal;background-color:#df8;">gtk/</span></strong>              Makefile.am  third-party/
AUTHORS        configure.ac  INSTALL           Makefile.in  transmission.spec.in
autogen.sh*    COPYING       install-sh*       missing*     Transmission.xcodeproj/
ChangeLog      daemon/       libtransmission/  NEWS         update-version-h.sh*
cli/           debian/       ltmain.sh*        po/          web/
config.guess*  depcomp*      m4/               qt/
config.sub*    doc/          macosx/           README</pre>
</div>
<p>Como estou interessado em alterar a interface Gtk, vamos ao seu diretório:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75/gtk$ <strong>ls -F</strong>
actions.c     icons.h         sexy-icon-entry.c        tr-core.h
actions.h     lock.h          sexy-icon-entry.h        tr-icon.c
add-dialog.c  logo.h          sexy-marshal.c           tr-icon.h
add-dialog.h  main.c          sexy-marshal.h           tr-prefs.c
<strong><span style="font-weight:normal;background-color:#df8;">conf.c</span></strong>        Makefile.am     stats.c                  tr-prefs.h
conf.h        Makefile.in     stats.h                  tr-torrent.c
details.c     makemeta-ui.c   torrent-cell-renderer.c  tr-torrent.h
details.h     makemeta-ui.h   torrent-cell-renderer.h  tr-window.c
dialogs.c     marshal.list    tracker-list.c           tr-window.h
dialogs.h     msgwin.c        tracker-list.h           turtles.h
file-list.c   msgwin.h        transmission.1           ui.h
file-list.h   notify.c        transmission.desktop.in  util.c
hig.c         notify.h        transmission.png         util.h
hig.h         options-icon.h  tr-core.c
icons/        relocate.c      tr-core-dbus.h
icons.c       relocate.h      tr-core-dbus.xml</pre>
</div>
<p>Mesmo não conhecendo nada sobre a estrutura do programa, depois de dar uma olhada no nome dos arquivos, um <strong><span style="font-weight:normal;background-color:#df8;">bom palpite é que o arquivo <em>conf.c</em></span></strong> esteja relacionado com o que preciso alterar, já que é o mais parecido com algo referente à janela de configuração. Edite-no-lo.</p>
<p>Como de praxe, o arquivo começa com alguns includes e em seguida passa para definições de funções. Todas estão com pelo menos uma linha de comentário e têm nomes legíveis. Até que um <strong><span style="font-weight:normal;background-color:#df8;">comentário chama atenção</span></strong>:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/**
 * This is where we initialize the preferences file with the default values.
 * If you add a <strong><span style="font-weight:normal;background-color:#df8;">new preferences key, you /must/ add a default value here</span></strong>.
 */</pre>
</div>
<p>Vamos <strong><span style="font-weight:normal;background-color:#df8;">precisar adicionar uma <em>preference key</em></span></strong>, para determinar se o novo checkbox da janela de configuração está marcado ou não. Então, melhor <strong><span style="font-weight:normal;background-color:#df8;">seguir a recomendação do comentário</span></strong> e definir um valor padrão para a nova chave:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/conf.c transmission-1.75/gtk/conf.c</strong>
--- transmission-1.75-original/gtk/conf.c	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/conf.c	2009-10-03 14:20:54.000000000 -0300
@@ -192,6 +192,7 @@
 #endif
     if( !str ) str = tr_getDefaultDownloadDir( );
     tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR, str );
+    <strong><span style="font-weight:normal;background-color:#df8;">tr_bencDictAddBool( d, PREF_KEY_DOWNLOAD_SAME_DIR, FALSE );</span></strong>

     tr_bencDictAddBool( d, PREF_KEY_ASKQUIT, TRUE );
</pre>
</div>
<p>Se você não está familiarizado com o <strong><span style="font-weight:normal;background-color:#df8;">commando <em>diff</em></span></strong>, basta saber que as primeiras linhas ali definem os arquivos comparados (o conf.c com o mesmo arquivo do diretório original), em seguida o numero da linha do trecho onde ocorreu a alteração, e logo abaixo a alteração: as linhas iniciadas com + foram adicionadas e com &#8211; removidas, as demais são apenas para referência da posição.</p>
<p>Contudo, a <strong><span style="font-weight:normal;background-color:#df8;">chave adicionada <em>PREF_KEY_DOWNLOAD_SAME_DIR</em> não existe ainda</span></strong>, foi inventada agora, e é necessário definí-la em algum lugar, que não sabemos onde. Meu primeiro palpite foi o arquivo <em>conf.h</em>, mas não tinha nada de relevante lá. Para não ter que ficar procurando arquivo por arquivo, vamos procurar onde uma outra chave qualquer já tenha sido definida:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75/gtk$ <strong><span style="background-color:#df8;">grep PREF_KEY_START *</span></strong>
conf.c:    tr_bencDictAddBool( d, PREF_KEY_START, TRUE );
tr-core.c:        tr_ctorSetPaused( ctor, TR_FORCE, !pref_flag_get( PREF_KEY_START ) );
tr-core.c:    const gboolean doStart = pref_flag_eval( start, PREF_KEY_START );
tr-prefs.c:    w = new_check_button( s, PREF_KEY_START, core );
tr-prefs.h:<strong><span style="font-weight:normal;background-color:#df8;">#define PREF_KEY_START</span></strong>                      "start-added-torrents"</pre>
</div>
<p>Pronto, agora sabemos que a definição de <em>PREF_KEY_START</em> (uma preferência de checkbox no mesmo lugar onde adicionaremos a nova) foi <strong><span style="font-weight:normal;background-color:#df8;">feita no arquivo <em>tr-prefs.h</em></span></strong>. Vamos lá adicionar nossa chave nova também:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/tr-prefs.h transmission-1.75/gtk/tr-prefs.h</strong>
--- transmission-1.75-original/gtk/tr-prefs.h	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/tr-prefs.h	2009-10-03 14:38:55.000000000 -0300
@@ -26,6 +26,7 @@
 #define PREF_KEY_INHIBIT_HIBERNATION        "inhibit-desktop-hibernation"
 #define PREF_KEY_DIR_WATCH                  "watch-dir"
 #define PREF_KEY_DIR_WATCH_ENABLED          "watch-dir-enabled"
+<strong><span style="font-weight:normal;background-color:#df8;">#define PREF_KEY_DOWNLOAD_SAME_DIR          "download-same-dir"</span></strong>
 #define PREF_KEY_SHOW_TRAY_ICON             "show-notification-area-icon"
 #define PREF_KEY_SHOW_DESKTOP_NOTIFICATION  "show-desktop-notification"
 #define PREF_KEY_START                      "start-added-torrents"</pre>
</div>
<p>Ainda olhando o resultado do último <em>grep</em>, é possível observar que o <strong><span style="font-weight:normal;background-color:#df8;">arquivo <em>tr-prefs.c</em> também será útil</span></strong>, pois nele tem uma <strong><span style="font-weight:normal;background-color:#df8;">chamada a <em>new_check_button</em></span></strong>, que apesar de não conhecer, dá a entender que cria um checkbox na janela de preferências. Editemos esse arquivo e adicionemos nosso checkbox novo:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/tr-prefs.c transmission-1.75/gtk/tr-prefs.c</strong>
--- transmission-1.75-original/gtk/tr-prefs.c	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/tr-prefs.c	2009-10-03 15:08:09.000000000 -0300
@@ -305,6 +305,10 @@
     w = new_path_chooser_button( TR_PREFS_KEY_DOWNLOAD_DIR, core );
     hig_workarea_add_row( t, &amp;row, _( "Save to _Location:" ), w, NULL );

+    <strong><span style="font-weight:normal;background-color:#df8;">s = _( "Save to the same directory as torrent file" );</span></strong>
+    <strong><span style="font-weight:normal;background-color:#df8;">w = new_check_button( s, PREF_KEY_DOWNLOAD_SAME_DIR, core );</span></strong>
+    <strong><span style="font-weight:normal;background-color:#df8;">hig_workarea_add_wide_control( t, &amp;row, w );</span></strong>
+
     hig_workarea_add_section_divider( t, &amp;row );
     hig_workarea_add_section_title( t, &amp;row, _( "Limits" ) );
 </pre>
</div>
<p>O trecho adicionado foi baseado numa opção já existente. Para o que precisamos, não é necessário saber pra que servem as funções utilizadas, apesar de que em alguns minutos é possível descobrir isso e se familiarizar melhor com o que está acontecendo.</p>
<p>Bem, a princípio, o <strong><span style="font-weight:normal;background-color:#df8;">checkbox</span></strong> para configurar se queremos salvar os arquivos no mesmo diretório foi <strong><span style="font-weight:normal;background-color:#df8;">adicionado</span></strong>. Falta só <strong><span style="font-weight:normal;background-color:#df8;">utilizar o valor desta opção na janela de adicionar torrents</span></strong>.</p>
<p>Olhando novamente o diretório <em>gtk</em>, o <strong><span style="font-weight:normal;background-color:#df8;">provável arquivo que monta a janela que precisamos é o <em>add-dialog.c</em></span></strong>. O que queremos nele é: caso o checkbox com a configuração <em>PREF_KEY_DOWNLOAD_SAME_DIR</em> esteja marcado, devemos usar o diretório do arquivo torrent ao invés do diretório configurado. Desta vez não teve muita mágica para encontrar onde mexer. A dica é ler as funções definidas e tentar identificar o que estamos procurando.</p>
<p>Dentro da <strong><span style="font-weight:normal;background-color:#df8;">função <em>addSingleTorrentDialog</em> no arquivo <em>add-dialog.c</em></span></strong> foi possível encontrar o seguinte trecho:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>    if( <strong><span style="font-weight:normal;background-color:#df8;">tr_ctorGetDownloadDir</span></strong>( ctor, TR_FORCE, <strong><span style="font-weight:normal;background-color:#df8;">&amp;str</span></strong> ) )
        g_assert_not_reached( );
    g_assert( str );

    data = g_new0( struct AddData, 1 );
    data-&gt;core = core;
    data-&gt;ctor = ctor;
    data-&gt;filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
    <strong><span style="font-weight:normal;background-color:#df8;">data-&gt;downloadDir = g_strdup( str );</span></strong></pre>
</div>
<p>Julgando pelos nomes, a função <em>tr_ctorGetDownloadDir</em> preenche o diretório de download do torrent da variável <em>ctor</em> na variável <em>str</em>.</p>
<p>O que precisamos então é <strong><span style="font-weight:normal;background-color:#df8;">definir a variável <em>str</em> para o diretório do arquivo torrent</span></strong> caso o checkbox <em>PREF_KEY_DOWNLOAD_SAME_DIR</em> esteja marcado.</p>
<p>Olhando o trecho de código anterior, sabemos que o <strong><span style="font-weight:normal;background-color:#df8;">caminho do arquivo</span></strong> pode ser obtido através da função <em>tr_ctorGetSourceFile</em> e, ainda no mesmo arquivo, é possível ver que consultamos se o <strong><span style="font-weight:normal;background-color:#df8;">checkbox da configuração</span></strong> está marcado com a função <em>pref_flag_get</em>. A única coisa que fica faltando é conseguir o <strong><span style="font-weight:normal;background-color:#df8;">nome do diretório</span></strong> a partir do caminho completo.</p>
<p>É comum que o diretório de um caminho completo seja retornado pela função ou comando chamado <em>dirname</em>. Como <strong><span style="font-weight:normal;background-color:#df8;">não sei nada de C</span></strong> pra ter certeza de como fazer, dei um <em>grep</em> por <em>dirname</em> para saber como o resto do programa obtém essa informação. <strong><span style="font-weight:normal;background-color:#df8;">Achei</span></strong> o cabeçalho <em>libtransmission/utils.h</em> que define a <strong><span style="font-weight:normal;background-color:#df8;">função <em>tr_dirname</em></span></strong>. Tudo que eu precisava.</p>
<p>A alteração final, já incluindo o arquivo .h necessário para a função de diretório, ficou assim:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/add-dialog.c transmission-1.75/gtk/add-dialog.c</strong>
--- transmission-1.75-original/gtk/add-dialog.c	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/add-dialog.c	2009-10-03 15:26:40.000000000 -0300
@@ -17,6 +17,7 @@
 #include "file-list.h"
 #include "hig.h"
 #include "tr-prefs.h"
+<strong><span style="font-weight:normal;background-color:#df8;">#include "libtransmission/utils.h"</span></strong>

 /****
 *****
@@ -285,8 +286,12 @@
                                              GTK_RESPONSE_CANCEL,
                                              -1 );

-    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &amp;str ) )
-        g_assert_not_reached( );
+    if ( <strong><span style="font-weight:normal;background-color:#df8;">pref_flag_get( PREF_KEY_DOWNLOAD_SAME_DIR )</span></strong> ) {
+        str = <strong><span style="font-weight:normal;background-color:#df8;">tr_dirname</span></strong>( tr_strdup( <strong><span style="font-weight:normal;background-color:#df8;">tr_ctorGetSourceFile</span></strong>( ctor ) ) );
+    } else {
+        if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &amp;str ) )
+            g_assert_not_reached( );
+    }
     g_assert( str );

     data = g_new0( struct AddData, 1 );</pre>
</div>
<p>O resto foi apenas <strong><span style="font-weight:normal;background-color:#df8;">baseado em código já existente</span></strong>.</p>
<h3>Compilando e instalando o pacote</h3>
<p>Para finalizar, basta deixar que o Debian compile e gere o pacote:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">dpkg-buildpackage -rfakeroot -uc -b</span></strong></pre>
</div>
<p>Em seguida, para instalar o pacote que foi gerado no diretório acima do diretório do código fonte, execute como root:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/home/diogo/transmission# <strong><span style="background-color:#df8;">dpkg -i transmission-gtk_1.75-1_amd64.deb</span></strong></pre>
</div>
<h3>Gerando um patch</h3>
<p>A forma universal de trocar alterações em código é através de patch, um arquivo com todos os <em>diff</em>&#8216;s mostrados acima.</p>
<p>Mas antes de criar o patch, é preciso remover alguns arquivos gerados pela compilação:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">dpkg-buildpackage -rfakeroot -Tclean</span></strong></pre>
</div>
<p>Agora é possível utilizar o <em>diff</em> para comparar o diretório original com o diretório onde as alterações foram feitas:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong><span style="background-color:#df8;">diff -ru transmission-1.75-original/ transmission-1.75/ &gt; download-same-directory.diff</span></strong></pre>
</div>
<p>Ao enviar o patch para alguém ou para simplesmente aplicá-lo no diretório original, basta fazer:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75-original$ <strong><span style="background-color:#df8;">patch -p1 &lt; ../download-same-directory.diff</span></strong>
patching file gtk/add-dialog.c
patching file gtk/conf.c
patching file gtk/tr-prefs.c
patching file gtk/tr-prefs.h</pre>
</div>
<p>Se você abrir o patch vai reparar que o caminho para os arquivos inicia com o nome dos diretórios <em>transmission-1.75-original</em> e <em>transmission-1.75</em>. O argumento <em>-p1</em> do <em>patch</em> é justamente para ignorar esse primeiro pedaço do path, uma vez que já estamos no diretório onde as alterações devem ser aplicadas.</p>
<h3>Considerações finais</h3>
<p>Esta alteração, na verdade, foi extremamente <strong><span style="font-weight:normal;background-color:#df8;">simples e com fim didático</span></strong>. Para modificações reais, é fundamental ter <strong><span style="font-weight:normal;background-color:#df8;">mais dedicação</span></strong> para entender a estrutura do projeto e produzir um <strong><span style="font-weight:normal;background-color:#df8;">patch de qualidade</span></strong>, que eventualmente possa ser <strong><span style="font-weight:normal;background-color:#df8;">utilizado pelo autor</span></strong>. No caso mostrado, por exemplo, é provável que a melhor abordagem seria alterar o <em>downloadDir</em> do <em>optional_args</em> do <em>tr_ctor</em>, mas seria mais chato para descrever neste post.</p>
<p>Os passos acima são voltados mais para <strong><span style="font-weight:normal;background-color:#df8;">começar com pequenas alterações de forma prática, sem ter que participar ativamente do projeto</span></strong>.</p>
<p>Caso deseje realmente participar, a melhor forma continua sendo utilizar o <strong><span style="font-weight:normal;background-color:#df8;">repositório oficial</span></strong> e interagir com os <strong><span style="font-weight:normal;background-color:#df8;">colaboradores</span></strong>, até mesmo pra saber se a sua idéia já não está em desenvolvimento ou se você pode coloborar com tarefas mais importantes.</p>
<p>Além disso, é bem comum que os desenvolvedores <strong><span style="font-weight:normal;background-color:#df8;">não aceitem um patch</span></strong> porque ele foi feito baseado no <strong><span style="font-weight:normal;background-color:#df8;">código de uma versão anterior</span></strong> ao trunk / head (que é o caso dos releases de pacotes do Debian), não sendo mais possível aplicá-lo depois de tantas alterações na versão de desenvolvimento.</p>
<p>Já estou até imaginando a galera toda alterando seus programas agora&#8230; <strong><span style="font-weight:normal;background-color:#df8;">Boa sorte!</span></strong></p>
<br />Publicado em Linux  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/682/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=682&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/10/05/alterando-software-livre-jeito-debian-patch-transmission/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2009/10/samedirectory.png" medium="image">
			<media:title type="html">Save to the same directory as torrent file</media:title>
		</media:content>
	</item>
		<item>
		<title>Pequena utilidade para variáveis estáticas</title>
		<link>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/</link>
		<comments>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 12:50:10 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=664</guid>
		<description><![CDATA[Finalmente, depois de muitos anos, achei que tivesse encontrado uma situação em que variáveis estáticas seriam úteis para mim no PHP. Mas não acho que foi o caso. A diferença da variável estática em uma função é que ela não perde o seu valor quando a execução deixa o seu escopo. Isto é, na próxima [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=664&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Finalmente, depois de muitos anos, achei que tivesse encontrado uma situação em que variáveis estáticas seriam úteis para mim no PHP. Mas não acho que foi o caso.<br />
<span id="more-664"></span><br />
A diferença da variável estática em uma função é que ela não perde o seu valor quando a execução deixa o seu escopo. Isto é, na próxima vez que a função for executada, a variável terá o mesmo valor que tinha na execução anterior.</p>
<p>Nunca tinha achado muita utilidade pra isso, até porque geralmente as variáveis locais de um método realmente tinham o tempo de vida de cada execução. Quando não, fazia mais sentido utilizar uma propriedade da classe.</p>
<p>Até que recentemente surgiu a necessidade de executar um método que consultava o banco de dados dezenas de vezes em uma única requisição, alterando apenas o parâmetro da query.</p>
<p>Como consultar o banco uma única vez não era viável neste caso, um raciocínio que segui para tentar poupar um pouco o servidor foi efetuar o <em>prepare</em> somente 1 vez para cada query. E aí entrou a variável estática, guardando o resultado do <em>prepare</em> para execuções futuras, na mesma requisição.</p>
<div style="font-size:12px;font-family:Monaco,monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#bdb76b;">&lt;?php</span><br />
<span style="color:#00ff00;">class</span>&nbsp;TrechoDaMinhaClasse <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;consultarAlgo<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">id</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">static</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">if</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">!</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>db<span style="color:#00ff00;">-&gt;</span>prepare<span style="color:#bdb76b;">(</span>&#039;<br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT id, descricao, peso</span><br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM minhatabela</span><br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE id = :0</span><br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>&#039;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">rs</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>db<span style="color:#00ff00;">-&gt;</span>execute<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>, <span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">id</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;GradeCurricular<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">rs</span><span style="color:#00ff00;">-&gt;</span>fetchRow<span style="color:#bdb76b;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>Dessa forma, a partir da segunda vez que o método for chamado, ele executa direto o <em>prepared statement</em> com o id que deve ser consultado, sem ter que fazer o <em>prepare</em> de novo.</p>
<p>Para minha surpresa, fazendo um benchmark simples hoje (meses depois de implementar com static, assumindo que seria mais rápido), percebi que poupar o <em>prepare</em> no Oracle não fez muita diferença. Pelo visto o Oracle percebe que é a mesma query e não prepara novamente, ou simplesmente fazer o prepare é tão simples que não faz diferença economizar.</p>
<p>Sendo assim, parece que a pequena utilidade que eu tinha dado a variáveis estáticas não me serviu de nada. Estou apresentando o resultado aqui porque, bem&#8230; &#8220;Negative results are still results. Even 20 thousand of them&#8221;.</p>
<p>Pelo visto vou ficar sem ter utilidade para variáveis estáticas. A não ser que você tenha outros relatos positivos :)</p>
<br />Publicado em PHP  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/664/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=664&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Agrupamento parcial com WITH ROLLUP no MySQL</title>
		<link>http://garotosopa.wordpress.com/2009/06/19/agrupamento-parcial-com-with-rollup-no-mysql/</link>
		<comments>http://garotosopa.wordpress.com/2009/06/19/agrupamento-parcial-com-with-rollup-no-mysql/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 11:00:11 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=628</guid>
		<description><![CDATA[Acho que desde que descobri o recurso de GROUP BY &#8230; WITH ROLLUP no MySQL, todas as consultas que faço pra relatórios incluem o modificador. Uma query de exemplo seria pra consultar a quantidade de pessoas por estado, retornando também o total parcial por região. Para que o MySQL já calcule este subtotal, basta incluir [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=628&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Acho que desde que descobri o recurso de <em>GROUP BY &#8230; WITH ROLLUP</em> no MySQL, todas as consultas que faço pra relatórios incluem o modificador.<br />
<span id="more-628"></span><br />
Uma query de exemplo seria pra consultar a quantidade de pessoas por estado, retornando também o total parcial por região.</p>
<p>Para que o MySQL já calcule este subtotal, basta incluir o modificador <strong>WITH ROLLUP</strong> logo após o GROUP BY:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#6495ed;">SELECT</span> uf.regiao, uf.nome, <span style="color:#bdb76b;">COUNT(</span>p.id<span style="color:#bdb76b;">)</span><br />
<span style="color:#6495ed;">FROM</span> uf<br />
<span style="color:#6495ed;">LEFT JOIN</span> pessoa p <span style="color:#6495ed;">ON</span> uf.id = p.id_uf<br />
<span style="color:#6495ed;">GROUP BY</span> uf.regiao, uf.nome <span style="color:#6495ed;">WITH ROLLUP</span>
</div>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';">
<pre>
+--------------+---------------------+-------------+
| regiao       | nome                | COUNT(p.id) |
+--------------+---------------------+-------------+
| Centro-Oeste | Distrito Federal    |          99 |
| Centro-Oeste | Goiás               |         114 |
| Centro-Oeste | Mato Grosso         |         102 |
| Centro-Oeste | Mato Grosso do Sul  |          91 |
<span style="background-color:#FFCCCC;">| Centro-Oeste | <em>NULL</em>                |         406 |</span>
| Nordeste     | Alagoas             |         107 |
| Nordeste     | Bahia               |          72 |
| Nordeste     | Ceará               |         100 |
| Nordeste     | Maranhão            |          89 |
| Nordeste     | Paraíba             |         128 |
| Nordeste     | Pernambuco          |         105 |
| Nordeste     | Piauí               |          92 |
| Nordeste     | Rio Grande do Norte |          83 |
| Nordeste     | Sergipe             |         115 |
<span style="background-color:#FFCCCC;">| Nordeste     | <em>NULL</em>                |         891 |</span>
| Norte        | Acre                |          87 |
| Norte        | Amapá               |          97 |
| Norte        | Amazonas            |         103 |
| Norte        | Pará                |         116 |
| Norte        | Rondônia            |         111 |
| Norte        | Roraima             |          93 |
| Norte        | Tocantins           |         101 |
<span style="background-color:#FFCCCC;">| Norte        | <em>NULL</em>                |         708 |</span>
| Sul          | Paraná              |         112 |
| Sul          | Rio Grande do Sul   |         110 |
| Sul          | Santa Catarina      |         115 |
<span style="background-color:#FFCCCC;">| Sul          | <em>NULL</em>                |         337 |</span>
<span style="background-color:#FFCCCC;">| <em>NULL</em>         | <em>NULL</em>                |        2342 |</span>
+--------------+---------------------+-------------+
</pre>
</div>
<p>&nbsp;<br />
Com o modificador <em>WITH ROLLUP</em>, para cada região existe um valor <strong><em>NULL</em></strong> na coluna do estado, representando o subtotal daquela região.</p>
<p>Esta regra vale para todos os níveis de agrupamento. As demais colunas agrupadas ficam com valor <em>NULL</em> quando a função de agregação, neste caso o <em>COUNT</em>, está representando um resultado parcial.</p>
<p>No final é retornado ainda o <strong>total geral</strong>, como se não houvesse agrupamento algum, deixando todas as colunas agrupadas com valor <em>NULL</em>.</p>
<p>Agora basta formatar o resultado pelo código e deixar as colunas de subtotal com algum estilo diferente e descrição apropriada.</p>
<p>Vale lembrar que o <em>WITH ROLLUP</em> retorna os <strong>rows ordenados pelas colunas agrupadas</strong>, não sendo permitido misturar uma cláusula <em>ORDER BY</em> na mesma query, até porque o MySQL se baseia na troca do valor da coluna para saber quando deve mostrar um total parcial (da mesma forma que faríamos manualmente). Caso seja realmente necessário, é possível utilizar o <em>WITH ROLLUP</em> em uma query derivada e a partir dela acrescentar o <em>ORDER BY</em>.</p>
<p>Veja mais detalhes sobre modificadores de agrupamento no capítulo <a href="http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html">GROUP BY Modifiers</a> do manual.</p>
<div style="font-size:80%;">* se alguém reparar que estão faltando os estados da região sudeste, é só porque eu esqueci de cadastrar no banco de testes mesmo.</div>
<br />Publicado em MySQL, SQL  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/628/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=628&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/06/19/agrupamento-parcial-com-with-rollup-no-mysql/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>7 coisas simples em PHP que alguns ainda complicam</title>
		<link>http://garotosopa.wordpress.com/2009/05/30/7-coisas-simples-em-php-que-alguns-ainda-complicam/</link>
		<comments>http://garotosopa.wordpress.com/2009/05/30/7-coisas-simples-em-php-que-alguns-ainda-complicam/#comments</comments>
		<pubDate>Sat, 30 May 2009 18:54:17 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=608</guid>
		<description><![CDATA[É comum ver scripts com dezenas de linhas de código pra fazer algo extremamente simples. Fica aqui meu apelo desesperado com algumas dicas rápidas. 1 &#8211; Listar arquivos de um diretório Se não houver um motivo muito claro pra usar opendir, readdir e closedir (não consigo pensar em nenhum), a forma mais prática de listar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=608&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>É comum ver scripts com dezenas de linhas de código pra fazer algo extremamente simples. Fica aqui meu apelo desesperado com algumas dicas rápidas.</p>
<p><span id="more-608"></span></p>
<h3><a href="#listar-arquivos" name="listar-arquivos">1 &#8211; Listar arquivos de um diretório</a></h3>
<p>Se não houver um motivo muito claro pra usar <a href="http://php.net/opendir">opendir</a>, <a href="http://php.net/readdir">readdir</a> e <a href="http://php.net/closedir">closedir</a> (não consigo pensar em nenhum), a forma mais prática de listar o conteúdo de um diretório é com <a href="http://php.net/DirectoryIterator">DirectoryIterator</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">DirectoryIterator</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">/var/www</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span><span style="color:#00ff00;">-&gt;</span>getFilename<span style="color:#bdb76b;">()</span>, &quot;<span style="color:#bdb76b;">\n</span>&quot;;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Se for necessário listar os arquivos recursivamente, percorrendo todos os subdiretórios, é só usar o <a href="http://php.net/RecursiveDirectoryIterator">RecursiveDirectoryIterator</a> junto com o <a href="http://php.net/RecursiveIteratorIterator">RecursiveIteratorIterator</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">RecursiveDirectoryIterator</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">/var/www</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">recursiveIterator</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">RecursiveIteratorIterator</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">recursiveIterator</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span><span style="color:#00ff00;">-&gt;</span>getFilename<span style="color:#bdb76b;">()</span>, &quot;<span style="color:#bdb76b;">\n</span>&quot;;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Com um pouco de criatividade, é possível estender essas classes com qualquer lógica facilmente, como por exemplo, para montar uma árvore com a estrutura dos diretórios.</p>
<h3><a href="#query-string" name="query-string">2 &#8211; montar e desmontar query strings</a></h3>
<p>Mesmo que menos comum (e menos útil), colocar uma <em>query string</em> numa URL é um trabalho trivial demais pra ser feito com <a href="http://php.net/implode">implode</a>, concatenando tudo ou qualquer outro método engenhoso. Desde o lançamento do PHP 5 é possível contar com a <a href="http://php.net/http_build_query">http_build_query</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">dados</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">hl</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">pt-BR</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">q</span>&#39;&nbsp;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">Forgetting Sarah Marshall</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">testa-escape</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">acentuação</span>&#39;,<br />
<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ffdead;">http_build_query</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">dados</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#666666;">// hl=pt-BR&amp;q=Forgetting+Sarah+Marshall&amp;testa-escape=acentua%C3%A7%C3%A3o </span></div>
<p>E o inverso também é possível com as funções <a href="http://php.net/parse_url">parse_url</a> e <a href="http://php.net/parse_str">parse_str</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">parse_url</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">http://www.google.com/search?q=anneke+van+giersbergen&amp;num=50</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ffdead;">parse_str</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">query</span>&#39;<span style="color:#bdb76b;">]</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">query</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">query</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">q</span>&#39;<span style="color:#bdb76b;">]</span>;<br />
<span style="color:#666666;">// anneke van giersbergen</span></div>
<p>Só fique atento que, por motivos alheios ao bom senso, <a href="http://php.net/parse_str">parse_str</a> por padrão extrai as variáveis no escopo onde foi chamada. É necessário passar um segundo argumento para ter um array gerado por referência, como no exemplo acima com a variável <em>$query</em>.</p>
<h3><a href="#ler-paginas-remotas" name="ler-paginas-remotas">3 &#8211; ler páginas remotas</a></h3>
<p>Dentre todas as implementações, a mais desnecessária costuma ser <a href="http://php.net/fsockopen">fsockopen</a>, <a href="http://php.net/fwrite">fwrite</a>, <a href="http://php.net/feof">feof</a>, <a href="http://php.net/fgets">fgets</a> e <a href="http://php.net/fclose">fclose</a> para ler arquivos remotos por HTTP.</p>
<p>Uma função já resolve:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">contents</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">file_get_contents</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">http://php.net/file_get_contents</span>&#39;<span style="color:#bdb76b;">)</span>;</div>
<p>Isso é possível graças aos <a href="http://php.net/wrappers">protocol wrappers</a> que encapsulam a lógica de acesso aos respectivos protocolos, tal como HTTP. Esta forma de acesso, no entanto, depende da configuração <a href="http://php.net/filesystem.configuration#ini.allow-url-fopen">allow_url_fopen</a> estar habilitada no php.ini (que é o padrão).</p>
<p>Para ler os <em>response headers</em> da requisição, utilize <a href="http://php.net/fopen">fopen</a> com <a href="http://php.net/stream_get_meta_data">stream_get_meta_data</a>.</p>
<p>E se um dia você quiser impressionar a mulherada, veja a função <a href="http://php.net/stream_wrapper_register">stream_wrapper_register</a> para criar o seu próprio <em>protocol wrapper</em>.</p>
<h3><a href="#submeter-post-remoto" name="submeter-post-remoto">4 &#8211; submeter dados por post para uma página remota</a></h3>
<p>A coisa fica mais complicada quando o desenvolvedor pensa em usar <a href="http://php.net/curl">cURL</a> pra submeter dados por POST para outro servidor. A extensão até tem seu mérito, mas usá-la <strong>apenas</strong> pra este propósito é um grande equívoco.</p>
<p>As funções que fazem uso dos <a href="http://php.net/wrappers">protocol wrappers</a> aceitam um objeto de <em>stream context</em>, criado pela função <a href="http://php.net/stream_context_create">stream_context_create</a>, para configurar alguns aspectos do protocolo. As <a href="http://php.net/context.http">opções de contexto do protocolo HTTP</a> permitem definir, entre outras coisas, o método de acesso (GET, POST, etc) e o conteúdo a ser postado:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">content</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">http_build_query</span><span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">cidade</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">Rio de Janeiro</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">tipo</span>&#39;&nbsp;&nbsp; <span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">Apartamento</span>&#39;,<br />
<span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">context</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">stream_context_create</span><span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">http</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">method</span>&#39;&nbsp;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">POST</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">content</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">content</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">)</span><br />
<span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">contents</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">file_get_contents</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">http://exemplo/teste.php</span>&#39;, <span style="color:#6495ed;">null</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">context</span><span style="color:#bdb76b;">)</span>;</div>
<p>Quando não for necessário ler o retorno da requisição, basta chamar a url com <a href="http://php.net/fopen">fopen</a> passando o contexto como quarto argumento.</p>
<h3><a href="#download-remoto" name="download-remoto">5 &#8211; fazer download de um arquivo remoto</a></h3>
<p>Vale lembrar que a maioria das funções de stream e filesystem aceitam URLs completas e fazem uso da abstração do protocolo. O que eu vejo muita gente esquecer é que isso inclui a função <a href="http://php.net/copy">copy</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;&quot;<span style="color:#87ceeb;">http://userserve-ak.last.fm/serve/500/4349551/Terri+Clark.jpg</span>&quot;;<br />
&nbsp;<br />
<span style="color:#ffdead;">copy</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>, &#39;<span style="color:#87ceeb;">/tmp/</span>&#39;&nbsp;<span style="color:#ff0000;">.</span>&nbsp;<span style="color:#ffdead;">urldecode</span><span style="color:#bdb76b;">(</span><span style="color:#ffdead;">basename</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span><span style="color:#bdb76b;">)))</span>;</div>
<p>O trecho acima vai baixar a imagem remota e salvar no arquivo local <em>/tmp/Terri Clark.jpg</em>. E caso não seja óbvio, &#8220;local&#8221; se refere a quem está executando o script PHP, que no caso será o seu servidor caso seja um script web, e não o cliente que está acessando pelo browser.</p>
<p>Se o objetivo for realmente repassar o conteúdo remoto para o cliente que estiver acessando pelo browser, o script é igualmente simples:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;&#39;<span style="color:#87ceeb;">http://userserve-ak.last.fm/serve/500/4349551/Terri+Clark.jpg</span>&#39;;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">handle</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">fopen</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>, &#39;<span style="color:#87ceeb;">r</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">meta_data</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">stream_get_meta_data</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">handle</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#666666;">// Repassa todos os headers do servidor remoto para o nosso cliente</span><br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">meta_data</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">wrapper_data</span>&#39;<span style="color:#bdb76b;">]</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffdead;">header</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
<span style="color:#666666;">// Repassa o conteúdo para o nosso cliente</span><br />
<span style="color:#ffdead;">fpassthru</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">handle</span><span style="color:#bdb76b;">)</span>;</div>
<p>Considerando que estamos apenas testando a funcionalidade. Ter um script de proxy totalmente funcional é bem mais complexo, e certamente já tem algo pronto por aí.</p>
<h3><a href="#calculo-data" name="calculo-data">6 &#8211; fazer cálculo com data</a></h3>
<p>Dentre todas as simplificações possíveis, a que mais costuma comover é a função <a href="http://php.net/strtotime">strtotime</a>. Pra quem já está acostumado, parece que não faz mais do que sua obrigação. Mas pra quem ainda faz cálculos com data multiplicando por 86400, chega a parecer mágico:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ffd700;">echo</span>&nbsp;&#39;<span style="color:#87ceeb;">Amanhã: </span>&#39;, <span style="color:#ffdead;">strftime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">%A</span>&#39;, <span style="color:#ffdead;">strtotime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">tomorrow</span>&#39;<span style="color:#bdb76b;">))</span>;<br />
<span style="color:#666666;">// Amanhã: domingo</span><br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;&#39;<span style="color:#87ceeb;">Próxima segunda: </span>&#39;, <span style="color:#ffdead;">strftime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">%d de %B de %Y</span>&#39;, <span style="color:#ffdead;">strtotime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">next monday</span>&#39;<span style="color:#bdb76b;">))</span>;<br />
<span style="color:#666666;">// Próxima segunda: 01 de junho de 2009</span><br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;&#39;<span style="color:#87ceeb;">Vencimento: </span>&#39;, <span style="color:#ffdead;">strftime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">%d/%m/%Y</span>&#39;, <span style="color:#ffdead;">strtotime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">+3 months</span>&#39;<span style="color:#bdb76b;">))</span>;<br />
<span style="color:#666666;">// Vencimento: 30/08/2009</span></div>
<p>Mais exemplos você mesmo pode ver no manual do PHP ou na página de <a href="http://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html">Date Input Formats do projeto GNU</a>. Para o nome dos meses e dias da semana ficarem em português, utilize <em>setlocale(LC_TIME, &#8216;pt_BR&#8217;);</em> antes de chamar a função <a href="http://php.net/strftime">strftime</a>.</p>
<h3><a href="#escapar-sql-html" name="escapar-sql-html">7 &#8211; escapar sql e html</a></h3>
<p>Felizmente nunca mais vi nenhum script com aberrações anti-sql-injection, mas há algum tempo era possível encontrar pessoas removendo palavras-chave de SQL de todas as strings que íam para o banco de dados. Se o usuário digitasse palavras como select, delete ou drop, elas eram simplesmente removidas da frase. Isso quando o programador não interrompia o script e acusava o usuário de estar tentando explorar alguma falha de segurança. Eu juro, isso existia.</p>
<p>Ao trabalhar com <a href="http://php.net/pdo">PDO</a>, a melhor opção (pra não dizer a única!) é utilizar <a href="http://php.net/pdo.prepare">prepare</a> e <a href="http://php.net/pdostatement.execute">execute</a> pra separar a query em si dos seus parâmetros:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">PDO</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">mysql:dbname=banco;host=localhost</span>&#39;, &#39;<span style="color:#87ceeb;">login</span>&#39;, &#39;<span style="color:#87ceeb;">senha</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">uf</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;&#39;<span style="color:#87ceeb;">RJ</span>&#39;;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">idade</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">18</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sth</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span><span style="color:#00ff00;">-&gt;</span>prepare<span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">SELECT nome FROM pessoa WHERE uf = ? AND idade &gt; ?</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sth</span><span style="color:#00ff00;">-&gt;</span>execute<span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">uf</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">idade</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">while</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">row</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sth</span><span style="color:#00ff00;">-&gt;</span>fetch<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">row</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">nome</span>&#39;<span style="color:#bdb76b;">]</span>;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Se estiver utilizando drivers nativos, veja as funções <a href="http://php.net/mysql_real_escape_string">mysql_real_escape_string</a> ou <a href="http://php.net/mysqli.prepare">mysqli_prepare</a> e <a href="http://php.net/mysqli-stmt.bind-param">mysqli_stmt_bind_param</a>, dependendo da extensão. Certamente outros bancos de dados têm a mesma funcionalidade.</p>
<p>A única preocupação é garantir que os parâmetros não se misturem com a query; não precisa inventar moda e remover o que o usuário digitou.</p>
<p>Outra confusão comum é ao escapar HTML. O objetivo é evitar que o texto digitado por um usuário seja interpretado pelo browser de todos os usuários do site.</p>
<p>Conceitualmente, esta é uma responsabilidade da camada de exibição. O template é que deve utilizar <a href="http://php.net/htmlspecialchars">htmlspecialchars</a> antes de gerar a saída na tela, e não antes de salvar no banco. Isso garante que o conteúdo que está no banco é fiel ao que foi digitado pelo usuário e pode ser reaproveitado em outras mídias além do HTML.</p>
<p>O que pode e deve ser feito é filtrar conteúdo realmente indevido, como caracteres inválidos ou espaços extras, dependendo da aplicação.</p>
<br />Publicado em PHP  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/608/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=608&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/05/30/7-coisas-simples-em-php-que-alguns-ainda-complicam/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Aproveitando melhor o aptitude</title>
		<link>http://garotosopa.wordpress.com/2009/04/26/aproveitando-melhor-o-aptitude/</link>
		<comments>http://garotosopa.wordpress.com/2009/04/26/aproveitando-melhor-o-aptitude/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 23:45:14 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=599</guid>
		<description><![CDATA[Pra quem usa Debian ou semelhante, como o Ubuntu, talvez as notas abaixo sejam úteis na hora de gerenciar os pacotes pelo aptitude. Resumo CTRL-T para acessar o menu %D é o atributo de package size no display format u para update U para upgrade g para executar e confirmar as alterações : para ignorar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=599&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Pra quem usa Debian ou semelhante, como o Ubuntu, talvez as notas abaixo sejam úteis na hora de gerenciar os pacotes pelo <strong>aptitude</strong>.<br />
<span id="more-599"></span></p>
<h3>Resumo</h3>
<ul>
<li><strong>CTRL-T</strong> para acessar o menu</li>
<li><strong>%D</strong> é o atributo de <em>package size</em> no <em>display format</em></li>
<li><strong>u</strong> para update</li>
<li><strong>U</strong> para upgrade</li>
<li><strong>g</strong> para executar e confirmar as alterações</li>
<li><strong>:</strong> para ignorar a atualização de um pacote</li>
<li><strong>=</strong> para deixar o pacote nesta versão até a segunda ordem</li>
<li><strong>G</strong> para filtrar ou alterar a exibição da lista de pacotes</li>
<li><strong>filter(~i !~M)</strong> mostra apenas os pacotes instalados manualmente</li>
<li><strong>m</strong> para marcar um pacote como instalado manualmente</li>
<li><strong>M</strong> para marcar um pacote como instalado automaticamente</li>
<li>Isso é só cultura inútil, ignore se tiver outra coisa pra fazer</li>
</ul>
<h3>Pacotes recomendados</h3>
<p>Uma boa coisa a se fazer ao instalar o sistema do zero é configurar o aptitude para não instalar os pacotes recomendados automaticamente, somente as dependências. Isso poupa dezena de pacotes que você provavelmente não quer.</p>
<p>A opção está disponível no menu <strong>Options -&gt; Preferences</strong>, que pode ser acessado pressionando <strong>CTRL-T</strong>. Desmarque a opção <em>Install recommended packages automatically</em>.</p>
<h3>Pacotes desnecessários</h3>
<p>Logo abaixo tem a opção <em>Remove unused packages automatically</em>. Confirme que ela esteja marcada para garantir que pacotes que foram instalados para satisfazer dependências sejam removidos quando não forem mais necessários.</p>
<h3>Package size</h3>
<p>Ainda nas preferências, acho legal incluir a coluna com o tamanho do pacote a ser baixado, em caso de atualização ou nova instalação.</p>
<p>Edite a opção <em>The display format for package views</em> e inclua o atributo <strong>%D</strong>. Aqui a configuração ficou <em><span style="background-color:#eaeaea;">%c%a%M%S %p %Z %D %v %V</span></em>.</p>
<p>Saber o tamanho do pacote ajuda na hora de priorizar alguns e desistir de outros, caso tenha muita coisa para atualizar.</p>
<h3>Ignorando atualizações</h3>
<p>Para atualizar o sistema, utiliza-se a tecla <strong>u</strong> (minúsculo) para atualizar a lista de pacotes do repositório (o mesmo que o comando aptitude update ou apt-get update) e depois a tecla <strong>U</strong> (maiúsculo) para marcar para atualização os pacotes com versões mais novas disponíveis (o mesmo que aptitude upgrade ou apt-get upgrade).</p>
<p>Para executar as alterações, pressione <strong>g</strong> (minúsculo). Você será levado para uma tela de preview. Pressione <strong>g</strong> novamente para confirmar.</p>
<p>Se quiser ignorar alguma atualização, pressione <strong>:</strong> em cima do pacote que deseja ignorar. Ele ficará como <em>upgradable</em> até o próximo upgrade (<strong>U</strong>).</p>
<p>Caso prefira manter o pacote na versão atual indefinidamente, pressione <strong>=</strong> em cima do pacote para deixá-lo em <em>hold</em>. Ele ficará aguardando neste status até que você remova o hold.</p>
<h3>Filtrando a lista de pacotes</h3>
<p>Na tela principal do aptitude estão listados todos os pacotes dos repositórios agrupados por tarefa, status e seção. Este agrupamento pode ser trocado através da tecla <strong>G</strong> (maiúsculo).</p>
<p>Uma visualização que faço frequentemente é filtrar os pacotes instalados com o filtro <em><span style="background-color:#eaeaeal;">filter(~i !~M)</span></em>. O atributo <em>~i</em> lista os pacotes instalados e o atributo <em>~M</em> lista os pacotes instalados automaticamente para satisfazer dependências (neste caso, utilizado com negação).</p>
<p>Ao pressionar <strong>G</strong>, o filtro e agrupamentos ficam <em><span style="background-color:#eaeaea;">filter(~i !~M),section</span></em>.</p>
<h3>Marcar pacotes como instalados automaticamente</h3>
<p>O benefício do filtro acima é poder diferenciar os pacotes que realmente se quer instalados dos que foram instalados por necessidade.</p>
<p>Utilizando o filtro e agrupmento como no exemplo anterior, a seção <em>libs</em> deveria mostrar uma quantidade mínima de pacotes, já que o que utilizamos são os programas, sendo as bibliotecas apenas para satisfazer dependências (salvo algumas exceções como a libdvdcss2, por exemplo).</p>
<p>Se com o filtro anterior forem exibidos vários pacotes na seção libs é porque, pro aptitude, estas bibliotecas foram instaladas manualmente. O problema disso é que, se todos os programas que utilizam a biblioteca forem removidos, ela vai continuar lá.</p>
<p>Para marcar os pacotes como instalados automaticamente, pressione <strong>M</strong> (maiúsculo) em cima do pacote, ou em cima da seção para marcar todos como automáticos, como no caso das libs.</p>
<p>Se esta é a primeira vez que você faz isso, é comum que vários pacotes sejam removidos. Nesse caso, ao pressionar <strong>g</strong> para concluir as alterações, vale a pena dar uma boa olhada no preview antes de pressionar <strong>g</strong> novamente para confirmar.</p>
<p>Para marcar um pacote como instalado manualmente e evitar que ele seja removido quando nenhum outro pacote depender mais dele, pressione <strong>m</strong> (minúsculo) em cima do pacote.</p>
<p>Caso você tenha muita paciência ou mais nada de interessante pra fazer, pode ser um <del>bom</del> longo passatempo percorrer toda a lista de pacotes (com <em>filter(~i !~M)</em>) e marcar como instalação automática aqueles que você desconhece ou acha que não precisa. </p>
<p>Na dúvida é melhor deixar instalado, principalmente se for algum relacionado a boot ou filesystem.</p>
<h3>Ignore tudo isso</h3>
<p>Em quase 100% dos casos os usuários vão preferir desconhecer os pacotes instalados e só usar o Synaptic de vez em quando. Eu entendo. Afinal são só pacotes no computador. É que eu estava sem o que fazer e precisava de algum lugar pra anotar isso, porque sempre esqueço.</p>
<p>Caso alguém se interesse, o User&#8217;s Manual disponível no menu (através de <strong>CTRL-T</strong>) é mais completo do que <em>man aptitude</em>.</p>
<br />Publicado em Linux  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/599/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&amp;blog=954761&amp;post=599&amp;subd=garotosopa&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/04/26/aproveitando-melhor-o-aptitude/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
	</channel>
</rss>
