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

Revision 2503, 121.5 kB (checked in by takayama, 18 months ago)

Fixed BugId:80007
* Related fix of case 79997

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