Dotclear

source: inc/core/class.dc.blog.php @ 1280:d9627cb1cb02

Revision 1280:d9627cb1cb02, 59.7 KB checked in by Dsls, 11 years ago (diff)

Backed out merge changeset: 48c827f9db99

Backed out merge revision to its first parent (5ceeeb6f5454)

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14/**
15@ingroup DC_CORE
16@nosubgrouping
17@brief Dotclear blog class.
18
19Dotclear blog class instance is provided by dcCore $blog property.
20*/
21class dcBlog
22{
23     /** @var dcCore dcCore instance */
24     protected $core;
25     /** @var connection Database connection object */
26     public $con;
27     /** @var string Database table prefix */
28     public $prefix;
29     
30     /** @var string Blog ID */
31     public $id;
32     /** @var string Blog unique ID */
33     public $uid;
34     /** @var string Blog name */
35     public $name;
36     /** @var string Blog description */
37     public $desc;
38     /** @var string Blog URL */
39     public $url;
40     /** @var string Blog host */
41     public $host;
42     /** @var string Blog creation date */
43     public $creadt;
44     /** @var string Blog last update date */
45     public $upddt;
46     /** @var string Blog status */
47     public $status;
48     
49     /** @var dcSettings dcSettings object */
50     public $settings;
51     /** @var string Blog theme path */
52     public $themes_path;
53     /** @var string Blog public path */
54     public $public_path;
55     
56     private $post_status = array();
57     private $comment_status = array();
58     
59     private $categories;
60     
61     /** @var boolean Disallow entries password protection */
62     public $without_password = true;
63     
64     /**
65     Inits dcBlog object
66     
67     @param    core      <b>dcCore</b>       Dotclear core reference
68     @param    id        <b>string</b>       Blog ID
69     */
70     public function __construct($core, $id)
71     {
72          $this->con =& $core->con;
73          $this->prefix = $core->prefix;
74          $this->core =& $core;
75         
76          if (($b = $this->core->getBlog($id)) !== false)
77          {
78               $this->id = $id;
79               $this->uid = $b->blog_uid;
80               $this->name = $b->blog_name;
81               $this->desc = $b->blog_desc;
82               $this->url = $b->blog_url;
83               $this->host = http::getHostFromURL($this->url);
84               $this->creadt = strtotime($b->blog_creadt);
85               $this->upddt = strtotime($b->blog_upddt);
86               $this->status = $b->blog_status;
87               
88               $this->settings = new dcSettings($this->core,$this->id);
89               
90               $this->themes_path = path::fullFromRoot($this->settings->system->themes_path,DC_ROOT);
91               $this->public_path = path::fullFromRoot($this->settings->system->public_path,DC_ROOT);
92               
93               $this->post_status['-2'] = __('pending');
94               $this->post_status['-1'] = __('scheduled');
95               $this->post_status['0'] = __('unpublished');
96               $this->post_status['1'] = __('published');
97               
98               $this->comment_status['-2'] = __('junk');
99               $this->comment_status['-1'] = __('pending');
100               $this->comment_status['0'] = __('unpublished');
101               $this->comment_status['1'] = __('published');
102               
103               # --BEHAVIOR-- coreBlogConstruct
104               $this->core->callBehavior('coreBlogConstruct',$this);
105          }
106     }
107     
108     /// @name Common public methods
109     //@{
110     /**
111     Returns blog URL ending with a question mark.
112     */
113     public function getQmarkURL()
114     {
115          if (substr($this->url,-1) != '?') {
116               return $this->url.'?';
117          }
118         
119          return $this->url;
120     }
121     
122     /**
123     Returns an entry status name given to a code. Status are translated, never
124     use it for tests. If status code does not exist, returns <i>unpublished</i>.
125     
126     @param    s    <b>integer</b> Status code
127     @return   <b>string</b> Blog status name
128     */
129     public function getPostStatus($s)
130     {
131          if (isset($this->post_status[$s])) {
132               return $this->post_status[$s];
133          }
134          return $this->post_status['0'];
135     }
136     
137     /**
138     Returns an array of available entry status codes and names.
139     
140     @return   <b>array</b> Simple array with codes in keys and names in value
141     */
142     public function getAllPostStatus()
143     {
144          return $this->post_status;
145     }
146     
147     /**
148     Returns an array of available comment status codes and names.
149     
150     @return   <b>array</b> Simple array with codes in keys and names in value
151     */
152     public function getAllCommentStatus()
153     {
154          return $this->comment_status;
155     }
156     
157     /**
158     Disallows entries password protection. You need to set it to
159     <var>false</var> while serving a public blog.
160     
161     @param    v         <b>boolean</b>
162     */
163     public function withoutPassword($v)
164     {
165          $this->without_password = (boolean) $v;
166     }
167     //@}
168     
169     /// @name Triggers methods
170     //@{
171     /**
172     Updates blog last update date. Should be called every time you change
173     an element related to the blog.
174     */
175     public function triggerBlog()
176     {
177          $cur = $this->con->openCursor($this->prefix.'blog');
178         
179          $cur->blog_upddt = date('Y-m-d H:i:s');
180         
181          $cur->update("WHERE blog_id = '".$this->con->escape($this->id)."' ");
182         
183          # --BEHAVIOR-- coreBlogAfterTriggerBlog
184          $this->core->callBehavior('coreBlogAfterTriggerBlog',$cur);
185     }
186     
187     /**
188     Updates comment and trackback counters in post table. Should be called
189     every time a comment or trackback is added, removed or changed its status.
190     
191     @param    id        <b>integer</b>      Comment ID
192     @param    del       <b>boolean</b>      If comment is delete, set this to true
193     */
194     public function triggerComment($id,$del=false)
195     {
196          $this->triggerComments($id,$del);
197     }
198     
199     /**
200     Updates comments and trackbacks counters in post table. Should be called
201     every time comments or trackbacks are added, removed or changed there status.
202     
203     @param    ids       <b>mixed</b>        Comment(s) ID(s)
204     @param    del       <b>boolean</b>      If comment is delete, set this to true
205     */
206     public function triggerComments($ids,$del=false)
207     {
208          $co_ids = dcUtils::cleanIds($ids);
209         
210          # a) Retrieve posts affected by comments edition
211          $strReq = 
212               'SELECT post_id, comment_trackback '.
213               'FROM '.$this->prefix.'comment '.
214               'WHERE comment_id'.$this->con->in($co_ids).
215               'GROUP BY post_id,comment_trackback';
216         
217          $rs = $this->con->select($strReq);
218         
219          $a_ids = $a_tbs = array();
220          while ($rs->fetch()) {
221               $a_ids[] = (integer) $rs->post_id;
222               $a_tbs[] = (integer) $rs->comment_trackback;
223          }
224         
225          # b) Count comments of each posts previously retrieved
226          # Note that this does not return posts without comment
227          $strReq = 
228               'SELECT post_id, COUNT(post_id) AS nb_comment,comment_trackback '.
229               'FROM '.$this->prefix.'comment '.
230               'WHERE comment_status = 1 '.
231               (count($a_ids) > 0 ? 'AND post_id'.$this->con->in($a_ids) : ' ');
232         
233          if ($del) {
234               $strReq .= 
235                    'AND comment_id NOT'.$this->con->in($co_ids);
236          }
237         
238          $strReq .= 
239               'GROUP BY post_id,comment_trackback';
240         
241          $rs = $this->con->select($strReq);
242         
243          $b_ids = $b_tbs = $b_nbs = array();
244          while ($rs->fetch()) {
245               $b_ids[] = (integer) $rs->post_id;
246               $b_tbs[] = (integer) $rs->comment_trackback;
247               $b_nbs[] = (integer) $rs->nb_comment;
248          }
249         
250          # c) Update comments numbers on posts
251          # This compare previous requests to update also posts without comment
252          $cur = $this->con->openCursor($this->prefix.'post');
253         
254          foreach($a_ids as $a_key => $a_id)
255          {
256               $nb_comment = $nb_trackback = 0;
257               foreach($b_ids as $b_key => $b_id)
258               {
259                    if ($a_id != $b_id || $a_tbs[$a_key] != $b_tbs[$b_key]) {
260                         continue;
261                    }
262                   
263                    if ($b_tbs[$b_key]) {
264                         $nb_trackback = $b_nbs[$b_key];
265                    } else {
266                         $nb_comment = $b_nbs[$b_key];
267                    }
268               }
269               
270               if ($a_tbs[$a_key]) {
271                    $cur->nb_trackback = $nb_trackback;
272               } else {
273                    $cur->nb_comment = $nb_comment;
274               }
275               $cur->update('WHERE post_id = '.$a_id);
276          }
277     }
278     //@}
279     
280     /// @name Categories management methods
281     //@{
282     public function categories()
283     {
284          if (!($this->categories instanceof dcCategories)) {
285               $this->categories = new dcCategories($this->core);
286          }
287         
288          return $this->categories;
289     }
290     
291     /**
292     Retrieves categories. <var>$params</var> is an associative array which can
293     take the following parameters:
294     
295     - post_type: Get only entries with given type (default "post")
296     - cat_url: filter on cat_url field
297     - cat_id: filter on cat_id field
298     - start: start with a given category
299     - level: categories level to retrieve
300     
301     @param    params    <b>array</b>        Parameters
302     @return   <b>record</b>
303     */
304     public function getCategories($params=array())
305     {
306          $c_params = array();
307          if (isset($params['post_type'])) {
308               $c_params['post_type'] = $params['post_type'];
309               unset($params['post_type']);
310          }
311          $counter = $this->getCategoriesCounter($c_params);
312         
313          $without_empty = $this->core->auth->userID() == false; # For public display
314         
315          $start = isset($params['start']) ? (integer) $params['start'] : 0;
316          $l = isset($params['level']) ? (integer) $params['level'] : 0;
317         
318          $rs = $this->categories()->getChildren($start,null,'desc');
319         
320          # Get each categories total posts count
321          $data = array();
322          $stack = array();
323          $level = 0;
324          $cols = $rs->columns();
325          while ($rs->fetch())
326          {
327               $nb_post = isset($counter[$rs->cat_id]) ? (integer) $counter[$rs->cat_id] : 0;
328               
329               if ($rs->level > $level) {
330                    $nb_total = $nb_post;
331                    $stack[$rs->level] = (integer) $nb_post;
332               } elseif ($rs->level == $level) {
333                    $nb_total = $nb_post;
334                    $stack[$rs->level] += $nb_post;
335               } else {
336                    $nb_total = $stack[$rs->level+1] + $nb_post;
337                    if (isset($stack[$rs->level])) {
338                         $stack[$rs->level] += $nb_total;
339                    } else {
340                         $stack[$rs->level] = $nb_total;
341                    }
342                    unset($stack[$rs->level+1]);
343               }
344               
345               if ($nb_total == 0 && $without_empty) {
346                    continue;
347               }
348               
349               $level = $rs->level;
350               
351               $t = array();
352               foreach ($cols as $c) {
353                    $t[$c] = $rs->f($c);
354               }
355               $t['nb_post'] = $nb_post;
356               $t['nb_total'] = $nb_total;
357               
358               if ($l == 0 || ($l > 0 && $l == $rs->level)) {
359                    array_unshift($data,$t);
360               }
361          }
362         
363          # We need to apply filter after counting
364          if (isset($params['cat_id']) && $params['cat_id'] !== '')
365          {
366               $found = false;
367               foreach ($data as $v) {
368                    if ($v['cat_id'] == $params['cat_id']) {
369                         $found = true;
370                         $data = array($v);
371                         break;
372                    }
373               }
374               if (!$found) {
375                    $data = array();
376               }
377          }
378         
379          if (isset($params['cat_url']) && ($params['cat_url'] !== '') 
380               && !isset($params['cat_id']))
381          {
382               $found = false;
383               foreach ($data as $v) {
384                    if ($v['cat_url'] == $params['cat_url']) {
385                         $found = true;
386                         $data = array($v);
387                         break;
388                    }
389               }
390               if (!$found) {
391                    $data = array();
392               }
393          }
394         
395          return staticRecord::newFromArray($data);
396     }
397     
398     /**
399     Retrieves a category by its ID.
400     
401     @param    id        <b>integer</b>      Category ID
402     @return   <b>record</b>
403     */
404     public function getCategory($id)
405     {
406          return $this->getCategories(array('cat_id' => $id));
407     }
408     
409     /**
410     Retrieves parents of a given category.
411     
412     @param    id        <b>integer</b>      Category ID
413     @return   <b>record</b>
414     */
415     public function getCategoryParents($id)
416     {
417          return $this->categories()->getParents($id);
418     }
419     
420     /**
421     Retrieves first parent of a given category.
422     
423     @param    id        <b>integer</b>      Category ID
424     @return   <b>record</b>
425     */
426     public function getCategoryParent($id)
427     {
428          return $this->categories()->getParent($id);
429     }
430     
431     /**
432     Retrieves all category's first children
433     
434     @param    id        <b>integer</b>      Category ID
435     @return   <b>record</b>
436     */
437     public function getCategoryFirstChildren($id)
438     {
439          return $this->getCategories(array('start' => $id,'level' => $id == 0 ? 1 : 2));
440     }
441     
442     private function getCategoriesCounter($params=array())
443     {
444          $strReq =
445          'SELECT  C.cat_id, COUNT(P.post_id) AS nb_post '.
446          'FROM '.$this->prefix.'category AS C '.
447          'JOIN '.$this->prefix."post P ON (C.cat_id = P.cat_id AND P.blog_id = '".$this->con->escape($this->id)."' ) ".
448          "WHERE C.blog_id = '".$this->con->escape($this->id)."' ";
449         
450          if (!$this->core->auth->userID()) {
451               $strReq .= 'AND P.post_status = 1 ';
452          }
453         
454          if (!empty($params['post_type'])) {
455               $strReq .= 'AND P.post_type '.$this->con->in($params['post_type']);
456          }
457         
458          $strReq .= 'GROUP BY C.cat_id ';
459         
460          $rs = $this->con->select($strReq);
461          $counters = array();
462          while ($rs->fetch()) {
463               $counters[$rs->cat_id] = $rs->nb_post;
464          }
465         
466          return $counters;
467     }
468     
469     /**
470     Creates a new category. Takes a cursor as input and returns the new category
471     ID.
472     
473     @param    cur       <b>cursor</b>       Category cursor
474     @return   <b>integer</b>      New category ID
475     */
476     public function addCategory($cur,$parent=0)
477     {
478          if (!$this->core->auth->check('categories',$this->id)) {
479               throw new Exception(__('You are not allowed to add categories'));
480          }
481         
482          $url = array();
483          if ($parent != 0)
484          {
485               $rs = $this->getCategory($parent);
486               if ($rs->isEmpty()) {
487                    $url = array();
488               } else {
489                    $url[] = $rs->cat_url;
490               }
491          }
492         
493          if ($cur->cat_url == '') {
494               $url[] = text::tidyURL($cur->cat_title,false);
495          } else {
496               $url[] = $cur->cat_url;
497          }
498         
499          $cur->cat_url = implode('/',$url);
500         
501          $this->getCategoryCursor($cur);
502          $cur->blog_id = (string) $this->id;
503         
504          # --BEHAVIOR-- coreBeforeCategoryCreate
505          $this->core->callBehavior('coreBeforeCategoryCreate',$this,$cur);
506         
507          $this->categories()->addNode($cur,$parent);
508         
509          # --BEHAVIOR-- coreAfterCategoryCreate
510          $this->core->callBehavior('coreAfterCategoryCreate',$this,$cur);
511          $this->triggerBlog();
512         
513          return $cur->cat_id;
514     }
515     
516     /**
517     Updates an existing category.
518     
519     @param    id        <b>integer</b>      Category ID
520     @param    cur       <b>cursor</b>       Category cursor
521     */
522     public function updCategory($id,$cur)
523     {
524          if (!$this->core->auth->check('categories',$this->id)) {
525               throw new Exception(__('You are not allowed to update categories'));
526          }
527         
528          if ($cur->cat_url == '')
529          {
530               $url = array();
531               $rs = $this->categories()->getParents($id);
532               while ($rs->fetch()) {
533                    if ($rs->index() == $rs->count()-1) {
534                         $url[] = $rs->cat_url;
535                    }
536               }
537               
538               
539               $url[] = text::tidyURL($cur->cat_title,false);
540               $cur->cat_url = implode('/',$url);
541          }
542         
543          $this->getCategoryCursor($cur,$id);
544         
545          # --BEHAVIOR-- coreBeforeCategoryUpdate
546          $this->core->callBehavior('coreBeforeCategoryUpdate',$this,$cur);
547         
548          $cur->update(
549          'WHERE cat_id = '.(integer) $id.' '.
550          "AND blog_id = '".$this->con->escape($this->id)."' ");
551         
552          # --BEHAVIOR-- coreAfterCategoryUpdate
553          $this->core->callBehavior('coreAfterCategoryUpdate',$this,$cur);
554         
555          $this->triggerBlog();
556     }
557     
558     /**
559     DEPRECATED METHOD. Use dcBlog::setCategoryParent and dcBlog::moveCategory
560     instead.
561     
562     @param    id        <b>integer</b>      Category ID
563     @param    order     <b>integer</b>      Category position
564     */
565     public function updCategoryOrder($id,$order)
566     {
567          return;
568     }
569     
570     /**
571     Set a category parent
572     
573     @param    id        <b>integer</b>      Category ID
574     @param    parent    <b>integer</b>      Parent Category ID
575     */
576     public function setCategoryParent($id,$parent)
577     {
578          $this->categories()->setNodeParent($id,$parent);
579          $this->triggerBlog();
580     }
581     
582     /**
583     Set category position
584     
585     @param    id        <b>integer</b>      Category ID
586     @param    sibling   <b>integer</b>      Sibling Category ID
587     @param    move      <b>integer</b>      Order (before|after)
588     */
589     public function setCategoryPosition($id,$sibling,$move)
590     {
591          $this->categories()->setNodePosition($id,$sibling,$move);
592          $this->triggerBlog();
593     }
594     
595     /**
596     Deletes a category.
597     
598     @param    id        <b>integer</b>      Category ID
599     */
600     public function delCategory($id)
601     {
602          if (!$this->core->auth->check('categories',$this->id)) {
603               throw new Exception(__('You are not allowed to delete categories'));
604          }
605         
606          $strReq = 'SELECT COUNT(post_id) AS nb_post '.
607                    'FROM '.$this->prefix.'post '.
608                    'WHERE cat_id = '.(integer) $id.' '.
609                    "AND blog_id = '".$this->con->escape($this->id)."' ";
610         
611          $rs = $this->con->select($strReq);
612         
613          if ($rs->nb_post > 0) {
614               throw new Exception(__('This category is not empty.'));
615          }
616         
617          $this->categories()->deleteNode($id,true);
618          $this->triggerBlog();
619     }
620     
621     /**
622     Reset categories order and relocate them to first level
623     */
624     public function resetCategoriesOrder()
625     {
626          if (!$this->core->auth->check('categories',$this->id)) {
627               throw new Exception(__('You are not allowed to reset categories order'));
628          }
629         
630          $this->categories()->resetOrder();
631          $this->triggerBlog();
632     }
633     
634     private function checkCategory($title,$url,$id=null)
635     {
636          $strReq = 'SELECT cat_id '.
637                    'FROM '.$this->prefix.'category '.
638                    "WHERE cat_url = '".$this->con->escape($url)."' ".
639                    "AND blog_id = '".$this->con->escape($this->id)."' ";
640         
641          if ($id !== null) {
642               $strReq .= 'AND cat_id <> '.(integer) $id.' ';
643          }
644         
645          $rs = $this->con->select($strReq);
646         
647          if (!$rs->isEmpty()) {
648               throw new Exception(__('Category URL must be unique.'));
649          }
650     }
651     
652     private function getCategoryCursor($cur,$id=null)
653     {
654          if ($cur->cat_title == '') {
655               throw new Exception(__('You must provide a category title'));
656          }
657         
658          # If we don't have any cat_url, let's do one
659          if ($cur->cat_url == '') {
660               $cur->cat_url = text::tidyURL($cur->cat_title,false);
661          }
662         
663          # Still empty ?
664          if ($cur->cat_url == '') {
665               throw new Exception(__('You must provide a category URL'));
666          } else {
667               $cur->cat_url = text::tidyURL($cur->cat_url,true);
668          }
669         
670          # Check if title or url are unique
671          $this->checkCategory($cur->cat_title,$cur->cat_url,$id);
672         
673          if ($cur->cat_desc !== null) {
674               $cur->cat_desc = $this->core->HTMLfilter($cur->cat_desc);
675          }
676     }
677     //@}
678     
679     /// @name Entries management methods
680     //@{
681     /**
682     Retrieves entries. <b>$params</b> is an array taking the following
683     optionnal parameters:
684     
685     - no_content: Don't retrieve entry content (excerpt and content)
686     - post_type: Get only entries with given type (default "post", array for many types and '' for no type)
687     - post_id: (integer) Get entry with given post_id
688     - post_url: Get entry with given post_url field
689     - user_id: (integer) Get entries belonging to given user ID
690     - cat_id: (string or array) Get entries belonging to given category ID
691     - cat_id_not: deprecated (use cat_id with "id ?not" instead)
692     - cat_url: (string or array) Get entries belonging to given category URL
693     - cat_url_not: deprecated (use cat_url with "url ?not" instead)
694     - post_status: (integer) Get entries with given post_status
695     - post_selected: (boolean) Get select flaged entries
696     - post_year: (integer) Get entries with given year
697     - post_month: (integer) Get entries with given month
698     - post_day: (integer) Get entries with given day
699     - post_lang: Get entries with given language code
700     - search: Get entries corresponding of the following search string
701     - columns: (array) More columns to retrieve
702     - sql: Append SQL string at the end of the query
703     - from: Append SQL string after "FROM" statement in query
704     - order: Order of results (default "ORDER BY post_dt DES")
705     - limit: Limit parameter
706     - sql_only : return the sql request instead of results. Only ids are selected
707     
708     Please note that on every cat_id or cat_url, you can add ?not to exclude
709     the category and ?sub to get subcategories.
710     
711     @param    params         <b>array</b>        Parameters
712     @param    count_only     <b>boolean</b>      Only counts results
713     @return   <b>record</b>  A record with some more capabilities or the SQL request
714     */
715     public function getPosts($params=array(),$count_only=false)
716     {
717          # --BEHAVIOR-- coreBlogBeforeGetPosts
718          $params = new ArrayObject($params);
719          $this->core->callBehavior('coreBlogBeforeGetPosts',$params);
720
721          if ($count_only)
722          {
723               $strReq = 'SELECT count(P.post_id) ';
724          }
725          elseif (!empty($params['sql_only'])) 
726          {
727               $strReq = 'SELECT P.post_id ';
728          }
729          else
730          {
731               if (!empty($params['no_content'])) {
732                    $content_req = '';
733               } else {
734                    $content_req =
735                    'post_excerpt, post_excerpt_xhtml, '.
736                    'post_content, post_content_xhtml, post_notes, ';
737               }
738               
739               if (!empty($params['columns']) && is_array($params['columns'])) {
740                    $content_req .= implode(', ',$params['columns']).', ';
741               }
742               
743               $strReq =
744               'SELECT P.post_id, P.blog_id, P.user_id, P.cat_id, post_dt, '.
745               'post_tz, post_creadt, post_upddt, post_format, post_password, '.
746               'post_url, post_lang, post_title, '.$content_req.
747               'post_type, post_meta, post_status, post_selected, post_position, '.
748               'post_open_comment, post_open_tb, nb_comment, nb_trackback, '.
749               'U.user_name, U.user_firstname, U.user_displayname, U.user_email, '.
750               'U.user_url, '.
751               'C.cat_title, C.cat_url, C.cat_desc ';
752          }
753         
754          $strReq .=
755          'FROM '.$this->prefix.'post P '.
756          'INNER JOIN '.$this->prefix.'user U ON U.user_id = P.user_id '.
757          'LEFT OUTER JOIN '.$this->prefix.'category C ON P.cat_id = C.cat_id ';
758         
759          if (!empty($params['from'])) {
760               $strReq .= $params['from'].' ';
761          }
762         
763          $strReq .=
764          "WHERE P.blog_id = '".$this->con->escape($this->id)."' ";
765         
766          if (!$this->core->auth->check('contentadmin',$this->id)) {
767               $strReq .= 'AND ((post_status = 1 ';
768               
769               if ($this->without_password) {
770                    $strReq .= 'AND post_password IS NULL ';
771               }
772               $strReq .= ') ';
773               
774               if ($this->core->auth->userID()) {
775                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
776               } else {
777                    $strReq .= ') ';
778               }
779          }
780         
781          #Adding parameters
782          if (isset($params['post_type']))
783          {
784               if (is_array($params['post_type']) || $params['post_type'] != '') {
785                    $strReq .= 'AND post_type '.$this->con->in($params['post_type']);
786               }
787          }
788          else
789          {
790               $strReq .= "AND post_type = 'post' ";
791          }
792         
793          if (isset($params['post_id']) && $params['post_id'] !== '') {
794               if (is_array($params['post_id'])) {
795                    array_walk($params['post_id'],create_function('&$v,$k','if($v!==null){$v=(integer)$v;}'));
796               } else {
797                    $params['post_id'] = array((integer) $params['post_id']);
798               }
799               $strReq .= 'AND P.post_id '.$this->con->in($params['post_id']);
800          }
801         
802          if (isset($params['post_url']) && $params['post_url'] !== '') {
803               $strReq .= "AND post_url = '".$this->con->escape($params['post_url'])."' ";
804          }
805         
806          if (!empty($params['user_id'])) {
807               $strReq .= "AND U.user_id = '".$this->con->escape($params['user_id'])."' ";
808          }
809         
810          if (isset($params['cat_id']) && $params['cat_id'] !== '')
811          {
812               if (!is_array($params['cat_id'])) {
813                    $params['cat_id'] = array($params['cat_id']);
814               }
815               if (!empty($params['cat_id_not'])) {
816                    array_walk($params['cat_id'],create_function('&$v,$k','$v=$v." ?not";'));
817               }
818               $strReq .= 'AND '.$this->getPostsCategoryFilter($params['cat_id'],'cat_id').' ';
819          }
820          elseif (isset($params['cat_url']) && $params['cat_url'] !== '')
821          {
822               if (!is_array($params['cat_url'])) {
823                    $params['cat_url'] = array($params['cat_url']);
824               }
825               if (!empty($params['cat_url_not'])) {
826                    array_walk($params['cat_url'],create_function('&$v,$k','$v=$v." ?not";'));
827               }
828               $strReq .= 'AND '.$this->getPostsCategoryFilter($params['cat_url'],'cat_url').' ';
829          }
830         
831          /* Other filters */
832          if (isset($params['post_status'])) {
833               $strReq .= 'AND post_status = '.(integer) $params['post_status'].' ';
834          }
835         
836          if (isset($params['post_selected'])) {
837               $strReq .= 'AND post_selected = '.(integer) $params['post_selected'].' ';
838          }
839         
840          if (!empty($params['post_year'])) {
841               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%Y').' = '.
842               "'".sprintf('%04d',$params['post_year'])."' ";
843          }
844         
845          if (!empty($params['post_month'])) {
846               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%m').' = '.
847               "'".sprintf('%02d',$params['post_month'])."' ";
848          }
849         
850          if (!empty($params['post_day'])) {
851               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%d').' = '.
852               "'".sprintf('%02d',$params['post_day'])."' ";
853          }
854         
855          if (!empty($params['post_lang'])) {
856               $strReq .= "AND P.post_lang = '".$this->con->escape($params['post_lang'])."' ";
857          }
858         
859          if (!empty($params['search']))
860          {
861               $words = text::splitWords($params['search']);
862               
863               if (!empty($words))
864               {
865                    # --BEHAVIOR-- corePostSearch
866                    if ($this->core->hasBehavior('corePostSearch')) {
867                         $this->core->callBehavior('corePostSearch',$this->core,array(&$words,&$strReq,&$params));
868                    }
869                   
870                    if ($words)
871                    {
872                         foreach ($words as $i => $w) {
873                              $words[$i] = "post_words LIKE '%".$this->con->escape($w)."%'";
874                         }
875                         $strReq .= 'AND '.implode(' AND ',$words).' ';
876                    }
877               }
878          }
879         
880          if (!empty($params['sql'])) {
881               $strReq .= $params['sql'].' ';
882          }
883         
884          if (!$count_only)
885          {
886               if (!empty($params['order'])) {
887                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
888               } else {
889                    $strReq .= 'ORDER BY post_dt DESC ';
890               }
891          }
892         
893          if (!$count_only && !empty($params['limit'])) {
894               $strReq .= $this->con->limit($params['limit']);
895          }
896         
897          if (!empty($params['sql_only'])) {
898               return $strReq;
899          }
900         
901          $rs = $this->con->select($strReq);
902          $rs->core = $this->core;
903          $rs->_nb_media = array();
904          $rs->extend('rsExtPost');
905         
906          # --BEHAVIOR-- coreBlogGetPosts
907          $this->core->callBehavior('coreBlogGetPosts',$rs);
908         
909          return $rs;
910     }
911     
912     /**
913     Returns a record with post id, title and date for next or previous post
914     according to the post ID.
915     $dir could be 1 (next post) or -1 (previous post).
916     
917     @param    post_id                  <b>integer</b>      Post ID
918     @param    dir                      <b>integer</b>      Search direction
919     @param    restrict_to_category     <b>boolean</b>      Restrict to post with same category
920     @param    restrict_to_lang         <b>boolean</b>      Restrict to post with same lang
921     @return   record
922     */
923     public function getNextPost($post,$dir,$restrict_to_category=false, $restrict_to_lang=false)
924     {
925          $dt = $post->post_dt;
926          $post_id = (integer) $post->post_id;
927         
928          if($dir > 0) {
929               $sign = '>';
930               $order = 'ASC';
931          }
932          else {
933               $sign = '<';
934               $order = 'DESC';
935          }
936         
937          $params['post_type'] = $post->post_type;
938          $params['limit'] = 1;
939          $params['order'] = 'post_dt '.$order.', P.post_id '.$order;
940          $params['sql'] =
941          'AND ( '.
942          "    (post_dt = '".$this->con->escape($dt)."' AND P.post_id ".$sign." ".$post_id.") ".
943          "    OR post_dt ".$sign." '".$this->con->escape($dt)."' ".
944          ') ';
945         
946          if ($restrict_to_category) {
947               $params['sql'] .= $post->cat_id ? 'AND P.cat_id = '.(integer) $post->cat_id.' ' : 'AND P.cat_id IS NULL ';
948          }
949         
950          if ($restrict_to_lang) {
951               $params['sql'] .= $post->post_lang ? 'AND P.post_lang = \''. $this->con->escape($post->post_lang) .'\' ': 'AND P.post_lang IS NULL ';
952          }
953         
954          $rs = $this->getPosts($params);
955         
956          if ($rs->isEmpty()) {
957               return null;
958          }
959         
960          return $rs;
961     }
962     
963     /**
964     Retrieves different languages and post count on blog, based on post_lang
965     field. <var>$params</var> is an array taking the following optionnal
966     parameters:
967     
968     - post_type: Get only entries with given type (default "post", '' for no type)
969     - lang: retrieve post count for selected lang
970     - order: order statement (default post_lang DESC)
971     
972     @param    params    <b>array</b>        Parameters
973     @return   record
974     */
975     public function getLangs($params=array())
976     {
977          $strReq = 'SELECT COUNT(post_id) as nb_post, post_lang '.
978                    'FROM '.$this->prefix.'post '.
979                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
980                    "AND post_lang <> '' ".
981                    "AND post_lang IS NOT NULL ";
982         
983          if (!$this->core->auth->check('contentadmin',$this->id)) {
984               $strReq .= 'AND ((post_status = 1 ';
985               
986               if ($this->without_password) {
987                    $strReq .= 'AND post_password IS NULL ';
988               }
989               $strReq .= ') ';
990               
991               if ($this->core->auth->userID()) {
992                    $strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."')";
993               } else {
994                    $strReq .= ') ';
995               }
996          }
997         
998          if (isset($params['post_type'])) {
999               if ($params['post_type'] != '') {
1000                    $strReq .= "AND post_type = '".$this->con->escape($params['post_type'])."' ";
1001               }
1002          } else {
1003               $strReq .= "AND post_type = 'post' ";
1004          }
1005         
1006          if (isset($params['lang'])) {
1007               $strReq .= "AND post_lang = '".$this->con->escape($params['lang'])."' ";
1008          }
1009         
1010          $strReq .= 'GROUP BY post_lang ';
1011         
1012          $order = 'desc';
1013          if (!empty($params['order']) && preg_match('/^(desc|asc)$/i',$params['order'])) {
1014               $order = $params['order'];
1015          }
1016          $strReq .= 'ORDER BY post_lang '.$order.' ';
1017         
1018          return $this->con->select($strReq);
1019     }
1020     
1021     /**
1022     Returns a record with all distinct blog dates and post count.
1023     <var>$params</var> is an array taking the following optionnal parameters:
1024     
1025     - type: (day|month|year) Get days, months or years
1026     - year: (integer) Get dates for given year
1027     - month: (integer) Get dates for given month
1028     - day: (integer) Get dates for given day
1029     - cat_id: (integer) Category ID filter
1030     - cat_url: Category URL filter
1031     - post_lang: lang of the posts
1032     - next: Get date following match
1033     - previous: Get date before match
1034     - order: Sort by date "ASC" or "DESC"
1035     
1036     @param    params    <b>array</b>        Parameters array
1037     @return   record
1038     */
1039     public function getDates($params=array())
1040     {
1041          $dt_f = '%Y-%m-%d';
1042          $dt_fc = '%Y%m%d';
1043          if (isset($params['type'])) {
1044               if ($params['type'] == 'year') {
1045                    $dt_f = '%Y-01-01';
1046                    $dt_fc = '%Y0101';
1047               } elseif ($params['type'] == 'month') {
1048                    $dt_f = '%Y-%m-01';
1049                    $dt_fc = '%Y%m01';
1050               }
1051          }
1052          $dt_f .= ' 00:00:00';
1053          $dt_fc .= '000000';
1054         
1055          $cat_field = $catReq = $limit = '';
1056         
1057          if (isset($params['cat_id']) && $params['cat_id'] !== '') {
1058               $catReq = 'AND P.cat_id = '.(integer) $params['cat_id'].' ';
1059               $cat_field = ', C.cat_url ';
1060          } elseif (isset($params['cat_url']) && $params['cat_url'] !== '') {
1061               $catReq = "AND C.cat_url = '".$this->con->escape($params['cat_url'])."' ";
1062               $cat_field = ', C.cat_url ';
1063          }
1064          if (!empty($params['post_lang'])) {
1065               $catReq = 'AND P.post_lang = \''. $params['post_lang'].'\' ';
1066          }
1067         
1068          $strReq = 'SELECT DISTINCT('.$this->con->dateFormat('post_dt',$dt_f).') AS dt '.
1069                    $cat_field.
1070                    ',COUNT(P.post_id) AS nb_post '.
1071                    'FROM '.$this->prefix.'post P LEFT JOIN '.$this->prefix.'category C '.
1072                    'ON P.cat_id = C.cat_id '.
1073                    "WHERE P.blog_id = '".$this->con->escape($this->id)."' ".
1074                    $catReq;
1075         
1076          if (!$this->core->auth->check('contentadmin',$this->id)) {
1077               $strReq .= 'AND ((post_status = 1 ';
1078               
1079               if ($this->without_password) {
1080                    $strReq .= 'AND post_password IS NULL ';
1081               }
1082               $strReq .= ') ';
1083               
1084               if ($this->core->auth->userID()) {
1085                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
1086               } else {
1087                    $strReq .= ') ';
1088               }
1089          }
1090         
1091          if (!empty($params['post_type'])) {
1092               $strReq .= "AND post_type ".$this->con->in($params['post_type'])." ";
1093          } else {
1094               $strReq .= "AND post_type = 'post' ";
1095          }
1096         
1097          if (!empty($params['year'])) {
1098               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%Y')." = '".sprintf('%04d',$params['year'])."' ";
1099          }
1100         
1101          if (!empty($params['month'])) {
1102               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%m')." = '".sprintf('%02d',$params['month'])."' ";
1103          }
1104         
1105          if (!empty($params['day'])) {
1106               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%d')." = '".sprintf('%02d',$params['day'])."' ";
1107          }
1108         
1109          # Get next or previous date
1110          if (!empty($params['next']) || !empty($params['previous']))
1111          {
1112               if (!empty($params['next'])) {
1113                    $pdir = ' > ';
1114                    $params['order'] = 'asc';
1115                    $dt = $params['next'];
1116               } else {
1117                    $pdir = ' < ';
1118                    $params['order'] = 'desc';
1119                    $dt = $params['previous'];
1120               }
1121               
1122               $dt = date('YmdHis',strtotime($dt));
1123               
1124               $strReq .= 'AND '.$this->con->dateFormat('post_dt',$dt_fc).$pdir."'".$dt."' ";
1125               $limit = $this->con->limit(1);
1126          }
1127         
1128          $strReq .= 'GROUP BY dt '.$cat_field;
1129         
1130          $order = 'desc';
1131          if (!empty($params['order']) && preg_match('/^(desc|asc)$/i',$params['order'])) {
1132               $order = $params['order'];
1133          }
1134         
1135          $strReq .=
1136          'ORDER BY dt '.$order.' '.
1137          $limit;
1138         
1139          $rs = $this->con->select($strReq);
1140          $rs->extend('rsExtDates');
1141          return $rs;
1142     }
1143     
1144     /**
1145     Creates a new entry. Takes a cursor as input and returns the new entry
1146     ID.
1147     
1148     @param    cur       <b>cursor</b>       Post cursor
1149     @return   <b>integer</b>      New post ID
1150     */
1151     public function addPost($cur)
1152     {
1153          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1154               throw new Exception(__('You are not allowed to create an entry'));
1155          }
1156         
1157          $this->con->writeLock($this->prefix.'post');
1158          try
1159          {
1160               # Get ID
1161               $rs = $this->con->select(
1162                    'SELECT MAX(post_id) '.
1163                    'FROM '.$this->prefix.'post ' 
1164                    );
1165               
1166               $cur->post_id = (integer) $rs->f(0) + 1;
1167               $cur->blog_id = (string) $this->id;
1168               $cur->post_creadt = date('Y-m-d H:i:s');
1169               $cur->post_upddt = date('Y-m-d H:i:s');
1170               $cur->post_tz = $this->core->auth->getInfo('user_tz');
1171               
1172               # Post excerpt and content
1173               $this->getPostContent($cur,$cur->post_id);
1174               
1175               $this->getPostCursor($cur);
1176               
1177               $cur->post_url = $this->getPostURL($cur->post_url,$cur->post_dt,$cur->post_title,$cur->post_id);
1178               
1179               if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1180                    $cur->post_status = -2;
1181               }
1182               
1183               # --BEHAVIOR-- coreBeforePostCreate
1184               $this->core->callBehavior('coreBeforePostCreate',$this,$cur);
1185               
1186               $cur->insert();
1187               $this->con->unlock();
1188          }
1189          catch (Exception $e)
1190          {
1191               $this->con->unlock();
1192               throw $e;
1193          }
1194         
1195          # --BEHAVIOR-- coreAfterPostCreate
1196          $this->core->callBehavior('coreAfterPostCreate',$this,$cur);
1197         
1198          $this->triggerBlog();
1199         
1200          return $cur->post_id;
1201     }
1202     
1203     /**
1204     Updates an existing post.
1205     
1206     @param    id        <b>integer</b>      Post ID
1207     @param    cur       <b>cursor</b>       Post cursor
1208     */
1209     public function updPost($id,$cur)
1210     {
1211          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1212               throw new Exception(__('You are not allowed to update entries'));
1213          }
1214         
1215          $id = (integer) $id;
1216         
1217          if (empty($id)) {
1218               throw new Exception(__('No such entry ID'));
1219          }
1220         
1221          # Post excerpt and content
1222          $this->getPostContent($cur,$id);
1223         
1224          $this->getPostCursor($cur);
1225         
1226          if ($cur->post_url !== null) {
1227               $cur->post_url = $this->getPostURL($cur->post_url,$cur->post_dt,$cur->post_title,$id);
1228          }
1229         
1230          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1231               $cur->unsetField('post_status');
1232          }
1233         
1234          $cur->post_upddt = date('Y-m-d H:i:s');
1235         
1236          #If user is only "usage", we need to check the post's owner
1237          if (!$this->core->auth->check('contentadmin',$this->id))
1238          {
1239               $strReq = 'SELECT post_id '.
1240                         'FROM '.$this->prefix.'post '.
1241                         'WHERE post_id = '.$id.' '.
1242                         "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1243               
1244               $rs = $this->con->select($strReq);
1245               
1246               if ($rs->isEmpty()) {
1247                    throw new Exception(__('You are not allowed to edit this entry'));
1248               }
1249          }
1250         
1251          # --BEHAVIOR-- coreBeforePostUpdate
1252          $this->core->callBehavior('coreBeforePostUpdate',$this,$cur);
1253         
1254          $cur->update('WHERE post_id = '.$id.' ');
1255         
1256          # --BEHAVIOR-- coreAfterPostUpdate
1257          $this->core->callBehavior('coreAfterPostUpdate',$this,$cur);
1258         
1259          $this->triggerBlog();
1260     }
1261     
1262     /**
1263     Updates post status.
1264     
1265     @param    id        <b>integer</b>      Post ID
1266     @param    status    <b>integer</b>      Post status
1267     */
1268     public function updPostStatus($id,$status)
1269     {
1270          $this->updPostsStatus($id,$status);
1271     }
1272     
1273     /**
1274     Updates posts status.
1275     
1276     @param    ids       <b>mixed</b>        Post(s) ID(s)
1277     @param    status    <b>integer</b>      Post status
1278     */
1279     public function updPostsStatus($ids,$status)
1280     {
1281          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1282               throw new Exception(__('You are not allowed to change this entry status'));
1283          }
1284         
1285          $posts_ids = dcUtils::cleanIds($ids);
1286          $status = (integer) $status;
1287         
1288          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1289                    "AND post_id ".$this->con->in($posts_ids);
1290         
1291          #If user can only publish, we need to check the post's owner
1292          if (!$this->core->auth->check('contentadmin',$this->id))
1293          {
1294               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1295          }
1296         
1297          $cur = $this->con->openCursor($this->prefix.'post');
1298         
1299          $cur->post_status = $status;
1300          $cur->post_upddt = date('Y-m-d H:i:s');
1301         
1302          $cur->update($strReq);
1303          $this->triggerBlog();
1304     }
1305     
1306     /**
1307     Updates post selection.
1308     
1309     @param    id        <b>integer</b>      Post ID
1310     @param    selected  <b>integer</b>      Is selected post
1311     */
1312     public function updPostSelected($id,$selected)
1313     {
1314          $this->updPostsSelected($id,$selected);
1315     }
1316     
1317     /**
1318     Updates posts selection.
1319     
1320     @param    ids       <b>mixed</b>        Post(s) ID(s)
1321     @param    selected  <b>integer</b>      Is selected post(s)
1322     */
1323     public function updPostsSelected($ids,$selected)
1324     {
1325          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1326               throw new Exception(__('You are not allowed to change this entry category'));
1327          }
1328         
1329          $posts_ids = dcUtils::cleanIds($ids);
1330          $selected = (boolean) $selected;
1331         
1332          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1333                    "AND post_id ".$this->con->in($posts_ids);
1334         
1335          # If user is only usage, we need to check the post's owner
1336          if (!$this->core->auth->check('contentadmin',$this->id))
1337          {
1338               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1339          }
1340         
1341          $cur = $this->con->openCursor($this->prefix.'post');
1342         
1343          $cur->post_selected = (integer) $selected;
1344          $cur->post_upddt = date('Y-m-d H:i:s');
1345         
1346          $cur->update($strReq);
1347          $this->triggerBlog();
1348     }
1349     
1350     /**
1351     Updates post category. <var>$cat_id</var> can be null.
1352     
1353     @param    id        <b>integer</b>      Post ID
1354     @param    cat_id    <b>integer</b>      Category ID
1355     */
1356     public function updPostCategory($id,$cat_id)
1357     {
1358          $this->updPostsCategory($id,$cat_id);
1359     }
1360     
1361     /**
1362     Updates posts category. <var>$cat_id</var> can be null.
1363     
1364     @param    ids       <b>mixed</b>        Post(s) ID(s)
1365     @param    cat_id    <b>integer</b>      Category ID
1366     */
1367     public function updPostsCategory($ids,$cat_id)
1368     {
1369          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1370               throw new Exception(__('You are not allowed to change this entry category'));
1371          }
1372         
1373          $posts_ids = dcUtils::cleanIds($ids);
1374          $cat_id = (integer) $cat_id;
1375         
1376          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1377                    "AND post_id ".$this->con->in($posts_ids);
1378         
1379          # If user is only usage, we need to check the post's owner
1380          if (!$this->core->auth->check('contentadmin',$this->id))
1381          {
1382               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1383          }
1384         
1385          $cur = $this->con->openCursor($this->prefix.'post');
1386         
1387          $cur->cat_id = ($cat_id ? $cat_id : null);
1388          $cur->post_upddt = date('Y-m-d H:i:s');
1389         
1390          $cur->update($strReq);
1391          $this->triggerBlog();
1392     }
1393     
1394     /**
1395     Updates posts category. <var>$new_cat_id</var> can be null.
1396     
1397     @param    old_cat_id     <b>integer</b>      Old category ID
1398     @param    new_cat_id     <b>integer</b>      New category ID
1399     */
1400     public function changePostsCategory($old_cat_id,$new_cat_id)
1401     {
1402          if (!$this->core->auth->check('contentadmin,categories',$this->id)) {
1403               throw new Exception(__('You are not allowed to change entries category'));
1404          }
1405         
1406          $old_cat_id = (integer) $old_cat_id;
1407          $new_cat_id = (integer) $new_cat_id;
1408         
1409          $cur = $this->con->openCursor($this->prefix.'post');
1410         
1411          $cur->cat_id = ($new_cat_id ? $new_cat_id : null);
1412          $cur->post_upddt = date('Y-m-d H:i:s');
1413         
1414          $cur->update(
1415               'WHERE cat_id = '.$old_cat_id.' '.
1416               "AND blog_id = '".$this->con->escape($this->id)."' "
1417          );
1418          $this->triggerBlog();
1419     }
1420     
1421     /**
1422     Deletes a post.
1423     
1424     @param    id        <b>integer</b>      Post ID
1425     */
1426     public function delPost($id)
1427     {
1428          $this->delPosts($id);
1429     }
1430     
1431     /**
1432     Deletes multiple posts.
1433     
1434     @param    ids       <b>mixed</b>        Post(s) ID(s)
1435     */
1436     public function delPosts($ids)
1437     {
1438          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
1439               throw new Exception(__('You are not allowed to delete entries'));
1440          }
1441         
1442          $posts_ids = dcUtils::cleanIds($ids);
1443         
1444          if (empty($posts_ids)) {
1445               throw new Exception(__('No such entry ID'));
1446          }
1447         
1448          $strReq = 'DELETE FROM '.$this->prefix.'post '.
1449                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1450                    "AND post_id ".$this->con->in($posts_ids);
1451         
1452          #If user can only delete, we need to check the post's owner
1453          if (!$this->core->auth->check('contentadmin',$this->id))
1454          {
1455               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1456          }
1457         
1458          $this->con->execute($strReq);
1459          $this->triggerBlog();
1460     }
1461     
1462     /**
1463     Publishes all entries flaged as "scheduled".
1464     */
1465     public function publishScheduledEntries()
1466     {
1467          $strReq = 'SELECT post_id, post_dt, post_tz '.
1468                    'FROM '.$this->prefix.'post '.
1469                    'WHERE post_status = -1 '.
1470                    "AND blog_id = '".$this->con->escape($this->id)."' ";
1471         
1472          $rs = $this->con->select($strReq);
1473         
1474          $now = dt::toUTC(time());
1475          $to_change = new ArrayObject();
1476
1477          if ($rs->isEmpty()) {
1478               return;
1479          }
1480         
1481          while ($rs->fetch())
1482          {
1483               # Now timestamp with post timezone
1484               $now_tz = $now + dt::getTimeOffset($rs->post_tz,$now);
1485               
1486               # Post timestamp
1487               $post_ts = strtotime($rs->post_dt);
1488               
1489               # If now_tz >= post_ts, we publish the entry
1490               if ($now_tz >= $post_ts) {
1491                    $to_change[] = (integer) $rs->post_id;
1492               }
1493          }
1494          if (count($to_change))
1495          {
1496               # --BEHAVIOR-- coreBeforeScheduledEntriesPublish
1497               $this->core->callBehavior('coreBeforeScheduledEntriesPublish',$this,$to_change);
1498
1499               $strReq =
1500               'UPDATE '.$this->prefix.'post SET '.
1501               'post_status = 1 '.
1502               "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1503               'AND post_id '.$this->con->in((array)$to_change).' ';
1504               $this->con->execute($strReq);
1505               $this->triggerBlog();
1506
1507               # --BEHAVIOR-- coreAfterScheduledEntriesPublish
1508               $this->core->callBehavior('coreAfterScheduledEntriesPublish',$this,$to_change);
1509          }
1510         
1511     }
1512     
1513     /**
1514     Retrieves all users having posts on current blog.
1515     
1516     @param    post_type      <b>string</b>       post_type filter (post)
1517     @return   record
1518     */
1519     public function getPostsUsers($post_type='post')
1520     {
1521          $strReq = 'SELECT P.user_id, user_name, user_firstname, '.
1522                    'user_displayname, user_email '.
1523                    'FROM '.$this->prefix.'post P, '.$this->prefix.'user U '.
1524                    'WHERE P.user_id = U.user_id '.
1525                    "AND blog_id = '".$this->con->escape($this->id)."' ";
1526         
1527          if ($post_type) {
1528               $strReq .= "AND post_type = '".$this->con->escape($post_type)."' ";
1529          }
1530         
1531          $strReq .= 'GROUP BY P.user_id, user_name, user_firstname, user_displayname, user_email ';
1532         
1533          return $this->con->select($strReq);
1534     }
1535     
1536     private function getPostsCategoryFilter($arr,$field='cat_id')
1537     {
1538          $field = $field == 'cat_id' ? 'cat_id' : 'cat_url';
1539         
1540          $sub = array();
1541          $not = array();
1542          $queries = array();
1543         
1544          foreach ($arr as $v)
1545          {
1546               $v = trim($v);
1547               $args = preg_split('/\s*[?]\s*/',$v,-1,PREG_SPLIT_NO_EMPTY);
1548               $id = array_shift($args);
1549               $args = array_flip($args);
1550               
1551               if (isset($args['not'])) { $not[$id] = 1; }
1552               if (isset($args['sub'])) { $sub[$id] = 1; }
1553               if ($field == 'cat_id') {
1554                    if (preg_match('/^null$/i',$id)) {
1555                         $queries[$id] = 'P.cat_id IS NULL';
1556                    }
1557                    else {
1558                         $queries[$id] = 'P.cat_id = '.(integer) $id;
1559                    }
1560               } else {
1561                    $queries[$id] = "C.cat_url = '".$this->con->escape($id)."' ";
1562               }
1563          }
1564         
1565          if (!empty($sub)) {
1566               $rs = $this->con->select(
1567                    'SELECT cat_id, cat_url, cat_lft, cat_rgt FROM '.$this->prefix.'category '.
1568                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1569                    'AND '.$field.' '.$this->con->in(array_keys($sub))
1570               );
1571               
1572               while ($rs->fetch()) {
1573                    $queries[$rs->f($field)] = '(C.cat_lft BETWEEN '.$rs->cat_lft.' AND '.$rs->cat_rgt.')';
1574               }
1575          }
1576         
1577          # Create queries
1578          $sql = array(
1579               0 => array(), # wanted categories
1580               1 => array()  # excluded categories
1581          );
1582         
1583          foreach ($queries as $id => $q) {
1584               $sql[(integer) isset($not[$id])][] = $q;
1585          }
1586         
1587          $sql[0] = implode(' OR ',$sql[0]);
1588          $sql[1] = implode(' OR ',$sql[1]);
1589         
1590          if ($sql[0]) {
1591               $sql[0] = '('.$sql[0].')';
1592          } else {
1593               unset($sql[0]);
1594          }
1595         
1596          if ($sql[1]) {
1597               $sql[1] = '(P.cat_id IS NULL OR NOT('.$sql[1].'))';
1598          } else {
1599               unset($sql[1]);
1600          }
1601         
1602          return implode(' AND ',$sql);
1603     }
1604     
1605     private function getPostCursor($cur,$post_id=null)
1606     {
1607          if ($cur->post_title == '') {
1608               throw new Exception(__('No entry title'));
1609          }
1610         
1611          if ($cur->post_content == '') {
1612               throw new Exception(__('No entry content'));
1613          }
1614         
1615          if ($cur->post_password === '') {
1616               $cur->post_password = null;
1617          }
1618         
1619          if ($cur->post_dt == '') {
1620               $offset = dt::getTimeOffset($this->core->auth->getInfo('user_tz'));
1621               $now = time() + $offset;
1622               $cur->post_dt = date('Y-m-d H:i:00',$now);
1623          }
1624         
1625          $post_id = is_int($post_id) ? $post_id : $cur->post_id;
1626         
1627          if ($cur->post_content_xhtml == '') {
1628               throw new Exception(__('No entry content'));
1629          }
1630         
1631          # Words list
1632          if ($cur->post_title !== null && $cur->post_excerpt_xhtml !== null
1633          && $cur->post_content_xhtml !== null)
1634          {
1635               $words =
1636               $cur->post_title.' '.
1637               $cur->post_excerpt_xhtml.' '.
1638               $cur->post_content_xhtml;
1639               
1640               $cur->post_words = implode(' ',text::splitWords($words));
1641          }
1642     }
1643     
1644     private function getPostContent($cur,$post_id)
1645     {
1646          $post_excerpt = $cur->post_excerpt;
1647          $post_excerpt_xhtml = $cur->post_excerpt_xhtml;
1648          $post_content = $cur->post_content;
1649          $post_content_xhtml = $cur->post_content_xhtml;
1650         
1651          $this->setPostContent(
1652               $post_id,$cur->post_format,$cur->post_lang,
1653               $post_excerpt,$post_excerpt_xhtml,
1654               $post_content,$post_content_xhtml
1655          );
1656         
1657          $cur->post_excerpt = $post_excerpt;
1658          $cur->post_excerpt_xhtml = $post_excerpt_xhtml;
1659          $cur->post_content = $post_content;
1660          $cur->post_content_xhtml = $post_content_xhtml;
1661     }
1662     
1663     /**
1664     Creates post HTML content, taking format and lang into account.
1665     
1666     @param         post_id        <b>integer</b>      Post ID
1667     @param         format         <b>string</b>       Post format
1668     @param         lang           <b>string</b>       Post lang
1669     @param         excerpt        <b>string</b>       Post excerpt
1670     @param[out]    excerpt_xhtml  <b>string</b>       Post excerpt HTML
1671     @param         content        <b>string</b>       Post content
1672     @param[out]    content_xhtml  <b>string</b>       Post content HTML
1673     */
1674     public function setPostContent($post_id,$format,$lang,&$excerpt,&$excerpt_xhtml,&$content,&$content_xhtml)
1675     {
1676          if ($format == 'wiki')
1677          {
1678               $this->core->initWikiPost();
1679               $this->core->wiki2xhtml->setOpt('note_prefix','pnote-'.$post_id);
1680               switch ($this->settings->system->note_title_tag) {
1681                    case 1:
1682                         $tag = 'h3';
1683                         break;
1684                    case 2:
1685                         $tag = 'p';
1686                         break;
1687                    default:
1688                         $tag = 'h4';
1689                         break;
1690               }
1691               $this->core->wiki2xhtml->setOpt('note_str','<div class="footnotes"><'.$tag.' class="footnotes-title">'.
1692                    __('Notes').'</'.$tag.'>%s</div>');
1693               $this->core->wiki2xhtml->setOpt('note_str_single','<div class="footnotes"><'.$tag.' class="footnotes-title">'.
1694                    __('Note').'</'.$tag.'>%s</div>');
1695               if (strpos($lang,'fr') === 0) {
1696                    $this->core->wiki2xhtml->setOpt('active_fr_syntax',1);
1697               }
1698          }
1699         
1700          if ($excerpt) {
1701               $excerpt_xhtml = $this->core->callFormater($format,$excerpt);
1702               $excerpt_xhtml = $this->core->HTMLfilter($excerpt_xhtml);
1703          } else {
1704               $excerpt_xhtml = '';
1705          }
1706         
1707          if ($content) {
1708               $content_xhtml = $this->core->callFormater($format,$content);
1709               $content_xhtml = $this->core->HTMLfilter($content_xhtml);
1710          } else {
1711               $content_xhtml = '';
1712          }
1713         
1714          # --BEHAVIOR-- coreAfterPostContentFormat
1715          $this->core->callBehavior('coreAfterPostContentFormat',array(
1716               'excerpt' => &$excerpt,
1717               'content' => &$content,
1718               'excerpt_xhtml' => &$excerpt_xhtml,
1719               'content_xhtml' => &$content_xhtml
1720          ));
1721     }
1722     
1723     /**
1724     Returns URL for a post according to blog setting <var>post_url_format</var>.
1725     It will try to guess URL and append some figures if needed.
1726     
1727     @param    url            <b>string</b>       Origin URL, could be empty
1728     @param    post_dt        <b>string</b>       Post date (in YYYY-MM-DD HH:mm:ss)
1729     @param    post_title     <b>string</b>       Post title
1730     @param    post_id        <b>integer</b>      Post ID
1731     @return   <b>string</b>  result URL
1732     */
1733     public function getPostURL($url,$post_dt,$post_title,$post_id)
1734     {
1735          $url = trim($url);
1736         
1737          $url_patterns = array(
1738          '{y}' => date('Y',strtotime($post_dt)),
1739          '{m}' => date('m',strtotime($post_dt)),
1740          '{d}' => date('d',strtotime($post_dt)),
1741          '{t}' => text::tidyURL($post_title),
1742          '{id}' => (integer) $post_id
1743          );
1744         
1745          # If URL is empty, we create a new one
1746          if ($url == '')
1747          {
1748               # Transform with format
1749               $url = str_replace(
1750                    array_keys($url_patterns),
1751                    array_values($url_patterns),
1752                    $this->settings->system->post_url_format
1753               );
1754          }
1755          else
1756          {
1757               $url = text::tidyURL($url);
1758          }
1759         
1760          # Let's check if URL is taken...
1761          $strReq = 'SELECT post_url FROM '.$this->prefix.'post '.
1762                    "WHERE post_url = '".$this->con->escape($url)."' ".
1763                    'AND post_id <> '.(integer) $post_id. ' '.
1764                    "AND blog_id = '".$this->con->escape($this->id)."' ".
1765                    'ORDER BY post_url DESC';
1766         
1767          $rs = $this->con->select($strReq);
1768         
1769          if (!$rs->isEmpty())
1770          {
1771               if ($this->con->driver() == 'mysql') {
1772                    $clause = "REGEXP '^".$this->con->escape($url)."[0-9]+$'";
1773               } elseif ($this->con->driver() == 'pgsql') {
1774                    $clause = "~ '^".$this->con->escape($url)."[0-9]+$'";
1775               } else {
1776                    $clause = "LIKE '".$this->con->escape($url)."%'";
1777               }
1778               $strReq = 'SELECT post_url FROM '.$this->prefix.'post '.
1779                         "WHERE post_url ".$clause.' '.
1780                         'AND post_id <> '.(integer) $post_id.' '.
1781                         "AND blog_id = '".$this->con->escape($this->id)."' ".
1782                         'ORDER BY post_url DESC ';
1783               
1784               $rs = $this->con->select($strReq);
1785               $a = array();
1786               while ($rs->fetch()) {
1787                    $a[] = $rs->post_url;
1788               }
1789               
1790               natsort($a);
1791               $t_url = end($a);
1792               
1793               if (preg_match('/(.*?)([0-9]+)$/',$t_url,$m)) {
1794                    $i = (integer) $m[2];
1795                    $url = $m[1];
1796               } else {
1797                    $i = 1;
1798               }
1799               
1800               return $url.($i+1);
1801          }
1802         
1803          # URL is empty?
1804          if ($url == '') {
1805               throw new Exception(__('Empty entry URL'));
1806          }
1807         
1808          return $url;
1809     }
1810     //@}
1811     
1812     /// @name Comments management methods
1813     //@{
1814     /**
1815     Retrieves comments. <b>$params</b> is an array taking the following
1816     optionnal parameters:
1817     
1818     - no_content: Don't retrieve comment content
1819     - post_type: Get only entries with given type (default no type, array for many types)
1820     - post_id: (integer) Get comments belonging to given post_id
1821     - cat_id: (integer or array) Get comments belonging to entries of given category ID
1822     - comment_id: (integer) Get comment with given ID
1823     - comment_status: (integer) Get comments with given comment_status
1824     - comment_trackback: (integer) Get only comments (0) or trackbacks (1)
1825     - comment_ip: (string) Get comments with given IP address
1826     - post_url: Get entry with given post_url field
1827     - user_id: (integer) Get entries belonging to given user ID
1828     - q_author: Search comments by author
1829     - sql: Append SQL string at the end of the query
1830     - from: Append SQL string after "FROM" statement in query
1831     - order: Order of results (default "ORDER BY comment_dt DES")
1832     - limit: Limit parameter
1833     - sql_only : return the sql request instead of results. Only ids are selected
1834     
1835     @param    params         <b>array</b>        Parameters
1836     @param    count_only     <b>boolean</b>      Only counts results
1837     @return   <b>record</b>  A record with some more capabilities
1838     */
1839     public function getComments($params=array(),$count_only=false)
1840     {
1841          if ($count_only)
1842          {
1843               $strReq = 'SELECT count(comment_id) ';
1844          }
1845          elseif (!empty($params['sql_only'])) 
1846          {
1847               $strReq = 'SELECT P.post_id ';
1848          }
1849          else
1850          {
1851               if (!empty($params['no_content'])) {
1852                    $content_req = '';
1853               } else {
1854                    $content_req = 'comment_content, ';
1855               }
1856               
1857               if (!empty($params['columns']) && is_array($params['columns'])) {
1858                    $content_req .= implode(', ',$params['columns']).', ';
1859               }
1860               
1861               $strReq =
1862               'SELECT C.comment_id, comment_dt, comment_tz, comment_upddt, '.
1863               'comment_author, comment_email, comment_site, '.
1864               $content_req.' comment_trackback, comment_status, '.
1865               'comment_spam_status, comment_spam_filter, comment_ip, '.
1866               'P.post_title, P.post_url, P.post_id, P.post_password, P.post_type, '.
1867               'P.post_dt, P.user_id, U.user_email, U.user_url ';
1868          }
1869         
1870          $strReq .=
1871          'FROM '.$this->prefix.'comment C '.
1872          'INNER JOIN '.$this->prefix.'post P ON C.post_id = P.post_id '.
1873          'INNER JOIN '.$this->prefix.'user U ON P.user_id = U.user_id ';
1874         
1875          if (!empty($params['from'])) {
1876               $strReq .= $params['from'].' ';
1877          }
1878         
1879          $strReq .=
1880          "WHERE P.blog_id = '".$this->con->escape($this->id)."' ";
1881         
1882          if (!$this->core->auth->check('contentadmin',$this->id)) {
1883               $strReq .= 'AND ((comment_status = 1 AND P.post_status = 1 ';
1884               
1885               if ($this->without_password) {
1886                    $strReq .= 'AND post_password IS NULL ';
1887               }
1888               $strReq .= ') ';
1889               
1890               if ($this->core->auth->userID()) {
1891                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
1892               } else {
1893                    $strReq .= ') ';
1894               }
1895          }
1896         
1897          if (!empty($params['post_type']))
1898          {
1899               $strReq .= 'AND post_type '.$this->con->in($params['post_type']);
1900          }
1901         
1902          if (isset($params['post_id']) && $params['post_id'] !== '') {
1903               $strReq .= 'AND P.post_id = '.(integer) $params['post_id'].' ';
1904          }
1905         
1906          if (isset($params['cat_id']) && $params['cat_id'] !== '') {
1907               $strReq .= 'AND P.cat_id = '.(integer) $params['cat_id'].' ';
1908          }
1909         
1910          if (isset($params['comment_id']) && $params['comment_id'] !== '') {
1911               $strReq .= 'AND comment_id = '.(integer) $params['comment_id'].' ';
1912          }
1913         
1914          if (isset($params['comment_status'])) {
1915               $strReq .= 'AND comment_status = '.(integer) $params['comment_status'].' ';
1916          }
1917         
1918          if (!empty($params['comment_status_not']))
1919          {
1920               $strReq .= 'AND comment_status <> '.(integer) $params['comment_status_not'].' ';
1921          }
1922         
1923          if (isset($params['comment_trackback'])) {
1924               $strReq .= 'AND comment_trackback = '.(integer) (boolean) $params['comment_trackback'].' ';
1925          }
1926         
1927          if (isset($params['comment_ip'])) {
1928               $comment_ip = $this->con->escape(str_replace('*','%',$params['comment_ip']));
1929               $strReq .= "AND comment_ip LIKE '".$comment_ip."' ";
1930          }
1931         
1932          if (isset($params['q_author'])) {
1933               $q_author = $this->con->escape(str_replace('*','%',strtolower($params['q_author'])));
1934               $strReq .= "AND LOWER(comment_author) LIKE '".$q_author."' ";
1935          }
1936         
1937          if (!empty($params['search']))
1938          {
1939               $words = text::splitWords($params['search']);
1940               
1941               if (!empty($words))
1942               {
1943                    # --BEHAVIOR coreCommentSearch
1944                    if ($this->core->hasBehavior('coreCommentSearch')) {
1945                         $this->core->callBehavior('coreCommentSearch',$this->core,array(&$words,&$strReq,&$params));
1946                    }
1947                   
1948                    if ($words)
1949                    {
1950                         foreach ($words as $i => $w) {
1951                              $words[$i] = "comment_words LIKE '%".$this->con->escape($w)."%'";
1952                         }
1953                         $strReq .= 'AND '.implode(' AND ',$words).' ';
1954                    }
1955               }
1956          }
1957         
1958          if (!empty($params['sql'])) {
1959               $strReq .= $params['sql'].' ';
1960          }
1961         
1962          if (!$count_only)
1963          {
1964               if (!empty($params['order'])) {
1965                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
1966               } else {
1967                    $strReq .= 'ORDER BY comment_dt DESC ';
1968               }
1969          }
1970         
1971          if (!$count_only && !empty($params['limit'])) {
1972               $strReq .= $this->con->limit($params['limit']);
1973          }
1974
1975          if (!empty($params['sql_only'])) {
1976               return $strReq;
1977          }
1978         
1979          $rs = $this->con->select($strReq);
1980          $rs->core = $this->core;
1981          $rs->extend('rsExtComment');
1982         
1983          # --BEHAVIOR-- coreBlogGetComments
1984          $this->core->callBehavior('coreBlogGetComments',$rs);
1985         
1986          return $rs;
1987     }
1988     
1989     /**
1990     Creates a new comment. Takes a cursor as input and returns the new comment
1991     ID.
1992     
1993     @param    cur       <b>cursor</b>       Comment cursor
1994     @return   <b>integer</b>      New comment ID
1995     */
1996     public function addComment($cur)
1997     {
1998          $this->con->writeLock($this->prefix.'comment');
1999          try
2000          {
2001               # Get ID
2002               $rs = $this->con->select(
2003                    'SELECT MAX(comment_id) '.
2004                    'FROM '.$this->prefix.'comment ' 
2005               );
2006               
2007               $cur->comment_id = (integer) $rs->f(0) + 1;
2008               $cur->comment_upddt = date('Y-m-d H:i:s');
2009               
2010               $offset = dt::getTimeOffset($this->settings->system->blog_timezone);
2011               $cur->comment_dt = date('Y-m-d H:i:s',time() + $offset);
2012               $cur->comment_tz = $this->settings->system->blog_timezone;
2013               
2014               $this->getCommentCursor($cur);
2015               
2016               if ($cur->comment_ip === null) {
2017                    $cur->comment_ip = http::realIP();
2018               }
2019               
2020               # --BEHAVIOR-- coreBeforeCommentCreate
2021               $this->core->callBehavior('coreBeforeCommentCreate',$this,$cur);
2022               
2023               $cur->insert();
2024               $this->con->unlock();
2025          }
2026          catch (Exception $e)
2027          {
2028               $this->con->unlock();
2029               throw $e;
2030          }
2031         
2032          # --BEHAVIOR-- coreAfterCommentCreate
2033          $this->core->callBehavior('coreAfterCommentCreate',$this,$cur);
2034         
2035          $this->triggerComment($cur->comment_id);
2036          if ($cur->comment_status != -2) {
2037               $this->triggerBlog();
2038          }   
2039          return $cur->comment_id;
2040     }
2041     
2042     /**
2043     Updates an existing comment.
2044     
2045     @param    id        <b>integer</b>      Comment ID
2046     @param    cur       <b>cursor</b>       Comment cursor
2047     */
2048     public function updComment($id,$cur)
2049     {
2050          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
2051               throw new Exception(__('You are not allowed to update comments'));
2052          }
2053         
2054          $id = (integer) $id;
2055         
2056          if (empty($id)) {
2057               throw new Exception(__('No such comment ID'));
2058          }
2059         
2060          $rs = $this->getComments(array('comment_id' => $id));
2061         
2062          if ($rs->isEmpty()) {
2063               throw new Exception(__('No such comment ID'));
2064          }
2065         
2066          #If user is only usage, we need to check the post's owner
2067          if (!$this->core->auth->check('contentadmin',$this->id))
2068          {
2069               if ($rs->user_id != $this->core->auth->userID()) {
2070                    throw new Exception(__('You are not allowed to update this comment'));
2071               }
2072          }
2073         
2074          $this->getCommentCursor($cur);
2075         
2076          $cur->comment_upddt = date('Y-m-d H:i:s');
2077         
2078          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
2079               $cur->unsetField('comment_status');
2080          }
2081         
2082          # --BEHAVIOR-- coreBeforeCommentUpdate
2083          $this->core->callBehavior('coreBeforeCommentUpdate',$this,$cur,$rs);
2084         
2085          $cur->update('WHERE comment_id = '.$id.' ');
2086         
2087          # --BEHAVIOR-- coreAfterCommentUpdate
2088          $this->core->callBehavior('coreAfterCommentUpdate',$this,$cur,$rs);
2089         
2090          $this->triggerComment($id);
2091          $this->triggerBlog();
2092     }
2093     
2094     /**
2095     Updates comment status.
2096     
2097     @param    id        <b>integer</b>      Comment ID
2098     @param    status    <b>integer</b>      Comment status
2099     */
2100     public function updCommentStatus($id,$status)
2101     {
2102          $this->updCommentsStatus($id,$status);
2103     }
2104     
2105     /**
2106     Updates comments status.
2107     
2108     @param    ids       <b>mixed</b>        Comment(s) ID(s)
2109     @param    status    <b>integer</b>      Comment status
2110     */
2111     public function updCommentsStatus($ids,$status)
2112     {
2113          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
2114               throw new Exception(__("You are not allowed to change this comment's status"));
2115          }
2116         
2117          $co_ids = dcUtils::cleanIds($ids);
2118          $status = (integer) $status;
2119         
2120          $strReq = 
2121               'UPDATE '.$this->prefix.'comment tc ';
2122         
2123          # mySQL uses "JOIN" synthax
2124          if ($this->con->driver() == 'mysql') {
2125               $strReq .= 
2126                    'JOIN '.$this->prefix.'post tp ON tc.post_id = tp.post_id ';
2127          }
2128         
2129          $strReq .= 
2130               'SET comment_status = '.$status.' ';
2131         
2132          # pgSQL uses "FROM" synthax
2133          if ($this->con->driver() != 'mysql') {
2134               $strReq .= 
2135                    'FROM '.$this->prefix.'post tp ';
2136          }
2137         
2138          $strReq .=
2139               "WHERE blog_id = '".$this->con->escape($this->id)."' ".
2140               'AND comment_id'.$this->con->in($co_ids);
2141         
2142          # add pgSQL "WHERE" clause
2143          if ($this->con->driver() != 'mysql') {
2144               $strReq .= 
2145                    'AND tc.post_id = tp.post_id ';
2146          }
2147         
2148          #If user is only usage, we need to check the post's owner
2149          if (!$this->core->auth->check('contentadmin',$this->id))
2150          {
2151               $strReq .= 
2152                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2153          }
2154         
2155          $this->con->execute($strReq);
2156          $this->triggerComments($co_ids);
2157          $this->triggerBlog();
2158     }
2159     
2160     /**
2161     Delete a comment
2162     
2163     @param    id        <b>integer</b>      Comment ID
2164     */
2165     public function delComment($id)
2166     {
2167          $this->delComments($id);
2168     }
2169     
2170     /**
2171     Delete comments
2172     
2173     @param    ids       <b>mixed</b>        Comment(s) ID(s)
2174     */
2175     public function delComments($ids)
2176     {
2177          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
2178               throw new Exception(__('You are not allowed to delete comments'));
2179          }
2180         
2181          $co_ids = dcUtils::cleanIds($ids);
2182         
2183          if (empty($ids)) {
2184               throw new Exception(__('No such comment ID'));
2185          }
2186         
2187          # mySQL uses "INNER JOIN" synthax
2188          if ($this->con->driver() == 'mysql') {
2189               $strReq = 
2190                    'DELETE FROM tc '.
2191                    'USING '.$this->prefix.'comment tc '.
2192                    'INNER JOIN '.$this->prefix.'post tp ';
2193          }
2194          # pgSQL uses nothing special
2195          else {
2196               $strReq = 
2197                    'DELETE FROM '.$this->prefix.'comment tc '.
2198                    'USING '.$this->prefix.'post tp ';
2199          }
2200         
2201          $strReq .= 
2202               'WHERE tc.post_id = tp.post_id '.
2203               "AND tp.blog_id = '".$this->con->escape($this->id)."' ".
2204               'AND comment_id'.$this->con->in($co_ids);
2205         
2206          #If user can only delete, we need to check the post's owner
2207          if (!$this->core->auth->check('contentadmin',$this->id))
2208          {
2209               $strReq .= 
2210                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2211          }
2212         
2213          $this->con->execute($strReq);
2214          $this->triggerComments($co_ids,true);
2215          $this->triggerBlog();
2216     }
2217
2218     public function delJunkComments()
2219     {
2220          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
2221               throw new Exception(__('You are not allowed to delete comments'));
2222          }
2223         
2224          # mySQL uses "INNER JOIN" synthax
2225          if ($this->con->driver() == 'mysql') {
2226               $strReq = 
2227                    'DELETE FROM tc '.
2228                    'USING '.$this->prefix.'comment tc '.
2229                    'INNER JOIN '.$this->prefix.'post tp ';
2230          }
2231          # pgSQL uses nothing special
2232          else {
2233               $strReq = 
2234                    'DELETE FROM '.$this->prefix.'comment tc '.
2235                    'USING '.$this->prefix.'post tp ';
2236          }
2237         
2238          $strReq .= 
2239               'WHERE tc.post_id = tp.post_id '.
2240               "AND tp.blog_id = '".$this->con->escape($this->id)."' ".
2241               'AND comment_status = -2';
2242         
2243          #If user can only delete, we need to check the post's owner
2244          if (!$this->core->auth->check('contentadmin',$this->id))
2245          {
2246               $strReq .= 
2247                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2248          }
2249         
2250          $this->con->execute($strReq);
2251          $this->triggerBlog();
2252     }
2253     
2254     private function getCommentCursor($cur)
2255     {
2256          if ($cur->comment_content !== null && $cur->comment_content == '') {
2257               throw new Exception(__('You must provide a comment'));
2258          }
2259         
2260          if ($cur->comment_author !== null && $cur->comment_author == '') {
2261               throw new Exception(__('You must provide an author name'));
2262          }
2263         
2264          if ($cur->comment_email != '' && !text::isEmail($cur->comment_email)) {
2265               throw new Exception(__('Email address is not valid.'));
2266          }
2267         
2268          if ($cur->comment_site !== null && $cur->comment_site != '') {
2269               if (!preg_match('|^http(s?)://|',$cur->comment_site)) {
2270                    $cur->comment_site = 'http://'.$cur->comment_site;
2271               }
2272          }
2273         
2274          if ($cur->comment_status === null) {
2275               $cur->comment_status = (integer) $this->settings->system->comments_pub;
2276          }
2277         
2278          # Words list
2279          if ($cur->comment_content !== null)
2280          {
2281               $cur->comment_words = implode(' ',text::splitWords($cur->comment_content));
2282          }
2283     }
2284     //@}
2285}
2286?>
Note: See TracBrowser for help on using the repository browser.

Sites map