213 lines
6.1 KiB
PHP
213 lines
6.1 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Hura8\System;
|
||
|
|
|
||
|
|
class FileSystem
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* The cache directory.
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
*/
|
||
|
|
protected $directory;
|
||
|
|
|
||
|
|
/** @var int */
|
||
|
|
private $umask;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param string $directory The cache directory.
|
||
|
|
* @param int $umask
|
||
|
|
*
|
||
|
|
* @throws \Exception
|
||
|
|
*/
|
||
|
|
public function __construct($directory, $umask = 0002)
|
||
|
|
{
|
||
|
|
// YES, this needs to be *before* createPathIfNeeded()
|
||
|
|
if (! is_int($umask)) {
|
||
|
|
throw new \Exception(sprintf(
|
||
|
|
'The umask parameter is required to be integer, was: %s',
|
||
|
|
gettype($umask)
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->umask = $umask;
|
||
|
|
|
||
|
|
if (! $this->createPathIfNeeded($directory)) {
|
||
|
|
throw new \Exception(sprintf(
|
||
|
|
'The directory "%s" does not exist and could not be created.',
|
||
|
|
$directory
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! is_writable($directory)) {
|
||
|
|
throw new \Exception(sprintf(
|
||
|
|
'The directory "%s" is not writable.',
|
||
|
|
$directory
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
// YES, this needs to be *after* createPathIfNeeded()
|
||
|
|
$this->directory = realpath($directory);
|
||
|
|
|
||
|
|
//$this->directoryStringLength = strlen($this->directory);
|
||
|
|
//$this->isRunningOnWindows = defined('PHP_WINDOWS_VERSION_BUILD');
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description extract a zip file after it has been uploaded to the server
|
||
|
|
* @param string $filename name of the zip file (abc.zip)
|
||
|
|
* @param string $uploaded_zip_path path where it's uploaded to i.e /usr/.../tmp_upload/
|
||
|
|
* @param string $extract_target_path path where the zip files will be extracted to , if not provided the $uploaded_zip_path will be used
|
||
|
|
* @return array [extracted_folder, test_folder_exist]
|
||
|
|
*/
|
||
|
|
public static function unzip(string $filename, string $uploaded_zip_path, string $extract_target_path = '') {
|
||
|
|
$extract_path = $extract_target_path ?: $uploaded_zip_path;
|
||
|
|
|
||
|
|
$zip = new \ZipArchive();
|
||
|
|
$x = $zip->open($uploaded_zip_path . DIRECTORY_SEPARATOR . $filename);
|
||
|
|
if ($x === true) {
|
||
|
|
$zip->extractTo($extract_path); // change this to the correct site path
|
||
|
|
$zip->close();
|
||
|
|
}
|
||
|
|
@unlink($uploaded_zip_path . DIRECTORY_SEPARATOR . $filename);
|
||
|
|
|
||
|
|
$expected_result = $extract_path . DIRECTORY_SEPARATOR . str_replace(".zip", "", $filename);
|
||
|
|
|
||
|
|
return array($expected_result, file_exists($expected_result));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description scan a folder recursively and return all files with sub-path
|
||
|
|
* @param string $folder full path /usr/local/.../
|
||
|
|
* @param array $file_list
|
||
|
|
*/
|
||
|
|
public static function scanDirRecursive(string $folder, array &$file_list = []) {
|
||
|
|
$dir = opendir($folder);
|
||
|
|
while(( $file = readdir($dir)) ) {
|
||
|
|
if (( $file != '.' ) && ( $file != '..' )) {
|
||
|
|
if ( is_dir($folder. '/' . $file) ) {
|
||
|
|
FileSystem::scanDirRecursive($folder. '/' . $file, $file_list);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
//$file_list[] = str_replace(PUBLIC_DIR . "/", "", $folder .'/'. $file);
|
||
|
|
$file_list[] = $folder .'/'. $file;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
closedir($dir);
|
||
|
|
}
|
||
|
|
|
||
|
|
//remove directory recursively
|
||
|
|
public static function removeDir($dir) {
|
||
|
|
if (is_dir($dir)) {
|
||
|
|
$objects = scandir($dir);
|
||
|
|
foreach ($objects as $object) {
|
||
|
|
if ($object != "." && $object != "..") {
|
||
|
|
if (is_dir($dir."/".$object)) {
|
||
|
|
self::removeDir($dir."/".$object);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
@unlink($dir."/".$object);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
@rmdir($dir);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getFile(string $filename)
|
||
|
|
{
|
||
|
|
$full_filepath = $this->getFilename($filename);
|
||
|
|
if(file_exists($full_filepath)) {
|
||
|
|
return file_get_contents($full_filepath);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getFileLastModifiedTime(string $filename)
|
||
|
|
{
|
||
|
|
$full_filepath = $this->getFilename($filename);
|
||
|
|
if(file_exists($full_filepath)) {
|
||
|
|
return filemtime($full_filepath);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Writes a string content to file in an atomic way.
|
||
|
|
*
|
||
|
|
* @param string $filename Path to the file where to write the data.
|
||
|
|
* @param string $content The content to write
|
||
|
|
*
|
||
|
|
* @return bool TRUE on success, FALSE if path cannot be created, if path is not writable or an any other error.
|
||
|
|
*/
|
||
|
|
public function writeFile(string $filename, string $content)
|
||
|
|
{
|
||
|
|
$full_filepath = $this->getFilename($filename);
|
||
|
|
$filepath = pathinfo($full_filepath, PATHINFO_DIRNAME);
|
||
|
|
|
||
|
|
if (! $this->createPathIfNeeded($filepath)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! is_writable($filepath)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
$tmpFile = tempnam($filepath, 'swap');
|
||
|
|
@chmod($tmpFile, 0666 & (~$this->umask));
|
||
|
|
|
||
|
|
if (file_put_contents($tmpFile, $content) !== false) {
|
||
|
|
|
||
|
|
@chmod($tmpFile, 0666 & (~$this->umask));
|
||
|
|
if (@rename($tmpFile, $full_filepath)) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
@unlink($tmpFile);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function delete($filename)
|
||
|
|
{
|
||
|
|
$full_filepath = $this->getFilename($filename);
|
||
|
|
|
||
|
|
return @unlink($full_filepath) || ! file_exists($full_filepath);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param string $filename
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function getFilename($filename)
|
||
|
|
{
|
||
|
|
return $this->directory
|
||
|
|
. DIRECTORY_SEPARATOR
|
||
|
|
. $filename ;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create path if needed.
|
||
|
|
*
|
||
|
|
* @return bool TRUE on success or if path already exists, FALSE if path cannot be created.
|
||
|
|
*/
|
||
|
|
private function createPathIfNeeded(string $path)
|
||
|
|
{
|
||
|
|
if (! is_dir($path)) {
|
||
|
|
if (@mkdir($path, 0755 & (~$this->umask), true) === false && ! is_dir($path)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|