Skip to content

Instantly share code, notes, and snippets.

@fernando-basso
Created August 30, 2013 21:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fernando-basso/6394645 to your computer and use it in GitHub Desktop.
Save fernando-basso/6394645 to your computer and use it in GitHub Desktop.
Multiple upload with javascript + Imagick
<?php
class GalleryUp {
/**
*
* @var PDO Uma conexão estática com PDO (singleton).
*/
private $db;
/**
* O diretório temporário para o upload e operações necessárias na imagem.
*
* @var String tmp_ups/
*/
private $dir;
/**
*
* @var String '/uploads/posts_images/'
*/
private $final_dir = GALLERIES_DIR;
public function __construct(PDO $con) {
$this->db = $con;
$this->dir = ROOT . '/sysadm/gallery_up/tmp_ups';
}
public function get_post_title( $post_id ) {
$sql = 'SELECT title FROM posts WHERE id = :post_id;';
try {
$stmt = $this->db->prepare( $sql );
$stmt->bindParam( ':post_id', $post_id, PDO::PARAM_INT );
$stmt->execute();
return ( $stmt->rowCount() > 0 ) ? $stmt->fetchColumn( 0 ) : FALSE;
}
catch ( PDOException $err ) {
die( 'Erro ao buscar título do conteúdo.' );
}
}
public function save_images() {
$id = $_POST[ 'id' ];
$tmpdir = "{$this->dir}/_{$id}";
if ( isset( $_FILES ) ) {
// Tenta remover, se por algum motivo já existe.
self::remove_tmp_dir( $tmpdir );
self::make_tmp_dir( $tmpdir );
foreach( $_FILES AS $file ) {
// O nome do arquivo será o id_do_post-{01,02,03,etc}. OK por que nesse
// projeto cada conteúdo terá somente uma galeria. Se o conteúdo tivesse
// diversos albuns + galerias, teria que ser diferente.
$rand = $id . '-' . substr( rand(), 1, 5 ) . '-' . date('Ymdhis');
$info = pathinfo( $file[ 'name' ] );
$ext = $info[ 'extension' ];
self::save_image( $file, $tmpdir, $rand, $ext );
self::resize_image( $tmpdir, $rand, $ext );
// A cada imagem redimensionada, devemos já salvar no destino, senão
// só temos o $rand final, o que faz com que a próxima imagem
// sempre sobrescreva a anterior.
if ( self::move_finished_files( $tmpdir, $this->final_dir, $rand ) ) {
// Estamo dentro do if por que não vamos salvar no banco uma
// imagem que não foi salva no HD.
self::save_on_database( $rand, $ext, $id );
}
// Como estamos recebendo todos os arquivos de uma única vez, esse nome de
// arquivo com $num funciona. Se for um arquivo por requrest, num vai ser
// sempre zero e o nome do arquivo será sempre o mesmo, sobrescrevendo os
// arquivos já enviados.
}
}
// Vamos assumir que se chegou até aqui, é por que deu tudo certo.
return self::remove_tmp_dir( $tmpdir );
}
private function save_image( $file, $dir, $rand, $ext ) {
if ( ! move_uploaded_file( $file[ 'tmp_name' ], "{$dir}/{$rand}.{$ext}" ) ) {
die( 'Erro ao salvar a imagem.' );
}
}
private function resize_image( $dir, $rand, $ext ) {
$Img = new Imagick( "{$dir}/{$rand}.{$ext}" );
$info = $Img->getImageGeometry();
// Se tiver pelomenos 600px...
if ( $info[ 'width' ] > 600 ) {
$Img->scaleImage( 600, 0 );
$Img->writeImage( "{$dir}/{$rand}-G.{$ext}" );
$Img->scaleImage( 400, 0 );
$Img->writeImage( "{$dir}/{$rand}-M.{$ext}" );
}
else {
// Se não é nem 600 px, salva a grande e a média com o mesmo tamanho.
$Img->scaleImage( 400, 0 );
$Img->writeImage( "{$dir}/{$rand}-G.{$ext}" );
$Img->writeImage( "{$dir}/{$rand}-M.{$ext}" );
}
// E a pequena (thumbnail) é sempre desse tamanho, no matter what!
$Img->scaleImage( 220, 180 );
$Img->writeImage( "{$dir}/{$rand}-P.{$ext}" );
$Img->scaleImage( 80, 60 );
$Img->writeImage( "{$dir}/{$rand}-thumb.{$ext}" );
$Img->destroy();
self::remove_tmp_files( $dir, array( "{$rand}.{$ext}" ) );
}
private function remove_tmp_files( $path, $files ) {
$flag = TRUE;
foreach( $files AS $f ):
if ( ! unlink( "{$path}/{$f}" ) )
$flag = FALSE;
endforeach;
return $flag;
}
/**
* Cria o diretório temporário para o tratamento das imagens.
*
* @param String $path O caminho do diretório a ser criado.
*/
private function make_tmp_dir( $path ) {
// Tem que ser 0777 senão não conseguimos visualizar a image, pois o novo
// dir fica com dono http e grupo http (ou www-data em debian servers ).
if ( ! mkdir( $path, 0777, TRUE ) )
die( 'erro ao criar diretório temporário' );
}
/**
* Remove um diretório.
*
* @param String $path O caminho do diretório a ser excluído.
* @return Boolean TRUE/FALSE
*/
public function remove_tmp_dir( $path ) {
$flag = TRUE;
// Se o dir existe...
if ( file_exists( $path ) ) {
// Se há algo dentro dele (só um nível)...
if ( glob( "{$path}/*" ) ) {
foreach( glob( "{$path}/*" ) AS $f ) {
$flag = ( ! unlink( $f ) ) ? FALSE : TRUE;
}
}
// Se não, só remove o dir, pois estava vazio.
// Se deu erro no foreach, mas dá true aqui, a $flag será sobrescrita,
// o que não está correto. TODO. Concertar esse bug.
$flag = ( ! rmdir( $path ) ) ? FALSE : TRUE;
}
return $flag;
}
/**
* @param String $rand_name O nome randômico gerada para a imagem.
* @param Integer $id O id do registro a receber o nome da imagem.
* @return boolean TRUE on success, FALSE otherwise.
*/
public function save_on_database( $rand, $ext, $post_id ) {
$sql = "INSERT INTO galleries ( post_id, rand_name, imgext )
VALUES( :post_id, '{$rand}', '{$ext}' );";
try {
$stmt = $this->db->prepare( $sql );
$stmt->bindParam( ':post_id', $post_id, PDO::PARAM_INT );
$res = $stmt->execute();
}
catch( PDOException $err ) {
echo 'catch erro: ' . $err;
}
return $res;
}
public function get_images( $id ) {
$sql = 'SELECT post_id, rand_name, imgext FROM galleries WHERE post_id = :id;';
try {
$stmt = $this->db->prepare( $sql );
$stmt->bindParam( ':id', $id, PDO::PARAM_INT );
$stmt->execute();
return $stmt->rowCount() > 0 ? $stmt : FALSE;
}
catch( PDOExeption $err ) {
die( 'Erro ao buscar imagens da galleria: ' . $err );
}
}
/**
* Move os arquivos redimensionados e recortados para o dir correto.
*
* Imagens de posts vão para um diretório, banners para outro.
*
* @param String $rand O nome randômico da imagem.
* @return boolean TRUE se moveu todos os arquivos, FALSE se pelo menos um falhou.
*/
public function move_finished_files( $tmp_dir, $final_dir, $rand ) {
$flag = TRUE;
foreach ( glob( "{$tmp_dir}/{$rand}*" ) AS $filename ):
$name = pathinfo($filename)['basename'];
copy( $filename, "{$final_dir}/{$name}" );
if ( ! unlink ( $filename ) ) {
$flag = FALSE;
}
endforeach;
return $flag;
}
/**
* Remove imagem do banco e do hd.
*
* Não precisa o caminho pois temos o $final_dir na classe.
*/
public function remove_image( $rand ) {
if ( array_map( 'unlink', glob( "{$this->final_dir}/{$rand}*" ) ) ) {
$sql = 'DELETE FROM galleries WHERE rand_name = :rand;';
try {
$stmt = $this->db->prepare( $sql );
$stmt->bindParam( ':rand', $rand, PDO::PARAM_STR );
if ( $stmt->execute() ) {
echo 1; // Mandar 1 em php é true em js.
}
}
catch( PDOExeption $err ) {
die( 'Erro ao remover a imagem da galeria: ' . $err );
}
}
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment