Dotclear

source: inc/core/class.dc.core.php @ 2313:ef1db3d7c388

Revision 2313:ef1db3d7c388, 37.1 KB checked in by Dsls, 12 years ago (diff)

Twig merge - lots of things to adapt yet

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

Sites map