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

Revision 2129, 118.4 kB (checked in by fumiakiy, 19 months ago)

Rewrote the function signature and the call to it in PHP4-friendly way. BugId:79535

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