diff --git a/File.php b/File.php index df95a3c..0443b73 100644 --- a/File.php +++ b/File.php @@ -1,9 +1,9 @@ select($this->table, '*', [ 'sha1' => $row['sha1'] ], NULL, MS_ROW); + if ($exist) + { + $exist['props'] = json_decode($exist['props'], true); + return $exist; + } + $row['id'] = App::$db->insert_row($this->table, [ + 'props' => json_encode($row['props'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), + 'added' => time(), + ] + $row); + return $row; + } + public static function upload(LocalFile $localFile, $allowedFormats = File::ANYTHING) { - return FileHandler::upload($localFile, $allowedFormats); + return self::doUpload(FileHandler::upload($localFile, $allowedFormats)); } public static function uploadUrl($url, $allowedFormats = File::ONLY_IMAGES, $curl_options = []) { - return FileHandler::uploadUrl($url, $allowedFormats, $curl_options); + return self::doUpload(FileHandler::uploadUrl($url, $allowedFormats, $curl_options)); } public static function deleteFiles($where) diff --git a/FileHandler.php b/FileHandler.php index c4deee2..5445f6b 100644 --- a/FileHandler.php +++ b/FileHandler.php @@ -1,35 +1,22 @@ db = $db; $this->config = $config + [ 'basedir' => '', 'baseurl' => '', - 'table' => 'files', - 'get_user_id' => NULL, 'mime_blacklist' => '#'. // HTML may contain cookie-stealing JavaScript and web bugs '^text/(html|(x-)?javascript)$|^application/x-shellscript$'. @@ -60,40 +47,15 @@ class FileHandler $this->config['thumb_path'] . '/' . $type . '/' .substr($s, 0, 1) . '/' . substr($s, 0, 2) . '/' . $s . '.' . $ext; } - public 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 function upload(LocalFile $localFile, $allowedFormats = FileHandler::ANYTHING) + public function upload($localFile, $allowedFormats = FileUtils::ANYTHING) { $tmp_name = $localFile->getLocalPath(); $props = FileUtils::getProps($allowedFormats, $this->config['mime_blacklist'], $tmp_name, $localFile->getFileName()); - $row = [ - 'id' => NULL, - 'added' => time(), - ] + $props + [ 'props' => [] ]; - if ($this->config['get_user_id']) + $fn = $this->getPath(false, $props); + if (file_exists($fn) && filesize($fn) == $props['size']) { - $row['user_id'] = $this->config['get_user_id']() ?: NULL; + return $props; } - $exist = $this->db->select($this->config['table'], '*', [ 'sha1' => $row['sha1'] ], NULL, MS_ROW); - if ($exist) - { - $exist['props'] = json_decode($exist['props'], true); - return $exist; - } - $row['id'] = $this->db->insert_row($this->config['table'], [ - 'props' => json_encode($row['props'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), - ] + $row); - $fn = $this->getPath(false, $row); FileUtils::mkpath(dirname($fn), true); $m = $localFile->shouldMove ? 'rename' : 'copy'; if (!@$m($tmp_name, $fn)) @@ -102,10 +64,10 @@ class FileHandler throw new Exception($error['message']); } chmod($fn, 0666 & ~umask()); - return $row; + return $props; } - public function uploadUrl($url, $flags = FileHandler::ONLY_IMAGES, $curl_options = []) + public function uploadUrl($url, $flags = FileUtils::ONLY_IMAGES, $curl_options = []) { if (!$url) { @@ -142,17 +104,20 @@ class FileHandler return $file; } - public function deleteFiles($where) + public function deleteFile($e) { - $files = $this->db->select($this->config['table'], '*', $where); - foreach ($existing as $e) + $disk_name = $this->getPath(false, $e); + if (file_exists($disk_name)) { - $disk_name = $this->getPath(false, $e); - if (file_exists($disk_name)) + // Remove old file + unlink($disk_name); + } + $thumb_glob = $this->getThumbPath(false, $e, '*'); + foreach (glob($thumb_glob) as $thumb) + { + if (file_exists($thumb)) { - // Remove old file - // FIXME unlink thumbnails - unlink($disk_name); + unlink($thumb); } } } @@ -162,22 +127,12 @@ class FileHandler */ public function getThumb($file, $width, $height, $force = false, $crop = false, $alignY = 0.5) { - $size = FileUtils::getThumbSize($file, $width, $height, $crop); - if (!$size) + $type = FileUtils::getThumbType($file, $width, $height, $crop, $alignY); + if (!$type) { - return $this->getPath(true, $file); + return NULL; } - list($width, $height) = $size; - if (!$crop) - { - $type = intval($width); - } - else - { - $p = $crop == FileHandler::CROP_Y ? 'cy' : ($crop == FileHandler::CROP_X ? 'cx' : 'c'); - $type = intval($width).'x'.intval($height).'_'.$alignY; - } - $fn = $this->getThumbPath(false, $file, $type); + $fn = $this->getThumbPath(false, $file, $type['type']); if (!file_exists($fn) || $force) { if (substr($file['mimetype'], 0, 6) === 'video/') @@ -188,29 +143,9 @@ class FileHandler { $sourcefn = $this->getPath(false, $file); } - try + if (!FileUtils::generateThumbnail($sourcefn, $fn, $file, $type['width'], $type['height'], $crop, $alignY)) { - $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 == FileHandler::CROP_X || $crop == FileHandler::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 NULL; } } return $this->getThumbPath(true, $file, $type); diff --git a/FileUtils.php b/FileUtils.php index cefe6f1..866d408 100644 --- a/FileUtils.php +++ b/FileUtils.php @@ -1,13 +1,27 @@ 0, 'height' => 0, ]; - $flag = FileHandler::ONLY_BINARY; + $flag = FileUtils::ONLY_BINARY; $props = NULL; if ($mime == 'application/x-shockwave-flash') { $props = self::getSWFProps($fs_path); if ($props) - $flag = FileHandler::ONLY_SWF; + $flag = FileUtils::ONLY_SWF; } elseif (substr($mime, 0, 6) == 'image/') { $props = self::getImageProps($fs_path); if ($props) - $flag = FileHandler::ONLY_IMAGES; + $flag = FileUtils::ONLY_IMAGES; } elseif (substr($mime, 0, 6) == 'video/') { $props = VideoUtils::getVideoProps($fs_path); if ($props) - $flag = FileHandler::ONLY_VIDEO; + $flag = FileUtils::ONLY_VIDEO; } if (!($allowed_types & $flag)) { @@ -295,6 +286,41 @@ class FileUtils } } + 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 exifGPS($coordinate, $hemisphere) + { + for ($i = 0; $i < 3; $i++) + { + $part = explode('/', $coordinate[$i]); + if (count($part) == 1) + { + $coordinate[$i] = $part[0]; + } + elseif (count($part) == 2) + { + $coordinate[$i] = floatval($part[0])/floatval($part[1]); + } + else + { + $coordinate[$i] = 0; + } + } + list($degrees, $minutes, $seconds) = $coordinate; + $sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1; + return $sign * ($degrees + $minutes/60 + $seconds/3600); + } + /** * Calculate thumbnail image width and height */ @@ -397,11 +423,11 @@ class FileUtils { $iw = $im->getImageWidth(); $ih = $im->getImageHeight(); - if ($crop == FileHandler::CROP_Y && $ih*$width/$iw < $height) + if ($crop == FileUtils::CROP_Y && $ih*$width/$iw < $height) { $height = $ih*$width/$iw; } - elseif ($crop == FileHandler::CROP_X && $iw*$height/$ih < $width) + elseif ($crop == FileUtils::CROP_X && $iw*$height/$ih < $width) { $width = $iw*$height/$ih; } @@ -430,4 +456,56 @@ class FileUtils self::fixOrientation($im, $orientation); } } + + /** + * Get thumbnail type + */ + public static function getThumbType($file, $width, $height, $crop = false, $alignY = 0.5) + { + $size = FileUtils::getThumbSize($file, $width, $height, $crop); + if (!$size) + { + return NULL; + } + list($width, $height) = $size; + if (!$crop) + { + $type = intval($width); + } + else + { + $p = $crop == FileUtils::CROP_Y ? 'cy' : ($crop == FileUtils::CROP_X ? 'cx' : 'c'); + $type = intval($width).'x'.intval($height).'_'.$alignY; + } + return [ 'width' => $width, 'height' => $height, 'type' => $type ]; + } + + public static function generateThumbnail($sourcefn, $thumbfn, $file, $width, $height, $crop = false, $alignY = 0.5) + { + 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 == FileUtils::CROP_X || $crop == FileUtils::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($thumbfn)); + $im->writeImage($thumbfn); + } + catch (Exception $e) + { + trigger_error("$e"); + return false; + } + return true; + } }