Remove static's
parent
2812bab85d
commit
cbcfe42667
110
FileHandler.php
110
FileHandler.php
|
@ -2,52 +2,65 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Простой слой загрузки файлов на сервер
|
* Простой слой загрузки файлов на сервер
|
||||||
* Версия 2018-01-14
|
* Версия 2018-09-10
|
||||||
* (c) Виталий Филиппов 2018
|
* (c) Виталий Филиппов 2018
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class FileHandler
|
class FileHandler
|
||||||
{
|
{
|
||||||
public static $thumbPath = 'thumb/';
|
const ONLY_BINARY = 1;
|
||||||
|
const ONLY_IMAGES = 2;
|
||||||
|
const ONLY_SWF = 4;
|
||||||
|
const ONLY_VIDEO = 8;
|
||||||
|
const IMAGES_VIDEO = 10;
|
||||||
|
const ANY_MEDIA = 14;
|
||||||
|
const ANYTHING = 15;
|
||||||
|
|
||||||
public static function base($web_or_fs = true)
|
const CROP_XY = 1;
|
||||||
|
const CROP_Y = 2;
|
||||||
|
const CROP_X = 3;
|
||||||
|
|
||||||
|
public static $uploadCurl;
|
||||||
|
|
||||||
|
public function __construct($db, $config)
|
||||||
{
|
{
|
||||||
static $p, $l;
|
$this->db = $db;
|
||||||
if (!$p)
|
$this->config = $config + [
|
||||||
{
|
'basedir' => '',
|
||||||
$p = App::$config['files_path'];
|
'baseurl' => '',
|
||||||
if ($p{0} != '/')
|
'table' => 'files',
|
||||||
{
|
'get_user_id' => NULL,
|
||||||
$p = '/'.$p;
|
'mime_blacklist' => '#'.
|
||||||
}
|
// HTML may contain cookie-stealing JavaScript and web bugs
|
||||||
$l = App::$config['local_path'];
|
'^text/(html|(x-)?javascript)$|^application/x-shellscript$'.
|
||||||
if ($l{strlen($l)-1} == '/')
|
// PHP/Perl/Bash/etc scripts may execute arbitrary code on the server
|
||||||
{
|
'|php|perl|python|bash|x-c?sh(e|$)'.
|
||||||
$l = substr($l, 0, -1);
|
// Client-side hazards on Internet Explorer
|
||||||
}
|
'|^text/scriptlet$|^application/x-msdownload$'.
|
||||||
if ($p{strlen($p)-1} != '/')
|
// Windows metafile, client-side vulnerability on some systems
|
||||||
{
|
'|^application/x-msmetafile$'.
|
||||||
$p .= '/';
|
'#is',
|
||||||
}
|
'thumb_path' => 'thumb/',
|
||||||
}
|
];
|
||||||
return $web_or_fs ? App::domain().$p : $l.$p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getPath($web_or_fs, $file)
|
public function getPath($web_or_fs, $file)
|
||||||
{
|
{
|
||||||
$s = $file['sha1'];
|
$s = $file['sha1'];
|
||||||
return FileHandler::base($web_or_fs) . '/' . substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $file['format'];
|
return $this->config[$web_or_fs ? 'baseurl' : 'basedir'] . '/' .
|
||||||
|
substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $file['format'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getThumbPath($web_or_fs, $file, $type)
|
public function getThumbPath($web_or_fs, $file, $type)
|
||||||
{
|
{
|
||||||
$s = $file['sha1'];
|
$s = $file['sha1'];
|
||||||
$ext = $file['format'] == 'jpg' || $file['format'] == 'png' || $file['format'] == 'gif'
|
$ext = $file['format'] == 'jpg' || $file['format'] == 'png' || $file['format'] == 'gif'
|
||||||
? $file['format'] : 'jpg';
|
? $file['format'] : 'jpg';
|
||||||
return FileHandler::base($web_or_fs) . self::$thumbPath . '/' . $type . '/' .substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $ext;
|
return $this->config[$web_or_fs ? 'baseurl' : 'basedir'] . '/' .
|
||||||
|
$this->config['thumb_path'] . '/' . $type . '/' .substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getGPS($file)
|
public function getGPS($file)
|
||||||
{
|
{
|
||||||
$props = $file['props'];
|
$props = $file['props'];
|
||||||
if (empty($props['GPSLatitude']) && empty($props['GPSLongitude']))
|
if (empty($props['GPSLatitude']) && empty($props['GPSLongitude']))
|
||||||
|
@ -59,25 +72,28 @@ class FileHandler
|
||||||
return [ $latitude, $longitude ];
|
return [ $latitude, $longitude ];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function upload(LocalFile $localFile, $allowedFormats = File::ANYTHING)
|
public function upload(LocalFile $localFile, $allowedFormats = FileHandler::ANYTHING)
|
||||||
{
|
{
|
||||||
$tmp_name = $localFile->getLocalPath();
|
$tmp_name = $localFile->getLocalPath();
|
||||||
$props = FileUtils::getProps($allowedFormats, $tmp_name, $localFile->getFileName());
|
$props = FileUtils::getProps($allowedFormats, $this->config['mime_blacklist'], $tmp_name, $localFile->getFileName());
|
||||||
$row = [
|
$row = [
|
||||||
'id' => NULL,
|
'id' => NULL,
|
||||||
'added' => time(),
|
'added' => time(),
|
||||||
'user_id' => App::$user['id'] ?: NULL,
|
|
||||||
] + $props + [ 'props' => [] ];
|
] + $props + [ 'props' => [] ];
|
||||||
$exist = App::$db->select(File::$table, '*', [ 'sha1' => $row['sha1'] ], NULL, MS_ROW);
|
if ($this->config['get_user_id'])
|
||||||
|
{
|
||||||
|
$row['user_id'] = $this->config['get_user_id']() ?: NULL;
|
||||||
|
}
|
||||||
|
$exist = $this->db->select($this->config['table'], '*', [ 'sha1' => $row['sha1'] ], NULL, MS_ROW);
|
||||||
if ($exist)
|
if ($exist)
|
||||||
{
|
{
|
||||||
$exist['props'] = json_decode($exist['props'], true);
|
$exist['props'] = json_decode($exist['props'], true);
|
||||||
return $exist;
|
return $exist;
|
||||||
}
|
}
|
||||||
$row['id'] = App::$db->insert_row(File::$table, [
|
$row['id'] = $this->db->insert_row($this->config['table'], [
|
||||||
'props' => json_encode($row['props'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),
|
'props' => json_encode($row['props'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),
|
||||||
] + $row);
|
] + $row);
|
||||||
$fn = FileHandler::getPath(false, $row);
|
$fn = $this->getPath(false, $row);
|
||||||
FileUtils::mkpath(dirname($fn), true);
|
FileUtils::mkpath(dirname($fn), true);
|
||||||
$m = $localFile->shouldMove ? 'rename' : 'copy';
|
$m = $localFile->shouldMove ? 'rename' : 'copy';
|
||||||
if (!@$m($tmp_name, $fn))
|
if (!@$m($tmp_name, $fn))
|
||||||
|
@ -89,9 +105,7 @@ class FileHandler
|
||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
static $uploadCurl;
|
public function uploadUrl($url, $flags = FileHandler::ONLY_IMAGES, $curl_options = [])
|
||||||
|
|
||||||
public static function uploadUrl($url, $flags = File::ONLY_IMAGES, $curl_options = [])
|
|
||||||
{
|
{
|
||||||
if (!$url)
|
if (!$url)
|
||||||
{
|
{
|
||||||
|
@ -117,7 +131,7 @@ class FileHandler
|
||||||
$tmp = tempnam(sys_get_temp_dir(), 'upl');
|
$tmp = tempnam(sys_get_temp_dir(), 'upl');
|
||||||
file_put_contents($tmp, $s);
|
file_put_contents($tmp, $s);
|
||||||
unset($s);
|
unset($s);
|
||||||
$file = File::upload(new LocalFile($tmp, true), $flags);
|
$file = $this->upload(new LocalFile($tmp, true), $flags);
|
||||||
@unlink($tmp);
|
@unlink($tmp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -128,12 +142,12 @@ class FileHandler
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function deleteFiles($where)
|
public function deleteFiles($where)
|
||||||
{
|
{
|
||||||
$files = App::$db->select(File::$table, '*', $where);
|
$files = $this->db->select($this->config['table'], '*', $where);
|
||||||
foreach ($existing as $e)
|
foreach ($existing as $e)
|
||||||
{
|
{
|
||||||
$disk_name = FileHandler::getPath(false, $e);
|
$disk_name = $this->getPath(false, $e);
|
||||||
if (file_exists($disk_name))
|
if (file_exists($disk_name))
|
||||||
{
|
{
|
||||||
// Remove old file
|
// Remove old file
|
||||||
|
@ -146,12 +160,12 @@ class FileHandler
|
||||||
/**
|
/**
|
||||||
* Get or generate a thumbnail and return its URL
|
* Get or generate a thumbnail and return its URL
|
||||||
*/
|
*/
|
||||||
public static function getThumb($file, $width, $height, $force = false, $crop = false, $alignY = 0.5)
|
public function getThumb($file, $width, $height, $force = false, $crop = false, $alignY = 0.5)
|
||||||
{
|
{
|
||||||
$size = FileUtils::getThumbSize($file, $width, $height, $crop);
|
$size = FileUtils::getThumbSize($file, $width, $height, $crop);
|
||||||
if (!$size)
|
if (!$size)
|
||||||
{
|
{
|
||||||
return FileHandler::getPath(true, $file);
|
return $this->getPath(true, $file);
|
||||||
}
|
}
|
||||||
list($width, $height) = $size;
|
list($width, $height) = $size;
|
||||||
if (!$crop)
|
if (!$crop)
|
||||||
|
@ -160,19 +174,19 @@ class FileHandler
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$p = $crop == File::CROP_Y ? 'cy' : ($crop == File::CROP_X ? 'cx' : 'c');
|
$p = $crop == FileHandler::CROP_Y ? 'cy' : ($crop == FileHandler::CROP_X ? 'cx' : 'c');
|
||||||
$type = intval($width).'x'.intval($height).'_'.$alignY;
|
$type = intval($width).'x'.intval($height).'_'.$alignY;
|
||||||
}
|
}
|
||||||
$fn = FileHandler::getThumbPath(false, $file, $type);
|
$fn = $this->getThumbPath(false, $file, $type);
|
||||||
if (!file_exists($fn) || $force)
|
if (!file_exists($fn) || $force)
|
||||||
{
|
{
|
||||||
if (substr($file['mimetype'], 0, 6) === 'video/')
|
if (substr($file['mimetype'], 0, 6) === 'video/')
|
||||||
{
|
{
|
||||||
$sourcefn = FileHandler::getThumbPath(false, $file, 'src');
|
$sourcefn = $this->getThumbPath(false, $file, 'src');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$sourcefn = FileHandler::getPath(false, $file);
|
$sourcefn = $this->getPath(false, $file);
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -185,7 +199,7 @@ class FileHandler
|
||||||
$t = $width;
|
$t = $width;
|
||||||
$width = $height;
|
$width = $height;
|
||||||
$height = $t;
|
$height = $t;
|
||||||
if ($crop == File::CROP_X || $crop == File::CROP_Y)
|
if ($crop == FileHandler::CROP_X || $crop == FileHandler::CROP_Y)
|
||||||
$crop = 5-$crop;
|
$crop = 5-$crop;
|
||||||
}
|
}
|
||||||
FileUtils::makeThumb($im, $width, $height, $crop, isset($props['Orientation']) ? $props['Orientation'] : NULL, $alignY);
|
FileUtils::makeThumb($im, $width, $height, $crop, isset($props['Orientation']) ? $props['Orientation'] : NULL, $alignY);
|
||||||
|
@ -199,6 +213,6 @@ class FileHandler
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FileHandler::getThumbPath(true, $file, $type);
|
return $this->getThumbPath(true, $file, $type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Простой слой загрузки файлов на сервер
|
||||||
|
* Версия 2018-09-10
|
||||||
|
* (c) Виталий Филиппов 2018
|
||||||
|
*/
|
||||||
|
|
||||||
class FileUtils
|
class FileUtils
|
||||||
{
|
{
|
||||||
public static $quality = 90;
|
public static $quality = 90;
|
||||||
|
@ -56,7 +62,7 @@ class FileUtils
|
||||||
/**
|
/**
|
||||||
* Get image or file properties (content SHA1, width, height, selected EXIF properties)
|
* Get image or file properties (content SHA1, width, height, selected EXIF properties)
|
||||||
*/
|
*/
|
||||||
public static function getProps($allowed_types, $fs_path, $orig_name)
|
public static function getProps($allowed_types, $mime_blacklist, $fs_path, $orig_name)
|
||||||
{
|
{
|
||||||
if (!file_exists($fs_path))
|
if (!file_exists($fs_path))
|
||||||
{
|
{
|
||||||
|
@ -67,7 +73,7 @@ class FileUtils
|
||||||
{
|
{
|
||||||
throw new UserException('file-mime-type-unknown');
|
throw new UserException('file-mime-type-unknown');
|
||||||
}
|
}
|
||||||
elseif (preg_match(App::$config['mime_blacklist'], $mime))
|
elseif (preg_match($mime_blacklist, $mime))
|
||||||
{
|
{
|
||||||
// Prevent uploads with dangerous MIME types
|
// Prevent uploads with dangerous MIME types
|
||||||
throw new UserException('file-mime-type-blacklisted');
|
throw new UserException('file-mime-type-blacklisted');
|
||||||
|
@ -80,25 +86,25 @@ class FileUtils
|
||||||
'width' => 0,
|
'width' => 0,
|
||||||
'height' => 0,
|
'height' => 0,
|
||||||
];
|
];
|
||||||
$flag = File::ONLY_BINARY;
|
$flag = FileHandler::ONLY_BINARY;
|
||||||
$props = NULL;
|
$props = NULL;
|
||||||
if ($mime == 'application/x-shockwave-flash')
|
if ($mime == 'application/x-shockwave-flash')
|
||||||
{
|
{
|
||||||
$props = self::getSWFProps($fs_path);
|
$props = self::getSWFProps($fs_path);
|
||||||
if ($props)
|
if ($props)
|
||||||
$flag = File::ONLY_SWF;
|
$flag = FileHandler::ONLY_SWF;
|
||||||
}
|
}
|
||||||
elseif (substr($mime, 0, 6) == 'image/')
|
elseif (substr($mime, 0, 6) == 'image/')
|
||||||
{
|
{
|
||||||
$props = self::getImageProps($fs_path);
|
$props = self::getImageProps($fs_path);
|
||||||
if ($props)
|
if ($props)
|
||||||
$flag = File::ONLY_IMAGES;
|
$flag = FileHandler::ONLY_IMAGES;
|
||||||
}
|
}
|
||||||
elseif (substr($mime, 0, 6) == 'video/')
|
elseif (substr($mime, 0, 6) == 'video/')
|
||||||
{
|
{
|
||||||
$props = VideoUtils::getVideoProps($fs_path);
|
$props = VideoUtils::getVideoProps($fs_path);
|
||||||
if ($props)
|
if ($props)
|
||||||
$flag = File::ONLY_VIDEO;
|
$flag = FileHandler::ONLY_VIDEO;
|
||||||
}
|
}
|
||||||
if (!($allowed_types & $flag))
|
if (!($allowed_types & $flag))
|
||||||
{
|
{
|
||||||
|
@ -391,11 +397,11 @@ class FileUtils
|
||||||
{
|
{
|
||||||
$iw = $im->getImageWidth();
|
$iw = $im->getImageWidth();
|
||||||
$ih = $im->getImageHeight();
|
$ih = $im->getImageHeight();
|
||||||
if ($crop == File::CROP_Y && $ih*$width/$iw < $height)
|
if ($crop == FileHandler::CROP_Y && $ih*$width/$iw < $height)
|
||||||
{
|
{
|
||||||
$height = $ih*$width/$iw;
|
$height = $ih*$width/$iw;
|
||||||
}
|
}
|
||||||
elseif ($crop == File::CROP_X && $iw*$height/$ih < $width)
|
elseif ($crop == FileHandler::CROP_X && $iw*$height/$ih < $width)
|
||||||
{
|
{
|
||||||
$width = $iw*$height/$ih;
|
$width = $iw*$height/$ih;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ class VideoUtils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Сконвертированный файл
|
// Сконвертированный файл
|
||||||
$update = FileUtils::getProps(File::ONLY_VIDEO, $out, $out);
|
$update = FileUtils::getProps(File::ONLY_VIDEO, $this->config['mime_blacklist'], $out, $out);
|
||||||
$update['format'] = 'mp4';
|
$update['format'] = 'mp4';
|
||||||
$newfn = FileHandler::getPath(false, $update + $file);
|
$newfn = FileHandler::getPath(false, $update + $file);
|
||||||
FileUtils::mkpath(dirname($newfn), true);
|
FileUtils::mkpath(dirname($newfn), true);
|
||||||
|
|
Loading…
Reference in New Issue