<?php namespace App\Classes; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Log; use Symfony\Component\HttpFoundation\File\File as FileBase; use App\Classes\FTN\Packet; class File extends FileBase implements \Iterator { private const LOGKEY = 'F--'; private int $counter = 0; private bool $isArchive = FALSE; private bool $canHandle = FALSE; private \ZipArchive $z; private array $zipfile = []; public function __construct(mixed $path,bool $checkPath=true) { parent::__construct($path,$checkPath); switch($x=$this->guessExtension()) { case 'zip': $this->canHandle = TRUE; $this->isArchive = TRUE; $this->z = new \ZipArchive; $this->z->open($this->getRealPath()); break; case NULL: case 'bin': if ($this->isPacket() || ($path instanceof UploadedFile && (strcasecmp($path->getClientOriginalExtension(),'pkt') === 0))) { $this->canHandle = TRUE; break; } default: Log::alert(sprintf('%s:? Unknown file received: %s (%s) [%s]',self::LOGKEY,$x,$this->getExtension(),$path instanceof UploadedFile ? $path->getClientOriginalExtension() : '-')); } } /* ITERATOR */ public function current() { if ($this->isArchive) { $this->zipfile = $this->z->statIndex($this->counter,\ZipArchive::FL_UNCHANGED); $f = $this->z->getStream($this->zipfile['name']); if (! $f) throw new \Exception(sprintf('%s:Failed getting ZipArchive::stream (%s)',self::LOGKEY,$this->z->getStatusString())); return $f; } else { return fopen($this->getRealPath(),'r+'); } } public function next() { $this->counter++; } public function key() { return $this->counter; } public function valid() { // If we have a pkt file, then counter can only be 1. return $this->canHandle && (($this->isArchive && ($this->counter < $this->z->numFiles)) || $this->counter === 0); } public function rewind() { $this->counter = 0; } /* METHODS */ /** * Determine if the file is a mail packet * * @return bool */ private function isPacket(): bool { return (strcasecmp($this->getExtension(),'pkt') === 0); } public function itemName(): string { return ($this->isArchive && $this->valid()) ? Arr::get(stream_get_meta_data($this->current()),'uri') : $this->getFilename(); } public function itemSize(): int { return $this->isArchive ? Arr::get($this->zipfile,'size') : $this->getSize(); } /** * Return the name of the file, without a node ID, mtime prefix * * @return string */ public function rawName(): string { return preg_replace(sprintf('/^%s\.pkt$/i',Packet::regex),'\3\4',$this->getFilename()); } /** * Return the packet name * * @return string|null * @throws \Exception */ public function pktName(): ?string { if ($this->isArchive) { $this->zipfile = $this->z->statIndex($this->counter,\ZipArchive::FL_UNCHANGED); $f = $this->z->getStream($this->zipfile['name']); if (! $f) throw new \Exception(sprintf('%s:Failed getting ZipArchive::stream (%s)',self::LOGKEY,$this->z->getStatusString())); return preg_replace('/.pkt$/i','',Arr::get(stream_get_meta_data($f),'uri')); } else { return $this->isPacket() ? $this->rawName() : NULL; } } }