| // +---------------------------------------------------------------------------+ // /** * @package Capsule */ namespace App\Ajax\Controller; use App\Ajax\Controller\Controller; use App\Cms\Cms; use Capsule\Common\Path; use Capsule\Capsule; use Capsule\DataStruct\ReturnValue; use Capsule\Superglobals\Post; use Capsule\I18n\Lang; use Capsule\File\Upload\Msg; use Capsule\Plugin\Storage\Storage; use App\Cms\Model\HistoryUploadImage; /** * CpUpload.php * * @package Capsule * @author kenik * * @property */ class CpUpload extends Controller { protected $result; protected $maxWidth = 128; protected $maxHeight = 128; protected $maxSize = 3; /** * Загрузить одно изображение * * @param void * @return void */ protected function uploadNewAvatar() { $path = new Path(array( Capsule::getInstance()->systemRoot, Cms::getInstance()->config->templates, '/ajax/' . __FUNCTION__ . '.php') ); #die($path); #include $path; print $this->uploadSingleImageHandler()->toJson(); } /** * Обработчик загрузки изображений вызываемый из ajax ответа шаблона * * @param void * @return \Capsule\DataStruct\ReturnValue */ private function uploadSingleImageHandler() { $this->result = new ReturnValue(); $this->result->error = null; $this->retrieveImage(); return $this->result; } /** * Возвращает изображение * * @param void * @return resource */ private function retrieveImage() { $image = $this->getPastedImage(); if (!is_array($image)) { if ($this->result->error) { return false; } $image = $this->getUploadedImage(); if (!is_array($image)) { if (!$this->result->error) { $this->result->error = Lang::_('Unable to upload file'); } return false; } } $image = $this->resize($image); $image = $this->crop($image); $tmp_handle = tmpfile(); $meta = stream_get_meta_data($tmp_handle); $path = $meta['uri']; switch ($image['extension']) { case 'jpg': $result = imagejpeg($image['image'], $path); break; case 'gif': $result = imagegif($image['image'], $path); break; default: $result = imagepng($image['image'], $path, 9); break; } if (!$result) { $this->result->error = Lang::_('Unable to save image'); return false; } try { $result = Storage::getInstance()->addFile($path, $image['extension']); } catch (\Exception $e) { $this->result->error = Lang::_('Unable to save file'); return false; } $image = array_replace($image, $result); imagedestroy($image['image']); unset($image['image']); $history = new HistoryUploadImage(); foreach ($image as $k => $v) { $this->result->$k = $v; $history->$k = $v; } $history->path = $history->url; $history->storage = Storage::getInstanceName(Storage::getInstance()); HistoryUploadImage::deleteSamePath($history); $history->store(); $this->result->historyId = $history->id; } /** * Возвращает изображение, вставленное из буфера обмена в строку. * * @param void * @return array|false */ private function getPastedImage() { $image_string = Post::getInstance()->get('imageString'); if (is_null($image_string)) { return false; } if (!is_scalar($image_string)) { return false; } if (!$image_string) { return false; } $image_string = base64_decode($image_string); if (!$image_string) { $this->result->error = Lang::_('Unable to decode image string'); return false; } /** * Сначала создаем изображение поддерживаеиого типа а потом уже * выполняем getimagesize. * см. http://habrahabr.ru/post/224351/ */ $image = imagecreatefromstring($image_string); if (!is_resource($image)) { $this->result->error = Lang::_('Unable to load image'); return false; } $img_info = getimagesizefromstring($image_string); if (false === $img_info) { $this->result->error = Lang::_('Unable to read image'); return false; } $width = imagesx($image); $height = imagesy($image); if ($width !== $img_info[0]) { $this->result->error = Lang::_('Image is corrupted'); return false; } if ($height !== $img_info[1]) { $this->result->error = Lang::_('Image is corrupted'); return false; } if ($width > $this->maxWidth) { $this->result->error = Lang::_('Image is too big. Maximum image size is 128x128'); return false; } if ($height > $this->maxWidth) { $this->result->error = Lang::_('Image is too big. Maximum image size is 128x128'); return false; } if (!$width) { $this->result->error = Lang::_('Image data is empty'); return false; } if (!$height) { $this->result->error = Lang::_('Image data is empty'); return false; } if (image_type_to_mime_type(IMAGETYPE_PNG) !== $img_info['mime']) { $this->result->error = Lang::_('Image type unsupported error'); return false; } imagealphablending($image, false); imagesavealpha($image, true); return array( 'image' => $image, 'width' => $width, 'height' => $height, 'mime' => $img_info['mime'], 'extension' => 'png', 'name' => 'clipboard.png' ); } /** * Возвращает изображение, загруженное из файла. * * @param void * @return array|false */ private function getUploadedImage() { if (!isset($_FILES['file'])) { return false; } $file = $_FILES['file']; $keys = array( 'name', 'type', 'tmp_name', 'error', 'size' ); foreach ($keys as $key) { if (!isset($file[$key])) { $this->result->error = Lang::_('No file specified'); return false; } if (!is_scalar($file[$key])) { $this->result->error = Lang::_('No file specified'); return false; } } $name = $file['name']; $type = $file['type']; $tmp_name = $file['tmp_name']; $error = $file['error']; $size = $file['size']; if ($error) { $this->result->error = Lang::_(Msg::msg($error)); return false; } if (!is_uploaded_file($tmp_name)) { $this->result->error = Lang::_('Unable to upload file'); return false; } $extension = pathinfo($name, PATHINFO_EXTENSION); if (!$extension) { $this->result->error = Lang::_('File without extension'); return false; } $extension = strtolower($extension); $type_to_extension = array( 'jpg' => 'jpg', 'jpeg' => 'jpg', 'png' => 'png', 'gif' => 'gif', ); if (!array_key_exists($extension, $type_to_extension)) { $this->result->error = Lang::_('Unsupported extension'); return false; } $extension = $type_to_extension[$extension]; $image = null; /** * Сначала создаем изображение поддерживаеиого типа а потом уже * выполняем getimagesize. * см. http://habrahabr.ru/post/224351/ */ switch ($extension) { case 'jpg': $image = imagecreatefromjpeg($tmp_name); break; case 'png': $image = @imagecreatefrompng($tmp_name); imagealphablending($image, false); imagesavealpha($image, true); break; case 'gif': $image = @imagecreatefromgif($tmp_name); break; default: $this->result->error = Lang::_('Unsupported extension'); return false; break; } if (!is_resource($image)) { $this->result->error = Lang::_('Unable to load image'); return false; } $img_info = getimagesize($tmp_name); if (false === $img_info) { $this->result->error = Lang::_('Unable to read image'); return false; } $width = imagesx($image); $height = imagesy($image); if ($width !== $img_info[0]) { $this->result->error = Lang::_('Image is corrupted'); return false; } if ($height !== $img_info[1]) { $this->result->error = Lang::_('Image is corrupted'); return false; } if ($width > $this->maxWidth) { $this->result->error = Lang::_('Image is too big. Maximum image size is 128x128'); return false; } if ($height > $this->maxWidth) { $this->result->error = Lang::_('Image is too big. Maximum image size is 128x128'); return false; } if (!$width) { $this->result->error = Lang::_('Image data is empty'); return false; } if (!$height) { $this->result->error = Lang::_('Image data is empty'); return false; } if (image_type_to_mime_type(IMAGETYPE_PNG) !== $img_info['mime'] && image_type_to_mime_type(IMAGETYPE_JPEG) !== $img_info['mime'] && image_type_to_mime_type(IMAGETYPE_GIF) !== $img_info['mime']) { $this->result->error = Lang::_('Image type unsupported error'); return false; } return array( 'image' => $image, 'width' => $width, 'height' => $height, 'mime' => $img_info['mime'], 'extension' => $extension, 'name' => $name ); } /** * Resize image * * @param array $image * @return array */ private function resize(array $image) { $keys = array('width', 'height'); $post = Post::getInstance(); foreach ($keys as $key) { $$key = $post->$key; if (!is_scalar($$key)) return $image; if (!ctype_digit($$key)) return $image; $$key = intval($$key); if (!$$key) return $image; } $width = ${'width'}; $height = ${'height'}; if ($width === $image['width'] && $height === $image['height']) return $image; $k = 1.7; // Коэффициент пошагового увеличения $tmp_width = intval($image['width'] * $k); if ($tmp_width > $width) { $tmp_width = $width; } $tmp_height = intval($image['height'] * $k); if ($tmp_height > $height) { $tmp_height = $height; } $src_img = $image['image']; if ('gif' === $image['extension']) { $tmp_width = $width; $tmp_height = $height; } while ($tmp_height < $height || $tmp_width < $width) { $tmp_img = imagecreatetruecolor($tmp_width, $tmp_height); if ('png' === $image['extension']) { imagealphablending($tmp_img, false); imagesavealpha($tmp_img, true); $src_trans = imagecolorallocatealpha($tmp_img, 255, 255, 255, 127); imagefill($tmp_img, 0, 0, $src_trans); } elseif ('gif' === $image['extension']) { $src_trans = imagecolortransparent($src_img); if ($src_trans != (-1)) { $transparent_color = ImageColorsForIndex($src_img, $src_trans); } if (!empty($transparent_color)) { /* simple check to find wether transparent color was set or not */ $transparent_new = ImageColorAllocate($tmp_img, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); imagefill($tmp_img, 0, 0, $transparent_new ); /* don't forget to fill the new image with the transparent color */ $transparent_new_index = ImageColorTransparent($tmp_img, $transparent_new); } } if (false === imagecopyresampled($tmp_img, $src_img, 0, 0, 0, 0, $tmp_width, $tmp_height, $image['width'], $image['height'])) { imagedestroy($tmp_img); return $image; } $image['width'] = $tmp_width; $image['height'] = $tmp_height; $src_img = $tmp_img; $tmp_width = intval($image['width'] * $k); if ($tmp_width > $width) { $tmp_width = $width; } $tmp_height = intval($image['height'] * $k); if ($tmp_height > $height) { $tmp_height = $height; } } $dst_image = imagecreatetruecolor($width, $height); if ('png' === $image['extension']) { imagealphablending($dst_image, false); imagesavealpha($dst_image, true); $src_trans = imagecolorallocatealpha($dst_image, 255, 255, 255, 127); imagefill($dst_image, 0, 0, $src_trans); } elseif ('gif' === $image['extension']) { $src_trans = imagecolortransparent($src_img); if ($src_trans != (-1)) { $transparent_color = ImageColorsForIndex($src_img, $src_trans); } if (!empty($transparent_color)) { /* simple check to find wether transparent color was set or not */ $transparent_new = ImageColorAllocate($dst_image, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); imagefill($dst_image, 0, 0, $transparent_new); /* don't forget to fill the new image with the transparent color */ $transparent_new_index = ImageColorTransparent($dst_image, $transparent_new); } } if (false === imagecopyresampled($dst_image, $src_img, 0, 0, 0, 0, $tmp_width, $tmp_height, $image['width'], $image['height'])) { imagedestroy($dst_image); return $image; } imagedestroy($image['image']); $image['image'] = $dst_image; $image['width'] = $width; $image['height'] = $height; return $image; } /** * Crop image * * @param array $image * @return array */ private function crop(array $image) { $keys = array('x1', 'y1', 'x2', 'y2'); $post = Post::getInstance(); foreach ($keys as $key) { $$key = $post->$key; if (!is_scalar($$key)) return $image; if (!ctype_digit($$key)) return $image; $$key = intval($$key); if (!$$key && 0 !== $$key) return $image; } $x1 = ${'x1'}; $y1 = ${'y1'}; $x2 = ${'x2'}; $y2 = ${'y2'}; $src_width = $image['width']; $src_height = $image['height']; if ($x1 >= $src_width) return $image; if ($x2 >= $src_width) return $image; if ($y1 >= $src_height) return $image; if ($y2 >= $src_height) return $image; $dst_width = abs($x2 - $x1) + 1; $dst_height = abs($y2 - $y1) + 1; if ($x1 + $dst_width > $src_width) return $image; if ($y1 + $dst_height > $src_height) return $image; $dst_image = imagecreatetruecolor($dst_width, $dst_height); if ('png' === $image['extension']) { imagealphablending($dst_image, false); imagesavealpha($dst_image, true); $src_trans = imagecolorallocatealpha($dst_image, 255, 255, 255, 127); imagefill($dst_image, 0, 0, $src_trans); } elseif ('gif' === $image['extension']) { $src_trans = imagecolortransparent($image['image']); imagepalettecopy($dst_image, $image['image']); imagefill($dst_image, 0, 0, $src_trans); imagecolortransparent($dst_image, $src_trans); } if (false === imagecopyresampled($dst_image, $image['image'], 0, 0, $x1, $y1, $dst_width, $dst_height, $dst_width, $dst_height)) { imagedestroy($dst_image); return $image; } imagedestroy($image['image']); $image['image'] = $dst_image; $image['width'] = $dst_width; $image['height'] = $dst_height; return $image; } /** * Меняет значение favorites на противоположное * * @param void * @return void */ protected function toggleFavoritesImage() { $ret = array( 'error' => true ); $image = HistoryUploadImage::id(Post::getInstance()->gets('id')); if ($image) { $k = 'favorites'; $v = $image->$k; $image->$k = !$v; $image->store(); $ret[$k] = !$v; $ret['error'] = false; } print json_encode($ret); } /** * Устанавливает значение favorites в true * * @param void * @return void */ protected function addToFavoritesImage() { $ret = array( 'error' => true ); $image = HistoryUploadImage::id(Post::getInstance()->gets('id')); if ($image) { $image->favorites = true; $image->store(); $ret['error'] = false; } print json_encode($ret); } /** * Добавляет комментарий к изображению * * @param void * @return void */ protected function commentImage() { $ret = array( 'error' => true ); $image = HistoryUploadImage::id(Post::getInstance()->gets('id')); if ($image) { $image->comment = Post::getInstance()->gets('comment'); $image->store(); $ret['error'] = false; } print json_encode($ret); } /** * Удаляет изображение из истории и из хранилища, если хранилищем * поддерживается функция удаления * * @param void * @return void */ protected function deleteImage() { $ret = array( 'error' => true ); $image = HistoryUploadImage::id(Post::getInstance()->gets('id')); if ($image) { $filename = pathinfo($image->path, PATHINFO_BASENAME); try { Storage::getInstance()->delFile($filename); } catch (\Exception $e) { } HistoryUploadImage::del($image->id); $ret['error'] = false; } print json_encode($ret); } }