root/branches/release-36/php/lib/mtdb_base.php @ 2091

Revision 2091, 115.0 kB (checked in by fumiakiy, 19 months ago)

PHP tags for Widget Manager. BugId:68750

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