Forráskód Böngészése

Upload Mod v3.0.0 + related compatibility changes

Visman 5 éve
szülő
commit
04a1a32016
15 módosított fájl, 2280 hozzáadás és 1052 törlés
  1. 1 0
      footer.php
  2. 2 2
      header.php
  3. 2 11
      include/bbcode.inc.php
  4. 769 348
      include/upload.php
  5. 116 0
      include/uploadf.php
  6. 11 11
      include/uploadp.php
  7. 15 27
      js/post.js
  8. 407 0
      js/upload.js
  9. 18 12
      lang/English/upload.php
  10. 17 13
      lang/Russian/upload.php
  11. 36 20
      plugins/AP_Smilies.php
  12. 369 276
      plugins/AP_Upload.php
  13. 51 43
      profile.php
  14. 40 2
      style/imports/upfiles.css
  15. 426 287
      upfiles.php

+ 1 - 0
footer.php

@@ -18,6 +18,7 @@ ob_end_clean();
 
 // START SUBST - <pun_footer>
 ob_start();
+require PUN_ROOT.'include/uploadf.php'; // Upload mod - Visman
 
 // START быстрое переключение языка - Visman
 if (!isset($languages) || !is_array($languages))

+ 2 - 2
header.php

@@ -149,11 +149,11 @@ function process_form(the_form)
 
 }
 
-require PUN_ROOT.'include/fancybox.php';
-
 // New PMS - Visman
 require PUN_ROOT.'include/pms_new/pmsnheader.php';
 
+require PUN_ROOT.'include/fancybox.php';
+
 if (!empty($page_head))
 	echo implode("\n", $page_head)."\n";
 

+ 2 - 11
include/bbcode.inc.php

@@ -40,14 +40,6 @@ foreach ($smilies as $smileyt => $smileyi)
 $bbres = '<style type="text/css">div.grippie {background:#EEEEEE url(img/grippie.png) no-repeat scroll center 2px;border-color:#DDDDDD;border-style:solid;border-width:0pt 1px 1px;cursor:s-resize;height:9px;overflow:hidden;} .resizable-textarea textarea {display:block;margin-bottom:0pt;width:95%;height: 20%;}</style>';
 $tpl_main = str_replace('</head>', $bbres."\n".'</head>', $tpl_main);
 
-// mod upload
-$bbflagup = 0;
-if (!$pun_user['is_guest'] && !empty($pun_user['g_up_ext']))
-{
-	if ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_up_limit'] > 0 && $pun_user['g_up_max'] > 0))
-		$bbflagup = 1;
-}
-
 $page_js['j'] = 1; // for resize textarea :(
 $page_js['f']['bbcode'] = 'js/post.js';
 $page_js['c'][] = 'if (typeof FluxBB === \'undefined\' || !FluxBB) {var FluxBB = {};}
@@ -55,9 +47,8 @@ FluxBB.vars = {
 	bbDir: "'.$btndir.'",
 	bbGuest: '.($pun_user['is_guest'] ? 1 : 0).',
 	bbCIndex: '.$cur_index.',
-	bbFlagUp: '.$bbflagup.',
-	bbSmImg: ['.implode(',',$smil_i).'],
-	bbSmTxt: ['.implode(',',$smil_t).']
+	bbSmImg: ['.implode(',', $smil_i).'],
+	bbSmTxt: ['.implode(',', $smil_t).']
 };
 FluxBB.post.init();';
 

+ 769 - 348
include/upload.php

@@ -6,358 +6,779 @@
  */
 
 // 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';
-
-$gd  = extension_loaded('gd');
-$gd2 = ($gd && function_exists('imagecreatetruecolor'));
-
-$extimage = array('gif', 'jpeg', 'jpg', 'jpe', 'png', 'bmp', 'tiff', 'tif', 'swf', 'psd', 'iff', 'wbmp', 'wbm', 'xbm');
-$extforno = array('asmx', 'asp', 'aspx', 'cgi', 'dll', 'exe', 'fcgi', 'fpl', 'htaccess', 'htm', 'html', 'js', 'jsp', 'php', 'php3', 'php4', 'php5', 'php6', 'php7', 'phar', 'phps', 'phtm', 'phtml', 'pl', 'py', 'rb', 'shtm', 'shtml', 'wml', 'xml');
-
-$extimage2 = array(
-	1 => array('gif'),
-	2 => array('jpg', 'jpeg', 'jpe'),
-	3 => array('png'),
-	4 => array('swf'),
-	5 => array('psd'),
-	6 => array('bmp'),
-	7 => array('tif', 'tiff'),
-	8 => array('tif', 'tiff'),
-	9 => array('jpg', 'jpeg', 'jpe'),
-	10 => array('jpg', 'jpeg', 'jpe'),
-	11 => array('jpg', 'jpeg', 'jpe'),
-	12 => array('jpg', 'jpeg', 'jpe'),
-	13 => array('swf'),
-	14 => array('iff'),
-	15 => array('wbmp', 'wbm'),
-	16 => array('xbm'),
-);
-
-$extimageGD = array(
-	'gif' => 'gif',
-	'jpeg' => 'jpeg',
-	'jpg' => 'jpeg',
-	'jpe' => 'jpeg',
-	'png' => 'png',
-	'bmp' => 'bmp',
-	'wbmp' => 'wbmp',
-	'wbm' => 'wbmp',
-	'xbm' => 'xbm',
-);
-
-function parse_file($f)
-{
-	static $UTF8AR = null;
-
-	if (is_null($UTF8AR))
-	{
-		$UTF8AR = array(
-			'à' => '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',
-			);
-	}
-
-	$f = preg_replace('%[\x00-\x1f]%', '', $f);
-	$f = preg_replace('%[@=\' ]+%', '-', $f);
-	$f = str_replace(array_keys($UTF8AR), array_values($UTF8AR), $f);
-	$f = preg_replace('%[^\w\.-]+%', '', $f);
-
-	return $f;
+if (! defined('PUN')) {
+    exit;
 }
 
-function dir_size($dir)
-{
-	global $extforno;
-
-	$upload = 0;
-	$open = opendir(PUN_ROOT.$dir);
-	while(($file = readdir($open)) !== false)
-	{
-		if (is_file(PUN_ROOT.$dir.$file))
-		{
-			$ext = strtolower(substr(strrchr($file, '.'), 1)); // берем расширение файла
-			if ($ext != '' && $file[0] != '#' && !in_array($ext, $extforno))
-				$upload += filesize(PUN_ROOT.$dir.$file);
-		}
-	}
-	closedir($open);
-	return $upload;
-}
-
-if ($gd && !function_exists('ImageCreateFromBMP'))
-{
-	/*********************************************/
-	/* Fonction: ImageCreateFromBMP              */
-	/* Author:   DHKold                          */
-	/* Contact:  admin@dhkold.com                */
-	/* Date:     The 15th of June 2005           */
-	/* Version:  2.0B                            */
-	/*********************************************/
-
-	function ImageCreateFromBMP($filename)
-	{
-		global $gd2;
-		//Ouverture du fichier en mode binaire
-		if (! $f1 = fopen($filename,"rb")) return FALSE;
-
-		//1 : Chargement des ent�tes FICHIER
-		$FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
-		if ($FILE['file_type'] != 19778) return FALSE;
-
-		//2 : Chargement des ent�tes BMP
-		$BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
-									'/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
-									'/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
-		$BMP['colors'] = pow(2,$BMP['bits_per_pixel']);
-		if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
-		$BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
-		$BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
-		$BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
-		$BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
-		$BMP['decal'] = 4-(4*$BMP['decal']);
-		if ($BMP['decal'] == 4) $BMP['decal'] = 0;
-
-		//3 : Chargement des couleurs de la palette
-		$PALETTE = array();
-		if ($BMP['colors'] < 16777216)
-		{
-			$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
-		}
-
-		//4 : Cr�ation de l'image
-		$IMG = fread($f1,$BMP['size_bitmap']);
-		$VIDE = chr(0);
-
-		if ($gd2)
-			$res = imagecreatetruecolor($BMP['width'],$BMP['height']);
-		else
-			$res = imagecreate($BMP['width'],$BMP['height']);
-
-		$P = 0;
-		$Y = $BMP['height']-1;
-		while ($Y >= 0)
-		{
-			$X=0;
-			while ($X < $BMP['width'])
-			{
-				if ($BMP['bits_per_pixel'] == 24)
-					$COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
-				elseif ($BMP['bits_per_pixel'] == 16)
-				{
-					$COLOR = unpack("n",substr($IMG,$P,2));
-					$COLOR[1] = $PALETTE[$COLOR[1]+1];
-				}
-				elseif ($BMP['bits_per_pixel'] == 8)
-				{
-					$COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
-					$COLOR[1] = $PALETTE[$COLOR[1]+1];
-				}
-				elseif ($BMP['bits_per_pixel'] == 4)
-				{
-					$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
-					if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
-					$COLOR[1] = $PALETTE[$COLOR[1]+1];
-				}
-				elseif ($BMP['bits_per_pixel'] == 1)
-				{
-					$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
-					if     (($P*8)%8 == 0) $COLOR[1] =  $COLOR[1]        >>7;
-					elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
-					elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
-					elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
-					elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
-					elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
-					elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
-					elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
-					$COLOR[1] = $PALETTE[$COLOR[1]+1];
-				}
-				else
-					return FALSE;
-				imagesetpixel($res,$X,$Y,$COLOR[1]);
-				$X++;
-				$P += $BMP['bytes_per_pixel'];
-			}
-			$Y--;
-			$P+=$BMP['decal'];
-		}
-
-		//Fermeture du fichier
-		fclose($f1);
-
-		return $res;
-	}
-}
-
-function img_resize ($file, $dir, $name, $type, $width = 0, $height = 0, $quality = 75, $flag = false)
-{
-	global $gd, $gd2, $extimage2, $extimageGD;
-
-	if (!$gd) return 1;
-	if (!file_exists($file)) return 2;
-
-	$size = getimagesize($file);
-	if ($size === false) return 3;
-
-	$type2 = strtolower($type);
-	$type1 = (($flag && in_array($type2, array('jpeg','jpg','jpe','gif','png','bmp'))) || ($type2 == 'bmp')) ? 'jpeg' : $extimageGD[$type2];
-
-	$icfunc = 'imagecreatefrom'.$extimageGD[$extimage2[$size[2]][0]]; //  $type;
-	if (!function_exists($icfunc)) return 4;
-
-	$xr = ($width == 0) ? 1 : $width / $size[0];
-	$yr = ($height == 0) ? 1 : $height / $size[1];
-	$r = min($xr, $yr, 1);
-	$width = round($size[0] * $r);
-	$height = round($size[1] * $r);
-
-	$image = @$icfunc($file);
-	if (!isset($image) || empty($image)) return 5;
-
-	if ($gd2)
-	{
-		$idest = imagecreatetruecolor($width, $height);
-		imagefill($idest, 0, 0, 0x7FFFFFFF);
-		imagecolortransparent($idest, 0x7FFFFFFF);
-		if ($type1 == 'gif')
-		{
-			$palette = imagecolorstotal($image);
-			imagetruecolortopalette($idest, true, $palette);
-		}
-		imagecopyresampled($idest, $image, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
-		imagesavealpha($idest, true);
-	}
-	else
-	{
-		$idest = imagecreate($width, $height);
-		imagecopyresized($idest, $image, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
-	}
-
-	$icfunc = 'image'.$type1;
-	if (!function_exists($icfunc))
-	{
-		$type1 = 'jpeg';
-		$icfunc = 'image'.$type1;
-		if (!function_exists($icfunc)) return 6;
-	}
-
-	if ($flag) $type = $type1;
-
-	if ($type1 == 'png' && version_compare(PHP_VERSION, '5.1.2', '>='))
-	{
-		$quality = floor((100 - $quality) / 11);
-		@imagepng($idest, PUN_ROOT.$dir.$name.'.'.$type, $quality);
-	}
-	else if ($type1 == 'jpeg')
-		@imagejpeg($idest, PUN_ROOT.$dir.$name.'.'.$type, $quality);
-	else
-		@$icfunc($idest, PUN_ROOT.$dir.$name.'.'.$type);
-
-	imagedestroy($image);
-	imagedestroy($idest);
-
-	if (!file_exists(PUN_ROOT.$dir.$name.'.'.$type)) return 7;
-	@chmod(PUN_ROOT.$dir.$name.'.'.$type, 0644);
-
-	return array($name, $type);
+// 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';
 }
 
-function isXSSattack ($file)
+class upfClass
 {
-	global $lang_up;
-	// сканируем содержание загруженного файла
-	$fin = fopen($file, "rb");
-	if (!$fin)
-		return $lang_up['Error open'];
-
-	$buf1 = '';
-	while ($buf2 = fread($fin, 4096))
-	{
-		if (preg_match( "%<(script|html|head|title|body|table|a\s+href|img\s|plaintext|cross\-domain\-policy|embed|applet|\?php)%si", $buf1.$buf2 ))
-		{
-			fclose($fin);
-			return $lang_up['Error inject'];
-		}
-		$buf1 = substr($buf2,-30);
-	}
-	fclose($fin);
-	return false;
+    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);
+    }
 }
 
-function return_bytes ($val)
-{
-// Author: Ivo Mandalski
-	if(empty($val))return 0;
-
-	$val = trim($val);
-
-	preg_match('#([0-9]+)[\s]*([a-z]+)#i', $val, $matches);
-
-	$last = '';
-	if(isset($matches[2])){
-		$last = $matches[2];
-	}
-
-	if(isset($matches[1])){
-		$val = (int)$matches[1];
-	}
-
-	switch (strtolower($last))
-	{
-		case 'g':
-		case 'gb':
-			$val *= 1024;
-		case 'm':
-		case 'mb':
-			$val *= 1024;
-		case 'k':
-		case 'kb':
-			$val *= 1024;
-	}
-
-	return (int)$val;
-}
+$upf_class = new upfClass();

+ 116 - 0
include/uploadf.php

@@ -0,0 +1,116 @@
+<?php
+/**
+ * Copyright (C) 2011-2019 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="display: none;">
+	<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>&#160;</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>&#160;</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
+
+	}
+}

+ 11 - 11
include/uploadp.php

@@ -1,23 +1,23 @@
 <?php
 
 /**
- * Copyright (C) 2011-2013 Visman (mio.visman@yandex.ru)
+ * 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'))
+if (! defined('PUN')) {
 	exit;
+}
 
-if (isset($pun_user['g_up_ext']))
-{
-	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';
+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";
+		echo "\t\t\t\t\t" . '<li' . (($page == 'upload') ? ' class="isactive"' : '') . '><a href="upfiles.php?id=' . $id . '">' . $lang_up['upfiles'] . '</a></li>' . "\n";
 	}
 }

+ 15 - 27
js/post.js

@@ -1,9 +1,9 @@
-// post.js v2.1.1 Copyright (C) 2014-2016 Visman (mio.visman@yandex.ru)
+// post.js v2.2.0 Copyright (C) 2014-2019 Visman (mio.visman@yandex.ru)
 if (typeof FluxBB === 'undefined' || !FluxBB) {var FluxBB = {};}
 
 FluxBB.post = (function (doc, win) {
 	'use strict';
-	
+
 	var nameusers = [],
 			bbcode = [],
 			lang = [],
@@ -52,14 +52,14 @@ FluxBB.post = (function (doc, win) {
 		}
 		return !1;
 	}
-	
+
 	function check_apq () {
 		if (apq_id != -1)	{
 			get('pq' + apq_id).innerHTML = apq_temp;
 			apq_id = -1;
 		}
 	}
-	
+
 	function orsc(req) {
 		if (req.readyState == 4) {
 			check_apq();
@@ -80,7 +80,7 @@ FluxBB.post = (function (doc, win) {
 		}
 		return html;
 	}
-	
+
 	function ColorMapBB() {
 		var colors = [], a = ['00', '33', '66', '99', 'cc', 'ff'];
 		for (var x = 0; x < 6; x++) {
@@ -106,7 +106,7 @@ FluxBB.post = (function (doc, win) {
 		init : function () {
 			if (fls) return false;
 			fls = true;
-			
+
 			textarea = doc.getElementsByName('req_message')[0];
 			if (typeof textarea === 'undefined') return false;
 
@@ -136,11 +136,11 @@ FluxBB.post = (function (doc, win) {
 				{i:'smile.png', a:'smileys', f:'return FluxBB.post.overlay(this, \'bbcode_smileys\');'}];
 
 			if (doc.getElementsByTagName('html')[0].getAttribute('lang') == 'ru') {
-			  lang = {'b':'Полужирный текст', 'i':'Наклонный текст', 'u':'Подчеркнутый текст', 's':'Зачёркнутый текст', 'center':'По центру', 'right':'По правому краю', 'justify':'По ширине', 'mono':'Моношрифт', 'url':'Ссылка', 'email':'Электронная почта', 'img':'Картинка', 'list':'Список', '*':'Элемент списка', 'quote':'Цитата', 'code':'Блок кода', 'hr':'Горизонтальная линия', 'color':'Цвет текста', 'spoiler':'Скрытый текст', 'smileys':'Смайлы', 'upfiles':'Загрузки', 'QQ':'Цитировать', 'Loading':'Загрузка...', 'Must':'Вы должны выделить текст для цитирования'};
+			  lang = {'b':'Полужирный текст', 'i':'Наклонный текст', 'u':'Подчеркнутый текст', 's':'Зачёркнутый текст', 'center':'По центру', 'right':'По правому краю', 'justify':'По ширине', 'mono':'Моношрифт', 'url':'Ссылка', 'email':'Электронная почта', 'img':'Картинка', 'list':'Список', '*':'Элемент списка', 'quote':'Цитата', 'code':'Блок кода', 'hr':'Горизонтальная линия', 'color':'Цвет текста', 'spoiler':'Скрытый текст', 'smileys':'Смайлы', 'QQ':'Цитировать', 'Loading':'Загрузка...', 'Must':'Вы должны выделить текст для цитирования'};
 			} else {
-			  lang = {'b':'Bold text', 'i':'Italic text', 'u':'Underlined text', 's':'Strike-through text', 'center':'Center', 'right':'Right', 'justify':'Justify', 'mono':'Mono', 'url':'Link', 'email':'E-mail', 'img':'Image', 'list':'List', '*':'List element', 'quote':'Quote', 'code':'Code block', 'hr':'Horizontal line', 'color':'Colour of text', 'spoiler':'Spoiler', 'smileys':'Smileys', 'upfiles':'Uploads', 'QQ':'Quote', 'Loading':'Loading...', 'Must':'You must select text before quoting'};
+			  lang = {'b':'Bold text', 'i':'Italic text', 'u':'Underlined text', 's':'Strike-through text', 'center':'Center', 'right':'Right', 'justify':'Justify', 'mono':'Mono', 'url':'Link', 'email':'E-mail', 'img':'Image', 'list':'List', '*':'List element', 'quote':'Quote', 'code':'Code block', 'hr':'Horizontal line', 'color':'Colour of text', 'spoiler':'Spoiler', 'smileys':'Smileys', 'QQ':'Quote', 'Loading':'Loading...', 'Must':'You must select text before quoting'};
 			}
-			
+
 			var div = createElement('div');
 			div.setAttribute('id', 'bbcode_bar');
 
@@ -173,7 +173,7 @@ FluxBB.post = (function (doc, win) {
 					if (typeof dt !== 'undefined') {
 						var a = dt.innerHTML;
 						var n = a.replace(/<[^>]+>/g, '');
-						
+
 						// Decode html special chars
 						nameusers[id] = n.replace(/&lt;/g, '<')
 							.replace(/&gt;/g, '>')
@@ -193,18 +193,6 @@ FluxBB.post = (function (doc, win) {
 					}
 				}
 			}
-			
-			if (!!FluxBB.vars.bbFlagUp && !FluxBB.vars.bbGuest) {
-				var all_ul = doc.getElementsByTagName('ul'),
-						i = all_ul.length - 1;
-				while (i > -1) {
-					if (all_ul[i].className == 'bblinks') {
-						all_ul[i].insertAdjacentHTML('beforeEnd', '<li><span><a href="upfiles.php" onclick="return FluxBB.post.popUp(this.href);"><strong>' + lang['upfiles'] + '</strong></a></span></li>');
-						i = 0;
-					}
-					i--;
-				}
-			}
 		},
 
 		insText : function (open, close) {
@@ -234,16 +222,16 @@ FluxBB.post = (function (doc, win) {
 			textarea.focus();
 			return false;
 		},
-		
+
 		insName: function (id) {
 			return FluxBB.post.insText('', '[b]@' + nameusers[id] + '[/b], ');
 		},
-		
+
 		getText: function () {
 			if (win.getSelection) quote_text = win.getSelection().toString();
 			else if (doc.selection && doc.selection.createRange) quote_text = doc.selection.createRange().text;
 		},
-		
+
 		quote: function (id) {
 			if (typeof id !== 'number' || id < 1) return false;
 			if (quote_text != '') {
@@ -276,7 +264,7 @@ FluxBB.post = (function (doc, win) {
 			win.open(url, 'gest', 'top=' + t + ',left=' + l + ',width=' + w + ',height=' + h + ',resizable=yes,location=no,menubar=no,status=no,scrollbars=yes');
 			return false;
 		},
-		
+
 		overlay : function (prt, str) {
 			var m = get(str);
 			if (m.style.display != 'block') {
@@ -308,7 +296,7 @@ FluxBB.post = (function (doc, win) {
 
 			return false;
 		},
-		
+
 		showMapColor : function (color) {
 			get('selectedMapColor').style.backgroundColor = color;
 			get('selectedMapColorBox').value = color;

+ 407 - 0
js/upload.js

@@ -0,0 +1,407 @@
+// upload.js v3.0.0 BETA Copyright (C) 2019 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;
+			if (typeof MouseEvent === 'function') {
+				event = new MouseEvent('click');
+			} else {
+				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);
+}

+ 18 - 12
lang/English/upload.php

@@ -8,9 +8,10 @@ $lang_up = array(
 '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 (%d).',
+'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.',
@@ -27,10 +28,10 @@ $lang_up = array(
 'thumb'							=> 'Activate thumbnails',
 'thumb_size'				=> 'Thumbs size: ',
 'quality'						=> 'Quality: ',
-'maxsize_member'		=> 'Max size members can upload.',
-'limit_member'			=> 'Space allocated to members.',
+'maxsize_member'		=> 'Max size members can upload (MBytes).',
+'limit_member'			=> 'Space allocated to members (MBytes).',
 'px'								=> 'Pixel',
-'bytes'							=> 'Bytes',
+'kbytes'							=> 'KBytes',
 'pictures'					=> 'Pictures',
 'for pictures'			=> 'For a picture in weight it is more',
 'Install quality'		=> 'Install quality:',
@@ -45,8 +46,8 @@ $lang_up = array(
 'titre_4'						=> 'My uploads',
 'popup_title'				=> 'File manager',
 
-'info_2'						=> 'Your file must not be bigger than %s and must be a %s file.',
-'info_4'						=> 'Storage space used: %s in %s',
+'info_2'						=> '%1$s (%2$s max file size)',
+'info_4'						=> 'Storage space used: <span>%s</span> in %s',
 'legend'						=> 'File',
 'fichier'						=> 'Select a file',
 
@@ -74,13 +75,18 @@ $lang_up = array(
 'group'							=> 'Group',
 
 // Avatar upload stuff
-'Too large ini'			=>	'The selected file was too large to upload. The server didn\'t allow the upload.',
-'Partial upload'		=>	'The selected file was only partially uploaded. Please try again.',
-'No tmp directory'	=>	'PHP was unable to save the uploaded file to a temporary location.',
-'No file'						=>	'You did not select a file for upload.',
 '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. Please contact the forum administrator at',
-'Unknown failure'		=>	'An unknown error occurred. Please try again.',
+'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.',
 );

+ 17 - 13
lang/Russian/upload.php

@@ -8,9 +8,10 @@ $lang_up = array(
 'Error space'				=> 'Вы превысили лимит отведенного места под ваши файлы.',
 'Error delete'			=> 'При удалении одного из файлов возникла ошибка.',
 'Error img'					=> 'Неверный формат картинки. Или сервер не поддерживает обработку картинок.',
-'Error no mod img'	=> 'Модификация картинки не удалась (%d).',
+'Error no mod img'	=> 'Модификация картинки не удалась.',
 'Error open'				=> 'Загруженный файл не открывается.',
 'Error inject'			=> 'Загруженный файл содержит запрещенную последовательность символов. Заархивируйте файл и попробуйте снова, или обратитесь к администрации форума.',
+'Error usage'			=> 'Файл используется в %d сообщении(ях).',
 
 'Redirect'					=> 'Настройки изменены. Переадресация …',
 'Install info'			=> 'Плагин внесет нужные изменения в базу форума и обновит кэш.',
@@ -27,10 +28,10 @@ $lang_up = array(
 'thumb'							=> 'Использовать превьюшки',
 'thumb_size'				=> 'Высота превью: ',
 'quality'						=> 'Качество: ',
-'maxsize_member'		=> 'Максимальный размер файла для загрузки.',
-'limit_member'			=> 'Лимит дискового пространства.',
+'maxsize_member'		=> 'Максимальный размер файла для загрузки (Мбайт).',
+'limit_member'			=> 'Лимит дискового пространства (Мбайт).',
 'px'								=> 'точек',
-'bytes'							=> 'байт',
+'kbytes'							=> 'Кбайт',
 'pictures'					=> 'Картинки',
 'for pictures'			=> 'Для картинки весом больше',
 'Install quality'		=> 'Установить качество:',
@@ -45,8 +46,8 @@ $lang_up = array(
 'titre_4'						=> 'Мои загрузки',
 'popup_title'				=> 'Управление файлами',
 
-'info_2'						=> 'Файл по размеру не должен превышать %s и должен иметь расширение из списка: %s.',
-'info_4'						=> 'Использовано: %s из %s',
+'info_2'						=> '%1$s (макс. %2$s)',
+'info_4'						=> 'Использовано: <span>%s</span> из %s',
 'legend'						=> 'Файл',
 'fichier'						=> 'Выберите файл',
 
@@ -73,16 +74,19 @@ $lang_up = array(
 'groups'						=> 'Настройка групп',
 'group'							=> 'Группа',
 
-
-
 // Avatar upload stuff
-'Too large ini'			=>	'Выбранный файл слишком велик для загрузки. Сервер отклонил загрузку.',
-'Partial upload'		=>	'Выбранный файл был загружен частично. Пожалуйста, повторите попытку.',
-'No tmp directory'	=>	'PHP не может сохранить загруженный файл по временному адресу.',
-'No file'						=>	'Не выбран файл для загрузки.',
 'Bad type'					=>	'Загрузка файла с используемым расширением запрещена.',
 'Too large'					=>	'Выбранный файл больше максимально допустимых размеров',
 'Move failed'				=>	'Сервер не смог сохранить загруженный файл.',
-'Unknown failure'		=>	'Произошла неизвестная ошибка. Пожалуйста, повторите попытку.',
+'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' => 'Неизвестная ошибка загрузки.',
 );

+ 36 - 20
plugins/AP_Smilies.php

@@ -211,34 +211,50 @@ elseif (isset($_POST['add_image']))
 	{
 		include PUN_ROOT.'include/upload.php';
 
-		$filename = parse_file(substr($uploaded_file['name'], 0, strpos($uploaded_file['name'], '.')));
-		if (empty($filename))
-			message($lang_smiley['Bad name']);
+		// Make sure the file isn't too big
+		if ($uploaded_file['size'] > $smilies_config_image_size) {
+			message($lang_smiley['Too large'].' '.$smilies_config_image_size.' '.$lang_smiley['bytes'].'.');
+		}
 
-		if (isXSSattack($uploaded_file['tmp_name']) !== false)
-			message($lang_smiley['Bad type']);
+		if (false === $upf_class->loadFile($uploaded_file['tmp_name'], $uploaded_file['name'])) {
+			message($lang_up['Unknown failure'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')');
+		}
 
-		// Check types
-		$allowed_types = array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png');
-		if (!in_array($uploaded_file['type'], $allowed_types))
+		if (true !== $upf_class->isImage() || ! in_array($upf_class->getFileExt(), ['jpg', 'gif', 'png'])) {
 			message($lang_smiley['Bad type']);
+		}
 
-		// Make sure the file isn't too big
-		if ($uploaded_file['size'] > $smilies_config_image_size)
-			message($lang_smiley['Too large'].' '.$smilies_config_image_size.' '.$lang_smiley['bytes'].'.');
+		if (false !== $upf_class->isUnsafeContent()) {
+			message($lang_up['Error inject']);
+		}
+
+		$upf_class->prepFileName();
 
+		if (false === $upf_class->loadImage()) {
+			message($lang_up['Error img'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')');
+		}
+
+		$filename = $upf_class->getFileName();
 		// Determine type
 		$extensions = null;
-		if ($uploaded_file['type'] == 'image/gif')
-			$extensions = array('.gif', '.jpg', '.png');
-		else if ($uploaded_file['type'] == 'image/jpeg' || $uploaded_file['type'] == 'image/pjpeg')
-			$extensions = array('.jpg', '.gif', '.png');
-		else
-			$extensions = array('.png', '.gif', '.jpg');
+		switch ($upf_class->getFileExt()) {
+			case 'gif':
+				$extensions = array('.gif', '.jpg', '.png');
+				break;
+			case 'jpg':
+				$extensions = array('.jpg', '.gif', '.png');
+				break;
+			case 'png':
+				$extensions = array('.png', '.gif', '.jpg');
+				break;
+			default:
+				message($lang_smiley['Bad type']);
+		}
 
-		// Move the file to the avatar directory. We do this before checking the width/height to circumvent open_basedir restrictions.
-		if (!@move_uploaded_file($uploaded_file['tmp_name'], PUN_ROOT.'img/smilies/'.$filename.'.tmp'))
-			message($lang_smiley['Move failed']);
+		$fileinfo = $upf_class->saveFile(PUN_ROOT . 'img/smilies/' . $filename . '.tmp', true);
+		if (false === $fileinfo) {
+			message($lang_smiley['Move failed'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')');
+		}
 
 		// Now check the width/height
 		list($width, $height, $type,) = getimagesize(PUN_ROOT.'img/smilies/'.$filename.'.tmp');

+ 369 - 276
plugins/AP_Upload.php

@@ -1,49 +1,115 @@
 <?php
 
 /**
- * Copyright (C) 2011-2017 Visman (mio.visman@yandex.ru)
+ * Copyright (C) 2011-2019 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'))
+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', '2.1.0');
-define('PLUGIN_URL', pun_htmlspecialchars('admin_loader.php?plugin='.$plugin));
-define('PLUGIN_EXTS', 'jpg,jpeg,png,gif,mp3,zip,rar,7z');
+define('PLUGIN_VERSION', '3.0.0');
+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';
+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 = array(
-	'thumb' => ($gd ? 1 : 0),
+$sconf = [
+	'thumb' => (true === $upf_class->isResize()) ? 1 : 0,
 	'thumb_size' => 100,
 	'thumb_perc' => 75,
-	'pic_mass' => 307200,
+	'pic_mass' => 300, //килобайт
 	'pic_perc' => 75,
-	'pic_w' => 1680,
-	'pic_h' => 1050,
-	);
+	'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(serialize($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', 'INT(15)', false, 0) or error(sprintf($lang_up['Error DB'], 'users'), __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());
 
-	$db->query('UPDATE '.$db->prefix.'groups SET g_up_ext=\''.$db->escape(PLUGIN_EXTS).'\', g_up_limit=1073741824, g_up_max='.min(return_bytes(ini_get('upload_max_filesize')), return_bytes(ini_get('post_max_size'))).' WHERE g_id='.PUN_ADMIN) or error('Unable to update user group list', __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_uploadile_other\'') or error('Unable to remove config entries', __FILE__, __LINE__, $db->error());;
-	$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES(\'o_uploadile_other\', \''.$db->escape(serialize($sconf)).'\')') or error($lang_up['Error DB ins-up'], __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';
+	if (! defined('FORUM_CACHE_FUNCTIONS_LOADED')) {
+		require PUN_ROOT . 'include/cache.php';
+	}
 
 	generate_config_cache();
 
@@ -51,70 +117,70 @@ if (isset($_POST['installation']))
 }
 
 // Обновления параметров
-else if (isset($_POST['update']))
-{
-	if (!isset($pun_user['g_up_ext']))
-	{
-		$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(15)', false, 0) or error(sprintf($lang_up['Error DB'], 'groups'), __FILE__, __LINE__, $db->error());
+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;
 	}
 
-	$g_up_ext = isset($_POST['g_up_ext']) ? array_map('pun_trim', $_POST['g_up_ext']) : array();
-	$g_up_limit = isset($_POST['g_up_limit']) ? array_map('intval', $_POST['g_up_limit']) : array();
-	$g_up_max = isset($_POST['g_up_max']) ? array_map('intval', $_POST['g_up_max']) : array();
-
-	$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)
-		{
-			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;
+	$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 ($cur_group['g_id'] == PUN_ADMIN)
-			{
-				$g_lim = 1073741824;
-				$g_max = min(return_bytes(ini_get('upload_max_filesize')), return_bytes(ini_get('post_max_size')));
-			}
-			else
-			{
-				$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_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 = min($g_max, return_bytes(ini_get('upload_max_filesize')), return_bytes(ini_get('post_max_size')));
+		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;
 			}
-
-			$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());
+			$g_ext = strtolower($g_ext);
+		} else {
+			$g_ext = PLUGIN_EXTS;
 		}
 
-	if (isset($_POST['thumb']))
-		$sconf['thumb'] = ($_POST['thumb'] == '1' ? 1 : 0);
-	if (isset($_POST['thumb_size']) && $_POST['thumb_size'] > 0)
-		$sconf['thumb_size'] = intval($_POST['thumb_size']);
-	if (isset($_POST['thumb_perc']) && $_POST['thumb_perc'] > 0 && $_POST['thumb_perc'] <= 100)
-		$sconf['thumb_perc'] = intval($_POST['thumb_perc']);
+		$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['pic_mass']) && $_POST['pic_mass'] >= 0)
-		$sconf['pic_mass'] = intval($_POST['pic_mass']);
-	if (isset($_POST['pic_perc']) && $_POST['pic_perc'] > 0 && $_POST['pic_perc'] <= 100)
-		$sconf['pic_perc'] = intval($_POST['pic_perc']);
-	if (isset($_POST['pic_w']) && $_POST['pic_w'] >= 100)
-		$sconf['pic_w'] = intval($_POST['pic_w']);
-	if (isset($_POST['pic_h']) && $_POST['pic_h'] >= 100)
-		$sconf['pic_h'] = intval($_POST['pic_h']);
+	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_uploadile_other\'') or error('Unable to remove config entries', __FILE__, __LINE__, $db->error());;
-	$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES(\'o_uploadile_other\', \''.$db->escape(serialize($sconf)).'\')') or error($lang_up['Error DB ins-up'], __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';
+	if (! defined('FORUM_CACHE_FUNCTIONS_LOADED')) {
+		require PUN_ROOT . 'include/cache.php';
+	}
 
 	generate_config_cache();
 
@@ -122,182 +188,165 @@ else if (isset($_POST['update']))
 }
 
 // Удаление мода
-else if (isset($_POST['restore']))
-{
-	$db->drop_field('users', 'upload') or error('Unable to drop upload field', __FILE__, __LINE__, $db->error());
+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_uploadile_other\'') or error('Unable to remove config entries', __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';
+	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_uploadile_other']))
-	$aconf = unserialize($pun_config['o_uploadile_other']);
-else
-{
+if (isset($pun_config['o_upload_config'])) {
+	$aconf = unserialize($pun_config['o_upload_config']);
+} else {
 	$aconf = $sconf;
 	$aconf['thumb'] = 0;
 	define('PLUGIN_OFF', 1);
 }
 
-$mem = 'img/members/';
-$regx = '%^img/members/(\d+)/(.+)\.([0-9a-zA-Z]+)$%i';
+$upf_mem = 'img/members/';
+$upf_regx = '%^img/members/(\d+)/([\w-]+)\.(\w+)$%iD';
+
 // #############################################################################
+
 // Удаление файлов
-if (isset($_POST['delete']) && isset($_POST['delete_f']) && is_array($_POST['delete_f']))
-{
-	$error = 0;
-
-	if (is_dir(PUN_ROOT.$mem))
-	{
-		$au = array();
-		foreach ($_POST['delete_f'] as $file)
-		{
-			preg_match($regx, $file, $fi);
-			if (!isset($fi[1]) || !isset($fi[2]) || !isset($fi[3])) continue;
-
-			$f = parse_file($fi[2].'.'.$fi[3]);
-			$dir = $mem.$fi[1].'/';
-			if (is_file(PUN_ROOT.$dir.$f))
-			{
-				$au[$fi[1]] = $fi[1];
-				if (unlink(PUN_ROOT.$dir.$f))
-				{
-					if (is_file(PUN_ROOT.$dir.'mini_'.$f))
-						unlink(PUN_ROOT.$dir.'mini_'.$f);
+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++;
+			} else {
+				$error = true;
 			}
 		}
 
-		if (!defined('PLUGIN_OFF'))
-		{
-			foreach ($au as $user)
-			{
+		if (! defined('PLUGIN_OFF')) {
+			foreach ($au as $user) {
 				// Считаем общий размер файлов юзера
-				$upload = dir_size($mem.$user.'/');
-				$db->query('UPDATE '.$db->prefix.'users SET upload=\''.$upload.'\' WHERE id='.$user) or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error());
+				$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 = (!isset($_GET['p']) || $_GET['p'] <= 1) ? 1 : intval($_GET['p']);
+	$p = empty($_GET['p']) || $_GET['p'] < 1 ? 1 : (int) $_GET['p'];
 
-	if ($error == 0)
-		redirect(PLUGIN_URL.($p > 1 ? '&amp;p='.$p : ''), $lang_up['Redirect delete']);
-	else
-	{
-		$pun_config['o_redirect_delay'] = 5;
-		redirect(PLUGIN_URL.($p > 1 ? '&amp;p='.$p : ''), $lang_up['Error'].$lang_up['Error delete']);
+	if ($error) {
+		if ($pun_config['o_redirect_delay'] < 5) {
+			$pun_config['o_redirect_delay'] = 5;
+		}
+		redirect(PLUGIN_URL . ($p > 1 ? '&amp;p=' . $p : ''), $lang_up['Error'] . $lang_up['Error delete']);
+	} else {
+		redirect(PLUGIN_URL . ($p > 1 ? '&amp;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
+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);
+}
+$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.<?php echo PLUGIN_VERSION ?></span></h2>
+		<h2><span>Plugin Upload Files v.<?= PLUGIN_VERSION ?></span></h2>
 		<div class="box">
 			<div class="inbox">
-				<p><?php echo $lang_up['plugin_desc'] ?></p>
-				<form action="<?php echo PLUGIN_URL ?>" method="post">
+				<p><?= $lang_up['plugin_desc'] ?></p>
+				<form action="<?= PLUGIN_URL ?>" method="post">
 					<p>
+						<input type="hidden" name="csrf_hash" value="<?= $upf_token ?>" />
 <?php
 
-$stthumb = '" disabled="disabled';
-
-if (defined('PLUGIN_OFF'))
-{
+if (defined('PLUGIN_OFF')) {
 
 ?>
-						<input type="submit" name="installation" value="<?php echo $lang_up['Install'] ?>" />&#160;<?php echo $lang_up['Install info'] ?><br />
+						<input type="submit" name="installation" value="<?= $lang_up['Install'] ?>" />&#160;<?= $lang_up['Install info'] ?><br />
 					</p>
 				</form>
 			</div>
 		</div>
 <?php
 
-}
-else
-{
-
-	if ($aconf['thumb'] == 1 && $gd)
-		$stthumb = '';
-	if ($gd)
-	{
-		$disbl = '';
-		$gd_vers = gd_info();
-		$gd_vers = $gd_vers['GD Version'];
-	}
-	else
-	{
-		$disbl = '" disabled="disabled';
-		$gd_vers = '-';
-	}
+} else {
+	$disbl = (true === $upf_class->isResize()) ? '' : '" disabled="disabled';
+	$stthumb = ('' === $disbl && 1 == $aconf['thumb']) ? '' : '" disabled="disabled';
 
 ?>
-						<input type="submit" name="update" value="<?php echo $lang_up['Update'] ?>" />&#160;<?php echo $lang_up['Update info'] ?><br />
-						<input type="submit" name="restore" value="<?php echo $lang_up['Uninstall'] ?>" />&#160;<?php echo $lang_up['Uninstall info'] ?><br /><br />
+						<input type="submit" name="update" value="<?= $lang_up['Update'] ?>" />&#160;<?= $lang_up['Update info'] ?><br />
+						<input type="submit" name="restore" value="<?= $lang_up['Uninstall'] ?>" />&#160;<?= $lang_up['Uninstall info'] ?><br /><br />
 					</p>
 				</form>
 			</div>
 		</div>
-		<h2 class="block2"><span><?php echo $lang_up['configuration'] ?></span></h2>
+		<h2 class="block2"><span><?= $lang_up['configuration'] ?></span></h2>
 		<div class="box">
-			<form method="post" action="<?php echo PLUGIN_URL ?>">
-				<p class="submittop"><input type="submit" name="update" value="<?php echo $lang_up['Update'] ?>" tabindex="<?php echo $tabindex++ ?>" /></p>
+			<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><?php echo $lang_up['legend_2'] ?></legend>
+						<legend><?= $lang_up['legend_2'] ?></legend>
 						<div class="infldset">
 						<table>
 							<tr>
-								<th scope="row"><label>GD Version</label></th>
-								<td><?php echo pun_htmlspecialchars($gd_vers) ?></td>
+								<th scope="row"><label><?= $upf_class->getLibName() ?></label></th>
+								<td><?= pun_htmlspecialchars($upf_class->getLibVersion()) ?></td>
 							</tr>
 							<tr>
-								<th scope="row"><label for="pic_mass"><?php echo $lang_up['pictures'] ?></label></th>
+								<th scope="row"><label><?= $lang_up['pictures'] ?></label></th>
 								<td>
-									<?php echo $lang_up['for pictures']."\n" ?>
-									<input type="text" name="pic_mass" size="8" maxlength="8" tabindex="<?php echo $tabindex++ ?>" value="<?php echo pun_htmlspecialchars($aconf['pic_mass']).$disbl ?>" />&#160;<?php echo $lang_up['bytes'].":\n" ?><br />
-									&#160;*&#160;<?php echo $lang_up['to jpeg'] ?><br />
-									&#160;*&#160;<?php echo $lang_up['Install quality']."\n" ?>
-									<input type="text" name="pic_perc" size="4" maxlength="3" tabindex="<?php echo $tabindex++ ?>" value="<?php echo pun_htmlspecialchars($aconf['pic_perc']).$disbl ?>" />&#160;%<br />
-									&#160;*&#160;<?php echo $lang_up['Size not more']."\n" ?>
-									<input type="text" name="pic_w" size="4" maxlength="4" tabindex="<?php echo $tabindex++ ?>" value="<?php echo pun_htmlspecialchars($aconf['pic_w']).$disbl ?>" />&#160;x
-									<input type="text" name="pic_h" size="4" maxlength="4" tabindex="<?php echo $tabindex++ ?>" value="<?php echo pun_htmlspecialchars($aconf['pic_h']).$disbl ?>" />&#160;<?php echo $lang_up['px']."\n" ?>
+									<?= $lang_up['for pictures'] . "\n" ?>
+									<input type="text" name="pic_mass" size="8" maxlength="8" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_mass']) . $disbl ?>" />&#160;<?= $lang_up['kbytes'] . ":\n" ?><br />
+									&#160;*&#160;<?= $lang_up['Install quality'] . "\n" ?>
+									<input type="text" name="pic_perc" size="4" maxlength="3" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_perc']) . $disbl ?>" />&#160;%<br />
+									&#160;*&#160;<?= $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 ?>" />&#160;x
+									<input type="text" name="pic_h" size="4" maxlength="4" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['pic_h']) . $disbl ?>" />&#160;<?= $lang_up['px'] . "\n" ?>
 								</td>
 							</tr>
 							<tr>
-								<th scope="row"><label for="thumb"><?php echo $lang_up['thumb'] ?></label></th>
+								<th scope="row"><label><?= $lang_up['thumb'] ?></label></th>
 								<td>
-									<input type="radio" tabindex="<?php echo ($tabindex++).$disbl ?>" name="thumb" value="1"<?php if ($aconf['thumb'] == 1) echo ' checked="checked"' ?> /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>
+									<input type="radio" tabindex="<?= ($tabindex++) . $disbl ?>" name="thumb" value="1"<?= $aconf['thumb'] == 1 ? ' checked="checked"' : '' ?> /> <strong><?= $lang_admin_common['Yes'] ?></strong>
 									&#160;&#160;&#160;
-									<input type="radio" tabindex="<?php echo ($tabindex++).$disbl ?>" name="thumb" value="0"<?php if ($aconf['thumb'] == 0) echo ' checked="checked"' ?> /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+									<input type="radio" tabindex="<?= ($tabindex++) . $disbl ?>" name="thumb" value="0"<?= $aconf['thumb'] == 0 ? ' checked="checked"' : '' ?> /> <strong><?= $lang_admin_common['No'] ?></strong>
 									<br />
-									&#160;*&#160;<?php echo $lang_up['thumb_size']."\n" ?>
-									<input type="text" name="thumb_size" size="4" maxlength="4" tabindex="<?php echo $tabindex++ ?>" value="<?php echo pun_htmlspecialchars($aconf['thumb_size']).$disbl ?>" />&#160;<?php echo $lang_up['px']."\n" ?><br />
-									&#160;*&#160;<?php echo $lang_up['quality']."\n" ?>
-									<input type="text" name="thumb_perc" size="4" maxlength="3" tabindex="<?php echo $tabindex++ ?>" value="<?php echo pun_htmlspecialchars($aconf['thumb_perc']).$disbl ?>" />&#160;%
+									&#160;*&#160;<?= $lang_up['thumb_size'] . "\n" ?>
+									<input type="text" name="thumb_size" size="4" maxlength="4" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['thumb_size']) . $disbl ?>" />&#160;<?= $lang_up['px'] . "\n" ?><br />
+									&#160;*&#160;<?= $lang_up['quality'] . "\n" ?>
+									<input type="text" name="thumb_perc" size="4" maxlength="3" tabindex="<?= $tabindex++ ?>" value="<?= pun_htmlspecialchars($aconf['thumb_perc']) . $disbl ?>" />&#160;%
 								</td>
 							</tr>
 						</table>
@@ -307,17 +356,17 @@ else
 
 				<div class="inform">
 					<fieldset>
-						<legend><?php echo $lang_up['groups'] ?></legend>
+						<legend><?= $lang_up['groups'] ?></legend>
 						<div class="infldset">
 							<div class="inbox">
-								<p>1* - <?php echo $lang_up['laws'] ?></p>
-								<p>2* - <?php echo $lang_up['maxsize_member'] ?></p>
-								<p>3* - <?php echo $lang_up['limit_member'] ?></p>
+								<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"><?php echo $lang_up['group'] ?></th>
+									<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>
@@ -326,27 +375,26 @@ else
 							<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());
+	$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']))
-			{
+	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"><?php echo pun_htmlspecialchars($cur_group['g_title']) ?></td>
-									<td class="tc2"><input type="text" name="g_up_ext[<?php echo $cur_group['g_id'] ?>]" value="<?php echo pun_htmlspecialchars($cur_group['g_up_ext']) ?>" tabindex="<?php echo $tabindex++ ?>" size="40" maxlength="255" /></td>
-									<td class="tcr"><input type="text" name="g_up_max[<?php echo $cur_group['g_id'] ?>]" value="<?php echo $cur_group['g_up_max'] ?>" tabindex="<?php echo $tabindex++ ?>" size="10" maxlength="10" <?php echo ($cur_group['g_id'] == PUN_ADMIN ? 'disabled="disabled" ' : '')?>/></td>
-									<td class="tcr"><input type="text" name="g_up_limit[<?php echo $cur_group['g_id'] ?>]" value="<?php echo $cur_group['g_up_limit'] ?>" tabindex="<?php echo $tabindex++ ?>" size="10" maxlength="10" <?php echo ($cur_group['g_id'] == PUN_ADMIN ? 'disabled="disabled" ' : '')?>/></td>
+									<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>
@@ -355,14 +403,17 @@ else
 					</fieldset>
 				</div>
 
-				<p class="submitend"><input type="submit" name="update" value="<?php echo $lang_up['Update'] ?>" tabindex="<?php echo $tabindex++ ?>" /></p>
+				<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><?php echo $lang_up['legend_1'] ?></legend>
+						<legend><?= $lang_up['legend_1'] ?></legend>
 						<div class="infldset">
-							<label for="mo"><?php echo $lang_up['mo'] ?></label> <input type="text" name="mo" id="mo" size="15" tabindex="<?php echo $tabindex++ ?>" /> <input type="button" value="<?php echo $lang_up['convert'] ?>" tabindex="<?php echo $tabindex++ ?>" onclick="javascript:document.getElementById('ko').value=document.getElementById('mo').value*1024; document.getElementById('o').value=document.getElementById('mo').value*1048576;" />
-							<label for="ko"><?php echo $lang_up['ko'] ?></label> <input type="text" name="ko" id="ko" size="15" tabindex="<?php echo $tabindex++ ?>" /> <input type="button" value="<?php echo $lang_up['convert'] ?>" tabindex="<?php echo $tabindex++ ?>" onclick="javascript:document.getElementById('mo').value=document.getElementById('ko').value/1024; document.getElementById('o').value=document.getElementById('ko').value*1024;"/>
-							<label for="o"><?php echo $lang_up['o'] ?></label> <input type="text" name="o" id="o" size="15" tabindex="<?php echo $tabindex++ ?>" /> <input type="button" value="<?php echo $lang_up['convert'] ?>" tabindex="<?php echo $tabindex++ ?>" onclick="javascript:document.getElementById('mo').value=document.getElementById('o').value/1048576; document.getElementById('ko').value=(document.getElementById('o').value*1024)/1048576;"/>
+							<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>
@@ -371,48 +422,52 @@ else
 <?php
 
 }
+
 // #############################################################################
-$files = array();
-if (is_dir(PUN_ROOT.$mem))
-{
-	$af = array();
-	$ad = scandir(PUN_ROOT.$mem);
-	foreach($ad as $f)
-	{
-		if ($f != '.' && $f != '..' && is_dir(PUN_ROOT.$mem.$f))
-		{
-			$dir = $mem.$f.'/';
-			$open = opendir(PUN_ROOT.$dir);
-			while(($file = readdir($open)) !== false)
-			{
-				if (is_file(PUN_ROOT.$dir.$file) && $file[0] != '.' && $file[0] != '#' && substr($file, 0, 5) != 'mini_')
-				{
-					$ext = strtolower(substr(strrchr($file, '.'), 1)); // берем расширение файла
-					if (!in_array($ext, $extforno))
-					{
-						$time = filemtime(PUN_ROOT.$dir.$file).$file.$f;
-						$af[$time] = $dir.$file;
-					}
-				}
+
+$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;
 			}
-			closedir($open);
+
+			$time = filemtime(PUN_ROOT . $dir . $file) . $file . $f;
+			$af[$time] = $dir . $file;
 		}
+		closedir($open);
 	}
+
 	unset($ad);
-	if (!empty($af))
-	{
-		$num_pages = ceil(sizeof($af) / PLUGIN_NF);
-		$p = (!isset($_GET['p']) || $_GET['p'] <= 1) ? 1 : intval($_GET['p']);
-		if ($p > $num_pages)
-		{
-			header('Location: '.PLUGIN_URL.'&p='.$num_pages.'#gofile');
+
+	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 = '<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);
@@ -422,101 +477,139 @@ if (is_dir(PUN_ROOT.$mem))
 }
 
 ?>
-		<h2 id="gofile" class="block2"><span><?php echo $lang_up['Member files'] ?></span></h2>
+		<h2 id="gofile" class="block2"><span><?= $lang_up['Member files'] ?></span></h2>
 		<div class="box">
 <?php
 
-if (empty($files))
-{
+if (empty($files)) {
 
 ?>
 			<div class="inbox">
-				<p><?php echo $lang_up['No upfiles'] ?></p>
+				<p><?= $lang_up['No upfiles'] ?></p>
 			</div>
 <?php
 
-}
-else
-{
+} else {
 
 ?>
 
 			<div class="inbox">
 				<div class="pagepost">
-					<p class="pagelink conl"><?php echo $paging_links ?></p>
+					<p class="pagelink conl"><?= $paging_links ?></p>
 				</div>
 			</div>
 
-			<form method="post" action="<?php echo PLUGIN_URL.($p > 1 ? '&amp;p='.$p : '').'#gofile' ?>">
+			<form method="post" action="<?= PLUGIN_URL . ($p > 1 ? '&amp;p=' . $p : '') . '#gofile' ?>">
 				<div class="inform">
-					<p class="submittop"><input type="submit" name="update_thumb" value="<?php echo $lang_up['update_thumb'].$stthumb ?>" /></p>
+					<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"><?php echo $lang_up['th0'] ?></th>
-									<th class="upf-c2" scope="col"><?php echo $lang_up['th1'] ?></th>
-									<th class="upf-c3" scope="col"><?php echo $lang_up['th2'] ?></th>
-									<th class="upf-c4" scope="col"><input type="submit" value="<?php echo $lang_up['delete'] ?>" name="delete" tabindex="<?php echo $tabindex++ ?>" /></th>
+									<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"><?php echo $lang_up['th0'] ?></th>
-									<th class="upf-c2"><?php echo $lang_up['th1'] ?></th>
-									<th class="upf-c3"><?php echo $lang_up['th2'] ?></th>
-									<th class="upf-c4"><input type="submit" value="<?php echo $lang_up['delete'] ?>" name="delete" tabindex="<?php echo $tabindex++ ?>" /></th>
+									<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 = $ag = array();
-	$result = $db->query('SELECT id, username, group_id FROM '.$db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error());
-	while ($u = $db->fetch_assoc($result))
-	{
+	$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 = array();
-	$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']] = array();
+	$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);
 
-	foreach ($files as $file)
-	{
-		preg_match($regx, $file, $fi);
-		if (!isset($fi[1]) || !isset($fi[2]) || !isset($fi[3])) continue;
+	$upf_img_exts = ['jpg', 'jpeg', 'gif', 'png', 'bmp', 'webp'];
+	foreach ($files as $file) {
+		if (! preg_match($upf_regx, $file, $fi)) {
+			continue;
+		}
 
-		$fb = in_array(strtolower($fi[3]), array('jpg', 'jpeg', 'gif', 'png', 'bmp')) ? '" class="fancy_zoom" rel="vi001' : '';
-		$dir = $mem.$fi[1].'/';
-		$size_file = file_size(filesize(PUN_ROOT.$file));
-		$miniature = $dir.'mini_'.$fi[2].'.'.$fi[3];
-		if (isset($_POST['update_thumb']) && $aconf['thumb'] == 1 && array_key_exists(strtolower($fi[3]),$extimageGD))
-			img_resize(PUN_ROOT.$file, $dir, 'mini_'.$fi[2], $fi[3], 0, $aconf['thumb_size'], $aconf['thumb_perc']);
+		$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"><?php echo (isset($au[$fi[1]]) ? pun_htmlspecialchars($au[$fi[1]]) : '&#160;') ?></td>
-									<td class="upf-c2"><a href="<?php echo pun_htmlspecialchars($file) ?>"><?php echo pun_htmlspecialchars($fi[2]) ?></a> [<?php echo pun_htmlspecialchars($size_file) ?>].[<?php echo (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>
+									<td class="upf-c1"><?= (isset($au[$fi[1]]) ? pun_htmlspecialchars($au[$fi[1]]) : '&#160;') ?></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
 
-		if (is_file(PUN_ROOT.$miniature) && ($size = getimagesize(PUN_ROOT.$miniature)) !== false)
-			echo "\t\t\t\t\t\t\t\t\t".'<td class="upf-c3"><a href="'.pun_htmlspecialchars($file).$fb.'"><img style="width:'.min(150, $size[0]).'px" src="'.pun_htmlspecialchars($miniature).'" alt="'.pun_htmlspecialchars($fi[2]).'" /></a></td>'."\n";
-		else
-			echo "\t\t\t\t\t\t\t\t\t".'<td class="upf-c3">'.$lang_up['no_preview'].'</td>'."\n";
+		} else {
+
+?>
+									<td class="upf-c3"><?= $lang_up['no_preview'] ?></td>
+<?php
+
+		}
 
 ?>
-									<td class="upf-c4"><input type="checkbox" name="delete_f[]" value="<?php echo pun_htmlspecialchars($file) ?>" tabindex="<?php echo $tabindex++ ?>" /></td>
+									<td class="upf-c4"><input type="checkbox" name="delete_f[]" value="<?= pun_htmlspecialchars($file) ?>" tabindex="<?= $tabindex++ ?>" /></td>
 								</tr>
 <?php
 
@@ -531,7 +624,7 @@ else
 
 			<div class="inbox">
 				<div class="pagepost">
-					<p class="pagelink conl"><?php echo $paging_links ?></p>
+					<p class="pagelink conl"><?= $paging_links ?></p>
 				</div>
 			</div>
 

+ 51 - 43
profile.php

@@ -330,7 +330,10 @@ else if ($action == 'upload_avatar' || $action == 'upload_avatar2')
 	if ($pun_user['id'] != $id && !$pun_user['is_admmod'])
 		message($lang_common['No permission'], false, '403 Forbidden');
 
-	require PUN_ROOT.'include/upload.php'; // Visman - auto resize avatar
+// Visman - auto resize avatar
+	require PUN_ROOT.'include/upload.php';
+	$max_filesize = (true === $upf_class->isResize()) ? min(2097152, $upf_class->size(ini_get('upload_max_filesize')), $upf_class->size(ini_get('post_max_size'))) : $pun_config['o_avatars_size'];
+// Visman - auto resize avatar
 
 	if (isset($_POST['form_sent']))
 	{
@@ -374,61 +377,66 @@ else if ($action == 'upload_avatar' || $action == 'upload_avatar2')
 
 		if (is_uploaded_file($uploaded_file['tmp_name']))
 		{
-			// Preliminary file check, adequate in most cases
-			$allowed_types = array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png');
-			if (!in_array($uploaded_file['type'], $allowed_types))
-				message($lang_profile['Bad type']);
-
+// Visman - auto resize avatar
 			// Make sure the file isn't too big
-			if ($uploaded_file['size'] > ($gd ? min(2097152, return_bytes(ini_get('upload_max_filesize')), return_bytes(ini_get('post_max_size'))) : $pun_config['o_avatars_size'])) // Visman - auto resize avatar
-				message($lang_profile['Too large'].' '.forum_number_format(($gd ? min(2097152, return_bytes(ini_get('upload_max_filesize')), return_bytes(ini_get('post_max_size'))) : $pun_config['o_avatars_size'])).' '.$lang_profile['bytes'].'.'); // Visman - auto resize avatar
+			if ($uploaded_file['size'] > $max_filesize) {
+				message($lang_profile['Too large'].' '.forum_number_format($max_filesize).' '.$lang_profile['bytes'].'.');
+			}
 
-			// Move the file to the avatar directory. We do this before checking the width/height to circumvent open_basedir restrictions
-			if (!@move_uploaded_file($uploaded_file['tmp_name'], PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp'))
-				message($lang_profile['Move failed'].' <a href="mailto:'.pun_htmlspecialchars($pun_config['o_admin_email']).'">'.pun_htmlspecialchars($pun_config['o_admin_email']).'</a>.');
+			if (false === $upf_class->loadFile($uploaded_file['tmp_name'], 'temp' . $id . '.tmp')) {
+				message($lang_up['Unknown failure'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')');
+			}
 
-			list($width, $height, $type,) = @getimagesize(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp');
+			if (true !== $upf_class->isImage() || ! in_array($upf_class->getFileExt(), ['jpg', 'gif', 'png'])) {
+				message($lang_profile['Bad type']);
+			}
 
-// Visman - auto resize avatar
-			if ($gd && !empty($width) && !empty($height) && ($uploaded_file['size'] > $pun_config['o_avatars_size'] || $width > $pun_config['o_avatars_width'] || $height > $pun_config['o_avatars_height'] || $type == IMAGETYPE_BMP))
-			{
-				$result_res = img_resize(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp', $pun_config['o_avatars_dir'].'/', 'temp'.$id, $extimage2[$type][0], $pun_config['o_avatars_width'], $pun_config['o_avatars_height']);
-				if (is_array($result_res))
-				{
-					@unlink(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp');
-					@rename(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$result_res[0].'.'.$result_res[1], PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp');
+			if (false !== $upf_class->isUnsafeContent()) {
+				message($lang_up['Error inject']);
+			}
 
-					list($width, $height, $type,) = @getimagesize(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp');
-				}
+			$result = $upf_class->loadImage();
+			if (false === $result) {
+				message($lang_up['Error img'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')');
 			}
-// Visman - auto resize avatar
 
+			$scaleResize = false;
 
-			// Determine type
-			if ($type == IMAGETYPE_GIF)
-				$extension = '.gif';
-			else if ($type == IMAGETYPE_JPEG)
-				$extension = '.jpg';
-			else if ($type == IMAGETYPE_PNG)
-				$extension = '.png';
-			else
-			{
-				// Invalid type
-				@unlink(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp');
-				message($lang_profile['Bad type']);
-			}
+			if (
+				$uploaded_file['size'] <= $pun_config['o_avatars_size']
+				&& $result[0] <= $pun_config['o_avatars_width']
+				&& $result[1] <= $pun_config['o_avatars_height']
+			) {
+				$fileinfo = $upf_class->saveFile(PUN_ROOT . $pun_config['o_avatars_dir'] . '/' . $upf_class->getFileName() . '.' . $upf_class->getFileExt(), true);
+			} else if (true === $upf_class->isResize()) {
+				$upf_class->setImageQuality(40);
+				$scaleResize = $upf_class->resizeImage($pun_config['o_avatars_width'], $pun_config['o_avatars_height']);
 
-			// Now check the width/height
-			if (empty($width) || empty($height) || $width > $pun_config['o_avatars_width'] || $height > $pun_config['o_avatars_height'])
-			{
-				@unlink(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp');
+				if (false === $scaleResize) {
+					message($lang_up['Error no mod img'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); //????
+				}
+
+				$fileinfo = $upf_class->saveImage(PUN_ROOT . $pun_config['o_avatars_dir'] . '/' . $upf_class->getFileName() . '.' . $upf_class->getFileExt(), true);
+			} else if (
+				$result[0] > $pun_config['o_avatars_width']
+				|| $result[1] > $pun_config['o_avatars_height']
+			) {
 				message($lang_profile['Too wide or high'].' '.$pun_config['o_avatars_width'].'x'.$pun_config['o_avatars_height'].' '.$lang_profile['pixels'].'.');
 			}
 
+			if (false === $fileinfo) {
+				message($lang_profile['Move failed'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); //????
+			}
+			if (filesize($fileinfo['path']) > $pun_config['o_avatars_size']) {
+				@unlink($fileinfo['path']);
+				message($lang_profile['Too large'].' '.forum_number_format($pun_config['o_avatars_size']).' '.$lang_profile['bytes'].'.');
+			}
+
 			// Delete any old avatars and put the new one in place
 			delete_avatar($id);
-			@rename(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.'.tmp', PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.$extension);
-			@chmod(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$id.$extension, 0644);
+			@rename($fileinfo['path'], PUN_ROOT . $pun_config['o_avatars_dir'] . '/' . $id . '.' . $fileinfo['extension']);
+			@chmod(PUN_ROOT . $pun_config['o_avatars_dir'] . '/' . $id . '.' . $fileinfo['extension'], 0644);
+// Visman - auto resize avatar
 		}
 		else
 			message($lang_profile['Unknown failure']);
@@ -453,7 +461,7 @@ else if ($action == 'upload_avatar' || $action == 'upload_avatar2')
 					<div class="infldset">
 						<input type="hidden" name="form_sent" value="1" />
 						<input type="hidden" name="csrf_hash" value="<?php echo csrf_hash() ?>" />
-						<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo ($gd ? min(2097152, return_bytes(ini_get('upload_max_filesize')), return_bytes(ini_get('post_max_size'))) : $pun_config['o_avatars_size']) ?>" />
+						<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $max_filesize ?>" />
 						<label class="required"><strong><?php echo $lang_profile['File'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><input name="req_file" type="file" size="40" /><br /></label>
 						<p><?php echo $lang_profile['Avatar desc'].' '.$pun_config['o_avatars_width'].' x '.$pun_config['o_avatars_height'].' '.$lang_profile['pixels'].' '.$lang_common['and'].' '.forum_number_format($pun_config['o_avatars_size']).' '.$lang_profile['bytes'].' ('.file_size($pun_config['o_avatars_size']).').' ?></p>
 					</div>

+ 40 - 2
style/imports/upfiles.css

@@ -16,7 +16,7 @@ ul#upf-list {
 }
 
 #upf-list li {
-	display: inline-block;
+	display: block;
 	float: left;
 	margin: 3px;
 	padding: 3px;
@@ -25,6 +25,19 @@ ul#upf-list {
 	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;
 }
@@ -73,7 +86,8 @@ ul#upf-list {
 	float: right;
 }
 
-.upf-delete .upf-loading span {
+.upf-delete .upf-loading span,
+.upf-removal .upf-delete span {
 	background: url("../../img/loading.gif") no-repeat scroll 5px 5px;
 }
 
@@ -110,6 +124,10 @@ ul#upf-list {
 	width: 100%;
 }
 
+#upf-legend div span {
+	filter: invert(1) grayscale(1) contrast(9);
+}
+
 #upf-table th, #upf-table td {
 	text-align: center;
 	width: auto;
@@ -122,8 +140,28 @@ ul#upf-list {
 
 #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;
+}

+ 426 - 287
upfiles.php

@@ -1,29 +1,99 @@
 <?php
 
 /**
- * Copyright (C) 2011-2017 Visman (mio.visman@yandex.ru)
+ * Copyright (C) 2011-2019 Visman (mio.visman@yandex.ru)
  * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
  */
 
-if (isset($_GET['delete']))
-	define('PUN_QUIET_VISIT', 1);
+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;
+	}
+}
 
-define('PUN_ROOT', dirname(__FILE__).'/');
-require PUN_ROOT.'include/common.php';
+function upf_message($message, $no_back_link = false, $http_status = null)
+{
+	global $upf_ajax;
 
-if ($pun_user['g_read_board'] == '0')
-	message($lang_common['No view'], false, '403 Forbidden');
+	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 ($pun_user['is_guest'] || !isset($pun_user['g_up_ext']) || empty($pun_config['o_uploadile_other']))
-	message($lang_common['Bad request'], false, '404 Not Found');
+	if ($upf_ajax) {
+		upf_return_json(['error' => $message]);
+	} else {
+		redirect($destination_url, $lang_up['Error'] . $message);
+	}
+}
 
-require PUN_ROOT.'include/upload.php';
+define('PUN_ROOT', dirname(__FILE__) . '/');
+require PUN_ROOT . 'include/common.php';
 
 define('PLUGIN_REF', pun_htmlspecialchars('upfiles.php'));
 define('PLUGIN_NF', 25);
 
-if (!isset($_GET['id']))
-{
+$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);
@@ -31,345 +101,397 @@ if (!isset($_GET['id']))
 	define('PLUGIN_URLD', PLUGIN_URL.'?');
 	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_up['popup_title']);
 	$fpr = false;
-	$extsup = $pun_user['g_up_ext'];
-	$limit = $pun_user['g_up_limit'];
-	$maxsize = $pun_user['g_up_max'];
-	$upload = $pun_user['upload'];
-}
-else
-{
+	$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']))
-		message($lang_common['Bad request'], false, '404 Not Found');
+	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, 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());
+	$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)
-		message($lang_common['Bad request'], false, '404 Not Found');
+	if (!$user_info) {
+		upf_message($lang_common['Bad request'], false, '404 Not Found');
+	}
 
-	list($usname, $upload, $extsup, $maxsize, $limit) = $user_info;
+	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.'&amp;');
+	define('PLUGIN_URL', PLUGIN_REF . '?id=' . $id);
+	define('PLUGIN_URLD', PLUGIN_URL . '&amp;');
 	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Profile'], $lang_up['popup_title']);
 	$fpr = true;
 }
 
-if ($pun_user['g_id'] != PUN_ADMIN && $limit*$maxsize == 0)
-	message($lang_common['Bad request'], false, '404 Not Found');
+$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;
 
-$prcent = ($limit == 0) ? 100 : ceil($upload*100/$limit);
-$prcent = min(100, $prcent);
+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));
 
-$dir = 'img/members/'.$id.'/';
-$aconf = unserialize($pun_config['o_uploadile_other']);
-$extsup = explode(',', $extsup.','.strtoupper($extsup));
+$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 (isset($_GET['delete']))
-{
-	confirm_referrer(PLUGIN_REF);
+// Удаление файла
+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']);
+		}
 
-	$error = 0;
+		$count = count($words);
 
-	if (is_dir(PUN_ROOT.$dir))
-	{
-		$file = parse_file(pun_trim($_GET['delete']));
-		$ext = strtolower(substr(strrchr($file, '.'), 1)); // берем расширение файла
-		if ($file[0] != '.' && $ext != '' && !in_array($ext, $extforno) && is_file(PUN_ROOT.$dir.$file))
-		{
-			if (unlink(PUN_ROOT.$dir.$file))
-			{
-				if (is_file(PUN_ROOT.$dir.'mini_'.$file))
-					unlink(PUN_ROOT.$dir.'mini_'.$file);
+		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) . '%\'';
 			}
-			else
-				$error++;
-		}
-		else
-			$error++;
-
-		// Считаем общий размер файлов юзера
-		$upload = dir_size($dir);
-		$db->query('UPDATE '.$db->prefix.'users SET upload='.$upload.' WHERE id='.$id) or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error());
-	}
-	else
-		$error++;
 
-	if (isset($_GET['ajx']))
-	{
-		$db->end_transaction();
-		$db->close();
+			$result = $db->query($query) or error('Unable to fetch search information', __FILE__, __LINE__, $db->error());
+			$count = $db->result($result);
+		}
 
-		header('Content-type: text/html; charset=utf-8');
+		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]);
+			}
 
-		if ($error)
-			exit('not ok');
+			$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));
 
-		exit('ok');
+			$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;
 	}
 
-	$s = $lang_up['Redirect delete'];
-	if ($error)
-	{
-		$pun_config['o_redirect_delay'] = 5;
-		$s = $lang_up['Error'].$lang_up['Error delete'];
+	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']);
 	}
-	redirect(empty($_GET['p']) || $_GET['p'] < 2 ? PLUGIN_URL : PLUGIN_URLD.'p='.intval($_GET['p']).'#gofile', $s);
 }
 
 // Загрузка файла
-else if (isset($_FILES['upfile']) && $id == $pun_user['id'])
-{
-	$pun_config['o_redirect_delay'] = 5;
+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 1: // UPLOAD_ERR_INI_SIZE
-			case 2: // UPLOAD_ERR_FORM_SIZE
-				redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Too large ini']);
+	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 3: // UPLOAD_ERR_PARTIAL
-				redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Partial upload']);
+			case UPLOAD_ERR_FORM_SIZE:
+				upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_FORM_SIZE']);
 				break;
-
-			case 4: // UPLOAD_ERR_NO_FILE
-				redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['No file']);
+			case UPLOAD_ERR_PARTIAL:
+				upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_PARTIAL']);
 				break;
-
-			case 6: // UPLOAD_ERR_NO_TMP_DIR
-				redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['No tmp directory']);
+			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:
-				// No error occured, but was something actually uploaded?
-				if ($uploaded_file['size'] == 0)
-					redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['No file']);
+				upf_redirect(PLUGIN_URL, $lang_up['UPLOAD_ERR_UNKNOWN']);
 				break;
 		}
 	}
 
-	if (is_uploaded_file($_FILES['upfile']['tmp_name']))
-	{
-		confirm_referrer(PLUGIN_REF);
+	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()) . ')'); //????
+			}
 
-		$f = pathinfo(parse_file($_FILES['upfile']['name']));
-		if (empty($f['extension']))
-			redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Bad type']);
-
-		// Проверяем расширение
-		$ext = strtolower($f['extension']);
-		if (in_array($ext, $extforno) || !in_array($ext, $extsup))
-			redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Bad type']);
-
-		// Проверяется максимальный размер файла
-		if ($_FILES['upfile']['size'] > $maxsize)
-			redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Too large'].' '.pun_htmlspecialchars(file_size($maxsize)).'.');
-
-		// Проверяем допустимое пространство
-		if ($_FILES['upfile']['size'] + $upload > $limit)
-			redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Error space']);
-
-		// Проверяем картинку (флэш) на правильность
-		$isimg2 = (in_array($ext, $extimage));
-		$size = @getimagesize($_FILES['upfile']['tmp_name']);
-		if (($size === false && $isimg2) || ($size !== false && !$isimg2))
-			redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Error img']);
-		if ($isimg2)
-		{
-			$isimge = false;
-
-			if (empty($size[0]) || empty($size[1]) || empty($size[2]))
-				$isimge = true;
-			else if (!isset($extimage2[$size[2]]) || !in_array($ext, $extimage2[$size[2]]))
-				$isimge = true;
-			if ($isimge)
-				redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Error img']);
+			// картика стала больше после ресайза
+			if (filesize($fileinfo['path']) > $_FILES['upfile']['size']) {
+				$saveImage = false;
+				unlink($fileinfo['path']);
+			}
 		}
+	}
 
-		// обрабатываем имя
-		$name = str_replace('.', '_', $f['filename']);
-		if (substr($name, 0, 5) == 'mini_')
-			$name = substr($name, 5);
-		if ($name == '')
-			$name = 'none';
-		if (strlen($name) > 100)
-			$name = substr($name, 0, 100);
-		if (is_file(PUN_ROOT.$dir.$name.'.'.$ext) || is_file(PUN_ROOT.$dir.$name.'.jpeg')) // если уже есть, переименуем
-			$name = $name.'_'.parse_file(date('Ymd\-Hi', time()));
-
-		if (!is_dir(PUN_ROOT.'img/members/'))
-			mkdir(PUN_ROOT.'img/members', 0755);
-		if (!is_dir(PUN_ROOT.$dir))
-			mkdir(PUN_ROOT.'img/members/'.$id, 0755);
-
-		if ($_FILES['upfile']['size'] > $aconf['pic_mass'] && $isimg2 && $gd && array_key_exists($ext,$extimageGD))
-		{
-			$ext_ml = img_resize($_FILES['upfile']['tmp_name'], $dir, $name, $ext, $aconf['pic_w'], $aconf['pic_h'], $aconf['pic_perc'], true);
-			if (!is_array($ext_ml))
-				redirect(PLUGIN_URL, $lang_up['Error'].sprintf($lang_up['Error no mod img'], $ext_ml));
-
-			list($name, $ext) = $ext_ml;
+	// сохранение файла
+	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);
 		}
-		else
-		{
-			$error = isXSSattack($_FILES['upfile']['tmp_name']);
-			if ($error !== false)
-				redirect(PLUGIN_URL, $lang_up['Error'].$error);
-
-			if (!@move_uploaded_file($_FILES['upfile']['tmp_name'], PUN_ROOT.$dir.$name.'.'.$ext))
-				redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Move failed']);
-			@chmod(PUN_ROOT.$dir.$name.'.'.$ext, 0644);
+
+		if (false === $fileinfo) {
+			upf_redirect(PLUGIN_URL, $lang_up['Move failed'] . ' (' . pun_htmlspecialchars($upf_class->getError()) . ')'); //????
 		}
+	}
 
-		// Создание привьюшки (только для поддерживаемых GD форматов)
-		if ($aconf['thumb'] == 1 && $isimg2 && $gd && array_key_exists($ext,$extimageGD))
-			img_resize(PUN_ROOT.$dir.$name.'.'.$ext, $dir, 'mini_'.$name, $ext, 0, $aconf['thumb_size'], $aconf['thumb_perc']);
+	// превью
+	if (true === $upf_class->isImage() && 1 == $upf_conf['thumb'] && $upf_class->isResize()) {
+		$upf_class->setImageQuality($upf_conf['thumb_perc']);
 
-		// Считаем общий размер файлов юзера
-		$upload = dir_size($dir);
-		$db->query('UPDATE '.$db->prefix.'users SET upload=\''.$upload.'\' WHERE id='.$id) or error($lang_up['Error DB ins-up'], __FILE__, __LINE__, $db->error());
+		$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);
+			}
+		}
+	}
 
-		$pun_config['o_redirect_delay'] = '1';
+	$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']);
 	}
-	else
-		redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Unknown failure']);
 }
 
 // Unknown failure
-else if (!empty($_POST))
-	redirect(PLUGIN_URL, $lang_up['Error'].$lang_up['Unknown failure']);
+else if (($upf_ajax && 'view' !== $upf_action) || (! $upf_ajax && ! empty($_POST))) {
+	upf_redirect(PLUGIN_URL, $lang_up['Unknown failure']);
+}
 
 // #############################################################################
 
-if (!isset($page_head))
-	$page_head = array();
+$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('&amp;', '&', 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
+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';
+require PUN_ROOT . 'header.php';
 $tpl_main = str_replace('id="punhelp"', 'id="punupfiles"', $tpl_main);
 
-$tabi = 0;
+$tabindex = 1;
 
-$vcsrf = (function_exists('csrf_hash')) ? csrf_hash() : '1';
+$upf_token = function_exists('csrf_hash') ? csrf_hash() : pun_csrf_token();
 
-if ($fpr)
-{
+if ($fpr) {
 	// Load the profile.php language file
-	require PUN_ROOT.'lang/'.$pun_user['language'].'/profile.php';
+	require PUN_ROOT . 'lang/' . $pun_user['language'] . '/profile.php';
 
 	generate_profile_menu('upload');
 }
 
-if ($id == $pun_user['id'])
-{
+if ($id == $pun_user['id']) {
 
 ?>
 	<div class="blockform">
-		<h2><span><?php echo $lang_up['titre_2'] ?></span></h2>
+		<h2><span><?= $lang_up['titre_2'] ?></span></h2>
 		<div class="box">
-			<form method="post" action="<?php echo PLUGIN_URL ?>" enctype="multipart/form-data">
-				<input type="hidden" name="csrf_hash" value="<?php echo $vcsrf ?>" />
-				<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $maxsize; ?>" />
+			<form method="post" action="<?= PLUGIN_URL ?>" enctype="multipart/form-data">
 				<div class="inform">
 					<fieldset>
-						<legend><?php echo $lang_up['legend'] ?></legend>
+						<legend><?= $lang_up['legend'] ?></legend>
 						<div class="infldset">
-							<p><?php echo $lang_up['fichier'] ?></p>
-							<input type="file" id="upfile" name="upfile" tabindex="<?php echo $tabi++ ?>" />
-							<p><?php	printf($lang_up['info_2'], pun_htmlspecialchars(file_size($maxsize)), pun_htmlspecialchars(str_replace(',', ', ', $pun_user['g_up_ext']))) ?></p>
+							<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="<?php echo $lang_up['Upload'] ?>" tabindex="<?php echo $tabi++ ?>" /></p>
+				<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'];
-}
-
-$files = $filesvar = array();
-if (is_dir(PUN_ROOT.$dir))
-{
-	$open = opendir(PUN_ROOT.$dir);
-	while (($file = readdir($open)) !== false)
-	{
-		if (is_file(PUN_ROOT.$dir.$file))
-		{
-			$ext = strtolower(substr(strrchr($file, '.'), 1));
-			if (!in_array($ext, $extforno) && $file[0] != '#' && substr($file, 0, 5) != 'mini_')
-			{
-				$time = filemtime(PUN_ROOT.$dir.$file).$file;
-				$filesvar[$time] = $dir.$file;
-			}
-		}
-	}
-	closedir($open);
-	if (!empty($filesvar))
-	{
-		$num_pages = ceil(sizeof($filesvar) / PLUGIN_NF);
-		$p = (!isset($_GET['p']) || $_GET['p'] <= 1) ? 1 : intval($_GET['p']);
-		if ($p > $num_pages)
-		{
-			header('Location: '.str_replace('&amp;', '&', PLUGIN_URLD).'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 = str_replace(PLUGIN_REF.'&amp;', PLUGIN_REF.'?', $paging_links);
-		$paging_links = preg_replace('%href="([^">]+)"%', 'href="$1#gofile"', $paging_links);
-
-		krsort($filesvar);
-		$files = array_slice($filesvar, $start_from, PLUGIN_NF);
-		unset($filesvar);
-	}
+} else {
+	$tit = pun_htmlspecialchars($usname) . ' - ' . $lang_up['upfiles'];
 }
 
 ?>
 	<div id="upf-block" class="block">
-		<h2 id="gofile" class="block2"><span><?php echo $tit ?></span></h2>
+		<h2 id="gofile" class="block2"><span><?= $tit ?></span></h2>
 		<div class="box">
 <?php
 
-if (empty($files))
-{
-	echo "\t\t\t".'<div class="inbox"><p><span>'.$lang_up['No upfiles'].'</span></p></div>'."\n";
-}
-else
-{
+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 . '&amp;', PLUGIN_REF . '?', $paging_links);
+	$paging_links = preg_replace('%href="([^">]+)"%', 'href="$1#gofile"', $paging_links);
 
 ?>
 			<div class="inbox">
 				<div id="upf-legend">
-					<div style="<?php echo 'background-color: rgb('.ceil(($prcent > 50 ? 50 : $prcent)*255/50).', '.ceil(($prcent < 50 ? 50 : 100 - $prcent)*255/50).', 0); width:'.$prcent.'%;' ?>"><?php echo $prcent.'%' ?></div>
+					<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"><?php echo sprintf($lang_up['info_4'], pun_htmlspecialchars(file_size($upload)),pun_htmlspecialchars(file_size($limit))) ?></p>
+				<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"><?php echo $paging_links ?></p>
+					<p class="pagelink conl"><?= $paging_links ?></p>
 				</div>
 			</div>
 			<div class="inbox">
@@ -377,33 +499,22 @@ else
 					<ul id="upf-list">
 <?php
 
-	$height = max(intval($aconf['thumb_size']), 100);
-	$regx = '%^img/members/'.$id.'/(.+)\.([0-9a-zA-Z]+)$%i';
-	foreach($files as $file)
-	{
-		preg_match($regx, $file, $fi);
-		if (!isset($fi[1]) || !isset($fi[2]) || in_array(strtolower($fi[2]), $extforno))
-			continue;
-
-		$fb = in_array(strtolower($fi[2]), array('jpg', 'jpeg', 'gif', 'png', 'bmp')) ? '" class="fancy_zoom" rel="vi001' : '';
-		$size_file = file_size(filesize(PUN_ROOT.$file));
-		$f = $fi[1].'.'.$fi[2];
-		$m = 'mini_'.$f;
-		$mini = $dir.$m;
-		$fmini = (is_file(PUN_ROOT.$mini));
+	$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="<?php echo pun_htmlspecialchars($f) ?>"><span><?php echo pun_htmlspecialchars(pun_strlen($f) > 20 ? utf8_substr($f, 0, 18).'…' : $f) ?></span></div>
-							<div class="upf-file" style="height:<?php echo $height ?>px;">
-								<a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/'.$file).$fb ?>">
-<?php if ($fmini || $fb): ?>									<img src="<?php echo pun_htmlspecialchars($fmini ? get_base_url(true).'/'.$mini : get_base_url(true).'/'.$file) ?>" alt="<?php echo pun_htmlspecialchars((pun_strlen($fi[1]) > 15 ? utf8_substr($fi[1], 0, 10).'… ' : $fi[1]).'.'.$fi[2]) ?>" />
-<?php else: ?>									<span><?php echo pun_htmlspecialchars((pun_strlen($fi[1]) > 15 ? utf8_substr($fi[1], 0, 10).'… ' : $fi[1]).'.'.$fi[2]) ?></span>
+							<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><?php echo pun_htmlspecialchars($size_file) ?></span></div>
-							<div class="upf-but upf-delete"><a title="<?php echo $lang_up['delete'] ?>" href="<?php echo PLUGIN_URLD.'csrf_hash='.$vcsrf.(empty($_GET['p']) || $_GET['p'] < 2 ? '' : '&amp;p='.intval($_GET['p'])).'&amp;delete='.$f ?>" onclick="return FluxBB.upfile.del(this);"><span></span></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 ? '' : '&amp;p=' . $upf_page) . '&amp;action=delete&amp;file=' . pun_htmlspecialchars($file['filename']) ?>" onclick="return FluxBB.upfile.del(this);"><span></span></a></div>
 						</li>
 <?php
 
@@ -415,7 +526,7 @@ else
 			</div>
 			<div class="inbox">
 				<div class="pagepost">
-					<p class="pagelink conl"><?php echo $paging_links ?></p>
+					<p class="pagelink conl"><?= $paging_links ?></p>
 				</div>
 			</div>
 <?php
@@ -427,8 +538,14 @@ else
 	</div>
 <?php
 
-if ($fpr)
-	echo "\t".'<div class="clearer"></div>'."\n".'</div>'."\n";
+if ($fpr) {
+
+?>
+	<div class="clearer"></div>
+</div>
+<?php
+
+}
 
 ?>
 <script type="text/javascript">
@@ -449,7 +566,7 @@ FluxBB.upfile = (function (doc, win) {
 	}
 
 	function is_img(a) {
-		return /.+\.(jpg|jpeg|png|gif|bmp)$/.test(a);
+		return /.+\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(a);
 	}
 
 	function get_us(li) {
@@ -472,13 +589,13 @@ FluxBB.upfile = (function (doc, win) {
 		if (!!url) {
 			var div = createElement('div');
 			div.className = 'upf-but upf-insert';
-			div.innerHTML = '<a title="<?php echo $lang_up['insert'] ?>" href="#" onclick="return FluxBB.upfile.ins(this);"><span></span></a>';
+			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="<?php echo $lang_up['insert_thumb'] ?>" href="#" onclick="return FluxBB.upfile.ins(this, 1);"><span></span></a>';
+				div.innerHTML = '<a title="<?= $lang_up['insert_thumb'] ?>" href="#" onclick="return FluxBB.upfile.ins(this, 1);"><span></span></a>';
 				li.appendChild(div);
 			}
 		}
@@ -514,11 +631,31 @@ FluxBB.upfile = (function (doc, win) {
 	}
 
 	function orsc(req, ref) {
-		if (req.readyState == 4)
-		{
+		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 (req.status == 200 && req.responseText == 'ok') {
+			if (!error) {
 				ref.parentNode.parentNode.parentNode.removeChild(ref.parentNode.parentNode);
 				if (get('upf-list').getElementsByTagName('li').length == 0) {
 					win.location.reload(true);
@@ -531,13 +668,15 @@ FluxBB.upfile = (function (doc, win) {
 
 		del : function (ref) {
 			if (ref.className) return !1;
-			if (!confirm('<?php echo addslashes($lang_up['delete file']) ?>')) 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.onreadystatechange = function() {
+					orsc(req, ref);
+				};
 				req.open('GET', ref.href + '&ajx=1', true);
 				req.send();
 
@@ -557,7 +696,7 @@ FluxBB.upfile = (function (doc, win) {
 				insr('', '[img]' + url + '[/img]', '');
 			} else {
 				if (f = url.match(/.*\/img\/members\/\d+\/(.+)$/)) f = f[1];
-				else f = '<?php echo $lang_up['texte'] ?>';
+				else f = '<?= $lang_up['texte'] ?>';
 
 				insr('[url=' + url + ']', '[/url]', f);
 			}
@@ -580,7 +719,7 @@ FluxBB.upfile = (function (doc, win) {
 		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);
+			} else doc.addEventListener('DOMContentLoaded', FluxBB.upfile.run, false);
 		}
 	};
 }(document, window));
@@ -590,4 +729,4 @@ FluxBB.upfile.init();
 </script>
 <?php
 
-require PUN_ROOT.'footer.php';
+require PUN_ROOT . 'footer.php';