UploadedFile.php 14.51 KiB
<?php
/*
 * Copyright (C) 2015 IRSTEA
 * All rights reserved.
 */
namespace Irstea\FileUploadBundle\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Gaufrette\Exception\FileNotFound;
use Gaufrette\Filesystem;
use Gaufrette\StreamMode;
use InvalidArgumentException;
use Irstea\FileUploadBundle\Entity\Repository\UploadedFileRepository;
use Irstea\FileUploadBundle\Model\UploadedFileInterface;
use Irstea\FileUploadBundle\Utils\MimeTypeIcon;
use Rhumsaa\Uuid\Uuid;
/**
 * @ORM\Entity(repositoryClass="Irstea\FileUploadBundle\Entity\Repository\UploadedFileRepository")
 * @ORM\EntityListeners({"Irstea\FileUploadBundle\Listener\UploadedFileListener"})
class UploadedFile implements UploadedFileInterface
    // Taille de bloc utilisé pour les copies
    static public $copyBlockSize = 8192;
    /**
     * @ORM\Id
     * @ORM\Column(type="guid")
     * @var string
    private $id;
    /**
     * @ORM\Column(type="string", length=1024)
     * @var string
    private $displayName;
    /**
     * @ORM\Column(type="string", length=1024)
     * @var string
    private $path;
    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @var string
    private $mimeType = null;
    /**
     * @ORM\Column(type="integer", nullable=true)
     * @var int
    private $size = null;
    /**
     * @ORM\Column(type="string", length=64, nullable=true)
     * @var string
    private $checksum = null;
    /**
     * @ORM\Column(type="string", length=10)
     * @var string
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
*/ private $etat = self::ETAT_EN_COURS; /** * @ORM\Column(type="datetime") * @var DateTime */ private $createdAt; /** * @ORM\Column(type="string", nullable=true) * @var string */ private $createdBy; /** * @ORM\Column(type="string", nullable=true) * @var string */ private $createdFrom; /** * @ORM\Column(type="json_array", nullable=true) * @var array */ private $metadata = null; /** * @ORM\Column(type="string", length=256, nullable=true) * @var string */ private $description = null; /** * @var Filesystem */ private $filesystem; /** Contient le nom de chemin local. * * @var string */ private $localTempPath = null; /** * * @param string $createdBy * @param string $createdFrom */ public function __construct($createdBy = null, $createdFrom = null) { $this->id = Uuid::uuid4()->toString(); $this->path = "orphan/".$this->id; $this->createdAt = new DateTime('now'); $this->createdBy = $createdBy; $this->createdFrom = $createdFrom; } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set originalFilename
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
* * @param string $displayName * @return UploadedFileInterface */ public function setDisplayName($displayName) { $this->displayName = $displayName; return $this; } /** * Get originalFilename * * @return string */ public function getDisplayName() { return $this->displayName; } /** * Get path * * @return string */ public function getPath() { return $this->path; } /** * Set path * * @param string $path * @return UploadedFileInterface */ public function setPath($path) { if(!static::isSafePath($path)) { throw new InvalidArgumentException("Unsafe path: $path"); } $this->path = trim($path, '/'); return $this; } /** Change le chemin d'un fichier sans changer le nom. * * @param string $newDir Nouveau répertoire * @return UploadedFileInterface */ public function moveTo($newDir) { $this->setPath(rtrim($newDir, '/') . '/' . pathinfo($this->path, PATHINFO_FILENAME)); } /** * Set mimeType * * @param string $mimeType * @return UploadedFileInterface */ public function setMimeType($mimeType) { $this->mimeType = $mimeType; return $this; }
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
/** * Get mimeType * * @return string */ public function getMimeType() { return $this->mimeType; } /** * Set size * * @param integer $size * @return UploadedFileInterface */ 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 UploadedFileInterface */ public function setChecksum($checksum) { $this->checksum = $checksum; return $this; } /** * Get checksum * * @return string */ public function getChecksum() { return $this->checksum; } /** * Set etat * * @param string $etat * @return UploadedFileInterface */ public function setEtat($etat) { if(!in_array( $etat, [ self::ETAT_CORROMPU, self::ETAT_EN_COURS, self::ETAT_MANQUANT,
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
self::ETAT_NORMAL, self::ETAT_ORPHELIN, self::ETAT_REJETE ] )) { throw new InvalidArgumentException(sprintf("Etat invalide: '%s'", (string)$etat)); } $this->etat = $etat; return $this; } /** * Get etat * * @return string */ public function getEtat() { return $this->etat; } /** * Get createdAt * * @return \DateTime */ public function getCreatedAt() { return $this->createdAt; } /** * Set metadata * * @param array $metadata * @return UploadedFileInterface */ 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"; } }
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
return sprintf("%s (%s, %d%so)", $this->displayName, $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; $path = $this->getPath(); if (!$filesystem->has($path)) { $this->setEtat(self::ETAT_MANQUANT); return; } if ($filesystem->size($path) !== $this->size || $filesystem->checksum($path) !== $this->checksum) { $this->setEtat(self::ETAT_CORROMPU); return; } } /** * * @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 \DateTime */ public function getLastModified() { try { return new \DateTime(sprintf('@%d', $this->filesystem->mtime($this->getPath()))); } catch(FileNotFound $ex) { return null; } } /** Retourne le contenu du fichier. * * @return string Une chaîne si $asResource vaut faux, */ public function getContent() {
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
return $this->filesystem->read($this->getPath()); } /** Ecrit dans le fichier. * * @param string $content */ public function setContent($content) { 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) { if($maxlen === 0) { return 0; } $stream = $this->filesystem->createStream($this->getPath()); $stream->open(new StreamMode('cb')); $stream->seek($writeOffset); 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); } if (0 <= $actualLength) { return 0; } $stream = $this->filesystem->createStream($this->getPath()); $stream->open(new StreamMode('rb')); $stream->seek($readOffset);
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
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 * @return boolean */ protected function feof($filehandle) { return feof($filehandle); } /** Wrapper de fread * * @param resource $filehandle * @param int $maxlen * @return int|boolean */ protected function fread($filehandle, $maxlen = -1) { return fread($filehandle, $maxlen); } /** Wrapper de fwrite * * @param resource $filehandle * @param int $maxlen * @return int|boolean */ protected function fwrite($filehandle, $maxlen = -1) { return fwrite($filehandle, $maxlen); } /** Vérifie si * * @param string $path * @return boolean */ public static function isSafePath($path) { $parts = explode('/', trim($path, '/')); $level = 0;
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
foreach($parts as $part) { switch($part) { case '.': break; case '..': $level--; if($level < 0) { return false; } break; default: $level++; } } return true; } /** * @return string */ public function getDescription() { return $this->description; } /** * * @param string $description * @return UploadedFileInterface */ public function setDescription($description = null) { $this->description = $description; return $this; } /** * @return array */ public function toArray() { return [ 'id' => $this->getId(), 'name' => $this->getDisplayName(), 'size' => $this->getSize(), 'type' => $this->getMimeType(), 'etat' => $this->getEtat(), 'description' => $this->getDescription(), 'checksum' => $this->getChecksum(), 'icon' => MimeTypeIcon::getMimeTypeIcon($this->getMimeType()) ]; } /** * Get createdBy * * @return string */ public function getCreatedBy() { return $this->createdBy; } /** * Get createdFrom * * @return string */ public function getCreatedFrom() {
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
return $this->createdFrom; } public function getLocalPath() { if(null !== $this->localTempPath) { return $this->localTempPath; } $stream = $this->filesystem->createStream($this->getPath()); $stream->open(new StreamMode('rb')); $handle = $stream->cast(STREAM_CAST_AS_STREAM); if(false !== $handle) { if(stream_is_local($handle)) { $this->localTempPath = stream_get_meta_data($handle)['uri']; fclose($handle); return $this->localTempPath; } fclose($handle); } $this->localTempPath = tempnam(sys_get_temp_dir(), 'UploadedFile'); register_shutdown_function('unlink', $this->localTempPath); $tmp = fopen($this->localTempPath, 'xb'); $this->copyTo($tmp); fclose($tmp); return $this->localTempPath; } }