3 * Thumbnail plugin for Nucleus CMS
4 * Version 4.0.0 for PHP5
5 * Written By Mocchi, Apr. 06, 2011
6 * Original code was written by jirochou, May 23, 2004 and maintained by nakahara21
7 * This plugin depends on NP_MediaUtils
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 3
12 * of the License, or (at your option) any later version.
15 class NP_Thumbnail extends NucleusPlugin
17 private static $thumbdir = '.thumb';
18 private static $max_sync = 10;
19 private static $authorid = 0;
20 private static $buffering = FALSE;
21 private static $table_name = 'plugin_thumbnail'; // not implemented yet
23 public function getName() { return 'Thumbnail'; }
24 public function getAuthor() { return 'Mocchi, nakahara21, jirochou'; }
25 public function getURL() { return 'http://japan.nucleuscms.org/wiki/plugins:thumbnail'; }
26 public function getVersion() { return '4.0.0'; }
27 public function getDescription() { return _NP_THUMBNAIL_01; }
28 public function getPluginDep() { return array('NP_MediaUtils'); }
29 public function getMinNucleusVersion() { return 340; }
30 public function supportsFeature($feature) { return in_array ($feature, array('SqlTablePrefix', 'SqlApi'));}
31 public function getEventList() { return array('QuickMenu', 'PrePluginOptionsEdit', 'PostAuthentication', 'PreItem', 'PostMediaUpload'); }
33 public function install ()
35 $this->createOption('maxwidth', '_NP_THUMBNAIL_02', 'text', '100', 'datatype=numerical');
36 $this->createOption('maxheight', '_NP_THUMBNAIL_03', 'text', '100', 'datatype=numerical');
37 $this->createOption('save_thumb', '_NP_THUMBNAIL_04', 'select', 'filesystem', '_NP_THUMBNAIL_05|no|_NP_THUMBNAIL_06|filesystem');
38 $this->createBlogOption('force_thumb', '_NP_THUMBNAIL_07', 'yesno', 'yes');
39 $this->createBlogOption('thumb_template', '_NP_THUMBNAIL_08', 'textarea', '<a href="<%rawpopuplink%>" title="<%popuptext%>" onclick="<%popupcode%>"><img src="<%thumb_url%>" width="<%thumb_width%>" height="<%thumb_height%>" alt="<%popuptext%>" /></a>');
44 * plugin options are purged automatically when uninstalled.
46 public function uninstall()
49 MediaUtils::purgeDir($DIR_MEDIA . self::$thumbdir);
53 public function init()
59 if ( !class_exists('Medium', FALSE) )
61 $manager->getPlugin('NP_Thumbnail');
66 if ( class_exists('i18n', FALSE) )
68 $locale = i18n::get_current_locale() . '.' . i18n::get_current_charset() . '.php';
73 $language = preg_replace('#[/|\\\\]#', '', getLanguageName());
74 if ( $language == 'japanese-euc' )
76 $locale = 'ja_Jpan_JP.EUC-JP.php';
78 else if ( $language = 'japanese-utf8' )
80 $locale = 'ja_Jpan_JP.UTF-8.php';
84 if ( !$locale || !file_exists($this->getDirectory() . $locale) )
86 include($this->getDirectory() . 'en_Latn_US.ISO-8859-1.php');
90 include($this->getDirectory() . $locale);
99 public function event_PrePluginOptionsEdit($data)
101 /* Old version do not support natively */
102 if ( getNucleusVersion() < 400 )
104 if ( $data['context'] != 'global' )
106 foreach ( $data['options'] as $key => $option )
108 if ( $option['pid'] == $this->getID() )
110 if ( defined($option['description']) )
112 $data['options'][$key]['description'] = constant($option['description']);
114 if ( $option['type'] == 'select' )
116 foreach ( explode('|', $option['typeinfo']) as $option )
118 if ( defined($option) )
120 $data['options'][$key]['typeinfo'] = str_replace($option, constant($option), $data['options'][$key]['typeinfo']);
127 else if ($data['plugid'] == $this->getID() )
129 foreach ( $data['options'] as $key => $option )
131 if ( defined($option['description']) )
133 $data['options'][$key]['description'] = constant($option['description']);
135 if ( $option['type'] == 'select' )
137 foreach ( explode('|', $option['typeinfo']) as $option )
139 if ( defined($option) )
141 $data['options'][$key]['typeinfo'] = str_replace($option, constant($option), $data['options'][$key]['typeinfo']);
155 static private function t($text, $array=array())
157 if ( is_array($array) )
162 foreach ( $array as $key => $value )
164 if ( is_array($value) )
168 $search[] = '<%'.preg_replace('/[^a-zA-Z0-9_]+/','',$key).'%>';
172 return htmlspecialchars(str_replace($search, $replace, $text), ENT_QUOTES, _CHARSET);
175 public function event_QuickMenu(&$data)
179 if ( $this->getOption('save_thumb') !== 'no' )
182 'title' => 'NP_Thumbnail',
183 'url' => "{$CONF['ActionURL']}?action=plugin&name={$this->getname()}&type=admin",
184 'tooltip' => _NP_THUMBNAIL_09);
185 array_push($data['options'], $option);
190 public function event_PostAuthentication(&$data)
192 if ( array_key_exists('action', $_REQUEST)
193 && array_key_exists('name', $_REQUEST)
194 && array_key_exists('type', $_REQUEST)
195 && array_key_exists('width', $_REQUEST)
196 && array_key_exists('height', $_REQUEST)
197 && $_REQUEST['action'] === 'plugin'
198 && $_REQUEST['name'] === $this->getName()
199 && $_REQUEST['type'] !== '' )
201 self::$buffering = ob_start;
206 public function doAction($type)
208 global $DIR_MEDIA, $member;
210 $type = (string) $type;
216 if ( array_key_exists('path', $_GET) )
218 $path = (string) $_GET['path'];
220 if ( array_key_exists('width', $_GET) )
222 $maxwidth = (integer) $_GET['width'];
224 if ( array_key_exists('height', $_GET) )
226 $maxheight = (integer) $_GET['height'];
229 if ( self::$buffering )
234 if ( in_array($type, array('admin', 'clear', 'sync')) && $member->isAdmin() )
236 $this->showAdmin($type);
240 if ( $maxwidth <= 0 || $maxwidth > 1000 || $maxheight <= 0 || $maxheight > 1000 )
242 MediaUtils::error($this->t(_NP_THUMBNAIL_10, array($maxwidth, $maxheight)));
246 if ( FALSE === ($medium = new Medium($DIR_MEDIA, $path, MediaUtils::$prefix)) )
248 MediaUtils::error($this->t(_NP_THUMBNAIL_11, array($path)));
252 if ( FALSE === $medium->setResampledSize($maxwidth, $maxheight) )
254 MediaUtils::error($this->t(_NP_THUMBNAIL_10, array($maxwidth, $maxheight)));
258 MediaUtils::responseResampledImage($medium);
262 public function doSkinVar($skinType)
269 /* retrieve arguments. This is for preventing E_STRICT */
270 $args = func_get_args();
271 if ( array_key_exists(0, $args) )
273 $path = (string) $args[0];
275 if ( array_key_exists(1, $args) )
277 $maxwidth = (integer) $args[1];
279 if ( array_key_exists(2, $args) )
281 $maxheight = (integer) $args[2];
283 if ( array_key_exists(3, $args) )
285 $alt = (string) $args[3];
288 if ( $this->getBlogOption(MediaUtils::$blogid, 'force_thumb') == 'yes' )
290 echo $this->getParsedTag(array('', '', $path, 0, 0, $alt), $maxwidth, $maxheight);
296 public function event_PreItem(&$data)
298 $item =& $data["item"];
299 self::$authorid = $item->authorid;
300 $item->body = preg_replace_callback("#<\%(Thumbnail)\((.*?)\|(.*?)\|(.*?)\|(.*?)\)%\>#", array(&$this, 'getParsedTag'), $item->body);
301 $item->more = preg_replace_callback("#<\%(Thumbnail)\((.*?)\|(.*?)\|(.*?)\|(.*?)\)%\>#", array(&$this, 'getParsedTag'), $item->more);
303 if ( $this->getBlogOption(MediaUtils::$blogid, 'force_thumb') == 'yes' )
305 $item->body = preg_replace_callback("#<\%(popup)\((.*?)\|(.*?)\|(.*?)\|(.*?)\)%\>#", array(&$this, 'getParsedTag'), $item->body);
306 $item->more = preg_replace_callback("#<\%(popup)\((.*?)\|(.*?)\|(.*?)\|(.*?)\)%\>#", array(&$this, 'getParsedTag'), $item->more);
311 public function event_PostMediaUpload(&$data)
315 if ( $this->getOption('save_thumb') == 'no' )
320 $root = rtrim($DIR_MEDIA, '/');
321 $path = trim($data['collection'], '/');
322 $filename = trim($data['filename'], '/');
323 $maxwidth = $this->getOption('maxwidth');
324 $maxheight = $this->getOption('maxheight');
326 if ( !MediaUtils::checkDir ($root . '/' . self::$thumbdir) )
331 if ( FALSE === ($medium = new Medium($root, "{$path}/{$filename}", MediaUtils::$prefix)) )
336 if ( !array_key_exists($medium->mime, MediaUtils::$image_mime) )
341 if ( FALSE === $medium->setResampledSize($maxwidth, $maxheight) )
346 $target = self::getThumbPath($medium);
348 if ( $this->getOption('save_thumb') == 'filesystem' )
350 if ( !file_exists("{$root}/{$target}")
351 && !MediaUtils::storeResampledImage ($DIR_MEDIA, $target, $medium) )
360 public function getParsedTag($match, $maxwidth=0, $maxheight=0)
362 global $DIR_MEDIA, $member;
364 list($code, $tag, $path, $width, $height, $alt) = $match;
366 if ( !preg_match("#^.+?/.+$#", $path) && self::$authorid )
368 $path = self::$authorid . '/' . $path;
371 if ( FALSE === ($medium = new Medium($DIR_MEDIA, $path, MediaUtils::$prefix)) )
373 return $this->t('NP_Thumbnail: 指定したメディアファイルを読み込めませんでした。', array($path));
376 if ( !array_key_exists($medium->mime, MediaUtils::$image_mime) )
378 return $this->t(_NP_THUMBNAIL_12, array($path));
381 if ( $tag == 'Thumbnail' )
383 $maxwidth = (integer) $width;
384 $maxheight = (integer) $height;
387 if ( ($maxwidth == 0) && ($maxheight == 0) )
389 $maxwidth = (integer) $this->getOption('maxwidth');
390 $maxheight = (integer) $this->getOption('maxheight');
393 if ( $maxwidth < 0 || $maxwidth > 1000 || $maxheight < 0 || $maxheight > 1000 )
395 return $this->t(_NP_THUMBNAIL_10, array($path));
398 if ( FALSE === $medium->setResampledSize($maxwidth, $maxheight) )
400 return $this->t('NP_Thumbnail: サムネイルのサイズが不正です。', array($path));
408 return $this->generateTag($this->getBlogOption(MediaUtils::$blogid, 'thumb_template'), $medium, $alt);
411 public function generateTag($template, $medium, $alt)
415 if ( !class_exists('BODYACTIONS', FALSE) )
417 include($DIR_LIBS . 'BODYACTIONS.php');
419 $action = new BODYACTIONS;
421 if ( array_key_exists($medium->mime, MediaUtils::$image_mime)
422 && $this->getOption('save_thumb') == 'filesystem' )
424 if ( !MediaUtils::checkDir ($medium->root . '/' . self::$thumbdir) )
426 return $this->t(_NP_THUMBNAIL_13, array(self::$thumbdir));
428 if ( !file_exists($medium->root . '/' . self::getThumbPath($medium)) )
430 MediaUtils::storeResampledImage ($medium->root, self::getThumbPath($medium), $medium);
435 if ( array_key_exists($medium->mime, MediaUtils::$image_mime) && $this->getThumbURL($medium) )
437 $action->template['POPUP_CODE'] = $template;
438 $replacements = array(
439 '<%thumb_width%>' => $medium->resampledwidth,
440 '<%thumb_height%>' => $medium->resampledheight,
441 '<%thumb_url%>' => $this->getThumbURL($medium)
443 foreach ( $replacements as $target => $replacement )
445 $action->template['POPUP_CODE'] = str_replace ($target, $replacement, $action->template['POPUP_CODE']);
447 $action->createPopupCode("{$medium->path}/{$medium->name}", $medium->width, $medium->height, $alt);
451 $action->template['MEDIA_CODE'] = $template;
452 $action->createMediaCode("{$medium->path}/{$medium->name}", $alt);
454 $tag = ob_get_contents();
457 return preg_replace('#href="(.*?)imagetext(.*?)"#', 'href="$1imagetext$2&blogid='.MediaUtils::$blogid . '"', $tag);
460 private function showAdmin($type)
462 global $CONF, $DIR_LIBS, $DIR_MEDIA, $manager;
464 $type = (string) $type;
466 if ( !class_exists ('PLUGINADMIN', FALSE) )
468 include ($DIR_LIBS . 'PLUGINADMIN.php');
471 $oPluginAdmin = new PluginAdmin('Thumbnail');
472 $oPluginAdmin->start();
474 echo "<h2>NP_Thumbnail</h2>\n";
476 if ( $this->getOption('save_thumb') === 'no' )
478 echo '<p>' . $this->t(_NP_THUMBNAIL_14) . "</p>\n";
479 $oPluginAdmin->end();
484 if ( $type == 'clear' )
486 if ( $this->getOption('save_thumb') == 'filesystem' )
488 $logs = MediaUtils::purgeDir($DIR_MEDIA, self::$thumbdir . '/');
492 echo "<p>" . $this->t(_NP_THUMBNAIL_15, array(self::$thumbdir)) . "<br />\n";
493 echo $this->t(_NP_THUMBNAIL_16, array(self::$max_sync)) . "<br />\n";
494 echo $this->t(_NP_THUMBNAIL_17) . "</p>\n";
496 if ( $type == 'sync' )
498 $maxwidth = $this->getOption('maxwidth');
499 $maxheight = $this->getOption('maxheight');
500 if ( $this->getOption('save_thumb') == 'filesystem' )
502 echo "<h3>" . $this->t(_NP_THUMBNAIL_22) . "</h3>\n";
503 if ( self::syncFilesystem ($DIR_MEDIA, self::$thumbdir, $maxwidth, $maxheight) )
505 echo "<p>何かのエラーメッセージ</p>\n";
510 $media = MediaUtils::getMediaList($DIR_MEDIA);
514 foreach ( $media as $medium )
516 if ( !array_key_exists($medium->mime, MediaUtils::$image_mime) )
520 if ( file_exists($DIR_MEDIA . self::getThumbPath($medium)) )
522 $rejected[] =& $medium;
527 $elected[] =& $medium;
532 $total_media = count ($media);
533 $total_elected = count ($elected);
534 $total_rejected = count ($rejected);
535 $total_images = count ($rejected) + $total_elected;
538 * NOTICE: NP_Improvededia with eachblogdir option rewrite
539 * global variables of "DIR_MEDIA" and "$CONF['MediaURL']"
540 * in its initializing process.
541 * (I realized it a bad behavior but there is no other way...)
542 * Here are based on its rewriting system.
545 if ( $manager->pluginInstalled('NP_ImprovedMedia') )
547 $NP_ImprovedMedia =& $manager->getPlugin('NP_ImprovedMedia');
548 if ( $NP_ImprovedMedia->getOption('IM_EACHBLOGDIR') == 'yes' )
550 echo "<form method=\"post\" action=\"{$CONF['ActionURL']}?action=plugin&name=Thumbnail\" enctype=\"application/x-www-form-urlencoded\">\n";
552 echo "<label for=\"blogid\">" . $this->t(_NP_THUMBNAIL_18) . "</label>\n";
553 echo "<select name=\"blogid\" id=\"blogid\"onchange=\"return form.submit()\">\n";
554 foreach ( MediaUtils::$blogs as $blogid => $bshortname )
556 if ( $blogid == MediaUtils::$blogid )
558 echo "<option value=\"{$blogid}\" selected=\"selected\">{$bshortname}</option>\n";
562 echo "<option value=\"{$blogid}\">{$bshortname}</option>\n";
566 echo "<input type=\"hidden\" id=\"admin\" name=\"type\" value=\"admin\">\n";
572 echo "<form method=\"post\" action=\"{$CONF['ActionURL']}?action=plugin&name=Thumbnail\" enctype=\"application/x-www-form-urlencoded\">\n";
574 echo "<li>" . $this->t(_NP_THUMBNAIL_19, array($total_media)) . "</li>\n";
575 echo "<li>" . $this->t(_NP_THUMBNAIL_20, array($total_images)) . "</li>\n";
576 echo "<li>" . $this->t(_NP_THUMBNAIL_21, array($total_rejected)) . "</li>\n";
579 echo '<input type="hidden" name="blogid" value="' . MediaUtils::$blogid . '">' . "\n";
580 echo "<input type=\"submit\" name=\"type\" value=\"sync\">\n";
581 echo "<input type=\"submit\" name=\"type\" value=\"clear\">\n";
586 echo "<h3>" . $this->t(_NP_THUMBNAIL_22) . "</h3>\n";
589 foreach ( $logs as $log )
591 echo "<li>{$log}</li>\n";
597 $oPluginAdmin->end();
601 public static function syncFilesystem ($root, $dest, $maxwidth, $maxheight)
605 $root = rtrim($root, '/');
606 if ( !$root || !file_exists($root) )
611 if ( !MediaUtils::checkDir(rtrim($root, '/') . '/' . trim($dest, '/')) )
618 $media = MediaUtils::getMediaList($root);
622 foreach ( $media as $medium )
627 if ( $count > self::$max_sync )
632 if ( FALSE === ($destination = self::getThumbPath($medium))
633 || file_exists (rtrim($root, '/') . '/' . $destination) )
638 if ( FALSE === $medium->setResampledSize($maxwidth, $maxheight)
639 || !MediaUtils::storeResampledImage ($root, $destination, $medium) )
641 echo "<li>Fail: {$medium->name}</li>\n";
645 echo "<li>Success: {$medium->name}</li>\n";
655 public static function getThumbPath($medium)
657 if ( !array_key_exists ($medium->mime, MediaUtils::$image_mime) )
661 return self::$thumbdir . '/' . $medium->getHashedName(MediaUtils::$algorism) . MediaUtils::$image_mime[$medium->mime];
664 public function getThumbURL($medium)
666 global $CONF, $DIR_MEDIA;
668 if ( ($medium->width < $medium->resampledwidth && $medium->height < $medium->resampledheight)
669 || ($medium->width <= $this->getOption('maxwidth') && $medium->height <= $this->getOption('maxheight')) )
671 $url = "{$CONF['MediaURL']}{$medium->path}/{$medium->name}";
673 else if ( $medium->resampledwidth > $this->getOption('maxwidth') && $medium->resampledheight > $this->getOption('maxheight') )
675 $url = "{$CONF['ActionURL']}?action=plugin&name={$this->getName()}&path={$medium->path}/{$medium->name}&width={$medium->resampledwidth}&height={$medium->resampledheight}&blogid=" . MediaUtils::$blogid;
677 else if (file_exists($DIR_MEDIA . self::getThumbPath($medium)) )
679 $url = $CONF['MediaURL'] . self::getThumbPath($medium);