Dotclear

source: inc/core/class.dc.core.php @ 1315:220e119ae6c8

Revision 1315:220e119ae6c8, 36.8 KB checked in by Dsls, 12 years ago (diff)

Merge with default

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

Sites map