Commit 7ca564b1 authored by Adam Brown's avatar Adam Brown

version 1.1.0

parent 2078fb8b
......@@ -8,11 +8,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.0.0] - 2018-07-08
### Added
-
- Boolean checks
- File event dates
- Basic Hashing
- Path info and mime types
- File Permission info
- File size calculator
## [1.1.0] - 2018-07-12
### Added
- Ability to check to see if Carbon is installed and output dates in Carbon format
- Added a hashing benchmark and friendly microtime output method. Will be taken out and put into another package soon
- Now lets you specify what hashes process using the config file
- Allows you to set a maximum file size for hashing
- Now shows how much space a directory takes
### Changed
-
- Changed function name from `examine` to `all`
- Now uses variable set in $this so it doesn't have to be passed to every function
- Object is now mostly arrays rather than sub objects
### Removed
-
......@@ -9,18 +9,23 @@ Feed it a file location and get back information like its mimetype, hashes, size
### To Do
- [ ] If file is beyond a certain size, do not hash it automatically when requesting all the data
- [ ] Allow for specific hash tests
- [X] If file is beyond a certain size, do not hash it automatically when requesting all the data
- [X] Allow for specific hash tests
- [ ] Make everything a lot more fluent
- [ ] Return a proper collection
- [ ] Allow for hash grouping tests and set one to be the default
- [ ] check for hash algorithm before running
- [ ] Allow file name to be specified during the creation
- [X] check for hash algorithm before running
- [X] Allow file name to be specified during the creation
- [ ] Allow static access
- [ ] Add Techendeavors\FriendlyScale results to FileSize output if the package is loaded
- [ ] Make Permissions a collection that has octal and human readable permission information and maybe also list ACL info
- [ ] Move user and group info to an Ownership collection. ACL info might need to be in there instead/also.
- [ ] Make a getEvents class that includes the file creation and modification date
- [ ] Convert the functions to traits
- [ ] Optional modules to check file hashes against various databases
- [ ] Transition some integrated scaling functions to Techendeavors\FriendlyScale
- [X] Make Permissions a collection that has octal and human readable permission information
- [ ] Look into listing ACL info
- [ ] Output current user and group the check is running under
- [X] Move user and group info to an Ownership collection.
- [X] Make a getEvents class that includes the file creation and modification date
- [X] Convert the functions to traits
- [ ] Optional modules to check file hashes against various databases (perhaps another package?)
- [ ] https://totalhash.com/
- [ ] https://www.team-cymru.com/mhr.html#dns (DNS using Techendeavors\DNSOverHttps)
- [ ] https://www.owasp.org/index.php/OWASP_File_Hash_Repository (DNS using Techendeavors\DNSOverHttps)
......@@ -57,17 +62,121 @@ composer require techendeavors/fileinfo
### Usage
``` php
$skeleton = new Techendeavors\FileInfo();
echo $skeleton->echoPhrase('Hello, Techendeavors!');
Useful file output
```
>>> $test = new FileInfo('/usr/bin/ffmpeg')
=> Techendeavors\FileInfo\FileInfo {#2855}
>>> $test->all()
=> Illuminate\Support\Collection {#2849
all: [
"query" => "/usr/bin/ffmpeg",
"tests" => [
"directory" => false,
"executable" => true,
"file" => true,
"link" => false,
],
"permissions" => [
"readable" => true,
"writable" => false,
"user" => "root",
"group" => "root",
"octal" => "0755",
"human" => "rwxr-xr-x",
],
"info" => [
"name" => "ffmpeg",
"path" => "/usr/bin",
"type" => "file",
"mime" => "application/x-sharedlib",
],
"size" => [
"bytes" => 272528,
"human" => "266.14KB",
],
"hashes" => [
"crc32" => "ec9b4c8f",
"crc32b" => "b5be398b",
"md5" => "7f7f8d7d5549ec1deabaff3f615f80ce",
"ripemd256" => "8fc001f0f9395f14ceb652cdef4d4a54caa33dae549a002e95ad45c8365ff4cc",
"sha1" => "f43e9bb580a156aa3f84ba15d6965ac23d86b5d0",
"sha256" => "290bb7c6a8bfdd308b2a59c3fd8f3655aec224646a9f348920a81d492db85aef",
"sha3-256" => "7ef630dda0bc7484f00cd7e9c4268ee3c886212121991c0e94ab49e0c799cdfb",
"sha3-384" => "cfb8fba5ee465a81c6c0d9ba2171d248fa902ec0a288cfb284f319aa7bbe6e2310e2f33252596d78de5ef8e3af3c78ba",
"sha3-512" => "3fceb5e875610d283d223e10f914af02a7d367247dd00e87dff33e61afa7364e814a84ce2b831d91042605051e1d2371a3004ba0ca5dbd804dd8cf6cf843eeeb",
"sha384" => "8e8a8dbb4542f55152cf77ed44d304febdc3182a775e54238c5d85a942d30b226347475a148b36f2e7638fedd5b0dab6",
"sha512" => "0f3a69a3dada9ac0f12111a9c6c901d29c17fc30510764278a3cb52c1c0b61f57ad33e9197dda5f673452105df9d117b3fb99c7feeb330ffc55dae893325f859",
],
"events" => [
"modified" => Carbon\Carbon @1523273080 {#2866
date: 2018-04-09 11:24:40.0 UTC (+00:00),
},
"changed" => Carbon\Carbon @1526714923 {#2861
date: 2018-05-19 07:28:43.0 UTC (+00:00),
},
"accessed" => Carbon\Carbon @1531345222 {#2856
date: 2018-07-11 21:40:22.0 UTC (+00:00),
},
],
],
}
```
### Testing
Even works with directories
```
>>> $test = new FileInfo('/usr/bin')
=> Techendeavors\FileInfo\FileInfo {#2864}
>>> $test->all()
=> Illuminate\Support\Collection {#2861
all: [
"query" => "/usr/bin",
"tests" => [
"directory" => true,
"executable" => true,
"file" => false,
"link" => false,
],
"permissions" => [
"readable" => true,
"writable" => false,
"user" => "root",
"group" => "root",
"octal" => "755",
"human" => "rwxr-xr-x",
],
"info" => [
"name" => "bin",
"path" => "/usr",
"type" => "dir",
"mime" => "directory",
],
"size" => [
"bytes" => 980864346,
"human" => "935.43MB",
],
"hashes" => null,
"events" => [
"modified" => Carbon\Carbon @1531375218 {#2854
date: 2018-07-12 06:00:18.0 UTC (+00:00),
},
"changed" => Carbon\Carbon @1531375218 {#2855
date: 2018-07-12 06:00:18.0 UTC (+00:00),
},
"accessed" => Carbon\Carbon @1531375223 {#2849
date: 2018-07-12 06:00:23.0 UTC (+00:00),
},
],
],
}
>>>
``` bash
composer test
```
### Testing
Not yet implemented
### Changelog
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
......
......@@ -10,6 +10,24 @@ return [
* When you view the default file information, it calculates multiple hash values.
* This can be a bad thing if the file is too big. The default limit is 20 megabytes
*/
'maxhashsize' => 1024 * 1024 * 20,
'hash_max_size' => 1024 * 1024 * 20,
/**
* What hash algorithms to use by default. For a full list, run \Techendeavors\FileInfo::hashAlgorithms();
* If an algorithm listed here isn't actually available, it'll be skipped.
*/
'hash_algos' => [
'crc32',
'crc32b',
'md5',
'ripemd256',
'sha1',
'sha256',
'sha3-256',
'sha3-384',
'sha3-512',
'sha384',
'sha512',
],
];
......@@ -26,7 +26,7 @@ class FileInfo
/**
* Create a new instance.
*/
public function __construct(string $filename = '')
public function __construct(string $filename)
{
$this->filename = $filename;
}
......@@ -37,16 +37,16 @@ class FileInfo
* @param string $phrase Phrase to return
* @return string Returns the phrase passed in
*/
public function examine(string $filename)
public function all()
{
return collect([
"query" => $filename,
"tests" => self::getTestResults($filename),
"permissions" => self::getPermissions($filename),
"info" => self::getInfo($filename),
"size" => self::getSize($filename),
"hashes" => self::getHashes($filename),
"events" => self::getEvents($filename)
"query" => $this->filename,
"tests" => self::getTestResults(),
"permissions" => self::getPermissions(),
"info" => self::getInfo(),
"size" => self::getSize(),
"hashes" => self::getHashes(),
"events" => self::getEvents()
]);
}
}
......@@ -4,74 +4,74 @@ namespace Techendeavors\FileInfo\Traits;
trait Checks
{
public function isThere(string $filename)
public function isThere()
{
return (bool) (file_exists($filename));
return (bool) (file_exists($this->filename));
}
public function isNotThere(string $filename)
public function isNotThere()
{
return (bool) (! self::isThere($filename));
return (bool) (! self::isThere());
}
public function isReadable(string $filename)
public function isReadable()
{
return (bool) (is_readable($filename));
return (bool) (is_readable($this->filename));
}
public function isNotReadable(string $filename)
public function isNotReadable()
{
return (bool) (! self::isReadable($filename));
return (bool) (! self::isReadable());
}
public function isWritable(string $filename)
public function isWritable()
{
return (bool) (is_writable($filename));
return (bool) (is_writable($this->filename));
}
public function isNotWritable(string $filename)
public function isNotWritable()
{
return (bool) (! self::isWritable($filename));
return (bool) (! self::isWritable());
}
public function isDirectory(string $filename)
public function isDirectory()
{
return (bool) (is_dir($filename));
return (bool) (is_dir($this->filename));
}
public function isNotDirectory(string $filename)
public function isNotDirectory()
{
return (bool) (! self::isDirectory($filename));
return (bool) (! self::isDirectory());
}
public function isExecutable(string $filename)
public function isExecutable()
{
return (bool) (is_executable($filename));
return (bool) (is_executable($this->filename));
}
public function isNotExecutable(string $filename)
public function isNotExecutable()
{
return (bool) (! self::isExecutable($filename));
return (bool) (! self::isExecutable());
}
public function isFile(string $filename)
public function isFile()
{
return (bool) (is_file($filename));
return (bool) (is_file($this->filename));
}
public function isNotFile(string $filename)
public function isNotFile()
{
return (bool) (! self::isFile($filename));
return (bool) (! self::isFile());
}
public function isLink(string $filename)
public function isLink()
{
return (bool) (is_link($filename));
return (bool) (is_link($this->filename));
}
public function isNotLink(string $filename)
public function isNotLink()
{
return (bool) (! self::isLink($filename));
return (bool) (! self::isLink());
}
}
......@@ -4,27 +4,27 @@ namespace Techendeavors\FileInfo\Traits;
trait Events
{
public function GetModifiedTime(string $filename)
public function getModifiedTime()
{
return (object) self::DateTimeObject(filemtime($filename));
return (object) self::dateTimeObject(filemtime($this->filename));
}
public function GetChangedTime(string $filename)
public function getChangedTime()
{
return (object) self::DateTimeObject(filectime($filename));
return (object) self::dateTimeObject(filectime($this->filename));
}
public function GetAccessedTime(string $filename)
public function getAccessedTime()
{
return (object) self::DateTimeObject(fileatime($filename));
return (object) self::dateTimeObject(fileatime($this->filename));
}
public function GetSystemTimeZone()
public function getSystemTimeZone()
{
return (object) (new \DateTimeZone(trim(shell_exec("date +%:z"))));
}
public function DateTimeObject(int $timestamp)
public function dateTimeObject(int $timestamp)
{
$timezone = self::GetSystemTimeZone();
......@@ -35,14 +35,14 @@ trait Events
}
}
public function getEvents(string $filename)
public function getEvents()
{
if (self::isThere($filename)) {
return (object) collect([
"modified" => self::GetModifiedTime($filename),
"changed" => self::GetChangedTime($filename),
"accessed" => self::GetAccessedTime($filename),
]);
if (self::isThere()) {
return array(
"modified" => self::getModifiedTime(),
"changed" => self::getChangedTime(),
"accessed" => self::getAccessedTime(),
);
}
}
}
......@@ -4,29 +4,82 @@ namespace Techendeavors\FileInfo\Traits;
trait Hashes
{
private static function microtimeHuman($time)
{
if ($time == 0) {
return 0;
}
$unit=array(
-4 => 'ps',
-3 => 'ns',
-2 => 'mcs',
-1 => 'ms',
0 => 's');
$picker=min(0, floor(log($time, 1000)));
$computed = @round($time/pow(1000, $picker), 1);
return $computed." ".$unit[$picker];
}
public function hashAvailable(string $algorithm)
{
return (bool) (in_array(strtolower($algorithm), hash_algos()));
}
public function hashEngine(string $filename, string $algorithm)
public static function hashBenchmark($format = false, $sort = "time")
{
$benchmark = random_bytes(16);
$algos = collect();
foreach (hash_algos() as $algo) {
$time_start = microtime(true);
for( $i = 0; $i<100; $i++ ) {
$hash = hash($algo, $benchmark);
}
$time_end = microtime(true);
$time = $time_end - $time_start;
$length = strlen($hash);
$algos->push([
'algo' => $algo,
'time' => $time,
'human_time' => self::microtimeHuman($time),
'length' => $length]);
}
$sorted = $algos->sortBy($sort);
if ($format) {
$output = sprintf("%-16s %-22s %-12s %-8s", "Algorithm", "Exact Time", "Easy Time", "Length") . PHP_EOL;
$output .= sprintf("%-16s+-%-22s+-%-12s+-%-8s", "----------------", "----------------------", "------------", "--------") . PHP_EOL;
foreach ($sorted as $line) {
$output .= vsprintf("%-16s| %-22s| %-12s| %-8s", $line) . PHP_EOL;
}
return (string) $output;
}
return (object) $algos;
}
public function hashEngine(string $algorithm)
{
if (self::hashAvailable($algorithm)) {
return (string) hash_file($algorithm, $filename);
return (string) hash_file($algorithm, $this->filename);
}
}
public function getHashes(string $filename)
public function getHashes()
{
if ((self::isFile($filename)) && (self::isReadable($filename)) && (self::getFileBytes($filename) <= config('fileinfo.maxhashsize'))) {
return (object) collect([
"md5" => self::hashEngine($filename, 'md5'),
"sha1" => self::hashEngine($filename, 'sha1'),
"sha256" => self::hashEngine($filename, 'sha256'),
"sha384" => self::hashEngine($filename, 'sha384'),
"sha512" => self::hashEngine($filename, 'sha512'),
"ripemd160" => self::hashEngine($filename, 'ripemd160'),
]);
if ((self::isFile($this->filename)) && (self::isReadable($this->filename)) && (self::getFileBytes($this->filename) <= config('fileinfo.hash_max_size'))) {
$hashes = collect();
foreach (config('fileinfo.hash_algos') as $algo) {
$hashes->put($algo, self::hashEngine($algo));
}
return (array) $hashes->toArray();
}
}
}
......@@ -5,40 +5,40 @@ namespace Techendeavors\FileInfo\Traits;
trait Info
{
public function getRealPath(string $filename)
public function getRealPath()
{
return (string) (realpath($filename));
return (string) (realpath($this->filename));
}
public function getFileName(string $filename)
public function getFileName()
{
return (string) (basename($filename));
return (string) (basename($this->filename));
}
public function getFilePath(string $filename)
public function getFilePath()
{
return (string) (dirname($filename));
return (string) (dirname($this->filename));
}
public function getType(string $filename)
public function getType()
{
return (string) (filetype($filename));
return (string) (filetype($this->filename));
}
public function getMime(string $filename)
public function getMime()
{
return (string) (mime_content_type($filename));
return (string) (mime_content_type($this->filename));
}
public function getInfo(string $filename)
public function getInfo()
{
if (self::isThere($filename)) {
return (object) collect([
"name" => self::getFileName($filename),
"path" => self::getFilePath($filename),
"type" => self::getType($filename),
"mime" => self::getMime($filename),
]);
if (self::isThere($this->filename)) {
return array(
"name" => self::getFileName(),
"path" => self::getFilePath(),
"type" => self::getType(),
"mime" => self::getMime(),
);
}
}
}
......@@ -4,14 +4,14 @@ namespace Techendeavors\FileInfo\Traits;
trait Permissions
{
public function getOctalPermissions(string $filename)
public function getOctalPermissions()
{
return (string) substr(decoct(fileperms($filename)), 2);
return (string) substr(decoct(fileperms($this->filename)), 2);
}
public function getHumanPermissions(string $filename)
public function getHumanPermissions()
{
$perms = fileperms($filename);
$perms = fileperms($this->filename);
$info = "";
......@@ -33,27 +33,27 @@ trait Permissions
return (string) $info;
}
public function getUserName(string $filename)
public function getUserName()
{
return (string) (posix_getpwuid(fileowner($filename))["name"]);
return (string) (posix_getpwuid(fileowner($this->filename))["name"]);
}
public function getGroupName(string $filename)
public function getGroupName()
{
return (string) (posix_getgrgid(filegroup($filename))["name"]);
return (string) (posix_getgrgid(filegroup($this->filename))["name"]);
}
public function getPermissions($filename)
public function getPermissions()
{
if (self::isThere($filename)) {
return (object) collect([
"readable" => self::isReadable($filename),
"writable" => self::isWritable($filename),
"user" => self::getUserName($filename),
"group" => self::getGroupName($filename),
"octal" => self::getOctalPermissions($filename),
"human" => self::getHumanPermissions($filename),
]);
if (self::isThere()) {
return array(
"readable" => self::isReadable(),
"writable" => self::isWritable(),
"user" => self::getUserName(),
"group" => self::getGroupName(),
"octal" => self::getOctalPermissions(),
"human" => self::getHumanPermissions(),
);
}
}
......
......@@ -4,9 +4,14 @@ namespace Techendeavors\FileInfo\Traits;
trait Size
{
public function getFileBytes(string $filename)
public function getFileBytes()
{
return (int) filesize($filename);
return (int) filesize($this->filename);
}
public function getDirectoryBytes()
{
return (int) array_filter(explode("\t", trim(shell_exec('du -sb0 ' . escapeshellcmd($this->filename) . ' 2>/dev/null'))))[0];
}
public function getHumanSize(int $bytes, int $decimals = 2)
......@@ -20,14 +25,22 @@ trait Size
return (string) sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$unit[$factor - 1] . 'B';
}
public function getSize(string $filename)
public function getSize()
{
if (self::isFile($filename) && self::isThere($filename)) {
$bytes = self::getFileBytes($filename);
return (object) collect([
if (self::isThere()) {
if (self::isFile()) {
$bytes = self::getFileBytes();
}
if (self::isDirectory()) {
$bytes = self::getDirectoryBytes();
}
return array(
"bytes" => $bytes,
"human" => self::getHumanSize($bytes),
]);
);
}
}
}
......@@ -4,15 +4,15 @@ namespace Techendeavors\FileInfo\Traits;
trait TestResults
{
public function getTestResults(string $filename)
public function getTestResults()
{
if (self::isThere($filename)) {
return (object) collect([
"directory" => self::isDirectory($filename),
"executable" => self::isExecutable($filename),
"file" => self::isFile($filename),
"link" => self::isLink($filename),
]);
if (self::isThere()) {
return array(
"directory" => self::isDirectory(),
"executable" => self::isExecutable(),
"file" => self::isFile(),
"link" => self::isLink(),
);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment