root/branches/slapshot/php/lib/mtdb_base.php @ 3978

Revision 3978, 125.9 kB (checked in by dphillips, 5 months ago)

Fix for r3776, which broke dynamic publishing for templates that have a NULL template_identifier field. BugID: 101024

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