Dotclear

source: inc/core/class.dc.core.php @ 136:4f8ecaf1b813

Revision 136:4f8ecaf1b813, 35.3 KB checked in by Dsls <dsls@…>, 14 years ago (diff)

Fixed handling of comment number updates, closes #1137

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2010 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@defgroup DC_CORE Dotclear Core Classes
16*/
17
18/**
19@ingroup DC_CORE
20@nosubgrouping
21@brief Dotclear core class
22
23True to its name dcCore is the core of Dotclear. It handles everything related
24to blogs, database connection, plugins...
25*/
26class dcCore
27{
28     public $con;        ///< <b>connection</b>        Database connection object
29     public $prefix;     ///< <b>string</b>            Database tables prefix
30     public $blog;       ///< <b>dcBlog</b>            dcBlog object
31     public $error;      ///< <b>dcError</b>           dcError object
32     public $auth;       ///< <b>dcAuth</b>            dcAuth object
33     public $session;    ///< <b>sessionDB</b>         sessionDB object
34     public $url;        ///< <b>urlHandler</b>        urlHandler object
35     public $wiki2xhtml; ///< <b>wiki2xhtml</b>        wiki2xhtml object
36     public $plugins;    ///< <b>dcModules</b>         dcModules object
37     public $media;      ///< <b>dcMedia</b>           dcMedia object
38     public $rest;       ///< <b>dcRestServer</b>      dcRestServer object
39     public $log;        ///< <b>dcLog</b>             dcLog object
40     
41     private $versions = null;
42     private $formaters = array();
43     private $behaviors = array();
44     private $post_types = array();
45     
46     /**
47     dcCore constructor inits everything related to Dotclear. It takes arguments
48     to init database connection.
49     
50     @param    driver    <b>string</b>  Database driver name
51     @param    host      <b>string</b>  Database hostname
52     @param    db        <b>string</b>  Database name
53     @param    user      <b>string</b>  Database username
54     @param    password  <b>string</b>  Database password
55     @param    prefix    <b>string</b>  DotClear tables prefix
56     @param    persist   <b>boolean</b> Persistent database connection
57     */
58     public function __construct($driver, $host, $db, $user, $password, $prefix, $persist)
59     {
60          $this->con = dbLayer::init($driver,$host,$db,$user,$password,$persist);
61         
62          # define weak_locks for mysql
63          if ($this->con instanceof mysqlConnection) {
64               mysqlConnection::$weak_locks = true;
65          }
66         
67          $this->prefix = $prefix;
68         
69          $this->error = new dcError();
70          $this->auth = $this->authInstance();
71          $this->session = new sessionDB($this->con,$this->prefix.'session',DC_SESSION_NAME,'',null,DC_ADMIN_SSL);
72          $this->url = new dcUrlHandlers();
73         
74          $this->plugins = new dcModules($this);
75         
76          $this->rest = new dcRestServer($this);
77         
78          $this->meta = new dcMeta($this);
79         
80          $this->log = new dcLog($this);
81         
82          $this->addFormater('xhtml', create_function('$s','return $s;'));
83          $this->addFormater('wiki', array($this,'wikiTransform'));
84     }
85     
86     private function authInstance()
87     {
88          # You can set DC_AUTH_CLASS to whatever you want.
89          # Your new class *should* inherits dcAuth.
90          if (!defined('DC_AUTH_CLASS')) {
91               $c = 'dcAuth';
92          } else {
93               $c = DC_AUTH_CLASS;
94          }
95         
96          if (!class_exists($c)) {
97               throw new Exception('Authentication class '.$c.' does not exist.');
98          }
99         
100          if ($c != 'dcAuth' && !is_subclass_of($c,'dcAuth')) {
101               throw new Exception('Authentication class '.$c.' does not inherit dcAuth.');
102          }
103         
104          return new $c($this);
105     }
106     
107     
108     /// @name Blog init methods
109     //@{
110     /**
111     Sets a blog to use in <var>blog</var> property.
112     
113     @param    id        <b>string</b>       Blog ID
114     */
115     public function setBlog($id)
116     {
117          $this->blog = new dcBlog($this, $id);
118     }
119     
120     /**
121     Unsets <var>blog</var> property.
122     */
123     public function unsetBlog()
124     {
125          $this->blog = null;
126     }
127     //@}
128     
129     
130     /// @name Blog status methods
131     //@{
132     /**
133     Returns an array of available blog status codes and names.
134     
135     @return   <b>array</b> Simple array with codes in keys and names in value
136     */
137     public function getAllBlogStatus()
138     {
139          return array(
140               1 => __('online'),
141               0 => __('offline'),
142               -1 => __('removed')
143          );
144     }
145     
146     /**
147     Returns a blog status name given to a code. This is intended to be
148     human-readable and will be translated, so never use it for tests.
149     If status code does not exist, returns <i>offline</i>.
150     
151     @param    s    <b>integer</b> Status code
152     @return   <b>string</b> Blog status name
153     */
154     public function getBlogStatus($s)
155     {
156          $r = $this->getAllBlogStatus();
157          if (isset($r[$s])) {
158               return $r[$s];
159          }
160          return $r[0];
161     }
162     //@}
163     
164     /// @name Admin nonce secret methods
165     //@{
166     
167     public function getNonce()
168     {
169          return crypt::hmac(DC_MASTER_KEY,session_id());
170     }
171     
172     public function checkNonce($secret)
173     {
174          if (!preg_match('/^([0-9a-f]{40,})$/i',$secret)) {
175               return false;
176          }
177         
178          return $secret == crypt::hmac(DC_MASTER_KEY,session_id());
179     }
180     
181     public function formNonce()
182     {
183          if (!session_id()) {
184               return;
185          }
186         
187          return form::hidden(array('xd_check'),$this->getNonce());
188     }
189     //@}
190     
191     
192     /// @name Text Formatters methods
193     //@{
194     /**
195     Adds a new text formater which will call the function <var>$func</var> to
196     transform text. The function must be a valid callback and takes one
197     argument: the string to transform. It returns the transformed string.
198     
199     @param    name      <b>string</b>       Formater name
200     @param    func      <b>callback</b>     Function to use, must be a valid and callable callback
201     */
202     public function addFormater($name,$func)
203     {
204          if (is_callable($func)) {
205               $this->formaters[$name] = $func;
206          }
207     }
208     
209     /**
210     Returns formaters list.
211     
212     @return   <b>array</b> An array of formaters names in values.
213     */
214     public function getFormaters()
215     {
216          return array_keys($this->formaters);
217     }
218     
219     /**
220     If <var>$name</var> is a valid formater, it returns <var>$str</var>
221     transformed using that formater.
222     
223     @param    name      <b>string</b>       Formater name
224     @param    str       <b>string</b>       String to transform
225     @return   <b>string</b>  String transformed
226     */
227     public function callFormater($name,$str)
228     {
229          if (isset($this->formaters[$name])) {
230               return call_user_func($this->formaters[$name],$str);
231          }
232         
233          return $str;
234     }
235     //@}
236     
237     
238     /// @name Behaviors methods
239     //@{
240     /**
241     Adds a new behavior to behaviors stack. <var>$func</var> must be a valid
242     and callable callback.
243     
244     @param    behavior  <b>string</b>       Behavior name
245     @param    func      <b>callback</b>     Function to call
246     */
247     public function addBehavior($behavior,$func)
248     {
249          if (is_callable($func)) {
250               $this->behaviors[$behavior][] = $func;
251          }
252     }
253     
254     /**
255     Tests if a particular behavior exists in behaviors stack.
256     
257     @param    behavior  <b>string</b>  Behavior name
258     @return   <b>boolean</b>
259     */
260     public function hasBehavior($behavior)
261     {
262          return isset($this->behaviors[$behavior]);
263     }
264     
265     /**
266     Get behaviors stack (or part of).
267     
268     @param    behavior  <b>string</b>       Behavior name
269     @return   <b>array</b>
270     */
271     public function getBehaviors($behavior='')
272     {
273          if (empty($this->behaviors)) return null;
274         
275          if ($behavior == '') {
276               return $this->behaviors;
277          } elseif (isset($this->behaviors[$behavior])) {
278               return $this->behaviors[$behavior];
279          }
280         
281          return array();
282     }
283     
284     /**
285     Calls every function in behaviors stack for a given behavior and returns
286     concatened result of each function.
287     
288     Every parameters added after <var>$behavior</var> will be pass to
289     behavior calls.
290     
291     @param    behavior  <b>string</b>  Behavior name
292     @return   <b>string</b> Behavior concatened result
293     */
294     public function callBehavior($behavior)
295     {
296          if (isset($this->behaviors[$behavior]))
297          {
298               $args = func_get_args();
299               array_shift($args);
300               
301               $res = '';
302               
303               foreach ($this->behaviors[$behavior] as $f) {
304                    $res .= call_user_func_array($f,$args);
305               }
306               
307               return $res;
308          }
309     }
310     //@}
311     
312     /// @name Post types URLs management
313     //@{
314     public function getPostAdminURL($type,$post_id,$escaped=true)
315     {
316          if (!isset($this->post_types[$type])) {
317               $type = 'post';
318          }
319         
320          $url = sprintf($this->post_types[$type]['admin_url'],$post_id);
321          return $escaped ? html::escapeURL($url) : $url;
322     }
323     
324     public function getPostPublicURL($type,$post_url,$escaped=true)
325     {
326          if (!isset($this->post_types[$type])) {
327               $type = 'post';
328          }
329         
330          $url = sprintf($this->post_types[$type]['public_url'],$post_url);
331          return $escaped ? html::escapeURL($url) : $url;
332     }
333     
334     public function setPostType($type,$admin_url,$public_url)
335     {
336          $this->post_types[$type] = array(
337               'admin_url' => $admin_url,
338               'public_url' => $public_url
339          );
340     }
341     
342     public function getPostTypes()
343     {
344          return $this->post_types;
345     }
346     //@}
347     
348     /// @name Versions management methods
349     //@{
350     /**
351     Returns a given $module version.
352     
353     @param    module    <b>string</b>  Module name
354     @return   <b>string</b>  Module version
355     */
356     public function getVersion($module='core')
357     {
358          # Fetch versions if needed
359          if (!is_array($this->versions))
360          {
361               $strReq = 'SELECT module, version FROM '.$this->prefix.'version';
362               $rs = $this->con->select($strReq);
363               
364               while ($rs->fetch()) {
365                    $this->versions[$rs->module] = $rs->version;
366               }
367          }
368         
369          if (isset($this->versions[$module])) {
370               return $this->versions[$module];
371          } else {
372               return null;
373          }
374     }
375     
376     /**
377     Sets $version to given $module.
378     
379     @param    module    <b>string</b>  Module name
380     @param    version   <b>string</b>  Module version
381     */
382     public function setVersion($module,$version)
383     {
384          $cur_version = $this->getVersion($module);
385         
386          $cur = $this->con->openCursor($this->prefix.'version');
387          $cur->module = (string) $module;
388          $cur->version = (string) $version;
389         
390          if ($cur_version === null) {
391               $cur->insert();
392          } else {
393               $cur->update("WHERE module='".$this->con->escape($module)."'");
394          }
395         
396          $this->versions[$module] = $version;
397     }
398     
399     /**
400     Removes given $module version entry.
401     
402     @param    module    <b>string</b>  Module name
403     */
404     public function delVersion($module)
405     {
406          $strReq =
407          'DELETE FROM '.$this->prefix.'version '.
408          "WHERE module = '".$this->con->escape($module)."' ";
409         
410          $this->con->execute($strReq);
411         
412          if (is_array($this->versions)) {
413               unset($this->versions[$module]);
414          }
415     }
416     
417     //@}
418     
419     /// @name Users management methods
420     //@{
421     /**
422     Returns a user by its ID.
423     
424     @param    id        <b>string</b>       User ID
425     @return   <b>record</b>
426     */
427     public function getUser($id)
428     {
429          $params['user_id'] = $id;
430         
431          return $this->getUsers($params);
432     }
433     
434     /**
435     Returns a users list. <b>$params</b> is an array with the following
436     optionnal parameters:
437     
438      - <var>q</var>: search string (on user_id, user_name, user_firstname)
439      - <var>user_id</var>: user ID
440      - <var>order</var>: ORDER BY clause (default: user_id ASC)
441      - <var>limit</var>: LIMIT clause (should be an array ![limit,offset])
442     
443     @param    params         <b>array</b>        Parameters
444     @param    count_only     <b>boolean</b>      Only counts results
445     @return   <b>record</b>
446     */
447     public function getUsers($params=array(),$count_only=false)
448     {
449          if ($count_only)
450          {
451               $strReq =
452               'SELECT count(U.user_id) '.
453               'FROM '.$this->prefix.'user U '.
454               'WHERE NULL IS NULL ';
455          }
456          else
457          {
458               $strReq =
459               'SELECT U.user_id,user_super,user_status,user_pwd,user_change_pwd,'.
460               'user_name,user_firstname,user_displayname,user_email,user_url,'.
461               'user_desc, user_lang,user_tz, user_post_status,user_options, '.
462               'count(P.post_id) AS nb_post '.
463               'FROM '.$this->prefix.'user U '.
464                    'LEFT JOIN '.$this->prefix.'post P ON U.user_id = P.user_id '.
465               'WHERE NULL IS NULL ';
466          }
467         
468          if (!empty($params['q'])) {
469               $q = $this->con->escape(str_replace('*','%',strtolower($params['q'])));
470               $strReq .= 'AND ('.
471                    "LOWER(U.user_id) LIKE '".$q."' ".
472                    "OR LOWER(user_name) LIKE '".$q."' ".
473                    "OR LOWER(user_firstname) LIKE '".$q."' ".
474                    ') ';
475          }
476         
477          if (!empty($params['user_id'])) {
478               $strReq .= "AND U.user_id = '".$this->con->escape($params['user_id'])."' ";
479          }
480         
481          if (!$count_only) {
482               $strReq .= 'GROUP BY U.user_id,user_super,user_status,user_pwd,user_change_pwd,'.
483               'user_name,user_firstname,user_displayname,user_email,user_url,'.
484               'user_desc, user_lang,user_tz,user_post_status,user_options ';
485               
486               if (!empty($params['order']) && !$count_only) {
487                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
488               } else {
489                    $strReq .= 'ORDER BY U.user_id ASC ';
490               }
491          }
492         
493          if (!$count_only && !empty($params['limit'])) {
494               $strReq .= $this->con->limit($params['limit']);
495          }
496         
497          $rs = $this->con->select($strReq);
498          $rs->extend('rsExtUser');
499          return $rs;
500     }
501     
502     /**
503     Create a new user. Takes a cursor as input and returns the new user ID.
504     
505     @param    cur       <b>cursor</b>       User cursor
506     @return   <b>string</b>
507     */
508     public function addUser($cur)
509     {
510          if (!$this->auth->isSuperAdmin()) {
511               throw new Exception(__('You are not an administrator'));
512          }
513         
514          if ($cur->user_id == '') {
515               throw new Exception(__('No user ID given'));
516          }
517         
518          if ($cur->user_pwd == '') {
519               throw new Exception(__('No password given'));
520          }
521         
522          $this->getUserCursor($cur);
523         
524          if ($cur->user_creadt === null) {
525               $cur->user_creadt = date('Y-m-d H:i:s');
526          }
527         
528          $cur->insert();
529         
530          $this->auth->afterAddUser($cur);
531         
532          return $cur->user_id;
533     }
534     
535     /**
536     Updates an existing user. Returns the user ID.
537     
538     @param    id        <b>string</b>       User ID
539     @param    cur       <b>cursor</b>       User cursor
540     @return   <b>string</b>
541     */
542     public function updUser($id,$cur)
543     {
544          $this->getUserCursor($cur);
545         
546          if (($cur->user_id !== null || $id != $this->auth->userID()) &&
547          !$this->auth->isSuperAdmin()) {
548               throw new Exception(__('You are not an administrator'));
549          }
550         
551          $cur->update("WHERE user_id = '".$this->con->escape($id)."' ");
552         
553          $this->auth->afterUpdUser($id,$cur);
554         
555          if ($cur->user_id !== null) {
556               $id = $cur->user_id;
557          }
558         
559          # Updating all user's blogs
560          $rs = $this->con->select(
561               'SELECT DISTINCT(blog_id) FROM '.$this->prefix.'post '.
562               "WHERE user_id = '".$this->con->escape($id)."' "
563               );
564         
565          while ($rs->fetch()) {
566               $b = new dcBlog($this,$rs->blog_id);
567               $b->triggerBlog();
568               unset($b);
569          }
570         
571          return $id;
572     }
573     
574     /**
575     Deletes a user.
576     
577     @param    id        <b>string</b>       User ID
578     */
579     public function delUser($id)
580     {
581          if (!$this->auth->isSuperAdmin()) {
582               throw new Exception(__('You are not an administrator'));
583          }
584         
585          if ($id == $this->auth->userID()) {
586               return;
587          }
588         
589          $rs = $this->getUser($id);
590         
591          if ($rs->nb_post > 0) {
592               return;
593          }
594         
595          $strReq = 'DELETE FROM '.$this->prefix.'user '.
596                    "WHERE user_id = '".$this->con->escape($id)."' ";
597         
598          $this->con->execute($strReq);
599         
600          $this->auth->afterDelUser($id);
601     }
602     
603     /**
604     Checks whether a user exists.
605     
606     @param    id        <b>string</b>       User ID
607     @return   <b>boolean</b>
608     */
609     public function userExists($id)
610     {
611          $strReq = 'SELECT user_id '.
612                    'FROM '.$this->prefix.'user '.
613                    "WHERE user_id = '".$this->con->escape($id)."' ";
614         
615          $rs = $this->con->select($strReq);
616         
617          return !$rs->isEmpty();
618     }
619     
620     /**
621     Returns all user permissions as an array which looks like:
622     
623      - [blog_id]
624        - [name] => Blog name
625        - [url] => Blog URL
626        - [p]
627          - [permission] => true
628          - ...
629     
630     @param    id        <b>string</b>       User ID
631     @return   <b>array</b>
632     */
633     public function getUserPermissions($id)
634     {
635          $strReq = 'SELECT B.blog_id, blog_name, blog_url, permissions '.
636                    'FROM '.$this->prefix.'permissions P '.
637                    'INNER JOIN '.$this->prefix.'blog B ON P.blog_id = B.blog_id '.
638                    "WHERE user_id = '".$this->con->escape($id)."' ";
639         
640          $rs = $this->con->select($strReq);
641         
642          $res = array();
643         
644          while ($rs->fetch())
645          {
646               $res[$rs->blog_id] = array(
647                    'name' => $rs->blog_name,
648                    'url' => $rs->blog_url,
649                    'p' => $this->auth->parsePermissions($rs->permissions)
650               );
651          }
652         
653          return $res;
654     }
655     
656     /**
657     Sets user permissions. The <var>$perms</var> array looks like:
658     
659      - [blog_id] => '|perm1|perm2|'
660      - ...
661     
662     @param    id        <b>string</b>       User ID
663     @param    perms     <b>array</b>        Permissions array
664     */
665     public function setUserPermissions($id,$perms)
666     {
667          if (!$this->auth->isSuperAdmin()) {
668               throw new Exception(__('You are not an administrator'));
669          }
670         
671          $strReq = 'DELETE FROM '.$this->prefix.'permissions '.
672                    "WHERE user_id = '".$this->con->escape($id)."' ";
673         
674          $this->con->execute($strReq);
675         
676          foreach ($perms as $blog_id => $p) {
677               $this->setUserBlogPermissions($id, $blog_id, $p, false);
678          }
679     }
680     
681     /**
682     Sets user permissions for a given blog. <var>$perms</var> is an array with
683     permissions in values
684     
685     @param    id             <b>string</b>       User ID
686     @param    blog_id        <b>string</b>       Blog ID
687     @param    perms          <b>array</b>        Permissions
688     @param    delete_first   <b>boolean</b>      Delete permissions before
689     */
690     public function setUserBlogPermissions($id, $blog_id, $perms, $delete_first=true)
691     {
692          if (!$this->auth->isSuperAdmin()) {
693               throw new Exception(__('You are not an administrator'));
694          }
695         
696          $no_perm = empty($perms);
697         
698          $perms = '|'.implode('|',array_keys($perms)).'|';
699         
700          $cur = $this->con->openCursor($this->prefix.'permissions');
701         
702          $cur->user_id = (string) $id;
703          $cur->blog_id = (string) $blog_id;
704          $cur->permissions = $perms;
705         
706          if ($delete_first || $no_perm)
707          {
708               $strReq = 'DELETE FROM '.$this->prefix.'permissions '.
709                         "WHERE blog_id = '".$this->con->escape($blog_id)."' ".
710                         "AND user_id = '".$this->con->escape($id)."' ";
711               
712               $this->con->execute($strReq);
713          }
714         
715          if (!$no_perm) {
716               $cur->insert();
717          }
718     }
719     
720     /**
721     Sets a user default blog. This blog will be selected when user log in.
722     
723     @param    id             <b>string</b>       User ID
724     @param    blog_id        <b>string</b>       Blog ID
725     */
726     public function setUserDefaultBlog($id, $blog_id)
727     {
728          $cur = $this->con->openCursor($this->prefix.'user');
729         
730          $cur->user_default_blog = (string) $blog_id;
731         
732          $cur->update("WHERE user_id = '".$this->con->escape($id)."'");
733     }
734     
735     private function getUserCursor($cur)
736     {
737          if ($cur->isField('user_id')
738          && !preg_match('/^[A-Za-z0-9@._-]{2,}$/',$cur->user_id)) {
739               throw new Exception(__('User ID must contain at least 2 characters using letters, numbers or symbols.'));
740          }
741         
742          if ($cur->user_url !== null && $cur->user_url != '') {
743               if (!preg_match('|^http(s?)://|',$cur->user_url)) {
744                    $cur->user_url = 'http://'.$cur->user_url;
745               }
746          }
747         
748          if ($cur->isField('user_pwd')) {
749               if (strlen($cur->user_pwd) < 6) {
750                    throw new Exception(__('Password must contain at least 6 characters.'));
751               }
752               $cur->user_pwd = crypt::hmac(DC_MASTER_KEY,$cur->user_pwd);
753          }
754         
755          if ($cur->user_lang !== null && !preg_match('/^[a-z]{2}(-[a-z]{2})?$/',$cur->user_lang)) {
756               throw new Exception(__('Invalid user language code'));
757          }
758         
759          if ($cur->user_upddt === null) {
760               $cur->user_upddt = date('Y-m-d H:i:s');
761          }
762         
763          if ($cur->user_options !== null) {
764               $cur->user_options = serialize((array) $cur->user_options);
765          }
766     }
767     
768     /**
769     Returns user default settings in an associative array with setting names in
770     keys.
771     
772     @return   <b>array</b>
773     */
774     public function userDefaults()
775     {
776          return array(
777               'edit_size' => 24,
778               'enable_wysiwyg' => true,
779               'post_format' => 'wiki',
780          );
781     }
782     //@}
783     
784     /// @name Blog management methods
785     //@{
786     /**
787     Returns all blog permissions (users) as an array which looks like:
788     
789      - [user_id]
790        - [name] => User name
791        - [firstname] => User firstname
792        - [displayname] => User displayname
793        - [super] => (true|false) super admin
794        - [p]
795          - [permission] => true
796          - ...
797     
798     @param    id             <b>string</b>       Blog ID
799     @param    with_super     <b>boolean</b>      Includes super admins in result
800     @return   <b>array</b>
801     */
802     public function getBlogPermissions($id,$with_super=true)
803     {
804          $strReq =
805          'SELECT U.user_id AS user_id, user_super, user_name, user_firstname, '.
806          'user_displayname, permissions '.
807          'FROM '.$this->prefix.'user U '.
808          'JOIN '.$this->prefix.'permissions P ON U.user_id = P.user_id '.
809          "WHERE blog_id = '".$this->con->escape($id)."' ";
810         
811          if ($with_super) {
812               $strReq .=
813               'UNION '.
814               'SELECT U.user_id AS user_id, user_super, user_name, user_firstname, '.
815               "user_displayname, NULL AS permissions ".
816               'FROM '.$this->prefix.'user U '.
817               'WHERE user_super = 1 ';
818          }
819         
820          $rs = $this->con->select($strReq);
821         
822          $res = array();
823         
824          while ($rs->fetch())
825          {
826               $res[$rs->user_id] = array(
827                    'name' => $rs->user_name,
828                    'firstname' => $rs->user_firstname,
829                    'displayname' => $rs->user_displayname,
830                    'super' => (boolean) $rs->user_super,
831                    'p' => $this->auth->parsePermissions($rs->permissions)
832               );
833          }
834         
835          return $res;
836     }
837     
838     /**
839     Returns a blog of given ID.
840     
841     @param    id        <b>string</b>       Blog ID
842     @return   <b>record</b>
843     */
844     public function getBlog($id)
845     {
846          $blog = $this->getBlogs(array('blog_id'=>$id));
847         
848          if ($blog->isEmpty()) {
849               return false;
850          }
851         
852          return $blog;
853     }
854     
855     /**
856     Returns a record of blogs. <b>$params</b> is an array with the following
857     optionnal parameters:
858     
859      - <var>blog_id</var>: Blog ID
860      - <var>q</var>: Search string on blog_id, blog_name and blog_url
861      - <var>limit</var>: limit results
862     
863     @param    params         <b>array</b>        Parameters
864     @param    count_only     <b>boolean</b>      Count only results
865     @return   <b>record</b>
866     */
867     public function getBlogs($params=array(),$count_only=false)
868     {
869          $join = '';    // %1$s
870          $where = '';   // %2$s
871         
872          if ($count_only)
873          {
874               $strReq = 'SELECT count(B.blog_id) '.
875                         'FROM '.$this->prefix.'blog B '.
876                         '%1$s '.
877                         'WHERE NULL IS NULL '.
878                         '%2$s ';
879          }
880          else
881          {
882               $strReq =
883               'SELECT B.blog_id, blog_uid, blog_url, blog_name, blog_desc, blog_creadt, '.
884               'blog_upddt, blog_status '.
885               'FROM '.$this->prefix.'blog B '.
886               '%1$s '.
887               'WHERE NULL IS NULL '.
888               '%2$s ';
889               
890               if (!empty($params['order'])) {
891                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
892               } else {
893                    $strReq .= 'ORDER BY B.blog_id ASC ';
894               }
895               
896               if (!empty($params['limit'])) {
897                    $strReq .= $this->con->limit($params['limit']);
898               }
899          }
900         
901          if ($this->auth->userID() && !$this->auth->isSuperAdmin())
902          {
903               $join = 'INNER JOIN '.$this->prefix.'permissions PE ON B.blog_id = PE.blog_id ';
904               $where =
905               "AND PE.user_id = '".$this->con->escape($this->auth->userID())."' ".
906               "AND (permissions LIKE '%|usage|%' OR permissions LIKE '%|admin|%' OR permissions LIKE '%|contentadmin|%') ".
907               "AND blog_status IN (1,0) ";
908          } elseif (!$this->auth->userID()) {
909               $where = 'AND blog_status IN (1,0) ';
910          }
911         
912          if (!empty($params['blog_id'])) {
913               $where .= "AND B.blog_id = '".$this->con->escape($params['blog_id'])."' ";
914          }
915         
916          if (!empty($params['q'])) {
917               $params['q'] = str_replace('*','%',$params['q']);
918               $where .=
919               'AND ('.
920               "LOWER(B.blog_id) LIKE '".$this->con->escape($params['q'])."' ".
921               "OR LOWER(B.blog_name) LIKE '".$this->con->escape($params['q'])."' ".
922               "OR LOWER(B.blog_url) LIKE '".$this->con->escape($params['q'])."' ".
923               ') ';
924          }
925         
926          $strReq = sprintf($strReq,$join,$where);
927          return $this->con->select($strReq);
928     }
929     
930     /**
931     Creates a new blog.
932     
933     @param    cur            <b>cursor</b>       Blog cursor
934     */
935     public function addBlog($cur)
936     {
937          if (!$this->auth->isSuperAdmin()) {
938               throw new Exception(__('You are not an administrator'));
939          }
940         
941          $this->getBlogCursor($cur);
942         
943          $cur->blog_creadt = date('Y-m-d H:i:s');
944          $cur->blog_upddt = date('Y-m-d H:i:s');
945          $cur->blog_uid = md5(uniqid());
946         
947          $cur->insert();
948     }
949     
950     /**
951     Updates a given blog.
952     
953     @param    id        <b>string</b>       Blog ID
954     @param    cur       <b>cursor</b>       Blog cursor
955     */
956     public function updBlog($id,$cur)
957     {
958          $this->getBlogCursor($cur);
959         
960          $cur->blog_upddt = date('Y-m-d H:i:s');
961         
962          $cur->update("WHERE blog_id = '".$this->con->escape($id)."'");
963     }
964     
965     private function getBlogCursor($cur)
966     {
967          if ($cur->blog_id !== null
968          && !preg_match('/^[A-Za-z0-9._-]{2,}$/',$cur->blog_id)) {
969               throw new Exception(__('Blog ID must contain at least 2 characters using letters, numbers or symbols.')); 
970          }
971         
972          if ($cur->blog_name !== null && $cur->blog_name == '') {
973               throw new Exception(__('No blog name'));
974          }
975         
976          if ($cur->blog_url !== null && $cur->blog_url == '') {
977               throw new Exception(__('No blog URL'));
978          }
979         
980          if ($cur->blog_desc !== null) {
981               $cur->blog_desc = html::clean($cur->blog_desc);
982          }
983     }
984     
985     /**
986     Removes a given blog.
987     @warning This will remove everything related to the blog (posts,
988     categories, comments, links...)
989     
990     @param    id        <b>string</b>       Blog ID
991     */
992     public function delBlog($id)
993     {
994          if (!$this->auth->isSuperAdmin()) {
995               throw new Exception(__('You are not an administrator'));
996          }
997         
998          $strReq = 'DELETE FROM '.$this->prefix.'blog '.
999                    "WHERE blog_id = '".$this->con->escape($id)."' ";
1000         
1001          $this->con->execute($strReq);
1002     }
1003     
1004     /**
1005     Checks if a blog exist.
1006     
1007     @param    id        <b>string</b>       Blog ID
1008     @return   <b>boolean</b>
1009     */
1010     public function blogExists($id)
1011     {
1012          $strReq = 'SELECT blog_id '.
1013                    'FROM '.$this->prefix.'blog '.
1014                    "WHERE blog_id = '".$this->con->escape($id)."' ";
1015         
1016          $rs = $this->con->select($strReq);
1017         
1018          return !$rs->isEmpty();
1019     }
1020     
1021     /**
1022     Count posts on a blog
1023     
1024     @param    id        <b>string</b>       Blog ID
1025     @param    type      <b>string</b>       Post type
1026     @return   <b>boolean</b>
1027     */
1028     public function countBlogPosts($id,$type=null)
1029     {
1030          $strReq = 'SELECT COUNT(post_id) '.
1031                    'FROM '.$this->prefix.'post '.
1032                    "WHERE blog_id = '".$this->con->escape($id)."' ";
1033         
1034          if ($type) {
1035               $strReq .= "AND post_type = '".$this->con->escape($type)."' ";
1036          }
1037         
1038          return $this->con->select($strReq)->f(0);
1039     }
1040     //@}
1041     
1042     /// @name HTML Filter methods
1043     //@{
1044     /**
1045     Calls HTML filter to drop bad tags and produce valid XHTML output (if
1046     tidy extension is present). If <b>enable_html_filter</b> blog setting is
1047     false, returns not filtered string.
1048     
1049     @param    str  <b>string</b>       String to filter
1050     @return   <b>string</b> Filtered string.
1051     */
1052     public function HTMLfilter($str)
1053     {
1054          if ($this->blog instanceof dcBlog && !$this->blog->settings->system->enable_html_filter) {
1055               return $str;
1056          }
1057         
1058          $filter = new htmlFilter;
1059          $str = trim($filter->apply($str));
1060          return $str;
1061     }
1062     //@}
1063     
1064     /// @name wiki2xhtml methods
1065     //@{
1066     private function initWiki()
1067     {
1068          $this->wiki2xhtml = new wiki2xhtml;
1069     }
1070     
1071     /**
1072     Returns a transformed string with wiki2xhtml.
1073     
1074     @param    str       <b>string</b>       String to transform
1075     @return   <b>string</b>  Transformed string
1076     */
1077     public function wikiTransform($str)
1078     {
1079          if (!($this->wiki2xhtml instanceof wiki2xhtml)) {
1080               $this->initWiki();
1081          }
1082          return $this->wiki2xhtml->transform($str);
1083     }
1084     
1085     /**
1086     Inits <var>wiki2xhtml</var> property for blog post.
1087     */
1088     public function initWikiPost()
1089     {
1090          $this->initWiki();
1091         
1092          $this->wiki2xhtml->setOpts(array(
1093               'active_title' => 1,
1094               'active_setext_title' => 0,
1095               'active_hr' => 1,
1096               'active_lists' => 1,
1097               'active_quote' => 1,
1098               'active_pre' => 1,
1099               'active_empty' => 1,
1100               'active_auto_br' => 0,
1101               'active_auto_urls' => 0,
1102               'active_urls' => 1,
1103               'active_auto_img' => 0,
1104               'active_img' => 1,
1105               'active_anchor' => 1,
1106               'active_em' => 1,
1107               'active_strong' => 1,
1108               'active_br' => 1,
1109               'active_q' => 1,
1110               'active_code' => 1,
1111               'active_acronym' => 1,
1112               'active_ins' => 1,
1113               'active_del' => 1,
1114               'active_footnotes' => 1,
1115               'active_wikiwords' => 0,
1116               'active_macros' => 1,
1117               'parse_pre' => 1,
1118               'active_fr_syntax' => 0,
1119               'first_title_level' => 3,
1120               'note_prefix' => 'wiki-footnote',
1121               'note_str' => '<div class="footnotes"><h4>Notes</h4>%s</div>'
1122          ));
1123         
1124          $this->wiki2xhtml->registerFunction('url:post',array($this,'wikiPostLink'));
1125         
1126          # --BEHAVIOR-- coreWikiPostInit
1127          $this->callBehavior('coreInitWikiPost',$this->wiki2xhtml);
1128     }
1129     
1130     /**
1131     Inits <var>wiki2xhtml</var> property for simple blog comment (basic syntax).
1132     */
1133     public function initWikiSimpleComment()
1134     {
1135          $this->initWiki();
1136         
1137          $this->wiki2xhtml->setOpts(array(
1138               'active_title' => 0,
1139               'active_setext_title' => 0,
1140               'active_hr' => 0,
1141               'active_lists' => 0,
1142               'active_quote' => 0,
1143               'active_pre' => 0,
1144               'active_empty' => 0,
1145               'active_auto_br' => 1,
1146               'active_auto_urls' => 1,
1147               'active_urls' => 0,
1148               'active_auto_img' => 0,
1149               'active_img' => 0,
1150               'active_anchor' => 0,
1151               'active_em' => 0,
1152               'active_strong' => 0,
1153               'active_br' => 0,
1154               'active_q' => 0,
1155               'active_code' => 0,
1156               'active_acronym' => 0,
1157               'active_ins' => 0,
1158               'active_del' => 0,
1159               'active_footnotes' => 0,
1160               'active_wikiwords' => 0,
1161               'active_macros' => 0,
1162               'parse_pre' => 0,
1163               'active_fr_syntax' => 0
1164          ));
1165         
1166          # --BEHAVIOR-- coreInitWikiSimpleComment
1167          $this->callBehavior('coreInitWikiSimpleComment',$this->wiki2xhtml);
1168     }
1169     
1170     /**
1171     Inits <var>wiki2xhtml</var> property for blog comment.
1172     */
1173     public function initWikiComment()
1174     {
1175          $this->initWiki();
1176         
1177          $this->wiki2xhtml->setOpts(array(
1178               'active_title' => 0,
1179               'active_setext_title' => 0,
1180               'active_hr' => 0,
1181               'active_lists' => 1,
1182               'active_quote' => 0,
1183               'active_pre' => 1,
1184               'active_empty' => 0,
1185               'active_auto_br' => 1,
1186               'active_auto_urls' => 1,
1187               'active_urls' => 1,
1188               'active_auto_img' => 0,
1189               'active_img' => 0,
1190               'active_anchor' => 0,
1191               'active_em' => 1,
1192               'active_strong' => 1,
1193               'active_br' => 1,
1194               'active_q' => 1,
1195               'active_code' => 1,
1196               'active_acronym' => 1,
1197               'active_ins' => 1,
1198               'active_del' => 1,
1199               'active_footnotes' => 0,
1200               'active_wikiwords' => 0,
1201               'active_macros' => 0,
1202               'parse_pre' => 0,
1203               'active_fr_syntax' => 0
1204          ));
1205         
1206          # --BEHAVIOR-- coreInitWikiComment
1207          $this->callBehavior('coreInitWikiComment',$this->wiki2xhtml);
1208     }
1209     
1210     public function wikiPostLink($url,$content)
1211     {
1212          if (!($this->blog instanceof dcBlog)) { 
1213               return array();
1214          }
1215         
1216          $post_id = abs((integer) substr($url,5));
1217          if (!$post_id) {
1218               return array();
1219          }
1220         
1221          $post = $this->blog->getPosts(array('post_id'=>$post_id));
1222          if ($post->isEmpty()) {
1223               return array();
1224          }
1225         
1226          $res = array('url' => $post->getURL());
1227          $post_title = $post->post_title;
1228         
1229          if ($content != $url) {
1230               $res['title'] = html::escapeHTML($post->post_title);
1231          }
1232         
1233          if ($content == '' || $content == $url) {
1234               $res['content'] = html::escapeHTML($post->post_title);
1235          }
1236         
1237          if ($post->post_lang) {
1238               $res['lang'] = $post->post_lang;
1239          }
1240         
1241          return $res;
1242     }
1243     //@}
1244     
1245     /// @name Maintenance methods
1246     //@{
1247     /**
1248     Creates default settings for active blog. Optionnal parameter
1249     <var>defaults</var> replaces default params while needed.
1250     
1251     @param    defaults       <b>array</b>   Default parameters
1252     */
1253     public function blogDefaults($defaults=null)
1254     {
1255          if (!is_array($defaults))
1256          {
1257               $defaults = array(
1258                    array('allow_comments','boolean',true,
1259                    'Allow comments on blog'),
1260                    array('allow_trackbacks','boolean',true,
1261                    'Allow trackbacks on blog'),
1262                    array('blog_timezone','string','Europe/London',
1263                    'Blog timezone'),
1264                    array('comments_nofollow','boolean',true,
1265                    'Add rel="nofollow" to comments URLs'),
1266                    array('comments_pub','boolean',true,
1267                    'Publish comments immediately'),
1268                    array('comments_ttl','integer',0,
1269                    'Number of days to keep comments open (0 means no ttl)'),
1270                    array('copyright_notice','string','','Copyright notice (simple text)'),
1271                    array('date_format','string','%A, %B %e %Y',
1272                    'Date format. See PHP strftime function for patterns'),
1273                    array('editor','string','',
1274                    'Person responsible of the content'),
1275                    array('enable_html_filter','boolean',0,
1276                    'Enable HTML filter'),
1277                    array('enable_xmlrpc','boolean',0,
1278                    'Enable XML/RPC interface'),
1279                    array('lang','string','en',
1280                    'Default blog language'),
1281                    array('media_exclusion','string','',
1282                    'File name exclusion pattern in media manager. (PCRE value)'),
1283                    array('media_img_m_size','integer',448,
1284                    'Image medium size in media manager'),
1285                    array('media_img_s_size','integer',240,
1286                    'Image small size in media manager'),
1287                    array('media_img_t_size','integer',100,
1288                    'Image thumbnail size in media manager'),
1289                    array('media_img_title_pattern','string','Title ;; Date(%b %Y) ;; separator(, )',
1290                    'Pattern to set image title when you insert it in a post'),
1291                    array('nb_post_per_page','integer',20,
1292                    'Number of entries on home page and category pages'),
1293                    array('nb_post_per_feed','integer',20,
1294                    'Number of entries on feeds'),
1295                    array('nb_comment_per_feed','integer',20,
1296                    'Number of comments on feeds'),
1297                    array('post_url_format','string','{y}/{m}/{d}/{t}',
1298                    'Post URL format. {y}: year, {m}: month, {d}: day, {id}: post id, {t}: entry title'),
1299                    array('public_path','string','public',
1300                    'Path to public directory, begins with a / for a full system path'),
1301                    array('public_url','string','/public',
1302                    'URL to public directory'),
1303                    array('robots_policy','string','INDEX,FOLLOW',
1304                    'Search engines robots policy'),
1305                    array('short_feed_items','boolean',false,
1306                    'Display short feed items'),
1307                    array('theme','string','default',
1308                    'Blog theme'),
1309                    array('themes_path','string','themes',
1310                    'Themes root path'),
1311                    array('themes_url','string','/themes',
1312                    'Themes root URL'),
1313                    array('time_format','string','%H:%M',
1314                    'Time format. See PHP strftime function for patterns'),
1315                    array('tpl_allow_php','boolean',false,
1316                    'Allow PHP code in templates'),
1317                    array('tpl_use_cache','boolean',true,
1318                    'Use template caching'),
1319                    array('trackbacks_pub','boolean',true,
1320                    'Publish trackbacks immediately'),
1321                    array('trackbacks_ttl','integer',0,
1322                    'Number of days to keep trackbacks open (0 means no ttl)'),
1323                    array('url_scan','string','query_string',
1324                    'URL handle mode (path_info or query_string)'),
1325                    array('use_smilies','boolean',false,
1326                    'Show smilies on entries and comments'),
1327                    array('wiki_comments','boolean',false,
1328                    'Allow commenters to use a subset of wiki syntax')
1329               );
1330          }
1331         
1332          $settings = new dcSettings($this,null);
1333          $settings->addNamespace('system');
1334         
1335          foreach ($defaults as $v) {
1336               $settings->system->put($v[0],$v[2],$v[1],$v[3],false,true);
1337          }
1338     }
1339     
1340     /**
1341     Recreates entries search engine index.
1342     
1343     @param    start     <b>integer</b>      Start entry index
1344     @param    limit     <b>integer</b>      Number of entry to index
1345     
1346     @return   <b>integer</b>      <var>$start</var> and <var>$limit</var> sum
1347     */
1348     public function indexAllPosts($start=null,$limit=null)
1349     {
1350          $strReq = 'SELECT COUNT(post_id) '.
1351                    'FROM '.$this->prefix.'post';
1352          $rs = $this->con->select($strReq);
1353          $count = $rs->f(0);
1354         
1355          $strReq = 'SELECT post_id, post_title, post_excerpt_xhtml, post_content_xhtml '.
1356                    'FROM '.$this->prefix.'post ';
1357         
1358          if ($start !== null && $limit !== null) {
1359               $strReq .= $this->con->limit($start,$limit);
1360          }
1361         
1362          $rs = $this->con->select($strReq,true);
1363         
1364          $cur = $this->con->openCursor($this->prefix.'post');
1365         
1366          while ($rs->fetch())
1367          {
1368               $words = $rs->post_title.' '. $rs->post_excerpt_xhtml.' '.
1369               $rs->post_content_xhtml;
1370               
1371               $cur->post_words = implode(' ',text::splitWords($words));
1372               $cur->update('WHERE post_id = '.(integer) $rs->post_id);
1373               $cur->clean();
1374          }
1375         
1376          if ($start+$limit > $count) {
1377               return null;
1378          }
1379          return $start+$limit;
1380     }
1381     
1382     /**
1383     Recreates comments search engine index.
1384     
1385     @param    start     <b>integer</b>      Start comment index
1386     @param    limit     <b>integer</b>      Number of comments to index
1387     
1388     @return   <b>integer</b>      <var>$start</var> and <var>$limit</var> sum
1389     */
1390     public function indexAllComments($start=null,$limit=null)
1391     {
1392          $strReq = 'SELECT COUNT(comment_id) '.
1393                    'FROM '.$this->prefix.'comment';
1394          $rs = $this->con->select($strReq);
1395          $count = $rs->f(0);
1396         
1397          $strReq = 'SELECT comment_id, comment_content '.
1398                    'FROM '.$this->prefix.'comment ';
1399         
1400          if ($start !== null && $limit !== null) {
1401               $strReq .= $this->con->limit($start,$limit);
1402          }
1403         
1404          $rs = $this->con->select($strReq);
1405         
1406          $cur = $this->con->openCursor($this->prefix.'comment');
1407         
1408          while ($rs->fetch())
1409          {
1410               $cur->comment_words = implode(' ',text::splitWords($rs->comment_content));
1411               $cur->update('WHERE comment_id = '.(integer) $rs->comment_id);
1412               $cur->clean();
1413          }
1414         
1415          if ($start+$limit > $count) {
1416               return null;
1417          }
1418          return $start+$limit;
1419     }
1420     
1421     /**
1422     Reinits nb_comment and nb_trackback in post table.
1423     */
1424     public function countAllComments()
1425     {
1426     
1427          $updCommentReq = 'UPDATE '.$this->prefix.'post P '.
1428               'SET nb_comment = ('.
1429                    'SELECT COUNT(C.comment_id) from '.$this->prefix.'comment C '.
1430                    'WHERE C.post_id = P.post_id AND C.comment_trackback <> 1 '.
1431                    'AND C.comment_status = 1 '.
1432               ')';
1433          $updTrackbackReq = 'UPDATE '.$this->prefix.'post P '.
1434               'SET nb_trackback = ('.
1435                    'SELECT COUNT(C.comment_id) from '.$this->prefix.'comment C '.
1436                    'WHERE C.post_id = P.post_id AND C.comment_trackback = 1 '.
1437                    'AND C.comment_status = 1 '.
1438               ')';
1439          $this->con->execute($updCommentReq);
1440          $this->con->execute($updTrackbackReq);
1441     }
1442     
1443     /**
1444     Empty templates cache directory
1445     */
1446     public function emptyTemplatesCache()
1447     {
1448          if (is_dir(DC_TPL_CACHE.'/cbtpl')) {
1449               files::deltree(DC_TPL_CACHE.'/cbtpl');
1450          }
1451     }
1452     //@}
1453}
1454?>
Note: See TracBrowser for help on using the repository browser.

Sites map