Dotclear

source: inc/core/class.dc.core.php @ 4014:e090908c8e13

Revision 4014:e090908c8e13, 50.1 KB checked in by franck <carnet.franck.paul@…>, 5 years ago (diff)

misc

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  = [];
34    private $behaviors  = [];
35    private $post_types = [];
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 [
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(['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 = [];
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 = [];
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 [];
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, ...$args)
379    {
380        if (isset($this->behaviors[$behavior])) {
381            $res = '';
382
383            foreach ($this->behaviors[$behavior] as $f) {
384                $res .= call_user_func_array($f, $args);
385            }
386
387            return $res;
388        }
389    }
390    //@}
391
392    /// @name Post types URLs management
393    //@{
394    public function getPostAdminURL($type, $post_id, $escaped = true)
395    {
396        if (!isset($this->post_types[$type])) {
397            $type = 'post';
398        }
399
400        $url = sprintf($this->post_types[$type]['admin_url'], $post_id);
401        return $escaped ? html::escapeURL($url) : $url;
402    }
403
404    public function getPostPublicURL($type, $post_url, $escaped = true)
405    {
406        if (!isset($this->post_types[$type])) {
407            $type = 'post';
408        }
409
410        $url = sprintf($this->post_types[$type]['public_url'], $post_url);
411        return $escaped ? html::escapeURL($url) : $url;
412    }
413
414    public function setPostType($type, $admin_url, $public_url, $label = '')
415    {
416        $this->post_types[$type] = [
417            'admin_url'  => $admin_url,
418            'public_url' => $public_url,
419            'label'      => ($label != '' ? $label : $type)
420        ];
421    }
422
423    public function getPostTypes()
424    {
425        return $this->post_types;
426    }
427    //@}
428
429    /// @name Versions management methods
430    //@{
431    /**
432    Returns a given $module version.
433
434    @param    module    <b>string</b>    Module name
435    @return    <b>string</b>    Module version
436     */
437    public function getVersion($module = 'core')
438    {
439        # Fetch versions if needed
440        if (!is_array($this->versions)) {
441            $strReq = 'SELECT module, version FROM ' . $this->prefix . 'version';
442            $rs     = $this->con->select($strReq);
443
444            while ($rs->fetch()) {
445                $this->versions[$rs->module] = $rs->version;
446            }
447        }
448
449        if (isset($this->versions[$module])) {
450            return $this->versions[$module];
451        } else {
452            return;
453        }
454    }
455
456    /**
457    Sets $version to given $module.
458
459    @param    module    <b>string</b>    Module name
460    @param    version    <b>string</b>    Module version
461     */
462    public function setVersion($module, $version)
463    {
464        $cur_version = $this->getVersion($module);
465
466        $cur          = $this->con->openCursor($this->prefix . 'version');
467        $cur->module  = (string) $module;
468        $cur->version = (string) $version;
469
470        if ($cur_version === null) {
471            $cur->insert();
472        } else {
473            $cur->update("WHERE module='" . $this->con->escape($module) . "'");
474        }
475
476        $this->versions[$module] = $version;
477    }
478
479    /**
480    Removes given $module version entry.
481
482    @param    module    <b>string</b>    Module name
483     */
484    public function delVersion($module)
485    {
486        $strReq =
487        'DELETE FROM ' . $this->prefix . 'version ' .
488        "WHERE module = '" . $this->con->escape($module) . "' ";
489
490        $this->con->execute($strReq);
491
492        if (is_array($this->versions)) {
493            unset($this->versions[$module]);
494        }
495    }
496
497    //@}
498
499    /// @name Users management methods
500    //@{
501    /**
502    Returns a user by its ID.
503
504    @param    id        <b>string</b>        User ID
505    @return    <b>record</b>
506     */
507    public function getUser($id)
508    {
509        $params['user_id'] = $id;
510
511        return $this->getUsers($params);
512    }
513
514    /**
515    Returns a users list. <b>$params</b> is an array with the following
516    optionnal parameters:
517
518    - <var>q</var>: search string (on user_id, user_name, user_firstname)
519    - <var>user_id</var>: user ID
520    - <var>order</var>: ORDER BY clause (default: user_id ASC)
521    - <var>limit</var>: LIMIT clause (should be an array ![limit,offset])
522
523    @param    params        <b>array</b>        Parameters
524    @param    count_only    <b>boolean</b>        Only counts results
525    @return    <b>record</b>
526     */
527    public function getUsers($params = [], $count_only = false)
528    {
529        if ($count_only) {
530            $strReq =
531            'SELECT count(U.user_id) ' .
532            'FROM ' . $this->prefix . 'user U ' .
533                'WHERE NULL IS NULL ';
534        } else {
535            $strReq =
536            'SELECT U.user_id,user_super,user_status,user_pwd,user_change_pwd,' .
537            'user_name,user_firstname,user_displayname,user_email,user_url,' .
538            'user_desc, user_lang,user_tz, user_post_status,user_options, ' .
539            'count(P.post_id) AS nb_post ' .
540            'FROM ' . $this->prefix . 'user U ' .
541            'LEFT JOIN ' . $this->prefix . 'post P ON U.user_id = P.user_id ' .
542                'WHERE NULL IS NULL ';
543        }
544
545        if (!empty($params['q'])) {
546            $q = $this->con->escape(str_replace('*', '%', strtolower($params['q'])));
547            $strReq .= 'AND (' .
548                "LOWER(U.user_id) LIKE '" . $q . "' " .
549                "OR LOWER(user_name) LIKE '" . $q . "' " .
550                "OR LOWER(user_firstname) LIKE '" . $q . "' " .
551                ') ';
552        }
553
554        if (!empty($params['user_id'])) {
555            $strReq .= "AND U.user_id = '" . $this->con->escape($params['user_id']) . "' ";
556        }
557
558        if (!$count_only) {
559            $strReq .= 'GROUP BY U.user_id,user_super,user_status,user_pwd,user_change_pwd,' .
560                'user_name,user_firstname,user_displayname,user_email,user_url,' .
561                'user_desc, user_lang,user_tz,user_post_status,user_options ';
562
563            if (!empty($params['order']) && !$count_only) {
564                if (preg_match('`^([^. ]+) (?:asc|desc)`i', $params['order'], $matches)) {
565                    if (in_array($matches[1], ['user_id', 'user_name', 'user_firstname', 'user_displayname'])) {
566                        $table_prefix = 'U.';
567                    } else {
568                        $table_prefix = ''; // order = nb_post (asc|desc)
569                    }
570                    $strReq .= 'ORDER BY ' . $table_prefix . $this->con->escape($params['order']) . ' ';
571                } else {
572                    $strReq .= 'ORDER BY ' . $this->con->escape($params['order']) . ' ';
573                }
574            } else {
575                $strReq .= 'ORDER BY U.user_id ASC ';
576            }
577        }
578
579        if (!$count_only && !empty($params['limit'])) {
580            $strReq .= $this->con->limit($params['limit']);
581        }
582        $rs = $this->con->select($strReq);
583        $rs->extend('rsExtUser');
584        return $rs;
585    }
586
587    /**
588    Create a new user. Takes a cursor as input and returns the new user ID.
589
590    @param    cur        <b>cursor</b>        User cursor
591    @return    <b>string</b>
592     */
593    public function addUser($cur)
594    {
595        if (!$this->auth->isSuperAdmin()) {
596            throw new Exception(__('You are not an administrator'));
597        }
598
599        if ($cur->user_id == '') {
600            throw new Exception(__('No user ID given'));
601        }
602
603        if ($cur->user_pwd == '') {
604            throw new Exception(__('No password given'));
605        }
606
607        $this->getUserCursor($cur);
608
609        if ($cur->user_creadt === null) {
610            $cur->user_creadt = date('Y-m-d H:i:s');
611        }
612
613        $cur->insert();
614
615        $this->auth->afterAddUser($cur);
616
617        return $cur->user_id;
618    }
619
620    /**
621    Updates an existing user. Returns the user ID.
622
623    @param    id        <b>string</b>        User ID
624    @param    cur        <b>cursor</b>        User cursor
625    @return    <b>string</b>
626     */
627    public function updUser($id, $cur)
628    {
629        $this->getUserCursor($cur);
630
631        if (($cur->user_id !== null || $id != $this->auth->userID()) &&
632            !$this->auth->isSuperAdmin()) {
633            throw new Exception(__('You are not an administrator'));
634        }
635
636        $cur->update("WHERE user_id = '" . $this->con->escape($id) . "' ");
637
638        $this->auth->afterUpdUser($id, $cur);
639
640        if ($cur->user_id !== null) {
641            $id = $cur->user_id;
642        }
643
644        # Updating all user's blogs
645        $rs = $this->con->select(
646            'SELECT DISTINCT(blog_id) FROM ' . $this->prefix . 'post ' .
647            "WHERE user_id = '" . $this->con->escape($id) . "' "
648        );
649
650        while ($rs->fetch()) {
651            $b = new dcBlog($this, $rs->blog_id);
652            $b->triggerBlog();
653            unset($b);
654        }
655
656        return $id;
657    }
658
659    /**
660    Deletes a user.
661
662    @param    id        <b>string</b>        User ID
663     */
664    public function delUser($id)
665    {
666        if (!$this->auth->isSuperAdmin()) {
667            throw new Exception(__('You are not an administrator'));
668        }
669
670        if ($id == $this->auth->userID()) {
671            return;
672        }
673
674        $rs = $this->getUser($id);
675
676        if ($rs->nb_post > 0) {
677            return;
678        }
679
680        $strReq = 'DELETE FROM ' . $this->prefix . 'user ' .
681        "WHERE user_id = '" . $this->con->escape($id) . "' ";
682
683        $this->con->execute($strReq);
684
685        $this->auth->afterDelUser($id);
686    }
687
688    /**
689    Checks whether a user exists.
690
691    @param    id        <b>string</b>        User ID
692    @return    <b>boolean</b>
693     */
694    public function userExists($id)
695    {
696        $strReq = 'SELECT user_id ' .
697        'FROM ' . $this->prefix . 'user ' .
698        "WHERE user_id = '" . $this->con->escape($id) . "' ";
699
700        $rs = $this->con->select($strReq);
701
702        return !$rs->isEmpty();
703    }
704
705    /**
706    Returns all user permissions as an array which looks like:
707
708    - [blog_id]
709    - [name] => Blog name
710    - [url] => Blog URL
711    - [p]
712    - [permission] => true
713    - ...
714
715    @param    id        <b>string</b>        User ID
716    @return    <b>array</b>
717     */
718    public function getUserPermissions($id)
719    {
720        $strReq = 'SELECT B.blog_id, blog_name, blog_url, permissions ' .
721        'FROM ' . $this->prefix . 'permissions P ' .
722        'INNER JOIN ' . $this->prefix . 'blog B ON P.blog_id = B.blog_id ' .
723        "WHERE user_id = '" . $this->con->escape($id) . "' ";
724
725        $rs = $this->con->select($strReq);
726
727        $res = [];
728
729        while ($rs->fetch()) {
730            $res[$rs->blog_id] = [
731                'name' => $rs->blog_name,
732                'url'  => $rs->blog_url,
733                'p'    => $this->auth->parsePermissions($rs->permissions)
734            ];
735        }
736
737        return $res;
738    }
739
740    /**
741    Sets user permissions. The <var>$perms</var> array looks like:
742
743    - [blog_id] => '|perm1|perm2|'
744    - ...
745
746    @param    id        <b>string</b>        User ID
747    @param    perms    <b>array</b>        Permissions array
748     */
749    public function setUserPermissions($id, $perms)
750    {
751        if (!$this->auth->isSuperAdmin()) {
752            throw new Exception(__('You are not an administrator'));
753        }
754
755        $strReq = 'DELETE FROM ' . $this->prefix . 'permissions ' .
756        "WHERE user_id = '" . $this->con->escape($id) . "' ";
757
758        $this->con->execute($strReq);
759
760        foreach ($perms as $blog_id => $p) {
761            $this->setUserBlogPermissions($id, $blog_id, $p, false);
762        }
763    }
764
765    /**
766    Sets user permissions for a given blog. <var>$perms</var> is an array with
767    permissions in values
768
769    @param    id            <b>string</b>        User ID
770    @param    blog_id        <b>string</b>        Blog ID
771    @param    perms        <b>array</b>        Permissions
772    @param    delete_first    <b>boolean</b>        Delete permissions before
773     */
774    public function setUserBlogPermissions($id, $blog_id, $perms, $delete_first = true)
775    {
776        if (!$this->auth->isSuperAdmin()) {
777            throw new Exception(__('You are not an administrator'));
778        }
779
780        $no_perm = empty($perms);
781
782        $perms = '|' . implode('|', array_keys($perms)) . '|';
783
784        $cur = $this->con->openCursor($this->prefix . 'permissions');
785
786        $cur->user_id     = (string) $id;
787        $cur->blog_id     = (string) $blog_id;
788        $cur->permissions = $perms;
789
790        if ($delete_first || $no_perm) {
791            $strReq = 'DELETE FROM ' . $this->prefix . 'permissions ' .
792            "WHERE blog_id = '" . $this->con->escape($blog_id) . "' " .
793            "AND user_id = '" . $this->con->escape($id) . "' ";
794
795            $this->con->execute($strReq);
796        }
797
798        if (!$no_perm) {
799            $cur->insert();
800        }
801    }
802
803    /**
804    Sets a user default blog. This blog will be selected when user log in.
805
806    @param    id            <b>string</b>        User ID
807    @param    blog_id        <b>string</b>        Blog ID
808     */
809    public function setUserDefaultBlog($id, $blog_id)
810    {
811        $cur = $this->con->openCursor($this->prefix . 'user');
812
813        $cur->user_default_blog = (string) $blog_id;
814
815        $cur->update("WHERE user_id = '" . $this->con->escape($id) . "'");
816    }
817
818    private function getUserCursor($cur)
819    {
820        if ($cur->isField('user_id')
821            && !preg_match('/^[A-Za-z0-9@._-]{2,}$/', $cur->user_id)) {
822            throw new Exception(__('User ID must contain at least 2 characters using letters, numbers or symbols.'));
823        }
824
825        if ($cur->user_url !== null && $cur->user_url != '') {
826            if (!preg_match('|^http(s?)://|', $cur->user_url)) {
827                $cur->user_url = 'http://' . $cur->user_url;
828            }
829        }
830
831        if ($cur->isField('user_pwd')) {
832            if (strlen($cur->user_pwd) < 6) {
833                throw new Exception(__('Password must contain at least 6 characters.'));
834            }
835            $cur->user_pwd = $this->auth->crypt($cur->user_pwd);
836        }
837
838        if ($cur->user_lang !== null && !preg_match('/^[a-z]{2}(-[a-z]{2})?$/', $cur->user_lang)) {
839            throw new Exception(__('Invalid user language code'));
840        }
841
842        if ($cur->user_upddt === null) {
843            $cur->user_upddt = date('Y-m-d H:i:s');
844        }
845
846        if ($cur->user_options !== null) {
847            $cur->user_options = serialize((array) $cur->user_options);
848        }
849    }
850
851    /**
852    Returns user default settings in an associative array with setting names in
853    keys.
854
855    @return    <b>array</b>
856     */
857    public function userDefaults()
858    {
859        return [
860            'edit_size'      => 24,
861            'enable_wysiwyg' => true,
862            'toolbar_bottom' => false,
863            'editor'         => ['xhtml' => 'dcCKEditor', 'wiki' => 'dcLegacyEditor'],
864            'post_format'    => 'wiki'
865        ];
866    }
867    //@}
868
869    /// @name Blog management methods
870    //@{
871    /**
872    Returns all blog permissions (users) as an array which looks like:
873
874    - [user_id]
875    - [name] => User name
876    - [firstname] => User firstname
877    - [displayname] => User displayname
878    - [super] => (true|false) super admin
879    - [p]
880    - [permission] => true
881    - ...
882
883    @param    id            <b>string</b>        Blog ID
884    @param    with_super    <b>boolean</b>        Includes super admins in result
885    @return    <b>array</b>
886     */
887    public function getBlogPermissions($id, $with_super = true)
888    {
889        $strReq =
890        'SELECT U.user_id AS user_id, user_super, user_name, user_firstname, ' .
891        'user_displayname, user_email, permissions ' .
892        'FROM ' . $this->prefix . 'user U ' .
893        'JOIN ' . $this->prefix . 'permissions P ON U.user_id = P.user_id ' .
894        "WHERE blog_id = '" . $this->con->escape($id) . "' ";
895
896        if ($with_super) {
897            $strReq .=
898            'UNION ' .
899            'SELECT U.user_id AS user_id, user_super, user_name, user_firstname, ' .
900            "user_displayname, user_email, NULL AS permissions " .
901            'FROM ' . $this->prefix . 'user U ' .
902                'WHERE user_super = 1 ';
903        }
904
905        $rs = $this->con->select($strReq);
906
907        $res = [];
908
909        while ($rs->fetch()) {
910            $res[$rs->user_id] = [
911                'name'        => $rs->user_name,
912                'firstname'   => $rs->user_firstname,
913                'displayname' => $rs->user_displayname,
914                'email'       => $rs->user_email,
915                'super'       => (boolean) $rs->user_super,
916                'p'           => $this->auth->parsePermissions($rs->permissions)
917            ];
918        }
919
920        return $res;
921    }
922
923    /**
924    Returns a blog of given ID.
925
926    @param    id        <b>string</b>        Blog ID
927    @return    <b>record</b>
928     */
929    public function getBlog($id)
930    {
931        $blog = $this->getBlogs(['blog_id' => $id]);
932
933        if ($blog->isEmpty()) {
934            return false;
935        }
936
937        return $blog;
938    }
939
940    /**
941    Returns a record of blogs. <b>$params</b> is an array with the following
942    optionnal parameters:
943
944    - <var>blog_id</var>: Blog ID
945    - <var>q</var>: Search string on blog_id, blog_name and blog_url
946    - <var>limit</var>: limit results
947
948    @param    params        <b>array</b>        Parameters
949    @param    count_only    <b>boolean</b>        Count only results
950    @return    <b>record</b>
951     */
952    public function getBlogs($params = [], $count_only = false)
953    {
954        $join  = ''; // %1$s
955        $where = ''; // %2$s
956
957        if ($count_only) {
958            $strReq = 'SELECT count(B.blog_id) ' .
959            'FROM ' . $this->prefix . 'blog B ' .
960                '%1$s ' .
961                'WHERE NULL IS NULL ' .
962                '%2$s ';
963        } else {
964            $strReq =
965            'SELECT B.blog_id, blog_uid, blog_url, blog_name, blog_desc, blog_creadt, ' .
966            'blog_upddt, blog_status ' .
967            'FROM ' . $this->prefix . 'blog B ' .
968                '%1$s ' .
969                'WHERE NULL IS NULL ' .
970                '%2$s ';
971
972            if (!empty($params['order'])) {
973                $strReq .= 'ORDER BY ' . $this->con->escape($params['order']) . ' ';
974            } else {
975                $strReq .= 'ORDER BY B.blog_id ASC ';
976            }
977
978            if (!empty($params['limit'])) {
979                $strReq .= $this->con->limit($params['limit']);
980            }
981        }
982
983        if ($this->auth->userID() && !$this->auth->isSuperAdmin()) {
984            $join  = 'INNER JOIN ' . $this->prefix . 'permissions PE ON B.blog_id = PE.blog_id ';
985            $where =
986            "AND PE.user_id = '" . $this->con->escape($this->auth->userID()) . "' " .
987                "AND (permissions LIKE '%|usage|%' OR permissions LIKE '%|admin|%' OR permissions LIKE '%|contentadmin|%') " .
988                "AND blog_status IN (1,0) ";
989        } elseif (!$this->auth->userID()) {
990            $where = 'AND blog_status IN (1,0) ';
991        }
992
993        if (isset($params['blog_status']) && $params['blog_status'] !== '' && $this->auth->isSuperAdmin()) {
994            $where .= 'AND blog_status = ' . (integer) $params['blog_status'] . ' ';
995        }
996
997        if (isset($params['blog_id']) && $params['blog_id'] !== '') {
998            if (!is_array($params['blog_id'])) {
999                $params['blog_id'] = [$params['blog_id']];
1000            }
1001            $where .= 'AND B.blog_id ' . $this->con->in($params['blog_id']);
1002        }
1003
1004        if (!empty($params['q'])) {
1005            $params['q'] = strtolower(str_replace('*', '%', $params['q']));
1006            $where .=
1007            'AND (' .
1008            "LOWER(B.blog_id) LIKE '" . $this->con->escape($params['q']) . "' " .
1009            "OR LOWER(B.blog_name) LIKE '" . $this->con->escape($params['q']) . "' " .
1010            "OR LOWER(B.blog_url) LIKE '" . $this->con->escape($params['q']) . "' " .
1011                ') ';
1012        }
1013
1014        $strReq = sprintf($strReq, $join, $where);
1015        return $this->con->select($strReq);
1016    }
1017
1018    /**
1019    Creates a new blog.
1020
1021    @param    cur            <b>cursor</b>        Blog cursor
1022     */
1023    public function addBlog($cur)
1024    {
1025        if (!$this->auth->isSuperAdmin()) {
1026            throw new Exception(__('You are not an administrator'));
1027        }
1028
1029        $this->getBlogCursor($cur);
1030
1031        $cur->blog_creadt = date('Y-m-d H:i:s');
1032        $cur->blog_upddt  = date('Y-m-d H:i:s');
1033        $cur->blog_uid    = md5(uniqid());
1034
1035        $cur->insert();
1036    }
1037
1038    /**
1039    Updates a given blog.
1040
1041    @param    id        <b>string</b>        Blog ID
1042    @param    cur        <b>cursor</b>        Blog cursor
1043     */
1044    public function updBlog($id, $cur)
1045    {
1046        $this->getBlogCursor($cur);
1047
1048        $cur->blog_upddt = date('Y-m-d H:i:s');
1049
1050        $cur->update("WHERE blog_id = '" . $this->con->escape($id) . "'");
1051    }
1052
1053    private function getBlogCursor($cur)
1054    {
1055        if (($cur->blog_id !== null
1056            && !preg_match('/^[A-Za-z0-9._-]{2,}$/', $cur->blog_id)) ||
1057            (!$cur->blog_id)) {
1058            throw new Exception(__('Blog ID must contain at least 2 characters using letters, numbers or symbols.'));
1059        }
1060
1061        if (($cur->blog_name !== null && $cur->blog_name == '') ||
1062            (!$cur->blog_name)) {
1063            throw new Exception(__('No blog name'));
1064        }
1065
1066        if (($cur->blog_url !== null && $cur->blog_url == '') ||
1067            (!$cur->blog_url)) {
1068            throw new Exception(__('No blog URL'));
1069        }
1070
1071        if ($cur->blog_desc !== null) {
1072            $cur->blog_desc = html::clean($cur->blog_desc);
1073        }
1074    }
1075
1076    /**
1077    Removes a given blog.
1078    @warning This will remove everything related to the blog (posts,
1079    categories, comments, links...)
1080
1081    @param    id        <b>string</b>        Blog ID
1082     */
1083    public function delBlog($id)
1084    {
1085        if (!$this->auth->isSuperAdmin()) {
1086            throw new Exception(__('You are not an administrator'));
1087        }
1088
1089        $strReq = 'DELETE FROM ' . $this->prefix . 'blog ' .
1090        "WHERE blog_id = '" . $this->con->escape($id) . "' ";
1091
1092        $this->con->execute($strReq);
1093    }
1094
1095    /**
1096    Checks if a blog exist.
1097
1098    @param    id        <b>string</b>        Blog ID
1099    @return    <b>boolean</b>
1100     */
1101    public function blogExists($id)
1102    {
1103        $strReq = 'SELECT blog_id ' .
1104        'FROM ' . $this->prefix . 'blog ' .
1105        "WHERE blog_id = '" . $this->con->escape($id) . "' ";
1106
1107        $rs = $this->con->select($strReq);
1108
1109        return !$rs->isEmpty();
1110    }
1111
1112    /**
1113    Count posts on a blog
1114
1115    @param    id        <b>string</b>        Blog ID
1116    @param    type        <b>string</b>        Post type
1117    @return    <b>boolean</b>
1118     */
1119    public function countBlogPosts($id, $type = null)
1120    {
1121        $strReq = 'SELECT COUNT(post_id) ' .
1122        'FROM ' . $this->prefix . 'post ' .
1123        "WHERE blog_id = '" . $this->con->escape($id) . "' ";
1124
1125        if ($type) {
1126            $strReq .= "AND post_type = '" . $this->con->escape($type) . "' ";
1127        }
1128
1129        return $this->con->select($strReq)->f(0);
1130    }
1131    //@}
1132
1133    /// @name HTML Filter methods
1134    //@{
1135    /**
1136    Calls HTML filter to drop bad tags and produce valid XHTML output (if
1137    tidy extension is present). If <b>enable_html_filter</b> blog setting is
1138    false, returns not filtered string.
1139
1140    @param    str    <b>string</b>        String to filter
1141    @return    <b>string</b> Filtered string.
1142     */
1143    public function HTMLfilter($str)
1144    {
1145        if ($this->blog instanceof dcBlog && !$this->blog->settings->system->enable_html_filter) {
1146            return $str;
1147        }
1148
1149        $filter = new htmlFilter;
1150        $str    = trim($filter->apply($str));
1151        return $str;
1152    }
1153    //@}
1154
1155    /// @name wiki2xhtml methods
1156    //@{
1157    private function initWiki()
1158    {
1159        $this->wiki2xhtml = new wiki2xhtml;
1160    }
1161
1162    /**
1163    Returns a transformed string with wiki2xhtml.
1164
1165    @param    str        <b>string</b>        String to transform
1166    @return    <b>string</b>    Transformed string
1167     */
1168    public function wikiTransform($str)
1169    {
1170        if (!($this->wiki2xhtml instanceof wiki2xhtml)) {
1171            $this->initWiki();
1172        }
1173        return $this->wiki2xhtml->transform($str);
1174    }
1175
1176    /**
1177    Inits <var>wiki2xhtml</var> property for blog post.
1178     */
1179    public function initWikiPost()
1180    {
1181        $this->initWiki();
1182
1183        $this->wiki2xhtml->setOpts([
1184            'active_title'        => 1,
1185            'active_setext_title' => 0,
1186            'active_hr'           => 1,
1187            'active_lists'        => 1,
1188            'active_defl'         => 1,
1189            'active_quote'        => 1,
1190            'active_pre'          => 1,
1191            'active_empty'        => 1,
1192            'active_auto_urls'    => 0,
1193            'active_auto_br'      => 0,
1194            'active_antispam'     => 1,
1195            'active_urls'         => 1,
1196            'active_auto_img'     => 0,
1197            'active_img'          => 1,
1198            'active_anchor'       => 1,
1199            'active_em'           => 1,
1200            'active_strong'       => 1,
1201            'active_br'           => 1,
1202            'active_q'            => 1,
1203            'active_code'         => 1,
1204            'active_acronym'      => 1,
1205            'active_ins'          => 1,
1206            'active_del'          => 1,
1207            'active_footnotes'    => 1,
1208            'active_wikiwords'    => 0,
1209            'active_macros'       => 1,
1210            'active_mark'         => 1,
1211            'active_aside'        => 1,
1212            'active_sup'          => 1,
1213            'active_sub'          => 1,
1214            'parse_pre'           => 1,
1215            'active_fr_syntax'    => 0,
1216            'first_title_level'   => 3,
1217            'note_prefix'         => 'wiki-footnote',
1218            'note_str'            => '<div class="footnotes"><h4>Notes</h4>%s</div>',
1219            'img_style_center'    => 'display:table; margin:0 auto;'
1220        ]);
1221
1222        $this->wiki2xhtml->registerFunction('url:post', [$this, 'wikiPostLink']);
1223
1224        # --BEHAVIOR-- coreWikiPostInit
1225        $this->callBehavior('coreInitWikiPost', $this->wiki2xhtml);
1226    }
1227
1228    /**
1229    Inits <var>wiki2xhtml</var> property for simple blog comment (basic syntax).
1230     */
1231    public function initWikiSimpleComment()
1232    {
1233        $this->initWiki();
1234
1235        $this->wiki2xhtml->setOpts([
1236            'active_title'        => 0,
1237            'active_setext_title' => 0,
1238            'active_hr'           => 0,
1239            'active_lists'        => 0,
1240            'active_defl'         => 0,
1241            'active_quote'        => 0,
1242            'active_pre'          => 0,
1243            'active_empty'        => 0,
1244            'active_auto_urls'    => 1,
1245            'active_auto_br'      => 1,
1246            'active_antispam'     => 1,
1247            'active_urls'         => 0,
1248            'active_auto_img'     => 0,
1249            'active_img'          => 0,
1250            'active_anchor'       => 0,
1251            'active_em'           => 0,
1252            'active_strong'       => 0,
1253            'active_br'           => 0,
1254            'active_q'            => 0,
1255            'active_code'         => 0,
1256            'active_acronym'      => 0,
1257            'active_ins'          => 0,
1258            'active_del'          => 0,
1259            'active_inline_html'  => 0,
1260            'active_footnotes'    => 0,
1261            'active_wikiwords'    => 0,
1262            'active_macros'       => 0,
1263            'active_mark'         => 0,
1264            'active_aside'        => 0,
1265            'active_sup'          => 0,
1266            'active_sub'          => 0,
1267            'parse_pre'           => 0,
1268            'active_fr_syntax'    => 0
1269        ]);
1270
1271        # --BEHAVIOR-- coreInitWikiSimpleComment
1272        $this->callBehavior('coreInitWikiSimpleComment', $this->wiki2xhtml);
1273    }
1274
1275    /**
1276    Inits <var>wiki2xhtml</var> property for blog comment.
1277     */
1278    public function initWikiComment()
1279    {
1280        $this->initWiki();
1281
1282        $this->wiki2xhtml->setOpts([
1283            'active_title'        => 0,
1284            'active_setext_title' => 0,
1285            'active_hr'           => 0,
1286            'active_lists'        => 1,
1287            'active_defl'         => 0,
1288            'active_quote'        => 1,
1289            'active_pre'          => 1,
1290            'active_aside'        => 0,
1291            'active_empty'        => 0,
1292            'active_auto_br'      => 1,
1293            'active_auto_urls'    => 1,
1294            'active_urls'         => 1,
1295            'active_auto_img'     => 0,
1296            'active_img'          => 0,
1297            'active_anchor'       => 0,
1298            'active_em'           => 1,
1299            'active_strong'       => 1,
1300            'active_br'           => 1,
1301            'active_q'            => 1,
1302            'active_code'         => 1,
1303            'active_acronym'      => 1,
1304            'active_ins'          => 1,
1305            'active_del'          => 1,
1306            'active_footnotes'    => 0,
1307            'active_inline_html'  => 0,
1308            'active_wikiwords'    => 0,
1309            'active_macros'       => 0,
1310            'active_mark'         => 1,
1311            'active_aside'        => 0,
1312            'active_sup'          => 1,
1313            'active_sub'          => 1,
1314            'parse_pre'           => 0,
1315            'active_fr_syntax'    => 0
1316        ]);
1317
1318        # --BEHAVIOR-- coreInitWikiComment
1319        $this->callBehavior('coreInitWikiComment', $this->wiki2xhtml);
1320    }
1321
1322    public function wikiPostLink($url, $content)
1323    {
1324        if (!($this->blog instanceof dcBlog)) {
1325            return [];
1326        }
1327
1328        $post_id = abs((integer) substr($url, 5));
1329        if (!$post_id) {
1330            return [];
1331        }
1332
1333        $post = $this->blog->getPosts(['post_id' => $post_id]);
1334        if ($post->isEmpty()) {
1335            return [];
1336        }
1337
1338        $res        = ['url' => $post->getURL()];
1339        $post_title = $post->post_title;
1340
1341        if ($content != $url) {
1342            $res['title'] = html::escapeHTML($post->post_title);
1343        }
1344
1345        if ($content == '' || $content == $url) {
1346            $res['content'] = html::escapeHTML($post->post_title);
1347        }
1348
1349        if ($post->post_lang) {
1350            $res['lang'] = $post->post_lang;
1351        }
1352
1353        return $res;
1354    }
1355    //@}
1356
1357    /// @name Maintenance methods
1358    //@{
1359    /**
1360    Creates default settings for active blog. Optionnal parameter
1361    <var>defaults</var> replaces default params while needed.
1362
1363    @param    defaults        <b>array</b>    Default parameters
1364     */
1365    public function blogDefaults($defaults = null)
1366    {
1367        if (!is_array($defaults)) {
1368            $defaults = [
1369                ['allow_comments', 'boolean', true,
1370                    'Allow comments on blog'],
1371                ['allow_trackbacks', 'boolean', true,
1372                    'Allow trackbacks on blog'],
1373                ['blog_timezone', 'string', 'Europe/London',
1374                    'Blog timezone'],
1375                ['comments_nofollow', 'boolean', true,
1376                    'Add rel="nofollow" to comments URLs'],
1377                ['comments_pub', 'boolean', true,
1378                    'Publish comments immediately'],
1379                ['comments_ttl', 'integer', 0,
1380                    'Number of days to keep comments open (0 means no ttl)'],
1381                ['copyright_notice', 'string', '', 'Copyright notice (simple text)'],
1382                ['date_format', 'string', '%A, %B %e %Y',
1383                    'Date format. See PHP strftime function for patterns'],
1384                ['editor', 'string', '',
1385                    'Person responsible of the content'],
1386                ['enable_html_filter', 'boolean', 0,
1387                    'Enable HTML filter'],
1388                ['enable_xmlrpc', 'boolean', 0,
1389                    'Enable XML/RPC interface'],
1390                ['lang', 'string', 'en',
1391                    'Default blog language'],
1392                ['media_exclusion', 'string', '/\.(phps?|pht(ml)?|phl|.?html?|xml|js|htaccess)[0-9]*$/i',
1393                    'File name exclusion pattern in media manager. (PCRE value)'],
1394                ['media_img_m_size', 'integer', 448,
1395                    'Image medium size in media manager'],
1396                ['media_img_s_size', 'integer', 240,
1397                    'Image small size in media manager'],
1398                ['media_img_t_size', 'integer', 100,
1399                    'Image thumbnail size in media manager'],
1400                ['media_img_title_pattern', 'string', 'Title ;; Date(%b %Y) ;; separator(, )',
1401                    'Pattern to set image title when you insert it in a post'],
1402                ['media_video_width', 'integer', 400,
1403                    'Video width in media manager'],
1404                ['media_video_height', 'integer', 300,
1405                    'Video height in media manager'],
1406                ['nb_post_for_home', 'integer', 20,
1407                    'Number of entries on first home page'],
1408                ['nb_post_per_page', 'integer', 20,
1409                    'Number of entries on home pages and category pages'],
1410                ['nb_post_per_feed', 'integer', 20,
1411                    'Number of entries on feeds'],
1412                ['nb_comment_per_feed', 'integer', 20,
1413                    'Number of comments on feeds'],
1414                ['post_url_format', 'string', '{y}/{m}/{d}/{t}',
1415                    'Post URL format. {y}: year, {m}: month, {d}: day, {id}: post id, {t}: entry title'],
1416                ['public_path', 'string', 'public',
1417                    'Path to public directory, begins with a / for a full system path'],
1418                ['public_url', 'string', '/public',
1419                    'URL to public directory'],
1420                ['robots_policy', 'string', 'INDEX,FOLLOW',
1421                    'Search engines robots policy'],
1422                ['short_feed_items', 'boolean', false,
1423                    'Display short feed items'],
1424                ['theme', 'string', 'berlin',
1425                    'Blog theme'],
1426                ['themes_path', 'string', 'themes',
1427                    'Themes root path'],
1428                ['themes_url', 'string', '/themes',
1429                    'Themes root URL'],
1430                ['time_format', 'string', '%H:%M',
1431                    'Time format. See PHP strftime function for patterns'],
1432                ['tpl_allow_php', 'boolean', false,
1433                    'Allow PHP code in templates'],
1434                ['tpl_use_cache', 'boolean', true,
1435                    'Use template caching'],
1436                ['trackbacks_pub', 'boolean', true,
1437                    'Publish trackbacks immediately'],
1438                ['trackbacks_ttl', 'integer', 0,
1439                    'Number of days to keep trackbacks open (0 means no ttl)'],
1440                ['url_scan', 'string', 'query_string',
1441                    'URL handle mode (path_info or query_string)'],
1442                ['use_smilies', 'boolean', false,
1443                    'Show smilies on entries and comments'],
1444                ['no_search', 'boolean', false,
1445                    'Disable search'],
1446                ['inc_subcats', 'boolean', false,
1447                    'Include sub-categories in category page and category posts feed'],
1448                ['wiki_comments', 'boolean', false,
1449                    'Allow commenters to use a subset of wiki syntax'],
1450                ['import_feed_url_control', 'boolean', true,
1451                    'Control feed URL before import'],
1452                ['import_feed_no_private_ip', 'boolean', true,
1453                    'Prevent import feed from private IP'],
1454                ['import_feed_ip_regexp', 'string', '',
1455                    'Authorize import feed only from this IP regexp'],
1456                ['import_feed_port_regexp', 'string', '/^(80|443)$/',
1457                    'Authorize import feed only from this port regexp']
1458            ];
1459        }
1460
1461        $settings = new dcSettings($this, null);
1462        $settings->addNamespace('system');
1463
1464        foreach ($defaults as $v) {
1465            $settings->system->put($v[0], $v[2], $v[1], $v[3], false, true);
1466        }
1467    }
1468
1469    /**
1470    Recreates entries search engine index.
1471
1472    @param    start    <b>integer</b>        Start entry index
1473    @param    limit    <b>integer</b>        Number of entry to index
1474
1475    @return    <b>integer</b>        <var>$start</var> and <var>$limit</var> sum
1476     */
1477    public function indexAllPosts($start = null, $limit = null)
1478    {
1479        $strReq = 'SELECT COUNT(post_id) ' .
1480        'FROM ' . $this->prefix . 'post';
1481        $rs    = $this->con->select($strReq);
1482        $count = $rs->f(0);
1483
1484        $strReq = 'SELECT post_id, post_title, post_excerpt_xhtml, post_content_xhtml ' .
1485        'FROM ' . $this->prefix . 'post ';
1486
1487        if ($start !== null && $limit !== null) {
1488            $strReq .= $this->con->limit($start, $limit);
1489        }
1490
1491        $rs = $this->con->select($strReq, true);
1492
1493        $cur = $this->con->openCursor($this->prefix . 'post');
1494
1495        while ($rs->fetch()) {
1496            $words = $rs->post_title . ' ' . $rs->post_excerpt_xhtml . ' ' .
1497            $rs->post_content_xhtml;
1498
1499            $cur->post_words = implode(' ', text::splitWords($words));
1500            $cur->update('WHERE post_id = ' . (integer) $rs->post_id);
1501            $cur->clean();
1502        }
1503
1504        if ($start + $limit > $count) {
1505            return;
1506        }
1507        return $start + $limit;
1508    }
1509
1510    /**
1511    Recreates comments search engine index.
1512
1513    @param    start    <b>integer</b>        Start comment index
1514    @param    limit    <b>integer</b>        Number of comments to index
1515
1516    @return    <b>integer</b>        <var>$start</var> and <var>$limit</var> sum
1517     */
1518    public function indexAllComments($start = null, $limit = null)
1519    {
1520        $strReq = 'SELECT COUNT(comment_id) ' .
1521        'FROM ' . $this->prefix . 'comment';
1522        $rs    = $this->con->select($strReq);
1523        $count = $rs->f(0);
1524
1525        $strReq = 'SELECT comment_id, comment_content ' .
1526        'FROM ' . $this->prefix . 'comment ';
1527
1528        if ($start !== null && $limit !== null) {
1529            $strReq .= $this->con->limit($start, $limit);
1530        }
1531
1532        $rs = $this->con->select($strReq);
1533
1534        $cur = $this->con->openCursor($this->prefix . 'comment');
1535
1536        while ($rs->fetch()) {
1537            $cur->comment_words = implode(' ', text::splitWords($rs->comment_content));
1538            $cur->update('WHERE comment_id = ' . (integer) $rs->comment_id);
1539            $cur->clean();
1540        }
1541
1542        if ($start + $limit > $count) {
1543            return;
1544        }
1545        return $start + $limit;
1546    }
1547
1548    /**
1549    Reinits nb_comment and nb_trackback in post table.
1550     */
1551    public function countAllComments()
1552    {
1553
1554        $updCommentReq = 'UPDATE ' . $this->prefix . 'post P ' .
1555        'SET nb_comment = (' .
1556        'SELECT COUNT(C.comment_id) from ' . $this->prefix . 'comment C ' .
1557            'WHERE C.post_id = P.post_id AND C.comment_trackback <> 1 ' .
1558            'AND C.comment_status = 1 ' .
1559            ')';
1560        $updTrackbackReq = 'UPDATE ' . $this->prefix . 'post P ' .
1561        'SET nb_trackback = (' .
1562        'SELECT COUNT(C.comment_id) from ' . $this->prefix . 'comment C ' .
1563            'WHERE C.post_id = P.post_id AND C.comment_trackback = 1 ' .
1564            'AND C.comment_status = 1 ' .
1565            ')';
1566        $this->con->execute($updCommentReq);
1567        $this->con->execute($updTrackbackReq);
1568    }
1569
1570    /**
1571    Empty templates cache directory
1572     */
1573    public function emptyTemplatesCache()
1574    {
1575        if (is_dir(DC_TPL_CACHE . '/cbtpl')) {
1576            files::deltree(DC_TPL_CACHE . '/cbtpl');
1577        }
1578    }
1579
1580    /**
1581    Return elapsed time since script has been started
1582    @param      $mtime <b>float</b> timestamp (microtime format) to evaluate delta from
1583    current time is taken if null
1584    @return <b>float</b>         elapsed time
1585     */
1586    public function getElapsedTime($mtime = null)
1587    {
1588        if ($mtime !== null) {
1589            return $mtime - $this->stime;
1590        } else {
1591            return microtime(true) - $this->stime;
1592        }
1593    }
1594    //@}
1595
1596}
Note: See TracBrowser for help on using the repository browser.

Sites map