Dotclear

source: inc/core/class.dc.blog.php @ 1492:a7112dcc916c

Revision 1492:a7112dcc916c, 60.6 KB checked in by Dsls, 12 years ago (diff)

Fusion avec default

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2011 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 = preg_replace('|^([a-z]{3,}://)(.*?)/.*$|','$1$2',$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          # Let's check if URL is taken...
637          $strReq = 
638               'SELECT cat_url FROM '.$this->prefix.'category '.
639               "WHERE cat_url = '".$this->con->escape($url)."' ".
640               ($id ? 'AND cat_id <> '.(integer) $id. ' ' : '').
641               "AND blog_id = '".$this->con->escape($this->id)."' ".
642               'ORDER BY cat_url DESC';
643         
644          $rs = $this->con->select($strReq);
645         
646          if (!$rs->isEmpty())
647          {
648               if ($this->con->driver() == 'mysql') {
649                    $clause = "REGEXP '^".$this->con->escape($url)."[0-9]+$'";
650               } elseif ($this->con->driver() == 'pgsql') {
651                    $clause = "~ '^".$this->con->escape($url)."[0-9]+$'";
652               } else {
653                    $clause = "LIKE '".$this->con->escape($url)."%'";
654               }
655               $strReq = 
656                    'SELECT cat_url FROM '.$this->prefix.'category '.
657                    "WHERE cat_url ".$clause.' '.
658                    ($id ? 'AND cat_id <> '.(integer) $id. ' ' : '').
659                    "AND blog_id = '".$this->con->escape($this->id)."' ".
660                    'ORDER BY cat_url DESC ';
661               
662               $rs = $this->con->select($strReq);
663               $a = array();
664               while ($rs->fetch()) {
665                    $a[] = $rs->cat_url;
666               }
667               
668               natsort($a);
669               $t_url = end($a);
670               
671               if (preg_match('/(.*?)([0-9]+)$/',$t_url,$m)) {
672                    $i = (integer) $m[2];
673                    $url = $m[1];
674               } else {
675                    $i = 1;
676               }
677               
678               return $url.($i+1);
679          }
680         
681          # URL is empty?
682          if ($url == '') {
683               throw new Exception(__('Empty category URL'));
684          }
685         
686          return $url;
687     }
688     
689     private function getCategoryCursor($cur,$id=null)
690     {
691          if ($cur->cat_title == '') {
692               throw new Exception(__('You must provide a category title'));
693          }
694         
695          # If we don't have any cat_url, let's do one
696          if ($cur->cat_url == '') {
697               $cur->cat_url = text::tidyURL($cur->cat_title,false);
698          }
699         
700          # Still empty ?
701          if ($cur->cat_url == '') {
702               throw new Exception(__('You must provide a category URL'));
703          } else {
704               $cur->cat_url = text::tidyURL($cur->cat_url,true);
705          }
706         
707          # Check if title or url are unique
708          $cur->cat_url = $this->checkCategory($cur->cat_title,$cur->cat_url,$id);
709         
710          if ($cur->cat_desc !== null) {
711               $cur->cat_desc = $this->core->HTMLfilter($cur->cat_desc);
712          }
713     }
714     //@}
715     
716     /// @name Entries management methods
717     //@{
718     /**
719     Retrieves entries. <b>$params</b> is an array taking the following
720     optionnal parameters:
721     
722     - no_content: Don't retrieve entry content (excerpt and content)
723     - post_type: Get only entries with given type (default "post", array for many types and '' for no type)
724     - post_id: (integer) Get entry with given post_id
725     - post_url: Get entry with given post_url field
726     - user_id: (integer) Get entries belonging to given user ID
727     - cat_id: (string or array) Get entries belonging to given category ID
728     - cat_id_not: deprecated (use cat_id with "id ?not" instead)
729     - cat_url: (string or array) Get entries belonging to given category URL
730     - cat_url_not: deprecated (use cat_url with "url ?not" instead)
731     - post_status: (integer) Get entries with given post_status
732     - post_selected: (boolean) Get select flaged entries
733     - post_year: (integer) Get entries with given year
734     - post_month: (integer) Get entries with given month
735     - post_day: (integer) Get entries with given day
736     - post_lang: Get entries with given language code
737     - search: Get entries corresponding of the following search string
738     - columns: (array) More columns to retrieve
739     - sql: Append SQL string at the end of the query
740     - from: Append SQL string after "FROM" statement in query
741     - order: Order of results (default "ORDER BY post_dt DES")
742     - limit: Limit parameter
743     - sql_only : return the sql request instead of results. Only ids are selected
744     
745     Please note that on every cat_id or cat_url, you can add ?not to exclude
746     the category and ?sub to get subcategories.
747     
748     @param    params         <b>array</b>        Parameters
749     @param    count_only     <b>boolean</b>      Only counts results
750     @return   <b>record</b>  A record with some more capabilities or the SQL request
751     */
752     public function getPosts($params=array(),$count_only=false)
753     {
754          # --BEHAVIOR-- coreBlogBeforeGetPosts
755          $params = new ArrayObject($params);
756          $this->core->callBehavior('coreBlogBeforeGetPosts',$params);
757
758          if ($count_only)
759          {
760               $strReq = 'SELECT count(P.post_id) ';
761          }
762          elseif (!empty($params['sql_only'])) 
763          {
764               $strReq = 'SELECT P.post_id ';
765          }
766          else
767          {
768               if (!empty($params['no_content'])) {
769                    $content_req = '';
770               } else {
771                    $content_req =
772                    'post_excerpt, post_excerpt_xhtml, '.
773                    'post_content, post_content_xhtml, post_notes, ';
774               }
775               
776               if (!empty($params['columns']) && is_array($params['columns'])) {
777                    $content_req .= implode(', ',$params['columns']).', ';
778               }
779               
780               $strReq =
781               'SELECT P.post_id, P.blog_id, P.user_id, P.cat_id, post_dt, '.
782               'post_tz, post_creadt, post_upddt, post_format, post_password, '.
783               'post_url, post_lang, post_title, '.$content_req.
784               'post_type, post_meta, post_status, post_selected, post_position, '.
785               'post_open_comment, post_open_tb, nb_comment, nb_trackback, '.
786               'U.user_name, U.user_firstname, U.user_displayname, U.user_email, '.
787               'U.user_url, '.
788               'C.cat_title, C.cat_url, C.cat_desc ';
789          }
790         
791          $strReq .=
792          'FROM '.$this->prefix.'post P '.
793          'INNER JOIN '.$this->prefix.'user U ON U.user_id = P.user_id '.
794          'LEFT OUTER JOIN '.$this->prefix.'category C ON P.cat_id = C.cat_id ';
795         
796          if (!empty($params['from'])) {
797               $strReq .= $params['from'].' ';
798          }
799         
800          $strReq .=
801          "WHERE P.blog_id = '".$this->con->escape($this->id)."' ";
802         
803          if (!$this->core->auth->check('contentadmin',$this->id)) {
804               $strReq .= 'AND ((post_status = 1 ';
805               
806               if ($this->without_password) {
807                    $strReq .= 'AND post_password IS NULL ';
808               }
809               $strReq .= ') ';
810               
811               if ($this->core->auth->userID()) {
812                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
813               } else {
814                    $strReq .= ') ';
815               }
816          }
817         
818          #Adding parameters
819          if (isset($params['post_type']))
820          {
821               if (is_array($params['post_type']) || $params['post_type'] != '') {
822                    $strReq .= 'AND post_type '.$this->con->in($params['post_type']);
823               }
824          }
825          else
826          {
827               $strReq .= "AND post_type = 'post' ";
828          }
829         
830          if (isset($params['post_id']) && $params['post_id'] !== '') {
831               if (is_array($params['post_id'])) {
832                    array_walk($params['post_id'],create_function('&$v,$k','if($v!==null){$v=(integer)$v;}'));
833               } else {
834                    $params['post_id'] = array((integer) $params['post_id']);
835               }
836               $strReq .= 'AND P.post_id '.$this->con->in($params['post_id']);
837          }
838         
839          if (isset($params['post_url']) && $params['post_url'] !== '') {
840               $strReq .= "AND post_url = '".$this->con->escape($params['post_url'])."' ";
841          }
842         
843          if (!empty($params['user_id'])) {
844               $strReq .= "AND U.user_id ".$this->con->in($params['user_id'])." ";
845          }
846         
847          if (isset($params['cat_id']) && $params['cat_id'] !== '')
848          {
849               if (!is_array($params['cat_id'])) {
850                    $params['cat_id'] = array($params['cat_id']);
851               }
852               if (!empty($params['cat_id_not'])) {
853                    array_walk($params['cat_id'],create_function('&$v,$k','$v=$v." ?not";'));
854               }
855               $strReq .= 'AND '.$this->getPostsCategoryFilter($params['cat_id'],'cat_id').' ';
856          }
857          elseif (isset($params['cat_url']) && $params['cat_url'] !== '')
858          {
859               if (!is_array($params['cat_url'])) {
860                    $params['cat_url'] = array($params['cat_url']);
861               }
862               if (!empty($params['cat_url_not'])) {
863                    array_walk($params['cat_url'],create_function('&$v,$k','$v=$v." ?not";'));
864               }
865               $strReq .= 'AND '.$this->getPostsCategoryFilter($params['cat_url'],'cat_url').' ';
866          }
867         
868          /* Other filters */
869          if (isset($params['post_status'])) {
870               $strReq .= 'AND post_status = '.(integer) $params['post_status'].' ';
871          }
872         
873          if (isset($params['post_selected'])) {
874               $strReq .= 'AND post_selected = '.(integer) $params['post_selected'].' ';
875          }
876         
877          if (!empty($params['post_year'])) {
878               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%Y').' = '.
879               "'".sprintf('%04d',$params['post_year'])."' ";
880          }
881         
882          if (!empty($params['post_month'])) {
883               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%m').' = '.
884               "'".sprintf('%02d',$params['post_month'])."' ";
885          }
886         
887          if (!empty($params['post_day'])) {
888               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%d').' = '.
889               "'".sprintf('%02d',$params['post_day'])."' ";
890          }
891         
892          if (!empty($params['post_lang'])) {
893               $strReq .= "AND P.post_lang = '".$this->con->escape($params['post_lang'])."' ";
894          }
895         
896          if (!empty($params['search']))
897          {
898               $words = text::splitWords($params['search']);
899               
900               if (!empty($words))
901               {
902                    # --BEHAVIOR-- corePostSearch
903                    if ($this->core->hasBehavior('corePostSearch')) {
904                         $this->core->callBehavior('corePostSearch',$this->core,array(&$words,&$strReq,&$params));
905                    }
906                   
907                    if ($words)
908                    {
909                         foreach ($words as $i => $w) {
910                              $words[$i] = "post_words LIKE '%".$this->con->escape($w)."%'";
911                         }
912                         $strReq .= 'AND '.implode(' AND ',$words).' ';
913                    }
914               }
915          }
916         
917          if (!empty($params['sql'])) {
918               $strReq .= $params['sql'].' ';
919          }
920         
921          if (!$count_only)
922          {
923               if (!empty($params['order'])) {
924                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
925               } else {
926                    $strReq .= 'ORDER BY post_dt DESC ';
927               }
928               if (!empty($params['limit'])) {
929                    $strReq .= $this->con->limit($params['limit']);
930               }
931          }
932         
933          if (!empty($params['sql_only'])) {
934               return $strReq;
935          }
936         
937          $rs = $this->con->select($strReq);
938          $rs->core = $this->core;
939          $rs->_nb_media = array();
940          $rs->extend('rsExtPost');
941         
942          # --BEHAVIOR-- coreBlogGetPosts
943          $this->core->callBehavior('coreBlogGetPosts',$rs);
944         
945          return $rs;
946     }
947     
948     /**
949     Returns a record with post id, title and date for next or previous post
950     according to the post ID.
951     $dir could be 1 (next post) or -1 (previous post).
952     
953     @param    post_id                  <b>integer</b>      Post ID
954     @param    dir                      <b>integer</b>      Search direction
955     @param    restrict_to_category     <b>boolean</b>      Restrict to post with same category
956     @param    restrict_to_lang         <b>boolean</b>      Restrict to post with same lang
957     @return   record
958     */
959     public function getNextPost($post,$dir,$restrict_to_category=false, $restrict_to_lang=false)
960     {
961          $dt = $post->post_dt;
962          $post_id = (integer) $post->post_id;
963         
964          if($dir > 0) {
965               $sign = '>';
966               $order = 'ASC';
967          }
968          else {
969               $sign = '<';
970               $order = 'DESC';
971          }
972         
973          $params['post_type'] = $post->post_type;
974          $params['limit'] = 1;
975          $params['order'] = 'post_dt '.$order.', P.post_id '.$order;
976          $params['sql'] =
977          'AND ( '.
978          "    (post_dt = '".$this->con->escape($dt)."' AND P.post_id ".$sign." ".$post_id.") ".
979          "    OR post_dt ".$sign." '".$this->con->escape($dt)."' ".
980          ') ';
981         
982          if ($restrict_to_category) {
983               $params['sql'] .= $post->cat_id ? 'AND P.cat_id = '.(integer) $post->cat_id.' ' : 'AND P.cat_id IS NULL ';
984          }
985         
986          if ($restrict_to_lang) {
987               $params['sql'] .= $post->post_lang ? 'AND P.post_lang = \''. $this->con->escape($post->post_lang) .'\' ': 'AND P.post_lang IS NULL ';
988          }
989         
990          $rs = $this->getPosts($params);
991         
992          if ($rs->isEmpty()) {
993               return null;
994          }
995         
996          return $rs;
997     }
998     
999     /**
1000     Retrieves different languages and post count on blog, based on post_lang
1001     field. <var>$params</var> is an array taking the following optionnal
1002     parameters:
1003     
1004     - post_type: Get only entries with given type (default "post", '' for no type)
1005     - lang: retrieve post count for selected lang
1006     - order: order statement (default post_lang DESC)
1007     
1008     @param    params    <b>array</b>        Parameters
1009     @return   record
1010     */
1011     public function getLangs($params=array())
1012     {
1013          $strReq = 'SELECT COUNT(post_id) as nb_post, post_lang '.
1014                    'FROM '.$this->prefix.'post '.
1015                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1016                    "AND post_lang <> '' ".
1017                    "AND post_lang IS NOT NULL ";
1018         
1019          if (!$this->core->auth->check('contentadmin',$this->id)) {
1020               $strReq .= 'AND ((post_status = 1 ';
1021               
1022               if ($this->without_password) {
1023                    $strReq .= 'AND post_password IS NULL ';
1024               }
1025               $strReq .= ') ';
1026               
1027               if ($this->core->auth->userID()) {
1028                    $strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."')";
1029               } else {
1030                    $strReq .= ') ';
1031               }
1032          }
1033         
1034          if (isset($params['post_type'])) {
1035               if ($params['post_type'] != '') {
1036                    $strReq .= "AND post_type = '".$this->con->escape($params['post_type'])."' ";
1037               }
1038          } else {
1039               $strReq .= "AND post_type = 'post' ";
1040          }
1041         
1042          if (isset($params['lang'])) {
1043               $strReq .= "AND post_lang = '".$this->con->escape($params['lang'])."' ";
1044          }
1045         
1046          $strReq .= 'GROUP BY post_lang ';
1047         
1048          $order = 'desc';
1049          if (!empty($params['order']) && preg_match('/^(desc|asc)$/i',$params['order'])) {
1050               $order = $params['order'];
1051          }
1052          $strReq .= 'ORDER BY post_lang '.$order.' ';
1053         
1054          return $this->con->select($strReq);
1055     }
1056     
1057     /**
1058     Returns a record with all distinct blog dates and post count.
1059     <var>$params</var> is an array taking the following optionnal parameters:
1060     
1061     - type: (day|month|year) Get days, months or years
1062     - year: (integer) Get dates for given year
1063     - month: (integer) Get dates for given month
1064     - day: (integer) Get dates for given day
1065     - cat_id: (integer) Category ID filter
1066     - cat_url: Category URL filter
1067     - post_lang: lang of the posts
1068     - next: Get date following match
1069     - previous: Get date before match
1070     - order: Sort by date "ASC" or "DESC"
1071     
1072     @param    params    <b>array</b>        Parameters array
1073     @return   record
1074     */
1075     public function getDates($params=array())
1076     {
1077          $dt_f = '%Y-%m-%d';
1078          $dt_fc = '%Y%m%d';
1079          if (isset($params['type'])) {
1080               if ($params['type'] == 'year') {
1081                    $dt_f = '%Y-01-01';
1082                    $dt_fc = '%Y0101';
1083               } elseif ($params['type'] == 'month') {
1084                    $dt_f = '%Y-%m-01';
1085                    $dt_fc = '%Y%m01';
1086               }
1087          }
1088          $dt_f .= ' 00:00:00';
1089          $dt_fc .= '000000';
1090         
1091          $cat_field = $catReq = $limit = '';
1092         
1093          if (isset($params['cat_id']) && $params['cat_id'] !== '') {
1094               $catReq = 'AND P.cat_id = '.(integer) $params['cat_id'].' ';
1095               $cat_field = ', C.cat_url ';
1096          } elseif (isset($params['cat_url']) && $params['cat_url'] !== '') {
1097               $catReq = "AND C.cat_url = '".$this->con->escape($params['cat_url'])."' ";
1098               $cat_field = ', C.cat_url ';
1099          }
1100          if (!empty($params['post_lang'])) {
1101               $catReq = 'AND P.post_lang = \''. $params['post_lang'].'\' ';
1102          }
1103         
1104          $strReq = 'SELECT DISTINCT('.$this->con->dateFormat('post_dt',$dt_f).') AS dt '.
1105                    $cat_field.
1106                    ',COUNT(P.post_id) AS nb_post '.
1107                    'FROM '.$this->prefix.'post P LEFT JOIN '.$this->prefix.'category C '.
1108                    'ON P.cat_id = C.cat_id '.
1109                    "WHERE P.blog_id = '".$this->con->escape($this->id)."' ".
1110                    $catReq;
1111         
1112          if (!$this->core->auth->check('contentadmin',$this->id)) {
1113               $strReq .= 'AND ((post_status = 1 ';
1114               
1115               if ($this->without_password) {
1116                    $strReq .= 'AND post_password IS NULL ';
1117               }
1118               $strReq .= ') ';
1119               
1120               if ($this->core->auth->userID()) {
1121                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
1122               } else {
1123                    $strReq .= ') ';
1124               }
1125          }
1126         
1127          if (!empty($params['post_type'])) {
1128               $strReq .= "AND post_type ".$this->con->in($params['post_type'])." ";
1129          } else {
1130               $strReq .= "AND post_type = 'post' ";
1131          }
1132         
1133          if (!empty($params['year'])) {
1134               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%Y')." = '".sprintf('%04d',$params['year'])."' ";
1135          }
1136         
1137          if (!empty($params['month'])) {
1138               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%m')." = '".sprintf('%02d',$params['month'])."' ";
1139          }
1140         
1141          if (!empty($params['day'])) {
1142               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%d')." = '".sprintf('%02d',$params['day'])."' ";
1143          }
1144         
1145          # Get next or previous date
1146          if (!empty($params['next']) || !empty($params['previous']))
1147          {
1148               if (!empty($params['next'])) {
1149                    $pdir = ' > ';
1150                    $params['order'] = 'asc';
1151                    $dt = $params['next'];
1152               } else {
1153                    $pdir = ' < ';
1154                    $params['order'] = 'desc';
1155                    $dt = $params['previous'];
1156               }
1157               
1158               $dt = date('YmdHis',strtotime($dt));
1159               
1160               $strReq .= 'AND '.$this->con->dateFormat('post_dt',$dt_fc).$pdir."'".$dt."' ";
1161               $limit = $this->con->limit(1);
1162          }
1163         
1164          $strReq .= 'GROUP BY dt '.$cat_field;
1165         
1166          $order = 'desc';
1167          if (!empty($params['order']) && preg_match('/^(desc|asc)$/i',$params['order'])) {
1168               $order = $params['order'];
1169          }
1170         
1171          $strReq .=
1172          'ORDER BY dt '.$order.' '.
1173          $limit;
1174         
1175          $rs = $this->con->select($strReq);
1176          $rs->extend('rsExtDates');
1177          return $rs;
1178     }
1179     
1180     /**
1181     Creates a new entry. Takes a cursor as input and returns the new entry
1182     ID.
1183     
1184     @param    cur       <b>cursor</b>       Post cursor
1185     @return   <b>integer</b>      New post ID
1186     */
1187     public function addPost($cur)
1188     {
1189          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1190               throw new Exception(__('You are not allowed to create an entry'));
1191          }
1192         
1193          $this->con->writeLock($this->prefix.'post');
1194          try
1195          {
1196               # Get ID
1197               $rs = $this->con->select(
1198                    'SELECT MAX(post_id) '.
1199                    'FROM '.$this->prefix.'post ' 
1200                    );
1201               
1202               $cur->post_id = (integer) $rs->f(0) + 1;
1203               $cur->blog_id = (string) $this->id;
1204               $cur->post_creadt = date('Y-m-d H:i:s');
1205               $cur->post_upddt = date('Y-m-d H:i:s');
1206               $cur->post_tz = $this->core->auth->getInfo('user_tz');
1207               
1208               # Post excerpt and content
1209               $this->getPostContent($cur,$cur->post_id);
1210               
1211               $this->getPostCursor($cur);
1212               
1213               $cur->post_url = $this->getPostURL($cur->post_url,$cur->post_dt,$cur->post_title,$cur->post_id);
1214               
1215               if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1216                    $cur->post_status = -2;
1217               }
1218               
1219               # --BEHAVIOR-- coreBeforePostCreate
1220               $this->core->callBehavior('coreBeforePostCreate',$this,$cur);
1221               
1222               $cur->insert();
1223               $this->con->unlock();
1224          }
1225          catch (Exception $e)
1226          {
1227               $this->con->unlock();
1228               throw $e;
1229          }
1230         
1231          # --BEHAVIOR-- coreAfterPostCreate
1232          $this->core->callBehavior('coreAfterPostCreate',$this,$cur);
1233         
1234          $this->triggerBlog();
1235         
1236          return $cur->post_id;
1237     }
1238     
1239     /**
1240     Updates an existing post.
1241     
1242     @param    id        <b>integer</b>      Post ID
1243     @param    cur       <b>cursor</b>       Post cursor
1244     */
1245     public function updPost($id,$cur)
1246     {
1247          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1248               throw new Exception(__('You are not allowed to update entries'));
1249          }
1250         
1251          $id = (integer) $id;
1252         
1253          if (empty($id)) {
1254               throw new Exception(__('No such entry ID'));
1255          }
1256         
1257          # Post excerpt and content
1258          $this->getPostContent($cur,$id);
1259         
1260          $this->getPostCursor($cur);
1261         
1262          if ($cur->post_url !== null) {
1263               $cur->post_url = $this->getPostURL($cur->post_url,$cur->post_dt,$cur->post_title,$id);
1264          }
1265         
1266          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1267               $cur->unsetField('post_status');
1268          }
1269         
1270          $cur->post_upddt = date('Y-m-d H:i:s');
1271         
1272          #If user is only "usage", we need to check the post's owner
1273          if (!$this->core->auth->check('contentadmin',$this->id))
1274          {
1275               $strReq = 'SELECT post_id '.
1276                         'FROM '.$this->prefix.'post '.
1277                         'WHERE post_id = '.$id.' '.
1278                         "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1279               
1280               $rs = $this->con->select($strReq);
1281               
1282               if ($rs->isEmpty()) {
1283                    throw new Exception(__('You are not allowed to edit this entry'));
1284               }
1285          }
1286         
1287          # --BEHAVIOR-- coreBeforePostUpdate
1288          $this->core->callBehavior('coreBeforePostUpdate',$this,$cur);
1289         
1290          $cur->update('WHERE post_id = '.$id.' ');
1291         
1292          # --BEHAVIOR-- coreAfterPostUpdate
1293          $this->core->callBehavior('coreAfterPostUpdate',$this,$cur);
1294         
1295          $this->triggerBlog();
1296     }
1297     
1298     /**
1299     Updates post status.
1300     
1301     @param    id        <b>integer</b>      Post ID
1302     @param    status    <b>integer</b>      Post status
1303     */
1304     public function updPostStatus($id,$status)
1305     {
1306          $this->updPostsStatus($id,$status);
1307     }
1308     
1309     /**
1310     Updates posts status.
1311     
1312     @param    ids       <b>mixed</b>        Post(s) ID(s)
1313     @param    status    <b>integer</b>      Post status
1314     */
1315     public function updPostsStatus($ids,$status)
1316     {
1317          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1318               throw new Exception(__('You are not allowed to change this entry status'));
1319          }
1320         
1321          $posts_ids = dcUtils::cleanIds($ids);
1322          $status = (integer) $status;
1323         
1324          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1325                    "AND post_id ".$this->con->in($posts_ids);
1326         
1327          #If user can only publish, we need to check the post's owner
1328          if (!$this->core->auth->check('contentadmin',$this->id))
1329          {
1330               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1331          }
1332         
1333          $cur = $this->con->openCursor($this->prefix.'post');
1334         
1335          $cur->post_status = $status;
1336          $cur->post_upddt = date('Y-m-d H:i:s');
1337         
1338          $cur->update($strReq);
1339          $this->triggerBlog();
1340     }
1341     
1342     /**
1343     Updates post selection.
1344     
1345     @param    id        <b>integer</b>      Post ID
1346     @param    selected  <b>integer</b>      Is selected post
1347     */
1348     public function updPostSelected($id,$selected)
1349     {
1350          $this->updPostsSelected($id,$selected);
1351     }
1352     
1353     /**
1354     Updates posts selection.
1355     
1356     @param    ids       <b>mixed</b>        Post(s) ID(s)
1357     @param    selected  <b>integer</b>      Is selected post(s)
1358     */
1359     public function updPostsSelected($ids,$selected)
1360     {
1361          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1362               throw new Exception(__('You are not allowed to change this entry category'));
1363          }
1364         
1365          $posts_ids = dcUtils::cleanIds($ids);
1366          $selected = (boolean) $selected;
1367         
1368          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1369                    "AND post_id ".$this->con->in($posts_ids);
1370         
1371          # If user is only usage, we need to check the post's owner
1372          if (!$this->core->auth->check('contentadmin',$this->id))
1373          {
1374               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1375          }
1376         
1377          $cur = $this->con->openCursor($this->prefix.'post');
1378         
1379          $cur->post_selected = (integer) $selected;
1380          $cur->post_upddt = date('Y-m-d H:i:s');
1381         
1382          $cur->update($strReq);
1383          $this->triggerBlog();
1384     }
1385     
1386     /**
1387     Updates post category. <var>$cat_id</var> can be null.
1388     
1389     @param    id        <b>integer</b>      Post ID
1390     @param    cat_id    <b>integer</b>      Category ID
1391     */
1392     public function updPostCategory($id,$cat_id)
1393     {
1394          $this->updPostsCategory($id,$cat_id);
1395     }
1396     
1397     /**
1398     Updates posts category. <var>$cat_id</var> can be null.
1399     
1400     @param    ids       <b>mixed</b>        Post(s) ID(s)
1401     @param    cat_id    <b>integer</b>      Category ID
1402     */
1403     public function updPostsCategory($ids,$cat_id)
1404     {
1405          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1406               throw new Exception(__('You are not allowed to change this entry category'));
1407          }
1408         
1409          $posts_ids = dcUtils::cleanIds($ids);
1410          $cat_id = (integer) $cat_id;
1411         
1412          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1413                    "AND post_id ".$this->con->in($posts_ids);
1414         
1415          # If user is only usage, we need to check the post's owner
1416          if (!$this->core->auth->check('contentadmin',$this->id))
1417          {
1418               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1419          }
1420         
1421          $cur = $this->con->openCursor($this->prefix.'post');
1422         
1423          $cur->cat_id = ($cat_id ? $cat_id : null);
1424          $cur->post_upddt = date('Y-m-d H:i:s');
1425         
1426          $cur->update($strReq);
1427          $this->triggerBlog();
1428     }
1429     
1430     /**
1431     Updates posts category. <var>$new_cat_id</var> can be null.
1432     
1433     @param    old_cat_id     <b>integer</b>      Old category ID
1434     @param    new_cat_id     <b>integer</b>      New category ID
1435     */
1436     public function changePostsCategory($old_cat_id,$new_cat_id)
1437     {
1438          if (!$this->core->auth->check('contentadmin,categories',$this->id)) {
1439               throw new Exception(__('You are not allowed to change entries category'));
1440          }
1441         
1442          $old_cat_id = (integer) $old_cat_id;
1443          $new_cat_id = (integer) $new_cat_id;
1444         
1445          $cur = $this->con->openCursor($this->prefix.'post');
1446         
1447          $cur->cat_id = ($new_cat_id ? $new_cat_id : null);
1448          $cur->post_upddt = date('Y-m-d H:i:s');
1449         
1450          $cur->update(
1451               'WHERE cat_id = '.$old_cat_id.' '.
1452               "AND blog_id = '".$this->con->escape($this->id)."' "
1453          );
1454          $this->triggerBlog();
1455     }
1456     
1457     /**
1458     Deletes a post.
1459     
1460     @param    id        <b>integer</b>      Post ID
1461     */
1462     public function delPost($id)
1463     {
1464          $this->delPosts($id);
1465     }
1466     
1467     /**
1468     Deletes multiple posts.
1469     
1470     @param    ids       <b>mixed</b>        Post(s) ID(s)
1471     */
1472     public function delPosts($ids)
1473     {
1474          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
1475               throw new Exception(__('You are not allowed to delete entries'));
1476          }
1477         
1478          $posts_ids = dcUtils::cleanIds($ids);
1479         
1480          if (empty($posts_ids)) {
1481               throw new Exception(__('No such entry ID'));
1482          }
1483         
1484          $strReq = 'DELETE FROM '.$this->prefix.'post '.
1485                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1486                    "AND post_id ".$this->con->in($posts_ids);
1487         
1488          #If user can only delete, we need to check the post's owner
1489          if (!$this->core->auth->check('contentadmin',$this->id))
1490          {
1491               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1492          }
1493         
1494          $this->con->execute($strReq);
1495          $this->triggerBlog();
1496     }
1497     
1498     /**
1499     Publishes all entries flaged as "scheduled".
1500     */
1501     public function publishScheduledEntries()
1502     {
1503          $strReq = 'SELECT post_id, post_dt, post_tz '.
1504                    'FROM '.$this->prefix.'post '.
1505                    'WHERE post_status = -1 '.
1506                    "AND blog_id = '".$this->con->escape($this->id)."' ";
1507         
1508          $rs = $this->con->select($strReq);
1509         
1510          $now = dt::toUTC(time());
1511          $to_change = new ArrayObject();
1512
1513          if ($rs->isEmpty()) {
1514               return;
1515          }
1516         
1517          while ($rs->fetch())
1518          {
1519               # Now timestamp with post timezone
1520               $now_tz = $now + dt::getTimeOffset($rs->post_tz,$now);
1521               
1522               # Post timestamp
1523               $post_ts = strtotime($rs->post_dt);
1524               
1525               # If now_tz >= post_ts, we publish the entry
1526               if ($now_tz >= $post_ts) {
1527                    $to_change[] = (integer) $rs->post_id;
1528               }
1529          }
1530          if (count($to_change))
1531          {
1532               # --BEHAVIOR-- coreBeforeScheduledEntriesPublish
1533               $this->core->callBehavior('coreBeforeScheduledEntriesPublish',$this,$to_change);
1534
1535               $strReq =
1536               'UPDATE '.$this->prefix.'post SET '.
1537               'post_status = 1 '.
1538               "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1539               'AND post_id '.$this->con->in((array)$to_change).' ';
1540               $this->con->execute($strReq);
1541               $this->triggerBlog();
1542
1543               # --BEHAVIOR-- coreAfterScheduledEntriesPublish
1544               $this->core->callBehavior('coreAfterScheduledEntriesPublish',$this,$to_change);
1545          }
1546         
1547     }
1548     
1549     /**
1550     Retrieves all users having posts on current blog.
1551     
1552     @param    post_type      <b>string</b>       post_type filter (post)
1553     @return   record
1554     */
1555     public function getPostsUsers($post_type='post')
1556     {
1557          $strReq = 'SELECT P.user_id, user_name, user_firstname, '.
1558                    'user_displayname, user_email '.
1559                    'FROM '.$this->prefix.'post P, '.$this->prefix.'user U '.
1560                    'WHERE P.user_id = U.user_id '.
1561                    "AND blog_id = '".$this->con->escape($this->id)."' ";
1562         
1563          if ($post_type) {
1564               $strReq .= "AND post_type = '".$this->con->escape($post_type)."' ";
1565          }
1566         
1567          $strReq .= 'GROUP BY P.user_id, user_name, user_firstname, user_displayname, user_email ';
1568         
1569          return $this->con->select($strReq);
1570     }
1571     
1572     private function getPostsCategoryFilter($arr,$field='cat_id')
1573     {
1574          $field = $field == 'cat_id' ? 'cat_id' : 'cat_url';
1575         
1576          $sub = array();
1577          $not = array();
1578          $queries = array();
1579         
1580          foreach ($arr as $v)
1581          {
1582               $v = trim($v);
1583               $args = preg_split('/\s*[?]\s*/',$v,-1,PREG_SPLIT_NO_EMPTY);
1584               $id = array_shift($args);
1585               $args = array_flip($args);
1586               
1587               if (isset($args['not'])) { $not[$id] = 1; }
1588               if (isset($args['sub'])) { $sub[$id] = 1; }
1589               if ($field == 'cat_id') {
1590                    if (preg_match('/^null$/i',$id)) {
1591                         $queries[$id] = 'P.cat_id IS NULL';
1592                    }
1593                    else {
1594                         $queries[$id] = 'P.cat_id = '.(integer) $id;
1595                    }
1596               } else {
1597                    $queries[$id] = "C.cat_url = '".$this->con->escape($id)."' ";
1598               }
1599          }
1600         
1601          if (!empty($sub)) {
1602               $rs = $this->con->select(
1603                    'SELECT cat_id, cat_url, cat_lft, cat_rgt FROM '.$this->prefix.'category '.
1604                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1605                    'AND '.$field.' '.$this->con->in(array_keys($sub))
1606               );
1607               
1608               while ($rs->fetch()) {
1609                    $queries[$rs->f($field)] = '(C.cat_lft BETWEEN '.$rs->cat_lft.' AND '.$rs->cat_rgt.')';
1610               }
1611          }
1612         
1613          # Create queries
1614          $sql = array(
1615               0 => array(), # wanted categories
1616               1 => array()  # excluded categories
1617          );
1618         
1619          foreach ($queries as $id => $q) {
1620               $sql[(integer) isset($not[$id])][] = $q;
1621          }
1622         
1623          $sql[0] = implode(' OR ',$sql[0]);
1624          $sql[1] = implode(' OR ',$sql[1]);
1625         
1626          if ($sql[0]) {
1627               $sql[0] = '('.$sql[0].')';
1628          } else {
1629               unset($sql[0]);
1630          }
1631         
1632          if ($sql[1]) {
1633               $sql[1] = '(P.cat_id IS NULL OR NOT('.$sql[1].'))';
1634          } else {
1635               unset($sql[1]);
1636          }
1637         
1638          return implode(' AND ',$sql);
1639     }
1640     
1641     private function getPostCursor($cur,$post_id=null)
1642     {
1643          if ($cur->post_title == '') {
1644               throw new Exception(__('No entry title'));
1645          }
1646         
1647          if ($cur->post_content == '') {
1648               throw new Exception(__('No entry content'));
1649          }
1650         
1651          if ($cur->post_password === '') {
1652               $cur->post_password = null;
1653          }
1654         
1655          if ($cur->post_dt == '') {
1656               $offset = dt::getTimeOffset($this->core->auth->getInfo('user_tz'));
1657               $now = time() + $offset;
1658               $cur->post_dt = date('Y-m-d H:i:00',$now);
1659          }
1660         
1661          $post_id = is_int($post_id) ? $post_id : $cur->post_id;
1662         
1663          if ($cur->post_content_xhtml == '') {
1664               throw new Exception(__('No entry content'));
1665          }
1666         
1667          # Words list
1668          if ($cur->post_title !== null && $cur->post_excerpt_xhtml !== null
1669          && $cur->post_content_xhtml !== null)
1670          {
1671               $words =
1672               $cur->post_title.' '.
1673               $cur->post_excerpt_xhtml.' '.
1674               $cur->post_content_xhtml;
1675               
1676               $cur->post_words = implode(' ',text::splitWords($words));
1677          }
1678     }
1679     
1680     private function getPostContent($cur,$post_id)
1681     {
1682          $post_excerpt = $cur->post_excerpt;
1683          $post_excerpt_xhtml = $cur->post_excerpt_xhtml;
1684          $post_content = $cur->post_content;
1685          $post_content_xhtml = $cur->post_content_xhtml;
1686         
1687          $this->setPostContent(
1688               $post_id,$cur->post_format,$cur->post_lang,
1689               $post_excerpt,$post_excerpt_xhtml,
1690               $post_content,$post_content_xhtml
1691          );
1692         
1693          $cur->post_excerpt = $post_excerpt;
1694          $cur->post_excerpt_xhtml = $post_excerpt_xhtml;
1695          $cur->post_content = $post_content;
1696          $cur->post_content_xhtml = $post_content_xhtml;
1697     }
1698     
1699     /**
1700     Creates post HTML content, taking format and lang into account.
1701     
1702     @param         post_id        <b>integer</b>      Post ID
1703     @param         format         <b>string</b>       Post format
1704     @param         lang           <b>string</b>       Post lang
1705     @param         excerpt        <b>string</b>       Post excerpt
1706     @param[out]    excerpt_xhtml  <b>string</b>       Post excerpt HTML
1707     @param         content        <b>string</b>       Post content
1708     @param[out]    content_xhtml  <b>string</b>       Post content HTML
1709     */
1710     public function setPostContent($post_id,$format,$lang,&$excerpt,&$excerpt_xhtml,&$content,&$content_xhtml)
1711     {
1712          if ($format == 'wiki')
1713          {
1714               $this->core->initWikiPost();
1715               $this->core->wiki2xhtml->setOpt('note_prefix','pnote-'.$post_id);
1716               switch ($this->settings->system->note_title_tag) {
1717                    case 1:
1718                         $tag = 'h3';
1719                         break;
1720                    case 2:
1721                         $tag = 'p';
1722                         break;
1723                    default:
1724                         $tag = 'h4';
1725                         break;
1726               }
1727               $this->core->wiki2xhtml->setOpt('note_str','<div class="footnotes"><'.$tag.' class="footnotes-title">'.
1728                    __('Notes').'</'.$tag.'>%s</div>');
1729               $this->core->wiki2xhtml->setOpt('note_str_single','<div class="footnotes"><'.$tag.' class="footnotes-title">'.
1730                    __('Note').'</'.$tag.'>%s</div>');
1731               if (strpos($lang,'fr') === 0) {
1732                    $this->core->wiki2xhtml->setOpt('active_fr_syntax',1);
1733               }
1734          }
1735         
1736          if ($excerpt) {
1737               $excerpt_xhtml = $this->core->callFormater($format,$excerpt);
1738               $excerpt_xhtml = $this->core->HTMLfilter($excerpt_xhtml);
1739          } else {
1740               $excerpt_xhtml = '';
1741          }
1742         
1743          if ($content) {
1744               $content_xhtml = $this->core->callFormater($format,$content);
1745               $content_xhtml = $this->core->HTMLfilter($content_xhtml);
1746          } else {
1747               $content_xhtml = '';
1748          }
1749         
1750          # --BEHAVIOR-- coreAfterPostContentFormat
1751          $this->core->callBehavior('coreAfterPostContentFormat',array(
1752               'excerpt' => &$excerpt,
1753               'content' => &$content,
1754               'excerpt_xhtml' => &$excerpt_xhtml,
1755               'content_xhtml' => &$content_xhtml
1756          ));
1757     }
1758     
1759     /**
1760     Returns URL for a post according to blog setting <var>post_url_format</var>.
1761     It will try to guess URL and append some figures if needed.
1762     
1763     @param    url            <b>string</b>       Origin URL, could be empty
1764     @param    post_dt        <b>string</b>       Post date (in YYYY-MM-DD HH:mm:ss)
1765     @param    post_title     <b>string</b>       Post title
1766     @param    post_id        <b>integer</b>      Post ID
1767     @return   <b>string</b>  result URL
1768     */
1769     public function getPostURL($url,$post_dt,$post_title,$post_id)
1770     {
1771          $url = trim($url);
1772         
1773          $url_patterns = array(
1774          '{y}' => date('Y',strtotime($post_dt)),
1775          '{m}' => date('m',strtotime($post_dt)),
1776          '{d}' => date('d',strtotime($post_dt)),
1777          '{t}' => text::tidyURL($post_title),
1778          '{id}' => (integer) $post_id
1779          );
1780         
1781          # If URL is empty, we create a new one
1782          if ($url == '')
1783          {
1784               # Transform with format
1785               $url = str_replace(
1786                    array_keys($url_patterns),
1787                    array_values($url_patterns),
1788                    $this->settings->system->post_url_format
1789               );
1790          }
1791          else
1792          {
1793               $url = text::tidyURL($url);
1794          }
1795         
1796          # Let's check if URL is taken...
1797          $strReq = 'SELECT post_url FROM '.$this->prefix.'post '.
1798                    "WHERE post_url = '".$this->con->escape($url)."' ".
1799                    'AND post_id <> '.(integer) $post_id. ' '.
1800                    "AND blog_id = '".$this->con->escape($this->id)."' ".
1801                    'ORDER BY post_url DESC';
1802         
1803          $rs = $this->con->select($strReq);
1804         
1805          if (!$rs->isEmpty())
1806          {
1807               if ($this->con->driver() == 'mysql') {
1808                    $clause = "REGEXP '^".$this->con->escape($url)."[0-9]+$'";
1809               } elseif ($this->con->driver() == 'pgsql') {
1810                    $clause = "~ '^".$this->con->escape($url)."[0-9]+$'";
1811               } else {
1812                    $clause = "LIKE '".$this->con->escape($url)."%'";
1813               }
1814               $strReq = 'SELECT post_url FROM '.$this->prefix.'post '.
1815                         "WHERE post_url ".$clause.' '.
1816                         'AND post_id <> '.(integer) $post_id.' '.
1817                         "AND blog_id = '".$this->con->escape($this->id)."' ".
1818                         'ORDER BY post_url DESC ';
1819               
1820               $rs = $this->con->select($strReq);
1821               $a = array();
1822               while ($rs->fetch()) {
1823                    $a[] = $rs->post_url;
1824               }
1825               
1826               natsort($a);
1827               $t_url = end($a);
1828               
1829               if (preg_match('/(.*?)([0-9]+)$/',$t_url,$m)) {
1830                    $i = (integer) $m[2];
1831                    $url = $m[1];
1832               } else {
1833                    $i = 1;
1834               }
1835               
1836               return $url.($i+1);
1837          }
1838         
1839          # URL is empty?
1840          if ($url == '') {
1841               throw new Exception(__('Empty entry URL'));
1842          }
1843         
1844          return $url;
1845     }
1846     //@}
1847     
1848     /// @name Comments management methods
1849     //@{
1850     /**
1851     Retrieves comments. <b>$params</b> is an array taking the following
1852     optionnal parameters:
1853     
1854     - no_content: Don't retrieve comment content
1855     - post_type: Get only entries with given type (default no type, array for many types)
1856     - post_id: (integer) Get comments belonging to given post_id
1857     - cat_id: (integer or array) Get comments belonging to entries of given category ID
1858     - comment_id: (integer) Get comment with given ID
1859     - comment_status: (integer) Get comments with given comment_status
1860     - comment_trackback: (integer) Get only comments (0) or trackbacks (1)
1861     - comment_ip: (string) Get comments with given IP address
1862     - post_url: Get entry with given post_url field
1863     - user_id: (integer) Get entries belonging to given user ID
1864     - q_author: Search comments by author
1865     - sql: Append SQL string at the end of the query
1866     - from: Append SQL string after "FROM" statement in query
1867     - order: Order of results (default "ORDER BY comment_dt DES")
1868     - limit: Limit parameter
1869     - sql_only : return the sql request instead of results. Only ids are selected
1870     
1871     @param    params         <b>array</b>        Parameters
1872     @param    count_only     <b>boolean</b>      Only counts results
1873     @return   <b>record</b>  A record with some more capabilities
1874     */
1875     public function getComments($params=array(),$count_only=false)
1876     {
1877          if ($count_only)
1878          {
1879               $strReq = 'SELECT count(comment_id) ';
1880          }
1881          elseif (!empty($params['sql_only'])) 
1882          {
1883               $strReq = 'SELECT P.post_id ';
1884          }
1885          else
1886          {
1887               if (!empty($params['no_content'])) {
1888                    $content_req = '';
1889               } else {
1890                    $content_req = 'comment_content, ';
1891               }
1892               
1893               if (!empty($params['columns']) && is_array($params['columns'])) {
1894                    $content_req .= implode(', ',$params['columns']).', ';
1895               }
1896               
1897               $strReq =
1898               'SELECT C.comment_id, comment_dt, comment_tz, comment_upddt, '.
1899               'comment_author, comment_email, comment_site, '.
1900               $content_req.' comment_trackback, comment_status, '.
1901               'comment_spam_status, comment_spam_filter, comment_ip, '.
1902               'P.post_title, P.post_url, P.post_id, P.post_password, P.post_type, '.
1903               'P.post_dt, P.user_id, U.user_email, U.user_url ';
1904          }
1905         
1906          $strReq .=
1907          'FROM '.$this->prefix.'comment C '.
1908          'INNER JOIN '.$this->prefix.'post P ON C.post_id = P.post_id '.
1909          'INNER JOIN '.$this->prefix.'user U ON P.user_id = U.user_id ';
1910         
1911          if (!empty($params['from'])) {
1912               $strReq .= $params['from'].' ';
1913          }
1914         
1915          $strReq .=
1916          "WHERE P.blog_id = '".$this->con->escape($this->id)."' ";
1917         
1918          if (!$this->core->auth->check('contentadmin',$this->id)) {
1919               $strReq .= 'AND ((comment_status = 1 AND P.post_status = 1 ';
1920               
1921               if ($this->without_password) {
1922                    $strReq .= 'AND post_password IS NULL ';
1923               }
1924               $strReq .= ') ';
1925               
1926               if ($this->core->auth->userID()) {
1927                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
1928               } else {
1929                    $strReq .= ') ';
1930               }
1931          }
1932         
1933          if (!empty($params['post_type']))
1934          {
1935               $strReq .= 'AND post_type '.$this->con->in($params['post_type']);
1936          }
1937         
1938          if (isset($params['post_id']) && $params['post_id'] !== '') {
1939               $strReq .= 'AND P.post_id = '.(integer) $params['post_id'].' ';
1940          }
1941         
1942          if (isset($params['cat_id']) && $params['cat_id'] !== '') {
1943               $strReq .= 'AND P.cat_id = '.(integer) $params['cat_id'].' ';
1944          }
1945         
1946          if (isset($params['comment_id']) && $params['comment_id'] !== '') {
1947               $strReq .= 'AND comment_id = '.(integer) $params['comment_id'].' ';
1948          }
1949         
1950          if (isset($params['comment_status'])) {
1951               $strReq .= 'AND comment_status = '.(integer) $params['comment_status'].' ';
1952          }
1953         
1954          if (!empty($params['comment_status_not']))
1955          {
1956               $strReq .= 'AND comment_status <> '.(integer) $params['comment_status_not'].' ';
1957          }
1958         
1959          if (isset($params['comment_trackback'])) {
1960               $strReq .= 'AND comment_trackback = '.(integer) (boolean) $params['comment_trackback'].' ';
1961          }
1962         
1963          if (isset($params['comment_ip'])) {
1964               $comment_ip = $this->con->escape(str_replace('*','%',$params['comment_ip']));
1965               $strReq .= "AND comment_ip LIKE '".$comment_ip."' ";
1966          }
1967         
1968          if (isset($params['q_author'])) {
1969               $q_author = $this->con->escape(str_replace('*','%',strtolower($params['q_author'])));
1970               $strReq .= "AND LOWER(comment_author) LIKE '".$q_author."' ";
1971          }
1972         
1973          if (!empty($params['search']))
1974          {
1975               $words = text::splitWords($params['search']);
1976               
1977               if (!empty($words))
1978               {
1979                    # --BEHAVIOR coreCommentSearch
1980                    if ($this->core->hasBehavior('coreCommentSearch')) {
1981                         $this->core->callBehavior('coreCommentSearch',$this->core,array(&$words,&$strReq,&$params));
1982                    }
1983                   
1984                    if ($words)
1985                    {
1986                         foreach ($words as $i => $w) {
1987                              $words[$i] = "comment_words LIKE '%".$this->con->escape($w)."%'";
1988                         }
1989                         $strReq .= 'AND '.implode(' AND ',$words).' ';
1990                    }
1991               }
1992          }
1993         
1994          if (!empty($params['sql'])) {
1995               $strReq .= $params['sql'].' ';
1996          }
1997         
1998          if (!$count_only)
1999          {
2000               if (!empty($params['order'])) {
2001                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
2002               } else {
2003                    $strReq .= 'ORDER BY comment_dt DESC ';
2004               }
2005          }
2006         
2007          if (!$count_only && !empty($params['limit'])) {
2008               $strReq .= $this->con->limit($params['limit']);
2009          }
2010
2011          if (!empty($params['sql_only'])) {
2012               return $strReq;
2013          }
2014         
2015          $rs = $this->con->select($strReq);
2016          $rs->core = $this->core;
2017          $rs->extend('rsExtComment');
2018         
2019          # --BEHAVIOR-- coreBlogGetComments
2020          $this->core->callBehavior('coreBlogGetComments',$rs);
2021         
2022          return $rs;
2023     }
2024     
2025     /**
2026     Creates a new comment. Takes a cursor as input and returns the new comment
2027     ID.
2028     
2029     @param    cur       <b>cursor</b>       Comment cursor
2030     @return   <b>integer</b>      New comment ID
2031     */
2032     public function addComment($cur)
2033     {
2034          $this->con->writeLock($this->prefix.'comment');
2035          try
2036          {
2037               # Get ID
2038               $rs = $this->con->select(
2039                    'SELECT MAX(comment_id) '.
2040                    'FROM '.$this->prefix.'comment ' 
2041               );
2042               
2043               $cur->comment_id = (integer) $rs->f(0) + 1;
2044               $cur->comment_upddt = date('Y-m-d H:i:s');
2045               
2046               $offset = dt::getTimeOffset($this->settings->system->blog_timezone);
2047               $cur->comment_dt = date('Y-m-d H:i:s',time() + $offset);
2048               $cur->comment_tz = $this->settings->system->blog_timezone;
2049               
2050               $this->getCommentCursor($cur);
2051               
2052               if ($cur->comment_ip === null) {
2053                    $cur->comment_ip = http::realIP();
2054               }
2055               
2056               # --BEHAVIOR-- coreBeforeCommentCreate
2057               $this->core->callBehavior('coreBeforeCommentCreate',$this,$cur);
2058               
2059               $cur->insert();
2060               $this->con->unlock();
2061          }
2062          catch (Exception $e)
2063          {
2064               $this->con->unlock();
2065               throw $e;
2066          }
2067         
2068          # --BEHAVIOR-- coreAfterCommentCreate
2069          $this->core->callBehavior('coreAfterCommentCreate',$this,$cur);
2070         
2071          $this->triggerComment($cur->comment_id);
2072          if ($cur->comment_status != -2) {
2073               $this->triggerBlog();
2074          }   
2075          return $cur->comment_id;
2076     }
2077     
2078     /**
2079     Updates an existing comment.
2080     
2081     @param    id        <b>integer</b>      Comment ID
2082     @param    cur       <b>cursor</b>       Comment cursor
2083     */
2084     public function updComment($id,$cur)
2085     {
2086          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
2087               throw new Exception(__('You are not allowed to update comments'));
2088          }
2089         
2090          $id = (integer) $id;
2091         
2092          if (empty($id)) {
2093               throw new Exception(__('No such comment ID'));
2094          }
2095         
2096          $rs = $this->getComments(array('comment_id' => $id));
2097         
2098          if ($rs->isEmpty()) {
2099               throw new Exception(__('No such comment ID'));
2100          }
2101         
2102          #If user is only usage, we need to check the post's owner
2103          if (!$this->core->auth->check('contentadmin',$this->id))
2104          {
2105               if ($rs->user_id != $this->core->auth->userID()) {
2106                    throw new Exception(__('You are not allowed to update this comment'));
2107               }
2108          }
2109         
2110          $this->getCommentCursor($cur);
2111         
2112          $cur->comment_upddt = date('Y-m-d H:i:s');
2113         
2114          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
2115               $cur->unsetField('comment_status');
2116          }
2117         
2118          # --BEHAVIOR-- coreBeforeCommentUpdate
2119          $this->core->callBehavior('coreBeforeCommentUpdate',$this,$cur,$rs);
2120         
2121          $cur->update('WHERE comment_id = '.$id.' ');
2122         
2123          # --BEHAVIOR-- coreAfterCommentUpdate
2124          $this->core->callBehavior('coreAfterCommentUpdate',$this,$cur,$rs);
2125         
2126          $this->triggerComment($id);
2127          $this->triggerBlog();
2128     }
2129     
2130     /**
2131     Updates comment status.
2132     
2133     @param    id        <b>integer</b>      Comment ID
2134     @param    status    <b>integer</b>      Comment status
2135     */
2136     public function updCommentStatus($id,$status)
2137     {
2138          $this->updCommentsStatus($id,$status);
2139     }
2140     
2141     /**
2142     Updates comments status.
2143     
2144     @param    ids       <b>mixed</b>        Comment(s) ID(s)
2145     @param    status    <b>integer</b>      Comment status
2146     */
2147     public function updCommentsStatus($ids,$status)
2148     {
2149          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
2150               throw new Exception(__("You are not allowed to change this comment's status"));
2151          }
2152         
2153          $co_ids = dcUtils::cleanIds($ids);
2154          $status = (integer) $status;
2155         
2156          $strReq = 
2157               'UPDATE '.$this->prefix.'comment tc ';
2158         
2159          # mySQL uses "JOIN" synthax
2160          if ($this->con->driver() == 'mysql') {
2161               $strReq .= 
2162                    'JOIN '.$this->prefix.'post tp ON tc.post_id = tp.post_id ';
2163          }
2164         
2165          $strReq .= 
2166               'SET comment_status = '.$status.' ';
2167         
2168          # pgSQL uses "FROM" synthax
2169          if ($this->con->driver() != 'mysql') {
2170               $strReq .= 
2171                    'FROM '.$this->prefix.'post tp ';
2172          }
2173         
2174          $strReq .=
2175               "WHERE blog_id = '".$this->con->escape($this->id)."' ".
2176               'AND comment_id'.$this->con->in($co_ids);
2177         
2178          # add pgSQL "WHERE" clause
2179          if ($this->con->driver() != 'mysql') {
2180               $strReq .= 
2181                    'AND tc.post_id = tp.post_id ';
2182          }
2183         
2184          #If user is only usage, we need to check the post's owner
2185          if (!$this->core->auth->check('contentadmin',$this->id))
2186          {
2187               $strReq .= 
2188                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2189          }
2190         
2191          $this->con->execute($strReq);
2192          $this->triggerComments($co_ids);
2193          $this->triggerBlog();
2194     }
2195     
2196     /**
2197     Delete a comment
2198     
2199     @param    id        <b>integer</b>      Comment ID
2200     */
2201     public function delComment($id)
2202     {
2203          $this->delComments($id);
2204     }
2205     
2206     /**
2207     Delete comments
2208     
2209     @param    ids       <b>mixed</b>        Comment(s) ID(s)
2210     */
2211     public function delComments($ids)
2212     {
2213          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
2214               throw new Exception(__('You are not allowed to delete comments'));
2215          }
2216         
2217          $co_ids = dcUtils::cleanIds($ids);
2218         
2219          if (empty($ids)) {
2220               throw new Exception(__('No such comment ID'));
2221          }
2222         
2223          # mySQL uses "INNER JOIN" synthax
2224          if ($this->con->driver() == 'mysql') {
2225               $strReq = 
2226                    'DELETE FROM tc '.
2227                    'USING '.$this->prefix.'comment tc '.
2228                    'INNER JOIN '.$this->prefix.'post tp ';
2229          }
2230          # pgSQL uses nothing special
2231          else {
2232               $strReq = 
2233                    'DELETE FROM '.$this->prefix.'comment tc '.
2234                    'USING '.$this->prefix.'post tp ';
2235          }
2236         
2237          $strReq .= 
2238               'WHERE tc.post_id = tp.post_id '.
2239               "AND tp.blog_id = '".$this->con->escape($this->id)."' ".
2240               'AND comment_id'.$this->con->in($co_ids);
2241         
2242          #If user can only delete, we need to check the post's owner
2243          if (!$this->core->auth->check('contentadmin',$this->id))
2244          {
2245               $strReq .= 
2246                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2247          }
2248         
2249          $this->con->execute($strReq);
2250          $this->triggerComments($co_ids,true);
2251          $this->triggerBlog();
2252     }
2253
2254     public function delJunkComments()
2255     {
2256          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
2257               throw new Exception(__('You are not allowed to delete comments'));
2258          }
2259         
2260          # mySQL uses "INNER JOIN" synthax
2261          if ($this->con->driver() == 'mysql') {
2262               $strReq = 
2263                    'DELETE FROM tc '.
2264                    'USING '.$this->prefix.'comment tc '.
2265                    'INNER JOIN '.$this->prefix.'post tp ';
2266          }
2267          # pgSQL uses nothing special
2268          else {
2269               $strReq = 
2270                    'DELETE FROM '.$this->prefix.'comment tc '.
2271                    'USING '.$this->prefix.'post tp ';
2272          }
2273         
2274          $strReq .= 
2275               'WHERE tc.post_id = tp.post_id '.
2276               "AND tp.blog_id = '".$this->con->escape($this->id)."' ".
2277               'AND comment_status = -2';
2278         
2279          #If user can only delete, we need to check the post's owner
2280          if (!$this->core->auth->check('contentadmin',$this->id))
2281          {
2282               $strReq .= 
2283                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2284          }
2285         
2286          $this->con->execute($strReq);
2287          $this->triggerBlog();
2288     }
2289     
2290     private function getCommentCursor($cur)
2291     {
2292          if ($cur->comment_content !== null && $cur->comment_content == '') {
2293               throw new Exception(__('You must provide a comment'));
2294          }
2295         
2296          if ($cur->comment_author !== null && $cur->comment_author == '') {
2297               throw new Exception(__('You must provide an author name'));
2298          }
2299         
2300          if ($cur->comment_email != '' && !text::isEmail($cur->comment_email)) {
2301               throw new Exception(__('Email address is not valid.'));
2302          }
2303         
2304          if ($cur->comment_site !== null && $cur->comment_site != '') {
2305               if (!preg_match('|^http(s?)://|',$cur->comment_site)) {
2306                    $cur->comment_site = 'http://'.$cur->comment_site;
2307               }
2308          }
2309         
2310          if ($cur->comment_status === null) {
2311               $cur->comment_status = (integer) $this->settings->system->comments_pub;
2312          }
2313         
2314          # Words list
2315          if ($cur->comment_content !== null)
2316          {
2317               $cur->comment_words = implode(' ',text::splitWords($cur->comment_content));
2318          }
2319     }
2320     //@}
2321}
2322?>
Note: See TracBrowser for help on using the repository browser.

Sites map