205 lines
6.4 KiB
PHP
205 lines
6.4 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Простой слой загрузки файлов на сервер
|
|
* Версия 2018-01-14
|
|
* (c) Виталий Филиппов 2018
|
|
*/
|
|
|
|
class FileHandler
|
|
{
|
|
public static $thumbPath = 'thumb/';
|
|
|
|
public static function base($web_or_fs = true)
|
|
{
|
|
static $p, $l;
|
|
if (!$p)
|
|
{
|
|
$p = App::$config['files_path'];
|
|
if ($p{0} != '/')
|
|
{
|
|
$p = '/'.$p;
|
|
}
|
|
$l = App::$config['local_path'];
|
|
if ($l{strlen($l)-1} == '/')
|
|
{
|
|
$l = substr($l, 0, -1);
|
|
}
|
|
if ($p{strlen($p)-1} != '/')
|
|
{
|
|
$p .= '/';
|
|
}
|
|
}
|
|
return $web_or_fs ? App::domain().$p : $l.$p;
|
|
}
|
|
|
|
public static function getPath($web_or_fs, $file)
|
|
{
|
|
$s = $file['sha1'];
|
|
return FileHandler::base($web_or_fs) . '/' . substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $file['format'];
|
|
}
|
|
|
|
public static function getThumbPath($web_or_fs, $file, $type)
|
|
{
|
|
$s = $file['sha1'];
|
|
$ext = $file['format'] == 'jpg' || $file['format'] == 'png' || $file['format'] == 'gif'
|
|
? $file['format'] : 'jpg';
|
|
return FileHandler::base($web_or_fs) . self::$thumbPath . '/' . $type . '/' .substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $ext;
|
|
}
|
|
|
|
public static function getGPS($file)
|
|
{
|
|
$props = $file['props'];
|
|
if (empty($props['GPSLatitude']) && empty($props['GPSLongitude']))
|
|
{
|
|
return NULL;
|
|
}
|
|
$latitude = FileUtils::exifGPS($props['GPSLatitude'], $props['GPSLatitudeRef']);
|
|
$longitude = FileUtils::exifGPS($props['GPSLongitude'], $props['GPSLongitudeRef']);
|
|
return [ $latitude, $longitude ];
|
|
}
|
|
|
|
public static function upload(LocalFile $localFile, $allowedFormats = File::ANYTHING)
|
|
{
|
|
$tmp_name = $localFile->getLocalPath();
|
|
$props = FileUtils::getProps($allowedFormats, $tmp_name, $localFile->getFileName());
|
|
$row = [
|
|
'id' => NULL,
|
|
'added' => time(),
|
|
'user_id' => App::$user['id'] ?: NULL,
|
|
] + $props + [ 'props' => [] ];
|
|
$exist = App::$db->select(File::$table, '*', [ 'sha1' => $row['sha1'] ], NULL, MS_ROW);
|
|
if ($exist)
|
|
{
|
|
$exist['props'] = json_decode($exist['props'], true);
|
|
return $exist;
|
|
}
|
|
$row['id'] = App::$db->insert_row(File::$table, [
|
|
'props' => json_encode($row['props'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),
|
|
] + $row);
|
|
$fn = FileHandler::getPath(false, $row);
|
|
FileUtils::mkpath(dirname($fn), true);
|
|
$m = $localFile->shouldMove ? 'rename' : 'copy';
|
|
if (!@$m($tmp_name, $fn))
|
|
{
|
|
$error = error_get_last();
|
|
throw new Exception($error['message']);
|
|
}
|
|
chmod($fn, 0666 & ~umask());
|
|
return $row;
|
|
}
|
|
|
|
static $uploadCurl;
|
|
|
|
public static function uploadUrl($url, $flags = File::ONLY_IMAGES, $curl_options = [])
|
|
{
|
|
if (!$url)
|
|
{
|
|
return NULL;
|
|
}
|
|
$file = NULL;
|
|
if (substr($url, 0, 2) == '//')
|
|
{
|
|
$url = "http:$url";
|
|
}
|
|
if (!self::$uploadCurl)
|
|
{
|
|
// Reuse handle to use keepalive when possible
|
|
self::$uploadCurl = curl_init();
|
|
}
|
|
curl_setopt_array(self::$uploadCurl, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
] + $curl_options);
|
|
$s = curl_exec(self::$uploadCurl);
|
|
if ($s)
|
|
{
|
|
$tmp = tempnam(sys_get_temp_dir(), 'upl');
|
|
file_put_contents($tmp, $s);
|
|
unset($s);
|
|
$file = File::upload(new LocalFile($tmp, true), $flags);
|
|
@unlink($tmp);
|
|
}
|
|
else
|
|
{
|
|
// Log it as E_USER_NOTICE
|
|
trigger_error(curl_error(self::$uploadCurl));
|
|
}
|
|
return $file;
|
|
}
|
|
|
|
public static function deleteFiles($where)
|
|
{
|
|
$files = App::$db->select(File::$table, '*', $where);
|
|
foreach ($existing as $e)
|
|
{
|
|
$disk_name = FileHandler::getPath(false, $e);
|
|
if (file_exists($disk_name))
|
|
{
|
|
// Remove old file
|
|
// FIXME unlink thumbnails
|
|
unlink($disk_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get or generate a thumbnail and return its URL
|
|
*/
|
|
public static function getThumb($file, $width, $height, $force = false, $crop = false, $alignY = 0.5)
|
|
{
|
|
$size = FileUtils::getThumbSize($file, $width, $height, $crop);
|
|
if (!$size)
|
|
{
|
|
return FileHandler::getPath(true, $file);
|
|
}
|
|
list($width, $height) = $size;
|
|
if (!$crop)
|
|
{
|
|
$type = intval($width);
|
|
}
|
|
else
|
|
{
|
|
$p = $crop == File::CROP_Y ? 'cy' : ($crop == File::CROP_X ? 'cx' : 'c');
|
|
$type = intval($width).'x'.intval($height).'_'.$alignY;
|
|
}
|
|
$fn = FileHandler::getThumbPath(false, $file, $type);
|
|
if (!file_exists($fn) || $force)
|
|
{
|
|
if (substr($file['mimetype'], 0, 6) === 'video/')
|
|
{
|
|
$sourcefn = FileHandler::getThumbPath(false, $file, 'src');
|
|
}
|
|
else
|
|
{
|
|
$sourcefn = FileHandler::getPath(false, $file);
|
|
}
|
|
try
|
|
{
|
|
$im = FileUtils::magick();
|
|
$im->readImage($sourcefn);
|
|
$props = $file['props'];
|
|
if (!empty($props['Orientation']) && $props['Orientation'] > 5)
|
|
{
|
|
/* swap width & height */
|
|
$t = $width;
|
|
$width = $height;
|
|
$height = $t;
|
|
if ($crop == File::CROP_X || $crop == File::CROP_Y)
|
|
$crop = 5-$crop;
|
|
}
|
|
FileUtils::makeThumb($im, $width, $height, $crop, isset($props['Orientation']) ? $props['Orientation'] : NULL, $alignY);
|
|
$im->setCompressionQuality(FileUtils::$quality);
|
|
FileUtils::mkpath(dirname($fn));
|
|
$im->writeImage($fn);
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
trigger_error("$e");
|
|
return false;
|
|
}
|
|
}
|
|
return FileHandler::getThumbPath(true, $file, $type);
|
|
}
|
|
}
|