4 * TAGGING PLUG-IN FOR NucleusCMS
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 * (see nucleus/documentation/index.html#license for more info)
13 * @author Original Author nakahara21
14 * @copyright 2005-2008 nakahara21
15 * @copyright 2006-2009 shizuki
16 * @license http://www.gnu.org/licenses/gpl.txt
17 * GNU GENERAL PUBLIC LICENSE Version 2, June 1991
20 * @link http://nakahara21.com
25 * 0.73 TemplateExtraFields for v3.40
27 * 0.71 fix flat TAG level
28 * 0.70 add Tag lebel css
31 * 0.64 modified createTagLink function
32 * 0.63 fix Magical code
33 * 0.62 add function doIf() for NucleusCMS version3.3
34 * 0.6 fix delete tags when item update(425)
35 * mod scanExistTags function
36 * mod get tagLink title
38 * 0.5 TAG sort modified
39 * 0.43 fix URL generate
40 * 0.42 add URL selected tag check
41 * 0.41 security fix and add some trick
42 * 0.4 fixed bug: numlic only
43 * 0.3 fixed bug: delete action
44 * 0.2 supports and/or query
48 * define table names using plugin
50 if (!defined('_TAGEX_TABLE_DEFINED')) {
51 define('_TAGEX_TABLE_DEFINED', 1);
52 define('_TAGEX_TABLE', sql_table('plug_tagex'));
53 define('_TAGEX_KLIST_TABLE', sql_table('plug_tagex_klist'));
59 class NP_TagEX extends NucleusPlugin
62 * NP_MultipleCategories installed ?
67 * NP_CustomURL installed ?
80 return 'Tags Extension';
92 return 'nakahara21 + shizuki + Tucker + Cacher';
99 * get Plugin getting URL
104 return 'http://japan.nucleuscms.org/wiki/plugins:tagex';
114 function getVersion()
120 // {{{ getDescription()
123 * get Plugin Description
126 function getDescription()
128 return 'Tags Extension (for Japanese users)';
132 // {{{ supportsFeature()
135 * get Plugin supports Nucleus CORE feature
136 * @param string Nucleus CORE feature
139 function supportsFeature($what)
142 case 'SqlTablePrefix':
153 * plugin install script
155 * Create plugin options
157 * 'And' template's class 'tagex_and_or' CSS example
159 * font-family:tahoma;
163 * 'TagIndex' template is 'taglevel' class ver. for default.
164 * But there use '<%fontlevel%>' template tag.
167 * <span style="font-size:<%fontlevel%>em" title="<%tagamount%> post(s)! <%tagitems%>">
168 * <a href="<%taglinkurl%>"><%tag%></a>
173 $tplAND = <<<__ANDTAGTPL__
174 <span class="tagex_and_or"> <a href="<%andurl%>" title="narrow">&</a>.
176 $tplOR = <<<__ORTAGTPL__
177 <a href="<%orurl%>" title="expand">or</a> </span>
179 $tplIDX = <<<__ORTAGTPL__
181 <span class="level<%taglevel%>" title="<%tagamount%> post(s) <%tagitems%>">
182 <a href="<%taglinkurl%>"><%tag%></a>
185 $this->createOption('flg_erase', _NPTAGEX_ERASE_FLG, 'yesno', 'no');
186 $this->createOption('editTagOrder', _NPTAGEX_EDT_TAGORDER, 'select', '1', _NPTAGEX_ORDER_VALUE);
187 $this->createOption('and', _NPTAGEX_TPL_AND, 'textarea', $tplAND);
188 $this->createOption('or', _NPTAGEX_TPL_OR, 'textarea', $tplOR);
189 $this->createOption('tagIndex', _NPTAGEX_TPL_TAGIDX, 'textarea', $tplIDX);
190 $this->createOption('tagItemHeader', _NPTAGEX_TPL_ITEMHEAD, 'textarea', '');
191 $this->createOption('tagItem', _NPTAGEX_TPL_TAGITEMS, 'textarea', '<%itemid%>:<%itemtitle%>');
192 $this->createOption('tagItemSeparator', _NPTAGEX_TPL_ITEMSEPL, 'text', ' , ');
193 $this->createOption('tagItemFooter', _NPTAGEX_TPL_ITEMFOOT, 'textarea', '');
194 $this->createOption('tagIndexSeparator', _NPTAGEX_TPL_IDXSEP, 'text', ' | ');
195 $this->createOption('tagsonlycurrent', _NPTAGEX_ONLY_CURRENT, 'yesno', 'no');
196 $this->createOption('colorfulhighlight', _NPTAGEX_HILIGHT_MODE, 'yesno', 'no');
197 $this->createOption('highlight', _NPTAGEX_HILIGHT_NORM, 'text', '<span class="highlight">\0</span>');
198 $this->createOption('maxTagLevel', _NPTAGEX_MAX_TAGLEBEL, 'text', '6', 'datatype=numerical');
199 $this->createOption('minTagLevel', _NPTAGEX_MIN_TAGLEBEL, 'text', '1', 'datatype=numerical');
200 $table_q = 'CREATE TABLE IF NOT EXISTS ' . _TAGEX_TABLE . ' ('
201 . ' `inum` INT(9) NOT NULL default "0" PRIMARY KEY, '
202 . ' `itags` TEXT NOT NULL, '
203 . ' `itagreg` TIMESTAMP(14) NOT NULL'
206 $table_q = 'CREATE TABLE IF NOT EXISTS ' . _TAGEX_KLIST_TABLE . ' ('
207 . ' `listid` INT(9) NOT NULL AUTO_INCREMENT PRIMARY KEY, '
208 . ' `tag` VARCHAR(255) default NULL, '
209 . ' `inums` TEXT NOT NULL, '
210 . ' `inums_count` INT(11) NOT NULL default "0", '
211 . ' `ireg` TIMESTAMP(14) NOT NULL'
217 // {{{ defineMultilanguage()
220 * Multi language support
222 function defineMultilanguage()
225 '_NPTAGEX_ERASE_FLG' => array(
226 'Erase data when uninstall ?',
227 'アンインストール時にデータを消去しますか?',
229 '_NPTAGEX_EDT_TAGORDER' => array(
230 'editform tag order',
233 '_NPTAGEX_ORDER_VALUE' => array(
234 "amount(desc)|1|amount(asc)|2|tag's order|3|random|4",
235 'アイテムの多い順|1|アイテムの少ない順|2|タグ順(キャラクターコード順)|3|ランダム|4',
237 '_NPTAGEX_TPL_AND' => array(
238 "template for 'and'",
241 '_NPTAGEX_TPL_OR' => array(
245 '_NPTAGEX_TPL_TAGIDX' => array(
246 "template for 'tagIndex'",
249 '_NPTAGEX_TPL_ITEMHEAD' => array(
250 "template for 'tagItemHeader'",
253 '_NPTAGEX_TPL_TAGITEMS' => array(
254 "template for 'tagItem'",
257 '_NPTAGEX_TPL_ITEMSEPL' => array(
258 "template for 'tagItemSeparator'",
261 '_NPTAGEX_TPL_ITEMFOOT' => array(
262 "template for 'tagItemFooter'",
265 '_NPTAGEX_TPL_IDXSEP' => array(
266 "template for 'tagIndexSeparator'",
269 '_NPTAGEX_ONLY_CURRENT' => array(
270 'show tags only current blog have',
271 '表示中のブログのアイテムに登録してあるタグのみ表示'
273 '_NPTAGEX_HILIGHT_MODE' => array(
274 'colorful highlight mode ?',
277 '_NPTAGEX_HILIGHT_NORM' => array(
278 'template for normal highlightmode',
279 'ノーマルハイライトモードの時のテンプレート'
281 '_NPTAGEX_MAX_TAGLEBEL' => array(
285 '_NPTAGEX_MIN_TAGLEBEL' => array(
290 switch (ereg_replace('[\\|/]', '', getLanguageName())) {
292 foreach ($multilang as $key => $value) {
293 define($key, mb_convert_encoding($value[1], 'EUC-JP', 'UTF-8'));
296 case 'japanese-utf8':
297 foreach ($multilang as $key => $value) {
298 define($key, $value[1]);
302 foreach ($multilang as $key => $value) {
303 define($key, $value[0]);
317 $this->defineMultilanguage;
318 $usePathInfo = ($CONF['URLMode'] == 'pathinfo');
319 $this->maURL = (($this->plugCheck('MagicalURL2') || $this->plugCheck('Magical')) && $usePathInfo);
320 $this->cuURL = ($this->plugCheck('CustomURL') && $usePathInfo);
327 * Plugin uninstall and clear plugin's all data if you want.
331 if ($this->getOption('flg_erase') == 'yes') {
332 sql_query('DROP TABLE IF EXISTS ' . _TAGEX_TABLE);
333 sql_query('DROP TABLE IF EXISTS ' . _TAGEX_KLIST_TABLE);
338 // {{{ getTableList()
343 function getTableList()
352 // {{{ getEventList()
355 * Plugin fook these API.
358 function getEventList()
364 'EditItemFormExtras',
367 'TemplateExtraFields',
380 * other plugins installed ?
381 * @param string Plugin name
384 private function plugCheck($name)
387 return $manager->pluginInstalled('NP_' . $name);
394 * Quote string befor SQL.
395 * @param mix string, int, or array
396 * @return mix string or int
398 private function quote_smart($value)
400 // Escape SQL query strings
401 if (is_array($value)) {
402 if (get_magic_quotes_gpc()) {
403 $value = array_map("stripslashes", $value);
405 if (!array_map("is_numeric",$value)) {
406 if (version_compare(phpversion(),"4.3.0") == "-1") {
407 $value = array_map("mysql_escape_string", $value);
409 $value = array_map("mysql_real_escape_string", $value);
412 $value = intval($value);
415 if (get_magic_quotes_gpc()) {
416 $value = stripslashes($value);
418 if (!is_numeric($value)) {
419 if (version_compare(phpversion(), "4.3.0") == "-1") {
420 $value = "'" . mysql_escape_string($value) . "'";
422 $value = "'" . mysql_real_escape_string($value) . "'";
425 $value = intval($value);
434 * Processing of the event fook held from here
437 // {{{ event_PreItem()
440 * Quote string befor SQL.
441 * @param mix string, int, or array
442 * @return mix string or int
444 function event_PreItem($data)
447 global $currentTemplateName;
448 $currTemplateName = $this->quote_smart($currentTemplateName);
449 $templateDescTable = sql_table('template_desc');
450 $q_query = 'SELECT tddesc as result '
452 . 'WHERE tdname = %s';
453 $q_query = sprintf($q_query, $templateDescTable, $currTemplateName);
454 $currentTemplateDesc = quickQuery($q_query);
455 if (eregi('<highlightTagsAll>', $currentTemplateDesc)) {
456 $tags = $this->scanExistTags(0, 99999999);
460 $highlightKeys = array_keys($tags);
462 } elseif (eregi('<highlightTags>', $currentTemplateDesc)) {
463 $requestT = $this->getNoDecodeQuery('tag');
464 if (empty($requestT)) {
467 $requestTarray = $this->splitRequestTags($requestT);
468 $reqAND = array_map(array(&$this, "_rawdecode"), $requestTarray['and']);
469 if ($requestTarray['or']) {
470 $reqOR = array_map(array(&$this, "_rawdecode"), $requestTarray['or']);
473 $highlightKeys = array_merge($reqAND, $reqOR);
475 $highlightKeys = $reqAND;
480 $template['highlight'] = $this->getOption('highlight');
481 $curItem =& $data['item'];
482 if ($this->getOption('colorfulhighlight') == 'no') {// original mode
483 $curItem->body = highlight($curItem->body, $highlightKeys, $template['highlight']);
484 $curItem->more = highlight($curItem->more, $highlightKeys, $template['highlight']);
488 * use other color for each tags
493 foreach ($highlightKeys as $qValue) {
494 $pattern = '<span class=\'highlight_' . $sh . '\'>\0</span>';
495 $curItem->body = highlight($curItem->body, $qValue, $pattern);
501 if ($curItem->more) {
503 foreach ($highlightKeys as $qValue) {
504 $pattern = '<span class=\'highlight_' . $sh . '\'>\0</span>';
505 $curItem->more = highlight($curItem->more, $qValue, $pattern);
515 function event_TemplateExtraFields($data)
517 $data['fields']['NP_TagEX'] = array(
518 'nptagex_and' => _NPTAGEX_TPL_AND,
519 'nptagex_or' => _NPTAGEX_TPL_OR,
520 'nptagex_tagIndex' => _NPTAGEX_TPL_TAGIDX,
521 'nptagex_tagItemHeader' => _NPTAGEX_TPL_ITEMHEAD,
522 'nptagex_tagItem' => _NPTAGEX_TPL_TAGITEMS,
523 'nptagex_tagItemSeparator' => _NPTAGEX_TPL_ITEMSEPL,
524 'nptagex_tagItemFooter' => _NPTAGEX_TPL_ITEMFOOT,
525 'nptagex_tagIndexSeparator' => _NPTAGEX_TPL_IDXSEP,
526 'nptagex_highlight' => _NPTAGEX_HILIGHT_NORM,
531 * extra forms function
539 * TAGs only current blog
541 * From http://blog.uribou.net/
544 function _ItemFormExtras($tagrows, $tagcols, $blogid = 0, $oldforj = '', $itags = '')
546 $blogid = intval($blogid);
547 // Exstra form for add or update Item
548 if (strstr(serverVar('HTTP_USER_AGENT'), 'Gecko')) {
549 $divStyles = 'height: 24em;'
553 . 'border:1px solid lightblue;'
554 . 'margin-top:3.8em;'
555 . 'padding-left:0.5em;'
556 . '-moz-column-count: 3;'
557 . '-moz-column-width: 200px;'
558 . '-moz-column-gap: 0.5em;';
559 $txAStyles = ''//'width:10em;'
563 $divStyles = 'height: 200px;'
566 $txAStyles = 'width:95%;';
569 . "<h3>TagEX</h3>\n\t\t"
570 // . '<p style="float:left;width:95%;">' . "\n\t\t\t"
571 . '<label for="tagex">Tag(s):</label>' . "\n\t\t\t"
572 . '<a href="javascript:resetOlder'
573 . "('" . $oldforj . "')"
574 . '">[Reset]</a><br />' . "\n\t\t\t"
575 . '<textarea id="tagex" name="itags" rows="' . intval($tagrows)
576 . '" cols="' . intval($tagcols) . '" style="' . $txAStyles . '"'
578 . htmlspecialchars($itags) . '</textarea>' . "\n\t\t"
580 . '<script language="JavaScript" type="text/javascript">' . "\n"
582 . 'function insertag(tag){' . "\n\t"
583 . "if(document.getElementById('tagex').value != '')\n\t\t"
584 . 'tag = "\n" + tag;' . "\n\t"
585 . "document.getElementById('tagex').value += tag;\n"
587 . "function resetOlder(old){\n\t"
588 . "document.getElementById('tagex').value = old;\n"
591 . '<div style="' . $divStyles . '" class="tagex"><ul>' . "\n";
593 $tagOrder = intval($this->getOption('editTagOrder'));
594 if ($this->getOption('tagsonlycurrent') == no) {
595 $existTags = $this->scanExistTags(0, 99999999, $tagOrder);
597 $existTags = $this->scanExistTags(1, 99999999, $tagOrder, $blogid);
600 $existTags = array_keys($existTags);
602 for ($i=0; $i < count($existTags); $i++) {
603 $exTags = htmlspecialchars($existTags[$i]);
604 $printData = '<li><a href="javascript:insertag'
605 . "('" . $exTags . "')" . '">'
606 . $exTags . '</a></li>' . "\n";
609 echo '</ul></div><br style="clear:all;" />' . "\n";
612 function event_AddItemFormExtras($data)
614 /* global $CONF, $blogid;
615 if (is_numeric($blogid)) {
616 $blogid = intval($blogid);
618 $blogid = intval(getBlogIDFromName($blogid));
620 if (empty($blogid)) {
621 $blogid = intval($CONF['DefaultBlog']);
623 $blogid = intval($data['blog']->blogid);
625 // $oldforj = $itags = '';
626 $this->_ItemFormExtras(3, 40, $blogid);//, $oldforj, $itags);// <current blog only />
629 function event_EditItemFormExtras($data)
631 // Initialize tags when it have
632 $item_id = intval($data['variables']['itemid']);
633 $query = 'SELECT itags FROM %s WHERE inum = %d';
634 $result = sql_query(sprintf($query, _TAGEX_TABLE, $item_id));
635 if (mysql_num_rows($result) > 0) {
636 $itags = mysql_result($result,0,0);
638 $oldforj = str_replace("\n", '\n', htmlspecialchars($itags));
639 // $blogid = getBlogIDFromItemID($item_id);
640 $blogid = intval($data['blog']->blogid);//$blogid);
642 // current blog onry mode
643 $this->_ItemFormExtras(5, 20, $blogid, $oldforj, $itags);
646 function event_PostAddItem($data)
648 // Add tags when it add for Item
649 $itags = trim(requestVar('itags'));
653 $inum = intval($data['itemid']);
654 $query = 'INSERT INTO %s (inum, itags) VALUES (%d, %s)';
655 $query = sprintf($query, _TAGEX_TABLE, $inum, $this->quote_smart($itags));
657 $temp_tags_array = preg_split("/[\r\n,]+/", $itags);
658 for ($i=0; $i < count($temp_tags_array); $i++) {
659 $this->mergeTags(trim($temp_tags_array[$i]), $inum);
663 function event_PreUpdateItem($data)
665 // Add tags when it add for Item
666 $itags = trim(requestVar('itags'));
667 $inum = intval($data['itemid']);
668 $query = 'SELECT itags as result FROM %s WHERE inum = %d';
669 $oldTags = quickQuery(sprintf($query, _TAGEX_TABLE, $inum));
670 if ($itags == $oldTags) {
673 $query = 'DELETE FROM %s WHERE inum = %d';
674 sql_query(sprintf($query, _TAGEX_TABLE, $inum));
675 if (!empty($itags)) {
676 $query = 'INSERT INTO %s (inum, itags) VALUES (%d, %s)';
677 $query = sprintf($query, _TAGEX_TABLE, $inum, $this->quote_smart($itags));
680 $old_tags_array = $this->getTags($oldTags);
681 if (!is_array($old_tags_array)) $old_tags_array = array($old_tags_array);
682 $new_tags_array = $this->getTags($itags);
683 $deleteTags = $this->array_minus_array($old_tags_array, $new_tags_array);
684 for ($i=0; $i < count($deleteTags); $i++) {
685 $this->deleteTags($deleteTags[$i], $inum);
687 $addTags = $this->array_minus_array($new_tags_array, $old_tags_array);
688 for ($i=0; $i < count($addTags); $i++) {
689 $this->mergeTags($addTags[$i], $inum);
694 function event_PreDeleteItem($data)
696 // Delete tags when it for deleted Item
697 // or delete Itemid from TAG table
698 $inum = intval($data['itemid']);
699 $query = 'SELECT itags as result FROM %s WHERE inum = %d';
700 $oldTags = quickQuery(sprintf($query, _TAGEX_TABLE, $inum));
701 if (empty($oldTags)) {
704 $query = 'DELETE FROM %s WHERE inum = %d';
705 sql_query(sprintf($query, _TAGEX_TABLE, $inum));
706 $deleteTags = $this->getTags($oldTags);
707 for ($i=0; $i < count($deleteTags); $i++) {
708 $this->deleteTags($deleteTags[$i], $inum);
713 //------------------------------------------------------
715 function getTags($str)
717 // extract Item's TAG for array
718 if (!$str) return false;
719 $tempArray = preg_split("/[\r\n,]+/", $str);
720 $returnArray = array_map('trim', $tempArray);
721 return array_unique($returnArray);
724 function array_minus_array($a, $b)
726 // update Item's TAGs
727 $c = array_diff($a,$b);
728 $c = array_intersect($c, $a);
729 return array_values($c);
732 function deleteTags($tag, $inum)
734 // Delete TAGs and TAG's Item
735 $inum = intval($inum);
736 $tag = $this->quote_smart($tag);
737 $f_query = "SELECT inums FROM " . _TAGEX_KLIST_TABLE
738 . " WHERE tag = " . $tag
739 . ' AND inums REGEXP "(^|,)' . $inum . '(,|$)"'
740 . ' ORDER BY ireg DESC';
741 $findres = sql_query($f_query);
742 if (mysql_num_rows($findres) == 0) {
745 $temp_inums = mysql_result($findres, 0, 0);
746 if (preg_match('/^\d+$/', $temp_inums) && $inum == $temp_inums) {
747 $query = 'DELETE FROM %s WHERE tag = %s';
748 sql_query(sprintf($query, _TAGEX_KLIST_TABLE, $tag));
751 $inums_array = array();
752 $inums_array = explode(',', $temp_inums);
753 $trans = array_flip($inums_array);
754 unset($trans[$inum]);
755 $inums_array = array_flip($trans);
756 $inums_count = count($inums_array);
757 // $inums = @implode(",", $inums_array);
758 $inums = implode(",", $inums_array);
759 if (!empty($inums)) {
760 $update_query = 'UPDATE %s '
762 . 'inums_count = %d '
764 $iCount = intval($inums_count);
765 $quoteInums = $this->quote_smart($inums);
766 sql_query(sprintf($update_query, _TAGEX_KLIST_TABLE, $quoteInums, $iCount, $tag));
770 function mergeTags($tag, $inum)
777 $inums_array = array();
779 $inum = intval($inum);
780 $tag = $this->quote_smart($tag);
781 $f_query = 'SELECT inums'
782 . ' FROM ' . _TAGEX_KLIST_TABLE
783 . ' WHERE tag = ' . $tag
784 . ' ORDER BY ireg DESC';
785 $findres = sql_query($f_query);
786 if (mysql_num_rows($findres) > 0) {
787 $temp_inums = mysql_result($findres, 0, 0);
788 $inums_array = explode(',', $temp_inums);
789 if (!in_array($inum, $inums_array)) {
790 $inums = $temp_inums . ',' . $inum;
791 $inums_count = count($inums_array) + 1;
794 $q_query = 'INSERT INTO %s '
795 . '(tag, inums, inums_count) '
796 . 'VALUES (%s, %d, 1)';
797 sql_query(sprintf($q_query, _TAGEX_KLIST_TABLE, $tag, intval($inum)));
800 if (!empty($inums)) {
801 $q_query = 'UPDATE %s SET inums = %s, inums_count = %d WHERE tag = %s';
802 $iCount = intval($inums_count);
803 $quoteInums = $this->quote_smart($inums);
804 sql_query(sprintf($q_query, _TAGEX_KLIST_TABLE, $quoteInums, $iCount, $tag));
808 function scanExistItem($narrowMode = 0, $blogid = 0)
810 /// Select Items when Categories or Sub-categories or Archive selected
811 global $manager, $CONF, $blog, $catid, $archive;
816 $b =& $manager->getBlog($blogid);
820 $b =& $manager->getBlog($CONF['DefaultBlog']);
823 if ($narrowMode > 0) {
824 $where .= ' and i.iblog = ' . intval($b->getID());
826 if ($catid && $narrowMode > 1) {
827 $catid = intval($catid);
828 if ($manager->pluginInstalled('NP_MultipleCategories')) {
829 $where .= ' and ((i.inumber = p.item_id'
830 . ' and (p.categories REGEXP "(^|,)' . $catid . '(,|$)"'
831 . ' or i.icat = ' . $catid . '))'
832 . ' or (i.icat = ' . $catid
833 . ' and p.item_id IS NULL))';
834 $mtable = ' LEFT JOIN '
835 . sql_table('plug_multiple_categories') . ' as p'
836 . ' ON i.inumber = p.item_id';
837 $mplugin =& $manager->getPlugin('NP_MultipleCategories');
839 if ($subcatid && method_exists($mplugin, 'getRequestName')) {
841 $subcatid = intval($subcatid);
842 $scatTable = sql_table('plug_multiple_categories_sub');
843 $tres_query = 'SELECT * FROM %s WHERE scatid = %d';
844 $tres_query = sprintf($tres_query, $scatTable, $subcatid);
845 $tres = sql_query($tres_query);
846 $ra = mysql_fetch_array($tres, MYSQL_ASSOC);
847 if (array_key_exists('parentid', $ra)) {
849 $Children = explode('/', $subcatid . $this->getChildren($subcatid));
851 if ($loop = count($Children) >= 2) {
852 for ($i=0; $i < $loop; $i++) {
853 $chidID = intval($Children[$i]);
854 $temp_whr[] = ' p.subcategories REGEXP "(^|,)' . $chidID . '(,|$)" ';
857 . implode (' or ', $temp_whr)
860 $where .= ' and p.subcategories REGEXP "(^|,)' . $subcatid . '(,|$)"';
865 $where .= ' and i.icat = ' . $catid;
871 sscanf($archive, '%d-%d-%d', $y, $m, $d);
873 $timestamp_start = mktime(0, 0, 0, $m, $d, $y);
874 $timestamp_end = mktime(0, 0, 0, $m, $d+1, $y);
876 $timestamp_start = mktime(0, 0, 0, $m, 1, $y);
877 $timestamp_end = mktime(0, 0, 0, $m+1, 1, $y);
879 $timestamp_start = mktime(0, 0, 0, 1, 1, $y);
880 $timestamp_end = mktime(0, 0, 0, 1, 1, $y+1);
882 $where .= ' and i.itime >= ' . mysqldate($timestamp_start)
883 . ' and i.itime < ' . mysqldate($timestamp_end);
885 $where .= ' and i.itime <= ' . mysqldate($b->getCorrectTime());
888 $iquery = 'SELECT i.inumber '
891 . ' WHERE i.idraft = 0'
893 $res = sql_query(sprintf($iquery, sql_table('item')));
894 while ($row = mysql_fetch_row($res)) {
895 $existInums[] = $row[0];
903 * add TAG's order and Random sort
905 * From http://blog.uribou.net/
908 function sortTags($tags, $sortMode = 0)
911 // sortMode 1:max first
912 // sortMode 2:min first
913 // sortMode 3:tag's order
915 $sortMode = intval($sortMode);
916 if (!$tags || $sortMode == 0) {
919 foreach ($tags as $tag => $inums) {
920 $tagCount[$tag] = count($inums);
930 uksort($tagCount, array(&$this, 'sortTagOrder'));
933 srand ((float) microtime() * 10000000);
934 $tmp_key = array_rand($tagCount, count($tagCount));
937 foreach ($tmp_key as $k => $v) {
944 foreach ($tagCount as $k => $v) {
950 function sortTagOrder($a, $b)
952 return strcasecmp($a, $b);
955 function scanExistTags($narrowMode = 0, $amount = 99999999, $sortmode = 0, $blogid = 0)
958 // $narrowMode = 0: all blogs
959 // $narrowMode = 1: currentblog only
960 // $narrowMode = 2: narrowed with catid/subcatid
961 $narrowMode = intval($narrowMode);
962 $amount = intval($amount);
963 $sortmode = intval($sortmode);
964 // <mod by shizuki />
965 if (is_numeric($blogid)) {
966 $blogid = intval($blogid);
968 $blogid = intval(getBlogIDFromName($blogid));
970 $existInums = array();
971 $existInums = $this->scanExistItem($narrowMode, $blogid);
972 $res = sql_query(sprintf('SELECT * FROM %s', _TAGEX_KLIST_TABLE));
973 while ($o = mysql_fetch_object($res)) {
974 $tagsk[$o->tag] = explode(',', $o->inums);
976 $tagsk[$o->tag] = array_intersect($tagsk[$o->tag], $existInums);
977 $tagsk[$o->tag] = array_values($tagsk[$o->tag]);
979 if (empty($tagsk[$o->tag])) {
980 unset($tagsk[$o->tag]);
983 $tagsk = $this->sortTags($tagsk, $sortmode);
984 if (count($tagsk) > $amount) {
985 $tagsk = array_slice($tagsk, 0, $amount);
990 function scanCount($tags)
992 // ? count TAGs have Item ?
994 foreach ($tags as $tag) {
995 $tempCount = count($tag);
996 $max = max($max, $tempCount);
997 $min = min($min, $tempCount);
999 return array($max, $min);
1002 function getNoDecodeQuery($q)
1004 // Get urlencoded TAGs
1005 global $CONF, $manager;
1007 if ($CONF['URLMode'] == 'pathinfo') {
1008 $urlq = serverVar('REQUEST_URI');
1009 $tempq = explode($q . '/', $urlq, 2);
1010 if ($this->maURL) {//($manager->pluginInstalled('NP_MagicalURL2') || $manager->pluginInstalled('NP_Magical')) {
1011 $tempq = explode($q . '_', $urlq, 2);
1014 if (!empty($tempq[1])) {
1015 $tagq = explode('/', $tempq[1]);
1016 if ($this->maURL) {//($manager->pluginInstalled('NP_MagicalURL2') || $manager->pluginInstalled('NP_Magical')) {
1017 $tagq = explode('_', $tempq[1]);
1019 $str = preg_replace('|[^a-z0-9-~+_.#;,:@%]|i', '', $tagq[0]);
1024 $urlq = serverVar('QUERY_STRING');
1025 $urlq = str_replace('?', '', $urlq);
1026 $urlq = explode('&', $urlq);
1027 $qCnt = count($urlq);
1028 for ($i=0; $i<$qCnt; $i++) {
1029 $tempq = explode('=', $urlq[$i]);
1030 if ($tempq[0] == $q) {
1031 $str = preg_replace('|[^a-z0-9-~+_.#;,:@%]|i', '', $tempq[1]);
1039 function splitRequestTags($q)
1041 // extract TAGs to array
1042 if (!strpos($q, '+') && !strpos($q, ':')) {
1043 $res['and'][0] = $q;
1050 $tempAnd = explode('+', $q);
1051 $andCnt = count($tempAnd);
1052 for ($i=0; $i < $andCnt; $i++) {
1053 $temp = explode(':', $tempAnd[$i]);
1054 $res['and'][] = array_shift($temp);
1055 if ($temp != array()) {
1056 $res['or'] = array_merge($res['or'], $temp);
1062 function doIf($key, $value)
1064 if ($key != 'tag') {
1067 $reqTags = $this->getNoDecodeQuery('tag');
1068 if (!empty($reqTags)) {
1069 $reqTagsArr = $this->splitRequestTags($reqTags);
1070 $reqAND = array_map(array(&$this, "_rawdecode"), $reqTagsArr['and']);
1071 if ($requestTarray['or']) {
1072 $reqOR = array_map(array(&$this, "_rawdecode"), $reqTagsArr['or']);
1077 if (empty($value)) {
1080 $tagsArray = ($reqOR) ? array_merge($reqAND, $reqOR) : $reqAND;
1081 return in_array($value, $tagsArray);
1085 function doSkinVar($skinType, $type='list20/1/0/1/4')
1088 // echo 'ecat='.$ecatid.'<br />';
1089 // type[0]: type ( + amount (int))
1090 // type[1]: $narrowMode (0/1/2)
1091 // type[2]: sortMode (1/2/3/4)
1092 // type[3]: Minimum font-sizem(em) 0.5/1/1.5/2...
1093 // type[4]: Maximum font-sizem(em)
1094 $maxtaglevel = $this->getOption('maxTagLevel');
1095 $mintaglevel = $this->getOption('minTagLevel');
1099 $type = 'list20/2/1/1/4';
1101 $type = explode('/', $type);
1102 if (eregi('list', $type[0])) {
1103 $amount = eregi_replace("list", "", $type[0]);
1106 } elseif (eregi('meta', $type[0])) {
1107 $amount = eregi_replace("meta", "", $type[0]);
1111 $amount = (!empty($amount)) ? intval($amount): 99999999;
1113 $defaultType = array('list', '1', '0', '1', '4');
1114 $type = $type + $defaultType;
1115 $requestT = $this->getNoDecodeQuery('tag');
1116 if (!empty($requestT)) {
1117 $requestTarray = $this->splitRequestTags($requestT);
1118 $reqAND = array_map(array(&$this, "_rawdecode"), $requestTarray['and']);
1119 if ($requestTarray['or']) {
1120 $reqOR = array_map(array(&$this, "_rawdecode"), $requestTarray['or']);
1126 if ($requestTarray) {
1127 $reqAndLink = array();
1128 foreach ($reqAND as $val) {
1129 $reqAndLink[] = '<a href="'
1130 . $this->creatTagLink($val)
1131 . '" title="' . $val . '">'
1134 $reqANDp = implode('" + "', $reqAndLink);
1136 $reqOrLink = array();
1137 foreach ($reqOR as $val) {
1138 $reqOrLink[] = '<a href="'
1139 . $this->creatTagLink($val)
1140 . '" title="' . $val . '">'
1143 $reqORp = '"</u> or <u>"'
1144 . implode('"</u> or <u>"', $reqOrLink);
1146 echo '<h1> Tag for <u>"' . $reqANDp . $reqORp . '"</u></h1>';
1150 // meta keywords="TAG"
1153 global $manager, $itemid;
1154 $itemid = intval($itemid);
1155 if ($type[3] != 'ad') {
1156 echo '<meta name="keywords" content="';
1158 } elseif ($type[3] == 'ad') {
1161 if ($skinType == 'item') {
1162 $q = 'SELECT * FROM %s WHERE inum = %d';
1163 $res = sql_query(sprintf($q, _TAGEX_TABLE, $itemid));
1164 while ($o = mysql_fetch_object($res)) {
1165 $temp_tags_array = preg_split("/[\n,]+/", trim($o->itags));
1166 $temp_tags_count = count($temp_tags_array);
1167 for ($i=0; $i < $temp_tags_count; $i++) {
1168 $tag = trim($temp_tags_array[$i]);
1169 $taglist[$i] = htmlspecialchars($tag, ENT_QUOTES, _CHARSET);
1173 echo implode(' ', $taglist);
1175 if ($tags = $this->scanExistTags(intval($type[1]), $amount, intval($type[2]))) {
1178 foreach ($tags as $tag => $inums) {
1179 $eachTag[$t] = htmlspecialchars($tag, ENT_QUOTES, _CHARSET);
1182 if ($type[3] != 'ad') {
1183 echo implode($sep, $eachTag);
1184 } elseif ($type[3] == 'ad') {
1185 $tag_str = implode($sep, $eachTag);
1189 if ($type[3] != 'ad') {
1191 } elseif ($type[3] == 'ad') {
1192 // $tag_str = mb_convert_encoding($tag_str, 'UTF-8', 'UTF-8');
1193 $tag_str = urlencode($tag_str);
1197 // TAG list(tag cloud)
1199 $template['and'] = $this->getOption('and');
1200 $template['or'] = $this->getOption('or');
1201 $template['tagIndex'] = $this->getOption('tagIndex');
1202 $template['tagItemHeader'] = $this->getOption('tagItemHeader');
1203 $template['tagItem'] = $this->getOption('tagItem');
1204 $template['tagItemSeparator'] = $this->getOption('tagItemSeparator');
1205 $template['tagItemFooter'] = $this->getOption('tagItemFooter');
1206 $template['tagIndexSeparator'] = $this->getOption('tagIndexSeparator');
1207 if ($tags = $this->scanExistTags($type[1])) {
1208 if ($type[3] != $type[4]) {
1209 $minFontSize = min((float)$type[3], (float)$type[4]) - 0.5;
1210 $maxFontSize = max((float)$type[3], (float)$type[4]);
1211 $levelsum = ($maxFontSize - $minFontSize) / 0.5;
1212 $taglevelsum = $maxtaglevel - $mintaglevel;
1213 list($maxCount, $minCount) = $this->scanCount($tags);
1214 $eachCount = ceil(($maxCount - $minCount) / $levelsum);
1218 $req = ($reqOR) ? array_merge($reqAND, $reqOR) : $reqAND;
1219 foreach ($req as $tag) {
1220 if (array_key_exists($tag, $tags)) {
1221 $select = array_merge($select, $tags[$tag]);
1222 $selected = array_unique($select);
1226 foreach ($tags as $tag => $inums) {
1228 if (!in_array($tag, $req)) {
1230 // if (!in_array($tag, $req) && !array_diff($tags[$tag], $selected)) {
1231 $tagCount[$tag] = count($inums);
1234 $tagCount[$tag] = count($inums);
1239 foreach ($tagCount as $k => $v) {
1243 if (count($r) > $amount) {
1244 $r = array_slice($r, 0, $amount);
1247 if (count($r) == 1) {
1250 $tags = $this->sortTags($r, intval($type[2]));
1258 foreach ($tags as $tag => $inums) {
1259 $tagitems = array();
1260 $tagAmount = count($inums);
1262 $fontlevel = ceil($tagAmount / $eachCount) * 0.5 + $minFontSize;
1266 if ($maxCount == $minCount) {//2008-05-22 Cacher
1269 $taglevel = round(($tagAmount - $minCount) / ($maxCount - $minCount) * $taglevelsum + $mintaglevel);
1271 /// Item's name had TAGs
1272 $iids = array_slice($inums, 0, 4);
1274 $qQuery = ' SELECT '
1275 . ' SUBSTRING(ititle, 1, 12) as short_title'
1279 . ' inumber in (' . implode(',', $iids) . ') '
1282 $sTitles = sql_query($qQuery);
1284 while ($sTitle = mysql_fetch_assoc($sTitles)) {
1285 $shortTitle = mb_convert_encoding($sTitle['short_title'], _CHARSET, _CHARSET);
1286 $shortTitle = htmlspecialchars($shortTitle, ENT_QUOTES, _CHARSET);
1287 $printData['tagItem']
1289 'itemid' => intval($iids[$i]),
1290 'itemtitle' => $shortTitle . '..',
1293 $tagitems[] = TEMPLATE::fill($template['tagItem'], $printData['tagItem']);
1295 $tagitem = implode($template['tagItemSeparator'], $tagitems) . '...etc.';
1297 // Generate URL link to TAGs
1299 /*********************
1300 * comment out this line when nodisplay selected TAGs */
1301 // $req = ($reqOR) ? array_merge($reqAND, $reqOR) : $reqAND;
1302 /*********************/
1303 if ($req && !in_array($tag, $req)) {
1304 $printData['and'] = array(
1305 'andurl' => $this->creatTagLink($tag, $type[1], $requestT, '+') //AND link
1307 $printData['or'] = array(
1308 'orurl' => $this->creatTagLink($tag, $type[1], $requestT, ':') //OR link
1310 $and = TEMPLATE::fill($template['and'], $printData['and']); // insert URL to template
1311 $or = TEMPLATE::fill($template['or'], $printData['or']);
1314 // insert data to template
1315 $printData['tagIndex'] = array(
1318 'tag' => htmlspecialchars($tag, ENT_QUOTES, _CHARSET),
1319 'tagamount' => $tagAmount,
1320 'fontlevel' => $fontlevel,
1321 'taglevel' => $taglevel,
1322 'taglinkurl' => $this->creatTagLink($tag, intval($type[1])),
1323 'tagitems' => $tagitem
1325 $eachTag[$t] = TEMPLATE::fill($template['tagIndex'], $printData['tagIndex']);
1327 // format outputdata and data output
1328 $eachTag[$t] .= $template['tagItemHeader'];
1330 if (!ereg('<%tagitems%>', $template['tagIndex'])) {//<%
1331 $eachTag[$t] .= $tagitem;
1334 $eachTag[$t] .= $template['tagItemFooter'];
1337 echo implode($template['tagIndexSeparator'] . "\n", $eachTag);
1341 // show selected TAGs for <title></title>
1344 $req = ($reqOR) ? array_merge($reqAND, $reqOR) : $reqAND;
1345 $data = htmlspecialchars(implode('|', $req), ENT_QUOTES, _CHARSET);
1346 echo ' : Selected Tag(s) » "' . $data . '"';
1352 // end of switch(type)
1355 function doTemplateVar(&$item, $type = '')
1357 // <highlight selected TAGs mod by shizuki>
1358 $requestT = $this->getNoDecodeQuery('tag');
1359 if (!empty($requestT)) {
1360 $requestTarray = $this->splitRequestTags($requestT);
1361 $reqAND = array_map(array(&$this, "_rawdecode"), $requestTarray['and']);
1362 if($requestTarray['or']) {
1363 $reqOR = array_map(array(&$this, "_rawdecode"), $requestTarray['or']);
1365 $words = ($reqOR)? array_merge($reqAND, $reqOR): $reqAND;
1369 $iid = intval($item->itemid);
1370 $q = 'SELECT * FROM %s WHERE inum = %d';
1371 $res = sql_query(sprintf($q, _TAGEX_TABLE, $iid));
1372 while ($o = mysql_fetch_object($res)) {
1373 $temp_tags_array = preg_split("/[\n,]+/", trim($o->itags));
1374 $temp_tags_count = count($temp_tags_array);
1375 for ($i=0; $i < $temp_tags_count; $i++) {
1376 $tag = trim($temp_tags_array[$i]);
1377 $taglink = $this->creatTagLink($tag, 0);
1378 // highlight selected TAGs
1379 $key = array_search($tag, $words);
1383 if (in_array($tag, $words)) {
1384 $taglist[$i] = '<a href="'
1385 . $this->creatTagLink($tag, 0)
1386 . '" class="highlight_0" rel="tag">'
1387 . htmlspecialchars($tag, ENT_QUOTES, _CHARSET) . '</a>';
1389 $taglist[$i] = '<a href="'
1390 . $this->creatTagLink($tag, 0)
1392 . htmlspecialchars($tag, ENT_QUOTES, _CHARSET) . '</a>';
1397 // echo 'Tag: ' . implode(' / ', $taglist);
1398 echo implode(' / ', $taglist);
1402 function _rawencode($str)
1405 if (_CHERSET != 'UTF-8') {
1406 $str = mb_convert_encoding($str, "UTF-8", _CHARSET);
1408 $str = rawurlencode($str);
1409 $str = preg_replace('|[^a-z0-9-~+_.?#=&;,/:@%]|i', '', $str);
1413 function _rawdecode($str)
1415 $str = rawurldecode($str);
1416 if (_CHERSET != 'UTF-8') {
1417 $str = mb_convert_encoding($str, _CHARSET, "UTF-8");
1419 $str = htmlspecialchars($str);
1423 function getChildren($subcat_id)
1425 $subcat_id = intval($subcat_id);
1434 $mcatTable = sql_table('plug_multiple_categories_sub');
1435 $que = sprintf($que, $mcatTable, $subcat_id);
1436 $res = sql_query($que);
1437 while ($so = mysql_fetch_object($res)) {
1438 $r .= $this->getChildren($so->scatid)
1445 function creatTagLink($tag, $narrowMode = 0, $ready = '', $sep = '')
1447 global $manager, $CONF, $blogid, $catid; //, $subcatid;
1448 $linkparams = array();
1449 if (is_numeric($blogid)) {
1450 $blogid = intval($blogid);
1452 $blogid = intval(getBlogIDFromName($blogid));
1455 $blogid = $CONF['DefaultBlog'];
1457 $b =& $manager->getBlog($blogid);
1458 if ($narrowMode == 2) {
1460 $linkparams['catid'] = intval($catid);
1462 if ($manager->pluginInstalled('NP_MultipleCategories')) {
1463 $mcategories =& $manager->getPlugin('NP_MultipleCategories');
1464 if (method_exists($mcategories, 'getRequestName')) {
1465 $subrequest = $mcategories->getRequestName();
1467 $subrequest = 'subcatid';
1469 $mcategories->event_PreSkinParse(array());
1472 $linkparams[$subrequest] = intval($subcatid);
1477 if (!empty($ready)) {
1478 $requestTagsArray = $this->splitRequestTags($ready);
1479 foreach ($requestTagsArray['and'] as $key => $val) {
1480 if (!$this->_isValidTag($val)) {
1481 $trush = array_splice($requestTagsArray['and'], $key, 1);
1484 $reqAnd = implode('+', $requestTagsArray['and']);
1485 if (!empty($requestTagsArray['or'])) {
1486 foreach ($requestTagsArray['or'] as $key => $val) {
1487 if (!$this->_isValidTag($val)) {
1488 $trush = array_splice($requestTagsArray['and'], $key, 1);
1491 $reqOr = ':' . implode(':', $requestTagsArray['or']);
1493 $ready = $reqAnd . $reqOr;
1500 /*// <Original URL Generate code>
1501 // if ($CONF['URLMode'] == 'pathinfo')
1502 // $link = $CONF['IndexURL'] . '/tag/' . $ready . $sep . $this->_rawencode($tag);
1504 // $link = $CONF['IndexURL'] . '?tag=' . $ready . $sep . $this->_rawencode($tag);
1505 $link = $b->getURL();
1506 if (substr($link, -1) != '/') {
1507 if (substr($link, -4) != '.php') {
1511 if ($CONF['URLMode'] == 'pathinfo') {
1512 $link .= 'tag/' . $ready . $sep . $this->_rawencode($tag);
1514 $link .= '?tag=' . $ready . $sep . $this->_rawencode($tag);
1516 // </ Original URL Generate code> */
1519 $CONF['BlogURL'] = $b->getURL();
1520 $linkparams['tag'] = $ready . $sep . $this->_rawencode($tag);
1521 $uri = createBlogidLink($blogid, $linkparams);
1522 if (strstr ($uri, '//')) {
1523 $uri = preg_replace("/([^:])\/\//", "$1/", $uri);
1528 // </mod by shizuki>*/
1531 // if ($manager->pluginInstalled('NP_CustomURL')) {
1532 $linkparams['tag'] = $ready . $sep . $this->_rawencode($tag);
1533 $uri = createBlogidLink($blogid, $linkparams);
1534 if (strstr ($uri, '//')) {
1535 $uri = preg_replace("/([^:])\/\//", "$1/", $uri);
1538 /* } elseif ($manager->pluginInstalled('NP_MagicalURL2') || $manager->pluginInstalled('NP_Magical')) {
1539 $uri = createBlogidLink($blogid, $linkparams);
1540 if (strstr ($uri, '//')) {
1541 $uri = preg_replace("/([^:])\/\//", "$1/", $uri);
1543 $uri = substr($uri, 0, -5) . '_tag' . $ready . $sep . $this->_rawencode($tag);
1546 // </mod by shizuki>*/
1548 // return addLinkParams($link, $linkparams);
1552 * function Tag valid
1555 function _isValidTag($encodedTag)
1557 $encodedTag = rawurldecode($encodedTag);
1558 if (_CHERSET != 'UTF-8') {
1559 $str = mb_convert_encoding($encodedTag, _CHARSET, "UTF-8");
1561 $str = $this->quote_smart($str);
1562 $q = 'SELECT listid as result FROM %s WHERE tag = %s';
1563 $Vali = quickQuery(sprintf($q, _TAGEX_KLIST_TABLE, $str));
1564 if (!empty($Vali)) {