xref: /plugin/avatar/syntax.php (revision f874a7c61ae407d193d871ca79c84b9af523714f)
1<?php
2/**
3 * Avatar Plugin: displays avatar images with syntax {{avatar>email@domain.com}}
4 * Optionally you can add a title attribute: {{avatar>email@domain.com|My Name}}
5 *
6 * For registered users the plugin looks first for a local avatar named
7 * username.jpg in user namespace. If none found or for unregistered guests, the
8 * avatar from Gravatar.com is taken when available. The MonsterID by Andreas
9 * Gohr serves as fallback.
10 *
11 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
12 * @author   Esther Brunner <wikidesign@gmail.com>
13 * @author   Daniel Dias Rodrigues <danieldiasr@gmail.com> (modernization)
14 */
15
16if(!defined('DOKU_INC')) die();
17
18class syntax_plugin_avatar extends DokuWiki_Syntax_Plugin {
19
20    const SIZE_SMALL = 20;
21    const SIZE_MEDIUM = 40;
22    const SIZE_LARGE = 80;
23    const SIZE_XLARGE = 120;
24
25    public function getType(): string { return 'substition'; }
26    public function getSort(): int { return 315; }
27
28    public function connectTo($mode): void {
29        $this->Lexer->addSpecialPattern("{{(?:gr|)avatar>.+?}}", $mode, 'plugin_avatar');
30    }
31
32    public function handle($match, $state, $pos, Doku_Handler $handler): ?array {
33        $parts = explode('>', substr($match, 2, -2), 2);
34
35        if (count($parts) !== 2) {
36            return null; // Malformed input → discards and interrupts handle()
37        }
38
39        $match = $parts[1]; //  $parts[0] = 'avatar' or 'gravatar'
40
41        if (!preg_match('/^([^?|]+)(?:\?([^|]*))?(?:\|(.*))?$/', $match, $matches)) {
42            return ['', '', null, null];
43        }
44
45        $user = $matches[1];
46
47        /* Final check:
48         * Even if something strange slipped through the first regex, here the
49         * string is checked in isolation. This ensures that the renderer will
50         * only receive a clean username or a valid email, preventing parsing
51         * problems, CSS errors, HTML injection, etc.
52         */
53        if (filter_var($user, FILTER_VALIDATE_EMAIL) === false &&
54            !preg_match('/^\s*[a-zA-Z0-9._-]+\s*$/', $user)) {
55            return null;
56        }
57
58        $param = isset($matches[2]) ? trim(strtolower($matches[2])) : '';
59        $title = isset($matches[3]) ? trim($matches[3]) : '';
60
61        // Determine alignment
62        $align = null;
63        if ($user !== ltrim($user)) $align = 'right';
64        if ($user !== rtrim($user)) $align = $align ? 'center' : 'left';
65        $user = trim($user);
66
67        // Determine size
68        switch ($param) {
69            case 's':  $size = self::SIZE_SMALL; break;
70            case 'm':  $size = self::SIZE_MEDIUM; break;
71            case 'l':  $size = self::SIZE_LARGE; break;
72            case 'xl': $size = self::SIZE_XLARGE; break;
73            default:   $size = null;
74        }
75
76        return [$user, $title, $align, $size];
77    }
78
79    public function render($mode, Doku_Renderer $renderer, $data): bool {
80        if ($mode !== 'xhtml') return false;
81
82        if ($data === null) {
83            $renderer->doc .= '<span style="color:red;font-family:monospace;' .
84                              'font-weight:bold;">' .
85                              'Error: Avatar plugin: Invalid username or' .
86                              ' email</span>';
87            return true;
88        }
89
90        if ($my = plugin_load('helper', 'avatar')) {
91            $renderer->doc .= '<span class="vcard">' .
92                $my->renderXhtml($data[0], $data[1], $data[2], $data[3]) .
93                '</span>';
94        }
95        return true;
96    }
97}
98