Backup zipado automático de toda base MySQL

1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (Sem votos, vote agora!)
Loading ... Loading ...

Postado por Plinio Cruz em 30 de dezembro de 2009 - Banco de Dados, PHP, Programação | Seja o primeiro a comentar

Na área de sistemas web uma coisa muito importante é o backup da base de dados, afinal um rotina imprópria no sistema pode alterar o banco de dados de forma errada comprometendo a integridade dos dados ou mesmo a consistência das informações. Além disso nenhuma empresa de hospedagem está livre de um problema sério com um servidor que coloque tudo a perder e como muitas não tiram backup podem criar um grande transtorno para o seu cliente.

Nós, da Trio Interativa, desenvolvemos muitos sistemas de gestão de eventos, muitas vezes, durante o processo de inscrições eletrônicas fazemos de três a quatro backup da base do cliente por dia. Além disse, trabalhamos muitas vezes nos sistemas enquanto são utilizados, ou seja, sempre estamos no risco, um código impróprio e podemos mudar tudo na base, então sempre que atualizamos um novo sistema fazemos backup da base também e os outros que normalmente fazemos ao longo do dia nos ajuda na detecção de erros e possíveis inconsistências nos dados.

Com o crescimento do número de clientes e os inúmeros eventos ocorrendo simultaneamente procuramos uma forma de fazer backup de forma rápida, eficiente e que fosse padronizada. Nas muitas pesquisas que fiz achei a uma rotina excelente do Fabio Berbet de Paula, fiz algumas interações no código para padronizá-las para nossa realidade e hoje qualquer profissional da TRIO tem um link para cada cliente, onde com a penas um clique fazemos o backup integral da base em um arquivo ZIP, perfeito e de forma íntegra. Tudo muito fácil e rápido. Veja o código com comentários e as interações que fiz.

Antes de mais nada agradeço ao Fabio Berbet o desenvolvimento do sistema. Para fazer o download do sistema e da classe clique aqui!.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
<?
/*
Programa usado para fazer o dump de uma base de dados do MySQL
 
Por: Fabio Berbert de Paula <fabio@vivaolinux.com.br>
     Rio de Janeiro, 26 de Novembro de 2002
link: http://www.vivaolinux.com.br/script/Backup-do-MySQL-via-PHP
 
Livres Adaptações: Plínio Cruz - Clube da Informática
- Inclusão de arquivo padrão de conexão com a base
- rotina "Lista de Tabelas"
- Padronização do nome do arquivo a ser gravado
 
*/
 
// classe phpzip.inc.php para criar os arquivos compactados
require 'phpzip.inc.php';
 
// variaveis de banco de dados de acordo com o arquivo padrão de conexão
$db_name    = ''; //Nome do banco de dados
$hostdb     = ''; //server do banco de dados
$userdb     = ''; //Usuário de log do banco de dados
$passdb     = ''; //senha do usuário do banco de dados
 
///////////////////////////////////////////////////////////////////////////////////////////////////
//Vamos montar a litas das tabelas do banco de dados escolhido
//Essa rotina foi incluída a original do Fábio, pois antes tínhamos que nomear as tabelas que
//queríamos guardar. Com a nova rotina ele faz o backup do banco como um todo, não precisando
//atualizar o sistema cada vez que você altera a base de dados
///////////////////////////////////////////////////////////////////////////////////////////////////
 
$nome = $db_name;
$link = mysql_connect("$hostdb","$userdb","$passdb");
$resultado_tabelas = mysql_list_tables($nome);
$qntd_tabelas = @mysql_numrows($resultado_tabelas);
if($qntd_tabelas == 0)
    {
      print "<li>Nenhuma tabela foi encontrada neste banco de bados</li>";
      die;
      //Assim "mato" o sistema quando existe um erro
    } else {
              //Aqui vamos criar a rotina para montar a listagem de tabelas
              for ($i = 0; $i < $qntd_tabelas; $i++)
                 {
                    //Temos que determinar as tabelas que não precisam de backup
                    //no meu caso pode ser tabelas como crm, cep, cidade, estado, etc.
                    //No exemplo não faremos backup da "cep" e concatemos as restantes
                    if (mysql_tablename($resultado_tabelas, $i)!='cep')
                    { $tabelas[]= mysql_tablename($resultado_tabelas, $i); };
                 };
              //Temos a array de tabelas pronta
 
           };
 
// as tabelas que quero
//$tabelas = array ('artigos','assuntos'); - Original da rotina do Fabio, onde você montava o array manualmente
//com as tabelas que desejava, a rotina acima faz automaticamente só isso
 
$tempdir = "/tmp"; // diretorio temporario
//$filename = 'sql.'.time().'.txt'; - Modo do Fabio de construir o nome do arquivo
$data = date("dmyhi",time());
$filename = 'nomedocliente.'.$data.'.txt';
//Inclui o nome do banco de dados no nome e a data completa
//Isso porque trabalho com phpmyadmin e MySqlFront e os dois trabalham com essa extensão
//o conteúdo é o mesmo, portanto não fará diferença na hora da gravação
//Na minha opinião facilita para aramazenamento de vários clientes na mesma pasta no servidor local
 
// variaveis do sistema
$incluir_insert = 1; // imprime os INSERT's tambem
 
// ----------------------------------------------------
// BLOCO PRINCIPAL
// conectar ao banco de dados
$con = mysql_pconnect($hostdb,$userdb,$passdb);
mysql_select_db($db_name);
 
// imprimir tipo do documento na tela
 
// imprimir o dump do banco de dados
//chdir($tempdir);
$fp = fopen($filename,"w");
for ($x=0; $x<count($tabelas); $x++) {
   $saida = getTableDef($db_name, $tabelas[$x], "\n");
   fputs($fp,$saida."\n\n");
 
   if ($incluir_insert) {
      getTableContentFast($db_name, $tabelas[$x], '', '');
      fputs($fp,"\n\n");
   }
}
fclose($fp);
 
// gerar o arquivo zipado
$zipname = ereg_replace("txt$","zip",$filename);
$zip = new PHPZip();
$files[]=$filename;
$zip -> Zip($files, $zipname);
 
$tamanho = filesize($zipname);
 
// imprimir arquivo p/ download
header("Content-Type: application/zip");
header("Content-Length: $tamanho");
header("Content-Disposition: attachment; filename=$zipname");
header("Content-Transfer-Encoding: binary");
 
// abrir e enviar o arquivo
$fp = fopen("$zipname", "r");
fpassthru($fp);
fclose($fp);
 
// remover os arquivos temporarios
//unlink($filename);
unlink($zipname);
 
// FIM DO PROGRAMA
// --------------------------------------------------------
 
 
// --------------------------------------------------------
// PROCEDIMENTOS - Baseado no csdigo do phpmyadmin
function sqlAddslashes($a_string = '', $is_like = FALSE) {
  if ($is_like) {
    $a_string = str_replace('\\', '\\\\\\\\', $a_string);
  } else {
    $a_string = str_replace('\\', '\\\\', $a_string);
  }
  $a_string = str_replace('\'', '\\\'', $a_string);
 
  return $a_string;
} // end of the 'sqlAddslashes()' function
 
 
function backquote($a_name, $do_it = TRUE) {
  if ($do_it && PMA_MYSQL_INT_VERSION >= 32306 && !empty($a_name)
      && $a_name != '*') {
 
     if (is_array($a_name)) {
        $result = array();
        reset($a_name);
        while(list($key, $val) = each($a_name)) {
           $result[$key] = '`' . $val . '`';
        }
        return $result;
     } else {
        return '`' . $a_name . '`';
     }
  } else {
     return $a_name;
  }
} // end of the 'backquote()' function
 
/**
* Returns $table's CREATE definition
*
* @param   string   the database name
* @param   string   the table name
* @param   string   the end of line sequence
*
* @return  string   the CREATE statement on success
*
* @global  boolean  whether to add 'drop' statements or not
* @global  boolean  whether to use backquotes to allow the use of special
*                   characters in database, table and fields names or not
*
* @see     PMA_htmlFormat()
*
* @access  public
*/
function getTableDef($db, $table, $crlf) {
   global $drop;
   global $use_backquotes;
   global $con;
 
   $schema_create = '';
   if (!empty($drop)) {
      $schema_create .= 'DROP TABLE IF EXISTS ' .
      backquote($table) . ';' . $crlf;
   }
 
   // For MySQL < 3.23.20
   $schema_create .= 'CREATE TABLE ' .
   backquote($table) . ' (' . $crlf;
 
   $local_query   = 'SHOW FIELDS FROM ' . backquote($table) . ' FROM '
   . backquote($db);
 
   $result = mysql_query($local_query,$con);
 
   while ($row = mysql_fetch_array($result)) {
      $schema_create     .= '   ' .
      backquote($row['Field'])
      . ' ' . $row['Type'];
 
      if (isset($row['Default']) && $row['Default'] != '') {
           $schema_create .= ' DEFAULT \'' .
           sqlAddslashes($row['Default']) . '\'';
      }
 
      if ($row['Null'] != 'YES') {
           $schema_create .= ' NOT NULL';
      }
 
      if ($row['Extra'] != '') {
           $schema_create .= ' ' . $row['Extra'];
      }
 
      $schema_create     .= ',' . $crlf;
   } // end while
 
   mysql_free_result($result);
   $schema_create = ereg_replace(',' . $crlf . '$', '', $schema_create);
 
   $local_query = 'SHOW KEYS FROM ' . backquote($table) . ' FROM '
   . backquote($db);
 
   $result = mysql_query($local_query,$con);
   while ($row = mysql_fetch_array($result)) {
       $kname    = $row['Key_name'];
       $comment  = (isset($row['Comment'])) ? $row['Comment'] : '';
       $sub_part = (isset($row['Sub_part'])) ? $row['Sub_part'] : '';
 
       if ($kname != 'PRIMARY' && $row['Non_unique'] == 0) {
           $kname = "UNIQUE|$kname";
       }
 
       if ($comment == 'FULLTEXT') {
           $kname = 'FULLTEXT|$kname';
       }
 
       if (!isset($index[$kname])) {
           $index[$kname] = array();
       }
 
       if ($sub_part > 1) {
           $index[$kname][] = backquote($row['Column_name']) . '(' . $sub_part . ')';
       } else {
           $index[$kname][] = backquote($row['Column_name']);
       }
   } // end while
   mysql_free_result($result);
 
   while (list($x, $columns) = @each($index)) {
       $schema_create .= ',' . $crlf;
       if ($x == 'PRIMARY') {
          $schema_create .= '   PRIMARY KEY (';
       } else if (substr($x, 0, 6) == 'UNIQUE') {
          $schema_create .= '   UNIQUE ' . substr($x, 7) . ' (';
       } else if (substr($x, 0, 8) == 'FULLTEXT') {
          $schema_create .= '   FULLTEXT ' . substr($x, 9) . ' (';
       } else {
          $schema_create .= '   KEY ' . $x . ' (';
       }
       $schema_create .= implode($columns, ', ') . ')';
   } // end while
 
   $schema_create .= $crlf . ');';
 
   return $schema_create;
} // end of the 'getTableDef()' function
 
/**
* php >= 4.0.5 only : get the content of $table as a series of INSERT
* statements.
* After every row, a custom callback function $handler gets called.
*
* Last revision 13 July 2001: Patch for limiting dump size from
* vinay@sanisoft.com & girish@sanisoft.com
*
* @param   string   the current database name
* @param   string   the current table name
* @param   string   the 'limit' clause to use with the sql query
* @param   string   the name of the handler (function) to use at the end
*                   of every row. This handler must accept one parameter
*                   ($sql_insert)
*
* @return  boolean  always true
*
* @global  boolean  whether to use backquotes to allow the use of special
*                   characters in database, table and fields names or not
* @global  integer  the number of records
* @global  integer  the current record position
*
* @access  private
*
* @see     PMA_getTableContent()
*
* @author  staybyte
*/
function getTableContentFast($db, $table, $add_query = '', $handler) {
   global $use_backquotes;
   global $rows_cnt;
   global $current_row;
   global $con;
   global $fp;
 
  $local_query = 'SELECT * FROM ' . backquote($db) . '.' . backquote($table)
  . $add_query;
 
  $result = mysql_query($local_query,$con);
  if ($result != FALSE) {
     $fields_cnt = mysql_num_fields($result);
     $rows_cnt   = mysql_num_rows($result);
 
     // Checks whether the field is an integer or not
     for ($j = 0; $j < $fields_cnt; $j++) {
         $field_set[$j] = backquote(mysql_field_name($result, $j), $use_backquotes);
         $type = mysql_field_type($result, $j);
         if ($type == 'tinyint' || $type == 'smallint' ||
             $type == 'mediumint' || $type == 'int' ||
             $type == 'bigint'  ||$type == 'timestamp') {
             $field_num[$j] = TRUE;
         } else {
             $field_num[$j] = FALSE;
         }
     } // end for
 
     // Sets the scheme
     if (isset($GLOBALS['showcolumns'])) {
         $fields = implode(', ', $field_set);
         $schema_insert = 'INSERT INTO ' . backquote($table)
         . ' (' . $fields . ') VALUES (';
     } else {
         $schema_insert = 'INSERT INTO ' .
         backquote($table) . ' VALUES (';
     }
 
     $search = array("\x00", "\x0a", "\x0d", "\x1a"); //\x08\\x09, not required
     $replace      = array('\0', '\n', '\r', '\Z');
     $current_row  = 0;
 
     @set_time_limit($GLOBALS['cfg']['ExecTimeLimit']);
 
     // loic1: send a fake header to bypass browser timeout if data
     //        are bufferized - part 1
     if (!empty($GLOBALS['ob_mode']) || (isset($GLOBALS['zip'])
         || isset($GLOBALS['bzip']) || isset($GLOBALS['gzip']))) {
         $time0 = time();
     }
 
     while ($row = mysql_fetch_row($result)) {
         $current_row++;
         for ($j = 0; $j < $fields_cnt; $j++) {
            if (!isset($row[$j])) {
                 $values[] = 'NULL';
            } else if ($row[$j] == '0' || $row[$j] != '') {
                 // a number
                 if ($field_num[$j]) {
                     $values[] = $row[$j];
                 } else {
                    // a string
                    $values[] = "'" . str_replace($search, $replace,
                    sqlAddslashes($row[$j])) . "'";
                 }
           } else {
              $values[] = "''";
           } // end if
        } // end for
 
        // Extended inserts case
        if (isset($GLOBALS['extended_ins'])) {
            if ($current_row == 1) {
               $insert_line  = $schema_insert . implode(', ', $values) . ');';
            } else {
               $insert_line  = '(' . implode(', ', $values) . ');';
            }
        } else {
        // Other inserts case
           $insert_line = $schema_insert . implode(', ', $values) . ');';
        }
        unset($values);
 
        // Call the handler
        fputs($fp,$insert_line . "\n");
 
        // loic1: send a fake header to bypass browser timeout if data
        //        are bufferized - part 2
        if (isset($time0)) {
            $time1 = time();
            if ($time1 >= $time0 + 30) {
               $time0 = $time1;
               header('X-pmaPing: Pong');
            }
        } // end if
     } // end while
  } // end if ($result != FALSE)
  mysql_free_result($result);
 
  return TRUE;
} // end of the 'getTableContentFast()' function
?>

Formatação de números em PHP

1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (1 votos, média: 5,00)
Loading ... Loading ...

Postado por Plinio Cruz em 13 de agosto de 2009 - PHP, Programação | Leia o primeiro comentário

Verificando se o número é PAR ou IMPAR

<?php
function verNumero($numero)
{  // Verificando o resto da divisão por 2
   if($numero % 2 == 0)
   {  // Se o resto for igual a zero é par
      return "PAR";
   }
   else
   {  // Caso não seja zero é impar
      return "IMPAR";
   }
}
$n = 654646570;
// Chamando a função e passando o parametro
echo verNumero($n);
?> 

Trabalhando com potênciação

<?php
function calcula_potencia($base,$expoente){
    $nuns = $base;
    // For de 1 até o valor do expoente
    for($c = 1;$c < $expoente;$c++){
        $nuns = $nuns * $base;
    }
    $verifica = explode("E",$nuns);
    if(count($verifica) > 1) {
        $nuns = "Expoente muito elevado.";
    }
    return $nuns ;
}
// Chamando a função passando base 7 e expoente 2
$potenciacao = calcula_potencia(7,2);
// Imprimindo na tela o resultado
echo $potenciacao;
?>

Verificando se um número é primo

<?php
$num = 1234567891;
if(nPrimo($num))
{
	echo "$num é primo.";
}
else
{
	echo "$num não é primo.";
}
function nPrimo($numero)
{   //com $numero > 2
    $p = 2 ;
    while($numero % $p != 0 && $p < sqrt($numero) ) $p+=1 ;
    // 1 = Primo / 0 = ñ Primo
    return ($numero%$p==0) ? 0 : 1 ;
}
?>

Trabalhando com Fatoração

<?php
$num = 123456789;
$resposta = fatorarando($num);
echo "Seus fatores: ";
foreach($resposta as $aux) echo "$aux ";
function fatorarando($numero)
{
	// $numero > 2
    $x=2 ;
    while($numero != 1)
    {
        if($numero % $x == 0)
        {   // Vetor recebendo a variavel $x
            $vet[] = $x;
            $numero = $numero/$x;
        }
        else
        {
        	$x++;
        }
    }
    return $vet;
}
?>

Formatando moeda

<?php
// Recebe o parametro $numero
// Existe outra maneira muito mais fácil
// Mas o objetivo e trabalhar seus conhecimentos
function formata($numero)
{
	if(strpos($numero,'.')!='')
	{
		   $var=explode('.',$numero);
		   if(strlen($var[0])==4)
		   {
		     $parte1=substr($var[0],0,1);
		     $parte2=substr($var[0],1,3);
		     if(strlen($var[1])&lt;2)
		     {
		     	$formatado=$parte1.'.'.$parte2.','.$var[1].'0';
		     }else
		     {
		     	$formatado=$parte1.'.'.$parte2.','.$var[1];
		     }
		   }
		   elseif(strlen($var[0])==5)
		   {
		     $parte1=substr($var[0],0,2);
		     $parte2=substr($var[0],2,3);
		     if(strlen($var[1])&lt;2)
		     {
		     	$formatado=$parte1.'.'.$parte2.','.$var[1].'0';
		     }
		     else
		     {
		     	$formatado=$parte1.'.'.$parte2.','.$var[1];
		     }
		   }
		   elseif(strlen($var[0])==6)
		   {
		     $parte1=substr($var[0],0,3);
		     $parte2=substr($var[0],3,3);
		     if(strlen($var[1])&lt;2)
		     {
		     	$formatado=$parte1.'.'.$parte2.','.$var[1].'0';
		     }
		     else
		     {
		     	$formatado=$parte1.'.'.$parte2.','.$var[1];
		     }
		   }
		   elseif(strlen($var[0])==7)
		   {
		     $parte1=substr($var[0],0,1);
		     $parte2=substr($var[0],1,3);
		     $parte3=substr($var[0],4,3);
		     if(strlen($var[1])&lt;2)
		     {
		     	$formatado=$parte1.'.'.$parte2.'.'.$parte3.','.$var[1].'0';
		     }
		     else
		     {
		     $formatado=$parte1.'.'.$parte2.'.'.$parte3.','.$var[1];
		     }
		   }
		   elseif(strlen($var[0])==8)
		   {
		     $parte1=substr($var[0],0,2);
		     $parte2=substr($var[0],2,3);
		     $parte3=substr($var[0],5,3);
		     if(strlen($var[1])&lt;2){
		     $formatado=$parte1.'.'.$parte2.'.'.$parte3.','.$var[1].'0';
		     }else{
		     $formatado=$parte1.'.'.$parte2.'.'.$parte3.','.$var[1];
		     }
		   }
		   elseif(strlen($var[0])==9)
		   {
		     $parte1=substr($var[0],0,3);
		     $parte2=substr($var[0],3,3);
		     $parte3=substr($var[0],6,3);
		     if(strlen($var[1])&lt;2)
		     {
		     	$formatado=$parte1.'.'.$parte2.'.'.$parte3.','.$var[1].'0';
		     }
		     else
		     {
		     	$formatado=$parte1.'.'.$parte2.'.'.$parte3.','.$var[1];
		     }
		   }
		   elseif(strlen($var[0])==10)
		   {
		     $parte1=substr($var[0],0,1);
		     $parte2=substr($var[0],1,3);
		     $parte3=substr($var[0],4,3);
		     $parte4=substr($var[0],7,3);
		     if(strlen($var[1])&lt;2)
		     {
		     	$formatado=$parte1.'.'.$parte2.'.'.$parte3.'.'.$parte4.','.$var[1].'0';
		     }
		     else
		     {
		     	$formatado=$parte1.'.'.$parte2.'.'.$parte3.'.'.$parte4.','.$var[1];
		     }
		   }
		   else
		   {
		     if(strlen($var[1])&lt;2)
		     {
		    	 $formatado=$var[0].','.$var[1].'0';
		     }
		     else
		     {
		    	 $formatado=$var[0].','.$var[1];
		     }
		   }
	  }
	  else
	  {
	     $var=$numero;
	   if(strlen($var)==4)
	   {
	     $parte1=substr($var,0,1);
	     $parte2=substr($var,1,3);
	     $formatado=$parte1.'.'.$parte2.','.'00';
	   }
	   elseif(strlen($var)==5)
	   {
	     $parte1=substr($var,0,2);
	     $parte2=substr($var,2,3);
	     $formatado=$parte1.'.'.$parte2.','.'00';
	   }
	   elseif(strlen($var)==6)
	   {
	     $parte1=substr($var,0,3);
	     $parte2=substr($var,3,3);
	     $formatado=$parte1.'.'.$parte2.','.'00';
	   }
	   elseif(strlen($var)==7)
	   {
	     $parte1=substr($var,0,1);
	     $parte2=substr($var,1,3);
	     $parte3=substr($var,4,3);
	     $formatado=$parte1.'.'.$parte2.'.'.$parte3.','.'00';
	   }
	   elseif(strlen($var)==8)
	   {
	     $parte1=substr($var,0,2);
	     $parte2=substr($var,2,3);
	     $parte3=substr($var,5,3);
	     $formatado=$parte1.'.'.$parte2.'.'.$parte3.','.'00';
	   }
	   elseif(strlen($var)==9)
	   {
	     $parte1=substr($var,0,3);
	     $parte2=substr($var,3,3);
	     $parte3=substr($var,6,3);
	     $formatado=$parte1.'.'.$parte2.'.'.$parte3.','.'00';
	   }
	   elseif(strlen($var)==10)
	   {
	     $parte1=substr($var,0,1);
	     $parte2=substr($var,1,3);
	     $parte3=substr($var,4,3);
	     $parte4=substr($var,7,3);
	     $formatado=$parte1.'.'.$parte2.'.'.$parte3.'.'.$parte4.','.'00';
	   }
	   else
	   {
	     $formatado=$var.','.'00';
	   }
	}
	  return $formatado." Reais";
}
$num = 1234567890;
echo formata($num);
?>

Formatação para número inteiro

<?php
// Formatação para numero inteiro
$number = "1234567890000000";
$number=number_format($number,0,'.','.');
echo $number;
// resultado 1.234.567.890.000.000
?>

Formatação para número monetário

<?php
// Formatação para numero monetário
$number = "1234567890000000";
$number=number_format($number,2,',','.');
echo $number;
// resultado 1.234.567.890.000.000,00
?>

Formatação para número inteiro com espaçamento a cada 3 casas

<?php
// Formatação para numero inteiro com espaçamento a cada 3 casas
$number = "1234567890000000";
$number=number_format($number,0,'.',chr(0xA0));
echo $number;
// resultado 1 234 567 890 000 000
?>

Formatação para número em reais com decimal 99

<?php
// Formatação para numero em reais com decimal 99
$number = "2229346.99";
echo "R$" .number_format($number, 2, ',', '.');
// resultado R$2.229.346,99
?>

Formatação para número em reais com decimal 00

<?php
// Formatação para número em reais com decimal 00
$number = "222934699";
echo "R$" .number_format($number, 2, ',', '.');
// resultado R$222.934.699,00
?>

Formatação para número em reais sem decimal

<?php
// Formatação para número em reais sem decimal
$number = "222934699";
echo "R$" .number_format($number, 0, ',', '.');
// resultado R$222.934.699
?>

Formatação para número colocando virgula a cada 3 casas

<?php
// Colocando virgula a cada 3 casas
// Recebendo o valor por parametro
function formatar($input)
{
  if(strlen($input)<=3)
  { return $input; }
  $length=substr($input,0,strlen($input)-3);
  $formatted_input = formatar($length).",".substr($input,-3);
  return $formatted_input;
}
// numero a ser passado por parametro
$num = 1234567;
// imprimindo o valor
echo  formatar($num);
// resultado 1,234,567
?>

Formatação para número colocando ponto a cada 3 casas

<?php
// Colocando ponto a cada 3 casas
// Recebendo o valor por parametro
function formatando($input)
{
  if(strlen($input)<=3)
  { return $input; }
  $length=substr($input,0,strlen($input)-3);
  $formatted_input = formatando($length).".".substr($input,-3);
  return $formatted_input;
}
// numero a ser passado por parametro
$num = 1234567;
// imprimindo o valor
echo  formatando($num);
// resultado 1.234.567
?>

Por:
Carlos Silva
Desenvolvedor web, certificado ISPA CYCLADES e Macromedia. Desenvolvedor usando as tecnologias C#, JSP, PHP, JavaScript, XML, ABAP, Tableless e outros. Certificado em Segurança da Informação e atualmente trabalhando com ativos de Rede Cisco.
Em: Revista PHP

Validação do CPF em PHP

1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (1 votos, média: 5,00)
Loading ... Loading ...

Postado por Plinio Cruz em 11 de julho de 2009 - PHP, Programação, Soluções | 3 Comentário para ler

Um dos artigos mais lidos do Clube da Informática é sobre o algortimo de validação do CPF, temos aqui no escritório essa validação em formato de função, utilizamos muito, temos em Java Script para os sistemas web e em formato de procedimento para Pascal, quando utilizamos o Delphi.

Estamos com um dos nossos clientes do Hermes que necessita fazer um formulário para colher inscrições para seu próximo evento dentro do hotsite do seu cliente, o problema é que estamos falando de uma das maiores empresa de assistência médica do país, que utiliza servidores próprios com programação de área restrita em seu site, busca e inúmeras ferramentas.

Para criar o menor impacto possível e agilizar o processo, nossa proposta foi a seguinte: vamos fazer todo o processo de inscrição (quatro telas) em um só arquivo de PHP, utilizando o banco de dados do nosso servidor e ainda, só utlizando o mais puro PHP, sem java script, sem AJAX, sem framework, sem nada que pudesse rivalizar ou incompatibilizar ferramentas do cliente ou as nossas próprias, ou ainda que necessitasse interação com o servidor para instalação, sendo assim enviaremos o arquivo para a empresa testado e pronto para colocação no hotsite do evento

Uma das rotinas que precisamos é de validação do CPF, que antes usamos em Java Script para poupar tempo e processos pela Internet, uma validação em JS dentro do site, quando acionado o botão de enviar a validação ocorre sem enviar os dados, ou seja, é mais rápido. No caso proposto vamos utilizar só PHP e uma única vez em cada inscrição realizada haverá validação, então deixamos de lado a função e incomporamos de forma bem enxuta a rotina.

Estamos tratando os dados na fonte, mesmo com o aviso de entrar só números, normalmente o usuários não prestam muito atenção nas instruções e já que vamos ter que “enviar” os dados por post e fazer a validação para retornar o resultado, vamos optar por tratar os dados, vamos fazer uma rotina para retirar sinais e espaços em branco da entrada, para evitar erros na validação e obrigar o usuário a verificar e reenviar os dados, o que aumentaria o processo e o número de vezes a interação com o trânsito de dados na internet.

      $sinais= array("/"," ",".","-",",");
      $cpf=str_replace($sinais,"",$_POST['cpf']);

Após a verificação vamos aplicar de forma matemática e direto a validação do algoritmo do processo do artigo já apresentado aqui no site. Confira o código:

      ///////////////////////////////////////
      //Valida o CPF - Algoritmo do Clube
      ///////////////////////////////////////
          $cpf_validar=substr($cpf,0,9);
          $soma=0; $n=11;
          for ($i=0;$i<=9;$i++)
                {
                   $n=$n-1;
                   $soma=$soma+(substr($cpf_validar,$i,1)*$n);
                };
          $resto= $soma % 11;
          if ($resto<2) {$cpf_validar=$cpf_validar."0";} else {$cpf_validar=$cpf_validar.(11-$resto);};
          //Segunda parte da validação do CPF
          $soma=0; $n=12;
          for ($i=0;$i<=10;$i++)
                {
                   $n=$n-1;
                   $soma=$soma+(substr($cpf_validar,$i,1)*$n);
                };
          $resto= $soma % 11;
          if ($resto<2) {$cpf_validar=$cpf_validar."0";} else {$cpf_validar=$cpf_validar.(11-$resto);}
          if ($cpf_validar==$cpf) {$erro=1;} else {$erro=0;$mensagens="CPF Inválido";};

As únicas obserrvações é que criamos um flag para o erro, ou seja, quando recebe “1″ está ok, caso contrário recebe “0″ e cria uma variável com a mensagem de erro. Espero que a rotina ajude a entender melhor o artigo e vice e versa. Qualquer dúvida escreva!

abraço

Plínio Cruz

Desenvolvendo plugins para WordPress

1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (1 votos, média: 5,00)
Loading ... Loading ...

Postado por Plinio Cruz em 1 de abril de 2009 - PHP, Programação | Seja o primeiro a comentar

Uma peça chave do sucesso do WordPress é justamente sua capacidade de aceitar plugins e widgets, além , é claro, dos milhares de programadores que desenvolvem os mais diversos plugins que fazem de tudo um pouco.

Algum tempo atrás fui abordado pelo Manoel Lemos do BlogBlogs para discutirmos uma missão, criar um plugin para o WordPress, baseado na API do site. Comecei entao minha saga atrás de como desenvolver um plugin. O material estava lá, espalhado em vários sites, mas estava lá.

Então agora com o sucesso do BBUinfo e na véspera de novos projetos, decidi tentar consolidar este conhecimento adquirido e focar ele no público brasileiro. Vou procurar mostrar o caminho das pedras de como começar e onde buscar os dados necessário para integrar seu código ao do WP.

O WP, como eu disse, foi desenhado com plugins em mente. Sua estrutura possui diversos componentes desenhados para que seu plugin se “encaixe” no ponto certo (attach points ou hooks) e na hora certa. Mas para isso é importante observar alguns passos, para melhor desenhar seu plugin.

Os passos a seguir são a minha recomendação de como desenvolver um plugin, e evitar maiores problemas e dificuldades. Para poder acompanhar melhor o código produzido, vou estar criando com vocês o meuPrimeiroPlugin, que será descrito passo a passo abaixo.

Passo 1: Planejamento

No desenvolvimento de qualquer sistema o primeiro passo deve sempre ser uma análise e planejamento do que será feito, com plugins, embora pequenos, isto se mantém.Como em sistemas é importante identificar neste momento o que se deseja fazer, qual o objetivo do plugin. Levantar entradas e saídas, dados externos e suas fontes, enfim, definir de forma geral o que o plugin faz, com que dados ele faz isso e como obter os dados necessários.Faça perguntas como:

  • Preciso de um banco de dados?
  • Preciso acessar dados externos por webservice ou uma API?
  • Vou mostrar algo visual para o usuário?
  • O que pretendo fazer?
  • Qual o nome darei ao plugin?(se você consegue definir o nome, sabe o que quer)

Um bom exercício para este momento é utilizar o padrão de arquivo readme do WP e já iniciar a escrita da descrição resumida e detalhada do plugin, pois este será seu guia.

Obs: Produtos desta etapa: Arquivo readme.txt, arquivo com “brainstorm” (tente um mindmap, como acima)

Passo 2: Projeto

Esta etapa segue os padrões de projetos de sistema, mas com algumas adições específicas do WordPress. Como base sugiro que use a linguagem UML para definir seu projeto e faça um diagrama de MER (base de dados).

Embora não seja obrigatório, a criação do plugin como um objeto, é recomendável e mais fácil de manter do que código estruturado, além claro de ser uma “prática recomendada” para o PHP5. Outra grande vantagem nesta orientação é que como os métodos são chamados de dentro do objeto a preocupação com “nomes coincidentes” é nula, sendo reduzida apenas ao nome do objeto que deve ser único.

Então defina o seu objeto com métodos que se identifiquem com as diversas ações que o plugin vai executar, por exemplo: adicionarAssinatura(), pegarDadosExternos(), salvarDados()…

Agora entra o ponto onde o WordPress traz toda sua mágica com os seus “hooks”, ou ganchos.

Ganchos do WordPress

Para facilitar que se ligue o plugin às ações doWP, são definidos ganchos em sua programação, ou seja, em pontos específicos do funcionamento do plugin, são disponibilizados pontos onde as funções podem se “pendurar”. Desta forma caso deseje criar um plugin, que deve executar determinada função no momento em que um comentário é salvo, você usaria o gancho “comment_post”. Estes ganchos são divididos em 2, ações e filtros. Ações são eventos disparados em momentos exatos durante a execução do WordPress.
Filtros são lançados no momento de gravação ou apresentação de um texto para que seja possível modificá-lo.
 

Para definir os ganchos você pode se perguntar “Em que momento devo fazer isso?” para cada ação e então verificar a lista de ganchos de ações e filtros para achar qual lhe atende.

meuPrimeiroPlugin

Neste caso podemos usar os seguintes pontos para anexar nossas funções:

  1. Instalar: ligada ao “register_activation_hook” que é executado na ativação de um plugin no menu
  2. Desinstalar: Estas funções foram bastante discutidas, mas ainda não existe um hook fixo.
  3. Inicializar: Esta deve ser executada logo no início, para isso temos o filtro “init”
  4. Aba de opções: para fazer a aba precisamos de dois pontos, a ação “admin_menu” e o “add_options_page”.
  5. Contar Visita: poderia ser melhor,mas o filtro “the_content” garante a contagem na hora mais certa.
  6. Inserir texto no comentário: Para isso o filtro “get_comment_text” é perfeito
  7. Substituir palavras: este é bem direto também, vamos usar o filtro “the_content”

Juntamente com este raciocínio, fiz o mapeamento da classe e do que seria necessário na base de dados:

Diagrama de classe do plugin:

Mer do Banco

Mer do Banco

 Obs: Produtos desta etapa: diagrama de classe do seu plugin, um MER do banco de dados e uma lista de possíveis pontos de inserção (ganchos).

Passo 3: Desenvolvendo

Com o caminho a sua frente devidamente mapeado, agora podemos nos aprofundar no código, além de conhecer algumas possibilidades que o WP traz embutidas em si mesmo.

O ideal é que seu plugin caiba dentro de um arquivo só, mas caso isso não seja possível, recomenda-se que todos arquivos sejam jogados dentro de uma pasta com o mesmo nome do plugin. O nome do plugin também pode (recomenda-se) ser o nome de seu arquivo principal, isso irá lhe facilitar usar funções “on activation” disparadas na ativação do plugin. Portanto teremos a seguinte estrutura para nosso exemplo:

 

A primeira coisa que deve aparecer em nosso arquivo meuPrimeiroPlugin.php é o cabeçalho. Este cabeçalho é usado pelo WP para mostrar os dados de seu plugin na página de administração de plugins, então é muito importante manter estes dados corretos, o cabeçalho segue o padrão abaixo:

/*
Plugin Name: Nome do Plugin
Plugin URI: http://Endereço_da_pagina
Description: Descrição simples e curta do plugin
Version: A versão atual do plugin, ex.: 1.0
Author: Nome do Autor do Plugin
Author URI: http://Endereço_do_site_do_autor
*/

Após isso podemos começar a definir a classe. A definição segue o padrão normal de um objeto em PHP (4 ou 5). Aqui vamos seguir uma orientação PHP5 por sua enorme vantagem e pelo “fim” do PHP.

O site do WP possui muito material sobre padrões de codificação, e eu recomendo uma leitura, mas são padrões bem estabelecidos que muitos programadores já devem usar normalmente.

Como vimos no passo anterior montamos um diagrama de classe e nesse diagrama já identificamos as funções que precisamos desenvolver em nosso plugin, portanto a seguir vou seguir passo a passo deste arquivos criando e explicando cada uma destas funções, e no final comentarei sobre os ganchos que serão colocados fora do escopo do objeto e porque.

Função Inicializar

Esta função serve para centralizar todas as ações que devem ser sempre tomadas para integrar o plugin com o WP, sejam elas ações de adição/remoção de filtros/ações ou instanciação de objetos, cópias de variáveis globais, enfim, todas ações que serão executadas sempre que o WP carregar.

public static function inicializar(){
global $wpdb;
 
//Definir ganchos
add_filter("get_comment_text", array("meuPrimeiroPlugin","exonerarComentarios"));
add_filter("the_content", array("meuPrimeiroPlugin","contarVisita"));
add_filter("the_content", array("meuPrimeiroPlugin","processarSubstituicao"));
add_action('admin_menu', array('meuPrimeiroPlugin','adicionarMenu'));
 
//Mapear objetos WP
meuPrimeiroPlugin::$wpdb = $wpdb;
 
//Outros mapeamentos
meuPrimeiroPlugin::$info['plugin_fpath'] = dirname(__FILE__);
 
}

Como podemos ver, no caso do meuPrimeiroPlugin, estamos cadastrando as outras funções com seus devidos filtros, ou seja, os ganchos que irão executá-las e copiando o objeto $wpdb para dentro do nosso script, podendo agora ser referenciado como: meuPrimeiroPlugin::$wpdb que é melhor que ficar sempre usando “global” no início da função. Além disso aproveita-se para obter a localização do plugin, usando a constante __FILE__ do PHP que define o caminho até o arquivo onde esta.

$wpdb: Este objeto sempre presente no WordPress é responsável pela sua conexão com a base de dados, ele pode executar queries, buscar dados, e realizar diversas funções relacionadas a base de dados.

Função Instalar

para ser executada no momento que o plugin é ativado na aba de plugins do WordPress. Como nosso plugin utiliza dados que serão salvos e lidos de bases de dados é necessário que elas sejam criadas antes de seu uso, o momento de ativação é excelente para isso, porém o plugin pode ser ativado e desativado diversas vezes (quando se faz upgrade do WordPress por exemplo) e não podemos simplesmente criar a tabela sempre, por isso observe o comando para criar apenas caso não exista.

public static function instalar(){
 
if ( is_null(meuPrimeiroPlugin::$wpdb) ) meuPrimeiroPlugin::inicializar();
 
//Criar base de dados
$sqlContador = "CREATE TABLE IF NOT EXISTS `".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas` (
`id_post` INT NOT NULL ,
`visitas` INT NULL ,
PRIMARY KEY (`id_post`) )";
 
$sqlPalavras = "CREATE TABLE IF NOT EXISTS `".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao` (
`idmpp_substituicao` INT NOT NULL AUTO_INCREMENT ,
`orig_palavra` VARCHAR(255) NULL ,
`subst_palavra` VARCHAR(255) NULL ,
PRIMARY KEY (`idmpp_substituicao`) )"; 
meuPrimeiroPlugin::$wpdb->query($sqlContador);
meuPrimeiroPlugin::$wpdb->query($sqlPalavras);
 
//Criar opções
add_option("mpp_texto_exonerar","O conteúdo deste comentário é de responsabilidade de: ");
}

Neste caso, de forma puramente didática, criei uma opção para armazenar o texto que será inserido nos comentários. Esta opção foi criada apenas para mostrar como elas podem ser utilizadas. Estas opções são gravadas na tabela de opções do próprio WordPress e acessadas com estes métodos: add_option, update_option, delete_option, get_option.

Note que no ínicio da função chamo a função de inicialização, isso é importante pois no ato em que a função de instalação é chamada o gancho “init” ainda não foi chamado e por isso não temos nossa conexão com o banco por exemplo. Isto causaria erros na ativação do plugin.

Dica: Se você receber um aviso “cannot redeclare class” na ativação do plugin, 9 em 10 vezes o erro não esta na declaração do plugin e sim omitido pelo WordPress, em sua função de captura de erros, que infelizmente possui algumas falhas, como essa. Para ver o erro verdadeiro vá até o arquivo wp-admin/plugin.php e comente as linhas 14 e 15, mostradas abaixo:

wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), 'plugins.php?error=true&plugin=' . $plugin)); // we'll override this later if the plugin can be included without fatal error
ob_start();

 
Função Desinstalar

Esta função não possui um hook para ser executada de forma automática, mas é uma função que recebeu muita atenção nos últimos tempos em diversas discussões pela internet. Nossa aba de opções deve implementar uma chamada a esta função, mas em breve o WordPress deve implementar um hook para ela.

Sua função é bem direta e simples, remover tudo que foi criado pela função de instalação. Por isso não é possível ligar ela ao ato de “desativar” o plugin, pois o usuário perderia suas preferências a cada vez que fizesse upgrade do WordPress (é recomendado que se desative os plugins para tal).

public static function desinstalar(){
 
//Remover bases de dados
$sqlContador = "DROP TABLE `".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas`";
$sqlPalavras = "DROP TABLE `".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao`";
 
meuPrimeiroPlugin::$wpdb->query($sqlContador);
meuPrimeiroPlugin::$wpdb->query($sqlPalavras);
 
//Remover opções
delete_option("mpp_texto_exonerar");
}

Como podemos ver apenas é feito um DROP nas tabelas e a remoção da opção que foi criada na própria tabela do WordPress.

Função adicionarMenu
Esta função indica ao WordPress que ao montar o menu da administração ele deve inserir uma nova aba que aponta para uma função de nosso plugin.

public static function adicionarMenu(){
add_options_page('meuPrimeiroPlugin - Gerenciamento','meuPrimeiroPlugin',10,__FILE__,array("meuPrimeiroPlugin","abaOpcoes"));
}

A sintaxe deste comando é a seguinte:

add_menu_page(titulo_da_pagina, titulo_do_menu, nivel_de_acesso, arquivo, [função]);

O nível de acesso diz respeito as permissões do usuário, o arquivo é o arquivo de nosso plugin (__FILE__) e a função é a função de nossa classe em formato de call_user_func.

Função abaOpcoes

Esta função é a que setamos no exemplo anterior para ser executada quando o usuário clicar na nossa aba do menu. Neste caso fiz uma implementação simplificada, onde uma mesma função mostra o menu e executa as operações de salvar e atualizar as opções.

Para salvar as opções fazemos inserções usando novamente o $wpdb->query(). Esta operação é executada sempre que o array de POST (dados enviados pelo form) possuir algum conteúdo. Para mostrar o formulário utilizei uma implementação simplificada de templates, onde tenho um arquivo .tpl externo com o layout do menu e chaves especiais ({PALAVRAS},{STATS}…) que são substituídas pelo conteúdo que quero gerar. Você pode usar outra técnica e até usar código espageti com HTML no meio de seu plugin, depende da sua facilidade e organização. Para gerar o conteúdo dinâmico, faço diversas queries no banco buscando os dados que são necessários.

public static function abaOpcoes(){
 
//Predefinidos
$templateVars['{UPDATED}'] = "";
$templateVars['{ERROS}'] = "";
 
//Executar operações definidas
if (count($_POST)> 0){
$ins = meuPrimeiroPlugin::$wpdb->query("INSERT INTO ".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao
(idmpp_substituicao,orig_palavra,subst_palavra)
VALUES
(NULL,'".$_POST['orig']."','".$_POST['subst']."')
");
$templateVars['{UPDATED}'] = '<div id="message" class="updated fade"><p><strong>';
if ($ins){
$templateVars['{UPDATED}'] .= "Dados atualizados!";
}else{
$templateVars['{UPDATED}'] .= "Erro ao atualizar dados!";
}
$templateVars['{UPDATED}'] .= "</strong></p></div>";
}
 
//Ler arquivo de template usando funções do WP
$admTplObj = new FileReader(meuPrimeiroPlugin::$info['plugin_fpath']."/admin_tpl.htm");
$admTpl = $admTplObj->read($admTplObj->_length);
 
//pegar palavras
$resultados = meuPrimeiroPlugin::$wpdb->get_results( "SELECT orig_palavra,subst_palavra FROM ".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao" );
foreach($resultados as $res){
$palavras .= "<li><b>".$res->orig_palavra." -></b> ".$res->subst_palavra."</li>";
}
$templateVars['{PALAVRAS}'] = $palavras;
 
//pegar estatisticas
$resultados = meuPrimeiroPlugin::$wpdb->get_results( "SELECT post_title,visitas FROM ".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas
LEFT JOIN ".meuPrimeiroPlugin::$wpdb->prefix."posts AS posts ON mpp_post_visitas.id_post = posts.ID" );
foreach ($resultados as $res){
$stats .= "<dt>".$res->post_title."</dt>";
$stats .= "<dd>".$res->visitas." Visitas</dd>";
}
$templateVars['{STATS}'] = $stats;
 
//Substituir variáveis no template
$admTpl = strtr($admTpl,$templateVars);
 
echo $admTpl;
 
}

Observe o uso da classe FileReader para leitura do arquivo .tpl. Esta classe é nativa do WordPress portanto a preferência de se utilizar ela ao invés de utilizar funções como fopen ou similares. É importante lembrar que o WordPress possui diversas classes disponíveis em suas pastas, e é uma boa idéia ver se existe alguma para executar a operação que você procura.

Função contarVisita

Como foi dito esta função é convocada pelo gancho “the_content” sempre que o conteúdo de um post for resgatado do banco para exibição. Então para fazer uma simples contagem de visualizações de um post, sem entrar em muitos detalhes, filtros por IP nem nada do tipo, apenas fazemos uma inserção no banco, em nossa tabela de contagem.

public static function contarVisita($post_texto){
global $post;
 
$sql = "INSERT INTO ".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas (id_post,visitas) VALUES ('".$post->ID."',1)
ON DUPLICATE KEY UPDATE visitas=visitas+1";
meuPrimeiroPlugin::$wpdb->query($sql);
 
return $post_texto;
}

Note neste caso que a função recebe um parâmetro que chamei de $post_texto. Sempre que uma função usa o gancho “the_content” ela receberá o conteúdo do post como parâmetro. Ao final da função este conteúdo, alterado ou não, deve ser retornado com uma chamada return, caso contrário o blog não exibirá o conteúdo do post.

Para o comando de SQL caso interesse usei o ON DUPLICATE KEY UPDATE, que verifica se já existe um registro para o post e faz a atualização do mesmo, caso contrário cria o novo registro. Ela é bem útil para não ser necessário fazer um select para decidir se devemos usar um INSERT ou UPDATE.

Função processarSubstituicao

Esta função, também ligada ao “the_content” efetua a troca das palavras que cadastrarmos, por outras que forem escolhidas. É interessante notar que podemos ter várias funções ligadas a um mesmo gancho e elas serão executadas na ordem que os ganchos são designados, por isso a importância ressaltada na função anterior, onde o parâmetro deve ser retornado no final.

Para fazer a substituição usei um método simples também, busquei no banco os pares (palavra original => nova palavra) e montei um array de “tradução”. Usando a função strtr do PHP eu passo este array e o texto do post e a função se encarrega de fazer a troca e me devolver o texto alterado.

public static function processarSubstituicao($post_texto){
 
//Montar array de palavras para substituirmos
$resultados = meuPrimeiroPlugin::$wpdb->get_results("SELECT orig_palavra,subst_palavra FROM ".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao");
 
foreach($resultados as $res){
$aTraducao[$res->orig_palavra] = $res->subst_palavra;
}
 
$post_text = strtr($post_texto,$aTraducao);
 
return $post_texto;
}

 

Função exonerarComentarios

Finalmente esta função será a responsável por incluir um texto ao final do comentário para nos exonerar das palavras do seu autor. Para isto usamos o gancho get_comment_text que é similar ao get_content acima, mas se refere ao comentário.

public static function exonerarComentarios($cmt_texto){
global $comment;
 
$anexo = "<br><br><b><i>".get_option('mpp_texto_exonerar').$comment->comment_author."</i></b>";
 
$cmt_texto .= $anexo;
 
return $cmt_texto;
}

Como antes, recebemos o texto como parâmetro e devemos retornar ele ao final para evitar quebrar outros plugins ou ocultar comentários.

Nota: Quando desenvolvi meu primeiro plugin de WordPress, usei o gancho get_comment_ID e não fiz o retorno do meu parâmetro ao final. Resultado, todos plugins executados após este quebravam, pois não recebiam um ID e sim uma string vazia.

Usando o contexto global, a variável $comment é um objeto que representa todos os dados do comentário atual, por isso como pode ser visto acima, posso acessar o nome do autor, para agregá-lo à mensagem, que foi buscada da tabela de opções pela chamada get_option. Ao final tudo isso é concatenado ao texto no comentário que segue em frente para outros plugins, ou é simplesmente mostrado.

Código remanescente

Para inicializar nosso plugin o código abaixo é inserido solto em nosso arquivo, para que seja executado diretamente quando o arquivo for incluso, já que tudo que esta no escopo da classe não é executado sem sua instanciação.

$mppPluginFile = substr(strrchr(dirname(__FILE__),DIRECTORY_SEPARATOR),1).DIRECTORY_SEPARATOR.basename(__FILE__);
/** Funcao de instalacao */
register_activation_hook($mppPluginFile,array('meuPrimeiroPlugin','instalar'));
/** Funcao de inicializacao */
add_filter('init', array('meuPrimeiroPlugin','inicializar'));

Nestes ganchos determinamos a execução da função instalar na ativação do plugin e da init na inicialização do WordPress. Para o gancho de ativação definimos a variável $mppPluginFile que determina a pasta onde o plugin esta, e para isso o plugin deve estar em uma sub-pasta de plugin e não na raiz. Com esta combinação de funções e as constantes DIRECTORY_SEPARATOR (barra invertida ou não), e o __FILE__, saimos com algo como “mpp/meuprimeiroplugin.php” ou seja, pasta e arquivo necessários para a detecção de ativação.

Divulgando seu plugin

Para divulgar seu plugin o primeiro e mais importante passo é adicionar ele no repositório do WordPress. Isso é uma excelente ferramenta, pois além de fornecer um repositório SVN que pode lehe ajudar a melhor controlar seu desenvolvimento ele permite que o usuário de seu plugin possa ser notificado de novas versões diretamente na página de plugins.

Divulgue o seu plugin no repositório oficial do WordPress: http://wordpress.org/extend/plugins/ usando o link http://wordpress.org/extend/plugins/add/. A única exigência é que o plugin deve ser licenciado como GPL.

Conclusão

Espero que com este artigo (que atrasou mais do que devia) muitos usuários de WordPress e desenvolvedores da comunidade possam embarcar no desenvolvimento de novos plugins e que todos tenham uma noção do poder que o blog oferece permitindo tamanha integração de forma tão simplificada e acessível.

O plugin criado neste exemplo esta 100% funcional e pode até ser usado, mas use-o para aprender e vá muito mais longe. Abaixo deixo os links para download caso lhes interesse.

Com o atraso do artigo estamos na beira do WordPress 2.5, mas tudo indica que além da carinha nova da administração, não haverá impactos no processo descrito acima, e inclusive este exemplo já funciona na nova versão e foi testado aqui com ela.

Rafael Dohms

MVC em PHP com Smarty – Parte 2

1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (3 votos, média: 4,33)
Loading ... Loading ...

Postado por Plinio Cruz em 21 de março de 2009 - PHP, Programação | 2 Comentário para ler

Olá leitores.

Abro o artigo dessa semana agradecendo todos os e-mails que venho recebendo com dúvidas, críticas, sugestões e elogios. Saibam que estou a plena disposição para respondê-los. Muito Obrigado!!

Também peço desculpas pela demora em meus artigos, estive ocupado com alguns projetos. Mas…

I´m Back!!!

Então chega de papo e mãos na massa, ou melhor, mãos ao teclado!

Esse artigo é a segunda parte da série sobre MVC em PHP com Smarty. Durante nossa série trabalharemos na metodologia bottom-up, ou seja, começaremos trabalhando com a parte de visão do Smarty e subiremos (há quem diga que desceremos, mas tudo bem) para a tão esperada camada de controle (mas isso só próximo artigo, ok?!).

Hoje Faremos uso de algumas tags customizadas na camada view (visão) da nossa da aplicação.

Na primeira parte desse artigo iniciamos uma simples aplicação. Começaremos outra mais completa. :D

Para um correto acompanhamento de nossos artigos, peço que deêm uma lida em como instalar o Smarty em sua aplicação no site oficial do framework (http://smarty.php.net/). O site possui manual em português e a instalação é rápida e simples. Basta descompactar o arquivo “baixado” do site e setar permissões em alguns diretórios.

Vamos à nossa aplicação…

Imagine que você receba a seguinte tarefa do gerente de projeto de sua empresa ou diretamente de seu cliente.

“Querido Programador,.

Como parte da funcionalidade de nosso portal, gostaria que você implementasse um mecanismo de busca avançada. Onde em determinada tela fosse listado algumas opções de busca para meus pedidos e que não fosse preciso utilizar o refresh. Odeio esse tal de refresh. Gostaria que fosse igual àquele site que te mostrei, lembra?”.

Você pode se espantar com o nível de informalidade com que essa tarefa está descrita, mas para quem começou, ou quem está em pequenas empresas de desenvolvimento de software, sabe que esse tipo de informalidade acontece…

… e acontece muito!!

Para os mais “antenados”, uma rápida lida nessa especificação já trás implícito uma solução, não é mesmo?!

“Odeio refresh!”

AJAX nele!!!!

A citação do AJAX nesse ponto possui relevância, já que teremos que utiliza-lo para nos conectar a camada de visão com a camada de controle, efetuando algumas alterações no código do Smarty.

“O quê? Mexeremos no código do Smarty??!”

Pois é, essa modificação é necessária para conseguirmos conciliar o AJAX com Smarty. Mas não se preocupem, tudo ao seu tempo.

Voltando ao Smarty…

É através do Smarty que montamos a visualização do aplicativo com os dados retornados pela camada de controle.

“Como assim?”

Digamos que a camada de controle passe para a visão um conjunto de dados para serem mostrados em uma tabela. É necessário que o Smarty possua estruturas de laço e decisão para o processamento dessas informações.

E ele tem!

Com as tags foreach e if podemos interagir com os dados e fazer tomadas de decisão em tempo de execução.

Veja o exemplo do foreach:

A definição na camada de controle se parece com isso (pagina_controlador1.php)

pagina_controlador1.php

$clientes = array();
$cliente_1 = new Cliente("Erico");
$cliente_2 = new Cliente("Renato");
$clientes[] = $cliente_1;
$clientes[] = $cliente_2;

$smarty->assign("clientes", $clientes);

E a definição no HTML ficaria assim (pagina_visao1.html):

pagina_visao1.html

<table>
{foreach name=laco1 item=cliente from=$clientes}
<tr>
	<td>
	    Nome: {$cliente->nome}
	</td>
<tr>
{/foreach}

</table>

Com essa sistemática conseguimos a separação de código, definindo os dados na camada de controle e repassando a responsabilidade da visualização desses dados na camada de visão, no nosso caso, no HTML;

Podemos perceber três coisas no exemplo dado.

Primeiro é que as marcações do Smarty seguem a mesma filosofia do HTML e do XML, ou seja, abre-se a tag e fecha-se com uma barra “/”;

A segunda é que é possível a utilização da orientação a objetos na página de visão. Isso é ótimo para organização de código e estruturação da manutenção de software, além de todas as vantagens de se utilizar POO (Programação Orientada a Objetos);

Desaparece aqueles códigos “enrolados” com a mistura entre código PHP e HTML, chamados códigos de macarrão;

Além dessas marcações, o Smarty permite o uso de tag´s que formatam os componentes HTML. Isso é útil, por exemplo, quando utilizamos combobox em nossa aplicação, e que precisamos selecionar um dos valores por default. Algo como o exemplo a seguir:

Definição no controlador (pagina_controlador2php):

pagina_controlador2.php

$smarty = new Smarty;
$smarty->assign('nome_clientes', array(
			1001 => 'Erico Almeida',
			1002 => 'Renato Oliveira',
			1003 => 'Thiago Sergio',
			1004 => 'Carlos Breno'));
$smarty->assign('cliente_selecionado', 1001);
$smarty->display("pagina_visao2.html");

Página HTML (pagina_visao2.html)

<select name=cliente_id>
	{html_options options=$nome_clientes selected=$cliente_selecionado}
</select>

Nesse exemplo, criamos um array que será utilizado para compor os valores do combobox (select). Com a utilização do componente do Smarty para os options, é possível passar qual será o valor de seleção default para o select. Isso ajuda muito na construção de páginas para edição de dados;

Relembro que o Smarty possui diversas tags customizadas e que realmente vale a pena darmos atenção a esse framework e deixarmos de lado algumas manias que os programadores possuem desde do tempo do desenvolvimento procedural. De um código sem divisão de camadas, de difícil leitura e consequentemente de difícil manutenção.

Na próxima semana estaremos trabalhando a camada de controle (controller) e implementaremos a aplicação especificada nesse artigo. Lembro que essa é somente uma introdução do uso da View do Smarty e que foi abordado somente conceitos que serão melhor aplicados no decorrer do artigo. Para uma melhor noção das tags do Smarty, aconselho a leitura da documentação em português do framework no site oficial (http://smarty.php.net/manual/pt_BR/).

Uma boa semana para todos. Abraços!
 

Erico Almeida
Consulto em Gestão de TI

Ilustrações retiradas do artigo original do site www.imasters.com.br