180 lines
4.3 KiB
PHP
180 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Intervention\Image;
|
|
|
|
use Intervention\Image\Exceptions\DirectoryNotFoundException;
|
|
use Intervention\Image\Exceptions\FileNotFoundException;
|
|
use Intervention\Image\Exceptions\FileNotReadableException;
|
|
use Intervention\Image\Exceptions\FileNotWritableException;
|
|
use Intervention\Image\Exceptions\StreamException;
|
|
use Intervention\Image\Exceptions\InvalidArgumentException;
|
|
use Intervention\Image\Interfaces\FileInterface;
|
|
use Intervention\Image\Traits\CanBuildStream;
|
|
use Intervention\Image\Traits\CanParseFilePath;
|
|
use Stringable;
|
|
|
|
class File implements FileInterface, Stringable
|
|
{
|
|
use CanBuildStream;
|
|
use CanParseFilePath;
|
|
|
|
/**
|
|
* @var resource
|
|
*/
|
|
protected $stream;
|
|
|
|
/**
|
|
* Create new instance.
|
|
*
|
|
* @param string|resource|null $data
|
|
* @throws InvalidArgumentException
|
|
* @throws StreamException
|
|
*/
|
|
public function __construct(mixed $data = null)
|
|
{
|
|
$this->stream = self::buildStreamOrFail($data);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @see FileInterface::fromPath()
|
|
*
|
|
* @throws InvalidArgumentException
|
|
* @throws DirectoryNotFoundException
|
|
* @throws FileNotFoundException
|
|
* @throws FileNotReadableException
|
|
* @throws StreamException
|
|
*/
|
|
public static function fromPath(string $path): self
|
|
{
|
|
$stream = fopen(self::readableFilePathOrFail($path), 'r');
|
|
|
|
if ($stream === false) {
|
|
throw new FileNotReadableException('Failed to open file from path "' . $path . '"');
|
|
}
|
|
|
|
return new self($stream);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @see FileInterface::save()
|
|
*
|
|
* @throws InvalidArgumentException
|
|
* @throws DirectoryNotFoundException
|
|
* @throws FileNotWritableException
|
|
* @throws StreamException
|
|
*/
|
|
public function save(string $path): void
|
|
{
|
|
if ($path === '') {
|
|
throw new InvalidArgumentException('Path must not be an empty string');
|
|
}
|
|
|
|
if (strlen($path) > PHP_MAXPATHLEN) {
|
|
throw new InvalidArgumentException(
|
|
"Path is longer than the configured max. value of " . PHP_MAXPATHLEN
|
|
);
|
|
}
|
|
|
|
$dir = pathinfo($path, PATHINFO_DIRNAME);
|
|
|
|
if (!is_dir($dir)) {
|
|
throw new DirectoryNotFoundException(
|
|
'Can\'t write to path. Directory "' . $dir . '" does not exist'
|
|
);
|
|
}
|
|
|
|
if (!is_writable($dir)) {
|
|
throw new FileNotWritableException(
|
|
'Can\'t write to path. Directory "' . $dir . '" is not writable'
|
|
);
|
|
}
|
|
|
|
if (is_file($path) && !is_writable($path)) {
|
|
throw new FileNotWritableException(
|
|
"Can't write to path. Existing file " . $path . " is not writable"
|
|
);
|
|
}
|
|
|
|
// write data
|
|
$saved = file_put_contents($path, $this->toStream());
|
|
|
|
if ($saved === false) {
|
|
throw new FileNotWritableException(
|
|
"Failed to write file to path " . $path
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @see FileInterface::toString()
|
|
*
|
|
* @throws StreamException
|
|
*/
|
|
public function toString(): string
|
|
{
|
|
$data = stream_get_contents($this->toStream(), offset: 0);
|
|
|
|
if ($data === false) {
|
|
throw new StreamException('Unable to read data from stream');
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @see FileInterface::toStream()
|
|
*
|
|
* @throws StreamException
|
|
*/
|
|
public function toStream()
|
|
{
|
|
$rewind = rewind($this->stream);
|
|
|
|
if ($rewind === false) {
|
|
throw new StreamException('Failed to rewind stream');
|
|
}
|
|
|
|
return $this->stream;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @see FileInterface::size()
|
|
*
|
|
* @throws StreamException
|
|
*/
|
|
public function size(): int
|
|
{
|
|
$info = fstat($this->toStream());
|
|
|
|
if (!is_array($info)) {
|
|
throw new StreamException('Unable to read size of stream');
|
|
}
|
|
|
|
return intval($info['size']);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @see FileInterface::__toString()
|
|
*
|
|
* @throws StreamException
|
|
*/
|
|
public function __toString(): string
|
|
{
|
|
return $this->toString();
|
|
}
|
|
}
|