Upload adapter e file

Ciao, mi sono incartato nello sviluppo delle classi per l'upload di file con lo zend framework.

La mia idea era questa:

un classe file che possa gestire in modo astratto l'array $_FILES di php e salvarlo da qualche parte in base all'adapter utilizzato

una classe adapter ( upload ) per l'upload dei file su disco fisso

una interfaccia per la definizione degli adattatori

il codice è questo :

Filesystem.php

<?php

class Solemare_File_Adapter_Filesystem implements Solemare_File_Adapter_Interface
{
    protected $_path;
    
    public function write($file)
    {
        return move_uploaded_file($file['name'], $this->_path . $file['name']);
    }
    
    public function read($file)
    {
        
    }
    
    public function setPath($path)
    {
        $this->_path = $path;
    }
}

file.php

<?php

class Solemare_File
{
    protected $_files;
    protected $_adapter;
    
    public function __construct($field = null, $adapter = null)
    {          
        if (null !== $adapter) {
            $this->_adapter = $adapter;
        }
        if (null !== $field) {
            print_r($_FILES);
            $this->_list = $this->_orderArray($_FILES[$field]);
        }
    }
    
    private function _orderArray($array)
    {
        $file = $array;
        $files = Array();
        for($i=0; $i<sizeof($file['name'])-1;$i++) {
            $j = 0;
            foreach($file as $index => $value) {
                $files[$i][$index] = $file[$index][$i] ? $file[$index][$i] : null;
                $j++;
            }
        }        
        return $files;
    }
    public funcrion getAdapter()
    {
        return $this->_adapter;
    }    
    
    public function setAdapter(Solemare_File_Adapter_Interface $adapter)
    {
        $this->_adapter = $adapter;
        if (isset($this->_path)) {
            $this->_adapter->setPath($this->_path);
        } else {
            throw new Exception('No path specified');
        }
        return $this;
    }
    
    public function setField($field)
    {
        $this->_field = $field;
        return $this;
    }
    
    public function upload()
    {
        $i = 0;
        foreach ($this->_files as $file) {
            switch ($file['error']) {
                case UPLOAD_ERR_NO_FILE:
                    throw new Exception('No file to upload');
                    break;
                case UPLOAD_ERR_PARTIAL:
                    throw new Exception('File uploaded partially');
                    break;
                case UPLOAD_ERR_FORM_SIZE:
                    throw new Exception('File size exceed max file size');
                    break;
                case UPLOAD_ERR_INI_SIZE: 
                    throw new Exception('File size exceed php.ini max file size');
                    break;
                case UPLOAD_ERR_OK:
                    if (!is_uploaded_file($file['tmp_name'])) {
                        throw new Exception('File not uploaded');
                        break;
                    }
                    if (file_exists($path . $file['name'])) {
                        throw new Exception('The file already exists');
                        break;
                    }                
                    $this->_adapter->write($file['name']);
                    break;
                default:
                    echo 'errore sconosciuto';
                    break;
            }
        $i++;
        }
    }
}

interface.php

<?php
interface Solemare_File_Adapter_Interface
{
    public function read($file);
    public function write($file);  
}

il mio obiettivo è quello di utilizzare la classe per la gestione di upload su file system o database ( per ora mi interessa solo il filesystem ) con in più la possibilità di eseguire una funzione che si vuole prima di effettuare l'upload ( mi servirà per creare le 3 versioni di ogni immagine [anteprima,icona,ingrandita])

i problemi per ora sono :

* impossibile vedere cosa c'è in $_FILES

* chiamata della funzione di callback che crei le anteprime ( non è la funzione per il ridimensionamento il problema, ma come chiamarla passando come parametro il suo nome )

* boh, gli altri dovrebbero scaturire dal primo errore, o comunque ora non posso verificare se ce ne sono altri!

 :bye:

PS _orderArray mi permette di sistemare il macello che è $_FILES

cioè :

$_FILES originale :

array (
    [campo] => array(
        [name] => array (
            [0] 
            [1]
            [2]
            [3]
            ),
        [tmp_name] => array (
            [0] 
            [1]
            [2]
            [3]
            ),  
        [size] => array (
            [0] 
            [1]
            [2]
            [3]
            ),              
        )
    )
)

tentativo di renderlo così :

array(
    [0] => array(
        [name]
        [tmp_name]
        [size]
        [error]
        [type]        
    ),
    [1] => array(
        [name]
        [tmp_name]
        [size]
        [error]
        [type]        
    ),
    [2] => array(
        [name]
        [tmp_name]
        [size]
        [error]
        [type]        
    ),
)
inviato 9 anni fa
Andrea Turso
Andrea Turso
86
modificato 9 anni fa
X 0 X

ok credo di esserci riuscito:

adapter (filesystem)

<?php
/**
 * Solemaresalento
 * @author trashofmasters <trashofmasters@gmail.com>
 * @copyright Solemare 2007
 * @date 13/11/2007 17:46
 */

class Solemare_File_Adapter_Filesystem implements Solemare_File_Adapter_Interface
{
    protected $_path;
    protected $_failed = Array();
    protected $_succeeded = Array();
    
    public function write($file)
    {
        if (move_uploaded_file($file['tmp_name'], $this->_path . $file['name'])) {
            $this->_succeeded[] = $file['name'];
        } else { 
            $this->_failed[] = $file['name'];
        }
        return sizeof($this->_succeeded);
    }
    
    public function read($file){}
    
    public function setPath($path)
    {
        if (!'/' == substr($path, strlen($path)-1, 1)) {
            $path .= '/';
        }
        $this->_path = $path;
    }
    
    public function getResult()
    {
        return array('succedeed' => $this->_succeeded, 'failed' => $this->_failed);
    }
}

file.php

<?php
/**
 * Solemaresalento
 * @author trashofmasters <trashofmasters@gmail.com>
 * @copyright Solemare 2007
 * @date 13/11/2007 17:49
 */

class Solemare_File
{
    protected $_files = Array();
    protected $_adapter;
    protected $_overwriteExisting = false;
    protected $_allowed = Array();
    
    public function __construct($field = null, $adapter = null)
    {       
        if (null !== $adapter) {
            $this->setAdapter = $adapter;
        }
        if (null !== $field) {
            $this->setField($field);
        }
        if (isset($_FILES)) {        
            $this->_files = $this->_getFiles();
        }
        
        zend_debug::dump($this->_files);
    } 
       
    public function getAdapter()
    {
        return $this->_adapter;
    }   
    
    public function setAdapter(Solemare_File_Adapter_Interface $adapter)
    {
        $this->_adapter = $adapter;
        return $this;
    }
    
    public function setAllowed($allowed)
    {
        $this->_allowed = $allowed;
    }
    
    public function addAllowed($value)
    {
        $this->_allowed[] = $value;
    }
    
    public function setOverwriting($overwrite = false)
    {
        $this->_overwriteExisting = $overwrite;
        return $this;
    } 
    
    public function upload($field = null)
    {
        if (!is_array($this->_files)) {
            throw new Exception("No files in queue");
            return;
        }
        if (null === $field) {
            throw new Exception("Multi form uploads not yet supported");
            return;  
        } else {
            foreach($this->_files[$field] as $file) {
                $this->_upload($file);
            }
        }
        return $this->_adapter->getResult();     
    }
    
    protected function _upload($file)
    {
        switch ($file['error']) {
            case UPLOAD_ERR_NO_FILE:
                throw new Exception('No file to upload');
                break;
            case UPLOAD_ERR_PARTIAL:
                throw new Exception('File uploaded partially');
                break;
            case UPLOAD_ERR_FORM_SIZE:
                throw new Exception('File size exceed max file size');
                break;
            case UPLOAD_ERR_INI_SIZE: 
                throw new Exception('File size exceed php.ini max file size');
                break;
            case UPLOAD_ERR_OK:
                if (!is_uploaded_file($file['tmp_name'])) {
                    throw new Exception('File not uploaded');
                    break;
                }
                if ((file_exists($path . $file['name'])) && !($this->_overwriteExisting)) {
                    throw new Exception('The file already exists');
                    break;
                }   
                if (!in_array($file['type'], $this->_allowed)) {
                    throw new Exception('File format not supported');
                    break;
                }         
                $this->_adapter->write($file);
                break;
            default:
                echo 'errore sconosciuto';
                break;
        }
    }
    private function _getFiles()
    {
        $_files = $_FILES;      
        foreach ($_files as $field => $_file) {           
            foreach ($_file as $key => $value) {
                $i = 0;
                foreach ($value as $_data) {
                    $files[$field][$i][$key] = $_data;                    
                    $i++;
                    if ($files[$field][$i-1]['name'] == null) {
                        unset($files[$field][$i-1]);
                    } 
                }
            }
        }
        return $files;
    }
}

utilizzo

        try {
            $uploads = new Solemare_File();
            $uploads->setAllowed(array('image/jpg', 'image/gif', 'image/png', 'image/jpeg'));
            $adapter = $uploads->setAdapter(new Solemare_File_Adapter_Filesystem)
                               ->getAdapter()
                               ->setPath(DIR_ROOT . 'uploads/');
            if (isset($_POST['submit'])) {
                $result = $uploads->upload('filz');
                zend_debug::dump($result);
            }
        } catch (Exception $e) {
            echo $e->getMessage();
        }

ripulisce perfettamente il macello che è $_FILES.

upload senza problemi nella cartella desiderata.

mi servirebbe fare in modo che quando non carica un file proceda all'upload di quello successivo anzichè fermarsi . . .

come posso fare in modo che prima dell'upload possa passare l'immagine ad una funzione che mi generi le anteprime e le salvi al posto dell'immagine?

cioè con questo sistema ho un upload semplice che mi sposta i file da locale a server (filesystem,db o quant'altro).

Ora ho la necessità di creare 3 immagini ridimensionate da quella originale e salvarle nella cartella di destinazione ( sempre proseguendo, anche se alcune immagini non sono state caricate per diversi motivi, per quello ci sono gli array con i file uppati e quelli non, anche se dovrei mettere un messaggio :D )

risposto 9 anni fa
Andrea Turso
Andrea Turso
86
X 0 X

risolto anche questo :D

mi rimane solo da ridimensionare e salvare, meglio durante l'upload o dopo?

magari usando cron o qualcosa del genere.... ( anche per non rallentare la fase di upload )

grazie comunque :P

:bye:

risposto 9 anni fa
Andrea Turso
Andrea Turso
86
modificato 9 anni fa
X 0 X

se non devi conservare l'originale ti conviene ridimensionare durante l'upload

 :bye:

risposto 9 anni fa
Gianni Tomasicchio
X 0 X

Gianni ho un oggetto che fa da "bustina" all'array $_FILES, cioè ogni elemento di $_FILES è stato trasferito in un oggetto di tipo Solemare_Upload_File.

Questo tipo permette di effettuare l'upload del file ( $obj->upload() )

se è stato passato un handler viene chiamato il pre processore che effettua il ridimensionamento dell'immagine prima dell'upload effettivo, altrimenti se non è presente nessun handler si uppa il file sul supporto.

Praticamente mi trovo a lavorare sul file temporaneo dell'immagine perchè ancora non è stata caricata...

dai un'occhiata :

<?php
    public function upload()
    {   
        $this->_updateStatus(self::STATUS_NOT_READY);     
        switch ($this->error) {
            case UPLOAD_ERR_NO_FILE:
                $this->_updateStatus(self::STATUS_ERROR);
                break;
            case UPLOAD_ERR_PARTIAL:
                $this->_updateStatus(self::STATUS_UPLOAD_ERROR);
                break;
            case UPLOAD_ERR_FORM_SIZE:
                $this->_updateStatus(self::STATUS_EXCEED_MAX_FORM_SIZE);
                break;
            case UPLOAD_ERR_INI_SIZE: 
                $this->_updateStatus(self::STATUS_EXCEED_MAX_INI_SIZE);
                break;
            case UPLOAD_ERR_OK:
                if (!$this->_adapter->uploaded($this)) {
                    $this->_updateStatus(self::STATUS_ERROR);
                    break;
                }                
                if ($this->_adapter->exists($this) && !$this->_overwrite) {
                    $this->_updateStatus(self::STATUS_FILE_EXISTS);
                    break;
                }   
                if (!in_array($this->type, $this->_allowed)) {
                    $this->_updateStatus(self::STATUS_UPLOAD_FORMAT_NOT_ALLOWED);
                    break;
                }
                if (($this->_handler) && (-1 == $this->_handler->preProcess($this))) {
                    if(!$this->_adapter->write($this)) {
                        $this->_updateStatus(self::STATUS_UPLOAD_ERROR);
                    } else {
                        $this->_updateStatus(self::STATUS_UPLOAD_COMPLETE);
                    }
                }
                break;
            default:
                $this->_updateStatus(self::STATUS_NOT_READY);
                break;
        }
    }

l'handler di immagini è un oggetto del genere:

object(Solemare_Image_Editor)#54 (6) {
  ["_image:private"] => object(Solemare_Upload_File)#53 (11) {
    ["_status:protected"] => int(3)
    ["_adapter:protected"] => object(Solemare_Upload_Adapter_Filesystem)#50 (1) {
      ["_path:protected"] => string(74) "C:/Programmi/Apache Software Foundation/Apache2.2/htdocs/solemare/uploads/"
    }
    ["_allowed:protected"] => array(2) {
      [0] => string(10) "image/jpeg"
      [1] => string(9) "image/jpg"
    }
    ["_handler:protected"] => object(Solemare_Upload_Handler_Image)#51 (1) {
      ["_adapter:private"] => object(Solemare_Upload_Adapter_Filesystem)#50 (1) {
        ["_path:protected"] => string(74) "C:/Programmi/Apache Software Foundation/Apache2.2/htdocs/solemare/uploads/"
      }
    }
    ["name"] => string(6) "6l.jpg"
    ["tmp_name"] => string(26) "C:\WINDOWS\Temp\php701.tmp"
    ["type"] => string(10) "image/jpeg"
    ["size"] => int(229200)
    ["error"] => int(0)
    ["realtype"] => string(4) "jpeg"
    ["_mimes:protected"] => array(8) {
      ["image/jpeg"] => string(4) "jpeg"
      ["image/jpg"] => string(4) "jpeg"
      ["image/png"] => string(3) "png"
      ["image/gif"] => string(3) "gif"
      ["image/bmp"] => string(3) "bmp"
      ["text/plain"] => string(4) "text"
      ["application/pdf"] => string(3) "pdf"
      ["application/octet-stream"] => string(4) "file"
    }
  }
  ["_handle:private"] => resource(168) of type (gd)
  ["_attributes:private"] => array(4) {
    ["width"] => NULL
    ["height"] => NULL
    ["bits"] => NULL
    ["mime"] => NULL
  }
  ["_saveFormat:private"] => string(3) "jpg"
  ["_scale:private"] => bool(true)
  ["_path:private"] => string(74) "C:/Programmi/Apache Software Foundation/Apache2.2/htdocs/solemare/uploads/"
}

gli errori che ricevo sono :

Warning: getimagesize(Resource id #168) [function.getimagesize]: failed to open stream: No such file or directory in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 29

Warning: Division by zero in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 77

Warning: Division by zero in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 77
Warning: imagecreatetruecolor() [function.imagecreatetruecolor]: Invalid image dimensions in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 84

Warning: imagecopyresampled(): supplied argument is not a valid Image resource in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 85

Warning: imagedestroy(): supplied argument is not a valid Image resource in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 86

Warning: imagejpeg(): supplied argument is not a valid Image resource in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 142

Warning: Division by zero in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 77

Warning: Division by zero in C:\Programmi\Apache Software Foundation\Apache2.2\htdocs\solemare\libs\Solemare\Image\Editor.php on line 77

tutti dipendono dal fatto che non esiste un'immagine dalla quale prendere le dimensioni (division by zero) o effettuare ridimensionamenti a altro.

vorrei evitare di uppare il file, prenderlo, ridimensionarlo, salvare le 3 immagini ed eliminarlo ( questo si può fare dopo che l'upload è stato effettuato, usando il postprocessore)

 :bye:

risposto 9 anni fa
Andrea Turso
Andrea Turso
86
X 0 X

Hai verificato il perché getimagesize() punta al file sbagliato? E' un errore di percorso? Cosa cerca di aprire? Chi è che sbaglia a trasmettere il nome del file all'handler?

Dal dump dell'handler sembra che in tmp_name ci sia il percoso corretto del file temporaneo. getimagesize() non punta a questo?

 :bye:

risposto 9 anni fa
Gianni Tomasicchio
X 0 X

posso farlo con un file temporaneo?

comunque ora sto riscrivendo tutto da capo :D

spero di riuscirci.

non è difficile ( in teoria )

prendo $_FILES lo parso e metto tutto in un array di oggetti di tipo file ( immagine ) poi una volta che ho tutti i file nell'array files di upload scorro tutti i file e li uppo, se c'è il preprocessore lo eseguo e nel caso anche il postprocessore.

il problema è solo capire se posso usare le funzioni sulle immagini con il file temporaneo, così evito di uppare il file e lavorare su quello uppato (nella cartella)

risposto 9 anni fa
Andrea Turso
Andrea Turso
86
X 0 X

ma non puoi lavorare sul file temporaneo indicato in $_FILE?

risposto 9 anni fa
Gianni Tomasicchio
X 0 X

ehm non so se le GD mi permettono di usare i file temporanei come se fossero immagini, si può?

:bye:

risposto 9 anni fa
Andrea Turso
Andrea Turso
86
X 0 X

ehm non so se le GD mi permettono di usare i file temporanei come se fossero immagini, si può?

:bye:

secondo me si, comunque non devi far altro che provare.

 :bye:

risposto 9 anni fa
Gianni Tomasicchio
X 0 X

Gianni ho delegato alla classe Upload la creazione di un vettore di istanze di file, ogni file può essere di tipo :

Solemare_File_Type_Image

Solemare_File_Type_Text

Solemare_File_Type_Rar

--altri tipi di file --

il codice che si occupa dell'ordinamento di $_FILES e della creazione del vettore di oggetti è questo :

<?php
        foreach ($_files as $field => $data) {    
            $i = 0; 
            foreach ($data as $info) {            
                if ((('name' == $field) || ('size' == $field)  ||
                     ('type' == $field) || ('error' == $field) ||
                     ('tmp_name' == $field)) && (isset($info[0]))) {
                    $queue[$i][$field] = $info; 
                    //evito di inserire gli elementi di $_FILES vuoti , anche se perdo SIZE e ERROR ...
                }
                $i++;
            }
        }
        unset($_files);
        foreach ($queue as $file) {
            if (in_array($file['type'], $this->_allowed)) {
                $type = $this->_classType($file['type']);
                //il nome della classe è la parte prima dello / nel mime,
                // esempio : image/pgn -> image
                // application/pdf -> application in questo caso dovrei avere una sottoclasse : ...File_Type_Application_Pdf o File_Type_Pdf ( omettendo application nel caso sia quello il tipo ) ?
                $files[] = new Solemare_File_Type_Image($file, $path);
                // in questo punto dovrebbe decidere che tipo di classe instanziare
                // usato IMAGE per prova. come fare a decidere che tipo di class instanziare ?
                // ho provato Solemare_File_Type_$type($file,$path) ma non va :D
            }
        }

 :bye:

risposto 9 anni fa
Andrea Turso
Andrea Turso
86
X 0 X
Effettua l'accesso o registrati per rispondere a questa domanda