Assim que comecei a trabalhar com Zend_Form experimentei um erro com htmlspecialchars(), que me tomou algumas longas horas para identificar e gostaria de compartilhar a solução (simples, rápida e fácil).
A mensagem de erro era a seguinte:

Warning: htmlspecialchars() [function.htmlspecialchars]: charset `utf8′ not supported, assuming iso-8859-1 in C:\app\lib\Zend\View\Abstract.php on line 837

Isso aconteceu com a versão 1.7.7 e 1.8.0 do ZF.
Ok, o passo-a-passo da resolução do problema foi:
1 – PHP.net, função htmlspecialchars(), pode assumir como valor do seu terceiro parâmetro, a string ‘UTF-8’
2 – Fui até C:\app\lib\Zend\View\Abstract.php on line 837
return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_encoding);
Onde $this->_encoding é setado na linha 851, e de fato estava setando ‘utf8’ ao invés de ‘UTF-8’
3 – Fui até o arquivo de configurações da minha aplicação e reparei que a mesma config de charset que estava utilizando na conexão com o banco ‘utf8’ (exigido desta forma pelo PDO), estava também sendo usado para o htmlspecialchars()
4 – Criei outra constante no config da aplicação voltada para atender ao charset da aplicação como um todo, e pronto. Funcionou.


Muia gente se confunde na hora de escrever aquele IF numa linha só, e como essa semana me perguntaram 2x sobre como escrevê-lo, resolvi colocar aqui:

$result = ($var == 1) ? ‘Ativo’: ‘Inativo’;

Ou se quiser dar um Echo direto do resultado desta condicional, basta colocar:

Echo ($var == 1) ? ‘Ativo’: ‘Inativo’;

Como adicionar estilo em checkbox diferente do input type text?

input[type=”checkbox”] {
height: 20px;
}

Este é um exemplo simples e prático.


Acredito que todos devem saber que deixar “visível” a versão do Apache e do PHP utilizados em um servidor de produção é uma falha grave de segurança. Existem alguns usuários que ficam acompanhando pela rede as novas descobertas em falhas de segurança em versões de software e como elas podem ser exploradas, então, um site com uma versão com falha de segurança que ainda não tenha sido corrigida ou aplicado um patch, é um prato cheio…

Escondendo a versão do Apache: [arquivo: httpd.conf]

Altere “ServerSignature On” por “ServerSignature Off”, caso esta constante não exista, crie-a.
Adicione logo abaixo, a seguinte linha: “ServerTokens Prod”
Restarte o Apache

Comentários: Não utilize as aspas, elas foram aplicadas só para delimitar o texto a ser editado/inserido
Nota: Verifique se já não existe a constante “ServerTokens”, caso exista, comente-a (adicionando o símbolo # no início da linha)

Escondendo a versão do PHP [arquivo: php.ini]

Altere “expose_php On” para “expose_php Off”
Restarte o HTTP Server (Apache neste caso)

Para entender estas configurações com mais detalhes, veja aqui.


Muito bom todos os dias do evento PHP Conference Brasil 2008 que aconteceu em Osasco, São Paulo, Novembro. Agradeço por ter sido convidado a palestrar sobre Internacionalização de Software em PHP. Parabéns pela organização Galvão!


Se você está procurando uma solução robusta e complexa de menu com abas (tabs), meu script certamente não é a solução. Mas então por quê eu cheguei a fazê-lo? Para suprir uma necessidade básica que o TABS do jQuery UI3 não atende.

Ao mínimo estranho alguém dizer isso né? Pois bem, se alguém ainda não conhece essa UI do jQuery vale a pena testá-la, ah, para um bom teste, abra a página de testes de abas com o Javascript do seu navegador desabilitado para ver o que acontece.

Simplesmente o conteúdo da Aba que deveria vir logo abaixo dela, não é carregado. E isso se explica porque este conteúdo é carregado de uma outra URL logo durante o carregamento da página e o DIV (onde entra o conteúdo) também é gerado dinamicamente, ou seja, sem JS posso te adiantar que teremos erro de layout no site. Para quem quiser testar: http://www.stilbuero.de/jquery/tabs_3/

Bom, a idéia aqui é criar um menu com abas superiores, que mesmo sem o JS ativo ele mantenha o seu layout correto, e ao menos, o conteúdo da primeira aba ativa seja carregado. Outra funcionalidade é que cada aba possa ter 2 classes independentes, uma para o estado Ativo e outra para o estado Inativo. Digo que são classes independentes para cada aba, justamente para você poder adicionar Imagens de Fundo diferentes em cada Tab. Além disso, você pode definir para cada aba, uma mensagem de “Loading” customizada, ou usar a mensagem padrão definida pelo html, para o carregamento das abas do menu em questão.

Vamos ao código:

XHTML:

<div class=”tab_menu_container”>
<ul id=”tab_menu_1″ class=”tabs-nav” attrLoadingMessage=”Carregando…”>
<li class=”tab_cama_on”><a href=”www.exemplo.com/1″><span>Cama</span></a></li>
<li class=”tab_mesa_off”><a href=”www.exemplo.com/2″ attrLoadingMessage=”Carregando Mesa…”><span>Mesa</span></a></li>
<li class=”tab_banho_off”><a href=”www.exemplo.com/3″><span>Banho</span></a></li>
</ul>
<div class=”tabs-container”></div>
</div>

JAVASCRIPT – jQuery

$().ready(function() {

$(“.tabs-nav li a”).livequery(‘click’,function() {

/* Set Variables */
var URL = $(this).attr(‘href’);

var TabMenu = $(this).parents(“li:first”).parents(“ul:first”).attr(‘id’);
var CurrentTab = $(this).parents(“li:first”);
var ContentArea = $(this).parents(“li:first”).parents(“ul:first”).nextAll(“div:first”);
var LoadingMessageDefault = $(this).parents(“li:first”).parents(“ul:first”).attr(‘attrLoadingMessage’);
var LoadingMessageCustom = $(this).attr(‘attrLoadingMessage’);

/* Set Up the Loading Message */
if (typeof(LoadingMessageCustom) == “undefined” || LoadingMessageCustom == null)
{
var LoadingMessage = LoadingMessageDefault;
}
else
{
var LoadingMessage = LoadingMessageCustom;
}

var LoadingContent = ‘<div class=”tabs-loading”>’ + LoadingMessage + ‘</div>’;

/* Set All Tabs to the Inactive State */
$(“#” + TabMenu + ” > *”).each(function() {
var ActiveClass = $(this).attr(‘class’).replace(‘_off’,”_on”);
var InactiveClass = $(this).attr(‘class’).replace(‘_on’,”_off”);
$(this).removeClass(ActiveClass);
$(this).addClass(InactiveClass);
});

/* Set the Current Tab to the Active State */
var ActiveClass = CurrentTab.attr(‘class’).replace(‘_off’,”_on”);
var InactiveClass = CurrentTab.attr(‘class’).replace(‘_on’,”_off”);
CurrentTab.removeClass(InactiveClass);
CurrentTab.addClass(ActiveClass);

$.ajax({url: URL,
data: URL,
beforeSend: function() {
ContentArea.html(LoadingContent);
},
success: function(response){
ContentArea.html(response);
},
error: function(data) {
alert(‘erro…’);
},
type: “GET”,
dataType: “html”
});

return false;
});

});

CSS:

/* CSS FROM http://stilbuero.de/jquery/tabs_3/ */
/* Caution! Ensure accessibility in print and other media types… */
@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types… */
.tabs-hide {
display: none;
}
}

/* Hide useless elements in print layouts… */
@media print {
.tabs-nav {
display: none;
}
}

/* Skin */
.tabs-nav {
list-style: none;
margin: 0;
padding: 0px;
}
.tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
display: block;
clear: both;
content: ” “;
}
.tabs-nav li {
border: 1px solid #ccc; /* TAB ITEM */
border-bottom: 0px;
float: left;
margin: 0 0 0 0px;
min-width: 84px; /* be nice to Opera */
}
.tabs-nav a, .tabs-nav a span {
display: block;
padding: 0 10px;
background: url(tab.png) no-repeat;
}
.tabs-nav a {
position: relative;
top: 1px;
z-index: 2;
padding-left: 0;
color: #000 !important;
font-size: 12px;
font-weight: bold !important;
line-height: 1.2;
text-align: center;
text-decoration: none !important;
white-space: nowrap; /* required in IE 6 */
}
.tabs-nav .tabs-selected a {
color: #000;
}
.tabs-nav .tabs-selected a, .tabs-nav a:hover, .tabs-nav a:focus, .tabs-nav a:active {
background-position: 100% -150px;
outline: 0; /* prevent dotted border in Firefox */
}
.tabs-nav a, .tabs-nav .tabs-disabled a:hover, .tabs-nav .tabs-disabled a:focus, .tabs-nav .tabs-disabled a:active {
background-position: 100% -100px;
}
.tabs-nav a span {
width: 64px; /* IE 6 treats width as min-width */
min-width: 64px;
height: 18px; /* IE 6 treats height as min-height */
min-height: 18px;
padding-top: 6px;
padding-right: 0;
}
*>.tabs-nav a span { /* hide from IE 6 */
width: auto;
height: auto;
}
.tabs-nav .tabs-selected a span {
padding-top: 7px;
}
.tabs-nav .tabs-selected a span, .tabs-nav a:hover span, .tabs-nav a:focus span, .tabs-nav a:active span {
background-position: 0 -50px;
}
.tabs-nav a span, .tabs-nav .tabs-disabled a:hover span, .tabs-nav .tabs-disabled a:focus span, .tabs-nav .tabs-disabled a:active span {
background-position: 0 0;
}
.tabs-nav .tabs-selected a:link, .tabs-nav .tabs-selected a:visited, .tabs-nav .tabs-disabled a:link, .tabs-nav .tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor… */
cursor: text;
}
.tabs-nav a:hover, .tabs-nav a:focus, .tabs-nav a:active { /* @ Opera, we need to be explicit again here now… */
cursor: pointer;
}
.tabs-nav .tabs-disabled {
opacity: .4;
}
.tabs-container {
border: 1px solid #ccc;
padding: 1em 8px;
background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
min-height: 150px;
}
.tabs-loading {
padding: 0 0 0 20px;
background: url(/images/loading.uitabs.gif) no-repeat 0 50%;
}

/* Tabs Customization – ready to use image backgrounds to each tab */
.tabs-nav .tab_cama_on {background-color: #FF6600; border:1px solid #FF6600;}
.tabs-nav .tab_mesa_on {background-color: #FF6600; border:1px solid #FF6600;}
.tabs-nav .tab_banho_on {background-color: #FF6600; border:1px solid #FF6600;}

.tabs-nav .tab_cama_off {background-color: #FF9966; border:1px solid #FF9966;}
.tabs-nav .tab_mesa_off {background-color: #FF9966; border:1px solid #FF9966;}
.tabs-nav .tab_banho_off {background-color: #FF9966; border:1px solid #FF9966;}


Escrevi uma classe para manusear a inclusão dos arquivos CSS e Javascript no cabeçalho das páginas. Ele funciona da seguinte maneira:

Imagina que você tenha 10 arquivos CSS, e queira substituir estas 10 inclusões (http_requests) por apenas 2 inclusões. Ou seja, 2 arquivos CSS onde cada um deles tenha embutido, o conteúdo de 5 dos arquivos anteriores. Bom, legal, se fosse só pra isso, bastaria você utilizar uma classe de PHP Minify por exemplo a do VulgarisOverIp.

Mas a grande jogada aqui está no agrupamento dos arquivos, ou seja, você conseguir definir quaise arquivos estarão juntos em cada Package (para fazer o balanceamento de requests x peso por arquivo). E flexibilizar o REBUILD de cada package específico, caso 1 dos arquivos do pacote seja atualizado no futuro (não sendo necessário assim, re-criar todos os pacotes).

O resultado final desta classe PHP é:

<!– EMBEDED SCRIPTS CSS *************************************************** –>
<link rel=”stylesheet” type=”text/css” href=”http://www.exemplo.com/css/style.pk0.min_v.1.0.css&#8221; media=”screen”/>
<link rel=”stylesheet” type=”text/css” href=”http://www.exemplo.com/css/style.pk1.min_v.1.0.css&#8221; media=”screen”/>

<!– EMBEDED SCRIPTS JAVASCRIPT ******************************************** –>
<script type=”text/javascript” src=”http://www.exemplo.com/js/javascript.pk0.min_v.1.0.js”></script&gt;
<script type=”text/javascript” src=”http://www.exemplo.com/js/javascript.pk1.min_v.1.0.js”></script&gt;
<script type=”text/javascript” src=”http://www.exemplo.com/js/javascript.pk2.min_v.1.0.js”></script&gt;

Olhando um pouco mais de perto, a estrutura funciona assim:

//Include the header files handle class file
include(PATH_CLASSES .’/class.headerfiles.php’);
$hFiles = new HeaderFiles;
$hFiles->path_root_CSS = ‘root/www/site/css’;
$hFiles->path_root_JS = ‘root/www/site/js’;
$hFiles->path_public_CSS = ‘http://www.example.com/css&#8217;;
$hFiles->path_public_JS = ‘http://www.example.com/js&#8217;;

// Setting the 2 packages of CSS files – do not use the enxtension file: .css (if the name is: style.css, just use style)
define(‘VERSION_CSS’, ‘1.0’);
define(‘SCRIPTS_CSS’, serialize(array(
‘0’=>array(‘file1’,
‘file2’,
‘1’=>array(‘file3’,
‘file4’,
‘file5’)
)));
define(‘REBUILD_CSS’, serialize(array(‘*’)));

// Generating Embeded CSS
$EMBEDED_SCRIPT_CSS = $hFiles->SetIncludeFiles(unserialize(SCRIPTS_CSS),’css’,VERSION_CSS,’site’,unserialize(REBUILD_CSS));

// Generating Embeded Javascript
// $EMBEDED_SCRIPT_JS = $hFiles->SetIncludeFiles(unserialize(SCRIPTS_JS),’js’,VERSION_JS,’site’,unserialize(REBUILD_JS));

echo $EMBEDED_SCRIPT_CSS;
// result: <link rel=”stylesheet” type=”text/css” href=”……

Para o caso do CSS, esta classe faz a função de MINIFY, retirando comentários e espaços em branco desnecessários dos arquivos CSS de origem. Porém, para os arquivos Javascript, ela apenas agrupa os arquivos dentro dos pacotes, sem fazer nenhuma alteração neles (reduzindo apenas o número de requisições HTTP).

O quê pode melhorar?

  • Incluir a chamada de alguma classe de MINIFY de Javascript, a fim de reduzir o tamanho (Kb) dos pacotes gerados.

Abaixo está o código completo da classe:

<?php

/**
* Project: headerFiles
* File: class.headerfiles.php
*
* Description:
*
* This class is used to manage CSS and JAVASCRIPT files in the header of the page.
* The main feature is not to compress or minify CSS and JS (but this class also do it).
*
* I was focused on really manage this files, what I mean is: Imagine that you
* have a set of 10 CSS files and 10 JS files, and you want to JOIN them into
* 2 packages of 5 files each. (CSS: pk0 , pk1 – JS: pk0, pk1)
*
* When you should to update one of these 5 files (of each pack), you can just
* rebuild the package number what it is inside (not the both package).
*
* With this class you can MINIFY some CSS files and JOIN JS files into some packages containing
* a certain number of files inside it.
*
* More practical:
define(‘VERSION_CSS’, ‘1.0’);
define(‘SCRIPTS_CSS’, serialize(array(
‘0’=>array(‘file1’,
‘file2’,
‘1’=>array(‘file3’,
‘file4’,
‘file5’)
)));
define(‘REBUILD_CSS’, serialize(array(‘*’)));
*
* This will generate 2 Packages (pk0 and pk1), with these CSS files inside it, without comments – minify version)
* The parameter ‘*’ is used to rebuild ALL Packages or generate it at the first time.
*
* If someday you update your ‘file2.css’, just rebuild the package 2 [ serialize(array(‘2’)) ]
* or if you need to Rebuild more than one package, use: [ serialize(array(‘2′,’3′,’4′)) ]
*
* @link https://hlibco.wordpress.com/
* @author Felipe Hlibco <hlibco at gmail dot com>
* @package Header
* @version 1.0.0
*/

/**
* USAGE EXAMPLE
* ————-

//Include the header files handle class file
include(PATH_CLASSES .’/class.headerfiles.php’);
$hFiles = new HeaderFiles;
$hFiles->path_root_CSS = ‘root/www/site/css’;
$hFiles->path_root_JS = ‘root/www/site/js’;
$hFiles->path_public_CSS = ‘http://www.example.com/css&#8217;;
$hFiles->path_public_JS = ‘http://www.example.com/js&#8217;;

// Setting the 2 packages of CSS files – do not use the enxtension file: .css (if the name is: style.css, just use style)
define(‘VERSION_CSS’, ‘1.0’);
define(‘SCRIPTS_CSS’, serialize(array(
‘0’=>array(‘file1’,
‘file2’,
‘1’=>array(‘file3’,
‘file4’,
‘file5’)
)));
define(‘REBUILD_CSS’, serialize(array(‘*’)));

// Generating Embeded CSS
$EMBEDED_SCRIPT_CSS = $hFiles->SetIncludeFiles(unserialize(SCRIPTS_CSS),’css’,VERSION_CSS,’site’,unserialize(REBUILD_CSS));

// Generating Embeded Javascript
// $EMBEDED_SCRIPT_JS = $hFiles->SetIncludeFiles(unserialize(SCRIPTS_JS),’js’,VERSION_JS,’site’,unserialize(REBUILD_JS));

echo $EMBEDED_SCRIPT_CSS;
*
*
*
*/

class HeaderFiles {

var $path_root_CSS;
var $path_root_JS;
var $path_public_CSS;
var $path_public_JS;

/* Public: Include CSS and Javascript files in the header */
/*
PARAMETERS:
$filenamePool: (string | array)
$fileType: (string) ‘css’ | ‘js’
$version: (string)
$pack : (integer) [0] Does not exists a default package [1] Exists a default package
$rebuild: (integer) [0] Do not rebuild ths script [1] Rebuild the script
*/
function SetIncludeFiles($packageFiles, $fileType, $version = ‘1.0’, $object = ‘site’, $rebuild = 0)
{
/* Validate Version */
if (empty($version)) { $version = ‘1.0’; }

/* Add file type default settings */
if ($fileType == ‘css’)
{
$preName = ‘style’;
$pathPublic = $this->path_public_CSS;
$pathRoot = $this->path_root_CSS;
}
elseif ($fileType == ‘js’)
{
$preName = ‘javascript’;
$pathPublic = $this->path_public_JS;
$pathRoot = $this->path_root_JS;
}

/* Identifying Object */
if ($object != ‘site’)
{
$pathPublic .= ‘/’ . $object;
$pathRoot .= ‘/’ . $object;
}

/* Get the files parsed */
if (!is_array($filenamePool) && !empty($filenamePool))
{
$filenamePool = array($filenamePool);
}

/* For each file parsed into package, loop */
foreach($packageFiles as $package=>$files)
{
/* Generate the filename for each object type */
if ($object == ‘site’)
{
$filename = $preName . ‘.pk’ . $package . ‘.min_v.’ . $version . ‘.’ . $fileType;
}
else
{
/* Just allow 1 script file per object (film / filmclub / theater) */
$filename = $packageFiles[0] . ‘.’ . $fileType;
}

/* Validate rebuild activation */
if (!is_array($rebuild)) { $rebuild = array(); }

/* Rebuild some specified package or Re-generate all packages ‘*’ */
if (in_array($package,$rebuild) || in_array(‘*’,$rebuild))
{
/* Handle Files from diferent way */
if ($fileType == ‘css’)
{
foreach($files as $file)
{
$content = file_get_contents($pathRoot . ‘/’ . $file . ‘.’ . $fileType);
$packageContent .= str_replace(‘; ‘,’;’,str_replace(‘ }’,’}’,str_replace(‘{ ‘,'{‘,str_replace(array(“\r\n”,”\r”,”\n”,”\t”,’ ‘,’ ‘,’ ‘),””,preg_replace(‘!/\*[^*]*\*+([^/][^*]*\*+)*/!’,”,$content)))));
}
}
elseif ($fileType == ‘js’)
{
foreach($files as $file)
{
$packageContent .= file_get_contents($pathRoot . ‘/’ . $file . ‘.’ . $fileType);
}
}

$fp = fopen($pathRoot . ‘/’.$filename, ‘w+’);
fwrite($fp, $packageContent);
fclose($fp);
unset($packageContent);
}

/* Generating Tag */
if ($fileType == ‘css’)
{
$outputTag .= ‘<link rel=”stylesheet” type=”text/css” href=”‘ . $pathPublic . ‘/’ . $filename . ‘” media=”screen”/>’ . “\r\n”;
}
elseif ($fileType == ‘js’)
{
$outputTag .= ‘<script type=”text/javascript” src=”‘ . $pathPublic . ‘/’ . $filename . ‘”></script>’ . “\r\n”;
}
}

/* Return the content */
return $outputTag;
}

}
?>