root/branches/release-39/php/lib/mtdb_base.php @ 2521

Revision 2521, 122.0 kB (checked in by fumiakiy, 18 months ago)

Load blog in context if the request did not specify it. BugId:80045

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