4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2004 The Nucleus Group
\r
7 * This program is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation; either version 2
\r
10 * of the License, or (at your option) any later version.
\r
11 * (see nucleus/documentation/index.html#license for more info)
\r
13 * A class representing a blog and containing functions to get that blog shown
\r
21 // ID of currently selected category
\r
24 // After creating an object of the blog class, contains true if the BLOG object is
\r
25 // valid (the blog exists)
\r
28 // associative array, containing all blogsettings (use the get/set functions instead)
\r
32 * Creates a new BLOG object for the given blog
\r
36 function BLOG($id) {
\r
37 $this->blogid = intval($id);
\r
38 $this->readSettings();
\r
40 // try to set catid
\r
41 // (the parse functions in SKIN.php will override this, so it's mainly useless)
\r
43 $this->setSelectedCategory($catid);
\r
47 * Shows the given amount of items for this blog
\r
50 * String representing the template _NAME_ (!)
\r
51 * @param $amountEntries
\r
52 * amount of entries to show
\r
54 * offset from where items should be shown (e.g. 5 = start at fifth item)
\r
56 * amount of items shown
\r
58 function readLog($template, $amountEntries, $offset = 0, $startpos = 0) {
\r
59 return $this->readLogAmount($template,$amountEntries,'','',1,1,$offset, $startpos);
\r
63 * Shows an archive for a given month
\r
70 * String representing the template name to be used
\r
72 function showArchive($templatename, $year, $month, $day=0) {
\r
74 // create extra where clause for select query
\r
76 $timestamp_start = mktime(0,0,0,$month,1,$year);
\r
77 $timestamp_end = mktime(0,0,0,$month+1,1,$year); // also works when $month==12
\r
79 $timestamp_start = mktime(0,0,0,$month,$day,$year);
\r
80 $timestamp_end = mktime(0,0,0,$month,$day+1,$year);
\r
82 $extra_query = ' and i.itime>=' . mysqldate($timestamp_start)
\r
83 . ' and i.itime<' . mysqldate($timestamp_end);
\r
86 $this->readLogAmount($templatename,0,$extra_query,'',1,1);
\r
91 // sets/gets current category (only when category exists)
\r
92 function setSelectedCategory($catid) {
\r
93 if ($this->isValidCategory($catid) || (intval($catid) == 0))
\r
94 $this->selectedcatid = intval($catid);
\r
97 function setSelectedCategoryByName($catname) {
\r
98 $this->setSelectedCategory($this->getCategoryIdFromName($catname));
\r
101 function getSelectedCategory() {
\r
102 return $this->selectedcatid;
\r
106 * Shows the given amount of items for this blog
\r
109 * String representing the template _NAME_ (!)
\r
110 * @param $amountEntries
\r
111 * amount of entries to show (0 = no limit)
\r
112 * @param $extraQuery
\r
113 * extra conditions to be added to the query
\r
114 * @param $highlight
\r
115 * contains a query that should be highlighted
\r
117 * 1=show comments 0=don't show comments
\r
118 * @param $dateheads
\r
119 * 1=show dateheads 0=don't show dateheads
\r
123 * amount of items shown
\r
125 function readLogAmount($template, $amountEntries, $extraQuery, $highlight, $comments, $dateheads, $offset = 0, $startpos = 0) {
\r
127 $query = $this->getSqlBlog($extraQuery);
\r
129 if ($amountEntries > 0) {
\r
130 // $offset zou moeten worden:
\r
131 // (($startpos / $amountentries) + 1) * $offset ... later testen ...
\r
132 $query .= ' LIMIT ' . intval($startpos + $offset).',' . intval($amountEntries);
\r
134 return $this->showUsingQuery($template, $query, $highlight, $comments, $dateheads);
\r
137 function showUsingQuery($templateName, $query, $highlight = '', $comments = 0, $dateheads = 1) {
\r
138 global $CONF, $manager;
\r
140 $lastVisit = cookieVar('lastVisit');
\r
141 if ($lastVisit != 0)
\r
142 $lastVisit = $this->getCorrectTime($lastVisit);
\r
144 // set templatename as global variable (so plugins can access it)
\r
145 global $currentTemplateName;
\r
146 $currentTemplateName = $templateName;
\r
148 $template = TEMPLATE::read($templateName);
\r
150 // create parser object & action handler
\r
151 $actions = new ITEMACTIONS($this);
\r
152 $parser = new PARSER($actions->getDefinedActions(),$actions);
\r
153 $actions->setTemplate($template);
\r
154 $actions->setHighlight($highlight);
\r
155 $actions->setLastVisit($lastVisit);
\r
156 $actions->setParser($parser);
\r
157 $actions->setShowComments($comments);
\r
160 $items = sql_query($query);
\r
162 // loop over all items
\r
163 while ($item = mysql_fetch_object($items)) {
\r
165 $item->timestamp = strtotime($item->itime); // string timestamp -> unix timestamp
\r
167 // action handler needs to know the item we're handling
\r
168 $actions->setCurrentItem($item);
\r
170 // add date header if needed
\r
172 $new_date = date('dFY',$item->timestamp);
\r
173 if ($new_date != $old_date) {
\r
174 // unless this is the first time, write date footer
\r
175 $timestamp = $item->timestamp;
\r
176 if ($old_date != 0) {
\r
177 $oldTS = strtotime($old_date);
\r
178 $manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));
\r
179 $parser->parse(strftime($template['DATE_FOOTER'], $oldTS));
\r
180 $manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));
\r
182 $manager->notify('PreDateHead',array('blog' => &$this, 'timestamp' => $timestamp));
\r
183 // note, to use templatvars in the dateheader, the %-characters need to be doubled in
\r
184 // order to be preserved by strftime
\r
185 $parser->parse(strftime($template['DATE_HEADER'],$timestamp));
\r
186 $manager->notify('PostDateHead',array('blog' => &$this, 'timestamp' => $timestamp));
\r
188 $old_date = $new_date;
\r
192 $parser->parse($template['ITEM_HEADER']);
\r
193 $manager->notify('PreItem', array('blog' => &$this, 'item' => &$item));
\r
194 $parser->parse($template['ITEM']);
\r
195 $manager->notify('PostItem', array('blog' => &$this, 'item' => &$item));
\r
196 $parser->parse($template['ITEM_FOOTER']);
\r
200 $numrows = mysql_num_rows($items);
\r
202 // add another date footer if there was at least one item
\r
203 if (($numrows > 0) && $dateheads) {
\r
204 $manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));
\r
205 $parser->parse($template['DATE_FOOTER']);
\r
206 $manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));
\r
209 mysql_free_result($items); // free memory
\r
215 function showOneitem($itemid, $template, $highlight) {
\r
216 $extraQuery = ' and inumber=' . intval($itemid);
\r
218 return $this->readLogAmount($template, 1, $extraQuery, $highlight, 0, 0);
\r
223 * Adds an item to this blog
\r
225 function additem($catid, $title, $body, $more, $blogid, $authorid, $timestamp, $closed, $draft) {
\r
228 $blogid = intval($blogid);
\r
229 $authorid = intval($authorid);
\r
233 $catid = intval($catid);
\r
235 // convert newlines to <br />
\r
236 if ($this->convertBreaks()) {
\r
237 $body = addBreaks($body);
\r
238 $more = addBreaks($more);
\r
241 if ($closed != '1') $closed = '0';
\r
242 if ($draft != '0') $draft = '1';
\r
244 if (!$this->isValidCategory($catid))
\r
245 $catid = $this->getDefaultCategory();
\r
247 if ($timestamp > $this->getCorrectTime())
\r
250 $timestamp = date('Y-m-d H:i:s',$timestamp);
\r
252 $manager->notify('PreAddItem',array('title' => &$title, 'body' => &$body, 'more' => &$more, 'blog' => &$this, 'authorid' => &$authorid, 'timestamp' => &$timestamp, 'closed' => &$closed, 'draft' => &$draft, 'catid' => &$catid));
\r
254 $title = addslashes($title);
\r
255 $body = addslashes($body);
\r
256 $more = addslashes($more);
\r
258 $query = 'INSERT INTO '.sql_table('item').' (ITITLE, IBODY, IMORE, IBLOG, IAUTHOR, ITIME, ICLOSED, IDRAFT, ICAT) '
\r
259 . "VALUES ('$title', '$body', '$more', $blogid, $authorid, '$timestamp', $closed, $draft, $catid)";
\r
260 sql_query($query);
\r
261 $itemid = mysql_insert_id();
\r
263 $manager->notify('PostAddItem',array('itemid' => $itemid));
\r
266 $this->updateUpdateFile();
\r
268 // send notification mail
\r
269 if (!$draft && !$isFuture && $this->getNotifyAddress() && $this->notifyOnNewItem())
\r
270 $this->sendNewItemNotification($itemid, stripslashes($title), stripslashes($body));
\r
275 function sendNewItemNotification($itemid, $title, $body) {
\r
276 global $CONF, $member;
\r
278 // create text version of html post
\r
279 $ascii = toAscii($body);
\r
281 $mailto_msg = _NOTIFY_NI_MSG . " \n";
\r
282 $mailto_msg .= $CONF['IndexURL'] . 'index.php?itemid=' . $itemid . "\n\n";
\r
283 $mailto_msg .= _NOTIFY_TITLE . ' ' . strip_tags($title) . "\n";
\r
284 $mailto_msg .= _NOTIFY_CONTENTS . "\n " . $ascii . "\n";
\r
285 $mailto_msg .= getMailFooter();
\r
287 $mailto_title = $this->getName() . ': ' . _NOTIFY_NI_TITLE;
\r
289 $frommail = $member->getNotifyFromMailAddress();
\r
291 $notify = new NOTIFICATION($this->getNotifyAddress());
\r
292 $notify->notify($mailto_title, $mailto_msg , $frommail);
\r
300 * Creates a new category for this blog
\r
303 * name of the new category. When empty, a name is generated automatically
\r
304 * (starting with newcat)
\r
305 * @param $catDescription
\r
306 * description of the new category. Defaults to 'New Category'
\r
309 * the new category-id in case of success.
\r
312 function createNewCategory($catName = '', $catDescription = 'New category') {
\r
313 global $member, $manager;
\r
315 if ($member->blogAdminRights($this->getID())) {
\r
317 if ($catName == '')
\r
319 $catName = 'newcat';
\r
321 while(mysql_num_rows(sql_query('SELECT * FROM '.sql_table('category')." WHERE cname='".$catName.$i."' and cblog=".$this->getID())) > 0)
\r
323 $catName = $catName . $i;
\r
330 'name' => &$catName,
\r
331 'description' => $catDescription
\r
335 $query = 'INSERT INTO '.sql_table('category').' (cblog, cname, cdesc) VALUES (' . $this->getID() . ", '" . addslashes($catName) . "', '" . addslashes($catDescription) . "')";
\r
337 $catid = mysql_insert_id();
\r
343 'name' => $catName,
\r
344 'description' => $catDescription,
\r
358 * Searches all months of this blog for the given query
\r
363 * template to be used (__NAME__ of the template)
\r
364 * @param $amountMonths
\r
365 * max amount of months to be search (0 = all)
\r
366 * @param $maxresults
\r
367 * max number of results to show
\r
371 * amount of hits found
\r
373 function search($query, $template, $amountMonths, $maxresults, $startpos) {
\r
377 $sqlquery = $this->getSqlSearch($query, $amountMonths, $highlight);
\r
379 if ($sqlquery == '')
\r
381 // no query -> show everything
\r
383 $amountfound = $this->readLogAmount($template, $maxresults, $extraQuery, $query, 1, 1);
\r
386 // add LIMIT to query (to split search results into pages)
\r
387 if (intval($maxresults > 0))
\r
388 $sqlquery .= ' LIMIT ' . intval($startpos).',' . intval($maxresults);
\r
391 $amountfound = $this->showUsingQuery($template, $sqlquery, $highlight, 1, 1);
\r
393 // when no results were found, show a message
\r
394 if ($amountfound == 0)
\r
396 $template = TEMPLATE::read($template);
\r
398 'query' => htmlspecialchars($query),
\r
399 'blogid' => $this->getID()
\r
401 echo TEMPLATE::fill($template['SEARCH_NOTHINGFOUND'],$vars);
\r
405 return $amountfound;
\r
409 * Returns an SQL query to use for a search query
\r
413 * @param $amountMonths
\r
414 * amount of months to search back. Default = 0 = unlimited
\r
416 * either empty, or 'count'. In this case, the query will be a SELECT COUNT(*) query
\r
417 * @returns $highlight
\r
418 * words to highlight (out parameter)
\r
420 * either a full SQL query, or an empty string (if querystring empty)
\r
422 * No LIMIT clause is added. (caller should add this if multiple pages are requested)
\r
424 function getSqlSearch($query, $amountMonths = 0, &$highlight, $mode = '')
\r
426 $searchclass = new SEARCH($query);
\r
428 $highlight = $searchclass->inclusive;
\r
430 // if querystring is empty, return empty string
\r
431 if ($searchclass->inclusive == '')
\r
435 $where = $searchclass->boolean_sql_where('ititle,ibody,imore');
\r
436 $select = $searchclass->boolean_sql_select('ititle,ibody,imore');
\r
438 // get list of blogs to search
\r
439 $blogs = $searchclass->blogs; // array containing blogs that always need to be included
\r
440 $blogs[] = $this->getID(); // also search current blog (duh)
\r
441 $blogs = array_unique($blogs); // remove duplicates
\r
443 if (count($blogs) > 0)
\r
444 $selectblogs = ' and i.iblog in (' . implode(',', $blogs) . ')';
\r
448 $query = 'SELECT i.inumber as itemid, i.ititle as title, i.ibody as body, m.mname as author, m.mrealname as authorname, i.itime, i.imore as more, m.mnumber as authorid, m.memail as authormail, m.murl as authorurl, c.cname as category, i.icat as catid, i.iclosed as closed';
\r
450 $query .= ', '.$select. ' as score ';
\r
452 $query = 'SELECT COUNT(*) as result ';
\r
455 $query .= ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, '.sql_table('category').' as c'
\r
456 . ' WHERE i.iauthor=m.mnumber'
\r
457 . ' and i.icat=c.catid'
\r
458 . ' and i.idraft=0' // exclude drafts
\r
460 // don't show future items
\r
461 . ' and i.itime<=' . mysqldate($this->getCorrectTime())
\r
464 // take into account amount of months to search
\r
465 if ($amountMonths > 0)
\r
467 $localtime = getdate($this->getCorrectTime());
\r
468 $timestamp_start = mktime(0,0,0,$localtime['mon'] - $amountMonths,1,$localtime['year']);
\r
469 $query .= ' and i.itime>' . mysqldate($timestamp_start);
\r
475 $query .= ' ORDER BY score DESC';
\r
477 $query .= ' ORDER BY i.itime DESC ';
\r
484 * Returns the SQL query that's normally used to display the blog items on the index type skins
\r
487 * either empty, or 'count'. In this case, the query will be a SELECT COUNT(*) query
\r
489 * either a full SQL query, or an empty string
\r
491 * No LIMIT clause is added. (caller should add this if multiple pages are requested)
\r
493 function getSqlBlog($extraQuery, $mode = '')
\r
496 $query = 'SELECT i.inumber as itemid, i.ititle as title, i.ibody as body, m.mname as author, m.mrealname as authorname, i.itime, i.imore as more, m.mnumber as authorid, m.memail as authormail, m.murl as authorurl, c.cname as category, i.icat as catid, i.iclosed as closed';
\r
498 $query = 'SELECT COUNT(*) as result ';
\r
500 $query .= ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, '.sql_table('category').' as c'
\r
501 . ' WHERE i.iblog='.$this->blogid
\r
502 . ' and i.iauthor=m.mnumber'
\r
503 . ' and i.icat=c.catid'
\r
504 . ' and i.idraft=0' // exclude drafts
\r
505 // don't show future items
\r
506 . ' and i.itime<=' . mysqldate($this->getCorrectTime());
\r
508 if ($this->getSelectedCategory())
\r
509 $query .= ' and i.icat=' . $this->getSelectedCategory() . ' ';
\r
512 $query .= $extraQuery;
\r
515 $query .= ' ORDER BY i.itime DESC';
\r
521 * Shows the archivelist using the given template
\r
523 function showArchiveList($template, $mode = 'month', $limit = 0) {
\r
524 global $CONF, $catid;
\r
527 $linkparams = array('catid' => $catid);
\r
529 $template = TEMPLATE::read($template);
\r
530 $data['blogid'] = $this->getID();
\r
532 echo TEMPLATE::fill($template['ARCHIVELIST_HEADER'],$data);
\r
534 $query = 'SELECT itime, SUBSTRING(itime,1,4) AS Year, SUBSTRING(itime,6,2) AS Month, SUBSTRING(itime,9,2) as Day FROM '.sql_table('item')
\r
535 . ' WHERE iblog=' . $this->getID()
\r
536 . ' and itime <=' . mysqldate($this->getCorrectTime()) // don't show future items!
\r
537 . ' and idraft=0'; // don't show draft items
\r
540 $query .= ' and icat=' . intval($catid);
\r
542 $query .= ' GROUP BY Year, Month';
\r
543 if ($mode == 'day')
\r
547 $query .= ' ORDER BY itime DESC';
\r
550 $query .= ' LIMIT ' . intval($limit);
\r
552 $res = sql_query($query);
\r
554 while ($current = mysql_fetch_object($res)) {
\r
555 $current->itime = strtotime($current->itime); // string time -> unix timestamp
\r
557 if ($mode == 'day') {
\r
558 $archivedate = date('Y-m-d',$current->itime);
\r
559 $archive['day'] = date('d',$current->itime);
\r
561 $archivedate = date('Y-m',$current->itime);
\r
563 $data['month'] = date('m',$current->itime);
\r
564 $data['year'] = date('Y',$current->itime);
\r
565 $data['archivelink'] = createArchiveLink($this->getID(),$archivedate,$linkparams);
\r
567 $temp = TEMPLATE::fill($template['ARCHIVELIST_LISTITEM'],$data);
\r
568 echo strftime($temp,$current->itime);
\r
572 mysql_free_result($res);
\r
574 echo TEMPLATE::fill($template['ARCHIVELIST_FOOTER'],$data);
\r
579 * Shows the list of categories using a given template
\r
581 function showCategoryList($template) {
\r
584 // determine arguments next to catids
\r
585 // I guess this can be done in a better way, but it works
\r
586 global $archive, $archivelist;
\r
588 $linkparams = array();
\r
590 $blogurl = createArchiveLink($this->getID(), $archive, '');
\r
591 $linkparams['blogid'] = $this->getID();
\r
592 $linkparams['archive'] = $archive;
\r
593 } else if ($archivelist) {
\r
594 $blogurl = createArchiveListLink($this->getID(), '');
\r
595 $linkparams['archivelist'] = $archivelist;
\r
597 $blogurl = createBlogidLink($this->getID(), '');
\r
598 $linkparams['blogid'] = $this->getID();
\r
601 //$blogurl = $this->getURL() . $qargs;
\r
602 $blogurl = createBlogLink($this->getURL(), $linkparams);
\r
604 $template = TEMPLATE::read($template);
\r
606 echo TEMPLATE::fill($template['CATLIST_HEADER'],
\r
608 'blogid' => $this->getID(),
\r
609 'blogurl' => $blogurl,
\r
610 'self' => $CONF['Self']
\r
613 $query = 'SELECT catid, cdesc as catdesc, cname as catname FROM '.sql_table('category').' WHERE cblog=' . $this->getID() . ' ORDER BY cname ASC';
\r
614 $res = sql_query($query);
\r
617 while ($data = mysql_fetch_assoc($res)) {
\r
618 $data['blogid'] = $this->getID();
\r
619 $data['blogurl'] = $blogurl;
\r
620 $data['catlink'] = createCategoryLink($data['catid'], $linkparams);
\r
621 $data['self'] = $CONF['Self'];
\r
623 $temp = TEMPLATE::fill($template['CATLIST_LISTITEM'],$data);
\r
624 echo strftime($temp,$current->itime);
\r
628 mysql_free_result($res);
\r
630 echo TEMPLATE::fill($template['CATLIST_FOOTER'],
\r
632 'blogid' => $this->getID(),
\r
633 'blogurl' => $blogurl,
\r
634 'self' => $CONF['Self']
\r
639 * Blogsettings functions
\r
642 function readSettings() {
\r
643 $query = 'SELECT *'
\r
644 . ' FROM '.sql_table('blog')
\r
645 . ' WHERE bnumber=' . $this->blogid;
\r
646 $res = sql_query($query);
\r
648 $this->isValid = (mysql_num_rows($res) > 0);
\r
649 if (!$this->isValid)
\r
652 $this->settings = mysql_fetch_assoc($res);
\r
655 function writeSettings() {
\r
656 $query = 'UPDATE '.sql_table('blog')
\r
657 . " SET bname='" . addslashes($this->getName()) . "',"
\r
658 . " bshortname='". addslashes($this->getShortName()) . "',"
\r
659 . " bcomments=". intval($this->commentsEnabled()) . ","
\r
660 . " bmaxcomments=" . intval($this->getMaxComments()) . ","
\r
661 . " btimeoffset=" . floatval($this->getTimeOffset()) . ","
\r
662 . " bpublic=" . intval($this->isPublic()) . ","
\r
663 . " bsendping=" . intval($this->pingUserland()) . ","
\r
664 . " bconvertbreaks=" . intval($this->convertBreaks()) . ","
\r
665 . " ballowpast=" . intval($this->allowPastPosting()) . ","
\r
666 . " bnotify='" . addslashes($this->getNotifyAddress()) . "',"
\r
667 . " bnotifytype=" . intval($this->getNotifyType()) . ","
\r
668 . " burl='" . addslashes($this->getURL()) . "',"
\r
669 . " bupdate='" . addslashes($this->getUpdateFile()) . "',"
\r
670 . " bdesc='" . addslashes($this->getDescription()) . "',"
\r
671 . " bdefcat=" . intval($this->getDefaultCategory()) . ","
\r
672 . " bdefskin=" . intval($this->getDefaultSkin()) . ","
\r
673 . " bincludesearch=" . intval($this->getSearchable())
\r
674 . " WHERE bnumber=" . intval($this->getID());
\r
681 // update update file if requested
\r
682 function updateUpdatefile() {
\r
683 if ($this->getUpdateFile()) {
\r
684 $f_update = fopen($this->getUpdateFile(),'w');
\r
685 fputs($f_update,$this->getCorrectTime());
\r
692 * Sends a XML-RPC ping message to Userland, so the weblog can
\r
693 * show up in the weblogs.com updates-list
\r
695 function sendUserlandPing() {
\r
696 global $php_errormsg;
\r
698 if ($this->pingUserland()) {
\r
699 // testmessage for adding an item
\r
700 $message = new xmlrpcmsg('weblogUpdates.ping',array(
\r
701 new xmlrpcval($this->getName(),'string'),
\r
702 new xmlrpcval($this->getURL(),'string')
\r
705 $c = new xmlrpc_client('/RPC2', 'rpc.weblogs.com', 80);
\r
707 // $c->setDebug(1);
\r
709 $r = $c->send($message,15); // 15 seconds timeout...
\r
711 if (($r == 0) && ($r->errno || $r->errstring)) {
\r
712 return 'Error ' . $r->errno . ' : ' . $r->errstring;
\r
713 } elseif (($r == 0) && ($php_errormsg)) {
\r
714 return 'PHP Error: ' . $php_errormsg;
\r
715 } elseif ($r == 0) {
\r
716 return 'Error while trying to send ping. Sorry about that.';
\r
717 } elseif ($r->faultCode() != 0) {
\r
718 return 'Error: ' . $r->faultString();
\r
720 $r = $r->value(); // get response struct
\r
722 $flerror = $r->structmem('flerror');
\r
723 $flerror = $flerror->scalarval();
\r
726 $message = $r->structmem('message');
\r
727 $message = $message->scalarval();
\r
730 return 'Error (flerror=1): ' . $message;
\r
732 return 'Success: ' . $message;
\r
737 function isValidCategory($catid) {
\r
738 $query = 'SELECT * FROM '.sql_table('category').' WHERE cblog=' . $this->getID() . ' and catid=' . intval($catid);
\r
739 return (mysql_num_rows(mysql_query($query)) != 0);
\r
742 function getCategoryName($catid) {
\r
743 $res = mysql_query('SELECT cname FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
\r
744 $o = mysql_fetch_object($res);
\r
748 function getCategoryDesc($catid) {
\r
749 $res = mysql_query('SELECT cdesc FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
\r
750 $o = mysql_fetch_object($res);
\r
754 function getCategoryIdFromName($name) {
\r
755 $res = mysql_query('SELECT catid FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and cname="' . addslashes($name) . '"');
\r
756 if (mysql_num_rows($res) > 0) {
\r
757 $o = mysql_fetch_object($res);
\r
760 return $this->getDefaultCategory();
\r
764 function pingUserland() {
\r
765 return $this->getSetting('bsendping');
\r
768 function setPingUserland($val) {
\r
769 $this->setSetting('bsendping',$val);
\r
772 function convertBreaks() {
\r
773 return $this->getSetting('bconvertbreaks');
\r
776 function insertJavaScriptInfo($authorid = '') {
\r
777 global $member, $CONF;
\r
779 if ($authorid == '')
\r
780 $authorid = $member->getID();
\r
783 <script type="text/javascript">
\r
784 setConvertBreaks(<?php echo $this->convertBreaks() ? 'true' : 'false' ?>);
\r
785 setMediaUrl("<?php echo $CONF['MediaURL']?>");
\r
786 setAuthorId(<?php echo $authorid?>);
\r
789 function setConvertBreaks($val) {
\r
790 $this->setSetting('bconvertbreaks',$val);
\r
792 function setAllowPastPosting($val) {
\r
793 $this->setSetting('ballowpast',$val);
\r
795 function allowPastPosting() {
\r
796 return $this->getSetting('ballowpast');
\r
799 function getCorrectTime($t=0) {
\r
800 if ($t == 0) $t = time();
\r
801 return ($t + 3600 * $this->getTimeOffset());
\r
804 function getName() {
\r
805 return $this->getSetting('bname');
\r
808 function getShortName() {
\r
809 return $this->getSetting('bshortname');
\r
812 function getMaxComments() {
\r
813 return $this->getSetting('bmaxcomments');
\r
816 function getNotifyAddress() {
\r
817 return $this->getSetting('bnotify');
\r
820 function getNotifyType() {
\r
821 return $this->getSetting('bnotifytype');
\r
824 function notifyOnComment() {
\r
825 $n = $this->getNotifyType();
\r
826 return (($n != 0) && (($n % 3) == 0));
\r
829 function notifyOnVote() {
\r
830 $n = $this->getNotifyType();
\r
831 return (($n != 0) && (($n % 5) == 0));
\r
834 function notifyOnNewItem() {
\r
835 $n = $this->getNotifyType();
\r
836 return (($n != 0) && (($n % 7) == 0));
\r
839 function setNotifyType($val) {
\r
840 $this->setSetting('bnotifytype',$val);
\r
844 function getTimeOffset() {
\r
845 return $this->getSetting('btimeoffset');
\r
848 function commentsEnabled() {
\r
849 return $this->getSetting('bcomments');
\r
852 function getURL() {
\r
853 return $this->getSetting('burl');
\r
856 function getDefaultSkin() {
\r
857 return $this->getSetting('bdefskin');
\r
860 function getUpdateFile() {
\r
861 return $this->getSetting('bupdate');
\r
864 function getDescription() {
\r
865 return $this->getSetting('bdesc');
\r
868 function isPublic() {
\r
869 return $this->getSetting('bpublic');
\r
872 function getSearchable() {
\r
873 return $this->getSetting('bincludesearch');
\r
876 function getDefaultCategory() {
\r
877 return $this->getSetting('bdefcat');
\r
880 function setPublic($val) {
\r
881 $this->setSetting('bpublic',$val);
\r
884 function setSearchable($val) {
\r
885 $this->setSetting('bincludesearch',$val);
\r
888 function setDescription($val) {
\r
889 $this->setSetting('bdesc',$val);
\r
892 function setUpdateFile($val) {
\r
893 $this->setSetting('bupdate',$val);
\r
896 function setDefaultSkin($val) {
\r
897 $this->setSetting('bdefskin',$val);
\r
900 function setURL($val) {
\r
901 $this->setSetting('burl',$val);
\r
904 function setName($val) {
\r
905 $this->setSetting('bname',$val);
\r
908 function setShortName($val) {
\r
909 $this->setSetting('bshortname',$val);
\r
912 function setCommentsEnabled($val) {
\r
913 $this->setSetting('bcomments',$val);
\r
916 function setMaxComments($val) {
\r
917 $this->setSetting('bmaxcomments',$val);
\r
920 function setNotifyAddress($val) {
\r
921 $this->setSetting('bnotify',$val);
\r
924 function setTimeOffset($val) {
\r
925 // check validity of value
\r
926 // 1. replace , by . (common mistake)
\r
927 $val = str_replace(',','.',$val);
\r
928 // 2. cast to float or int
\r
929 if (is_numeric($val) && strstr($val,'.5')) {
\r
930 $val = (float) $val;
\r
932 $val = intval($val);
\r
935 $this->setSetting('btimeoffset',$val);
\r
938 function setDefaultCategory($val) {
\r
939 $this->setSetting('bdefcat',$val);
\r
942 function getSetting($key) {
\r
943 return $this->settings[$key];
\r
946 function setSetting($key,$value) {
\r
947 $this->settings[$key] = $value;
\r
951 // tries to add a member to the team. Returns false if the member was already on
\r
953 function addTeamMember($memberid, $admin) {
\r
956 $memberid = intval($memberid);
\r
957 $admin = intval($admin);
\r
959 // check if member is already a member
\r
960 $tmem = MEMBER::createFromID($memberid);
\r
962 if ($tmem->isTeamMember($this->getID()))
\r
966 'PreAddTeamMember',
\r
969 'member' => &$tmem,
\r
975 $query = 'INSERT INTO '.sql_table('team').' (TMEMBER, TBLOG, TADMIN) '
\r
976 . 'VALUES (' . $memberid .', '.$this->getID().', "'.$admin.'")';
\r
980 'PostAddTeamMember',
\r
983 'member' => &$tmem,
\r
989 ACTIONLOG::add(INFO, 'Added ' . $tmem->getDisplayName() . ' (ID=' .
\r
990 $memberid .') to the team of blog "' . $this->getName() . '"');
\r
996 return $this->blogid;
\r
999 // returns true if there is a blog with the given shortname (static)
\r
1000 function exists($name) {
\r
1001 $r = sql_query('select * FROM '.sql_table('blog').' WHERE bshortname="'.addslashes($name).'"');
\r
1002 return (mysql_num_rows($r) != 0);
\r
1005 // returns true if there is a blog with the given ID (static)
\r
1006 function existsID($id) {
\r
1007 $r = sql_query('select * FROM '.sql_table('blog').' WHERE bnumber='.intval($id));
\r
1008 return (mysql_num_rows($r) != 0);
\r
1015 * This class is used when parsing item templates
\r
1017 class ITEMACTIONS extends BaseActions {
\r
1019 // contains an assoc array with parameters that need to be included when
\r
1020 // generating links to items/archives/... (e.g. catid)
\r
1023 // true when the current user is a blog admin (and thus allowed to edit all items)
\r
1024 var $allowEditAll;
\r
1026 // timestamp of last visit
\r
1029 // item currently being handled (mysql result object, see BLOG::showUsingQuery)
\r
1032 // reference to the blog currently being displayed
\r
1035 // associative array with template info (part name => contents)
\r
1038 // true when comments need to be displayed
\r
1039 var $showComments;
\r
1041 function ITEMACTIONS(&$blog) {
\r
1042 // call constructor of superclass first
\r
1043 $this->BaseActions();
\r
1045 // extra parameters for created links
\r
1048 $this->linkparams = array('catid' => $catid);
\r
1050 // check if member is blog admin (and thus allowed to edit all items)
\r
1052 $this->allowEditAll = ($member->isLoggedIn() && $member->blogAdminRights($blog->getID()));
\r
1053 $this->setBlog($blog);
\r
1056 function getDefinedActions() {
\r
1078 'syndicate_title',
\r
1079 'syndicate_description',
\r
1104 function setLastVisit($lastVisit) { $this->lastVisit = $lastVisit; }
\r
1105 function setParser(&$parser) { $this->parser =& $parser; }
\r
1106 function setCurrentItem(&$item) { $this->currentItem =& $item; }
\r
1107 function setBlog(&$blog) { $this->blog =& $blog; }
\r
1108 function setTemplate($template) { $this->template =& $template; }
\r
1109 function setShowComments($val) { $this->showComments = $val; }
\r
1111 // methods used by parser to insert content
\r
1113 function parse_blogid() { echo $this->blog->getID(); }
\r
1114 function parse_body() { $this->highlightAndParse($this->currentItem->body); }
\r
1115 function parse_title() { $this->highlightAndParse($this->currentItem->title); }
\r
1116 function parse_more() { $this->highlightAndParse($this->currentItem->more); }
\r
1117 function parse_itemid() { echo $this->currentItem->itemid; }
\r
1118 function parse_category() { echo $this->currentItem->category; }
\r
1119 function parse_categorylink() { echo createCategoryLink($this->currentItem->catid); }
\r
1120 function parse_catid() { echo $this->currentItem->catid; }
\r
1121 function parse_authorid() { echo $this->currentItem->authorid; }
\r
1122 function parse_authorlink() { echo createMemberLink($this->currentItem->authorid, $this->linkparams); }
\r
1123 function parse_query() { echo $this->strHighlight; }
\r
1124 function parse_itemlink() { echo createItemLink($this->currentItem->itemid, $this->linkparams); }
\r
1125 function parse_blogurl() { echo $this->blog->getURL(); }
\r
1126 function parse_closed() { echo $this->currentItem->closed; }
\r
1127 function parse_relevance() { echo round($this->currentItem->score,2);}
\r
1129 function parse_karma($type = 'totalscore') {
\r
1132 // get karma object
\r
1133 $karma =& $manager->getKarma($this->currentItem->itemid);
\r
1137 echo $karma->getNbPosVotes();
\r
1140 echo $karma->getNbNegVotes();
\r
1143 echo $karma->getNbOfVotes();
\r
1146 $percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbPosVotes() / $karma->getNbOfVotes()) : 50;
\r
1147 echo number_format($percentage,2), '%';
\r
1150 $percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbNegVotes() / $karma->getNbOfVotes()) : 50;
\r
1151 echo number_format($percentage,2), '%';
\r
1153 case 'totalscore':
\r
1155 echo $karma->getTotalScore();
\r
1161 function parse_author($which = '') {
\r
1165 echo $this->currentItem->authorname;
\r
1168 echo $this->currentItem->authorid;
\r
1171 echo $this->currentItem->authormail;
\r
1174 echo $this->currentItem->authorurl;
\r
1178 echo $this->currentItem->author;
\r
1182 function parse_smartbody() {
\r
1183 if (!$this->currentItem->more) {
\r
1184 $this->highlightAndParse($this->currentItem->body);
\r
1186 $this->highlightAndParse($this->currentItem->more);
\r
1190 function parse_morelink() {
\r
1191 if ($this->currentItem->more)
\r
1192 $this->parser->parse($this->template['MORELINK']);
\r
1195 function parse_date($format = '') {
\r
1196 echo formatDate($format, $this->currentItem->timestamp, $this->template['FORMAT_DATE']);
\r
1200 * @param format optional strftime format
\r
1202 function parse_time($format = '') {
\r
1203 echo strftime($format ? $format : $this->template['FORMAT_TIME'],$this->currentItem->timestamp);
\r
1207 * @param maxLength optional maximum length
\r
1209 function parse_syndicate_title($maxLength = 100) {
\r
1210 $syndicated = strip_tags($this->currentItem->title);
\r
1211 echo htmlspecialchars(shorten($syndicated,$maxLength,'...'));
\r
1215 * @param maxLength optional maximum length
\r
1217 function parse_syndicate_description($maxLength = 250, $addHighlight = 0) {
\r
1218 $syndicated = strip_tags($this->currentItem->body);
\r
1219 if ($addHighlight) {
\r
1220 echo $this->highlightAndParse(htmlspecialchars(shorten($syndicated,$maxLength,'...')));
\r
1222 echo htmlspecialchars(shorten($syndicated,$maxLength,'...'));
\r
1226 function parse_karmaposlink($text = '') {
\r
1228 $link = $CONF['ActionURL'] . '?action=votepositive&itemid='.$this->currentItem->itemid;
\r
1229 echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
\r
1232 function parse_karmaneglink($text = '') {
\r
1234 $link = $CONF['ActionURL'] . '?action=votenegative&itemid='.$this->currentItem->itemid;
\r
1235 echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
\r
1238 function parse_new() {
\r
1239 if (($this->lastVisit != 0) && ($this->currentItem->timestamp > $this->lastVisit))
\r
1240 echo $this->template['NEW'];
\r
1243 function parse_image() {
\r
1244 // image/popup calls have arguments separated by |
\r
1245 $args = func_get_args();
\r
1246 $args = explode('|',implode($args,', '));
\r
1247 call_user_func_array(array(&$this,'createImageCode'),$args);
\r
1249 function parse_popup() {
\r
1250 // image/popup calls have arguments separated by |
\r
1251 $args = func_get_args();
\r
1252 $args = explode('|',implode($args,', '));
\r
1253 call_user_func_array(array(&$this,'createPopupCode'),$args);
\r
1255 function parse_media() {
\r
1256 // image/popup calls have arguments separated by |
\r
1257 $args = func_get_args();
\r
1258 $args = explode('|',implode($args,', '));
\r
1259 call_user_func_array(array(&$this,'createMediaCode'),$args);
\r
1262 function parse_daylink() {
\r
1263 echo createArchiveLink($this->blog->getID(), strftime('%Y-%m-%d',$this->currentItem->timestamp), $this->linkparams);
\r
1266 function parse_comments($maxToShow = 0) {
\r
1267 if ($maxToShow == 0)
\r
1268 $maxToShow = $this->blog->getMaxComments();
\r
1271 if ($this->showComments && $this->blog->commentsEnabled()) {
\r
1272 $comments = new COMMENTS($this->currentItem->itemid);
\r
1273 $comments->setItemActions($this);
\r
1274 $comments->showComments($this->template, $maxToShow, $this->currentItem->closed ? 0 : 1, $this->strHighlight);
\r
1279 * Executes a plugin templatevar
\r
1281 * @param pluginName name of plugin (without the NP_)
\r
1283 * extra parameters can be added
\r
1285 function parse_plugin($pluginName) {
\r
1288 // only continue when the plugin is really installed
\r
1289 if (!$manager->pluginInstalled('NP_' . $pluginName))
\r
1292 $plugin =& $manager->getPlugin('NP_' . $pluginName);
\r
1293 if (!$plugin) return;
\r
1296 $params = func_get_args();
\r
1298 // remove plugin name
\r
1299 array_shift($params);
\r
1301 // add item reference (array_unshift didn't work)
\r
1302 $params = array_merge(array(&$this->currentItem),$params);
\r
1304 call_user_func_array(array(&$plugin,'doTemplateVar'), $params);
\r
1307 function parse_edit() {
\r
1308 global $member, $CONF;
\r
1309 if ($this->allowEditAll || ($member->isLoggedIn() && ($member->getID() == $this->currentItem->authorid)) ) {
\r
1310 $this->parser->parse($this->template['EDITLINK']);
\r
1314 function parse_editlink() {
\r
1316 echo $CONF['AdminURL'],'bookmarklet.php?action=edit&itemid=',$this->currentItem->itemid;
\r
1319 function parse_editpopupcode() {
\r
1320 echo "if (event && event.preventDefault) event.preventDefault();winbm=window.open(this.href,'nucleusbm','scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');winbm.focus();return false;";
\r
1323 // helper functions
\r
1326 * Parses highlighted text, with limited actions only (to prevent not fully trusted team members
\r
1327 * from hacking your weblog.
\r
1329 function highlightAndParse(&$data) {
\r
1330 // allow only a limited subset of actions (do not allow includes etc, they might be evil)
\r
1331 $this->parser->actions = array('image','media','popup');
\r
1332 $this->parser->parse($this->highlight($data));
\r
1333 $this->parser->actions = $this->getDefinedActions();
\r
1336 function createPopupCode($filename, $width, $height, $text = '') {
\r
1339 // select private collection when no collection given
\r
1340 if (!strstr($filename,'/')) {
\r
1341 $filename = $this->currentItem->authorid . '/' . $filename;
\r
1344 $windowwidth = $width;
\r
1345 $windowheight = $height;
\r
1347 $vars['rawpopuplink'] = $CONF['Self'] . "?imagepopup=" . htmlspecialchars($filename) . "&width=$width&height=$height&imagetext=" . urlencode(htmlspecialchars($text));
\r
1348 $vars['popupcode'] = "window.open(this.href,'imagepopup','status=no,toolbar=no,scrollbars=no,resizable=yes,width=$windowwidth,height=$windowheight');return false;";
\r
1349 $vars['popuptext'] = htmlspecialchars($text);
\r
1350 $vars['popuplink'] = '<a href="' . $vars['rawpopuplink']. '" onclick="'. $vars['popupcode'].'" >' . $vars['popuptext'] . '</a>';
\r
1351 $vars['width'] = $width;
\r
1352 $vars['height'] = $height;
\r
1353 $vars['text'] = $text;
\r
1355 echo TEMPLATE::fill($this->template['POPUP_CODE'],$vars);
\r
1358 function createImageCode($filename, $width, $height, $text = '') {
\r
1361 // select private collection when no collection given
\r
1362 if (!strstr($filename,'/')) {
\r
1363 $filename = $this->currentItem->authorid . '/' . $filename;
\r
1366 $windowwidth = $width;
\r
1367 $windowheight = $height;
\r
1369 $vars['link'] = htmlspecialchars($CONF['MediaURL']. $filename);
\r
1370 $vars['text'] = htmlspecialchars($text);
\r
1371 $vars['image'] = '<img src="' . $vars['link'] . '" width="' . $width . '" height="' . $height . '" alt="' . $vars['text'] . '" />';
\r
1372 $vars['width'] = $width;
\r
1373 $vars['height'] = $height;
\r
1377 echo TEMPLATE::fill($this->template['IMAGE_CODE'],$vars);;
\r
1381 function createMediaCode($filename, $text = '') {
\r
1384 // select private collection when no collection given
\r
1385 if (!strstr($filename,'/')) {
\r
1386 $filename = $this->currentItem->authorid . '/' . $filename;
\r
1389 $vars['link'] = htmlspecialchars($CONF['MediaURL'] . $filename);
\r
1390 $vars['text'] = htmlspecialchars($text);
\r
1391 $vars['media'] = '<a href="' . $vars['link'] . '">' . $vars['text'] . '</a>';
\r
1393 echo TEMPLATE::fill($this->template['MEDIA_CODE'],$vars);;
\r
1400 // used for mail notification (html -> text)
\r
1402 function toAscii($html) {
\r
1403 // strip off most tags
\r
1404 $html = strip_tags($html,'<a>');
\r
1405 $to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i";
\r
1407 $ascii = preg_replace_callback ($to_replace, '_links_add', $html);
\r
1408 $ascii .= "\n\n" . _links_list();
\r
1409 return strip_tags($ascii);
\r
1412 function _links_init() {
\r
1413 global $tmp_links;
\r
1414 $tmp_links = array();
\r
1417 function _links_add($match) {
\r
1418 global $tmp_links;
\r
1419 array_push($tmp_links, $match[1]);
\r
1420 return $match[2] . ' [' . sizeof($tmp_links) .']';
\r
1423 function _links_list() {
\r
1424 global $tmp_links;
\r
1427 foreach ($tmp_links as $current) {
\r
1428 $output .= "[$i] $current\n";
\r