root/branches/release-35/php/lib/mtdb_base.php @ 1985

Revision 1985, 114.9 kB (checked in by takayama, 20 months ago)

Fixed BugId:79395
* Keep original ID values

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