root/branches/release-34/php/lib/mtdb_base.php @ 1800

Revision 1800, 111.8 kB (checked in by takayama, 20 months ago)

Fixed BugId:77293
* Changed to respect a class attribute

  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
3# This program is distributed under the terms of the
4# GNU General Public License, version 2.
5#
6# $Id$
7
8class MTDatabaseBase extends ezsql {
9    var $savedqueries = array();
10    var $_entry_id_cache = array();
11    var $_author_id_cache = array();
12    var $_comment_count_cache = array();
13    var $_ping_count_cache = array();
14    var $_cat_id_cache = array();
15    var $_tag_id_cache = array();
16    var $_blog_id_cache = array();
17    var $_entry_link_cache = array();
18    var $_cat_link_cache = array();
19    var $_archive_link_cache = array();
20    var $_entry_tag_cache = array();
21    var $_blog_tag_cache = array();
22    var $_asset_tag_cache = array();
23    var $_blog_asset_tag_cache = array();
24    var $serializer;
25    var $id;
26
27    function MTDatabaseBase($dbuser, $dbpassword = '', $dbname = '', $dbhost = '', $dbport = '', $dbsocket = '') {
28        $this->id = md5(uniqid('MTDatabaseBase',true));
29        $this->hide_errors();
30        $this->db($dbuser, $dbpassword, $dbname, $dbhost, $dbport, $dbsocket);
31    }
32
33    function unserialize($data) {
34        if (!$this->serializer) {
35            require_once("MTSerialize.php");
36            $this->serializer =& new MTSerialize();
37        }
38        return $this->serializer->unserialize($data);
39    }
40
41    function query($query) {
42        $this->savedqueries[] = $query;
43        parent::query($query);
44    }
45
46    function &resolve_url($path, $blog_id) {
47        $path = preg_replace('!/$!', '', $path);
48        $path = $this->escape($path);
49        $blog_id = intval($blog_id);
50        # resolve for $path -- one of:
51        #      /path/to/file.html
52        #      /path/to/index.html
53        #      /path/to/
54        #      /path/to
55        global $mt;
56        $index = $this->escape($mt->config('IndexBasename'));
57        $escindex = $this->escape($index);
58        foreach ( array($path, urldecode($path), urlencode($path)) as $p ) {
59            $sql = "
60                select *
61                  from mt_blog, mt_template, mt_fileinfo
62                  left outer join mt_templatemap on templatemap_id = fileinfo_templatemap_id
63                 where fileinfo_blog_id = $blog_id
64                       and ((fileinfo_url = '%1\$s' or fileinfo_url = '%1\$s/') or (fileinfo_url like '%1\$s/$escindex%%'))
65                   and blog_id = fileinfo_blog_id
66                   and template_id = fileinfo_template_id
67                 order by length(fileinfo_url) asc
68            ";
69            $rows = $this->get_results(sprintf($sql,$p), ARRAY_A);
70            if ($rows) {
71                break;
72            }
73        }
74        $path = $p;
75        if (!$rows) return null;
76
77        $found = false;
78        foreach ($rows as $row) {
79            $fiurl = $row['fileinfo_url'];
80            if ($fiurl == $path) {
81                $found = true;
82                break;
83            }
84            if ($fiurl == "$path/") {
85                $found = true;
86                break;
87            }
88            $ext = $row['blog_file_extension'];
89            if (!empty($ext)) $ext = '.' . $ext;
90            if ($fiurl == ($path.'/'.$index.$ext)) {
91                $found = true; break;
92            }
93            if ($found) break;
94        }
95        if (!$found) return null;
96        $data = array();
97        foreach ($row as $key => $value) {
98            if (preg_match('/^([a-z]+)/', $key, $matches)) {
99                $data[$matches[1]][$key] = $value;
100            }
101        }
102        $this->_blog_id_cache[$data['blog']['blog_id']] =& $data['blog'];
103        return $data;
104    }
105
106    function fetch_blogs($args) {
107
108        if ($blog_ids = $this->include_exclude_blogs($args)) {
109            $where = ' where blog_id ' . $blog_ids;
110        }
111        $sql = 'select * from mt_blog'
112            . $where . ' order by blog_name';
113        $res = $this->get_results($sql, ARRAY_A);
114        return $res;
115    }
116
117    function fetch_templates($args) {
118        if (isset($args['type'])) {
119            $type_filter = 'and template_type = \'' . $this->escape($args['type']) . '\'';
120        }
121        if (isset($args['blog_id'])) {
122            $blog_filter = 'and template_blog_id = ' . intval($args['blog_id']);
123        }
124        $sql = "select *
125                  from mt_template
126                 where 1 = 1
127                       $blog_filter
128                       $type_filter
129              order by template_name";
130        $result = $this->get_results($sql, ARRAY_A);
131        return $result;
132    }
133
134    function load_index_template(&$ctx, $tmpl, $blog_id = null) {
135        return $this->load_special_template($ctx, $tmpl, 'index');
136    }
137
138    function load_special_template(&$ctx, $tmpl, $type, $blog_id = null) {
139        $blog_id or $blog_id = $ctx->stash('blog_id');
140        $tmpl_name = $this->escape($tmpl);
141        $sql = "select * from mt_template" .
142            " where template_blog_id=$blog_id ".
143            ($tmpl ? " and (template_name='". $tmpl_name . "'" .
144            " or template_outfile='" . $tmpl_name ."'" .
145            " or template_identifier='" . $tmpl_name . "')" : "").
146            " and template_type='".$this->escape($type)."'";
147        list($row) = $this->get_results($sql, ARRAY_A);
148        if (!$row) return null;
149        return $row;
150    }
151
152    function fetch_config() {
153        $sql = "select * from mt_config";
154        list($row) = $this->get_results($sql, ARRAY_A);
155        if (!$row) return null;
156        return $row;
157    }
158
159    function category_link($cid, $args = null) {
160        if (isset($this->_cat_link_cache[$cid])) {
161            $url = $this->_cat_link_cache[$cid];
162        } else {
163            $sql = "select fileinfo_url, fileinfo_blog_id
164                      from mt_fileinfo, mt_templatemap
165                     where fileinfo_category_id = $cid
166                       and fileinfo_archive_type = 'Category'
167                       and templatemap_id = fileinfo_templatemap_id
168                       and templatemap_is_preferred = 1";
169            $rows = $this->get_results($sql, ARRAY_A);
170            if (count($rows)) {
171                $link =& $rows[0];
172            } else {
173                return null;
174            }
175            $blog =& $this->fetch_blog($link['fileinfo_blog_id']);
176            $blog_url = $blog['blog_site_url'];
177            $blog_url = preg_replace('!(https?://(?:[^/]+))/.*!', '$1', $blog_url);
178            $url = $blog_url . $link['fileinfo_url'];
179            $url = _strip_index($url, $blog);
180            $this->_cat_link_cache[$cid] = $url;
181        }
182        return $url;
183    }
184
185    function archive_link($ts, $at, $sql, $args) {
186        $blog_id = intval($args['blog_id']);
187        if (isset($this->_archive_link_cache[$blog_id.';'.$ts.';'.$at])) {
188            $url = $this->_archive_link_cache[$blog_id.';'.$ts.';'.$at];
189        } else {
190            if ($sql == '') {
191                $sql = "select fileinfo_url
192                          from mt_fileinfo, mt_templatemap
193                         where fileinfo_startdate = '$ts'
194                           and fileinfo_blog_id = $blog_id
195                           and fileinfo_archive_type = '".$this->escape($at)."'
196                           and templatemap_id = fileinfo_templatemap_id
197                           and templatemap_is_preferred = 1";
198            }
199            $rows = $this->get_results($sql, ARRAY_A);
200            if (count($rows)) {
201                $link =& $rows[0];
202            } else {
203                return null;
204            }
205            $blog =& $this->fetch_blog($blog_id);
206            $blog_url = $blog['blog_site_url'];
207            $blog_url = preg_replace('!(https?://(?:[^/]+))/.*!', '$1', $blog_url);
208            $url = $blog_url . $link['fileinfo_url'];
209            $url = _strip_index($url, $blog);
210            $this->_archive_link_cache[$ts.';'.$at] = $url;
211        }
212        return $url;
213    }
214
215    function entry_link($eid, $at = "Individual", $args = null) {
216        $blog_id = intval($args['blog_id']);
217        if (isset($this->_entry_link_cache[$eid.';'.$at])) {
218            $url = $this->_entry_link_cache[$eid.';'.$at];
219        } else {
220            if (preg_match('/Category/', $at)) {
221                $table = ", mt_placement";
222                $filter = "and placement_entry_id = $eid
223                           and fileinfo_category_id = placement_category_id
224                           and placement_is_primary = 1";
225            }
226            if (preg_match('/Page/', $at)) {
227                $entry = $this->fetch_page($eid);
228            } else {
229                $entry = $this->fetch_entry($eid);
230            }
231            $ts = $entry['entry_authored_on'];
232            if (preg_match('/Monthly$/', $at)) {
233                $ts = substr($ts, 0, 6) . '01000000';
234            } elseif (preg_match('/Daily$/', $at)) {
235                $ts = substr($ts, 0, 8) . '000000';
236            } elseif (preg_match('/Weekly$/', $at)) {
237                require_once("MTUtil.php");
238                list($ws, $we) = start_end_week($ts);
239                $ts = $ws;
240            } elseif (preg_match('/Yearly$/', $at)) {
241                $ts = substr($ts, 0, 4) . '0101000000';
242            } elseif ($at == 'Individual' || $at == 'Page') {
243                $filter .= "and fileinfo_entry_id = $eid";
244            }
245            if ($ts != $entry['entry_authored_on']) {
246                $filter .= " and fileinfo_startdate = '$ts'";
247            }
248            if (preg_match('/Author/', $at)) {
249                $filter .= " and fileinfo_author_id = ". $entry['entry_author_id'];
250            }
251            $sql = "select fileinfo_url, fileinfo_blog_id
252                     from mt_fileinfo, mt_templatemap $table
253                    where templatemap_id = fileinfo_templatemap_id
254                      and fileinfo_blog_id = $blog_id
255                      $filter
256                      and templatemap_archive_type = '$at'
257                      and templatemap_is_preferred = 1";
258            $rows = $this->get_results($sql, ARRAY_A);
259            if (count($rows)) {
260                $link =& $rows[0];
261            } else {
262                return null;
263            }
264            $blog =& $this->fetch_blog($link['fileinfo_blog_id']);
265            $blog_url = $blog['blog_site_url'];
266            $blog_url = preg_replace('!(https?://(?:[^/]+))/.*!', '$1', $blog_url);
267            $url = $blog_url . $link['fileinfo_url'];
268            $url = _strip_index($url, $blog);
269            $this->_entry_link_cache[$eid.';'.$at] = $url;
270        }
271        if ($at != 'Individual' && $at != 'Page') {
272            if (!$args || !isset($args['no_anchor'])) {
273                $url .= '#' . (!$args || isset($args['valid_html']) ? 'a' : '') .
274                        sprintf("%06d", $eid);
275            }
276        }
277        return $url;
278    }
279
280    /* recreation of generic load method functionality from MT::Object */
281    function &load($class, $terms = null, $args = null) {
282        $sql = "select * from mt_$class";
283        $where = '';
284        if ($terms) {
285            if (is_array($terms)) {
286                foreach ($terms as $col => $val) {
287                    $column = $class . '_' . $col;
288                    if (isset($args['range']) && isset($args['range'][$col])) {
289                        $range = '';
290                        if (isset($val[0]))
291                            $range = "$column > '" . $this->escape($val[0]) . "' ";
292                        if (isset($val[1])) {
293                            if ($range != '') $range .= ' and ';
294                            $range .= "$column < '" . $this->escape($val[0]) . "'";
295                        }
296                        $where .= " and ($range)";
297                    } elseif (isset($args['range_incl']) && isset($args['range_incl'][$col])) {
298                        $range = '';
299                        if (isset($val[0]))
300                            $range = "$column >= '" . $this->escape($val[0]) . "' ";
301                        if (isset($val[1])) {
302                            if ($range != '') $range .= ' and ';
303                            $range .= "$column <= '" . $this->escape($val[0]) . "'";
304                        }
305                        $where .= " and ($range)";
306                    } else {
307                        if (is_array($val)) {
308                            $list = '';
309                            foreach ($val as $item) {
310                                if ($list != '') $list .= ',';
311                                $list .= "'" . $this->escape($item). "'";
312                            }
313                            $where .= " and ($column in ($list))";
314                        } else {
315                            $where .= " and ($column='".$this->escape($val)."')";
316                        }
317                    }
318                }
319                $where = preg_replace('/^ and/', '', $where);
320            } else {
321                $where = " ($class"."_id=".intval($terms).")";
322            }
323            $sql .= ' where ' . $where;
324        }
325        if (isset($args['sort']) or isset($args['direction'])) {
326            $order = $args['sort'];
327            $order or $order = 'id';
328            $dir = $args['direction'] == 'descend' ? 'desc' : 'asc';
329            $sql .= " order by " . $class . "_" . $order . " $dir";
330        }
331        if (isset($args['limit']) or isset($args['offset'])) {
332            $sql .= ' <LIMIT>';
333            $sql = $this->apply_limit_sql($sql, $args['limit'], $args['offset']);
334        }
335        return $this->get_results($sql, ARRAY_A);
336    }
337
338    function get_template_text($ctx, $module, $blog_id = null, $type = 'custom', $global = null) {
339        $blog_id or $blog_id = $ctx->stash('blog_id');
340        if (($type === 'custom' || $type === 'widget')) {
341            $col = 'template_name';
342            $type_filter = "and template_type='$type'";
343        } else {
344            $col = 'template_identifier';
345            $type_filter = "";
346        }
347        if (!isset($global)) {
348            $blog_filter = "template_blog_id in (".$this->escape($blog_id).",0)";
349        } elseif ($global) {
350            $blog_filter = "template_blog_id=0";
351        } else {
352            $blog_filter = "template_blog_id=".$this->escape($blog_id);
353        }
354        $row = $this->get_row("
355            select template_text, template_modified_on, template_linked_file, template_linked_file_mtime, template_linked_file_size
356              from mt_template
357             where $blog_filter
358               and $col='".$this->escape($module)."'
359               $type_filter
360               order by template_blog_id desc", ARRAY_N);
361        if (!$row) return '';
362        list($tmpl, $ts, $file, $mtime, $size) = $row;
363        if ($file) {
364            if (!file_exists($file)) {
365                $blog = $ctx->stash('blog');
366                if ($blog['blog_id'] != $blog_id) {
367                    $blog = $this->fetch_blog($blog_id);
368                }
369                $path = $blog['blog_site_path'];
370                if (!preg_match('![\\/]$!', $path))
371                    $path .= '/';
372                $path .= $file;
373                if (is_file($path) && is_readable($path))
374                    $file = $path;
375                else
376                    $file = '';
377            }
378            if ($file) {
379                if ((filemtime($file) > $mtime) || (filesize($file) != $size)) {
380                    $contents = @file($file);
381                    $tmpl = implode('', $contents);
382                }
383            }
384        }
385        return $tmpl;
386    }
387
388    function &fetch_pages($args) {
389        $args['class'] = 'page';
390        return $this->fetch_entries($args);
391    }
392
393    function &fetch_entries($args) {
394        if ($sql = $this->include_exclude_blogs($args)) {
395            $blog_filter = 'and entry_blog_id ' . $sql;
396        } elseif (isset($args['blog_id'])) {
397            $blog_id = intval($args['blog_id']);
398            $blog_filter = 'and entry_blog_id = ' . $blog_id;
399            $blog = $this->fetch_blog($blog_id);
400        }
401
402        # automatically include offset if in request
403        if ($args['offset'] == 'auto') {
404            $args['offset'] = 0;
405            if ($args['limit'] || $args['lastn']) {
406                if ($_REQUEST['offset'] > 0) {
407                    $args['offset'] = $_REQUEST['offset'];
408                }
409            }
410        }
411
412        if ($args['limit'] > 0) {
413            $args['lastn'] = $args['limit'];
414        } elseif (!isset($args['days']) && !isset($args['lastn'])) {
415            if ($days = $blog['blog_days_on_index']) {
416                if (!isset($args['recently_commented_on'])) {
417                    $args['days'] = $days;
418                }
419            } elseif ($posts = $blog['blog_entries_on_index']) {
420                $args['lastn'] = $posts;
421            }
422        }
423        if ($args['limit'] == 'auto') {
424            if (($_REQUEST['limit'] > 0) && ($_REQUEST['limit'] < $args['lastn'])) {
425                $args['lastn'] = intval($_REQUEST['limit']);
426            }
427        }
428
429        if (isset($args['include_blogs']) or isset($args['exclude_blogs'])) {
430            $blog_ctx_arg = isset($args['include_blogs']) ?
431                array('include_blogs' => $args['include_blogs']) :
432                array('exclude_blogs' => $args['exclude_blogs']);
433        }
434
435        # a context hash for filter routines
436        $ctx = array();
437        $filters = array();
438
439        if (!isset($_REQUEST['entry_ids_published'])) {
440            $_REQUEST['entry_ids_published'] = array();
441        }
442
443        if (isset($args['unique'])) {
444            $filters[] = create_function('$e,$ctx', 'return !isset($ctx["entry_ids_published"][$e["entry_id"]]);');
445            $ctx['entry_ids_published'] = &$_REQUEST['entry_ids_published'];
446        }
447
448        # special case for selecting a particular entry
449        if (isset($args['entry_id'])) {
450            $entry_filter = 'and entry_id = '.$args['entry_id'];
451            $start = ''; $end = ''; $limit = 1; $blog_filter = ''; $day_filter = '';
452        } else {
453            $entry_filter = '';
454        }
455
456        # special case for excluding a particular entry
457        if (isset($args['not_entry_id'])) {
458            $entry_filter .= ' and entry_id != '.$args['not_entry_id'];
459        }
460
461        $entry_list = array();
462
463        # Adds a category filter to the filters list.
464        $cat_class = 'category';
465        if (!isset($args['class'])) {
466            $args['class'] = 'entry';
467        }
468        if ($args['class'] == 'page') {
469            $cat_class = 'folder';
470        }
471        if (isset($args['category']) or isset($args['categories'])) {
472            $category_arg = isset($args['category']) ? $args['category'] : $args['categories'];
473            require_once("MTUtil.php");
474            if (!preg_match('/\b(AND|OR|NOT)\b|\(|\)/i', $category_arg)) {
475                $not_clause = false;
476                $cats = cat_path_to_category($category_arg, $blog_ctx_arg, $cat_class);
477                if (count($cats)) {
478                    $category_arg = '';
479                    foreach ($cats as $cat) {
480                        if ($category_arg != '')
481                            $category_arg .= '|| ';
482                        $category_arg .= '#' . $cat['category_id'];
483                    }
484                    $category_arg = '(' . $category_arg . ')';
485                }
486            } else {
487                $not_clause = preg_match('/\bNOT\b/i', $category_arg);
488                if ($blog_ctx_arg)
489                    $cats =& $this->fetch_categories(array_merge($blog_ctx_arg, array('show_empty' => 1, 'class' => $cat_class)));
490                else
491                    $cats =& $this->fetch_categories(array('blog_id' => $blog_id, 'show_empty' => 1, 'class' => $cat_class));
492            }
493            if (!is_array($cats)) $cats = array();
494            $cexpr = create_cat_expr_function($category_arg, $cats, array('children' => $args['include_subcategories']));
495            if ($cexpr) {
496                $cmap = array();
497                $cat_list = array();
498                foreach ($cats as $cat)
499                    $cat_list[] = $cat['category_id'];
500                $pl =& $this->fetch_placements(array('category_id' => $cat_list));
501                if ($pl) {
502                    foreach ($pl as $p) {
503                        $cmap[$p['placement_entry_id']][$p['placement_category_id']]++;
504                        if (!$not_clause)
505                            $entry_list[$p['placement_entry_id']] = 1;
506                    }
507                }
508                $ctx['p'] =& $cmap;
509                $filters[] = $cexpr;
510            } else {
511                return null;
512            }
513        } elseif (isset($args['category_id'])) {
514            require_once("MTUtil.php");
515            $cat = $this->fetch_category($args['category_id']);
516            if ($cat) {
517                $cats = array($cat);
518                $cmap = array();
519                $cexpr = create_cat_expr_function($cat['category_label'], $cats, array('children' => $args['include_subcategories']));
520                $pl =& $this->fetch_placements(array('category_id' => array($cat['category_id'])));
521                if ($pl) {
522                    foreach ($pl as $p) {
523                        $cmap[$p['placement_entry_id']][$p['placement_category_id']]++;
524                    }
525                    $ctx['p'] =& $cmap;
526                    $filters[] = $cexpr;
527                } else {
528                    # this category have no entries (or pages)
529                    return null;
530                }
531            }
532        }
533        if ((0 == count($filters)) && (isset($args['show_empty']) && (1 == $args['show_empty']))) {
534            return null;
535        }
536
537        # Adds a tag filter to the filters list.
538        if (isset($args['tags']) or isset($args['tag'])) {
539            $tag_arg = isset($args['tag']) ? $args['tag'] : $args['tags'];
540            require_once("MTUtil.php");
541            $not_clause = preg_match('/\bNOT\b/i', $tag_arg);
542
543            require_once("MTUtil.php");
544            $include_private = 0;
545            $tag_array = tag_split($tag_arg);
546            foreach ($tag_array as $tag) {
547                if ($tag && (substr($tag,0,1) == '@')) {
548                    $include_private = 1;
549                }
550            }
551            if (isset($blog_ctx_arg))
552                $tags =& $this->fetch_entry_tags(array($blog_ctx_arg, 'tag' => $tag_arg, 'include_private' => $include_private, 'class' => $args['class']));
553            else
554                $tags =& $this->fetch_entry_tags(array('blog_id' => $blog_id, 'tag' => $tag_arg, 'include_private' => $include_private, 'class' => $args['class']));
555            if (!is_array($tags)) $tags = array();
556            $cexpr = create_tag_expr_function($tag_arg, $tags);
557
558            if ($cexpr) {
559                $tmap = array();
560                $tag_list = array();
561                foreach ($tags as $tag) {
562                    $tag_list[] = $tag['tag_id'];
563                }
564                if (isset($blog_ctx_arg))
565                    $ot =& $this->fetch_objecttags(array('tag_id' => $tag_list, 'datasource' => 'entry', $blog_ctx_arg));
566                elseif ($args['blog_id'])
567                    $ot =& $this->fetch_objecttags(array('tag_id' => $tag_list, 'datasource' => 'entry', 'blog_id' => $args['blog_id']));
568                if ($ot) {
569                    foreach ($ot as $o) {
570                            $tmap[$o['objecttag_object_id']][$o['objecttag_tag_id']]++;
571                        if (!$not_clause)
572                            $entry_list[$o['objecttag_object_id']] = 1;
573                    }
574                }
575                $ctx['t'] =& $tmap;
576                $filters[] = $cexpr;
577            } else {
578                return null;
579            }
580        }
581
582        # Adds a score or rate filter to the filters list.
583        if (isset($args['namespace'])) {
584            require_once("MTUtil.php");
585            $arg_names = array('min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count' );
586            foreach ($arg_names as $n) {
587                if (isset($args[$n])) {
588                    $rating_args = $args[$n];
589                    $cexpr = create_rating_expr_function($rating_args, $n, $args['namespace']);
590                    if ($cexpr) {
591                        $filters[] = $cexpr;
592                    } else {
593                        return null;
594                    }
595                }
596            }
597
598            if (isset($args['scored_by'])) {
599                $voter = $this->fetch_author_by_name($args['scored_by']);
600                if (!$voter) {
601                    echo "Invalid scored by filter: ".$args['scored_by'];
602                    return null;
603                }
604                $cexpr = create_rating_expr_function($voter['author_id'], 'scored_by', $args['namespace']);
605                if ($cexpr) {
606                    $filters[] = $cexpr;
607                } else {
608                    return null;
609                }
610            }
611        }
612
613        if (count($entry_list) && ($entry_filter == '')) {
614            $entry_list = implode(",", array_keys($entry_list));
615            # set a reasonable cap on the entry list cache. if
616            # user is selecting something too big, then they'll
617            # just have to wait through a scan.
618            if (strlen($entry_list) < 2048)
619                $entry_filter = "and entry_id in ($entry_list)";
620        }
621
622        if (isset($args['author']))
623            $author_filter = 'and author_name = \'' .
624                $this->escape($args['author']) . "'";
625
626        $start = isset($args['current_timestamp'])
627            ? $args['current_timestamp'] : null;
628        $end = isset($args['current_timestamp_end'])
629            ? $args['current_timestamp_end'] : null;
630        if ($start and $end) {
631            $start = $this->ts2db($start);
632            $end = $this->ts2db($end);
633            $date_filter = "and entry_authored_on between '$start' and '$end'";
634        } elseif ($start) {
635            $start = $this->ts2db($start);
636            $date_filter = "and entry_authored_on >= '$start'";
637        } elseif ($end) {
638            $end = $this->ts2db($end);
639            $date_filter = "and entry_authored_on <= '$end'";
640        } else {
641            $date_filter = '';
642        }
643
644        if (isset($args['lastn'])) {
645            if (!isset($args['entry_id'])) $limit = $args['lastn'];
646        } elseif (isset($args['days']) && !$date_filter) {
647            $day_filter = 'and ' . $this->limit_by_day_sql('entry_authored_on', intval($args['days']));
648        } else {
649            if ((!isset($args['current_timestamp']) &&
650                !isset($args['current_timestamp_end'])) &&
651                ($limit <= 0) &&
652                (!isset($args['category'])) &&
653                (!isset($args['categories'])) &&
654                (!isset($args['category_id'])) &&
655                (isset($blog))) {
656                if ($days = $blog['blog_days_on_index']) {
657                    if (!isset($args['recently_commented_on'])) {
658                        $day_filter = 'and ' . $this->limit_by_day_sql('entry_authored_on', $days);
659                    }
660                } elseif ($posts = $blog['blog_entries_on_index']) {
661                    $limit = $posts;
662                }
663            }
664        }
665
666        if (isset($args['sort_order'])) {
667            if ($args['sort_order'] == 'ascend') {
668                $order = 'asc';
669            } else if ($args['sort_order'] == 'descend') {
670                $order = 'desc';
671            }
672        } 
673        if (!isset($order)) {
674            $order = 'desc';
675            if (isset($blog) && isset($blog['blog_sort_order_posts'])) {
676                if ($blog['blog_sort_order_posts'] == 'ascend') {
677                    $order = 'asc';
678                }
679            }
680        }
681
682        if (isset($args['class'])) {
683            $class = $this->escape($args['class']);
684        } else {
685            $class = 'entry';
686        }
687        $class_filter = "and entry_class='$class'";
688       
689        $join_score = "";
690        $distinct = "";
691        if ( isset($args['sort_by'])
692          && (($args['sort_by'] == 'score') || ($args['sort_by'] == 'rate')) ) {
693            $join_score = "left join mt_objectscore on objectscore_object_id = entry_id and objectscore_namespace='"
694                . $args['namespace']."' and objectscore_object_ds='".$class."'";
695            $distinct = " distinct";
696        }
697
698        if (isset($args['offset']))
699            $offset = $args['offset'];
700
701        if (isset($args['limit'])) {
702            if (isset($args['sort_by'])) { 
703                if ($args['sort_by'] == 'title') { 
704                    $sort_field = 'entry_title'; 
705                } elseif ($args['sort_by'] == 'id') { 
706                    $sort_field = 'entry_id'; 
707                } elseif ($args['sort_by'] == 'status') { 
708                    $sort_field = 'entry_status'; 
709                } elseif ($args['sort_by'] == 'modified_on') { 
710                    $sort_field = 'entry_modified_on'; 
711                } elseif ($args['sort_by'] == 'author_id') { 
712                    $sort_field = 'entry_author_id'; 
713                } elseif ($args['sort_by'] == 'excerpt') { 
714                    $sort_field = 'entry_excerpt'; 
715                } elseif ($args['sort_by'] == 'comment_created_on') { 
716                    $sort_field = $args['sort_by']; 
717                } elseif ($args['sort_by'] == 'score' || $args['sort_by'] == 'rate') { 
718                    $post_sort_limit = $limit;
719                    $post_sort_offset = $offset;
720                    $limit = 0; $offset = 0;
721                } elseif ($args['sort_by'] == 'trackback_count') {
722                    $sort_field = 'entry_ping_count'; 
723                } else { 
724                    $sort_field = 'entry_' . $args['sort_by']; 
725                } 
726                if ($sort_field) $no_resort = 1; 
727            } 
728            else {
729                $sort_field ='entry_authored_on';
730            }
731            if ($sort_field) {
732                $base_order = ($args['sort_order'] == 'ascend' ? 'asc' : 'desc');
733                $base_order or $base_order = 'desc';
734            }
735        } else {
736            $base_order = 'desc';
737            if (isset($args['base_sort_order'])) {
738                if ($args['base_sort_order'] == 'ascend')
739                    $base_order = 'asc';
740            }
741            $sort_field ='entry_authored_on'; 
742            $no_resort = 0;
743        }
744
745        if (count($filters)) {
746            $post_select_limit = $limit;
747            $post_select_offset = $offset;
748            $limit = 0; $offset = 0;
749        }
750
751        $sql = "
752            select$distinct mt_entry.*, mt_placement.*, mt_author.*,
753                   mt_trackback.*
754              from mt_entry
755              left outer join mt_trackback on trackback_entry_id = entry_id
756              left outer join mt_placement on placement_entry_id = entry_id
757              $join_score
758                   and placement_is_primary = 1,
759                   mt_author
760             where entry_status = 2
761               and entry_author_id = author_id
762                   $blog_filter
763                   $entry_filter
764                   $author_filter
765                   $date_filter
766                   $day_filter
767                   $class_filter
768        ";
769        if ($sort_field) {
770            $sql .= "
771                order by $sort_field $base_order";
772        }
773        if (isset($args['recently_commented_on'])) {
774            $rco = $args['recently_commented_on'];
775            $sql = $this->entries_recently_commented_on_sql($sql);
776            $sql = $this->apply_limit_sql($sql, count($filters) ? null : $rco);
777            $args['sort_by'] or $args['sort_by'] = 'comment_created_on';
778            $args['sort_order'] or $args['sort_order'] = 'descend';
779            $post_select_limit = $rco;
780            $no_resort = 1;
781        } else {
782            $sql = $this->apply_limit_sql($sql . " <LIMIT>", $limit, $offset);
783        }
784
785        $result = $this->query_start($sql);
786        if (!$result) return null;
787
788        $entries = array();
789        $j = 0;
790        $offset = $post_select_offset ? $post_select_offset : 0;
791        $limit = $post_select_limit ? $post_select_limit : 0;
792        $id_list = array();
793        while (true) {
794            $e = $this->query_fetch(ARRAY_A);
795            if (!isset($e)) break;
796            if (count($filters)) {
797                foreach ($filters as $f) {
798                    $old_result = $this->result;
799                    if (!$f($e, $ctx)) {
800                        $this->result = $old_result;
801                        continue 2;
802                    }
803                    $this->result = $old_result;
804                }
805            }
806            if ($offset && ($j++ < $offset)) continue;
807            $e['entry_authored_on'] = $this->db2ts($e['entry_authored_on']);
808            $e['entry_modified_on'] = $this->db2ts($e['entry_modified_on']);
809            $id_list[] = $e['entry_id'];
810            $entries[] = $e;
811            $this->_comment_count_cache[$e['entry_id']] = $e['entry_comment_count'];
812            $this->_ping_count_cache[$e['entry_id']] = $e['entry_ping_count'];
813            if (($limit > 0) && (count($entries) >= $limit)) break;
814        }
815
816        if (!$no_resort) {
817            $sort_field = '';
818            if (isset($args['sort_by'])) {
819                if ($args['sort_by'] == 'title') {
820                    $sort_field = 'entry_title';
821                } elseif ($args['sort_by'] == 'id') {
822                    $sort_field = 'entry_id';
823                } elseif ($args['sort_by'] == 'status') {
824                    $sort_field = 'entry_status';
825                } elseif ($args['sort_by'] == 'modified_on') {
826                    $sort_field = 'entry_modified_on';
827                } elseif ($args['sort_by'] == 'author_id') {
828                    $sort_field = 'entry_author_id';
829                } elseif ($args['sort_by'] == 'excerpt') {
830                    $sort_field = 'entry_excerpt';
831                } elseif ($args['sort_by'] == 'comment_created_on') {
832                    $sort_field = $args['sort_by'];
833                } elseif ($args['sort_by'] == 'score') {
834                    $sort_field = $args['sort_by'];
835                } elseif ($args['sort_by'] == 'rate') {
836                    $sort_field = $args['sort_by'];
837                } elseif ($args['sort_by'] == 'trackback_count') {
838                    $sort_field = 'entry_ping_count'; 
839                } else {
840                    $sort_field = 'entry_' . $args['sort_by'];
841                }
842            } else {
843                $sort_field = 'entry_authored_on';
844            }
845            if ($sort_field) {
846                if ($sort_field == 'score') {
847                    $offset = $post_sort_offset ? $post_sort_offset : 0;
848                    $limit = $post_sort_limit ? $post_sort_limit : 0;
849                    $entries_tmp = array();
850                    foreach ($entries as $e) {
851                        $entries_tmp[$e['entry_id']] = $e;
852                    }
853                    $scores = $this->fetch_sum_scores($args['namespace'], 'entry', $order,
854                        $blog_filter . "\n" .
855                        $entry_filter . "\n" .
856                        $author_filter . "\n" .
857                        $date_filter . "\n" .
858                        $day_filter . "\n" .
859                        $class_filter . "\n"
860                    );
861                    $entries_sorted = array();
862                    foreach($scores as $score) {
863                        if (--$offset >= 0) continue;
864                        if (array_key_exists($score['objectscore_object_id'], $entries_tmp)) {
865                            array_push($entries_sorted, $entries_tmp[$score['objectscore_object_id']]);
866                            unset($entries_tmp[$score['objectscore_object_id']]);
867                            if (--$limit == 0) break;
868                        }
869                    }
870                    foreach ($entries_tmp as $et) {
871                        if ($limit == 0) break;
872                        if ($order == 'asc')
873                            array_unshift($entries_sorted, $et);
874                        else
875                            array_push($entries_sorted, $et);
876                        $limit--;
877                    }
878                    $entries = $entries_sorted;
879                } elseif ($sort_field == 'rate') {
880                    $offset = $post_sort_offset ? $post_sort_offset : 0;
881                    $limit = $post_sort_limit ? $post_sort_limit : 0;
882                    $entries_tmp = array();
883                    foreach ($entries as $e) {
884                        $entries_tmp[$e['entry_id']] = $e;
885                    }
886                    $scores = $this->fetch_avg_scores($args['namespace'], 'entry', $order,
887                        $blog_filter . "\n" .
888                        $entry_filter . "\n" .
889                        $author_filter . "\n" .
890                        $date_filter . "\n" .
891                        $day_filter . "\n" .
892                        $class_filter . "\n"
893                    );
894                    $entries_sorted = array();
895                    foreach($scores as $score) {
896                        if (--$offset >= 0) continue;
897                        if (array_key_exists($score['objectscore_object_id'], $entries_tmp)) {
898                            array_push($entries_sorted, $entries_tmp[$score['objectscore_object_id']]);
899                            unset($entries_tmp[$score['objectscore_object_id']]);
900                            if (--$limit == 0) break;
901                        }
902                    }
903                    foreach ($entries_tmp as $et) {
904                        if ($limit == 0) break;
905                        if ($order == 'asc')
906                            array_unshift($entries_sorted, $et);
907                        else
908                            array_push($entries_sorted, $et);
909                        $limit--;
910                    }
911                    $entries = $entries_sorted;
912                } else {
913                    if (($sort_field == 'entry_status') || ($sort_field == 'entry_author_id') || ($sort_field == 'entry_id')
914                          || ($sort_field == 'entry_comment_count') || ($sort_field == 'entry_ping_count')) {
915                        $sort_fn = "if (\$a['$sort_field'] == \$b['$sort_field']) return 0; return \$a['$sort_field'] < \$b['$sort_field'] ? -1 : 1;";
916                    } else {
917                        $sort_fn = "return strcmp(\$a['$sort_field'],\$b['$sort_field']);";
918                    }
919                    $sorter = create_function(
920                        $order == 'asc' ? '$a,$b' : '$b,$a',
921                        $sort_fn);
922                    usort($entries, $sorter);
923                }
924            }
925        }
926
927        if (count($id_list) <= 30) { # TODO: find a good upper limit
928            # pre-cache comment counts and categories for these entries
929            $this->cache_categories($id_list);
930            $this->cache_permalinks($id_list);
931        }
932
933        return $entries;
934    }
935
936    function fetch_plugin_config($plugin, $scope = "system") {
937        if ($scope != 'system') {
938            $key = 'configuration:'.$scope;
939        } else {
940            $key = 'configuration';
941        }
942        return $this->fetch_plugin_data($plugin, $key);
943    }
944
945    function fetch_plugin_data($plugin, $key) {
946        $plugin = $this->escape($plugin);
947        $key = $this->escape($key);
948        $sql = "
949            select plugindata_data from mt_plugindata
950             where plugindata_plugin = '$plugin'
951               and plugindata_key = '$key'";
952        $data = $this->get_var($sql);
953        if ($data) {
954            return $this->unserialize($data);
955        }
956        return null;
957    }
958
959    function &fetch_entry_tags($args) {
960        $class = 'entry';
961        if (isset($args['class'])) {
962            $class = $args['class'];
963        }
964
965        # load tags
966        if (isset($args['entry_id'])) {
967            if (!isset($args['tags']) && !isset($args['tag'])) {
968                if (isset($this->_entry_tag_cache[$args['entry_id']])) {
969                    return $this->_entry_tag_cache[$args['entry_id']];
970                }
971            }
972            $entry_filter = 'and objecttag_tag_id in (select objecttag_tag_id from mt_objecttag where objecttag_object_id='.intval($args['entry_id']).')';
973        }
974
975        $blog_filter = $this->include_exclude_blogs($args);
976        if ($blog_filter == '' and isset($args['blog_id'])) {
977            if (!isset($args['tags']) && !isset($args['tag'])) {
978                if (!isset($args['entry_id'])) {
979                    if (isset($this->_blog_tag_cache[$args['blog_id'].":$class"])) {
980                        return $this->_blog_tag_cache[$args['blog_id'].":$class"];
981                    }
982                }
983            }
984            $blog_filter = ' = '. intval($args['blog_id']);
985        }
986        if ($blog_filter != '') 
987            $blog_filter = 'and objecttag_blog_id ' . $blog_filter;
988
989        if (!isset($args['include_private'])) {
990            $private_filter = 'and (tag_is_private = 0 or tag_is_private is null)';
991        }
992        if (isset($args['tags']) && ($args['tags'] != '')) {
993            $tag_list = '';
994            require_once("MTUtil.php");
995            $tag_array = tag_split($args['tags']);
996            foreach ($tag_array as $tag) {
997                if ($tag_list != '') $tag_list .= ',';
998                $tag_list .= "'" . $this->escape($tag) . "'";
999            }
1000            if ($tag_list != '') {
1001                $tag_filter = 'and (tag_name in (' . $tag_list . '))';
1002                $private_filter = '';
1003            }
1004        }
1005
1006        $sort_col = isset($args['sort_by']) ? $args['sort_by'] : 'name';
1007        $sort_col = "tag_$sort_col";
1008        if (isset($args['sort_order']) and $args['sort_order'] == 'descend') {
1009            $order = 'desc';
1010        } else {
1011            $order = 'asc';
1012        }
1013        $id_order = '';
1014        if ($sort_col == 'tag_name') {
1015            $sort_col = 'lower(tag_name)';
1016        }else{
1017            $id_order = ', lower(tag_name)';
1018        }
1019
1020        $sql = "
1021            select tag_id, tag_name, count(*) as tag_count
1022             from mt_tag, mt_objecttag, mt_entry
1023             where objecttag_tag_id = tag_id
1024               and entry_id = objecttag_object_id and objecttag_object_datasource='entry'
1025               and entry_status = 2
1026                   and entry_class = '$class'
1027                   $blog_filter
1028                   $tag_filter
1029                   $entry_filter
1030                   $private_filter
1031            group by tag_id, tag_name
1032            order by $sort_col $order $id_order";
1033        $tags = $this->get_results($sql, ARRAY_A);
1034        if (!isset($args['tag'])) {
1035            if ($args['entry_id'])
1036                $this->_entry_tag_cache[$args['entry_id']] = $tags;
1037            elseif ($args['blog_id'])
1038                $this->_blog_tag_cache[$args['blog_id'].":$class"] = $tags;
1039        }
1040        return $tags;
1041    }
1042
1043    function &fetch_asset_tags($args) {
1044
1045        # load tags by asset
1046        if (!isset($args['include_private'])) {
1047            $private_filter = 'and (tag_is_private = 0 or tag_is_private is null)';
1048        }
1049
1050        if (isset($args['asset_id'])) {
1051            if (isset($args['tags'])) {
1052                if (isset($this->_asset_tag_cache[$args['asset_id']]))
1053                    return $this->_asset_tag_cache[$args['asset_id']];
1054            }
1055            $asset_filter = 'and objecttag_object_id = '.intval($args['asset_id']);
1056        }
1057       
1058        if (isset($args['blog_id'])) {
1059            if (!isset($args['tags'])) {
1060                if (isset($this->_blog_asset_tag_cache[$args['blog_id']]))
1061                    return $this->_blog_asset_tag_cache[$args['blog_id']];
1062            }
1063            $blog_filter = 'and objecttag_blog_id = '.intval($args['blog_id']);
1064        }
1065
1066        if (isset($args['tags']) && ($args['tags'] != '')) {
1067            $tag_list = '';
1068            require_once("MTUtil.php");
1069            $tag_array = tag_split($args['tags']);
1070            foreach ($tag_array as $tag) {
1071                if ($tag_list != '') $tag_list .= ',';
1072                $tag_list .= "'" . $this->escape($tag) . "'";
1073            }
1074            if ($tag_list != '') {
1075                $tag_filter = 'and (tag_name in (' . $tag_list . '))';
1076                $private_filter = '';
1077            }
1078        }
1079
1080        $sort_col = isset($args['sort_by']) ? $args['sort_by'] : 'name';
1081        $sort_col = "tag_$sort_col";
1082        if (isset($args['sort_order']) and $args['sort_order'] == 'descend')
1083            $order = 'desc';
1084        else
1085            $order = 'asc';
1086
1087        $id_order = '';
1088        if ($sort_col == 'tag_name')
1089            $sort_col = 'lower(tag_name)';
1090        else
1091            $id_order = ', lower(tag_name)';
1092
1093        $sql = "
1094            select tag_id, tag_name, count(*) as tag_count
1095            from mt_tag, mt_objecttag, mt_asset
1096            where objecttag_tag_id = tag_id
1097                and asset_id = objecttag_object_id and objecttag_object_datasource='asset'
1098                $blog_filter
1099                $private_filter
1100                $tag_filter
1101                $asset_filter
1102            group by tag_id, tag_name
1103            order by $sort_col $order $id_order
1104        ";
1105        $tags = $this->get_results($sql, ARRAY_A);
1106        if (isset($args['tags'])) {
1107            if ($args['asset_id'])
1108                $this->_asset_tag_cache[$args['asset_id']] = $tags;
1109            elseif ($args['blog_id'])
1110                $this->_blog_asset_tag_cache[$args['blog_id']] = $tags;
1111        }
1112        return $tags;
1113    }
1114
1115    function &fetch_folders($args) {
1116        $args['class'] = 'folder';
1117        return $this->fetch_categories($args);
1118    }
1119
1120    function &fetch_categories($args) {
1121        # load categories
1122
1123        if ($blog_filter = $this->include_exclude_blogs($args)) {
1124             $blog_filter = 'and category_blog_id '. $blog_filter;
1125        } elseif (isset($args['blog_id'])) {
1126            $blog_filter = 'and category_blog_id = '.intval($args['blog_id']);
1127        }
1128        if (isset($args['parent'])) {
1129            $parent = $args['parent'];
1130            if (is_array($parent)) {
1131                $parent_filter = 'and category_parent in (' . implode(',', $parent) . ')';
1132            } else {
1133                $parent_filter = 'and category_parent = '.intval($parent);
1134            }
1135        }
1136        if (isset($args['category_id'])) {
1137            if (isset($args['children'])) {
1138                if (isset($this->_cat_id_cache['c'.$args['category_id']])) {
1139                    $cat = $this->_cat_id_cache['c'.$args['category_id']];
1140                    if (isset($cat['_children'])) {
1141                        $children = $cat['_children'];
1142                        if ($children === false) {
1143                            return null;
1144                        } else {
1145                            return $children;
1146                        }
1147                    }
1148                }
1149
1150                $cat_filter = 'and category_parent = '.intval($args['category_id']);
1151            } else {
1152                $cat_filter = 'and category_id = '.intval($args['category_id']);
1153                $limit = 1;
1154            }
1155        } elseif (isset($args['label'])) {
1156            $cat_filter = 'and category_label = \''.$this->escape($args['label']).'\'';
1157        } else {
1158            $limit = $args['lastn'];
1159            if (isset($args['sort_order'])) {
1160                if ($args['sort_order'] == 'ascend') {
1161                    $sort_order = 'asc';
1162                } elseif ($args['sort_order'] == 'descend') {
1163                    $sort_order = 'desc';
1164                }
1165            } else {
1166                $sort_order = '';
1167            }
1168        }
1169        $count_column = 'placement_id';
1170        if ($args['show_empty']) {
1171            $join_clause = 'left outer join mt_placement on placement_category_id = category_id';
1172            if (isset($args['entry_id'])) {
1173                $join_clause .= ' left outer join mt_entry on placement_entry_id = entry_id and entry_id = '.intval($args['entry_id']);
1174            } else {
1175                $join_clause .= ' left outer join mt_entry on placement_entry_id = entry_id and entry_status = 2';
1176            }
1177            $count_column = 'entry_id';
1178        } else {
1179            $join_clause = ', mt_entry, mt_placement';
1180            $cat_filter .= ' and placement_category_id = category_id';
1181            if (isset($args['entry_id'])) {
1182                $entry_filter = 'and placement_entry_id = entry_id and placement_entry_id = '.intval($args['entry_id']);
1183            } else {
1184                $entry_filter = 'and placement_entry_id = entry_id and entry_status = 2';
1185            }
1186        }
1187
1188        if (isset($args['class'])) {
1189            $class = $this->escape($args['class']);
1190        } else {
1191            $class = "category";
1192        }
1193        $class_filter = "and category_class='$class'";
1194
1195        $sql = "
1196            select category_id, count($count_column) as category_count
1197              from mt_category $join_clause
1198             where 1 = 1
1199                   $cat_filter
1200                   $entry_filter
1201                   $blog_filter
1202                   $parent_filter
1203                   $class_filter
1204             group by category_id
1205                   <LIMIT>
1206        ";
1207        $sql = $this->apply_limit_sql($sql, $limit, $offset);
1208
1209        $categories = $this->get_results($sql, ARRAY_A);
1210        if (!$categories) {
1211            return null;
1212        }
1213        if (isset($args['children']) && isset($parent_cat)) {
1214            $parent_cat['_children'] =& $categories;
1215        } else {
1216            $ids = array();
1217            $counts = array();
1218            foreach ($categories as $cid => $cat) {
1219                $counts[$cat['category_id']] = $cat['category_count'];
1220                $ids[] = $cat['category_id'];
1221            }
1222            $list = implode(",", $ids);
1223            $sql2 = "
1224                select mt_category.*, mt_trackback.*
1225                    from mt_category left outer join mt_trackback on trackback_category_id = category_id
1226                   where category_id in ($list)
1227                order by category_label $sort_order
1228            ";
1229            $categories = $this->get_results($sql2, ARRAY_A);
1230            $id_list = array();
1231            foreach ($categories as $cid => $cat) {
1232                $cat_id = $cat['category_id'];
1233                $categories[$cid]['category_count'] = $counts[$cat_id];
1234                if (isset($args['top_level_categories']) || !isset($this->_cat_id_cache['c'.$cat_id])) {
1235                    $id_list[] = $cat_id;
1236                    $this->_cat_id_cache['c'.$cat_id] = $categories[$cid];
1237                }
1238                if (isset($args['top_level_categories'])) {
1239                    $this->_cat_id_cache['c'.$cat_id]['_children'] = false;
1240                }
1241            }
1242
1243            $top_cats = array();
1244            foreach ($categories as $cid => $cat) {
1245                if ($cat['category_parent'] > 0) {
1246                    $parent_id = $cat['category_parent'];
1247                    if (isset($this->_cat_id_cache['c'.$parent_id])) {
1248                        if (isset($args['top_level_categories'])) {
1249                            $parent =& $this->fetch_category($categories[$cid]['category_parent']);
1250                            if (!isset($parent['_children']) || ($parent['_children'] === false)) {
1251                                $parent['_children'] = array(&$categories[$cid]);
1252                            } else {
1253                                $parent['_children'][] = $categories[$cid];
1254                            }
1255                        }
1256                    }
1257                }
1258                if ((!$cat['category_parent']) && (isset($args['top_level_categories']))) {
1259                    $top_cats[] = $categories[$cid];
1260                }
1261            }
1262            $this->cache_category_links($id_list);
1263            if (isset($args['top_level_categories'])) {
1264                return $top_cats;
1265            }
1266        }
1267        return $categories;
1268    }
1269
1270    function &fetch_entry($entry_id) {
1271        if (isset($this->_entry_id_cache['entry_id'])) {
1272            return $this->_entry_id_cache[$entry_id];
1273        }
1274        list($entry) = $this->fetch_entries(array('entry_id' => $entry_id));
1275        $this->_entry_id_cache[$entry_id] = $entry;
1276        return $entry;
1277    }
1278
1279    function &fetch_page($entry_id) {
1280        if (isset($this->_entry_id_cache['entry_id'])) {
1281            return $this->_entry_id_cache[$entry_id];
1282        }
1283        list($entry) = $this->fetch_pages(array('entry_id' => $entry_id));
1284        $this->_entry_id_cache[$entry_id] = $entry;
1285        return $entry;
1286    }
1287
1288    function &fetch_author($author_id) {
1289        if (isset($this->_author_id_cache[$author_id])) {
1290            return $this->_author_id_cache[$author_id];
1291        }
1292        global $mt;
1293        $args['blog_id'] = $mt->blog_id;
1294        $args['author_id'] = $author_id;
1295        $args['any_type'] = 1;
1296        $result = $this->fetch_authors($args);
1297        $author = null;
1298        if (is_array($result)) {
1299            $author = $result[0];
1300            $this->_author_id_cache[$author_id] = $author;
1301        }
1302        return $author;
1303    }
1304
1305    function &fetch_author_by_name($author_name) {
1306        global $mt;
1307        $args['blog_id'] = $mt->blog_id;
1308        $args['author_name'] = $this->escape($author_name);
1309        $result = $this->fetch_authors($args);
1310        $author = null;
1311        if (is_array($result)) {
1312            $author = $result[0];
1313            $this->_author_id_cache[$author['author_id']] = $author;
1314        }
1315        return $author;
1316    }
1317
1318    function &fetch_authors($args) {
1319        # Adds blog join
1320        $extend_column = '';
1321        if ($sql = $this->include_exclude_blogs($args)) {
1322            $blog_join = 'join mt_permission on permission_author_id = author_id and permission_blog_id ' . $sql;
1323            $extend_column = ', mt_permission.*';
1324        } elseif (isset($args['blog_id'])) {
1325            $blog_id = intval($args['blog_id']);
1326            $blog_join = "join mt_permission on permission_author_id = author_id and permission_blog_id = $blog_id";
1327            $extend_column = ', mt_permission.*';
1328        }
1329
1330        # Adds author filter
1331        if (isset($args['author_id'])) {
1332            $author_id = intval($args['author_id']);
1333            $author_filter = " and author_id = $author_id";
1334        }
1335        if (isset($args['author_nickname'])) {
1336            $author_filter .= " and author_nickname = '".$args['author_nickname']."'";
1337        }
1338        if (isset($args['author_name'])) {
1339            $author_filter .= " and author_name = '".$args['author_name']."'";
1340        }
1341
1342        # Adds entry join and filter
1343        if ($args['need_entry']) {
1344            $entry_join = 'join mt_entry on author_id = entry_author_id';
1345            $unique_filter = 'distinct';
1346            $entry_filter = " and entry_status = 2";
1347            if ($blog_join) {
1348                $entry_filter .= " and entry_blog_id = permission_blog_id";
1349            } else {
1350                $entry_filter .= " and entry_blog_id = ".$args['blog_id'];
1351            }
1352        } else {
1353            if ( ! $args['any_type'] )
1354                $author_filter .= " and author_type = 1";
1355        }
1356
1357        # a context hash for filter routines
1358        $ctx = array();
1359        $filters = array();
1360
1361        if (isset($args['status'])) {
1362            $status_arg = $args['status'];
1363            require_once("MTUtil.php");
1364            $status = array(
1365                array('name' => 'enabled', 'id' => 1),
1366                array('name' => 'disabled', 'id' => 2));
1367
1368            $cexpr = create_status_expr_function($status_arg, $status);
1369            if ($cexpr) {
1370                $filters[] = $cexpr;
1371            }
1372        }
1373
1374        if (isset($args['roles']) or isset($args['role'])) {
1375            $role_arg = isset($args['role']) ? $args['role'] : $args['roles'];
1376            require_once("MTUtil.php");
1377            $roles =& $this->fetch_all_roles();
1378            if (!is_array($roles)) $roles = array();
1379
1380            $cexpr = create_role_expr_function($role_arg, $roles);
1381            if ($cexpr) {
1382                $rmap = array();
1383                $role_list = array();
1384                foreach ($roles as $role) {
1385                    $role_list[] = $role['role_id'];
1386                }
1387                $as =& $this->fetch_associations(array('blog_id' => $blog_id, 'role_id' => $role_list));
1388                if ($as) {
1389                    foreach ($as as $a) {
1390                        $rmap[$a['association_author_id']][$a['association_role_id']]++;
1391                    }
1392                }
1393                $ctx['r'] =& $rmap;
1394                $filters[] = $cexpr;
1395            }
1396        }
1397
1398        # Adds a score or rate filter to the filters list.
1399        $re_sort = false;
1400        if (isset($args['namespace'])) {
1401            require_once("MTUtil.php");
1402            $arg_names = array('min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count' );
1403            foreach ($arg_names as $n) {
1404                if (isset($args[$n])) {
1405                    $rating_args = $args[$n];
1406                    $cexpr = create_rating_expr_function($rating_args, $n, $args['namespace'], 'author');
1407                    if ($cexpr) {
1408                        $filters[] = $cexpr;
1409                        $re_sort = true;
1410                    } else {
1411                        return null;
1412                    }
1413                }
1414            }
1415        }
1416
1417        # sort
1418        $join_score = "";
1419        if (isset($args['sort_by'])) {
1420            if (($args['sort_by'] == 'score') || ($args['sort_by'] == 'rate')) {
1421                $join_score = "join mt_objectscore on objectscore_object_id = author_id and objectscore_namespace='".$args['namespace']."' and objectscore_object_ds='author'";
1422                $unique_filter = 'distinct';
1423                $order_sql = "order by author_created_on desc";
1424                $re_sort = true;
1425            } else {
1426                $sort_col = $args['sort_by'];
1427                $order = '';
1428                if (isset($args['sort_order'])) {
1429                    if ($args['sort_order'] == 'ascend')
1430                        $order = 'asc';
1431                    else
1432                        $order = 'desc';
1433                }
1434                $order_sql = "order by $sort_col $order";
1435   
1436                if (isset($args['start_string'])) {
1437                    $val = $args['start_string'];
1438                    if ($order == 'asc')
1439                        $val_order = '>';
1440                    else
1441                        $val_order = '<';
1442                    $sort_filter =  " and $sort_col $val_order '$val'";
1443                }
1444   
1445                if (isset($args['start_num'])) {
1446                    $val = $args['start_num'];
1447                    if ($order == 'asc')
1448                        $val_order = '>';
1449                    else
1450                        $val_order = '<';
1451                    $sort_filter .= " and $sort_col $val_order $val";
1452                }
1453            }
1454        }
1455
1456        $limit = 0;
1457        $offset = 0;
1458        if (isset($args['lastn']))
1459            $limit = $args['lastn'];
1460        if (isset($args['offset']))
1461            $limit = $args['offset'];
1462
1463        if ($re_sort) {
1464            $post_select_limit = $limit;
1465            $post_select_offset = $offset;
1466            $limit = 0; $offset = 0;
1467        }
1468       
1469        $sql = "
1470            select $unique_filter
1471                   mt_author.*
1472                   $extend_column
1473              from mt_author
1474                   $blog_join
1475                   $entry_join
1476                   $join_score
1477              where 1 = 1
1478                $author_filter
1479                $entry_filter
1480                $sort_filter
1481              $order_sql
1482                   <LIMIT>
1483        ";
1484        $sql = $this->apply_limit_sql($sql, $limit, $offset);
1485
1486        $result = $this->query_start($sql);
1487        if (!$result) return null;
1488
1489        $authors = array();
1490        if ($args['sort_by'] != 'score' && $args['sort_by'] != 'rate') {
1491            $offset = $post_select_offset ? $post_select_offset : 0;
1492            $limit = $post_select_limit ? $post_select_limit : 0;
1493        }
1494        $j = 0;
1495        while (true) {
1496            $e = $this->query_fetch(ARRAY_A);
1497            if ($offset && ($j++ < $offset)) continue;
1498            if (!isset($e)) break;
1499            if (count($filters)) {
1500                foreach ($filters as $f) {
1501                    if (!$f($e, $ctx)) continue 2;
1502                }
1503            }
1504            $authors[] = $e;
1505            if (($limit > 0) && (count($authors) >= $limit)) break;
1506        }
1507
1508        if (isset($args['sort_by']) && ('score' == $args['sort_by'])) {
1509            $authors_tmp = array();
1510            $order = 'asc';
1511            if (isset($args['sort_order']))
1512                $order = $args['sort_order'] == 'ascend' ? 'asc' : 'desc';
1513            foreach ($authors as $a) {
1514                $authors_tmp[$a['author_id']] = $a;
1515            }
1516            $scores = $this->fetch_sum_scores($args['namespace'], 'author', $order,
1517                $author_filter
1518            );
1519            $offset = $post_select_offset ? $post_select_offset : 0;
1520            $limit = $post_select_limit ? $post_select_limit : 0;
1521            $j = 0;
1522            $authors_sorted = array();
1523            foreach($scores as $score) {
1524                if (array_key_exists($score['objectscore_object_id'], $authors_tmp)) {
1525                    if ($offset && ($j++ < $offset)) continue;
1526                    array_push($authors_sorted, $authors_tmp[$score['objectscore_object_id']]);
1527                    unset($authors_tmp[$score['objectscore_object_id']]);
1528                    if (($limit > 0) && (count($authors_sorted) >= $limit)) break;
1529                }
1530            }
1531            $authors = $authors_sorted;
1532
1533        } elseif (isset($args['sort_by']) && ('rate' == $args['sort_by'])) {
1534            $authors_tmp = array();
1535            $order = 'asc';
1536            if (isset($args['sort_order']))
1537                $order = $args['sort_order'] == 'ascend' ? 'asc' : 'desc';
1538            foreach ($authors as $a) {
1539                $authors_tmp[$a['author_id']] = $a;
1540            }
1541            $scores = $this->fetch_avg_scores($args['namespace'], 'author', $order,
1542                $author_filter
1543            );
1544            $offset = $post_select_offset ? $post_select_offset : 0;
1545            $limit = $post_select_limit ? $post_select_limit : 0;
1546            $j = 0;
1547            $authors_sorted = array();
1548            foreach($scores as $score) {
1549                if (array_key_exists($score['objectscore_object_id'], $authors_tmp)) {
1550                    if ($offset && ($j++ < $offset)) continue;
1551                    array_push($authors_sorted, $authors_tmp[$score['objectscore_object_id']]);
1552                    unset($authors_tmp[$score['objectscore_object_id']]);
1553                    if (($limit > 0) && (count($authors_sorted) >= $limit)) break;
1554                }
1555            }
1556            $authors = $authors_sorted;
1557
1558        }
1559
1560        return $authors;
1561    }
1562
1563    function &fetch_all_roles() {
1564        $sql = "select *
1565                  from mt_role
1566              order by role_name";
1567        $result = $this->get_results($sql, ARRAY_A);
1568        return $result;
1569    }
1570
1571    function &fetch_associations($args) {
1572        $id_list = implode(",", $args['role_id']);
1573        if (empty($id_list))
1574            return;
1575        if ($sql = $this->include_exclude_blogs($args)) {
1576            $blog_filter = 'and association_blog_id  ' . $sql;
1577        } elseif (isset($args['blog_id'])) {
1578            $blog_filter = 'and association_blog_id = ' . intval($args['blog_id']);
1579        }
1580        $sql = "select *
1581                  from mt_association
1582                 where association_role_id in ($id_list)
1583                   $blog_filter";
1584        $result = $this->get_results($sql, ARRAY_A);
1585        return $result;
1586    }
1587
1588    function &fetch_tag($tag_id) {
1589        $tag_id = intval($tag_id);
1590        if (isset($this->_tag_id_cache[$tag_id])) {
1591            return $this->_tag_id_cache[$tag_id];
1592        }
1593        $tag = $this->get_row("
1594            select *
1595              from mt_tag
1596             where tag_id=$tag_id
1597        ", ARRAY_A);
1598        $this->_tag_id_cache[$tag_id] = $tag;
1599        return $tag;
1600    }
1601
1602    function &fetch_tag_by_name($tag_name) {
1603        $tag_name = $this->escape($tag_name);
1604        $tag = $this->get_row("
1605            select *
1606              from mt_tag
1607             where tag_name='$tag_name'
1608        ", ARRAY_A);
1609        $this->_tag_id_cache[$tag['tag_id']] = $tag;
1610        return $tag;
1611    }
1612
1613    function fetch_scores($namespace, $obj_id, $datasource) {
1614        $scores = $this->get_results("
1615            select * from mt_objectscore
1616            where objectscore_namespace='$namespace'
1617            and objectscore_object_id='$obj_id'
1618            and objectscore_object_ds='$datasource'
1619        ", ARRAY_A);
1620        return $scores;
1621    }
1622
1623    function fetch_score($namespace, $obj_id, $user_id, $datasource) {
1624        list($score) = $this->get_results("
1625            select * from mt_objectscore
1626            where objectscore_namespace='$namespace'
1627            and objectscore_object_id='$obj_id'
1628            and objectscore_object_ds='$datasource'
1629            and objectscore_author_id='$user_id'
1630        ", ARRAY_A);
1631        return $score;
1632    }
1633
1634    function fetch_sum_scores($namespace, $datasource, $order, $filters) {
1635        $othertables = '';
1636        $otherwhere = '';
1637        if ($datasource == 'asset') {
1638            $othertables = ', mt_author';
1639            $otherwhere = 'AND (objectscore_author_id = author_id)';
1640        }
1641        $join_column = $datasource . '_id';
1642        $join_where = "AND ($join_column = objectscore_object_id)";
1643        $sql_scores = 
1644            "SELECT SUM(objectscore_score) AS sum_objectscore_score, objectscore_object_id
1645             FROM mt_objectscore, mt_$datasource $othertables
1646             WHERE (objectscore_namespace = '$namespace')
1647             AND (objectscore_object_ds = '$datasource')
1648             $join_where
1649             $otherwhere
1650             $filters
1651             GROUP BY objectscore_object_id
1652             ORDER BY sum_objectscore_score " . $order;
1653        $scores = $this->get_results($sql_scores, ARRAY_A);
1654        return $scores;
1655    }
1656
1657    function fetch_avg_scores($namespace, $datasource, $order, $filters) {
1658        $othertables = '';
1659        $otherwhere = '';
1660        if ($datasource == 'asset') {
1661            $othertables = ', mt_author';
1662            $otherwhere = 'AND (objectscore_author_id = author_id)';
1663        }
1664        $join_column = $datasource . '_id';
1665        $join_where = "AND ($join_column = objectscore_object_id)";
1666        $sql_scores = 
1667            "SELECT AVG(objectscore_score) AS sum_objectscore_score, objectscore_object_id
1668             FROM mt_objectscore, mt_$datasource $othertables
1669             WHERE (objectscore_namespace = '$namespace')
1670             AND (objectscore_object_ds = '$datasource')
1671             $join_where
1672             $otherwhere
1673             $filters
1674             GROUP BY objectscore_object_id
1675             ORDER BY sum_objectscore_score " . $order;
1676        $scores = $this->get_results($sql_scores, ARRAY_A);
1677        return $scores;
1678    }
1679
1680    function cache_permalinks(&$entry_list) {
1681        $id_list = '';
1682        foreach ($entry_list as $entry_id) {
1683            if (!isset($this->_entry_link_cache[$entry_id.';Individual'])) {
1684                $id_list .= ','.$entry_id;
1685                $this->_entry_link_cache[$entry_id.';Individual'] = ''; 
1686            }
1687        }
1688        if (empty($id_list))
1689            return;
1690        $id_list = substr($id_list, 1);
1691        $query = "
1692            select fileinfo_entry_id, fileinfo_url, blog_site_url, blog_file_extension
1693              from mt_fileinfo, mt_templatemap, mt_blog
1694             where fileinfo_entry_id in ($id_list)
1695               and fileinfo_archive_type = 'Individual'
1696               and blog_id = fileinfo_blog_id
1697               and templatemap_id = fileinfo_templatemap_id
1698               and templatemap_is_preferred = 1
1699        ";
1700        $results = $this->get_results($query, ARRAY_N);
1701        if ($results) {
1702
1703            foreach ($results as $row) {
1704                $blog_url = $row[2];
1705                $blog_url = preg_replace('!(https?://(?:[^/]+))/.*!', '$1', $blog_url);
1706                $url = $blog_url . $row[1];
1707                $url = _strip_index($url, array('blog_file_extension' => $row[3]));
1708                $this->_entry_link_cache[$row[0].';Individual'] = $url;
1709            }
1710        }
1711    }
1712
1713    function cache_category_links(&$cat_list) {
1714        $id_list = '';
1715        foreach ($cat_list as $cat_id) {
1716            if (!isset($this->_cat_link_cache[$cat_id])) {
1717                $id_list .= ','.$cat_id;
1718                $this->_cat_link_cache[$cat_id] = '';
1719            }
1720        }
1721        if (empty($id_list))
1722            return;
1723        $id_list = substr($id_list, 1);
1724        $query = "
1725            select fileinfo_category_id, fileinfo_url, blog_site_url, blog_file_extension
1726              from mt_fileinfo, mt_templatemap, mt_blog
1727             where fileinfo_category_id in ($id_list)
1728               and fileinfo_archive_type = 'Category'
1729               and blog_id = fileinfo_blog_id
1730               and templatemap_id = fileinfo_templatemap_id
1731               and templatemap_is_preferred = 1
1732        ";
1733        $results = $this->get_results($query, ARRAY_N);
1734        if ($results) {
1735            foreach ($results as $row) {
1736                $blog_url = $row[2];
1737                $blog_url = preg_replace('!(https?://(?:[^/]+))/.*!', '$1', $blog_url);
1738                $url = $blog_url . $row[1];
1739                $url = _strip_index($url, array('blog_file_extension' => $row[3]));
1740                $this->_cat_link_cache[$row[0]] = $url;
1741            }
1742        }
1743    }
1744
1745    function cache_comment_counts(&$entry_list) {
1746        $id_list = '';
1747        foreach ($entry_list as $entry_id) {
1748            if (!isset($this->_comment_count_cache[$entry_id])) {
1749                $id_list .= ','.$entry_id;
1750                $this->_comment_count_cache[$entry_id] = 0;
1751            }
1752        }
1753        if (empty($id_list))
1754            return;
1755        $id_list = substr($id_list, 1);
1756        $query = "
1757            select entry_id, entry_comment_count
1758              from mt_entry
1759             where entry_id in ($id_list)
1760        ";
1761        $results = $this->get_results($query, ARRAY_N);
1762        if ($results) {
1763            foreach ($results as $row) {
1764                $this->_comment_count_cache[$row[0]] = $row[1];
1765            }
1766        }
1767    }
1768
1769    function blog_entry_count($args) {
1770
1771        if ($sql = $this->include_exclude_blogs($args)) {
1772            $blog_filter = 'and entry_blog_id ' . $sql;
1773        } elseif (isset($args['blog_id'])) {
1774            $blog_id = intval($args['blog_id']);
1775            $blog_filter = 'and entry_blog_id = ' . $blog_id;
1776        }
1777        $class = 'entry';
1778        if (isset($args['class'])) {
1779            $class = $args['class'];
1780        }
1781        $count = $this->get_var("
1782          select count(*)
1783            from mt_entry
1784            where entry_status = 2
1785            and entry_class='$class'
1786            $blog_filter
1787            ");
1788        return $count;
1789    }
1790
1791    function blog_comment_count($args) {
1792
1793        if ($sql = $this->include_exclude_blogs($args)) {
1794            $blog_filter = 'and comment_blog_id ' . $sql;
1795        } elseif (isset($args['blog_id'])) {
1796            $blog_id = intval($args['blog_id']);
1797            $blog_filter = 'and comment_blog_id = ' . $blog_id;
1798        }
1799
1800        $count = $this->get_var("
1801            select count(*)
1802              from mt_entry, mt_comment
1803             where entry_status = 2
1804               and comment_visible = 1
1805               and comment_entry_id = entry_id
1806               $blog_filter
1807        ");
1808        return $count;
1809    }
1810
1811    function category_comment_count($args) {
1812        $cat_id = (int)$args['category_id'];
1813        $sql = "select count(*)
1814             from mt_placement, mt_comment, mt_entry
1815            where placement_category_id=$cat_id
1816              and entry_id=placement_entry_id
1817              and entry_status=2
1818              and comment_entry_id=entry_id
1819              and comment_visible=1";
1820        return $this->get_var($sql);
1821    }
1822
1823    function blog_ping_count($args) {
1824
1825        if ($sql = $this->include_exclude_blogs($args)) {
1826            $blog_filter = 'and tbping_blog_id ' . $sql;
1827        } elseif (isset($args['blog_id'])) {
1828            $blog_id = intval($args['blog_id']);
1829            $blog_filter = 'and tbping_blog_id = ' . $blog_id;
1830        }
1831
1832        $count = $this->get_var("
1833            select count(*)
1834              from mt_tbping, mt_trackback
1835             where tbping_visible = 1
1836               and tbping_tb_id = trackback_id
1837                   $blog_filter
1838        ");
1839        return $count;
1840    }
1841
1842    function blog_category_count($args) {
1843
1844        if ($sql = $this->include_exclude_blogs($args)) {
1845            $blog_filter = 'and category_blog_id ' . $sql;
1846        } elseif (isset($args['blog_id'])) {
1847            $blog_id = intval($args['blog_id']);
1848            $blog_filter = 'and category_blog_id = ' . $blog_id;
1849        }
1850        $count = $this->get_var("
1851            select count(*)
1852              from mt_category
1853             where 1 = 1
1854             $blog_filter
1855        ");
1856        return $count;
1857    }
1858
1859    function tags_entry_count($tag_id) {
1860        $count = $this->get_var("
1861          select count(*)
1862            from mt_objecttag, mt_entry
1863           where objecttag_tag_id = " . intval($tag_id) . "
1864             and entry_id = objecttag_object_id and objecttag_object_datasource='entry'
1865             and entry_status = 2
1866        ");
1867        return $count;
1868    }
1869
1870    function entry_comment_count($entry_id) {
1871        if (isset($this->_comment_count_cache[$entry_id])) {
1872            return $this->_comment_count_cache[$entry_id];
1873        }
1874        $entry = $this->fetch_entry($entry_id);
1875        $count = $entry['entry_comment_count'];
1876        $this->_comment_count_cache[$entry_id] = $count;
1877        return $count;
1878    }
1879
1880    function author_entry_count($args) {
1881        if ($sql = $this->include_exclude_blogs($args)) {
1882            $blog_filter = 'and entry_blog_id ' . $sql;
1883        } elseif (isset($args['blog_id'])) {
1884            $blog_id = intval($args['blog_id']);
1885            $blog_filter = 'and entry_blog_id = ' . $blog_id;
1886        }
1887        if (isset($args['author_id'])) {
1888            $author_id = intval($args['author_id']);
1889            $author_filter = " and entry_author_id = $author_id";
1890        }
1891        if (isset($args['class'])) {
1892            $class = $args['class'];
1893        }
1894        $count = $this->get_var("
1895          select count(*)
1896            from mt_entry
1897            where entry_status = 2
1898            and entry_class='$class'
1899            $blog_filter
1900            $author_filter
1901            ");
1902        return $count;
1903    }
1904
1905    function &fetch_placements($args) {
1906        $category_id_list = $args['category_id'];
1907        $id_list = '';
1908        foreach ($category_id_list as $cat_id) {
1909            $id_list .= ',' . $cat_id;
1910        }
1911        if (empty($id_list))
1912            return;
1913        $id_list = substr($id_list, 1);
1914        $sql = "
1915            select mt_placement.*
1916              from mt_placement, mt_entry
1917              where placement_category_id in ($id_list)
1918               and entry_id = placement_entry_id and entry_status = 2
1919        ";
1920        $results = $this->get_results($sql, ARRAY_A);
1921        return $results;
1922    }
1923
1924    function &fetch_objecttags($args) {
1925        $tag_id_list = $args['tag_id'];
1926        $id_list = '';
1927        foreach ($tag_id_list as $tag_id) {
1928            $id_list .= ',' . $tag_id;
1929        }
1930        if (empty($id_list))
1931            return;
1932        $id_list = substr($id_list, 1);
1933
1934        $blog_filter = $this->include_exclude_blogs($args);
1935        if ($blog_filter == '' and $args['blog_id'])
1936            $blog_filter = intval($args['blog_id']);
1937        if ($blog_filter != '') 
1938            $blog_filter = 'and objecttag_blog_id = ' . $blog_filter;
1939
1940        if (isset($args['datasource']) && strtolower($args['datasource']) == 'asset') {
1941            $datasource = $args['datasource'];
1942            $from_object = 'mt_asset';
1943            $object_filter = 'and asset_id = objecttag_object_id';
1944        } else {
1945            $datasource = 'entry';
1946            $from_object = 'mt_entry';
1947            $object_filter = 'and entry_id = objecttag_object_id and entry_status = 2';
1948        }
1949        $sql = "
1950            select mt_objecttag.*
1951              from mt_objecttag, $from_object
1952              where
1953                objecttag_object_datasource ='$datasource'
1954                and objecttag_tag_id in ($id_list)
1955                $blog_filter
1956                $object_filter
1957        ";
1958        $results = $this->get_results($sql, ARRAY_A);
1959        return $results;
1960    }
1961
1962    function &fetch_comments($args) {
1963        # load comments
1964        $entry_id = intval($args['entry_id']);
1965
1966        $sql = $this->include_exclude_blogs($args);
1967        if ($sql != '') {
1968            $blog_filter = 'and comment_blog_id ' . $sql;
1969            if (isset($args['blog_id']))
1970                $blog =& $this->fetch_blog($args['blog_id']);
1971        } elseif ($args['blog_id']) {
1972            $blog =& $this->fetch_blog($args['blog_id']);
1973            $blog_filter = ' and comment_blog_id = ' . $blog['blog_id'];
1974        }
1975
1976        # Adds a score or rate filter to the filters list.
1977        if (isset($args['namespace'])) {
1978            require_once("MTUtil.php");
1979            $arg_names = array('min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count' );
1980            foreach ($arg_names as $n) {
1981                if (isset($args[$n])) {
1982                    $comment_args = $args[$n];
1983                    $cexpr = create_rating_expr_function($comment_args, $n, $args['namespace'], 'comment');
1984                    if ($cexpr) {
1985                        $filters[] = $cexpr;
1986                    } else {
1987                        return null;
1988                    }
1989                }
1990            }
1991            if (isset($args['scored_by'])) {
1992                $voter = $this->fetch_author_by_name($args['scored_by']);
1993                if (!$voter) {
1994                    echo "Invalid scored by filter: ".$args['scored_by'];
1995                    return null;
1996                }
1997                $cexpr = create_rating_expr_function($voter['author_id'], 'scored_by', $args['namespace'], 'comment');
1998                if ($cexpr) {
1999                    $filters[] = $cexpr;
2000                } else {
2001                    return null;
2002                }
2003            }
2004        }
2005
2006        $order = 'desc';
2007        if (isset($args['sort_order'])) {
2008            if ($args['sort_order'] == 'ascend') {
2009                $order = 'asc';
2010            }
2011        } elseif (isset($blog) && isset($blog['blog_sort_order_comments'])) {
2012            if ($blog['blog_sort_order_comments'] == 'ascend') {
2013                $order = 'asc';
2014            }
2015        }
2016        if ($order == 'asc' && $args['lastn']) {
2017            $reorder = 1;
2018            $order = 'desc';
2019        }
2020
2021        if ($entry_id) {
2022            $entry_filter = " and comment_entry_id = $entry_id";
2023            $entry_join = "join mt_entry on entry_id = comment_entry_id";
2024        } else {
2025            $entry_join = "join mt_entry on entry_id = comment_entry_id and entry_status = 2";
2026        }
2027
2028        $join_score = "";
2029        $distinct = "";
2030        if ( isset($args['sort_by'])
2031          && (($args['sort_by'] == 'score') || ($args['sort_by'] == 'rate')) ) {
2032            $join_score = "join mt_objectscore on objectscore_object_id = comment_id and objectscore_namespace='".$args['namespace']."' and objectscore_object_ds='comment'";
2033            $distinct = " distinct";
2034        }
2035
2036        $limit = 0;
2037        $offset = 0;
2038        if (isset($args['lastn']))
2039            $limit = $args['lastn'];
2040        if (isset($args['limit']))
2041            $limit = $args['limit'];
2042        if (isset($args['offset']))
2043            $limit = $args['offset'];
2044        if (count($filters)) {
2045            $post_select_limit = $limit;
2046            $post_select_offset = $offset;
2047            $limit = 0; $offset = 0;
2048        }
2049
2050        $sql = "
2051            select $distinct
2052                   mt_comment.*,
2053                   mt_entry.*
2054              from mt_comment
2055                   $entry_join
2056                   $join_score
2057             where comment_visible = 1
2058                   $entry_filter
2059                   $blog_filter
2060             order by comment_created_on $order
2061                   <LIMIT>";
2062        $sql = $this->apply_limit_sql($sql, $limit, $offset);
2063        # Fetch resultset
2064        $result = $this->query_start($sql);
2065        if (!$result) return null;
2066
2067        $comments = array();
2068        while (true) {
2069            $e = $this->query_fetch(ARRAY_A);
2070            if ($offset && ($j++ < $offset)) continue;
2071            if (!isset($e)) break;
2072            if (count($filters)) {
2073                foreach ($filters as $f) {
2074                    if (!$f($e, $ctx)) continue 2;
2075                }
2076            }
2077            $comments[] = $e;
2078            if (($limit > 0) && (count($comments) >= $limit)) break;
2079        }
2080
2081        if (isset($args['sort_by']) && ('score' == $args['sort_by'])) {
2082            $comments_tmp = array();
2083            foreach ($comments as $c) {
2084                $comments_tmp[$c['comment_id']] = $c;
2085            }
2086            $scores = $this->fetch_sum_scores($args['namespace'], 'comment', $order,
2087                $blog_filter . "\n" .
2088                $entry_filter . "\n"
2089            );
2090            $comments_sorted = array();
2091            foreach($scores as $score) {
2092                if (array_key_exists($score['objectscore_object_id'], $comments_tmp)) {
2093                    array_push($comments_sorted, $comments_tmp[$score['objectscore_object_id']]);
2094                    unset($comments_tmp[$score['objectscore_object_id']]);
2095                }
2096            }
2097            foreach ($comments_tmp as $et) {
2098                array_push($comments_sorted, $et);
2099            }
2100            $comments = $comments_sorted;
2101        } elseif (isset($args['sort_by']) && ('rate' == $args['sort_by'])) {
2102            $comments_tmp = array();
2103            foreach ($comments as $c) {
2104                $comments_tmp[$c['comment_id']] = $c;
2105            }
2106            $scores = $this->fetch_avg_scores($args['namespace'], 'comment', $order,
2107                $blog_filter . "\n" .
2108                $entry_filter . "\n"
2109            );
2110            $comments_sorted = array();
2111            foreach($scores as $score) {
2112                if (array_key_exists($score['objectscore_object_id'], $comments_tmp)) {
2113                    array_push($comments_sorted, $comments_tmp[$score['objectscore_object_id']]);
2114                    unset($comments_tmp[$score['objectscore_object_id']]);
2115                }
2116            }
2117            foreach ($comments_tmp as $et) {
2118                array_push($comments_sorted, $et);
2119            }
2120            $comments = $comments_sorted;
2121        }
2122
2123        if (!is_array($comments))
2124            return array();
2125
2126        if ($reorder) {  // lastn and ascending sort
2127            $asc_created_on = create_function('$a,$b', 'return strcmp($a["comment_created_on"], $b["comment_created_on"]);');
2128            usort($comments, $asc_created_on);
2129        }
2130
2131        return $comments;
2132    }
2133
2134    function &fetch_comment_parent($args) {
2135        if (!$args['parent_id']) {
2136            return array();
2137        }
2138        $parent_id = intval($args['parent_id']);
2139
2140        $sql = $this->include_exclude_blogs($args);
2141        if ($sql != '') {
2142            $blog_filter = 'and comment_blog_id ' . $sql;
2143            if (isset($args['blog_id']))
2144                $blog =& $this->fetch_blog($args['blog_id']);
2145        } elseif ($args['blog_id']) {
2146            $blog =& $this->fetch_blog($args['blog_id']);
2147            $blog_filter = ' and comment_blog_id = ' . $blog['blog_id'];
2148        }
2149
2150        $sql = "
2151            select *
2152              from mt_comment
2153             where 1 = 1
2154                   $blog_filter
2155               and comment_id = $parent_id
2156               and comment_visible = 1
2157        ";
2158        $comment = $this->get_results($sql, ARRAY_A);
2159
2160        return $comment;
2161    }
2162
2163    function &fetch_comment_replies($args) {
2164        if (!$args['comment_id']) {
2165            return array();
2166        }
2167        $comment_id = intval($args['comment_id']);
2168
2169        $sql = $this->include_exclude_blogs($args);
2170        if ($sql != '') {
2171            $blog_filter = 'and comment_blog_id ' . $sql;
2172            if (isset($args['blog_id']))
2173                $blog =& $this->fetch_blog($args['blog_id']);
2174        } elseif ($args['blog_id']) {
2175            $blog =& $this->fetch_blog($args['blog_id']);
2176            $blog_filter = ' and comment_blog_id = ' . $blog['blog_id'];
2177        }
2178
2179        $order = 'asc';
2180        if (isset($args['sort_order'])) {
2181            if ($args['sort_order'] == 'descend') {
2182                $order = 'desc';
2183            }
2184        } elseif (isset($blog) && isset($blog['blog_sort_order_comments'])) {
2185            if ($blog['blog_sort_order_comments'] == 'ascend') {
2186                $order = 'asc';
2187            }
2188        }
2189        if ($order == 'asc' && $args['lastn']) {
2190            $reorder = 1;
2191            $order = 'desc';
2192        }
2193        $sql = "
2194            select *
2195              from mt_comment
2196             where 1 = 1
2197                   $blog_filter
2198               and comment_parent_id = $comment_id
2199               and comment_visible = 1
2200             order by comment_created_on $order
2201                   <LIMIT>";
2202        $sql = $this->apply_limit_sql($sql, $args['lastn'], $args['offset']);
2203        $comments = $this->get_results($sql, ARRAY_A);
2204        if (!is_array($comments))