root/branches/release-41/php/lib/mtdb_base.php @ 2708

Revision 2708, 123.2 kB (checked in by fumiakiy, 17 months ago)

Do not bother if ID is empty string. BugId:80516

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