Dotclear

source: inc/core/class.dc.core.php @ 3761:849987324197

Revision 3761:849987324197, 51.9 KB checked in by franck <carnet.franck.paul@…>, 7 years ago (diff)

Apply SQL Statement in DC code, work in progress

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

Sites map