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

Revision 2103, 115.7 kB (checked in by fumiakiy, 19 months ago)

Implemented PHP version of pager related tags. Dynamically published archives can now be pagination-enabled by adding these tags and specify "auto" to limit and offset.

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