4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2005 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
16 * $Id: BLOG.php,v 1.3 2005-03-12 06:19:05 kimitake Exp $
\r
24 // ID of currently selected category
\r
27 // After creating an object of the blog class, contains true if the BLOG object is
\r
28 // valid (the blog exists)
\r
31 // associative array, containing all blogsettings (use the get/set functions instead)
\r
35 * Creates a new BLOG object for the given blog
\r
39 function BLOG($id) {
\r
40 $this->blogid = intval($id);
\r
41 $this->readSettings();
\r
43 // try to set catid
\r
44 // (the parse functions in SKIN.php will override this, so it's mainly useless)
\r
46 $this->setSelectedCategory($catid);
\r
50 * Shows the given amount of items for this blog
\r
53 * String representing the template _NAME_ (!)
\r
54 * @param $amountEntries
\r
55 * amount of entries to show
\r
57 * offset from where items should be shown (e.g. 5 = start at fifth item)
\r
59 * amount of items shown
\r
61 function readLog($template, $amountEntries, $offset = 0, $startpos = 0) {
\r
62 return $this->readLogAmount($template,$amountEntries,'','',1,1,$offset, $startpos);
\r
66 * Shows an archive for a given month
\r
73 * String representing the template name to be used
\r
75 function showArchive($templatename, $year, $month, $day=0) {
\r
77 // create extra where clause for select query
\r
79 $timestamp_start = mktime(0,0,0,$month,1,$year);
\r
80 $timestamp_end = mktime(0,0,0,$month+1,1,$year); // also works when $month==12
\r
82 $timestamp_start = mktime(0,0,0,$month,$day,$year);
\r
83 $timestamp_end = mktime(0,0,0,$month,$day+1,$year);
\r
85 $extra_query = ' and i.itime>=' . mysqldate($timestamp_start)
\r
86 . ' and i.itime<' . mysqldate($timestamp_end);
\r
89 $this->readLogAmount($templatename,0,$extra_query,'',1,1);
\r
94 // sets/gets current category (only when category exists)
\r
95 function setSelectedCategory($catid) {
\r
96 if ($this->isValidCategory($catid) || (intval($catid) == 0))
\r
97 $this->selectedcatid = intval($catid);
\r
100 function setSelectedCategoryByName($catname) {
\r
101 $this->setSelectedCategory($this->getCategoryIdFromName($catname));
\r
104 function getSelectedCategory() {
\r
105 return $this->selectedcatid;
\r
109 * Shows the given amount of items for this blog
\r
112 * String representing the template _NAME_ (!)
\r
113 * @param $amountEntries
\r
114 * amount of entries to show (0 = no limit)
\r
115 * @param $extraQuery
\r
116 * extra conditions to be added to the query
\r
117 * @param $highlight
\r
118 * contains a query that should be highlighted
\r
120 * 1=show comments 0=don't show comments
\r
121 * @param $dateheads
\r
122 * 1=show dateheads 0=don't show dateheads
\r
126 * amount of items shown
\r
128 function readLogAmount($template, $amountEntries, $extraQuery, $highlight, $comments, $dateheads, $offset = 0, $startpos = 0) {
\r
130 $query = $this->getSqlBlog($extraQuery);
\r
132 if ($amountEntries > 0) {
\r
133 // $offset zou moeten worden:
\r
134 // (($startpos / $amountentries) + 1) * $offset ... later testen ...
\r
135 $query .= ' LIMIT ' . intval($startpos + $offset).',' . intval($amountEntries);
\r
137 return $this->showUsingQuery($template, $query, $highlight, $comments, $dateheads);
\r
140 function showUsingQuery($templateName, $query, $highlight = '', $comments = 0, $dateheads = 1) {
\r
141 global $CONF, $manager;
\r
143 $lastVisit = cookieVar($CONF['CookiePrefix'] .'lastVisit');
\r
144 if ($lastVisit != 0)
\r
145 $lastVisit = $this->getCorrectTime($lastVisit);
\r
147 // set templatename as global variable (so plugins can access it)
\r
148 global $currentTemplateName;
\r
149 $currentTemplateName = $templateName;
\r
151 $template =& $manager->getTemplate($templateName);
\r
153 // create parser object & action handler
\r
154 $actions =& new ITEMACTIONS($this);
\r
155 $parser =& new PARSER($actions->getDefinedActions(),$actions);
\r
156 $actions->setTemplate($template);
\r
157 $actions->setHighlight($highlight);
\r
158 $actions->setLastVisit($lastVisit);
\r
159 $actions->setParser($parser);
\r
160 $actions->setShowComments($comments);
\r
163 $items = sql_query($query);
\r
165 // loop over all items
\r
166 while ($item = mysql_fetch_object($items)) {
\r
168 $item->timestamp = strtotime($item->itime); // string timestamp -> unix timestamp
\r
170 // action handler needs to know the item we're handling
\r
171 $actions->setCurrentItem($item);
\r
173 // add date header if needed
\r
175 $new_date = date('dFY',$item->timestamp);
\r
176 if ($new_date != $old_date) {
\r
177 // unless this is the first time, write date footer
\r
178 $timestamp = $item->timestamp;
\r
179 if ($old_date != 0) {
\r
180 $oldTS = strtotime($old_date);
\r
181 $manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));
\r
182 $parser->parse(strftime($template['DATE_FOOTER'], $oldTS));
\r
183 $manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));
\r
185 $manager->notify('PreDateHead',array('blog' => &$this, 'timestamp' => $timestamp));
\r
186 // note, to use templatvars in the dateheader, the %-characters need to be doubled in
\r
187 // order to be preserved by strftime
\r
188 $parser->parse(strftime($template['DATE_HEADER'],$timestamp));
\r
189 $manager->notify('PostDateHead',array('blog' => &$this, 'timestamp' => $timestamp));
\r
191 $old_date = $new_date;
\r
195 $parser->parse($template['ITEM_HEADER']);
\r
196 $manager->notify('PreItem', array('blog' => &$this, 'item' => &$item));
\r
197 $parser->parse($template['ITEM']);
\r
198 $manager->notify('PostItem', array('blog' => &$this, 'item' => &$item));
\r
199 $parser->parse($template['ITEM_FOOTER']);
\r
203 $numrows = mysql_num_rows($items);
\r
205 // add another date footer if there was at least one item
\r
206 if (($numrows > 0) && $dateheads) {
\r
207 $manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));
\r
208 $parser->parse($template['DATE_FOOTER']);
\r
209 $manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));
\r
212 mysql_free_result($items); // free memory
\r
218 function showOneitem($itemid, $template, $highlight) {
\r
219 $extraQuery = ' and inumber=' . intval($itemid);
\r
221 return $this->readLogAmount($template, 1, $extraQuery, $highlight, 0, 0);
\r
226 * Adds an item to this blog
\r
228 function additem($catid, $title, $body, $more, $blogid, $authorid, $timestamp, $closed, $draft) {
\r
231 $blogid = intval($blogid);
\r
232 $authorid = intval($authorid);
\r
236 $catid = intval($catid);
\r
238 // convert newlines to <br />
\r
239 if ($this->convertBreaks()) {
\r
240 $body = addBreaks($body);
\r
241 $more = addBreaks($more);
\r
244 if ($closed != '1') $closed = '0';
\r
245 if ($draft != '0') $draft = '1';
\r
247 if (!$this->isValidCategory($catid))
\r
248 $catid = $this->getDefaultCategory();
\r
250 if ($timestamp > $this->getCorrectTime())
\r
253 $timestamp = date('Y-m-d H:i:s',$timestamp);
\r
255 $manager->notify('PreAddItem',array('title' => &$title, 'body' => &$body, 'more' => &$more, 'blog' => &$this, 'authorid' => &$authorid, 'timestamp' => &$timestamp, 'closed' => &$closed, 'draft' => &$draft, 'catid' => &$catid));
\r
257 $title = addslashes($title);
\r
258 $body = addslashes($body);
\r
259 $more = addslashes($more);
\r
261 $query = 'INSERT INTO '.sql_table('item').' (ITITLE, IBODY, IMORE, IBLOG, IAUTHOR, ITIME, ICLOSED, IDRAFT, ICAT) '
\r
262 . "VALUES ('$title', '$body', '$more', $blogid, $authorid, '$timestamp', $closed, $draft, $catid)";
\r
263 sql_query($query);
\r
264 $itemid = mysql_insert_id();
\r
266 $manager->notify('PostAddItem',array('itemid' => $itemid));
\r
269 $this->updateUpdateFile();
\r
271 // send notification mail
\r
272 if (!$draft && !$isFuture && $this->getNotifyAddress() && $this->notifyOnNewItem())
\r
273 $this->sendNewItemNotification($itemid, stripslashes($title), stripslashes($body));
\r
278 function sendNewItemNotification($itemid, $title, $body) {
\r
279 global $CONF, $member;
\r
281 // create text version of html post
\r
282 $ascii = toAscii($body);
\r
284 $mailto_msg = _NOTIFY_NI_MSG . " \n";
\r
285 $mailto_msg .= $CONF['IndexURL'] . 'index.php?itemid=' . $itemid . "\n\n";
\r
286 $mailto_msg .= _NOTIFY_TITLE . ' ' . strip_tags($title) . "\n";
\r
287 $mailto_msg .= _NOTIFY_CONTENTS . "\n " . $ascii . "\n";
\r
288 $mailto_msg .= getMailFooter();
\r
290 $mailto_title = $this->getName() . ': ' . _NOTIFY_NI_TITLE;
\r
292 $frommail = $member->getNotifyFromMailAddress();
\r
294 $notify =& new NOTIFICATION($this->getNotifyAddress());
\r
295 $notify->notify($mailto_title, $mailto_msg , $frommail);
\r
303 * Creates a new category for this blog
\r
306 * name of the new category. When empty, a name is generated automatically
\r
307 * (starting with newcat)
\r
308 * @param $catDescription
\r
309 * description of the new category. Defaults to 'New Category'
\r
312 * the new category-id in case of success.
\r
315 function createNewCategory($catName = '', $catDescription = 'New category') {
\r
316 global $member, $manager;
\r
318 if ($member->blogAdminRights($this->getID())) {
\r
320 if ($catName == '')
\r
322 $catName = 'newcat';
\r
324 while(mysql_num_rows(sql_query('SELECT * FROM '.sql_table('category')." WHERE cname='".$catName.$i."' and cblog=".$this->getID())) > 0)
\r
326 $catName = $catName . $i;
\r
333 'name' => &$catName,
\r
334 'description' => $catDescription
\r
338 $query = 'INSERT INTO '.sql_table('category').' (cblog, cname, cdesc) VALUES (' . $this->getID() . ", '" . addslashes($catName) . "', '" . addslashes($catDescription) . "')";
\r
340 $catid = mysql_insert_id();
\r
346 'name' => $catName,
\r
347 'description' => $catDescription,
\r
361 * Searches all months of this blog for the given query
\r
366 * template to be used (__NAME__ of the template)
\r
367 * @param $amountMonths
\r
368 * max amount of months to be search (0 = all)
\r
369 * @param $maxresults
\r
370 * max number of results to show
\r
374 * amount of hits found
\r
376 function search($query, $template, $amountMonths, $maxresults, $startpos) {
\r
377 global $CONF, $manager;
\r
380 $sqlquery = $this->getSqlSearch($query, $amountMonths, $highlight);
\r
382 if ($sqlquery == '')
\r
384 // no query -> show everything
\r
386 $amountfound = $this->readLogAmount($template, $maxresults, $extraQuery, $query, 1, 1);
\r
389 // add LIMIT to query (to split search results into pages)
\r
390 if (intval($maxresults > 0))
\r
391 $sqlquery .= ' LIMIT ' . intval($startpos).',' . intval($maxresults);
\r
394 $amountfound = $this->showUsingQuery($template, $sqlquery, $highlight, 1, 1);
\r
396 // when no results were found, show a message
\r
397 if ($amountfound == 0)
\r
399 $template =& $manager->getTemplate($template);
\r
401 'query' => htmlspecialchars($query),
\r
402 'blogid' => $this->getID()
\r
404 echo TEMPLATE::fill($template['SEARCH_NOTHINGFOUND'],$vars);
\r
408 return $amountfound;
\r
412 * Returns an SQL query to use for a search query
\r
416 * @param $amountMonths
\r
417 * amount of months to search back. Default = 0 = unlimited
\r
419 * either empty, or 'count'. In this case, the query will be a SELECT COUNT(*) query
\r
420 * @returns $highlight
\r
421 * words to highlight (out parameter)
\r
423 * either a full SQL query, or an empty string (if querystring empty)
\r
425 * No LIMIT clause is added. (caller should add this if multiple pages are requested)
\r
427 function getSqlSearch($query, $amountMonths = 0, &$highlight, $mode = '')
\r
429 $searchclass =& new SEARCH($query);
\r
431 $highlight = $searchclass->inclusive;
\r
433 // if querystring is empty, return empty string
\r
434 if ($searchclass->inclusive == '')
\r
438 $where = $searchclass->boolean_sql_where('ititle,ibody,imore');
\r
439 $select = $searchclass->boolean_sql_select('ititle,ibody,imore');
\r
441 // get list of blogs to search
\r
442 $blogs = $searchclass->blogs; // array containing blogs that always need to be included
\r
443 $blogs[] = $this->getID(); // also search current blog (duh)
\r
444 $blogs = array_unique($blogs); // remove duplicates
\r
446 if (count($blogs) > 0)
\r
447 $selectblogs = ' and i.iblog in (' . implode(',', $blogs) . ')';
\r
451 $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
453 $query .= ', '.$select. ' as score ';
\r
455 $query = 'SELECT COUNT(*) as result ';
\r
458 $query .= ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, '.sql_table('category').' as c'
\r
459 . ' WHERE i.iauthor=m.mnumber'
\r
460 . ' and i.icat=c.catid'
\r
461 . ' and i.idraft=0' // exclude drafts
\r
463 // don't show future items
\r
464 . ' and i.itime<=' . mysqldate($this->getCorrectTime())
\r
467 // take into account amount of months to search
\r
468 if ($amountMonths > 0)
\r
470 $localtime = getdate($this->getCorrectTime());
\r
471 $timestamp_start = mktime(0,0,0,$localtime['mon'] - $amountMonths,1,$localtime['year']);
\r
472 $query .= ' and i.itime>' . mysqldate($timestamp_start);
\r
478 $query .= ' ORDER BY score DESC';
\r
480 $query .= ' ORDER BY i.itime DESC ';
\r
487 * Returns the SQL query that's normally used to display the blog items on the index type skins
\r
490 * either empty, or 'count'. In this case, the query will be a SELECT COUNT(*) query
\r
492 * either a full SQL query, or an empty string
\r
494 * No LIMIT clause is added. (caller should add this if multiple pages are requested)
\r
496 function getSqlBlog($extraQuery, $mode = '')
\r
499 $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
501 $query = 'SELECT COUNT(*) as result ';
\r
503 $query .= ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, '.sql_table('category').' as c'
\r
504 . ' WHERE i.iblog='.$this->blogid
\r
505 . ' and i.iauthor=m.mnumber'
\r
506 . ' and i.icat=c.catid'
\r
507 . ' and i.idraft=0' // exclude drafts
\r
508 // don't show future items
\r
509 . ' and i.itime<=' . mysqldate($this->getCorrectTime());
\r
511 if ($this->getSelectedCategory())
\r
512 $query .= ' and i.icat=' . $this->getSelectedCategory() . ' ';
\r
515 $query .= $extraQuery;
\r
518 $query .= ' ORDER BY i.itime DESC';
\r
524 * Shows the archivelist using the given template
\r
526 function showArchiveList($template, $mode = 'month', $limit = 0) {
\r
527 global $CONF, $catid, $manager;
\r
530 $linkparams = array('catid' => $catid);
\r
532 $template =& $manager->getTemplate($template);
\r
533 $data['blogid'] = $this->getID();
\r
535 echo TEMPLATE::fill($template['ARCHIVELIST_HEADER'],$data);
\r
537 $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
538 . ' WHERE iblog=' . $this->getID()
\r
539 . ' and itime <=' . mysqldate($this->getCorrectTime()) // don't show future items!
\r
540 . ' and idraft=0'; // don't show draft items
\r
543 $query .= ' and icat=' . intval($catid);
\r
545 $query .= ' GROUP BY Year, Month';
\r
546 if ($mode == 'day')
\r
550 $query .= ' ORDER BY itime DESC';
\r
553 $query .= ' LIMIT ' . intval($limit);
\r
555 $res = sql_query($query);
\r
557 while ($current = mysql_fetch_object($res)) {
\r
558 $current->itime = strtotime($current->itime); // string time -> unix timestamp
\r
560 if ($mode == 'day') {
\r
561 $archivedate = date('Y-m-d',$current->itime);
\r
562 $archive['day'] = date('d',$current->itime);
\r
564 $archivedate = date('Y-m',$current->itime);
\r
566 $data['month'] = date('m',$current->itime);
\r
567 $data['year'] = date('Y',$current->itime);
\r
568 $data['archivelink'] = createArchiveLink($this->getID(),$archivedate,$linkparams);
\r
570 $temp = TEMPLATE::fill($template['ARCHIVELIST_LISTITEM'],$data);
\r
571 echo strftime($temp,$current->itime);
\r
575 mysql_free_result($res);
\r
577 echo TEMPLATE::fill($template['ARCHIVELIST_FOOTER'],$data);
\r
582 * Shows the list of categories using a given template
\r
584 function showCategoryList($template) {
\r
585 global $CONF, $manager;
\r
587 // determine arguments next to catids
\r
588 // I guess this can be done in a better way, but it works
\r
589 global $archive, $archivelist;
\r
591 $linkparams = array();
\r
593 $blogurl = createArchiveLink($this->getID(), $archive, '');
\r
594 $linkparams['blogid'] = $this->getID();
\r
595 $linkparams['archive'] = $archive;
\r
596 } else if ($archivelist) {
\r
597 $blogurl = createArchiveListLink($this->getID(), '');
\r
598 $linkparams['archivelist'] = $archivelist;
\r
600 $blogurl = createBlogidLink($this->getID(), '');
\r
601 $linkparams['blogid'] = $this->getID();
\r
604 //$blogurl = $this->getURL() . $qargs;
\r
605 $blogurl = createBlogLink($this->getURL(), $linkparams);
\r
607 $template =& $manager->getTemplate($template);
\r
609 echo TEMPLATE::fill($template['CATLIST_HEADER'],
\r
611 'blogid' => $this->getID(),
\r
612 'blogurl' => $blogurl,
\r
613 'self' => $CONF['Self']
\r
616 $query = 'SELECT catid, cdesc as catdesc, cname as catname FROM '.sql_table('category').' WHERE cblog=' . $this->getID() . ' ORDER BY cname ASC';
\r
617 $res = sql_query($query);
\r
620 while ($data = mysql_fetch_assoc($res)) {
\r
621 $data['blogid'] = $this->getID();
\r
622 $data['blogurl'] = $blogurl;
\r
623 $data['catlink'] = createCategoryLink($data['catid'], $linkparams);
\r
624 $data['self'] = $CONF['Self'];
\r
626 $temp = TEMPLATE::fill($template['CATLIST_LISTITEM'],$data);
\r
627 echo strftime($temp,$current->itime);
\r
631 mysql_free_result($res);
\r
633 echo TEMPLATE::fill($template['CATLIST_FOOTER'],
\r
635 'blogid' => $this->getID(),
\r
636 'blogurl' => $blogurl,
\r
637 'self' => $CONF['Self']
\r
642 * Blogsettings functions
\r
645 function readSettings() {
\r
646 $query = 'SELECT *'
\r
647 . ' FROM '.sql_table('blog')
\r
648 . ' WHERE bnumber=' . $this->blogid;
\r
649 $res = sql_query($query);
\r
651 $this->isValid = (mysql_num_rows($res) > 0);
\r
652 if (!$this->isValid)
\r
655 $this->settings = mysql_fetch_assoc($res);
\r
658 function writeSettings() {
\r
660 // (can't use floatval since not available prior to PHP 4.2)
\r
661 $offset = $this->getTimeOffset();
\r
662 if (!is_float($offset))
\r
663 $offset = intval($offset);
\r
665 $query = 'UPDATE '.sql_table('blog')
\r
666 . " SET bname='" . addslashes($this->getName()) . "',"
\r
667 . " bshortname='". addslashes($this->getShortName()) . "',"
\r
668 . " bcomments=". intval($this->commentsEnabled()) . ","
\r
669 . " bmaxcomments=" . intval($this->getMaxComments()) . ","
\r
670 . " btimeoffset=" . $offset . ","
\r
671 . " bpublic=" . intval($this->isPublic()) . ","
\r
672 . " bsendping=" . intval($this->pingUserland()) . ","
\r
673 . " bconvertbreaks=" . intval($this->convertBreaks()) . ","
\r
674 . " ballowpast=" . intval($this->allowPastPosting()) . ","
\r
675 . " bnotify='" . addslashes($this->getNotifyAddress()) . "',"
\r
676 . " bnotifytype=" . intval($this->getNotifyType()) . ","
\r
677 . " burl='" . addslashes($this->getURL()) . "',"
\r
678 . " bupdate='" . addslashes($this->getUpdateFile()) . "',"
\r
679 . " bdesc='" . addslashes($this->getDescription()) . "',"
\r
680 . " bdefcat=" . intval($this->getDefaultCategory()) . ","
\r
681 . " bdefskin=" . intval($this->getDefaultSkin()) . ","
\r
682 . " bincludesearch=" . intval($this->getSearchable())
\r
683 . " WHERE bnumber=" . intval($this->getID());
\r
690 // update update file if requested
\r
691 function updateUpdatefile() {
\r
692 if ($this->getUpdateFile()) {
\r
693 $f_update = fopen($this->getUpdateFile(),'w');
\r
694 fputs($f_update,$this->getCorrectTime());
\r
701 * Sends a XML-RPC ping message to Userland, so the weblog can
\r
702 * show up in the weblogs.com updates-list
\r
704 function sendUserlandPing() {
\r
705 global $php_errormsg;
\r
707 if ($this->pingUserland()) {
\r
708 // testmessage for adding an item
\r
709 $message = new xmlrpcmsg('weblogUpdates.ping',array(
\r
710 new xmlrpcval($this->getName(),'string'),
\r
711 new xmlrpcval($this->getURL(),'string')
\r
714 $c = new xmlrpc_client('/RPC2', 'rpc.weblogs.com', 80);
\r
716 // $c->setDebug(1);
\r
718 $r = $c->send($message,15); // 15 seconds timeout...
\r
720 if (($r == 0) && ($r->errno || $r->errstring)) {
\r
721 return 'Error ' . $r->errno . ' : ' . $r->errstring;
\r
722 } elseif (($r == 0) && ($php_errormsg)) {
\r
723 return 'PHP Error: ' . $php_errormsg;
\r
724 } elseif ($r == 0) {
\r
725 return 'Error while trying to send ping. Sorry about that.';
\r
726 } elseif ($r->faultCode() != 0) {
\r
727 return 'Error: ' . $r->faultString();
\r
729 $r = $r->value(); // get response struct
\r
731 $flerror = $r->structmem('flerror');
\r
732 $flerror = $flerror->scalarval();
\r
735 $message = $r->structmem('message');
\r
736 $message = $message->scalarval();
\r
739 return 'Error (flerror=1): ' . $message;
\r
741 return 'Success: ' . $message;
\r
746 function isValidCategory($catid) {
\r
747 $query = 'SELECT * FROM '.sql_table('category').' WHERE cblog=' . $this->getID() . ' and catid=' . intval($catid);
\r
748 return (mysql_num_rows(mysql_query($query)) != 0);
\r
751 function getCategoryName($catid) {
\r
752 $res = mysql_query('SELECT cname FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
\r
753 $o = mysql_fetch_object($res);
\r
757 function getCategoryDesc($catid) {
\r
758 $res = mysql_query('SELECT cdesc FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
\r
759 $o = mysql_fetch_object($res);
\r
763 function getCategoryIdFromName($name) {
\r
764 $res = mysql_query('SELECT catid FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and cname="' . addslashes($name) . '"');
\r
765 if (mysql_num_rows($res) > 0) {
\r
766 $o = mysql_fetch_object($res);
\r
769 return $this->getDefaultCategory();
\r
773 function pingUserland() {
\r
774 return $this->getSetting('bsendping');
\r
777 function setPingUserland($val) {
\r
778 $this->setSetting('bsendping',$val);
\r
781 function convertBreaks() {
\r
782 return $this->getSetting('bconvertbreaks');
\r
785 function insertJavaScriptInfo($authorid = '') {
\r
786 global $member, $CONF;
\r
788 if ($authorid == '')
\r
789 $authorid = $member->getID();
\r
792 <script type="text/javascript">
\r
793 setConvertBreaks(<?php echo $this->convertBreaks() ? 'true' : 'false' ?>);
\r
794 setMediaUrl("<?php echo $CONF['MediaURL']?>");
\r
795 setAuthorId(<?php echo $authorid?>);
\r
798 function setConvertBreaks($val) {
\r
799 $this->setSetting('bconvertbreaks',$val);
\r
801 function setAllowPastPosting($val) {
\r
802 $this->setSetting('ballowpast',$val);
\r
804 function allowPastPosting() {
\r
805 return $this->getSetting('ballowpast');
\r
808 function getCorrectTime($t=0) {
\r
809 if ($t == 0) $t = time();
\r
810 return ($t + 3600 * $this->getTimeOffset());
\r
813 function getName() {
\r
814 return $this->getSetting('bname');
\r
817 function getShortName() {
\r
818 return $this->getSetting('bshortname');
\r
821 function getMaxComments() {
\r
822 return $this->getSetting('bmaxcomments');
\r
825 function getNotifyAddress() {
\r
826 return $this->getSetting('bnotify');
\r
829 function getNotifyType() {
\r
830 return $this->getSetting('bnotifytype');
\r
833 function notifyOnComment() {
\r
834 $n = $this->getNotifyType();
\r
835 return (($n != 0) && (($n % 3) == 0));
\r
838 function notifyOnVote() {
\r
839 $n = $this->getNotifyType();
\r
840 return (($n != 0) && (($n % 5) == 0));
\r
843 function notifyOnNewItem() {
\r
844 $n = $this->getNotifyType();
\r
845 return (($n != 0) && (($n % 7) == 0));
\r
848 function setNotifyType($val) {
\r
849 $this->setSetting('bnotifytype',$val);
\r
853 function getTimeOffset() {
\r
854 return $this->getSetting('btimeoffset');
\r
857 function commentsEnabled() {
\r
858 return $this->getSetting('bcomments');
\r
861 function getURL() {
\r
862 return $this->getSetting('burl');
\r
865 function getDefaultSkin() {
\r
866 return $this->getSetting('bdefskin');
\r
869 function getUpdateFile() {
\r
870 return $this->getSetting('bupdate');
\r
873 function getDescription() {
\r
874 return $this->getSetting('bdesc');
\r
877 function isPublic() {
\r
878 return $this->getSetting('bpublic');
\r
881 function getSearchable() {
\r
882 return $this->getSetting('bincludesearch');
\r
885 function getDefaultCategory() {
\r
886 return $this->getSetting('bdefcat');
\r
889 function setPublic($val) {
\r
890 $this->setSetting('bpublic',$val);
\r
893 function setSearchable($val) {
\r
894 $this->setSetting('bincludesearch',$val);
\r
897 function setDescription($val) {
\r
898 $this->setSetting('bdesc',$val);
\r
901 function setUpdateFile($val) {
\r
902 $this->setSetting('bupdate',$val);
\r
905 function setDefaultSkin($val) {
\r
906 $this->setSetting('bdefskin',$val);
\r
909 function setURL($val) {
\r
910 $this->setSetting('burl',$val);
\r
913 function setName($val) {
\r
914 $this->setSetting('bname',$val);
\r
917 function setShortName($val) {
\r
918 $this->setSetting('bshortname',$val);
\r
921 function setCommentsEnabled($val) {
\r
922 $this->setSetting('bcomments',$val);
\r
925 function setMaxComments($val) {
\r
926 $this->setSetting('bmaxcomments',$val);
\r
929 function setNotifyAddress($val) {
\r
930 $this->setSetting('bnotify',$val);
\r
933 function setTimeOffset($val) {
\r
934 // check validity of value
\r
935 // 1. replace , by . (common mistake)
\r
936 $val = str_replace(',','.',$val);
\r
937 // 2. cast to float or int
\r
938 if (is_numeric($val) && strstr($val,'.5')) {
\r
939 $val = (float) $val;
\r
941 $val = intval($val);
\r
944 $this->setSetting('btimeoffset',$val);
\r
947 function setDefaultCategory($val) {
\r
948 $this->setSetting('bdefcat',$val);
\r
951 function getSetting($key) {
\r
952 return $this->settings[$key];
\r
955 function setSetting($key,$value) {
\r
956 $this->settings[$key] = $value;
\r
960 // tries to add a member to the team. Returns false if the member was already on
\r
962 function addTeamMember($memberid, $admin) {
\r
965 $memberid = intval($memberid);
\r
966 $admin = intval($admin);
\r
968 // check if member is already a member
\r
969 $tmem = MEMBER::createFromID($memberid);
\r
971 if ($tmem->isTeamMember($this->getID()))
\r
975 'PreAddTeamMember',
\r
978 'member' => &$tmem,
\r
984 $query = 'INSERT INTO '.sql_table('team').' (TMEMBER, TBLOG, TADMIN) '
\r
985 . 'VALUES (' . $memberid .', '.$this->getID().', "'.$admin.'")';
\r
989 'PostAddTeamMember',
\r
992 'member' => &$tmem,
\r
998 ACTIONLOG::add(INFO, 'Added ' . $tmem->getDisplayName() . ' (ID=' .
\r
999 $memberid .') to the team of blog "' . $this->getName() . '"');
\r
1004 function getID() {
\r
1005 return $this->blogid;
\r
1008 // returns true if there is a blog with the given shortname (static)
\r
1009 function exists($name) {
\r
1010 $r = sql_query('select * FROM '.sql_table('blog').' WHERE bshortname="'.addslashes($name).'"');
\r
1011 return (mysql_num_rows($r) != 0);
\r
1014 // returns true if there is a blog with the given ID (static)
\r
1015 function existsID($id) {
\r
1016 $r = sql_query('select * FROM '.sql_table('blog').' WHERE bnumber='.intval($id));
\r
1017 return (mysql_num_rows($r) != 0);
\r
1024 * This class is used when parsing item templates
\r
1026 class ITEMACTIONS extends BaseActions {
\r
1028 // contains an assoc array with parameters that need to be included when
\r
1029 // generating links to items/archives/... (e.g. catid)
\r
1032 // true when the current user is a blog admin (and thus allowed to edit all items)
\r
1033 var $allowEditAll;
\r
1035 // timestamp of last visit
\r
1038 // item currently being handled (mysql result object, see BLOG::showUsingQuery)
\r
1041 // reference to the blog currently being displayed
\r
1044 // associative array with template info (part name => contents)
\r
1047 // true when comments need to be displayed
\r
1048 var $showComments;
\r
1050 function ITEMACTIONS(&$blog) {
\r
1051 // call constructor of superclass first
\r
1052 $this->BaseActions();
\r
1054 // extra parameters for created links
\r
1057 $this->linkparams = array('catid' => $catid);
\r
1059 // check if member is blog admin (and thus allowed to edit all items)
\r
1061 $this->allowEditAll = ($member->isLoggedIn() && $member->blogAdminRights($blog->getID()));
\r
1062 $this->setBlog($blog);
\r
1065 function getDefinedActions() {
\r
1087 'syndicate_title',
\r
1088 'syndicate_description',
\r
1113 function setLastVisit($lastVisit) { $this->lastVisit = $lastVisit; }
\r
1114 function setParser(&$parser) { $this->parser =& $parser; }
\r
1115 function setCurrentItem(&$item) { $this->currentItem =& $item; }
\r
1116 function setBlog(&$blog) { $this->blog =& $blog; }
\r
1117 function setTemplate($template) { $this->template =& $template; }
\r
1118 function setShowComments($val) { $this->showComments = $val; }
\r
1120 // methods used by parser to insert content
\r
1122 function parse_blogid() { echo $this->blog->getID(); }
\r
1123 function parse_body() { $this->highlightAndParse($this->currentItem->body); }
\r
1124 function parse_title() { $this->highlightAndParse($this->currentItem->title); }
\r
1125 function parse_more() { $this->highlightAndParse($this->currentItem->more); }
\r
1126 function parse_itemid() { echo $this->currentItem->itemid; }
\r
1127 function parse_category() { echo $this->currentItem->category; }
\r
1128 function parse_categorylink() { echo createCategoryLink($this->currentItem->catid); }
\r
1129 function parse_catid() { echo $this->currentItem->catid; }
\r
1130 function parse_authorid() { echo $this->currentItem->authorid; }
\r
1131 function parse_authorlink() { echo createMemberLink($this->currentItem->authorid, $this->linkparams); }
\r
1132 function parse_query() { echo $this->strHighlight; }
\r
1133 function parse_itemlink() { echo createItemLink($this->currentItem->itemid, $this->linkparams); }
\r
1134 function parse_blogurl() { echo $this->blog->getURL(); }
\r
1135 function parse_closed() { echo $this->currentItem->closed; }
\r
1136 function parse_relevance() { echo round($this->currentItem->score,2);}
\r
1138 function parse_karma($type = 'totalscore') {
\r
1141 // get karma object
\r
1142 $karma =& $manager->getKarma($this->currentItem->itemid);
\r
1146 echo $karma->getNbPosVotes();
\r
1149 echo $karma->getNbNegVotes();
\r
1152 echo $karma->getNbOfVotes();
\r
1155 $percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbPosVotes() / $karma->getNbOfVotes()) : 50;
\r
1156 echo number_format($percentage,2), '%';
\r
1159 $percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbNegVotes() / $karma->getNbOfVotes()) : 50;
\r
1160 echo number_format($percentage,2), '%';
\r
1162 case 'totalscore':
\r
1164 echo $karma->getTotalScore();
\r
1170 function parse_author($which = '') {
\r
1174 echo $this->currentItem->authorname;
\r
1177 echo $this->currentItem->authorid;
\r
1180 echo $this->currentItem->authormail;
\r
1183 echo $this->currentItem->authorurl;
\r
1187 echo $this->currentItem->author;
\r
1191 function parse_smartbody() {
\r
1192 if (!$this->currentItem->more) {
\r
1193 $this->highlightAndParse($this->currentItem->body);
\r
1195 $this->highlightAndParse($this->currentItem->more);
\r
1199 function parse_morelink() {
\r
1200 if ($this->currentItem->more)
\r
1201 $this->parser->parse($this->template['MORELINK']);
\r
1204 function parse_date($format = '') {
\r
1205 echo formatDate($format, $this->currentItem->timestamp, $this->template['FORMAT_DATE']);
\r
1209 * @param format optional strftime format
\r
1211 function parse_time($format = '') {
\r
1212 echo strftime($format ? $format : $this->template['FORMAT_TIME'],$this->currentItem->timestamp);
\r
1216 * @param maxLength optional maximum length
\r
1218 function parse_syndicate_title($maxLength = 100) {
\r
1219 $syndicated = strip_tags($this->currentItem->title);
\r
1220 echo htmlspecialchars(shorten($syndicated,$maxLength,'...'));
\r
1224 * @param maxLength optional maximum length
\r
1226 function parse_syndicate_description($maxLength = 250, $addHighlight = 0) {
\r
1227 $syndicated = strip_tags($this->currentItem->body);
\r
1228 if ($addHighlight) {
\r
1229 echo $this->highlightAndParse(htmlspecialchars(shorten($syndicated,$maxLength,'...')));
\r
1231 echo htmlspecialchars(shorten($syndicated,$maxLength,'...'));
\r
1235 function parse_karmaposlink($text = '') {
\r
1237 $link = $CONF['ActionURL'] . '?action=votepositive&itemid='.$this->currentItem->itemid;
\r
1238 echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
\r
1241 function parse_karmaneglink($text = '') {
\r
1243 $link = $CONF['ActionURL'] . '?action=votenegative&itemid='.$this->currentItem->itemid;
\r
1244 echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
\r
1247 function parse_new() {
\r
1248 if (($this->lastVisit != 0) && ($this->currentItem->timestamp > $this->lastVisit))
\r
1249 echo $this->template['NEW'];
\r
1252 function parse_image() {
\r
1253 // image/popup calls have arguments separated by |
\r
1254 $args = func_get_args();
\r
1255 $args = explode('|',implode($args,', '));
\r
1256 call_user_func_array(array(&$this,'createImageCode'),$args);
\r
1258 function parse_popup() {
\r
1259 // image/popup calls have arguments separated by |
\r
1260 $args = func_get_args();
\r
1261 $args = explode('|',implode($args,', '));
\r
1262 call_user_func_array(array(&$this,'createPopupCode'),$args);
\r
1264 function parse_media() {
\r
1265 // image/popup calls have arguments separated by |
\r
1266 $args = func_get_args();
\r
1267 $args = explode('|',implode($args,', '));
\r
1268 call_user_func_array(array(&$this,'createMediaCode'),$args);
\r
1271 function parse_daylink() {
\r
1272 echo createArchiveLink($this->blog->getID(), strftime('%Y-%m-%d',$this->currentItem->timestamp), $this->linkparams);
\r
1275 function parse_comments($maxToShow = 0) {
\r
1276 if ($maxToShow == 0)
\r
1277 $maxToShow = $this->blog->getMaxComments();
\r
1280 if ($this->showComments && $this->blog->commentsEnabled()) {
\r
1281 $comments =& new COMMENTS($this->currentItem->itemid);
\r
1282 $comments->setItemActions($this);
\r
1283 $comments->showComments($this->template, $maxToShow, $this->currentItem->closed ? 0 : 1, $this->strHighlight);
\r
1288 * Executes a plugin templatevar
\r
1290 * @param pluginName name of plugin (without the NP_)
\r
1292 * extra parameters can be added
\r
1294 function parse_plugin($pluginName) {
\r
1297 // only continue when the plugin is really installed
\r
1298 if (!$manager->pluginInstalled('NP_' . $pluginName))
\r
1301 $plugin =& $manager->getPlugin('NP_' . $pluginName);
\r
1302 if (!$plugin) return;
\r
1305 $params = func_get_args();
\r
1307 // remove plugin name
\r
1308 array_shift($params);
\r
1310 // add item reference (array_unshift didn't work)
\r
1311 $params = array_merge(array(&$this->currentItem),$params);
\r
1313 call_user_func_array(array(&$plugin,'doTemplateVar'), $params);
\r
1316 function parse_edit() {
\r
1317 global $member, $CONF;
\r
1318 if ($this->allowEditAll || ($member->isLoggedIn() && ($member->getID() == $this->currentItem->authorid)) ) {
\r
1319 $this->parser->parse($this->template['EDITLINK']);
\r
1323 function parse_editlink() {
\r
1325 echo $CONF['AdminURL'],'bookmarklet.php?action=edit&itemid=',$this->currentItem->itemid;
\r
1328 function parse_editpopupcode() {
\r
1329 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
1332 // helper functions
\r
1335 * Parses highlighted text, with limited actions only (to prevent not fully trusted team members
\r
1336 * from hacking your weblog.
\r
1338 function highlightAndParse(&$data) {
\r
1339 // allow only a limited subset of actions (do not allow includes etc, they might be evil)
\r
1340 $this->parser->actions = array('image','media','popup');
\r
1341 $this->parser->parse($this->highlight($data));
\r
1342 $this->parser->actions = $this->getDefinedActions();
\r
1345 function createPopupCode($filename, $width, $height, $text = '') {
\r
1348 // select private collection when no collection given
\r
1349 if (!strstr($filename,'/')) {
\r
1350 $filename = $this->currentItem->authorid . '/' . $filename;
\r
1353 $windowwidth = $width;
\r
1354 $windowheight = $height;
\r
1356 $vars['rawpopuplink'] = $CONF['Self'] . "?imagepopup=" . htmlspecialchars($filename) . "&width=$width&height=$height&imagetext=" . urlencode(htmlspecialchars($text));
\r
1357 $vars['popupcode'] = "window.open(this.href,'imagepopup','status=no,toolbar=no,scrollbars=no,resizable=yes,width=$windowwidth,height=$windowheight');return false;";
\r
1358 $vars['popuptext'] = htmlspecialchars($text);
\r
1359 $vars['popuplink'] = '<a href="' . $vars['rawpopuplink']. '" onclick="'. $vars['popupcode'].'" >' . $vars['popuptext'] . '</a>';
\r
1360 $vars['width'] = $width;
\r
1361 $vars['height'] = $height;
\r
1362 $vars['text'] = $text;
\r
1364 echo TEMPLATE::fill($this->template['POPUP_CODE'],$vars);
\r
1367 function createImageCode($filename, $width, $height, $text = '') {
\r
1370 // select private collection when no collection given
\r
1371 if (!strstr($filename,'/')) {
\r
1372 $filename = $this->currentItem->authorid . '/' . $filename;
\r
1375 $windowwidth = $width;
\r
1376 $windowheight = $height;
\r
1378 $vars['link'] = htmlspecialchars($CONF['MediaURL']. $filename);
\r
1379 $vars['text'] = htmlspecialchars($text);
\r
1380 $vars['image'] = '<img src="' . $vars['link'] . '" width="' . $width . '" height="' . $height . '" alt="' . $vars['text'] . '" title="' . $vars['text'] . '" />';
\r
1381 $vars['width'] = $width;
\r
1382 $vars['height'] = $height;
\r
1386 echo TEMPLATE::fill($this->template['IMAGE_CODE'],$vars);;
\r
1390 function createMediaCode($filename, $text = '') {
\r
1393 // select private collection when no collection given
\r
1394 if (!strstr($filename,'/')) {
\r
1395 $filename = $this->currentItem->authorid . '/' . $filename;
\r
1398 $vars['link'] = htmlspecialchars($CONF['MediaURL'] . $filename);
\r
1399 $vars['text'] = htmlspecialchars($text);
\r
1400 $vars['media'] = '<a href="' . $vars['link'] . '">' . $vars['text'] . '</a>';
\r
1402 echo TEMPLATE::fill($this->template['MEDIA_CODE'],$vars);;
\r
1409 // used for mail notification (html -> text)
\r
1411 function toAscii($html) {
\r
1412 // strip off most tags
\r
1413 $html = strip_tags($html,'<a>');
\r
1414 $to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i";
\r
1416 $ascii = preg_replace_callback ($to_replace, '_links_add', $html);
\r
1417 $ascii .= "\n\n" . _links_list();
\r
1418 return strip_tags($ascii);
\r
1421 function _links_init() {
\r
1422 global $tmp_links;
\r
1423 $tmp_links = array();
\r
1426 function _links_add($match) {
\r
1427 global $tmp_links;
\r
1428 array_push($tmp_links, $match[1]);
\r
1429 return $match[2] . ' [' . sizeof($tmp_links) .']';
\r
1432 function _links_list() {
\r
1433 global $tmp_links;
\r
1436 foreach ($tmp_links as $current) {
\r
1437 $output .= "[$i] $current\n";
\r