domingo, 30 de março de 2008

Upload de arquivo / imagem salvando no banco de dados com CakePHP

Este post ensinará como fazer upload de arquivos gravando o nome e diretório no banco de dados através do framework cakePHP.


Primeiro vamos criar o nossa tabela no banco:


CREATE TABLE `arquivos` (

`id` int(10) unsigned NOT NULL auto_increment,

`dir` varchar(255) NOT NULL,

`file_name` varchar(255) NOT NULL,

`type` varchar(255) NOT NULL,

`file_size` varchar(255) NOT NULL,

`created` datetime NOT NULL,

`updated` datetime NOT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;



Depois disso precisamos de um model arquivos:

models\arquivo.php


<?php

class Arquivo extends AppModel {


var $name = 'Arquivo';

var $useTable = 'arquivos';


}

?>



 


Criamos então o componente que vai fazer o upload (retirado do http://groups.google.com/group/cake-php-pt , e modificado por mim paras minhas necessidades)

controllers/components/upload.php


<?php

/**

* Upload class file.

*

* @Autor Tulio Faria

* @Contribuição Helio Ricardo, Vinicius Cruz, Caio Vitor Oliveira (caiovitor@gmail.com)

* @Link http://www.tuliofaria.net

* @Licença MIT

* @Versão x.x $Data: xx-xx-2007

*/

class UploadComponent extends Object{

var $controller = true;

var $path = "";

var $maxSize; //Tamanho máximo permitido

var $allowedExtensions = array("doc", "pdf"); //Arquivos permitidos

var $logErro = ""; //Log de erro


function startup(&$controller){

$this->path = APP . WEBROOT_DIR . DS;

$this->maxSize = 2*1024*1024; // 2MB

}

function setPath($p)

{

if ($p!=NULL){

$this->path = $this->path . $p . DS;

$this->path = eregi_replace("/", DS, $this->path);

$this->path = eregi_replace("\\\\", DS, $this->path);

return true;

}

}

//Seta novo tamanho máximo

function setMaxFileSize($size)

{

$this->maxSize = $size;

}

//Adiciona nova extensão no array

function addAllowedExt($ext)

{

if (is_array($ext))

{

$this->allowedExtensions = array_merge($this->allowedExtensions, $ext);


}else{

array_push($this->allowedExtensions, $ext);

}

}

//Retorna extensão de arquivo

function getExt($file)

{

$p = explode(".", $file);

return $p[count($p)-1];

}

//Exibe lista de extensões em array

function viewExt()

{

$list_tmp = "";

for($a=0; $a<count($this->allowedExtensions); $a++)

{

$list_tmp.= $this->allowedExtensions[$a].", ";

}

return substr($list_tmp, 0, -2);

}

//Verifica se arquivo pode ser feito upload

function verifyUpload($file)

{

$passed = false; //Variável de controle

if(is_uploaded_file($file["tmp_name"]))

{

$ext = $this->getExt($file["name"]);

if((count($this->allowedExtensions) == 0) || (in_array($ext, $this->allowedExtensions)))

{

$passed = true;

}

}

return $passed;

}

//Copia arquivo para destino

function copyUploadedFile($source, $destination="")

{

//Destino completo

$this->path = $this->path . $destination . DS;

//Cabeçalho de log de erro

$logMsg = '=============== UPLOAD LOG ===============<br />';

$logMsg .= 'Pasta destino: ' . $this->path . '<br />';

$logMsg .= 'Nome do arquivo: ' . $source["name"] . '<br />';


$logMsg .= 'Tamanho do arquivo: ' . $source["size"] . '

bytes<br />';

$logMsg .= 'Tipo de arquivo: ' . $source["type"] . '<br />';


$logMsg .=

'---------------------------------------------------------------<br />';


$this->setLog($logMsg);

//Verifica se arquivo é permitido

if($this->verifyUpload($source))

{

$novo_arquivo = $this->verifyFileExists($source["name"]);

if(move_uploaded_file($source["tmp_name"], $this->path . $novo_arquivo))

return $novo_arquivo;

else

{

$this->setLog("-> Erro ao enviar arquivo<br />");

$this->setLog(" Obs.: ".$this->getErrorUpload($source["error"])."<br />");


return false;

}

}else

{

$this->setLog("-> O arquivo que você está tentando enviar

não é permitido pelo administrador<br />");

$this->setLog(" Obs.: Apenas as extensões ".$this->viewExt()." são permitidas.<br />");


return false;

}

}


//Gerencia log de erro

function setLog($msg)

{

$this->logErro.=$msg;

}

function getLog()

{

return $this->logErro;

}

function getErrorUpload($cod="")

{

switch($cod)

{

case 1:

return "Arquivo com tamanho maior que definido no servidor.";

break;

case 2:

return "Arquivo com tamanho maior que definido no formulário de envio.";

break;

case 3:

return "Arquivo enviado parcialmente.";

break;

case 4:

return "Não foi possível realizar upload do arquivo.";

break;

case 5:

return "The servers temporary folder is missing.";

break;

case 6:

return "Failed to write to the temporary folder.";

break;

}

}

//Checa se arquivo já existe no servidor, e renomea

function verifyFileExists($file)

{

if(!file_exists($this->path.$file))

return $file;

else

return $this->renameFile($file);

}

//Renomea Arquivo, para evitar sobescrever

function renameFile($file)

{

$ext = $this->getExt($file); //Retorna extensão do arquivo

$file_tmp = substr($file, 0, -4); //Nome do arquivo, semextensao

do

{

$file_tmp.= base64_encode(date("His"));

}while(file_exists($this->path.$file_tmp.".".$ext));

return $file_tmp.".".$ext;

}

}


?>





E no controller:

controllers\arquivos_controller.php


<?php

class ArquivosController extends AppController {


var $name = 'Arquivos';

var $helpers = array('Html', 'Form');

var $components = array('Upload');


function add() {

if (!empty($this->data)) {


if(empty($this->data['Arquivo']['Arquivo']['tmp_name'])) {

$this->Session->setFlash(__('É preciso enviar o arquivo referente ao trabalho',true));

return false;

}



$path = "files";

$this->Upload->setPath($path);

$novo_arquivo = $this->Upload->copyUploadedFile($this->data['Arquivo']['Arquivo'], '');



//grava dados do arquivo no banco de dados

$this->data['Arquivo']['dir'] = 'files';

$this->data['Arquivo']['file_name'] = $novo_arquivo;

$this->data['Arquivo']['file_size'] = number_format($this->data['Arquivo']['Arquivo']['size']/1024, 2) . " KB";

$this->data['Arquivo']['type'] = $this->data['Arquivo']['Arquivo']['type'];



if ($this->Arquivo->save($this->data)) { //salva o trabalho



$this->Session->setFlash(__('Arquivo enviado com sucesso.', true));

$this->redirect(array('action'=>'index'));

} else {

$this->Session->setFlash(__('Desculpe. O trabalho não pode ser salvo. Tente novamente.', true));

}

} //fecha if - formulario enviado


}

}


?>



Vamos agora para a view:

views\arquivos\add.ctp



<div class="trabalhos form">

<?php echo $form->create('Trabalho', array('type'=>'file'));?>

<fieldset>

<legend><?php __('Enviar Trabalho');?></legend>

<?php

echo $form->input('Arquivo', array('type'=>'file'));

?>

</fieldset>

<?php echo $form->end('Submit');?>

</div>



Pronto, nosso upload de arquivos / imagens está pronto para ser usado.

sábado, 29 de março de 2008

Upload de arquivo com banco de dados e gravação de log no cakePHP

Este post ensinará como fazer upload de arquivos gravando o nome e diretório no banco de dados através do framework cakePHP.

Antes de mais nada precisamos do seguinte componente:

controllers/components/upload.php
path = APP . WEBROOT_DIR . DS;
$this->maxSize = 2*1024*1024; // 2MB
}
function setPath($p)
{
if ($p!=NULL){
$this->path = $this->path . $p . DS;
$this->path = eregi_replace("/", DS, $this->path);
$this->path = eregi_replace("\\\\", DS, $this->path);
return true;
}
}
//Seta novo tamanho máximo
function setMaxFileSize($size)
{
$this->maxSize = $size;
}
//Adiciona nova extensão no array
function addAllowedExt($ext)
{
if (is_array($ext))
{
$this->allowedExtensions = array_merge($this->allowedExtensions, $ext);

}else{
array_push($this->allowedExtensions, $ext);
}
}
//Retorna extensão de arquivo
function getExt($file)
{
$p = explode(".", $file);
return $p[count($p)-1];
}
//Exibe lista de extensões em array
function viewExt()
{
$list_tmp = "";
for($a=0; $aallowedExtensions); $a++)
{
$list_tmp.= $this->allowedExtensions[$a].", ";
}
return substr($list_tmp, 0, -2);
}
//Verifica se arquivo pode ser feito upload
function verifyUpload($file)
{
$passed = false; //Variável de controle
if(is_uploaded_file($file["tmp_name"]))
{
$ext = $this->getExt($file["name"]);
if((count($this->allowedExtensions) == 0) || (in_array($ext, $this->allowedExtensions)))
{
$passed = true;
}
}
return $passed;
}
//Copia arquivo para destino
function copyUploadedFile($source, $destination="")
{
//Destino completo
$this->path = $this->path . $destination . DS;
//Cabeçalho de log de erro
$logMsg = '=============== UPLOAD LOG ===============
';
$logMsg .= 'Pasta destino: ' . $this->path . '
';
$logMsg .= 'Nome do arquivo: ' . $source["name"] . '
';

$logMsg .= 'Tamanho do arquivo: ' . $source["size"] . '
bytes
';
$logMsg .= 'Tipo de arquivo: ' . $source["type"] . '
';

$logMsg .=
'---------------------------------------------------------------
';

$this->setLog($logMsg);
//Verifica se arquivo é permitido
if($this->verifyUpload($source))
{
$novo_arquivo = $this->verifyFileExists($source["name"]);
if(move_uploaded_file($source["tmp_name"], $this->path . $novo_arquivo))
return $novo_arquivo;
else
{
$this->setLog("-> Erro ao enviar arquivo
");
$this->setLog(" Obs.: ".$this->getErrorUpload($source["error"])."
");

return false;
}
}else
{
$this->setLog("-> O arquivo que você está tentando enviar
não é permitido pelo administrador
");
$this->setLog(" Obs.: Apenas as extensões ".$this->viewExt()." são permitidas.
");

return false;
}
}

//Gerencia log de erro
function setLog($msg)
{
$this->logErro.=$msg;
}
function getLog()
{
return $this->logErro;
}
function getErrorUpload($cod="")
{
switch($cod)
{
case 1:
return "Arquivo com tamanho maior que definido no servidor.";
break;
case 2:
return "Arquivo com tamanho maior que definido no formulário de envio.";
break;
case 3:
return "Arquivo enviado parcialmente.";
break;
case 4:
return "Não foi possível realizar upload do arquivo.";
break;
case 5:
return "The servers temporary folder is missing.";
break;
case 6:
return "Failed to write to the temporary folder.";
break;
}
}
//Checa se arquivo já existe no servidor, e renomea
function verifyFileExists($file)
{
if(!file_exists($this->path.$file))
return $file;
else
return $this->renameFile($file);
}
//Renomea Arquivo, para evitar sobescrever
function renameFile($file)
{
$ext = $this->getExt($file); //Retorna extensão do arquivo
$file_tmp = substr($file, 0, -4); //Nome do arquivo, semextensao
do
{
$file_tmp.= base64_encode(date("His"));
}while(file_exists($this->path.$file_tmp.".".$ext));
return $file_tmp.".".$ext;
}
}

?>

Instalação e configuração do cakePHP

Instalar o cakePHP é a coisa mais fácil do mundo. Antes de tudo você precisa de um ambiente de desenvolvimento PHP. Eu recomendo o wampserver, pois é windows style, baixar, abrir, next, next, next, a única alteração que eu faço é mudar os locais dos sites para: d:\www. Após instalado, você terá um ambiente de produção do PHP, com o apache instalado.
Vamos agora para o cakePHP. Vá no site do cakePHP e baixe a versão cakePHP 1.2 beta (apesar de ainda está em beta, já está quase pronta 95%). Depois disso extraia o arquivo e você terá uma estrutura de diretórios assim:

D:\www\cake_1.2.0.6311-beta

.
..
139 .htaccess
app
cake
0 diretorio.txt
docs
2.303 index.php
vendors

Copie a pasta cake para d:\www\, ficando assim agora:

Pasta de D:\www\cake

.
..
31.791 basics.php
1.648 bootstrap.php
config
console
20.408 dispatcher.php
libs
1.236 LICENSE.txt
tests
622 VERSION.txt

Depois disso, vamos pro famoso MS-DOS e executar os comandos da imagem abaixo (clicar na imagem para ampliar):



Temos então a estrutura básica para começarmos nosso site com o cakephp. Eu gosto desse tipo de instalação pois você só precisará enviar a pasta cake (core) para o public_html do seu provedor uma vez e todos os outros sites baseados no cake ficaram no mesmo diretório public_html, facilitando assim a manutenção.

/public_html/
cake/
aplicacao/

Sendo assim, vamos criar agora o banco para nossa aplicação. (Essa parte da criação vou supor que você já sabe)

Criado o banco, vamos configurar o cake para utilizar nosso banco, de acordo com a tela abaixo:



Agora temos um site pronto com o cake, veja:


Agora que começa a parte boa. Mas fica para o próximo post.

Sobre o cakephp

Falando um pouco sobre o cake, retirado de: (http://manual.cakephp.com.br/doku.php?id=introducao)

O que é CakePHP? Por que usar?

CakePHP é gratuito, de código aberto, uma framework em PHP para desenvolvimento ágil. É uma estrutura fundamental para programadores criarem aplicações web. Nosso principal objetivo é permitir que você trabalhe em uma estrutura que possa programar de forma rápida e sem a perda de flexibilidade.

CakePHP joga fora a monotonia do desenvolvimento web. Nós oferecemos todas as ferramentas que você precisa para começar programando o que realmente deseja: a lógica específica da sua aplicação. Em vez de reinventar a roda cada vez que se constrói um novo projeto, pegue uma cópia do CakePHP e comece a construir sua carruagem real da sua aplicação.

CakePHP tem uma equipe de desenvolvedores e uma grande comunidade, trazendo grande valor ao projeto. Além de manter você fora do reinvento da roda, usando CakePHP significa que o núcleo da sua aplicação é bem testado e constantemente aperfeiçoado.

Abaixo segue uma pequena lista dos recursos que você poderá desfrutar no CakePHP:

  • Ativo e com comunidade amigável;
  • Licença flexível;
  • Compatibilidade com PHP 4 e PHP 5;
  • Integrando funcionalidade CRUD (Create, Read, Update and Delete, ou Criar, Ler, Atualizar e Excluir) para interagir com o banco de dados;
  • Aplicações scaffolding;
  • Geração de código;
  • Arquitetura MVC (Model, View, Controller, ou Modelo, Visões, Controlador);
  • Requisições ao expedidor com clareza, URLs personalizáveis e rotas;
  • Validações internas;
  • Templates rápidos e flexíveis (Sintaxe PHP e com ajudantes);
  • Ajudantes para usar AJAX, JavaScript, HTML, formulários e outros nas visões;
  • Componentes de E-mail, Cookie, Segurança, Sessões, Manipulação de Requisições e outros;
  • Lista de controle de acessos flexível;
  • Limpeza de dados;
  • Flexibilidade com cache;
  • Internacionalização;
  • Funciona em qualquer subdiretório do seu website, com poucas configurações no Apache.

Onde obter ajuda?

Você começou no lugar certo. Este manual (e a API) deve ser provavelmente o primeiro lugar que você vá para procurar as respostas das suas dúvidas. Assim como acontece com muitos outros projetos de código aberto, nós obtemos novos usuários regularmente. Tentamos ser os melhores para responder seus questionamentos em primeiro lugar. As respostas podem demorar a chegar, mas permanecerá por tempos e ajudará a esclarecer outras pessoas. Tanto o manual, quanto a API podem ser encontradas online.

http://manual.cakephp.com.br (em português)

http://manual.cakephp.org (em inglês)

http://api.cakephp.org/1.2 (em inglês)

Se você estiver assustado, dê um grito pelo canal de IRC internacional ou entre no grupo da comunidade luso-brasileira. Além da equipe de desenvolvimento do núcleo do cake no canal, principalmente durante o dia. Se você precisar de alguma ajuda, deseja encontrar usuários na sua área ou gostaria de doar o novo carro esportivo, gostaríamos de falar com você.

Grupo da comunidade luso-brasileira

#cakephp-pt @ irc.freenode.net (em português)

#cakephp @ irc.freenode.net (em inglês)

O CakePHP Bakery é uma casa para todas as coisas de CakePHP. Visite este site para ver tutoriais, estudos de caso e exemplos de código. Assim que estiver familiarizado com o CakePHP, faça o login e compartilhe seus conhecimentos com a comunidade para ganhar fama e fortuna.

http://bakery.cakephp.org

O CakeForge é outro recurso que os desenvolvedores podem usar para hospedar seus projetos usando CakePHP e compartilhar com outras pessoas. Se você está olhando para achar projetos existentes, ou querendo compartilhar, acesso o CakeForge.

http://www.cakeforge.org

O site oficial do CakePHP está sempre esperando sua visita. Ele tem links para sites de outros desenvolvedores, screencasts, oportunidade para doar ao projeto e downloads.

http://www.cakephp.org

Sobre o blog, o framework cakePHP e os trabalhos

Este blog tem como intuito ser uma referência para os diversos problemas que eu tiver no meu aprendizado com o framework de desenvolvimento web cakePHP.


Sempre trabalhei com o PHP, e a minha escolha pelo PHP foi po ser um linguagem fácil e sem frescuras. Porém isso acabava por me atrapalhar quando precisava rever um site feito a algum tempo atrás, digamos 6 meses, eu teria que rever todo o site, uma mistura de modelo de banco de dados, com lógica da aplicação e design. Com o cakephp temos a famosa separação das camadas: MVC (Modelo, Visão e Controlador) ou em inglês (Model, View and Controller).

CakePHP é um framework escrito em PHP que tem como principais objetivos oferecer uma estrutura que possibilite aos programadores de PHP de todos os níveis desenvolverem aplicações robustas rapidamente, sem perder flexibilidade.

O Cake-PHP é baseado no framework Ruby on Rails e utiliza padrões de projeto conhecidos, tais como ActiveRecord, Association Data Mapping, Front Controller e MVC (Model-View-Controller).

A camada de banco de dados é abstraída no Modelo (Model), o controle da sua aplicação é feito pelo controlador e como os navegadores vêem, ou seja, o design da sua aplicação é feita pelas Visões (View). Isso facilita e muito o desenvolvimento e a manutenção.
Vamos lá, primeiro você pode achar que é muito complexo ter que trabalhar com várias camadas apenas pra imprimir um texto na tela, mas depois podemos ver o benefício disso quando se trabalha em equipe e na manutenção do código.
Com o cakePHP, fica muito mais fácil dividir sua equipe, como Designer de Banco de Dados (vai trabalhar com o banco de dados e os modelos), o programador em si que vai trabalhar com os controladores e o designer que vai trabalhar com as visões (views). Falarei mais sobre o cakePHP no próximo post.
Tentarei atualizar esse blog semanalmente, sempre nos fins de semana, quando tenho um tempo para respirar.