Skip to content

Commit

Permalink
File: better validation & errors, add info method
Browse files Browse the repository at this point in the history
  • Loading branch information
LikeAJohny committed Dec 4, 2023
1 parent 99ca1a3 commit 23816bf
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 26 deletions.
41 changes: 39 additions & 2 deletions src/Exception/FileException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,49 @@

use RuntimeException;

use function sprintf;

class FileException extends RuntimeException
{
public static function noFile(string $noFile): self
public static function createError(string $file, ?array $error): self
{
return new self(
sprintf('Could not create file "%s". %s', $file, $error['message'] ?? '')
);
}

public static function noFile(string $file): self
{
return new self(
sprintf('Given value "%s" doesn\'t appear to be a file.', $file)
);
}

public static function notReadable(string $file): self
{
return new self(
sprintf('Given file "%s" is not readable.', $file)
);
}

public static function readError(string $file, ?array $error): self
{
return new self(
sprintf('Could not read from file "%s". %s', $file, $error['message'] ?? ''),
);
}

public static function notWriteable(string $file): self
{
return new self(
sprintf('Given file "%s" is not writeable.', $file)
);
}

public static function writeError(string $file, ?array $error): self
{
return new self(
sprintf('Given value "%s" doesn\'t appear to be a file.', $noFile)
sprintf('Could not write to file "%s". %s', $file, $error['message'] ?? '')
);
}
}
113 changes: 93 additions & 20 deletions src/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,145 @@
namespace PhpFs;

use PhpFs\Exception\FileException;
use Throwable;

use function chmod;
use function error_get_last;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function fileperms;
use function finfo_close;
use function finfo_file;
use function finfo_open;
use function finfo_set_flags;
use function fopen;
use function is_file;
use function is_readable;
use function is_writeable;
use function pathinfo;
use function unlink;

class File
{
public static function create(string $file): bool
public static function create(string $file, int $mode = 0766): mixed
{
return (bool)fopen($file, 'wb');
$resource = fopen($file, 'wb');
if ($resource === false || !chmod($file, $mode)) {
throw FileException::createError($file, error_get_last());
}

return $resource;
}

public static function exists(string $file): bool
{
return file_exists($file);
}

public static function write(string $file, string $content): bool
public static function info(string $file): array
{
self::validate($file);
self::validateRead($file);

$info = [...pathinfo($file)];
$info['permissions'] = substr(sprintf('%o', fileperms($file)), -4);

return (bool)file_put_contents($file, $content);
$handle = finfo_open(FILEINFO_MIME_TYPE);
$info['mime_type'] = finfo_file($handle, $file);
finfo_set_flags($handle, FILEINFO_MIME_ENCODING);
$info['mime_encoding'] = finfo_file($handle, $file);
finfo_close($handle);

return $info;
}

public static function append(string $file, string $content): bool
public static function write(string $file, string $content): bool|int
{
self::validate($file);
self::validateWrite($file);

return (bool)file_put_contents($file, self::read($file) . $content);
$bytes = file_put_contents($file, $content);
if ($bytes === false) {
throw FileException::writeError($file, error_get_last());
}

return $bytes;
}

public static function prepend(string $file, string $content): bool
public static function append(string $file, string $content): bool|int
{
self::validate($file);
self::validateWrite($file);

$bytes = file_put_contents($file, self::read($file).$content);
if ($bytes === false) {
throw FileException::writeError($file, error_get_last());
}

return (bool)file_put_contents($file, $content . self::read($file));
return $bytes;
}

public static function read(string $file): string
public static function prepend(string $file, string $content): bool|int
{
return file_get_contents($file);
self::validateWrite($file);

$bytes = file_put_contents($file, $content.self::read($file));
if ($bytes === false) {
throw FileException::writeError($file, error_get_last());
}

return $bytes;
}

public static function remove(string $file): bool
public static function read(string $file): string
{
self::validate($file);
self::validateRead($file);

return unlink($file);
$content = file_get_contents($file);
if ($content === false) {
throw FileException::readError($file, error_get_last());
}

return $content;
}

public static function copy(string $file, string $targetFile): bool
{
self::validate($file);
self::validateFile($file);

return copy($file, $targetFile);
}

public static function move(string $file, string $targetFile): bool
{
self::validate($file);
self::validateFile($file);

return rename($file, $targetFile);
}

private static function validate(string $file): void
public static function remove(string $file): bool
{
self::validateFile($file);

return unlink($file);
}

private static function validateRead(string $file): void
{
self::validateFile($file);

if (!is_readable($file)) {
throw FileException::notReadable($file);
}
}

private static function validateWrite(string $file): void
{
self::validateFile($file);

if (!is_writeable($file)) {
throw FileException::notWriteable($file);
}
}

private static function validateFile(string $file): void
{
if (!is_file($file)) {
throw FileException::noFile($file);
Expand Down
45 changes: 41 additions & 4 deletions tests/FileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
use PhpFs\Exception\FileException;
use PhpFs\File;
use PHPUnit\Framework\TestCase;
use Throwable;

use function var_dump;

class FileTest extends TestCase
{
Expand All @@ -24,7 +27,6 @@ public function testCanCreateFile(): void
public function testThrowsExceptionOnCreateError(): void
{
$this->expectException(FileException::class);

File::create(self::ARTIFACTS . '/dir-does-not-exist/cool-story-bro.txt');
}

Expand All @@ -34,12 +36,38 @@ public function testDeterminesIfFileExists(): void
$this->assertFalse(File::exists(self::FIXTURES . '/content/second-level.txt'));
}

public function testGetsFileInformation(): void
{
$file = self::ARTIFACTS . '/test.txt';
File::create($file, 0644);
File::write($file, 'test');

$info = File::info($file);

$this->assertEquals(self::ARTIFACTS, $info['dirname']);
$this->assertEquals('test.txt', $info['basename']);
$this->assertEquals('test', $info['filename']);
$this->assertEquals('txt', $info['extension']);
$this->assertEquals('text/plain', $info['mime_type']);
$this->assertEquals('us-ascii', $info['mime_encoding']);
$this->assertEquals('0644', $info['permissions']);
}

public function testCanWriteToNewFile(): void
{
$file = self::ARTIFACTS . '/cool-story-bro.txt';
File::create($file);

$this->assertTrue(File::write($file, 'Tell me more, lol x3'));
$this->assertEquals(20, File::write($file, 'Tell me more, lol x3'));
}

public function testThrowsExceptionOnWriteError(): void
{
$file = self::ARTIFACTS . '/cool-story-bro.txt';
File::create($file, 0000);

$this->expectException(FileException::class);
File::write($file, 'Tell me more, lol x3');
}

public function testCanAppendToExistingFile(): void
Expand All @@ -48,7 +76,7 @@ public function testCanAppendToExistingFile(): void
File::create($file);
File::write($file, 'Test');

$this->assertTrue(File::append($file, ' Me'));
$this->assertEquals(7, File::append($file, ' Me'));
$this->assertEquals('Test Me', File::read($file));
}

Expand All @@ -58,7 +86,7 @@ public function testCanPrependToExistingFile(): void
File::create($file);
File::write($file, 'Me');

$this->assertTrue(File::prepend($file, 'Test '));
$this->assertEquals(7, File::prepend($file, 'Test '));
$this->assertEquals('Test Me', File::read($file));
}

Expand All @@ -74,6 +102,15 @@ public function testCanReadFromExistingFile(): void
);
}

public function testThrowsExceptionOnReadError(): void
{
$file = self::ARTIFACTS . '/cool-story-bro.txt';
File::create($file, 0000);

$this->expectException(FileException::class);
File::read($file);
}

public function testCanRemoveFile(): void
{
$file = self::ARTIFACTS . '/to-be-removed.txt';
Expand Down

0 comments on commit 23816bf

Please sign in to comment.