UploadedFile.php 10.5 KB
Newer Older
<?php

/*
 * Copyright (C) 2015 IRSTEA
 * All rights reserved.
 */

namespace Irstea\FileUploadBundle\Entity;

use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Gaufrette\Filesystem;
use Gaufrette\StreamMode;
use Rhumsaa\Uuid\Uuid;

/**
 * @ORM\Entity(repositoryClass="Irstea\FileUploadBundle\Entity\Repository\UploadedFileRepository")
 * @ORM\EntityListeners({"Irstea\FileUploadBundle\Listener\UploadedFileListener"})
 */
class UploadedFile
{
    // Taille de bloc utilisé pour les copies
    static public $copyBlockSize = 8192;

    const ETAT_EN_COURS = 'en-cours';
    const ETAT_ORPHELIN = 'orphelin';
    const ETAT_NORMAL   = 'normal';
    const ETAT_CORROMPU = 'corrompu';
    const ETAT_MANQUANT = 'manquant';

    /**
     * @ORM\Id
     * @ORM\Column(type="guid")
     * @var string
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=1024)
     * @var string
     */
    private $originalFilename;

    /**
     * @ORM\Column(type="string", length=1024)
     * @var string
     */
    private $path;

    /**
     *
     * @ORM\Column(type="string", length=255, nullable=true)
     * @var string
     */
    private $mimeType;

    /**
     * @ORM\Column(type="integer", nullable=true)
     * @var int
     */
    private $size;

    /**
     * @ORM\Column(type="string", length=64, nullable=true)
     * @var string
     */
    private $checksum;

    /**
     * @ORM\Column(type="string", length=10)
     * @var string
    private $etat = self::ETAT_EN_COURS;

    /**
     * @ORM\Column(type="datetime")
     * @var DateTime
     */
    private $createdAt;

    /**
     * @ORM\Column(type="json_array", nullable=true)
     * @var array
     */
    private $metadata;

    /**
     * @var Filesystem
     */
    private $filesystem;

    /**
     *
     */
    public function __construct()
    {
        $this->id = Uuid::uuid4()->toString();
        $this->path = "orphan/".$this->id;
        $this->createdAt = new DateTime('now');
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set originalFilename
     *
     * @param string $originalFilename
     * @return UploadedFile
     */
    public function setOriginalFilename($originalFilename)
    {
        $this->originalFilename = $originalFilename;

        return $this;
    }

    /**
     * Get originalFilename
     *
     * @return string
     */
    public function getOriginalFilename()
    {
        return $this->originalFilename;
    }

    /**
     * Get path
     *
     * @return string
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Set path
     *
     * @param string $path
     * @return UploadedFile
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * Set mimeType
     *
     * @param string $mimeType
     * @return UploadedFile
     */
    public function setMimeType($mimeType)
    {
        $this->mimeType = $mimeType;

        return $this;
    }

    /**
     * Get mimeType
     *
     * @return string
     */
    public function getMimeType()
    {
        return $this->mimeType;
    }

    /**
     * Set size
     *
     * @param integer $size
     * @return UploadedFile
     */
    public function setSize($size)
    {
        $this->size = $size;

        return $this;
    }

    /**
     * Get size
     *
     * @return integer
     */
    public function getSize()
    {
        return $this->size;
    }

    /**
     * Set checksum
     *
     * @param string $checksum
     * @return UploadedFile
     */
    public function setChecksum($checksum)
    {
        $this->checksum = $checksum;

        return $this;
    }

    /**
     * Get checksum
     *
     * @return string
     */
    public function getChecksum()
    {
        return $this->checksum;
    }

    /**
        if(!in_array($etat, [self::ETAT_CORROMPU, self::ETAT_EN_COURS, self::ETAT_MANQUANT, self::ETAT_NORMAL, self::ETAT_ORPHELIN])) {
            throw new InvalidArgumentException(sprintf("Etat invalide: '%s'", (string)$etat));
        }
        $this->etat = $etat;
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set metadata
     *
     * @param array $metadata
     * @return UploadedFile
     */
    public function setMetadata(array $metadata = null)
    {
        $this->metadata = $metadata;

        return $this;
    }

    /**
     * Get metadata
     *
     * @return array
     */
    public function getMetadata()
    {
        return $this->metadata;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        $unit = "";
        $size = $this->size ?: 0;
        if($size >= 10240) {
            $size /= 1024;
            $unit = "k";
            if($size >= 10240) {
                $size /= 1024;
                $unit = "m";
            }
        }
        return sprintf("%s (%s, %d%so)", $this->originalFilename, $this->mimeType ?: '?/?', $size, $unit);
    }

    /**
     * @param Filesystem $filesystem
     * @return self
     */
    public function setFilesystem(Filesystem $filesystem)
    {
        $this->filesystem = $filesystem;
        return $this;
    }

    public function validate()
    {
        if (self::ETAT_EN_COURS !== $this->getEtat()) {
            return;
        }

        $filesystem = $this->filesystem;
        if (!$filesystem->has($path)) {
            $this->setEtat(self::ETAT_MANQUANT);
            return;
        }

        if ($filesystem->size($path) !== $this->size || $filesystem->checksum($path) !== $this->checksum) {
     * @return boolean
     */
    public function isValid()
    {
        return $this->getEtat() === self::ETAT_ORPHELIN || $this->getEtat() === self::ETAT_NORMAL;
    }

    /**
     *
     * @return boolean
     */
    public function isOrphelin()
    {
        return $this->getEtat() === self::ETAT_ORPHELIN;
    /** Retourne la date de dernière modification dans le filesystem.
        return new \DateTime(sprintf('@%d', $this->filesystem->mtime($this->getPath())));
     * @return string Une chaîne si $asResource vaut faux,
     */
    public function getContent()
    {
        return $this->filesystem->read($this->getPath());
    }

        return $this->filesystem->write($this->getPath(), $content, true);
    }

    /** Ecrit dans le fichier depuis un descripteur de fichier.
     *
     * @param resource $source
     * @param int $maxlen
     * @param int $writeOffset
     * @return int
     */
    public function copyFrom($source, $maxlen = -1, $writeOffset = 0)
        $stream = $this->filesystem->createStream($this->getPath());
        $stream->open(new StreamMode('cb'));
        if(false !== $fileHandle = $stream->cast(STREAM_CAST_AS_STREAM)) {
            // Utilise stream_copy_to_stream si le Gaufrette\Stream peut nous retourner un filehandle
            $copied = $this->stream_copy_to_stream($source, $fileHandle, $maxlen);
        } else {
            // Sinon fait une copie par blocs (moins performant)
            if($maxlen === -1) {
                $maxlen = PHP_INT_MAX;
            }
            $copied = 0;
            while(!$this->feof($source) && $copied <= $maxlen) {
                $copied += $stream->write($this->fread($source, min(static::$copyBlockSize, $maxlen - $copied)));
            }
        }
        $stream->close();

        return $copied;
    }

    /** Envoie le contenu du fichier dans un descripteur de fichier.
     * @param resource $dest
     * @param int $maxlen
     * @param int $readOffset
     * @return int
     */
    public function copyTo($dest, $maxlen = PHP_INT_MAX, $readOffset = 0)
    {
        if($maxlen === -1) {
            $actualLength = $this->getSize() - $readOffset;
        } else {
            $actualLength = min($maxlen, $this->getSize() - $readOffset);
        }
        $stream = $this->filesystem->createStream($this->getPath());
        $stream->open(new StreamMode('rb'));
        $stream->seek($readOffset);

        if(false !== $fileHandle = $stream->cast(STREAM_CAST_AS_STREAM)) {
            // Utilise stream_copy_to_stream si le Stream nous renvoie un filehandle
            $copied = $this->stream_copy_to_stream($fileHandle, $dest, $actualLength);
        } else {
            // Sinon, on fait ça à la main par blocs de 8ko
            $copied = 0;
            while(!$stream->eof() && $copied < $actualLength) {
                $copied += $this->fwrite($dest, $stream->read(min(static::$copyBlockSize, $actualLength - $copied)));
            }
        }

        $stream->close();

        return $copied;
    }

    /** Wrapper de stream_copy_to_stream
     *
     * @param resource $source
     * @param resource $dest
     * @param int $maxlen
     * @param int $offset
     * @return int
     */
    protected function stream_copy_to_stream($source, $dest, $maxlen = -1, $offset = 0)
    {
        return stream_copy_to_stream($source, $dest, $maxlen, $offset);
    }

    /** Wrapper de feof
     *
     * @param resource $filehandle
    protected function feof($filehandle)
        return feof($filehandle);
     * @param resource $filehandle
    protected function fread($filehandle, $maxlen = -1)
        return fread($filehandle, $maxlen);
     * @param resource $filehandle
    protected function fwrite($filehandle, $maxlen = -1)
        return fwrite($filehandle, $maxlen);