index : fluxbb | |
Archlinux32 customized Fluxbb installation | gitolite user |
summaryrefslogtreecommitdiff |
-rw-r--r-- | img/loading.gif | bin | 0 -> 673 bytes | |||
-rw-r--r-- | img/members/.gitkeep | 0 | ||||
-rw-r--r-- | img/members/.htaccess | 72 | ||||
-rw-r--r-- | img/members/nofile.gif | bin | 0 -> 631 bytes | |||
-rw-r--r-- | img/upf-i.png | bin | 0 -> 649 bytes | |||
-rw-r--r-- | img/upf-it.png | bin | 0 -> 668 bytes | |||
-rw-r--r-- | img/upf-x.png | bin | 0 -> 778 bytes | |||
-rw-r--r-- | include/upload.php | 784 | ||||
-rw-r--r-- | include/uploadf.php | 116 | ||||
-rw-r--r-- | include/uploadp.php | 23 | ||||
-rw-r--r-- | js/upload.js | 407 | ||||
-rw-r--r-- | lang/English/upload.php | 92 | ||||
-rw-r--r-- | lang/French/upload.php | 92 | ||||
-rw-r--r-- | lang/German/upload.php | 92 | ||||
-rw-r--r-- | lang/Russian/upload.php | 92 | ||||
-rw-r--r-- | plugins/AP_Upload.php | 638 | ||||
-rw-r--r-- | readme.txt | 157 | ||||
-rw-r--r-- | style/imports/upfiles.css | 171 | ||||
-rw-r--r-- | upfiles.php | 732 |
diff --git a/img/loading.gif b/img/loading.gif Binary files differnew file mode 100644 index 0000000..f1c77c7 --- /dev/null +++ b/img/loading.gif diff --git a/img/members/.gitkeep b/img/members/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/img/members/.gitkeep diff --git a/img/members/.htaccess b/img/members/.htaccess new file mode 100644 index 0000000..2c530b3 --- /dev/null +++ b/img/members/.htaccess @@ -0,0 +1,72 @@ +# ---------------------------------------------------------------------- +# If something is broken, then see the apache config for your site, +# the AllowOverride directive https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride +# ---------------------------------------------------------------------- + +# ---------------------------------------------------------------------- +# Disable directory listing. +#----------------------------------------------------------------------- + +<IfModule mod_autoindex.c> + Options -Indexes +</IfModule> + +# ---------------------------------------------------------------------- +# Disable CGI script execution. +#----------------------------------------------------------------------- + +<IfModule mod_cgi.c> + Options -ExecCGI +</IfModule> +<IfModule mod_cgid.c> + Options -ExecCGI +</IfModule> +<IfModule mod_fcgid.c> + Options -ExecCGI +</IfModule> + +# ---------------------------------------------------------------------- +# Disable PHP script execution if php as apache module. +# If your php has a module name other than "mod_php", "mod_php_null", +# "mod_php5" and "mod_php7", then add here one more condition with your name. +#----------------------------------------------------------------------- + +<IfModule mod_php.c> + php_flag engine 0 +</IfModule> +<IfModule mod_php_null.c> + php_flag engine 0 +</IfModule> +<IfModule mod_php5.c> + php_flag engine 0 +</IfModule> +<IfModule mod_php7.c> + php_flag engine 0 +</IfModule> + +# ---------------------------------------------------------------------- +# Treat these files as plain text. +# ---------------------------------------------------------------------- + +<IfModule mod_mime.c> + RemoveHandler .asmx .asp .aspx .cgi .dll .exe .fcgi .fpl .htm .html .js .jsp .php .php3 .php4 .php5 .php6 .php7 .phar .phps .phtm .phtml .pl .py .rb .shtm .shtml .wml .xml + AddType text/plain .asmx .asp .aspx .cgi .dll .exe .fcgi .fpl .htm .html .js .jsp .php .php3 .php4 .php5 .php6 .php7 .phar .phps .phtm .phtml .pl .py .rb .shtm .shtml .wml .xml +</IfModule> + +# ---------------------------------------------------------------------- +# All files are given through the default handler for static content (Disable script execution). +# ---------------------------------------------------------------------- + +SetHandler default-handler + +# ---------------------------------------------------------------------- +# Show nofile.gif instead of missing files. +# ---------------------------------------------------------------------- + +<IfModule mod_rewrite.c> + RewriteEngine On +# Uncomment and properly set the RewriteBase if the rewrite rules are not working properly +# RewriteBase / + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule .* nofile.gif [L] +</IfModule> diff --git a/img/members/nofile.gif b/img/members/nofile.gif Binary files differnew file mode 100644 index 0000000..8b4224d --- /dev/null +++ b/img/members/nofile.gif diff --git a/img/upf-i.png b/img/upf-i.png Binary files differnew file mode 100644 index 0000000..5d96460 --- /dev/null +++ b/img/upf-i.png diff --git a/img/upf-it.png b/img/upf-it.png Binary files differnew file mode 100644 index 0000000..888173a --- /dev/null +++ b/img/upf-it.png diff --git a/img/upf-x.png b/img/upf-x.png Binary files differnew file mode 100644 index 0000000..29185fe --- /dev/null +++ b/img/upf-x.png diff --git a/include/upload.php b/include/upload.php new file mode 100644 index 0000000..5d3aac5 --- /dev/null +++ b/include/upload.php @@ -0,0 +1,784 @@ +<?php + +/** + * Copyright (C) 2011-2019 Visman (mio.visman@yandex.ru) + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher + */ + +// Make sure no one attempts to run this script "directly" +if (! defined('PUN')) { + exit; +} + +// Load language file +if (file_exists(PUN_ROOT . 'lang/' . $pun_user['language'] . '/upload.php')) { + require PUN_ROOT . 'lang/' . $pun_user['language'] . '/upload.php'; +} else { + require PUN_ROOT . 'lang/English/upload.php'; +} + +class upfClass +{ + protected $blackList = [ + '' => true, + 'asmx' => true, + 'asp' => true, + 'aspx' => true, + 'cgi' => true, + 'dll' => true, + 'exe' => true, + 'fcgi' => true, + 'fpl' => true, + 'htaccess' => true, + 'htm' => true, + 'html' => true, + 'js' => true, + 'jsp' => true, + 'php' => true, + 'php3' => true, + 'php4' => true, + 'php5' => true, + 'php6' => true, + 'php7' => true, + 'phar' => true, + 'phps' => true, + 'phtm' => true, + 'phtml' => true, + 'pl' => true, + 'py' => true, + 'rb' => true, + 'shtm' => true, + 'shtml' => true, + 'wml' => true, + 'xml' => true, + ]; + + /** + * Список кодов типов картинок и расширений для них???? + * @var array + */ + protected $imageType = [ + 1 => ['gif', true], + 2 => ['jpg', true], + 3 => ['png', true], + 4 => ['swf', false], + 5 => ['psd', false], + 6 => ['bmp', true], + 7 => ['tiff', false], + 8 => ['tiff', false], + 9 => ['jpc', false], + 10 => ['jp2', false], + 11 => ['jpx', false], + 12 => ['jb2', false], + 13 => ['swc', false], + 14 => ['iff', false], + 15 => ['wbmp', false], + 16 => ['xbm', false], + 17 => ['ico', false], + 18 => ['webp', true], + ]; + + /** + * Список единиц измерения + * @var string + */ + protected $units = 'BKMGTPEZY'; + + protected $UTF8AR = [ + 'à' => 'a', 'ô' => 'o', 'ď' => 'd', 'ḟ' => 'f', 'ë' => 'e', 'š' => 's', 'ơ' => 'o', + 'ß' => 'ss', 'ă' => 'a', 'ř' => 'r', 'ț' => 't', 'ň' => 'n', 'ā' => 'a', 'ķ' => 'k', + 'ŝ' => 's', 'ỳ' => 'y', 'ņ' => 'n', 'ĺ' => 'l', 'ħ' => 'h', 'ṗ' => 'p', 'ó' => 'o', + 'ú' => 'u', 'ě' => 'e', 'é' => 'e', 'ç' => 'c', 'ẁ' => 'w', 'ċ' => 'c', 'õ' => 'o', + 'ṡ' => 's', 'ø' => 'o', 'ģ' => 'g', 'ŧ' => 't', 'ș' => 's', 'ė' => 'e', 'ĉ' => 'c', + 'ś' => 's', 'î' => 'i', 'ű' => 'u', 'ć' => 'c', 'ę' => 'e', 'ŵ' => 'w', 'ṫ' => 't', + 'ū' => 'u', 'č' => 'c', 'ö' => 'oe', 'è' => 'e', 'ŷ' => 'y', 'ą' => 'a', 'ł' => 'l', + 'ų' => 'u', 'ů' => 'u', 'ş' => 's', 'ğ' => 'g', 'ļ' => 'l', 'ƒ' => 'f', 'ž' => 'z', + 'ẃ' => 'w', 'ḃ' => 'b', 'å' => 'a', 'ì' => 'i', 'ï' => 'i', 'ḋ' => 'd', 'ť' => 't', + 'ŗ' => 'r', 'ä' => 'ae', 'í' => 'i', 'ŕ' => 'r', 'ê' => 'e', 'ü' => 'ue', 'ò' => 'o', + 'ē' => 'e', 'ñ' => 'n', 'ń' => 'n', 'ĥ' => 'h', 'ĝ' => 'g', 'đ' => 'd', 'ĵ' => 'j', + 'ÿ' => 'y', 'ũ' => 'u', 'ŭ' => 'u', 'ư' => 'u', 'ţ' => 't', 'ý' => 'y', 'ő' => 'o', + 'â' => 'a', 'ľ' => 'l', 'ẅ' => 'w', 'ż' => 'z', 'ī' => 'i', 'ã' => 'a', 'ġ' => 'g', + 'ṁ' => 'm', 'ō' => 'o', 'ĩ' => 'i', 'ù' => 'u', 'į' => 'i', 'ź' => 'z', 'á' => 'a', + 'û' => 'u', 'þ' => 'th', 'ð' => 'dh', 'æ' => 'ae', 'µ' => 'u', 'ĕ' => 'e', + 'À' => 'A', 'Ô' => 'O', 'Ď' => 'D', 'Ḟ' => 'F', 'Ë' => 'E', 'Š' => 'S', 'Ơ' => 'O', + 'Ă' => 'A', 'Ř' => 'R', 'Ț' => 'T', 'Ň' => 'N', 'Ā' => 'A', 'Ķ' => 'K', + 'Ŝ' => 'S', 'Ỳ' => 'Y', 'Ņ' => 'N', 'Ĺ' => 'L', 'Ħ' => 'H', 'Ṗ' => 'P', 'Ó' => 'O', + 'Ú' => 'U', 'Ě' => 'E', 'É' => 'E', 'Ç' => 'C', 'Ẁ' => 'W', 'Ċ' => 'C', 'Õ' => 'O', + 'Ṡ' => 'S', 'Ø' => 'O', 'Ģ' => 'G', 'Ŧ' => 'T', 'Ș' => 'S', 'Ė' => 'E', 'Ĉ' => 'C', + 'Ś' => 'S', 'Î' => 'I', 'Ű' => 'U', 'Ć' => 'C', 'Ę' => 'E', 'Ŵ' => 'W', 'Ṫ' => 'T', + 'Ū' => 'U', 'Č' => 'C', 'Ö' => 'Oe', 'È' => 'E', 'Ŷ' => 'Y', 'Ą' => 'A', 'Ł' => 'L', + 'Ų' => 'U', 'Ů' => 'U', 'Ş' => 'S', 'Ğ' => 'G', 'Ļ' => 'L', 'Ƒ' => 'F', 'Ž' => 'Z', + 'Ẃ' => 'W', 'Ḃ' => 'B', 'Å' => 'A', 'Ì' => 'I', 'Ï' => 'I', 'Ḋ' => 'D', 'Ť' => 'T', + 'Ŗ' => 'R', 'Ä' => 'Ae', 'Í' => 'I', 'Ŕ' => 'R', 'Ê' => 'E', 'Ü' => 'Ue', 'Ò' => 'O', + 'Ē' => 'E', 'Ñ' => 'N', 'Ń' => 'N', 'Ĥ' => 'H', 'Ĝ' => 'G', 'Đ' => 'D', 'Ĵ' => 'J', + 'Ÿ' => 'Y', 'Ũ' => 'U', 'Ŭ' => 'U', 'Ư' => 'U', 'Ţ' => 'T', 'Ý' => 'Y', 'Ő' => 'O', + 'Â' => 'A', 'Ľ' => 'L', 'Ẅ' => 'W', 'Ż' => 'Z', 'Ī' => 'I', 'Ã' => 'A', 'Ġ' => 'G', + 'Ṁ' => 'M', 'Ō' => 'O', 'Ĩ' => 'I', 'Ù' => 'U', 'Į' => 'I', 'Ź' => 'Z', 'Á' => 'A', + 'Û' => 'U', 'Þ' => 'Th', 'Ð' => 'Dh', 'Æ' => 'Ae', 'Ĕ' => 'E', + 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'jo', + 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'jj', 'к' => 'k', 'л' => 'l', 'м' => 'm', + 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', + 'ф' => 'f', 'х' => 'kh', 'ц' => 'c', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shh', 'ъ' => '', + 'ы' => 'y', 'ь' => '', 'э' => 'eh', 'ю' => 'ju', 'я' => 'ja', + 'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'Jo', + 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I', 'Й' => 'Jj', 'К' => 'K', 'Л' => 'L', 'М' => 'M', + 'Н' => 'N', 'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', + 'Ф' => 'F', 'Х' => 'Kh', 'Ц' => 'C', 'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Shh', 'Ъ' => '', + 'Ы' => 'Y', 'Ь' => '', 'Э' => 'Eh', 'Ю' => 'Ju', 'Я' => 'Ja', + ]; + + const GD = 1; + const IMAGICK = 2; + + protected $resizeFlag = false; + protected $libType; + protected $libName = '-'; + protected $libVersion = '-'; + protected $error; + protected $quality = 75; + + public function __construct() + { + if (\extension_loaded('imagick') && \class_exists('\Imagick')) { + $this->resizeFlag = true; + $this->libType = self::IMAGICK; + $this->libName = 'ImageMagick'; + $imagick = \Imagick::getVersion(); + $this->libVersion = \trim(\preg_replace(['%ImageMagick%i', '%http[^\s]+%i'], '', $imagick['versionString'])); + } elseif (\extension_loaded('gd') && \function_exists('\\imagecreatetruecolor')) { + $this->resizeFlag = true; + $this->libType = self::GD; + $this->libName = 'GD'; + $gd = \gd_info(); + $this->libVersion = $gd['GD Version']; + } + } + + public function isResize() + { + return $this->resizeFlag; + } + + public function getLibName() + { + return $this->libName; + } + + public function getLibVersion() + { + return $this->libVersion; + } + + public function getError() + { + $error = $this->error; + $this->error = null; + return $error; + } + + protected function isBadLink($link) + { + if (false !== \strpos($link, ':', 2) || false !== \strpos($link, '//') || \preg_match('%\bphar\b%i', $link)) { + $this->error = 'Bad link'; + return true; + } else { + return false; + } + } + + public function inBlackList($ext) + { + return isset($this->blackList[\strtolower($ext)]); + } + + public function dirSize($dir) + { + if ($this->isBadLink($dir)) { + return false; + } + if (! \is_dir($dir)) { + $this->error = 'Directory expected'; + return false; + } + if (false === ($dh = \opendir($dir))) { + $this->error = 'Could not open directory'; + return false; + } + + $size = 0; + while (false !== ($file = \readdir($dh))) { + if ('' == \trim($file) || '.' === $file[0] || '#' === $file[0] || ! \is_file($dir . $file)) { + continue; + } + $ext = \strtolower(\substr(\strrchr($file, '.'), 1)); // расширение файла + if (isset($this->blackList[$ext])) { + continue; + } + $size += \filesize($dir . $file); + } + + \closedir($dh); + return $size; + } + + /** + * Переводит объем информации из одних единиц в другие + * кило = 1024, а не 1000 + * + * @param int|float|string $value + * @param string $to + * + * @return int|float|false + */ + public function size($value, $to = null) + { + if (\is_string($value)) { + if (! \preg_match('%^([^a-z]+)([a-z]+)?$%i', \trim($value), $matches)) { + $this->error = 'Expected string indicating the amount of information'; + return false; + } + if (! \is_numeric($matches[1])) { + $this->error = 'String does not contain number'; + return false; + } + + $value = 0 + $matches[1]; + + if (! empty($matches[2])) { + $unit = \strtoupper($matches[2][0]); + $expo = \strpos($this->units, $unit); + + if (false === $expo) { + $this->error = 'Unknown unit'; + return false; + } + + $value *= 1024 ** $expo; + } + } + + if (\is_string($to)) { + $to = \trim($to); + $unit = \strtoupper($to[0]); + $expo = \strpos($this->units, $unit); + + if (false === $expo) { + $this->error = 'Unknown unit'; + return false; + } + + $value /= 1024 ** $expo; + } + + return 0 + $value; + } + + /** + * Определяет по содержимому файла расширение картинки???? + * + * @param string $path + * + * @return false|array + */ + public function imageExt($path) + { + if ($this->isBadLink($path)) { + return false; + } + + if (\function_exists('\\exif_imagetype')) { + $type = \exif_imagetype($path); + } elseif ( + \function_exists('\\getimagesize') + && false !== ($type = @\getimagesize($path)) + && $type[0] > 0 + && $type[1] > 0 + ) { + $type = $type[2]; + } else { + $type = 0; + } + return isset($this->imageType[$type]) ? $this->imageType[$type] : false; + } + + /** + * Фильрует и переводит в латиницу(?) имя файла + * + * @param string $name + * + * @return string + */ + protected function filterName($name) + { + $new = false; + if (\function_exists('\\transliterator_transliterate')) { + $new = \transliterator_transliterate("Any-Latin; NFD; [:Nonspacing Mark:] Remove; NFC;", $name); + } + if (! \is_string($new)) { + $new = str_replace(array_keys($this->UTF8AR), array_values($this->UTF8AR), $name); + } + + $name = \trim(\preg_replace('%[^\w-]+%', '-', $new), '-_'); + + if (! isset($name[0])) { + $name = $this->filterName(\date('Ymd\-His')); + } + + return $name; + } + + public function getFileExt() + { + return $this->fileExt; + } + + public function getFileName() + { + return $this->fileName; + } + + public function prepFileName() + { + if ('mini_' === \substr($this->fileName, 0, 5)) { + $this->fileName = \substr($this->fileName, 5); + } + if (\strlen($this->fileName) > 100) { + $this->fileName = \substr($this->fileName, 0, 100); + } + if ('' == $this->fileName) { + $this->fileName = 'none'; + } + } + + public function isImage() + { + return $this->fileAsImage; + } + + public function setImageQuality($quality) + { + $this->quality = \min(\max((int) $quality, 1), 100); + } + + protected $filePath; + protected $fileName; + protected $fileExt; + protected $fileCalcExt; + protected $fileAsImage; + protected $fileIsUp; + protected $image; + + public function loadFile($path, $basename = null) + { + $this->filePath = null; + $this->fileName = null; + $this->fileExt = null; + $this->fileCalcExt = null; + $this->fileAsImage = false; + $this->fileIsUp = null !== $basename; + + $this->destroyImage(); + $this->image = null; + + if ($this->isBadLink($path)) { + return false; + } + + if (null !== $basename) { + $pattern = '%^(.+)\.(\w+)$%'; + $subject = $basename; + } else { + $pattern = '%[\\/]([\w-]+)\.(\w+)$%'; + $subject = $path; + } + if (! \preg_match($pattern, $subject, $matches)) { + $this->error = 'Bad file name or extension'; + return false; + } + + $this->fileExt = $this->fileCalcExt = \strtolower($matches[2]); + if (isset($this->blackList[$this->fileExt])) { + $this->error = 'Bad file extension'; + return false; + } + + if (null !== $basename) { + if (! \is_uploaded_file($path)) { + $this->error = 'File was not uploaded'; + return false; + } + } else { + if (! \is_file($path)) { + $this->error = 'No file'; + return false; + } + } + if (! \is_readable($path)) { + $this->error = 'File unreadable'; + return false; + } + + $imageInfo = $this->imageExt($path); + if (\is_array($imageInfo)) { + if (null !== $basename) { + $this->fileExt = $imageInfo[0]; + } + $this->fileCalcExt = $imageInfo[0]; + $this->fileAsImage = $imageInfo[1]; + } + + $this->fileName = null !== $basename ? $this->filterName($matches[1]) : $matches[1]; + $this->filePath = $path; + + return true; + } + + public function isUnsafeContent() + { + if (null === $this->filePath) { + return true; + } + + $f = \fopen($this->filePath, "rb"); + if (false === $f) { + return true; + } + + $buf1 = ''; + while ($buf2 = \fread($f, 4096)) { + if (\preg_match( "%<(?:script|html|head|title|body|table|a\s+href|img\s|plaintext|cross\-domain\-policy|embed|applet|i?frame|\?php)%msi", $buf1 . $buf2)) { + \fclose($f); + return true; + } + $buf1 = \substr($buf2, -30); + } + \fclose($f); + return false; + } + + public function loadImage() + { + if (null === $this->filePath || true !== $this->fileAsImage) { + $this->error = 'No image'; + return false; + } + switch ($this->libType) { + case self::IMAGICK: + try { + $image = new \Imagick(\realpath($this->filePath)); + $width = $image->getImageWidth(); + $height = $image->getImageHeight(); + } catch (\Exception $e) { + $this->error = $this->hidePath($e->getMessage()); + return false; + } + break; + case self::GD: + $type = $this->fileCalcExt; + switch ($type) { + case 'jpg': + $type = 'jpeg'; + break; + } + + $func = '\\imagecreatefrom' . $type; + if (! \function_exists($func)) { + $this->error = 'No function to create image'; + return false; + } + + $image = @$func($this->filePath); + if (! $image) { + $this->error = 'Failed to create image'; + return false; + } + if (false === \imagealphablending($image, false) || false === \imagesavealpha($image, true)) { + $this->error = 'Failed to adjust image'; + return false; + } + $width = \imagesx($image); + $height = \imagesy($image); + break; + default: + $this->error = 'Graphics library type not defined'; + return false; + } + $this->image = $image; + + return [ + $width, + $height, + ]; + } + + public function saveFile($path, $overwrite = false) + { + return $this->save($path, $overwrite, false); + } + + public function saveImage($path, $overwrite = false) + { + if (empty($this->image)) { + $this->error = 'No image'; + return false; + } + + return $this->save($path, $overwrite, true); + } + + protected function save($path, $overwrite, $isImage) + { + if ($this->isBadLink($path)) { + return false; + } + + if (! \preg_match('%^(.+[\\/])([\w-]+)\.(\w+)$%', $path, $matches)) { + $this->error = 'Bad dir name, file name or extension'; + return false; + } + + $ext = \strtolower($matches[3]); + if (isset($this->blackList[$ext])) { + $this->error = 'Bad file extension'; + return false; + } + $name = $matches[2]; + $dir = $matches[1]; + + if (true !== $overwrite) { + $tmp = ''; + $i = 0; + while (\is_file($dir . $name . $tmp . '.' . $ext) && $i < 100) { + $tmp = '-' . random_pass(4); + ++$i; + } + if ($i >= 100) { + $this->error = 'Many similar names'; + return false; + } + $name .= $tmp; + } + $path = $dir . $name . '.' . $ext; + + if (false === $isImage) { + $func = $this->fileIsUp ? '\\move_uploaded_file' : '\\copy'; + $result = @$func($this->filePath, $path); + if (! $result) { + $this->error = 'Failed to copy file'; + return false; + } + } else { + switch ($this->libType) { + case self::IMAGICK: + try { + //var_dump($this->image->getImageColors()); + $type = $this->fileCalcExt; + switch ($type) { + case 'png': + $this->image->setImageCompressionQuality(0); + break; + default: + $this->image->setImageCompressionQuality($this->quality); + break; + } + $this->image->writeImages($path, true); + } catch (\Exception $e) { + $this->error = $this->hidePath($e->getMessage(), $path); + return false; + } + break; + case self::GD: + $result = false; + $type = $this->fileCalcExt; + $args = [$this->image, $path]; + switch ($type) { + case 'jpg': + $type = 'jpeg'; + $args[] = $this->quality; + break; + case 'png': + //$args[] = -1; + //$args[] = \PNG_ALL_FILTERS; // \PNG_NO_FILTER; + // imagecolorstotal + // , int $quality = -1 , int $filters = -1 + break; + case 'webp': + $args[] = $this->quality; + break; + } + $func = '\\image' . $type; + if (! \function_exists($func)) { + $this->error = 'No function to save image'; + return false; + } + + $result = @$func(...$args); + if (true !== $result) { + $this->error = 'Failed to copy image'; + return false; + } + break; + default: + $this->error = 'Graphics library type not defined'; + return false; + } + } + + @\chmod($path, 0644); + + return [ + 'path' => $path, + 'dirname' => $dir, + 'filename' => $name, + 'extension' => $ext, + ]; + } + + public function resizeImage($width, $height = null) + { + if (empty($this->image)) { + $this->error = 'No image'; + return false; + } + + switch ($this->libType) { + case self::IMAGICK: + try { + $oldWidth = $this->image->getImageWidth(); + $oldHeight = $this->image->getImageHeight(); + } catch (\Exception $e) { + $this->error = $this->hidePath($e->getMessage()); + return false; + } + break; + case self::GD: + $oldWidth = \imagesx($this->image); + $oldHeight = \imagesy($this->image); + break; + default: + $this->error = 'Graphics library type not defined'; + return false; + } + + $w = (empty($width) || $width < 16) ? 1 : $width / $oldWidth; + $h = (empty($height) || $height < 16) ? 1 : $height / $oldHeight; + $r = \min(1, $w, $h); + if (1 == $r) { // ? + return 1; + } + $width = (int) \round($oldWidth * $r); + $height = (int) \round($oldHeight * $r); + + switch ($this->libType) { + case self::IMAGICK: + try { + // есть анимация + if ($this->image->getImageDelay() > 0) { + $image = $this->image->coalesceImages(); + + foreach ($image as $frame) { + $frame->resizeImage($width, $height, \Imagick::FILTER_LANCZOS, 1); + $frame->setImagePage($width, $height, 0, 0); + } + + $image = $image->deconstructImages(); + //$image = $image->optimizeImageLayers(); + // нет анимации + } else { + $image = clone $this->image; + $image->resizeImage($width, $height, \Imagick::FILTER_LANCZOS, 1); + } + } catch (\Exception $e) { + $this->error = $this->hidePath($e->getMessage()); + return false; + } + break; + case self::GD: + if (false === ($image = \imagecreatetruecolor($width, $height))) { + $this->error = 'Failed to create new truecolor image'; + return false; + } + if (false === ($transparent = \imagecolorallocatealpha($image, 255, 255, 255, 127))) { + $this->error = 'Failed to create color for image'; + return false; + } + if (false === \imagefill($image, 0, 0, $transparent)) { + $this->error = 'Failed to fill image with color'; + return false; + } + \imagecolortransparent($image, $transparent); + $colors = \imagecolorstotal($this->image); + if ($colors > 0 && false === \imagetruecolortopalette($image, true, $colors)) { + $this->error = 'Failed to convert image to palette'; + return false; + } + if (false === \imagealphablending($image, false) || false === \imagesavealpha($image, true)) { + $this->error = 'Failed to adjust image'; + return false; + } + if (false === \imagecopyresampled($image, $this->image, 0, 0, 0, 0, $width, $height, $oldWidth, $oldHeight)) { + $this->error = 'Failed to resize image'; + return false; + } + break; + } + + if (false === $this->destroyImage()) { + return false; + } + $this->image = $image; + + return $r; + } + + public function destroyImage() + { + if (empty($this->image)) { + return true; + } + + $result = false; + + switch ($this->libType) { + case self::IMAGICK: + try { + $result = $this->image->clear(); + } catch (\Exception $e) { + $result = false; + } + break; + case self::GD: + $result = \imagedestroy($this->image); + break; + } + + if (true === $result) { + $this->image = null; + } else { + $this->error = 'Failed to clear resource'; + } + + return $result; + } + + public function __destruct() + { + $this->destroyImage(); + } + + protected function hidePath($str, $path = null) + { + $search = []; + if (null !== $this->filePath) { + $search[] = \realpath($this->filePath); + $search[] = $this->filePath; + } + if (null !== $path) { + $search[] = \realpath($path); + $search[] = $path; + } + return empty($search) ? $str : \str_replace($search, '', $str); + } +} + +$upf_class = new upfClass(); diff --git a/include/uploadf.php b/include/uploadf.php new file mode 100644 index 0000000..527bc32 --- /dev/null +++ b/include/uploadf.php @@ -0,0 +1,116 @@ +<?php +/** + * Copyright (C) 2011-2020 Visman (visman@inbox.ru) + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher + */ + +// Make sure no one attempts to run this script "directly" +if (! defined('PUN')) { + exit; +} + +if (!$pun_user['is_guest'] && isset($pun_config['o_upload_config'], $required_fields['req_message'])) { + if ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_up_limit'] > 0 && $pun_user['g_up_max'] > 0)) { + // Load language file + if (! isset($lang_up)) { + if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/upload.php')) { + require PUN_ROOT.'lang/'.$pun_user['language'].'/upload.php'; + } else { + require PUN_ROOT.'lang/English/upload.php'; + } + } + + if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/upfiles.css')) { + $style = 'style/'.$pun_user['style'].'/upfiles.css'; + } else { + $style = 'style/imports/upfiles.css'; + } + + $upf_conf = unserialize($pun_config['o_upload_config']); + $upf_max_size = (int) (10485.76 * $pun_user['g_up_max']) + +?> +<script type="text/javascript"> +/* <![CDATA[ */ +if (typeof FluxBB === 'undefined' || !FluxBB) {var FluxBB = {};} +FluxBB.uploadvars = { + action: 'upfiles.php', + style: '<?= addslashes($style) ?>', + lang: { + upfiles: '<strong><?= addslashes($lang_up['upfiles']) ?></strong>', + confirmation: '<?= addslashes($lang_up['delete file']) ?>', + large: '<?= addslashes($lang_up['Too large']) ?>', + bad_type: '<?= addslashes($lang_up['Bad type']) ?>' + }, + maxsize: <?= $upf_max_size ?>, + exts: ['<?= str_replace([' ', ','], ['', '\', \''], addslashes($pun_user['g_up_ext'])) ?>'], + token: '<?= addslashes(function_exists('csrf_hash') ? csrf_hash('upfiles.php') : pun_csrf_token()) ?>' +}; +/* ]]> */ +</script> +<script type="text/javascript" src="js/upload.js"></script> + +<div id="upf-template" style="width: 0; height: 0; overflow: hidden; margin: 0; padding: 0;"> + <div class="inform upf-fmess"> + <fieldset> + <legend><?= $lang_up['upfiles'] ?></legend> + <div class="infldset"> + <button id="upf-button" type="button"><?= $lang_up['fichier'] ?></button> + <span><?= sprintf($lang_up['info_2'], pun_htmlspecialchars(str_replace([' ', ','], ['', ', '], $pun_user['g_up_ext'])), pun_htmlspecialchars(file_size($upf_max_size))) ?></span> + </div> + </fieldset> + </div> + <div class="inform upf-fmess"> + <fieldset id="upf-list-fls"> + <div class="infldset"> + <div id="upf-container"> + <ul id="upf-list"> + <li id="upf--"> + <div class="upf-name" title="End"> + <span> </span> + </div> + <div class="upf-file" style="height: <?= max((int) $upf_conf['thumb_size'], 100) ?>px;"> + <a> + <span> </span> + </a> + </div> + <div class="upf-size"> + <span> </span> + </div> + <div class="upf-but upf-delete"> + <a title="<?= $lang_up['delete'] ?>"> + <span></span> + </a> + </div> + <div class="upf-but upf-insert"> + <a title="<?= $lang_up['insert'] ?>"> + <span></span> + </a> + </div> + <div class="upf-but upf-insert-t"> + <a title="<?= $lang_up['insert_thumb'] ?>"> + <span></span> + </a> + </div> + </li> + </ul> + </div> + </div> + </fieldset> + </div> + <div class="inform upf-fmess"> + <fieldset> + <div class="infldset"> + <div id="upf-legend"> + <div style="background-color: rgb(0, 255, 0); width: 0%;"><span>0%</span></div> + </div> + <p id="upf-legend-p"><?= sprintf($lang_up['info_4'], 0, pun_htmlspecialchars(file_size(1048576 * $pun_user['g_up_limit']))) ?></p> + </div> + </fieldset> + </div> +</div> + +<?php + + } +} diff --git a/include/uploadp.php b/include/uploadp.php new file mode 100644 index 0000000..82f1bb5 --- /dev/null +++ b/include/uploadp.php @@ -0,0 +1,23 @@ +<?php + +/** + * Copyright (C) 2011-2019 Visman (mio.visman@yandex.ru) + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher + */ + +// Make sure no one attempts to run this script "directly" +if (! defined('PUN')) { + exit; +} + +if (isset($pun_config['o_upload_config'])) { + if ($pun_user['g_id'] == PUN_ADMIN || ($id == $pun_user['id'] && $pun_user['g_up_limit'] > 0 && $pun_user['g_up_max'] > 0)) { + if (file_exists(PUN_ROOT . 'lang/' . $pun_user['language'] . '/upload.php')) { + require PUN_ROOT . 'lang/' . $pun_user['language'] . '/upload.php'; + } else { + require PUN_ROOT . 'lang/English/upload.php'; + } + + echo "\t\t\t\t\t" . '<li' . (($page == 'upload') ? ' class="isactive"' : '') . '><a href="upfiles.php?id=' . $id . '">' . $lang_up['upfiles'] . '</a></li>' . "\n"; + } +} diff --git a/js/upload.js b/js/upload.js new file mode 100644 index 0000000..9087dd4 --- /dev/null +++ b/js/upload.js @@ -0,0 +1,407 @@ +// upload.js v3.0.2 Copyright (C) 2020 Visman (mio.visman@yandex.ru) +if (typeof FluxBB === 'undefined' || !FluxBB) {var FluxBB = {};} + +FluxBB.upload = (function (doc, win) { + 'use strict'; + + var state = 0, + anchor, + files = {}, + page = 0, + pages = 1, + textarea; + + function get(elem) { + return doc.getElementById(elem); + } + + function newXhr() { + if (typeof XMLHttpRequest === 'undefined') { + try { + return new ActiveXObject('Microsoft.XMLHTTP'); + } catch (e) {} + } else { + return new XMLHttpRequest(); + } + return false; + } + + function createStartLink(ul) { + var a = doc.createElement('a'), + span = doc.createElement('span'), + li = doc.createElement('li'); + a.innerHTML = FluxBB.uploadvars.lang.upfiles; + a.href = FluxBB.uploadvars.action; + span.appendChild(a); + li.appendChild(span); + ul.appendChild(li); + return a; + } + + function findAnchor(node) { + while (node) { + if ('FIELDSET' === node.tagName) { + anchor = node.parentNode; + return true; + } + node = node.parentNode; + } + return false; + } + + function popUp(url) { + var h = Math.min(430, screen.height), + w = Math.min(820, screen.width), + t = Math.max((screen.height - h) / 3, 0), + l = (screen.width - w) / 2; + win.open(url, 'gest', 'top=' + t + ',left=' + l + ',width=' + w + ',height=' + h + ',resizable=yes,location=no,menubar=no,status=no,scrollbars=yes'); + } + + function insertAfter(newNode, node) { + if (node.parentNode.lastChild === node) { + return node.parentNode.appendChild(newNode); + } else { + return node.parentNode.insertBefore(newNode, node.nextSibling); + } + } + + function setInput(name, value, type) { + var input = doc.createElement('input'); + input.type = type || 'hidden'; + input.name = name; + input.value = value; + return input; + } + + function initLoader() { + var style = doc.createElement('link'), + head = doc.querySelector('head'); + style.href = FluxBB.uploadvars.style; + style.rel = 'stylesheet'; + style.type = 'text/css'; + head.appendChild(style); + + var tmp = get('upf-template').children; + while (tmp[0]) { + anchor = insertAfter(tmp[0], anchor); + } + + var form = doc.createElement('form'); + form.id = 'upf-dataform'; + var div = doc.createElement('div'); + form.appendChild(div); + + var input = setInput('upfile', '', 'file'); + input.id = 'upfile'; + div.appendChild(input); + div.appendChild(setInput('csrf_hash', FluxBB.uploadvars.token)); + div.appendChild(setInput('ajx', '1')); + div.appendChild(setInput('action', 'upload')); + get('upf-template').appendChild(form); + + get('upf-button').addEventListener('click', FluxBB.upload.buttonHandler, false); + input.addEventListener('change', FluxBB.upload.changeHandler, false); + + files['-'] = {link: get('upf--')}; + loadFileData(); + } + + function postData(data, successHandler, errorHandler) { + var xhr = newXhr(); + if (!xhr) { + errorHandler && errorHandler(0, 'XMLHttpRequest not working'); + return; + } + xhr.open('POST', FluxBB.uploadvars.action, true); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + var data = xhr.responseText; + if (typeof data === 'string') { + try { + data = JSON.parse(data); + } catch (e) { + errorHandler && errorHandler(0, e.message); + return; + } + } + if ('error' in data) { + errorHandler && errorHandler(0, data.error); + } else { + successHandler && successHandler(data); + } + } else { + errorHandler && errorHandler(xhr.status, xhr.statusText); + } + } + }; + if (data instanceof FormData) { + xhr.send(data); + } else { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + data.ajx = 1; + data.csrf_hash = FluxBB.uploadvars.token; + var query = '', + separator = ''; + for (var key in data) { + query += separator + key + '=' + encodeURIComponent(data[key]); + separator = '&'; + } + xhr.send(query); + } + } + + function updateData(data, auto) { + pages = data.pages; + + setLegend(data.size, data.percent); + + for (var key in data.files) { + addFileToGallery(key, data.files[key]); + if (auto) { + insertCode(key, true); + } + } + + get('upf-container').addEventListener('scroll', FluxBB.upload.listHandler, false); + var event; + if (typeof Event === 'function') { + event = new Event('scroll'); + } else { + event = document.createEvent('Event'); + event.initEvent('scroll', false, false); + } + get('upf-container').dispatchEvent(event); + } + + function loadFileData() { + get('upf-container').removeEventListener('scroll', FluxBB.upload.listHandler, false); + + if (page >= pages) { + return; + } + ++page; + + postData({action: 'view', p: page}, function (data) { + updateData(data); + }, function (status, text) { + alert(text); + }); + } + + function addFileToGallery(key, data) { + if (key in files) { + return; + } + var max = ''; + for (var cur in files) { + if (key > cur && cur > max) { + max = cur; + } + } + var node = files['-'].link.cloneNode(true); + node.id = 'upf-' + key; + + var name = node.querySelector('.upf-name'); + name.title = data.filename; + name.querySelector('span').textContent = data.alt; + + node.querySelector('.upf-size').querySelector('span').textContent = data.size; + + var url = node.querySelector('.upf-file').querySelector('a'); + url.href = data.url; + var child = url.querySelector('span'); + if (data.mini) { + url.removeChild(child); + var child = doc.createElement('img'); + child.src = data.mini; + child.alt = data.alt; + url.appendChild(child); + } else { + child.textContent = data.alt; + } + + node.querySelector('.upf-delete').querySelector('a').addEventListener('click', FluxBB.upload.actionHandler, false); + node.querySelector('.upf-insert').querySelector('a').addEventListener('click', FluxBB.upload.actionHandler, false); + if (data.mini) { + node.querySelector('.upf-insert-t').querySelector('a').addEventListener('click', FluxBB.upload.actionHandler, false); + } else { + node.querySelector('.upf-insert-t').style.display = 'none'; + } + + files[max].link.parentNode.insertBefore(node, files[max].link); + data.link = node; + files[key] = data; + } + + function setLegend(size, percent) + { + try { + var rgb = 'rgb(' + Math.ceil((percent > 50 ? 50 : percent)*255/50) + ', ' + Math.ceil((percent < 50 ? 50 : 100 - percent)*255/50) + ', 0)', + legend = get('upf-legend'), + div = legend.querySelector('div'), + span = div.querySelector('span'); + legend.style.borderColor = div.style.backgroundColor = rgb; + div.style.width = span.textContent = percent + '%'; + } catch (e) {} + try { + get('upf-legend-p').querySelector('span').textContent = size; + } catch (e) {} + } + + function deleteFile(key) { + if (!confirm(FluxBB.uploadvars.lang.confirmation)) { + return; + } + + var file = files[key]; + + file.link.classList.add('upf-removal'); + + postData({action: 'delete', file: file.filename, p: page}, function (data) { + file.link.parentNode.removeChild(file.link); + file.link = null; + delete files[key]; + updateData(data); + }, function (status, text) { + file.link.classList.remove('upf-removal'); + alert(text); + }); + } + + function insertCode(key, thumb) { + var file = files[key]; + thumb = thumb && file.mini; + + if (thumb) { + insertText('', '[url=' + file.url + '][img]' + file.mini + '[/img][/url]', ''); + } else if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].indexOf(file.ext) > -1) { + insertText('', '[img]' + file.url + '[/img]', ''); + } else { + insertText('[url=' + file.url + ']', '[/url]', file.filename); + } + } + + function insertText(open, close, text) { + textarea.focus(); + // all and IE9+ + if ('selectionStart' in textarea) { + var len = textarea.value.length, + sp = Math.min(textarea.selectionStart, len), // IE bug + ep = Math.min(textarea.selectionEnd, len); // IE bug + + textarea.value = textarea.value.substring(0, sp) + + open + + (sp == ep ? text : textarea.value.substring(sp, ep)) + + close + + textarea.value.substring(ep); + + textarea.selectionStart = textarea.selectionEnd = ep + close.length + open.length + (sp == ep ? text.length : 0); + } + // IE9- + else if (doc.selection && doc.selection.createRange) { + var sel = doc.selection.createRange(); + sel.text = open + (!sel.text ? text : sel.text) + close; + } + textarea.focus(); + } +//*********************// + return { + init : function () { + if (0 !== state) { + return false; + } + state = -1; + + doc.removeEventListener("DOMContentLoaded", FluxBB.upload.init, false); + + textarea = doc.getElementsByName('req_message')[0]; + if (textarea && false !== findAnchor(textarea)) { + var bblinks = anchor.querySelector('.bblinks'); + if (bblinks) { + var link = createStartLink(bblinks); + link.addEventListener('click', FluxBB.upload.clickStart, false); + state = (typeof FormData === 'undefined') ? 1 : 2; + } + } + }, + + clickStart : function (event) { + event.preventDefault(); + switch (state) { + case 1: + popUp(FluxBB.uploadvars.action); + break; + case 2: + initLoader(); + state = 3; + break; + } + }, + + listHandler : function (event) { + var list = event.currentTarget; + if (list.scrollWidth - list.scrollLeft - list.clientWidth < 140) { + loadFileData(); + } + }, + + actionHandler : function (event) { + event.preventDefault(); + var target = event.currentTarget.parentNode, + cl = target.className, + key = target.parentNode.id.substring(4); + + if (!(key in files)) { + return; + } + + if (cl.indexOf('delete') > -1) { + deleteFile(key); + } else if (cl.indexOf('insert-t') > -1) { + insertCode(key, true) + } else if (cl.indexOf('insert') > -1) { + insertCode(key, false) + } + }, + + buttonHandler : function(event) { + var event; + try { + event = new MouseEvent('click'); + } catch (e) { + event = document.createEvent('MouseEvent'); + event.initEvent('click', false, false); + } + get('upfile').dispatchEvent(event); + }, + + changeHandler : function(event) { + var files = event.target.files; + if (1 !== files.length) { + return; + } + + var file = files[0]; + if (file.size > FluxBB.uploadvars.maxsize) { + alert(FluxBB.uploadvars.lang.large); + } else if (FluxBB.uploadvars.exts.indexOf(file.name.match(/\.([^.]*)$/)[1].toLowerCase()) < 0) { + alert(FluxBB.uploadvars.lang.bad_type); + } else { + var form = new FormData(get('upf-dataform')); + get('upf-button').classList.add('upf-uploading'); + postData(form, function (data) { + get('upf-button').classList.remove('upf-uploading'); + updateData(data, true); + }, function (status, text) { + get('upf-button').classList.remove('upf-uploading'); + alert(text); + }); + } + } + }; +}(document, window)); + +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", FluxBB.upload.init, false); +} diff --git a/lang/English/upload.php b/lang/English/upload.php new file mode 100644 index 0000000..8f8aa9a --- /dev/null +++ b/lang/English/upload.php @@ -0,0 +1,92 @@ +<?php + +$lang_up = array( +'No upfiles' => 'No upload.', +'Error' => '<strong>Error</strong> : ', +'Error DB' => 'Unable to insert in table %s', +'Error DB ins-up' => 'Error in the DB insert/update', +'Error space' => 'You exceeded your storage space. Delete files and try again.', +'Error delete' => 'Error during the file delete.', +'Error img' => 'Invalid format of the picture. Or the server doesn\'t support processing of pictures.', +'Error no mod img' => 'The picture has crash at updating.', +'Error open' => 'Uploaded file doesn\'t open.', +'Error inject' => 'Uploaded file contains the forbidden string. Archive this file and try again, Or speak to administrator.', +'Error usage' => 'File used in %d post(s).', + +'Redirect' => 'Options updated. Redirecting …', +'Install info' => 'Prepare the database and cache to operate Uploadile.', +'Install' => 'Install', +'Update info' => 'Update the cache. (default values)', +'Update' => 'Update', +'Uninstall info' => 'Restore the DB and modify the cache to uninstall Uploadile.', +'Uninstall' => 'Uninstall', + +'configuration' => 'Configuration', +'plugin_desc' => 'This plugin gives the chance to operate uploading of files.', +'legend_2' => 'Setup of pictures', +'laws' => 'File type allowed. Separate with a comma (,).', +'thumb' => 'Activate thumbnails', +'thumb_size' => 'Thumbs size: ', +'quality' => 'Quality: ', +'maxsize_member' => 'Max size members can upload (MBytes).', +'limit_member' => 'Space allocated to members (MBytes).', +'px' => 'Pixel', +'kbytes' => 'KBytes', +'pictures' => 'Pictures', +'for pictures' => 'For files greater than', +'Install quality' => 'Install quality:', +'Size not more' => 'Size not more (WxH):', +'to jpeg' => 'Convert to jpeg', + +'Redirect delete' => 'File(s) deleted with success. Redirecting …', +'Redirect upload' => 'File uploaded. Redirecting …', + +'uploadile' => 'My uploads', +'titre_2' => 'Upload a file', +'titre_4' => 'My uploads', +'popup_title' => 'File manager', + +'info_2' => '%1$s (%2$s max file size)', +'info_4' => 'Storage space used: <span>%s</span> of %s allowed.', +'legend' => 'File', +'fichier' => 'Select a file', + +'th0' => 'Username', +'th1' => 'File name', +'th2' => 'Preview', +'no_preview' => 'None', +'Member files' => 'Member files (new above)', + +'legend_1' => 'Convert', +'convert' => 'Convert', +'mo' => 'Value in MB', +'ko' => 'Value in KB', +'o' => 'Value in B', +'texte' => 'Your text here', +'delete' => 'Delete', +'delete file' => 'Do you want to delete this file?', +'insert' => 'Insert', +'insert_thumb' => 'Insert thumbnail', +'update_thumb' => 'Update thumbs', + +'upfiles' => 'Uploads', + +'groups' => 'Adjustment of groups', +'group' => 'Group', + +// Avatar upload stuff +'Bad type' => 'The file you tried to upload is not of an allowed type.', +'Too large' => 'The file you tried to upload is larger than the maximum allowed', +'Move failed' => 'The server was unable to save the uploaded file.', +'Unknown failure' => 'An unknown error occurred.', +'Upload' => 'Upload', + +'UPLOAD_ERR_INI_SIZE' => 'The uploaded file exceeds the upload_max_filesize directive in php.ini.', +'UPLOAD_ERR_FORM_SIZE' => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', +'UPLOAD_ERR_PARTIAL' => 'The uploaded file was only partially uploaded.', +'UPLOAD_ERR_NO_FILE' => 'No file was uploaded.', +'UPLOAD_ERR_NO_TMP_DIR' => 'Missing a temporary folder.', +'UPLOAD_ERR_CANT_WRITE' => 'Failed to write file to disk.', +'UPLOAD_ERR_EXTENSION' => 'A PHP extension stopped the file upload.', +'UPLOAD_ERR_UNKNOWN' => 'Unknown upload error.', +); diff --git a/lang/French/upload.php b/lang/French/upload.php new file mode 100644 index 0000000..b6113d7 --- /dev/null +++ b/lang/French/upload.php @@ -0,0 +1,92 @@ +<?php + +$lang_up = array( +'No upfiles' => 'Pas de téléchargement.', +'Error' => '<strong>Erreur</strong> : ', +'Error DB' => 'Impossible d\'insérer dans la table %s', +'Error DB ins-up' => 'Erreur pendant la mise à jour de la base de données', +'Error space' => 'Vous avez dépassé votre espace de stockage autorisé. Supprimez des fichiers et essayez à nouveau.', +'Error delete' => 'Erreur pendant lors de la supression du fichier, essayez à nouveau.', +'Error img' => 'Format invalide d\'image. Ou le serveur ne supporte pas le traitement d\'images.', +'Error no mod img' => 'L\'image a été endommagée pendant la mise à jour.', +'Error open' => 'Le fichier téléchargé ne s\'ouvre pas.', +'Error inject' => 'Le fichier envoyé contient la ficelle défendue. Compressez ce fichier et essayez à nouveau ou contacter à l\'administrateur.', +'Error usage' => 'File used in %d post(s).', + +'Redirect' => 'Options mises à jour. Redirection …', +'Install info' => 'Préparation de la base de données et du cache pour l\'installation Uploadile.', +'Install' => 'Installer', +'Update info' => 'Mise à jour. (valeurs par défauts) <br />', +'Update' => 'Mis à jour', +'Uninstall info' => 'Restauration la base de données et mise à jour du cache pour la désinstallation d\'Uploadile.', +'Uninstall' => 'Désinstaller', + +'configuration' => 'Configuration', +'plugin_desc' => 'Ce plugin permet de configurer les fonctions d\'Uploadile dont vous avez besoin.', +'legend_2' => 'Choisisser vos options', +'laws' => 'Types de fichier autorisés. Séparer avec des virgules (,).', +'thumb' => 'Activer les miniatures', +'thumb_size' => 'Taille de la miniature: ', +'quality' => 'Qualité: ', +'maxsize_member' => 'La taille maximum que les membres peuvent télécharger (MBytes).', +'limit_member' => 'Espace alloué aux membres (MBytes).', +'px' => 'Pixel', +'kbytes' => 'KBytes', +'pictures' => 'Images', +'for pictures' => 'Pour une image en poids, c\'est plus', +'Install quality' => 'Qualité de l\'image:', +'Size not more' => 'Taille pas plus grande (HxL):', +'to jpeg' => 'Convertir en jpeg', + +'Redirect delete' => 'Fichier(s) supprimé(s) avec succés. Redirection …', +'Redirect upload' => 'Fichier téléchargé. Redirection …', + +'uploadile' => 'Mes téléchargements', +'titre_2' => 'Télécharger un fichier', +'titre_4' => 'Mes téléchargements', +'popup_title' => 'Gestion des fichiers', + +'info_2' => '%1$s (max %2$s)', +'info_4' => 'Espace de stockage utilisé : <span>%s</span> en %s', +'legend' => 'Fichier', +'fichier' => 'Sélectionner un fichier', + +'th0' => 'Nom', +'th1' => 'Url du fichier', +'th2' => 'Prévisualiser', +'no_preview' => 'Aucune', +'Member files' => 'Fichiers des membres (nouveaux ci-dessus)', + +'legend_1' => 'Conversion', +'convert' => 'Convertir', +'mo' => 'Valeur en MB', +'ko' => 'Valeur en KB', +'o' => 'Valeur en B', +'texte' => 'Placer votre texte ici', +'delete' => 'Supprimer', +'delete file' => 'Voulez-vous supprimer ce fichier?', +'insert' => 'Insérer', +'insert_thumb' => 'Insérer une miniature', +'update_thumb' => 'Mettre à jour les miniatures', + +'upfiles' => 'Téléchargements', + +'groups' => 'Le réglage des groupes', +'group' => 'Groupe', + +// Avatar upload stuff +'Bad type' => 'Ce type de fichier n\'est pas autorisé.', +'Too large' => 'La taille du fichier dépasse le maximum autorisé', +'Move failed' => 'Le serveur n\'a pas pu enregistrer le fichier envoyé. Contactez l\'administrateur', +'Unknown failure' => 'Erreur inconnue. Merci de réessayer.', +'Upload' => 'Envoyer', + +'UPLOAD_ERR_INI_SIZE' => 'La taille du fichier téléchargé excède la valeur de upload_max_filesize, configurée dans le php.ini.', +'UPLOAD_ERR_FORM_SIZE' => 'La taille du fichier téléchargé excède la valeur de MAX_FILE_SIZE, qui a été spécifiée dans le formulaire HTML.', +'UPLOAD_ERR_PARTIAL' => 'Le fichier n\'a été que partiellement téléchargé.', +'UPLOAD_ERR_NO_FILE' => 'Aucun fichier n\'a été téléchargé.', +'UPLOAD_ERR_NO_TMP_DIR' => 'Un dossier temporaire est manquant.', +'UPLOAD_ERR_CANT_WRITE' => 'Échec de l\'écriture du fichier sur le disque.', +'UPLOAD_ERR_EXTENSION' => 'Une extension PHP a arrêté l\'envoi de fichier.', +'UPLOAD_ERR_UNKNOWN' => 'Erreur de téléchargement inconnue.', +); diff --git a/lang/German/upload.php b/lang/German/upload.php new file mode 100644 index 0000000..2bdf9c6 --- /dev/null +++ b/lang/German/upload.php @@ -0,0 +1,92 @@ +<?php + +$lang_up = array( +'No upfiles' => 'Keine Dateien vorhanden.', +'Error' => '<strong>Fehler</strong> : ', +'Error DB' => 'Konnte in die Tabelle %s nichts einfügen', +'Error DB ins-up' => 'Fehler beim Aktualisieren der Datenbank', +'Error space' => 'Der dir zugewiesene Speicherplatz ist überfüllt. Lösche ein paar Dateien und versuch es dann noch einmal.', +'Error delete' => 'Fehler während des Löschens der Datei.', +'Error img' => 'Ungültiges Bildformat. Oder der Server unterstützt keine Bildverarbeitung.', +'Error no mod img' => 'Das Bild wurde während der Aktualisierung zerstört.', +'Error open' => 'Die hochgeladene Datei konnte nicht geöffnet werden.', +'Error inject' => 'Uploaded file contains the forbidden string. Archiviere diese Datei und versuch es noch einmal. Oder sprich mit dem Administrator.', +'Error usage' => 'File used in %d post(s).', + +'Redirect' => 'Optionen aktualisiert. Leite weiter …', +'Install info' => 'Bereitet die Datenbank und den Cache für den Einsatz von Uploadile vor.', +'Install' => 'Installieren', +'Update info' => 'Den Cache aktualisieren. (voreingestellte Werte)', +'Update' => 'Aktualisieren', +'Uninstall info' => 'Die Datenbank zurücksetzen und den Zwischenspeicher modifizieren, um Uploadile zu deinstallieren.', +'Uninstall' => 'Deinstallieren', + +'configuration' => 'Konfiguration', +'plugin_desc' => 'Über dieses Plugin kannst du Uploadile an deine Bedürfnisse anpassen.', +'legend_2' => 'Wähle deine Optionen', +'laws' => 'Erlaubte Dateitypen. Mit Kommata (,) trennen.', +'thumb' => 'Vorschaubilder aktivieren', +'thumb_size' => 'Größe Vorschaubilder: ', +'quality' => 'Qualität: ', +'maxsize_member' => 'Maximale Dateigröße, die von Mitgliedern hochgeladen werden darf (MBytes)', +'limit_member' => 'Größe des Speicherplatzes für Mitglieder (MBytes)', +'px' => 'Pixel', +'kbytes' => 'KBytes', +'pictures' => 'Bilder', +'for pictures' => 'Bilder, die größer sind als', +'Install quality' => 'Konvertierungsqualität:', +'Size not more' => 'Nicht größer als (BxH):', +'to jpeg' => 'Ins JPEG-Format konvertieren', + +'Redirect delete' => 'Datei(en) gelöscht. Leite weiter …', +'Redirect upload' => 'Datei hochgeladen. Leite weiter …', + +'uploadile' => 'Meine hochgeladenen Dateien', +'titre_2' => 'Eine Datei hochladen', +'titre_4' => 'Meine hochgeladenen Dateien', +'popup_title' => 'Dateiverwaltung', + +'info_2' => '%1$s (max %2$s)', +'info_4' => 'Aktuell belegter Speicherplatz: <span>%s</span> in %s', +'legend' => 'Datei', +'fichier' => 'Eine Datei auswählen', + +'th0' => 'Mitgliedsname', +'th1' => 'Dateiname', +'th2' => 'Vorschau', +'no_preview' => 'Keine', +'Member files' => 'Dateien der Mitglieder (neueste zuerst)', + +'legend_1' => 'Konvertierung', +'convert' => 'Konvertieren', +'mo' => 'Wert in MB', +'ko' => 'Wert in KB', +'o' => 'Wert in B', +'texte' => 'Dein Text hier', +'delete' => 'Löschen', +'delete file' => 'Möchten Sie diese Datei löschen?', +'insert' => 'Einfügen', +'insert_thumb' => 'Vorschaubild einfügen', +'update_thumb' => 'Vorschaubild aktualisieren', + +'upfiles' => 'Dateien hochladen', + +'groups' => 'Anpassung von Gruppen', +'group' => 'Gruppen', + +// Avatar +'Bad type' => 'Die ausgewählte Datei hat ein falsches Format.', +'Too large' => 'Die ausgewählte Datei ist größer als maximal erlaubt', +'Move failed' => 'Der Server konnte die hochgeladene Datei nicht speichern. Bitte kontaktiere den Administrator unter', +'Unknown failure' => 'Ein unbekannter Fehler ist aufgetreten. Bitte versuche es noch einmal.', +'Upload' => 'Hochladen', + +'UPLOAD_ERR_INI_SIZE' => 'Die hochgeladene Datei überschreitet die in der Anweisung upload_max_filesize in php.ini festgelegte Größe.', +'UPLOAD_ERR_FORM_SIZE' => 'Die hochgeladene Datei überschreitet die in dem HTML Formular mittels der Anweisung MAX_FILE_SIZE angegebene maximale Dateigröße.', +'UPLOAD_ERR_PARTIAL' => 'Die Datei wurde nur teilweise hochgeladen.', +'UPLOAD_ERR_NO_FILE' => 'Es wurde keine Datei hochgeladen.', +'UPLOAD_ERR_NO_TMP_DIR' => 'Fehlender temporärer Ordner.', +'UPLOAD_ERR_CANT_WRITE' => 'Speichern der Datei auf die Festplatte ist fehlgeschlagen.', +'UPLOAD_ERR_EXTENSION' => 'Eine PHP Erweiterung hat den Upload der Datei gestoppt.', +'UPLOAD_ERR_UNKNOWN' => 'Unbekannter Upload-Fehler.', +); diff --git a/lang/Russian/upload.php b/lang/Russian/upload.php new file mode 100644 index 0000000..316266a --- /dev/null +++ b/lang/Russian/upload.php @@ -0,0 +1,92 @@ +<?php + +$lang_up = array( +'No upfiles' => 'Нет загруженных файлов.', +'Error' => '<strong>Ошибка</strong> : ', +'Error DB' => 'Не могу добавить поле в таблицу %s', +'Error DB ins-up' => 'Ошибка при добавлении/обновлении записи', +'Error space' => 'Вы превысили лимит отведенного места под ваши файлы.', +'Error delete' => 'При удалении одного из файлов возникла ошибка.', +'Error img' => 'Неверный формат картинки. Или сервер не поддерживает обработку картинок.', +'Error no mod img' => 'Модификация картинки не удалась.', +'Error open' => 'Загруженный файл не открывается.', +'Error inject' => 'Загруженный файл содержит запрещенную последовательность символов. Заархивируйте файл и попробуйте снова, или обратитесь к администрации форума.', +'Error usage' => 'Файл используется в %d сообщении(ях).', + +'Redirect' => 'Настройки изменены. Переадресация …', +'Install info' => 'Плагин внесет нужные изменения в базу форума и обновит кэш.', +'Install' => 'Установить', +'Update info' => 'Плагин установит настройки по умолчанию.', +'Update' => 'Обновить', +'Uninstall info' => 'Плагин удалит из базы форума изменения и обновит кэш.', +'Uninstall' => 'Удалить', + +'configuration' => 'Настройки', +'plugin_desc' => 'Этот плагин дает возможность управлять загрузкой файлов.', +'legend_2' => 'Настройка картинок', +'laws' => 'Разрешенные типы файлов. Разделяются запятыми (,).', +'thumb' => 'Использовать превьюшки', +'thumb_size' => 'Высота превью: ', +'quality' => 'Качество: ', +'maxsize_member' => 'Максимальный размер файла для загрузки (Мбайт).', +'limit_member' => 'Лимит дискового пространства (Мбайт).', +'px' => 'точек', +'kbytes' => 'Кбайт', +'pictures' => 'Картинки', +'for pictures' => 'Для картинки весом больше', +'Install quality' => 'Установить качество:', +'Size not more' => 'Размер не более (ШxВ):', +'to jpeg' => 'Конвертировать в jpeg', + +'Redirect delete' => 'Удаление файла(ов) прошло успешно. Переадресация …', +'Redirect upload' => 'Файл загружен. Переадресация …', + +'uploadile' => 'Мои загрузки', +'titre_2' => 'Загрузка файла', +'titre_4' => 'Мои загрузки', +'popup_title' => 'Управление файлами', + +'info_2' => '%1$s (макс. %2$s)', +'info_4' => 'Использовано: <span>%s</span> из %s', +'legend' => 'Файл', +'fichier' => 'Выберите файл', + +'th0' => 'Пользователь', +'th1' => 'Имя файла', +'th2' => 'Превью', +'no_preview' => 'нет', +'Member files' => 'Файлы пользователей (сначала новые)', + +'legend_1' => 'Конвертация данных', +'convert' => 'пересчитать', +'mo' => 'Величина в Мб', +'ko' => 'Величина в Кб', +'o' => 'Величина в байтах', +'texte' => 'Введите ваш текст', +'delete' => 'Удалить', +'delete file' => 'Удалить этот файл?', +'insert' => 'Вставить', +'insert_thumb' => 'Вставить превью', +'update_thumb' => 'Пересоздать превьюшки', + +'upfiles' => 'Загрузки', + +'groups' => 'Настройка групп', +'group' => 'Группа', + +// Avatar upload stuff +'Bad type' => 'Загрузка файла с используемым расширением запрещена.', +'Too large' => 'Выбранный файл больше максимально допустимых размеров', +'Move failed' => 'Сервер не смог сохранить загруженный файл.', +'Unknown failure' => 'Произошла неизвестная ошибка.', +'Upload' => 'Загрузить', + +'UPLOAD_ERR_INI_SIZE' => 'Размер принятого файла превысил максимально допустимый размер, который задан директивой upload_max_filesize конфигурационного файла php.ini.', +'UPLOAD_ERR_FORM_SIZE' => 'Размер загружаемого файла превысил значение MAX_FILE_SIZE, указанное в HTML-форме.', +'UPLOAD_ERR_PARTIAL' => 'Загружаемый файл был получен только частично.', +'UPLOAD_ERR_NO_FILE' => 'Файл не был загружен.', +'UPLOAD_ERR_NO_TMP_DIR' => 'Отсутствует временная папка.', +'UPLOAD_ERR_CANT_WRITE' => 'Не удалось записать файл на диск.', +'UPLOAD_ERR_EXTENSION' => 'PHP-расширение остановило загрузку файла.', +'UPLOAD_ERR_UNKNOWN' => 'Неизвестная ошибка загрузки.', +); diff --git a/plugins/AP_Upload.php b/plugins/AP_Upload.php new file mode 100644 index 0000000..fbf865e --- /dev/null +++ b/plugins/AP_Upload.php @@ -0,0 +1,638 @@ +<?php + +/** + * Copyright (C) 2011-2020 Visman (mio.visman@yandex.ru) + * Copyright (C) 2007 BN (bnmaster@la-bnbox.info) + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher + */ + +// Make sure no one attempts to run this script "directly" +if (! defined('PUN')) { + exit; +} + +// Tell admin_loader.php that this is indeed a plugin and that it is loaded +define('PUN_PLUGIN_LOADED', 1); +define('PLUGIN_VERSION', '3.0.3'); +define('PLUGIN_URL', pun_htmlspecialchars('admin_loader.php?plugin=' . $plugin)); +define('PLUGIN_EXTS', 'webp,jpg,jpeg,png,gif,mp3,zip,rar,7z'); +define('PLUGIN_NF', 25); + +require PUN_ROOT . 'include/upload.php'; + +// Any action must be confirmed by token +if (! empty($_POST)) { + if (function_exists('csrf_hash')) { + confirm_referrer('AP_Upload.php'); + } else { + check_csrf(isset($_POST['csrf_hash']) ? $_POST['csrf_hash'] : null); + } +} + +$sconf = [ + 'thumb' => (true === $upf_class->isResize()) ? 1 : 0, + 'thumb_size' => 100, + 'thumb_perc' => 75, + 'pic_mass' => 300, //килобайт + 'pic_perc' => 75, + 'pic_w' => 1920, + 'pic_h' => 1200, +]; + +// обновление до версии 2.3.0 +if (isset($pun_config['o_uploadile_other'])) { + if (! isset($pun_config['o_upload_config'])) { + $aconf = unserialize($pun_config['o_uploadile_other']); + $aconf['pic_mass'] = (int) ($aconf['pic_mass'] / 1024); + $pun_config['o_upload_config'] = serialize($aconf); + + $db->query('INSERT INTO ' . $db->prefix . 'config (conf_name, conf_value) VALUES(\'o_upload_config\', \'' . $db->escape($pun_config['o_upload_config']) . '\')') or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error()); + } + + $db->query('DELETE FROM ' . $db->prefix . 'config WHERE conf_name=\'o_uploadile_other\'') or error('Unable to remove config entries', __FILE__, __LINE__, $db->error());; + + if (! defined('FORUM_CACHE_FUNCTIONS_LOADED')) { + require PUN_ROOT . 'include/cache.php'; + } + + generate_config_cache(); + + $data_grs = []; + if (isset($pun_user['g_up_ext'], $pun_user['g_up_limit'], $pun_user['g_up_max'])) { + $result = $db->query('SELECT * FROM ' . $db->prefix . 'groups ORDER BY g_id') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error()); + + while ($cur_group = $db->fetch_assoc($result)) { + if ($cur_group['g_id'] == PUN_GUEST) { + continue; + } + $data_grs[$cur_group['g_id']] = [ + 'g_up_ext' => $cur_group['g_up_ext'], + 'g_up_max' => (int) ($cur_group['g_up_max'] / 10485.76), + 'g_up_limit' => (int) ($cur_group['g_up_limit'] / 1048576), + ]; + } + } + + $db->drop_field('groups', 'g_up_ext') or error('Unable to drop g_up_ext field', __FILE__, __LINE__, $db->error()); + $db->drop_field('groups', 'g_up_max') or error('Unable to drop g_up_max field', __FILE__, __LINE__, $db->error()); + $db->drop_field('groups', 'g_up_limit') or error('Unable to drop g_up_limit field', __FILE__, __LINE__, $db->error()); + + $db->add_field('groups', 'g_up_ext', 'VARCHAR(255)', false, PLUGIN_EXTS) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error()); + $db->add_field('groups', 'g_up_max', 'INT(10)', false, 0) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error()); + $db->add_field('groups', 'g_up_limit', 'INT(10)', false, 0) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error()); + + foreach ($data_grs as $g_id => $cur_group) { + $db->query('UPDATE ' . $db->prefix . 'groups SET g_up_ext=\'' . $db->escape($cur_group['g_up_ext']) . '\', g_up_limit=' . $cur_group['g_up_limit'] . ', g_up_max=' . $cur_group['g_up_max'] . ' WHERE g_id=' . $g_id) or error('Unable to update user group list', __FILE__, __LINE__, $db->error()); + } + + $db->add_field('users', 'upload_size', 'INT(10)', false, 0) or error(sprintf($lang_up['Error DB'], 'users'), __FILE__, __LINE__, $db->error()); + + if (isset($pun_user['upload'])) { + $db->query('UPDATE ' . $db->prefix . 'users SET upload_size=ROUND(upload/10485.76)') or error('Unable to update upload size of users', __FILE__, __LINE__, $db->error()); + } + + $db->drop_field('users', 'upload') or error('Unable to drop upload field', __FILE__, __LINE__, $db->error()); +} + +// Установка плагина/мода +if (isset($_POST['installation'])) { + $db->add_field('users', 'upload_size', 'INT(10)', false, 0) or error(sprintf($lang_up['Error DB'], 'users'), __FILE__, __LINE__, $db->error()); + $db->add_field('groups', 'g_up_ext', 'VARCHAR(255)', false, PLUGIN_EXTS) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error()); + $db->add_field('groups', 'g_up_max', 'INT(10)', false, 0) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error()); + $db->add_field('groups', 'g_up_limit', 'INT(10)', false, 0) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error()); + + $adm_max = (int) (min($upf_class->size(ini_get('upload_max_filesize')), $upf_class->size(ini_get('post_max_size'))) / 10485.76); + $db->query('UPDATE ' . $db->prefix . 'groups SET g_up_ext=\'' . $db->escape(PLUGIN_EXTS) . '\', g_up_limit=1024, g_up_max=' . $adm_max . ' WHERE g_id=' . PUN_ADMIN) or error('Unable to update user group list', __FILE__, __LINE__, $db->error()); + + $db->query('DELETE FROM ' . $db->prefix . 'config WHERE conf_name=\'o_upload_config\'') or error('Unable to remove config entries', __FILE__, __LINE__, $db->error());; + $db->query('INSERT INTO ' . $db->prefix . 'config (conf_name, conf_value) VALUES(\'o_upload_config\', \'' . $db->escape(serialize($sconf)) . '\')') or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error()); + + if (! defined('FORUM_CACHE_FUNCTIONS_LOADED')) { + require PUN_ROOT . 'include/cache.php'; + } + + generate_config_cache(); + + redirect(PLUGIN_URL, $lang_up['Redirect']); +} + +// Обновления параметров +else if (isset($_POST['update'])) { + $g_up_ext = isset($_POST['g_up_ext']) ? array_map('pun_trim', $_POST['g_up_ext']) : []; + $g_up_max = isset($_POST['g_up_max']) ? array_map('floatval', $_POST['g_up_max']) : []; + $g_up_limit = isset($_POST['g_up_limit']) ? array_map('intval', $_POST['g_up_limit']) : []; + + if (empty($g_up_limit)) { + $g_up_limit[PUN_ADMIN] = 1024; + $g_up_max[PUN_ADMIN] = 1024; + } + + $result = $db->query('SELECT g_id FROM ' . $db->prefix . 'groups ORDER BY g_id') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error()); + while ($cur_group = $db->fetch_assoc($result)) { + if ($cur_group['g_id'] == PUN_GUEST) { + continue; + } + + if (isset($g_up_ext[$cur_group['g_id']])) { + $g_ext = str_replace(' ', '', $g_up_ext[$cur_group['g_id']]); + $g_ext = preg_replace('%[,]+%u', ',', $g_ext); + if (preg_match('%^[0-9a-zA-Z][0-9a-zA-Z,]*[0-9a-zA-Z]$%uD', $g_ext) == 0) { + $g_ext = PLUGIN_EXTS; + } + $g_ext = strtolower($g_ext); + } else { + $g_ext = PLUGIN_EXTS; + } + + $g_max = (! isset($g_up_max[$cur_group['g_id']]) || $g_up_max[$cur_group['g_id']] < 0) ? 0 : $g_up_max[$cur_group['g_id']]; + $g_max = (int) (100 * min($g_max, $upf_class->size(ini_get('upload_max_filesize')) / 1048576, $upf_class->size(ini_get('post_max_size')) / 1048576)); + $g_lim = (! isset($g_up_limit[$cur_group['g_id']]) || $g_up_limit[$cur_group['g_id']] < 0) ? 0 : $g_up_limit[$cur_group['g_id']]; + $g_lim = min($g_lim, 20971520); + + $db->query('UPDATE ' . $db->prefix . 'groups SET g_up_ext=\'' . $db->escape($g_ext) . '\', g_up_limit=' . $g_lim . ', g_up_max=' . $g_max . ' WHERE g_id=' . $cur_group['g_id']) or error('Unable to update user group list', __FILE__, __LINE__, $db->error()); + } + + if (isset($_POST['thumb'])) { + $sconf['thumb'] = $_POST['thumb'] == '1' ? 1 : 0; + } + if (isset($_POST['thumb_size']) && $_POST['thumb_size'] > 0) { + $sconf['thumb_size'] = (int) $_POST['thumb_size']; + } + if (isset($_POST['thumb_perc']) && $_POST['thumb_perc'] > 0 && $_POST['thumb_perc'] <= 100) { + $sconf['thumb_perc'] = (int) $_POST['thumb_perc']; + } + + if (isset($_POST['pic_mass']) && $_POST['pic_mass'] >= 0) { + $sconf['pic_mass'] = (int) $_POST['pic_mass']; + } + if (isset($_POST['pic_perc']) && $_POST['pic_perc'] > 0 && $_POST['pic_perc'] <= 100) { + $sconf['pic_perc'] = (int) $_POST['pic_perc']; + } + if (isset($_POST['pic_w']) && $_POST['pic_w'] >= 100) { + $sconf['pic_w'] = (int) $_POST['pic_w']; + } + if (isset($_POST['pic_h']) && $_POST['pic_h'] >= 100) { + $sconf['pic_h'] = (int) $_POST['pic_h']; + } + + $db->query('DELETE FROM ' . $db->prefix . 'config WHERE conf_name=\'o_upload_config\'') or error('Unable to remove config entries', __FILE__, __LINE__, $db->error());; + $db->query('INSERT INTO ' . $db->prefix . 'config (conf_name, conf_value) VALUES(\'o_upload_config\', \'' . $db->escape(serialize($sconf)) . '\')') or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error()); + + if (! defined('FORUM_CACHE_FUNCTIONS_LOADED')) { + require PUN_ROOT . 'include/cache.php'; + } + + generate_config_cache(); + + redirect(PLUGIN_URL, $lang_up['Redirect']); +} + +// Удаление мода +else if (isset($_POST['restore'])) { + $db->drop_field('users', 'upload_size') or error('Unable to drop upload field', __FILE__, __LINE__, $db->error()); + $db->drop_field('groups', 'g_up_ext') or error('Unable to drop g_up_ext field', __FILE__, __LINE__, $db->error()); + $db->drop_field('groups', 'g_up_max') or error('Unable to drop g_up_max field', __FILE__, __LINE__, $db->error()); + $db->drop_field('groups', 'g_up_limit') or error('Unable to drop g_up_limit field', __FILE__, __LINE__, $db->error()); + + $db->query('DELETE FROM ' . $db->prefix . 'config WHERE conf_name=\'o_upload_config\'') or error('Unable to remove config entries', __FILE__, __LINE__, $db->error());; + + if (! defined('FORUM_CACHE_FUNCTIONS_LOADED')) { + require PUN_ROOT . 'include/cache.php'; + } + + generate_config_cache(); + + redirect(PLUGIN_URL, $lang_up['Redirect']); +} + +if (isset($pun_config['o_upload_config'])) { + $aconf = unserialize($pun_config['o_upload_config']); +} else { + $aconf = $sconf; + $aconf['thumb'] = 0; + define('PLUGIN_OFF', 1); +} + +$upf_mem = 'img/members/'; +$upf_regx = '%^img/members/(\d+)/([\w-]+)\.(\w+)$%iD'; + +// ############################################################################# + +// Удаление файлов +if (isset($_POST['delete'], $_POST['delete_f']) && is_array($_POST['delete_f'])) { + $error = false; + + if (is_dir(PUN_ROOT . $upf_mem)) { + $au = []; + foreach ($_POST['delete_f'] as $file) { + if ( + preg_match($upf_regx, $file, $matches) + && false === $upf_class->inBlackList($matches[3]) + && 'mini_' !== substr($matches[2], 0, 5) + && is_file(PUN_ROOT . $file) + ) { + if (unlink(PUN_ROOT . $file)) { + $id = (int) $matches[1]; + $au[$id] = $id; + if (is_file(PUN_ROOT . $upf_mem . $matches[1] . '/mini_' . $matches[2] . '.' . $matches[3])) { + unlink(PUN_ROOT . $upf_mem . $matches[1] . '/mini_' . $matches[2] . '.' . $matches[3]); + } + } else { + $error = true; + } + } else { + $error = true; + } + } + + if (! defined('PLUGIN_OFF')) { + foreach ($au as $user) { + // Считаем общий размер файлов юзера + $upload = (int) ($upf_class->dirSize(PUN_ROOT . $upf_mem . $user . '/') / 10485.76); + $db->query('UPDATE ' . $db->prefix . 'users SET upload_size=\'' . $upload . '\' WHERE id=' . $user) or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error()); + } + } + } + + $p = empty($_GET['p']) || $_GET['p'] < 1 ? 1 : (int) $_GET['p']; + + if ($error) { + if ($pun_config['o_redirect_delay'] < 5) { + $pun_config['o_redirect_delay'] = 5; + } + redirect(PLUGIN_URL . ($p > 1 ? '&p=' . $p : ''), $lang_up['Error'] . $lang_up['Error delete']); + } else { + redirect(PLUGIN_URL . ($p > 1 ? '&p=' . $p : ''), $lang_up['Redirect delete']); + } +} + +if (file_exists(PUN_ROOT . 'style/' . $pun_user['style'] . '/upfiles.css')) { + $s = '<link rel="stylesheet" type="text/css" href="style/' . $pun_user['style'] . '/upfiles.css" />'; +} else { + $s = '<link rel="stylesheet" type="text/css" href="style/imports/upfiles.css" />'; +} +$tpl_main = str_replace('</head>', $s . "\n</head>", $tpl_main); + +// Display the admin navigation menu +generate_admin_menu($plugin); + +$tabindex = 1; +$upf_token = function_exists('csrf_hash') ? csrf_hash('AP_Upload.php') : pun_csrf_token(); + +?> + <div id="upf-block" class="plugin blockform"> + <h2><span>Plugin Upload Files v.<?= PLUGIN_VERSION ?></span></h2> + <div class="box"> + <div class="inbox"> + <p><?= $lang_up['plugin_desc'] ?></p> + <form action="<?= PLUGIN_URL ?>" method="post"> + <p> + <input type="hidden" name="csrf_hash" value="<?= $upf_token ?>" /> +<?php + +if (defined('PLUGIN_OFF')) { + +?> + <input type="submit" name="installation" value="<?= $lang_up['Install'] ?>" /> <?= $lang_up['Install info'] ?><br /> + </p> + </form> + </div> + </div> +<?php + +} else { + $disbl = (true === $upf_class->isResize()) ? '' : '" disabled="disabled'; + $stthumb = ('' === $disbl && 1 == $aconf['thumb']) ? '' : '" disabled="disabled'; + +?> + <input type="submit" name="update" value="<?= $lang_up['Update'] ?>" /> <?= $lang_up['Update info'] ?><br /> + <input type="submit" name="restore" value="<?= $lang_up['Uninstall'] ?>" /> <?= $lang_up['Uninstall info'] ?><br /><br /> + </p> + </form> + </div> + </div> + <h2 class="block2"><span><?= $lang_up['configuration'] ?></span></h2> + <div class="box"> + <form method="post" action="<?= PLUGIN_URL ?>"> + <p class="submittop"><input type="submit" name="update" value="<?= $lang_up['Update'] ?>" tabindex="<?= $tabindex++ ?>" /></p> + <div class="inform"> + <fieldset> + <legend><?= $lang_up['legend_2'] ?></legend> + <div class="infldset"> + <table> + <tr> + <th scope="row"><label><?= $upf_class->getLibName() ?></label></th> + <td><?= pun_htmlspecialchars($upf_class->getLibVersion()) ?></td> + </tr> + <tr> + <th scope="row"><label><?= $lang_up['pictures'] ?></label></th> + <td> + <?= $lang_up['for pictures'] . "\n" ?> + <input type="text" name="pic_mass" size="8" maxlength="8" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_mass']) . $disbl ?>" /> <?= $lang_up['kbytes'] . ":\n" ?><br /> +  * <?= $lang_up['Install quality'] . "\n" ?> + <input type="text" name="pic_perc" size="4" maxlength="3" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_perc']) . $disbl ?>" /> %<br /> +  * <?= $lang_up['Size not more'] . "\n" ?> + <input type="text" name="pic_w" size="4" maxlength="4" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_w']) . $disbl ?>" /> x + <input type="text" name="pic_h" size="4" maxlength="4" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_h']) . $disbl ?>" /> <?= $lang_up['px'] . "\n" ?> + </td> + </tr> + <tr> + <th scope="row"><label><?= $lang_up['thumb'] ?></label></th> + <td> + <input type="radio" tabindex="<?= ($tabindex++) . $disbl ?>" name="thumb" value="1"<?= $aconf['thumb'] == 1 ? ' checked="checked"' : '' ?> /> <strong><?= $lang_admin_common['Yes'] ?></strong> +     + <input type="radio" tabindex="<?= ($tabindex++) . $disbl ?>" name="thumb" value="0"<?= $aconf['thumb'] == 0 ? ' checked="checked"' : '' ?> /> <strong><?= $lang_admin_common['No'] ?></strong> + <br /> +  * <?= $lang_up['thumb_size'] . "\n" ?> + <input type="text" name="thumb_size" size="4" maxlength="4" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['thumb_size']) . $disbl ?>" /> <?= $lang_up['px'] . "\n" ?><br /> +  * <?= $lang_up['quality'] . "\n" ?> + <input type="text" name="thumb_perc" size="4" maxlength="3" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['thumb_perc']) . $disbl ?>" /> % + </td> + </tr> + </table> + </div> + </fieldset> + </div> + + <div class="inform"> + <fieldset> + <legend><?= $lang_up['groups'] ?></legend> + <div class="infldset"> + <div class="inbox"> + <p>1* - <?= $lang_up['laws'] ?></p> + <p>2* - <?= $lang_up['maxsize_member'] ?></p> + <p>3* - <?= $lang_up['limit_member'] ?></p> + </div> + <table class="aligntop"> + <thead> + <tr> + <th class="tcl" scope="col"><?= $lang_up['group'] ?></th> + <th class="tc2" scope="col">1*</th> + <th class="tcr" scope="col">2*</th> + <th class="tcr" scope="col">3*</th> + </tr> + </thead> + <tbody> +<?php + + $result = $db->query('SELECT * FROM ' . $db->prefix . 'groups ORDER BY g_id') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error()); + + while ($cur_group = $db->fetch_assoc($result)) { + if ($cur_group['g_id'] != PUN_GUEST) { + if (! isset($cur_group['g_up_ext'])) { + $cur_group['g_up_max'] = $cur_group['g_up_limit'] = 0; + $cur_group['g_up_ext'] = ''; + } + +?> + <tr> + <td class="tcl"><?= pun_htmlspecialchars($cur_group['g_title']) ?></td> + <td class="tc2"><input type="text" name="g_up_ext[<?= $cur_group['g_id'] ?>]" value="<?= pun_htmlspecialchars($cur_group['g_up_ext']) ?>" tabindex="<?= $tabindex++ ?>" size="40" maxlength="255" /></td> + <td class="tcr"><input type="text" name="g_up_max[<?= $cur_group['g_id'] ?>]" value="<?= $cur_group['g_up_max'] / 100 ?>" tabindex="<?= $tabindex++ ?>" size="10" maxlength="10" /></td> + <td class="tcr"><input type="text" name="g_up_limit[<?= $cur_group['g_id'] ?>]" value="<?= $cur_group['g_up_limit'] ?>" tabindex="<?= $tabindex++ ?>" size="10" maxlength="10" /></td> + </tr> +<?php + + } + } + +?> + </tbody> + </table> + </div> + </fieldset> + </div> + + <p class="submitend"> + <input type="hidden" name="csrf_hash" value="<?= $upf_token ?>" /> + <input type="submit" name="update" value="<?= $lang_up['Update'] ?>" tabindex="<?= $tabindex++ ?>" /> + </p> + <div class="inform"> + <fieldset> + <legend><?= $lang_up['legend_1'] ?></legend> + <div class="infldset"> + <label for="mo"><?= $lang_up['mo'] ?></label> <input type="text" name="mo" id="mo" size="15" tabindex="<?= $tabindex++ ?>" /> <input type="button" value="<?= $lang_up['convert'] ?>" tabindex="<?= $tabindex++ ?>" onclick="javascript:document.getElementById('ko').value=document.getElementById('mo').value*1024; document.getElementById('o').value=document.getElementById('mo').value*1048576;" /> + <label for="ko"><?= $lang_up['ko'] ?></label> <input type="text" name="ko" id="ko" size="15" tabindex="<?= $tabindex++ ?>" /> <input type="button" value="<?= $lang_up['convert'] ?>" tabindex="<?= $tabindex++ ?>" onclick="javascript:document.getElementById('mo').value=document.getElementById('ko').value/1024; document.getElementById('o').value=document.getElementById('ko').value*1024;"/> + <label for="o"><?= $lang_up['o'] ?></label> <input type="text" name="o" id="o" size="15" tabindex="<?= $tabindex++ ?>" /> <input type="button" value="<?= $lang_up['convert'] ?>" tabindex="<?= $tabindex++ ?>" onclick="javascript:document.getElementById('mo').value=document.getElementById('o').value/1048576; document.getElementById('ko').value=(document.getElementById('o').value*1024)/1048576;"/> + </div> + </fieldset> + </div> + </form> + </div> +<?php + +} + +// ############################################################################# + +$files = []; +if (is_dir(PUN_ROOT . $upf_mem)) { + $af = []; + $ad = scandir(PUN_ROOT . $upf_mem); + + foreach($ad as $f) { + if ('.' === $f[0] || ! is_dir(PUN_ROOT . $upf_mem . $f)) { + continue; + } + + $dir = $upf_mem . $f . '/'; + $open = opendir(PUN_ROOT . $dir); + while (false !== ($file = readdir($open))) { + if ( + '.' === $file[0] + || '#' === $file[0] + || 'mini_' === substr($file, 0, 5) + || true === $upf_class->inBlackList(substr(strrchr($file, '.'), 1)) + || ! is_file(PUN_ROOT . $dir . $file) + ) { + continue; + } + + $time = filemtime(PUN_ROOT . $dir . $file) . $file . $f; + $af[$time] = $dir . $file; + } + closedir($open); + } + + unset($ad); + + if (! empty($af)) { + $num_pages = ceil(count($af) / PLUGIN_NF); + $p = (empty($_GET['p']) || $_GET['p'] < 1) ? 1 : (int) $_GET['p']; + if ($p > $num_pages) { + header('Location: ' . PLUGIN_URL . '&p=' . $num_pages . '#gofile'); + exit; + } + + $start_from = PLUGIN_NF * ($p - 1); + + // Generate paging links + $paging_links = '<span class="pages-label">' . $lang_common['Pages'] . ' </span>' . paginate($num_pages, $p, PLUGIN_URL); + $paging_links = preg_replace('%href="([^">]+)"%', 'href="$1#gofile"', $paging_links); + + krsort($af); + $files = array_slice($af, $start_from, PLUGIN_NF); + unset($af); + } +} + +?> + <h2 id="gofile" class="block2"><span><?= $lang_up['Member files'] ?></span></h2> + <div class="box"> +<?php + +if (empty($files)) { + +?> + <div class="inbox"> + <p><?= $lang_up['No upfiles'] ?></p> + </div> +<?php + +} else { + +?> + + <div class="inbox"> + <div class="pagepost"> + <p class="pagelink conl"><?= $paging_links ?></p> + </div> + </div> + + <form method="post" action="<?= PLUGIN_URL . ($p > 1 ? '&p=' . $p : '') . '#gofile' ?>"> + <div class="inform"> + <p class="submittop"> + <input type="hidden" name="csrf_hash" value="<?= $upf_token ?>" /> + <input type="submit" name="update_thumb" value="<?= $lang_up['update_thumb'] . $stthumb ?>" /> + </p> + <div class="infldset"> + <table id="upf-table" class="aligntop"> + <thead> + <tr> + <th class="upf-c1" scope="col"><?= $lang_up['th0'] ?></th> + <th class="upf-c2" scope="col"><?= $lang_up['th1'] ?></th> + <th class="upf-c3" scope="col"><?= $lang_up['th2'] ?></th> + <th class="upf-c4" scope="col"><input type="submit" value="<?= $lang_up['delete'] ?>" name="delete" tabindex="<?= $tabindex++ ?>" /></th> + </tr> + </thead> + <tfoot> + <tr> + <th class="upf-c1"><?= $lang_up['th0'] ?></th> + <th class="upf-c2"><?= $lang_up['th1'] ?></th> + <th class="upf-c3"><?= $lang_up['th2'] ?></th> + <th class="upf-c4"><input type="submit" value="<?= $lang_up['delete'] ?>" name="delete" tabindex="<?= $tabindex++ ?>" /></th> + </tr> + </tfoot> + <tbody> +<?php + + // данные по юзерам + $au = []; + foreach ($files as $file) { + if (preg_match($upf_regx, $file, $fi)) { + $id = (int) $fi[1]; + $au[$id] = $id; + } + } + $result = $db->query('SELECT id, username, group_id FROM ' . $db->prefix . 'users WHERE id IN(' . implode(',', $au) . ')') or error('Unable to fetch user information', __FILE__, __LINE__, $db->error()); + $au = $ag = []; + while ($u = $db->fetch_assoc($result)) { + $au[$u['id']] = $u['username']; + $ag[$u['id']] = $u['group_id']; + } + $db->free_result($result); + // данные по группам + $extsup = []; + $result = $db->query('SELECT * FROM ' . $db->prefix . 'groups') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error()); + while ($g = $db->fetch_assoc($result)) { + if (isset($g['g_up_ext'])) { + $extsup[$g['g_id']] = explode(',', $g['g_up_ext'] . ',' . strtoupper($g['g_up_ext'])); + } else { + $extsup[$g['g_id']] = []; + } + } + $db->free_result($result); + + $upf_img_exts = ['jpg', 'jpeg', 'gif', 'png', 'bmp', 'webp']; + foreach ($files as $file) { + if (! preg_match($upf_regx, $file, $fi)) { + continue; + } + + $fancybox = in_array(strtolower($fi[3]), $upf_img_exts) ? '" class="fancy_zoom" rel="vi001' : ''; + $dir = $upf_mem . $fi[1] . '/'; + $size_file = file_size(filesize(PUN_ROOT . $file)); + $miniature = $dir . 'mini_' . $fi[2] . '.' . $fi[3]; + + if ( + isset($_POST['update_thumb']) + && 1 == $aconf['thumb'] + && true === $upf_class->loadFile(PUN_ROOT . $file) + && true === $upf_class->isImage() + && false !== $upf_class->loadImage() + ) { + $upf_class->setImageQuality($aconf['thumb_perc']); + $scaleResize = $upf_class->resizeImage(null, $aconf['thumb_size']); + + if (false !== $scaleResize) { + if ($scaleResize < 1) { + $upf_class->saveImage(PUN_ROOT . $miniature, true); + } else { + copy(PUN_ROOT . $file, PUN_ROOT . $miniature); + chmod(PUN_ROOT . $miniature, 0644); + } + } + } + +?> + <tr> + <td class="upf-c1"><?= (isset($au[$fi[1]]) ? pun_htmlspecialchars($au[$fi[1]]) : ' ') ?></td> + <td class="upf-c2"><a href="<?= pun_htmlspecialchars($file) ?>"><?= pun_htmlspecialchars($fi[2]) ?></a> [<?= pun_htmlspecialchars($size_file) ?>].[<?= (isset($ag[$fi[1]]) && in_array($fi[3], $extsup[$ag[$fi[1]]]) ? pun_htmlspecialchars($fi[3]) : '<span style="color: #ff0000"><strong>' . pun_htmlspecialchars($fi[3]) . '</strong></span>') ?>]</td> +<?php + + if (is_file(PUN_ROOT . $miniature)) { + +?> + <td class="upf-c3"> + <a href="<?= pun_htmlspecialchars($file) . $fancybox ?>"> + <img src="<?= pun_htmlspecialchars($miniature) ?>" alt="<?= pun_htmlspecialchars($fi[2]) ?>" /> + </a> + </td> +<?php + + } else { + +?> + <td class="upf-c3"><?= $lang_up['no_preview'] ?></td> +<?php + + } + +?> + <td class="upf-c4"><input type="checkbox" name="delete_f[]" value="<?= pun_htmlspecialchars($file) ?>" tabindex="<?= $tabindex++ ?>" /></td> + </tr> +<?php + + } // end foreach + +?> + </tbody> + </table> + </div> + </div> + </form> + + <div class="inbox"> + <div class="pagepost"> + <p class="pagelink conl"><?= $paging_links ?></p> + </div> + </div> + +<?php + +} // end if + +?> + </div> + </div> +<?php diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..c9e01e2 --- /dev/null +++ b/readme.txt @@ -0,0 +1,157 @@ +## +## +## Mod title: Upload Mod +## +## Mod version: 3.0.3 +## Works on FluxBB: 1.5.11 +## Release date: 2020-07-28 +## Review date: YYYY-MM-DD (Leave unedited) +## Author: Visman (mio.visman@yandex.ru) +## On a basis "Uploadile" by bagu (https://fluxbb.org/resources/mods/uploadile/) +## +## Description: Users can upload files and pictures on a forum at directly in post. +## Юзеры могут загружать файлы и картинки на форум непосредственно при постинге сообщений. +## +## v 1.2.0 +## French is added. Thanks to Bloody. +## Has added management of the uploaded files in a profile. +## В профиль добавил возможность загрузки/удаления файлов. +## +## v 1.3.0 +## German is added. Thanks to cyberman. +## For FluxBB v.1.5.0 +## Settings for each group of users. +## Administration of files is changed. +## +## v 1.3.1 +## Fix bug in create thumbnails for .jpg and .jpe files. Thanks to Ian Stanistreet. +## +## v 1.3.2 +## For FluxBB v.1.5.1 +## Fix AP_Upload.php +## +## v 2.0 beta +## For FluxBB v.1.5.4 +## Новый вид списка загруженных файлов. +## New type of the list of the uploaded files. +## +## v 2.0.1 +## Fix AP_Upload.php. Thanks to Quy. +## +## v 2.2.0 beta +## New uploader for browsers with FormData support (https://caniuse.com/#search=FormData). +## Extended blacklist of file types for upload. +## New .htaccess for img/members/ folder. +## Automatically add bb-code to the message when uploading a file. +## +## v 2.2.1 beta +## Fix AP_Upload.php for SQLite. +## +## v 2.2.2 beta +## Updated .htaccess for img/members/ folder. +## A group of administrators can set limits for themselves. +## +## v 2.3.0 beta +## Maximum "Space allocated to members" increased from 2 GiB to 20 TiB. For 32 and 64-bit systems. +## Maximum "Max size members can upload" remained unchanged and depends on the server/PHP settings and OS bit depth. +## +## v 3.0.0 beta +## Added support for ImageMagick graphics library. +## The file mentioned in the forum posts cannot be deleted. +## The search for the mention of the file goes through the search index and further LIKE in the message. +## Admin can delete files without checks in the admin plugin. +## +## v 3.0.1 +## Minor fix: Remove double serialization during automatic reconfiguration of the modification. +## https://github.com/MioVisman/FluxBB_by_Visman/commit/61fcae2702b5981ecfe277f01792e38d6034214d +## +## v 3.0.3 +## Fix for Opera 12.18 +## Fix english language +## +## +## +## Repository URL: https://fluxbb.org/resources/mods/?s=author&t=Visman&v=all&o=name +## https://fluxbb.qb7.ru/forum/viewtopic.php?id=3380 +## +## Affected files: footer.php +## include/functions.php +## +## Affects DB: No (Yes in plugin) +## +## Notes: Russian/English/French/German +## Functions move_uploaded_file(), mkdir(), opendir() and others +## must be enabled in your Website and this one must accept +## resizing pictures with GD. +## +## DISCLAIMER: Please note that "mods" are not officially supported by +## FluxBB. Installation of this modification is done at +## your own risk. Backup your forum database and any and +## all applicable files before proceeding. +## +## + + +# +#---------[ 1. UPLOAD ]------------------------------------------------------- +# + +upfiles.php to / +img/ to /img/ +include/ to /include/ +js/ to /js/ +lang/ to /lang/ +plugins/ to /plugins/ +style/ to /style/ + +# +#---------[ 2. OPEN ]--------------------------------------------------------- +# + +footer.php + +# +#---------[ 3. FIND ]--------------------------------------------------------- +# + +ob_start(); + +# +#---------[ 4. AFTER, ADD ]--------------------------------------------------- +# + +require PUN_ROOT.'include/uploadf.php'; + +# +#---------[ 5. SAVE ]--------------------------------------------------------- +# + +footer.php + +# +#---------[ 6. OPEN ]--------------------------------------------------------- +# + +include/functions.php + +# +#---------[ 7. FIND ]--------------------------------------------------------- +# + + <li<?php if ($page == 'privacy') echo ' class="isactive"'; ?>><a href="profile.php?section=privacy&id=<?php echo $id ?>"><?php echo $lang_profile['Section privacy'] ?></a></li> + +# +#---------[ 8. AFTER, ADD ]--------------------------------------------------- +# + +<?php require PUN_ROOT.'include/uploadp.php'; ?> + +# +#---------[ 9. SAVE ]--------------------------------------------------------- +# + +include/functions.php + +# +# Adjust this plugin in Administration - Plugins menu - Upload +# diff --git a/style/imports/upfiles.css b/style/imports/upfiles.css new file mode 100644 index 0000000..e3104ba --- /dev/null +++ b/style/imports/upfiles.css @@ -0,0 +1,171 @@ +/* UpFiles +----------------------------------------------------------------*/ +#brdmain #upf-block .pagepost { + overflow: hidden; +} + +#upf-container { + overflow: auto; + padding: 0; +} + +ul#upf-list { + list-style-type: none; + margin: 0; + padding: 0; +} + +#upf-list li { + display: block; + float: left; + margin: 3px; + padding: 3px; + text-align: center; + border: 1px solid; + position: relative; +} + +.upf-fmess #upf-list-fls { + min-width: auto; +} + +.upf-fmess ul#upf-list { + white-space: nowrap; +} + +.upf-fmess #upf-list li { + display: inline-block; + float: none; +} + +.upf-but a, .upf-but a:link, .upf-but a:visited, .upf-but a:hover, .upf-but a:active, .upf-but a:focus { + text-decoration: none; +} + +.upf-file img { + max-height: 100%; + border: none; + max-width: 100%; +} + +#upf-list .upf-name { + height: 26px; + text-align: left; + word-wrap: break-word; + min-width: 120px; +} + +#upf-list .upf-size { + height: 26px; +} + +#upf-list .upf-name span, #upf-list .upf-size span { + line-height: 26px; +} + +.upf-delete { + position: absolute; + top: 0; + right: 0; +} + +.upf-insert { + position: absolute; + bottom: 0; + right: 0; +} + +.upf-insert-t { + position: absolute; + bottom: 0; + left: 0; +} + +.upf-delete span { + background: url("../../img/upf-x.png") no-repeat scroll 5px 5px; + float: right; +} + +.upf-delete .upf-loading span, +.upf-removal .upf-delete span { + background: url("../../img/loading.gif") no-repeat scroll 5px 5px; +} + +.upf-insert span { + background: url("../../img/upf-i.png") no-repeat scroll 5px 5px; + float: right; +} + +.upf-insert-t span { + background: url("../../img/upf-it.png") no-repeat scroll 5px 5px; + float: left; +} + +.upf-but a span { + height: 26px; + width: 26px; + opacity: 0.3; +} + +.upf-but a:hover span { + opacity: 1; + background-color: #999999; +} + +#upf-legend { + border: 1px solid #4E642D; + width: 100%; +} + +#upf-legend div { + border-right: 2px solid #4E642D; + background-color: #6C8A3F; + text-align: right; + width: 100%; +} + +#upf-legend div span { + filter: invert(1) grayscale(1) contrast(9); +} + +#upf-table th, #upf-table td { + text-align: center; + width: auto; +} + +#upf-table .upf-c2 { + width: 80%; + text-align: left; +} + +#upf-table .upf-c3 img { + border: none; + max-width: 150px; +} + +#upf-block #upf-table td { + vertical-align: middle; +} + +#upf-- .upf-delete, +#upf-- .upf-insert, +#upf-- .upf-insert-t { + display: none; +} + +#upf-button.upf-uploading { + display: none; +} + +#upf-button.upf-uploading + span:before { + height: 16px; + width: 26px; + background: url("../../img/loading.gif") no-repeat scroll left center; + display: inline-block; + content: " "; + vertical-align: middle; +} + +.upf-fmess #upf-- { + visibility: hidden; +} diff --git a/upfiles.php b/upfiles.php new file mode 100644 index 0000000..94d615e --- /dev/null +++ b/upfiles.php @@ -0,0 +1,732 @@ +<?php + +/** + * Copyright (C) 2011-2019 Visman (mio.visman@yandex.ru) + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher + */ + +function upf_return_json($data) +{ + global $db; + + $db->end_transaction(); + $db->close(); + + if (function_exists('forum_http_headers')) { + forum_http_headers('application/json'); + } else { + header('Content-type: application/json; charset=utf-8'); + header('Cache-Control: no-cache, no-store, must-revalidate'); + } + + exit(json_encode($data)); +} + +function upf_get_pg($key, $default = null) +{ + if (isset($_POST[$key])) { + return $_POST[$key]; + } else if (isset($_GET[$key])) { + return $_GET[$key]; + } else { + return $default; + } +} + +function upf_message($message, $no_back_link = false, $http_status = null) +{ + global $upf_ajax; + + if ($upf_ajax) { + upf_return_json(['error' => $message]); + } else { + message($message, $no_back_link, $http_status); + } +} + +function upf_redirect($destination_url, $message) +{ + global $upf_ajax, $lang_up; + + if ($upf_ajax) { + upf_return_json(['error' => $message]); + } else { + redirect($destination_url, $lang_up['Error'] . $message); + } +} + +define('PUN_ROOT', dirname(__FILE__) . '/'); +require PUN_ROOT . 'include/common.php'; + +define('PLUGIN_REF', pun_htmlspecialchars('upfiles.php')); +define('PLUGIN_NF', 25); + +$upf_ajax = ('1' == upf_get_pg('ajx')); +$upf_action = upf_get_pg('action'); +$upf_page = (int) upf_get_pg('p', 1); + +if ($pun_user['g_read_board'] == '0') { + upf_message($lang_common['No view'], false, '403 Forbidden'); +} + +if ($pun_user['is_guest'] || empty($pun_user['g_up_ext']) || empty($pun_config['o_upload_config']) || $upf_page < 1) { + upf_message($lang_common['Bad request'], false, '404 Not Found'); +} + +// Any action must be confirmed by token +if (null !== $upf_action) { + if (function_exists('csrf_hash')) { + if ($upf_ajax) { + $errors = []; + } + confirm_referrer(PLUGIN_REF); + if ($upf_ajax) { + if (! empty($errors)) { + upf_return_json(['error' => array_pop($errors)]); + } + unset($errors); + } + } else { + check_csrf(upf_get_pg('csrf_hash')); + } +} + +require PUN_ROOT . 'include/upload.php'; + +if (! isset($_GET['id'])) { + $id = $pun_user['id']; + + define('PUN_HELP', 1); + define('PLUGIN_URL', PLUGIN_REF); + define('PLUGIN_URLD', PLUGIN_URL.'?'); + $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_up['popup_title']); + $fpr = false; + $upf_exts = $pun_user['g_up_ext']; + $upf_limit = $pun_user['g_up_limit']; + $upf_max_size = $pun_user['g_up_max']; + $upf_dir_size = $pun_user['upload_size']; +} else { + $id = intval($_GET['id']); + if ($id < 2 || ($pun_user['g_id'] != PUN_ADMIN && $id != $pun_user['id'])) { + upf_message($lang_common['Bad request'], false, '404 Not Found'); + } + + $result = $db->query('SELECT u.username, u.upload_size, g.g_up_ext, g.g_up_max, g.g_up_limit FROM ' . $db->prefix . 'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id WHERE u.id=' . $id) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error()); + $user_info = $db->fetch_row($result); + + if (!$user_info) { + upf_message($lang_common['Bad request'], false, '404 Not Found'); + } + + list($usname, $upf_dir_size, $upf_exts, $upf_max_size, $upf_limit) = $user_info; + + define('PLUGIN_URL', PLUGIN_REF . '?id=' . $id); + define('PLUGIN_URLD', PLUGIN_URL . '&'); + $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Profile'], $lang_up['popup_title']); + $fpr = true; +} + +$upf_limit *= 1048576; +$upf_max_size = (int) min(10485.76 * $upf_max_size, $upf_class->size(ini_get('upload_max_filesize')), $upf_class->size(ini_get('post_max_size'))); +$upf_dir_size *= 10485.76; + +if ($pun_user['g_id'] != PUN_ADMIN && $upf_limit * $upf_max_size == 0) { + upf_message($lang_common['Bad request'], false, '404 Not Found'); +} + +$upf_percent = min(100, empty($upf_limit) ? 100 : ceil($upf_dir_size * 100 / $upf_limit)); + +$upf_dir = 'img/members/' . $id . '/'; +$upf_conf = unserialize($pun_config['o_upload_config']); +$upf_exts = explode(',', $upf_exts . ',' . strtoupper($upf_exts)); +$upf_new_files = []; + +// ############################################################################# + +// Удаление файла +if ('delete' === $upf_action) { + $error = false; + + if ( + is_dir(PUN_ROOT . $upf_dir) + && preg_match('%^([\w-]+)\.(\w+)$%', pun_trim(upf_get_pg('file')), $matches) + && false === $upf_class->inBlackList($matches[2]) + && 'mini_' !== substr($matches[1], 0, 5) + && is_file(PUN_ROOT . $upf_dir . $matches[1] . '.' . $matches[2]) + ) { + include PUN_ROOT . 'include/search_idx.php'; + $like = '/' . $upf_dir . $matches[1] . '.' . $matches[2]; + $words = split_words(utf8_strtolower($like), true); + + if (count($words) > 2) { + $words = array_diff($words, ['img', 'members']); + } + if (count($words) > 2) { + $words = array_diff($words, ['jpg', 'jpeg', 'png', 'gif', 'zip', 'rar', 'webp']); + } + + $count = count($words); + + if ($count > 0) { + if (1 == $count) { + $query = 'SELECT COUNT(m.post_id) AS numposts FROM ' . $db->prefix . 'search_words AS w INNER JOIN ' . $db->prefix . 'search_matches AS m ON m.word_id = w.id INNER JOIN ' . $db->prefix . 'posts AS p ON p.id=m.post_id WHERE w.word=\'' . $db->escape(array_pop($words)) . '\' AND p.message LIKE \'%' . $db->escape($like) . '%\''; + } else { + $query = 'SELECT COUNT(p.id) AS numposts FROM ' . $db->prefix . 'posts AS p WHERE p.id IN (SELECT m.post_id FROM ' . $db->prefix . 'search_words AS w INNER JOIN ' . $db->prefix . 'search_matches AS m ON m.word_id = w.id WHERE w.word IN (\'' . implode('\',\'', array_map([$db, 'escape'], $words)) . '\') GROUP BY m.post_id HAVING COUNT(m.post_id)=' . $count . ') AND p.message LIKE \'%' . $db->escape($like) . '%\''; + } + + $result = $db->query($query) or error('Unable to fetch search information', __FILE__, __LINE__, $db->error()); + $count = $db->result($result); + } + + if (empty($count) && unlink(PUN_ROOT . $upf_dir . $matches[1] . '.' . $matches[2])) { + if (is_file(PUN_ROOT . $upf_dir . 'mini_' . $matches[1] . '.' . $matches[2])) { + unlink(PUN_ROOT . $upf_dir . 'mini_' . $matches[1] . '.' . $matches[2]); + } + + $upf_dir_size = $upf_class->dirSize(PUN_ROOT . $upf_dir); + $upf_percent = min(100, empty($upf_limit) ? 100 : ceil($upf_dir_size * 100 / $upf_limit)); + + $db->query('UPDATE ' . $db->prefix . 'users SET upload_size=' . ((int) ($upf_dir_size / 10485.76)) . ' WHERE id=' . $id) or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error()); + } else { + $error = true; + } + } else { + $error = true; + } + + if ($error) { + if ($pun_config['o_redirect_delay'] < 5) { + $pun_config['o_redirect_delay'] = 5; + } + $message = empty($count) ? $lang_up['Error delete'] : sprintf($lang_up['Error usage'], $count); + upf_redirect(($upf_page < 2 ? PLUGIN_URL : PLUGIN_URLD . 'p=' . $upf_page ) . '#gofile', $message); + } else if (! $upf_ajax) { + redirect(($upf_page < 2 ? PLUGIN_URL : PLUGIN_URLD . 'p=' . $upf_page ) . '#gofile', $lang_up['Redirect delete']); + } +} + +// Загрузка файла +else if ('upload' === $upf_action && isset($_FILES['upfile']) && $id == $pun_user['id']) { + $upf_redir_delay = $pun_config['o_redirect_delay']; + if ($upf_redir_delay < 5) { + $pun_config['o_redirect_delay'] = 5; + } + + // Ошибка при загрузке + if (! empty($_FILES['upfile']['error'])) { + switch($_FILES['upfile']['error']) { + case UPLOAD_ERR_INI_SIZE: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_INI_SIZE']); + break; + case UPLOAD_ERR_FORM_SIZE: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_FORM_SIZE']); + break; + case UPLOAD_ERR_PARTIAL: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_PARTIAL']); + break; + case UPLOAD_ERR_NO_FILE: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_NO_FILE']); + break; + case UPLOAD_ERR_NO_TMP_DIR: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_NO_TMP_DIR']); + break; + case UPLOAD_ERR_CANT_WRITE: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_CANT_WRITE']); + break; + case UPLOAD_ERR_EXTENSION: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_EXTENSION']); + break; + default: + upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_UNKNOWN']); + break; + } + } + + if (false === $upf_class->loadFile($_FILES['upfile']['tmp_name'], $_FILES['upfile']['name'])) { + upf_redirect(PLUGIN_URL, $lang_up['Unknown failure'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); + } + + // расширение + if (! in_array($upf_class->getFileExt(), $upf_exts)) { + upf_redirect(PLUGIN_URL, $lang_up['Bad type']); + } + + // максимальный размер файла + if ($_FILES['upfile']['size'] > $upf_max_size) { + upf_redirect(PLUGIN_URL, $lang_up['Too large'] . ' (' . pun_htmlspecialchars(file_size($upf_max_size)) . ').'); + } + + // допустимое пространство + if ($_FILES['upfile']['size'] + $upf_dir_size > $upf_limit) { + upf_redirect(PLUGIN_URL, $lang_up['Error space']); + } + + // подозрительное содержимое + if (false !== $upf_class->isUnsafeContent()) { + upf_redirect(PLUGIN_URL, $lang_up['Error inject']); + } + + $upf_class->prepFileName(); + + if (! is_dir(PUN_ROOT . 'img/members/')) { + mkdir(PUN_ROOT . 'img/members', 0755); + } + if (! is_dir(PUN_ROOT . $upf_dir)) { + mkdir(PUN_ROOT . $upf_dir, 0755); + } + + $saveImage = false; + $fileinfo = false; + + // сохранение картинки + if (true === $upf_class->isImage()) { + $upf_class->setImageQuality($upf_conf['pic_perc']); + + if (false === $upf_class->loadImage()) { + upf_redirect(PLUGIN_URL, $lang_up['Error img'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); + } + + if ($_FILES['upfile']['size'] > 1024 * $upf_conf['pic_mass'] && $upf_class->isResize()) { + if (false === $upf_class->resizeImage($upf_conf['pic_w'], $upf_conf['pic_h'])) { + upf_redirect(PLUGIN_URL, $lang_up['Error no mod img']); + } + + $saveImage = true; + $fileinfo = $upf_class->saveImage(PUN_ROOT . $upf_dir . $upf_class->getFileName() . '.' . $upf_class->getFileExt(), false); + + if (false === $fileinfo) { + upf_redirect(PLUGIN_URL, $lang_up['Move failed'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); //???? + } + + // картика стала больше после ресайза + if (filesize($fileinfo['path']) > $_FILES['upfile']['size']) { + $saveImage = false; + unlink($fileinfo['path']); + } + } + } + + // сохранение файла + if (false === $saveImage) { + if (is_array($fileinfo)) { + $fileinfo = $upf_class->saveFile($fileinfo['path'], true); + } else { + $fileinfo = $upf_class->saveFile(PUN_ROOT . $upf_dir . $upf_class->getFileName() . '.' . $upf_class->getFileExt(), false); + } + + if (false === $fileinfo) { + upf_redirect(PLUGIN_URL, $lang_up['Move failed'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); //???? + } + } + + // превью + if (true === $upf_class->isImage() && 1 == $upf_conf['thumb'] && $upf_class->isResize()) { + $upf_class->setImageQuality($upf_conf['thumb_perc']); + + $scaleResize = $upf_class->resizeImage(null, $upf_conf['thumb_size']); + if (false !== $scaleResize) { + $path = PUN_ROOT . $upf_dir . 'mini_' . $fileinfo['filename'] . '.' . $fileinfo['extension']; + + if ($scaleResize < 1) { + $upf_class->saveImage($path, true); + } else { + copy($fileinfo['path'], $path); + chmod($path, 0644); + } + } + } + + $upf_dir_size = $upf_class->dirSize(PUN_ROOT . $upf_dir); + $upf_percent = min(100, empty($upf_limit) ? 100 : ceil($upf_dir_size * 100 / $upf_limit)); + $db->query('UPDATE ' . $db->prefix . 'users SET upload_size=' . ((int) ($upf_dir_size / 10485.76)) . ' WHERE id=' . $id) or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error()); + + if ($upf_ajax) { + $upf_page = 1; + $upf_new_files[$fileinfo['filename'] . '.' . $fileinfo['extension']] = true; + } else { + $pun_config['o_redirect_delay'] = $upf_redir_delay; + redirect(PLUGIN_URL, $lang_up['Redirect upload']); + } +} + +// Unknown failure +else if (($upf_ajax && 'view' !== $upf_action) || (! $upf_ajax && ! empty($_POST))) { + upf_redirect(PLUGIN_URL, $lang_up['Unknown failure']); +} + +// ############################################################################# + +$files = []; +$count = 0; +$num_pages = 1; +if (is_dir(PUN_ROOT . $upf_dir)) { + $tmp = get_base_url(true) . '/' . $upf_dir; + foreach (new DirectoryIterator(PUN_ROOT . $upf_dir) as $file) { + if (!$file->isFile() || true === $upf_class->inBlackList($file->getExtension())) { + continue; + } + + $filename = $file->getFilename(); + if ('#' === $filename[0] || 'mini_' === substr($filename, 0, 5)) { + continue; + } + + ++$count; + if (empty($upf_new_files) || isset($upf_new_files[$filename])) { + $files[$file->getMTime() . $filename] = [ + 'filename' => $filename, + 'ext' => $file->getExtension(), + 'alt' => pun_strlen($filename) > 18 ? utf8_substr($filename, 0, 16) . '…' : $filename, + 'size' => file_size($file->getSize()), + 'url' => $tmp . $filename, + 'mini' => is_file(PUN_ROOT . $upf_dir . 'mini_' . $filename) ? $tmp . 'mini_' . $filename : null, + ]; + } + } + if (! empty($files)) { + $num_pages = ceil($count / PLUGIN_NF); + if ($upf_page > $num_pages && !$upf_ajax) { + header('Location: ' . str_replace('&', '&', PLUGIN_URLD) . 'p=' . $num_pages . '#gofile'); + exit; + } + + krsort($files); + + if (empty($upf_new_files)) { + $start_from = PLUGIN_NF * ($upf_page - 1); + $files = array_slice($files, $start_from, PLUGIN_NF); + } + } +} + +if ($upf_ajax) { + upf_return_json([ + 'size' => file_size($upf_dir_size), + 'percent' => $upf_percent, + 'pages' => $num_pages, + 'files' => $files, + ]); +} + +if (! isset($page_head)) { + $page_head = []; +} + +if (file_exists(PUN_ROOT . 'style/' . $pun_user['style'] . '/upfiles.css')) { + $page_head['pmsnewstyle'] = '<link rel="stylesheet" type="text/css" href="style/' . $pun_user['style'] . '/upfiles.css" />'; +} else { + $page_head['pmsnewstyle'] = '<link rel="stylesheet" type="text/css" href="style/imports/upfiles.css" />'; +} + +define('PUN_ACTIVE_PAGE', 'profile'); +require PUN_ROOT . 'header.php'; +$tpl_main = str_replace('id="punhelp"', 'id="punupfiles"', $tpl_main); + +$tabindex = 1; + +$upf_token = function_exists('csrf_hash') ? csrf_hash() : pun_csrf_token(); + +if ($fpr) { + // Load the profile.php language file + require PUN_ROOT . 'lang/' . $pun_user['language'] . '/profile.php'; + + generate_profile_menu('upload'); +} + +if ($id == $pun_user['id']) { + +?> + <div class="blockform"> + <h2><span><?= $lang_up['titre_2'] ?></span></h2> + <div class="box"> + <form method="post" action="<?= PLUGIN_URL ?>" enctype="multipart/form-data"> + <div class="inform"> + <fieldset> + <legend><?= $lang_up['legend'] ?></legend> + <div class="infldset"> + <input type="hidden" name="csrf_hash" value="<?= $upf_token ?>" /> + <input type="hidden" name="action" value="upload" /> + <input type="hidden" name="MAX_FILE_SIZE" value="<?= $upf_max_size ?>" /> + <p><?= $lang_up['fichier'] ?></p> + <input type="file" id="upfile" name="upfile" tabindex="<?= $tabindex++ ?>" /> + <p><?= sprintf($lang_up['info_2'], pun_htmlspecialchars(str_replace([' ', ','], ['', ', '], $pun_user['g_up_ext'])), pun_htmlspecialchars(file_size($upf_max_size))) ?></p> + </div> + </fieldset> + </div> + <p class="buttons"><input type="submit" name="submit" value="<?= $lang_up['Upload'] ?>" tabindex="<?= $tabindex++ ?>" /></p> + </form> + </div> + </div> +<?php + + $tit = $lang_up['titre_4']; +} else { + $tit = pun_htmlspecialchars($usname) . ' - ' . $lang_up['upfiles']; +} + +?> + <div id="upf-block" class="block"> + <h2 id="gofile" class="block2"><span><?= $tit ?></span></h2> + <div class="box"> +<?php + +if (empty($files)) { + +?> + <div class="inbox"><p><span><?= $lang_up['No upfiles'] ?></span></p></div> +<?php + +} else { + // Generate paging links + $paging_links = '<span class="pages-label">' . $lang_common['Pages'] . ' </span>' . paginate($num_pages, $upf_page, PLUGIN_URL); + $paging_links = str_replace(PLUGIN_REF . '&', PLUGIN_REF . '?', $paging_links); + $paging_links = preg_replace('%href="([^">]+)"%', 'href="$1#gofile"', $paging_links); + +?> + <div class="inbox"> + <div id="upf-legend"> + <div style="<?= 'background-color: rgb(' . ceil(($upf_percent > 50 ? 50 : $upf_percent) * 255 / 50) . ', ' . ceil(($upf_percent < 50 ? 50 : 100 - $upf_percent) * 255 / 50) . ', 0); width:' . $upf_percent . '%;' ?>"><span><?= $upf_percent ?>%</span></div> + </div> + <p id="upf-legend-p"><?= sprintf($lang_up['info_4'], pun_htmlspecialchars(file_size($upf_dir_size)), pun_htmlspecialchars(file_size($upf_limit))) ?></p> + </div> + <div class="inbox"> + <div class="pagepost"> + <p class="pagelink conl"><?= $paging_links ?></p> + </div> + </div> + <div class="inbox"> + <div id="upf-container"> + <ul id="upf-list"> +<?php + + $upf_img_exts = ['jpg', 'jpeg', 'gif', 'png', 'bmp', 'webp']; + foreach($files as $file) { + $fb = in_array($file['ext'], $upf_img_exts) ? '" class="fancy_zoom" rel="vi001' : ''; + +?> + <li> + <div class="upf-name" title="<?= pun_htmlspecialchars($file['filename']) ?>"><span><?= pun_htmlspecialchars($file['alt']) ?></span></div> + <div class="upf-file" style="height:<?= max(intval($upf_conf['thumb_size']), 100) ?>px;"> + <a href="<?= pun_htmlspecialchars($file['url']) . $fb ?>"> +<?php if (isset($file['mini'])): ?> <img src="<?= pun_htmlspecialchars($file['mini']) ?>" alt="<?= pun_htmlspecialchars($file['alt']) ?>" /> +<?php else: ?> <span><?= pun_htmlspecialchars($file['alt']) ?></span> +<?php endif; ?> + </a> + </div> + <div class="upf-size"><span><?= pun_htmlspecialchars($file['size']) ?></span></div> + <div class="upf-but upf-delete"><a title="<?= $lang_up['delete'] ?>" href="<?= PLUGIN_URLD . 'csrf_hash=' . $upf_token . ($upf_page < 2 ? '' : '&p=' . $upf_page) . '&action=delete&file=' . pun_htmlspecialchars($file['filename']) ?>" onclick="return FluxBB.upfile.del(this);"><span></span></a></div> + </li> +<?php + + } // end foreach + +?> + </ul> + </div> + </div> + <div class="inbox"> + <div class="pagepost"> + <p class="pagelink conl"><?= $paging_links ?></p> + </div> + </div> +<?php + +} // end if + +?> + </div> + </div> +<?php + +if ($fpr) { + +?> + <div class="clearer"></div> +</div> +<?php + +} + +?> +<script type="text/javascript"> +/* <![CDATA[ */ +if (typeof FluxBB === 'undefined' || !FluxBB) {var FluxBB = {};} + +FluxBB.upfile = (function (doc, win) { + 'use strict'; + + var url, src, par, area; + + function get(elem) { + return doc.getElementById(elem); + } + + function createElement(elem) { + return (doc.createElementNS) ? doc.createElementNS('http://www.w3.org/1999/xhtml', elem) : doc.createElement(elem); + } + + function is_img(a) { + return /.+\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(a); + } + + function get_us(li) { + url = ''; + src = ''; + var div = li.getElementsByTagName('div')[1]; + if (!!div) { + var a = div.getElementsByTagName('a')[0]; + if (!!a) { + url = a.href; + var img = a.getElementsByTagName('img')[0]; + if (!!img) src = img.src; + } + } + } + + function set_button(li) { + get_us(li); + + if (!!url) { + var div = createElement('div'); + div.className = 'upf-but upf-insert'; + div.innerHTML = '<a title="<?= $lang_up['insert'] ?>" href="#" onclick="return FluxBB.upfile.ins(this);"><span></span></a>'; + li.appendChild(div); + + if (is_img(src) && src != url) { + div = createElement('div'); + div.className = 'upf-but upf-insert-t'; + div.innerHTML = '<a title="<?= $lang_up['insert_thumb'] ?>" href="#" onclick="return FluxBB.upfile.ins(this, 1);"><span></span></a>'; + li.appendChild(div); + } + } + } + + function insr(s, e, t) + { + area.focus(); + if ('selectionStart' in area) { // all new + var len = area.value.length, + sp = Math.min(area.selectionStart, len), // IE bug + ep = Math.min(area.selectionEnd, len); // IE bug + area.value = area.value.substring(0, sp) + s + (sp == ep ? t : area.value.substring(sp, ep)) + e + area.value.substring(ep); + area.selectionStart = ep + e.length + s.length + (sp == ep ? t.length : 0); + area.selectionEnd = area.selectionStart; + } else if (par.selection && par.selection.createRange) { // IE + var sel = par.selection.createRange(); + sel.text = s + (!sel.text ? t : sel.text) + e; + sel.select(); + } + win.focus(); + } + + function cr_req() { + if (win.XMLHttpRequest) { + return new XMLHttpRequest(); + } else { + try { + return new ActiveXObject('Microsoft.XMLHTTP'); + } catch (e){} + } + return !1; + } + + function orsc(req, ref) { + if (req.readyState == 4) { + ref.className = ''; + var error = true; + + if (req.status == 200) { + var data = req.responseText; + if (typeof data === 'string') { + try { + data = JSON.parse(data); + } catch (e) {} + } + if (typeof data === 'string') { + if ('{' === data.substr(0, 1) && !/"error"/.test(data)) { + error = false; + } + } else { + if ('error' in data) { + alert(data.error); + } else { + error = false; + } + } + } + + if (!error) { + ref.parentNode.parentNode.parentNode.removeChild(ref.parentNode.parentNode); + if (get('upf-list').getElementsByTagName('li').length == 0) { + win.location.reload(true); + } + } + } + } + + return { + + del : function (ref) { + if (ref.className) return !1; + if (!confirm('<?= addslashes($lang_up['delete file']) ?>')) return !1; + + ref.className = 'upf-loading'; + + var req = cr_req(); + if (req) { + req.onreadystatechange = function() { + orsc(req, ref); + }; + req.open('GET', ref.href + '&ajx=1', true); + req.send(); + + return !1; + } else + return !0; + }, + + ins : function (ref, f) { + + f = f || !1; + get_us(ref.parentNode.parentNode); + + if (f && is_img(src) && src != url) { + insr('', '[url=' + url + '][img]' + src + '[/img][/url]', ''); + } else if (is_img(url)) { + insr('', '[img]' + url + '[/img]', ''); + } else { + if (f = url.match(/.*\/img\/members\/\d+\/(.+)$/)) f = f[1]; + else f = '<?= $lang_up['texte'] ?>'; + + insr('[url=' + url + ']', '[/url]', f); + } + return !1; + }, + + run : function () { + if (!win.opener) return; + + par = win.opener.document; + area = par.getElementsByName('req_message')[0]; + if (!area) return; + + var li = get('upf-list').getElementsByTagName('li'); + for (var i in li) { + if (!!li[i].getElementsByTagName) set_button(li[i]); + } + }, + + init : function () { + if (!doc.addEventListener) { + /in/.test(doc.readyState) ? setTimeout(FluxBB.upfile.init, 100) : FluxBB.upfile.run(); + } else doc.addEventListener('DOMContentLoaded', FluxBB.upfile.run, false); + } + }; +}(document, window)); + +FluxBB.upfile.init(); +/* ]]> */ +</script> +<?php + +require PUN_ROOT . 'footer.php'; |