root/branches/release-32/php/lib/mtdb_base.php @ 1583

Revision 1583, 111.0 kB (checked in by auno, 20 months ago)

More fixed for dynamic and renamed tbping_count column name to ping_count. BugzID:68482

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