Dotclear

source: inc/core/class.dc.core.php @ 2492:8a25f7bf147d

Revision 2492:8a25f7bf147d, 36.0 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

New class dcPlugins, fix backward compatibility with generic dcModules class and un-type modules

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

Sites map