root/branches/release-38/php/lib/mtdb_base.php @ 2326

Revision 2326, 120.7 kB (checked in by takayama, 19 months ago)

Fixed BugId:78122
* Not join to mt_permission
* Added function that fetches mt_permission

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