Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core\output;
18
 
19
use core\context\user as context_user;
20
use core\exception\coding_exception;
21
use moodle_page;
22
use moodle_url;
23
use stdClass;
24
 
25
/**
26
 * Data structure representing a user picture.
27
 *
28
 * @copyright 2009 Nicolas Connault, 2010 Petr Skoda
29
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30
 * @since Modle 2.0
31
 * @package core
32
 * @category output
33
 */
34
class user_picture implements renderable {
35
    /**
36
     * @var stdClass A user object with at least fields all columns specified
37
     * in $fields array constant set.
38
     */
39
    public $user;
40
 
41
    /**
42
     * @var int The course id. Used when constructing the link to the user's
43
     * profile, page course id used if not specified.
44
     */
45
    public $courseid;
46
 
47
    /**
48
     * @var bool Add course profile link to image
49
     */
50
    public $link = true;
51
 
52
    /**
53
     * @var int Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility.
54
     * Recommended values (supporting user initials too): 16, 35, 64 and 100.
55
     */
56
    public $size = 35;
57
 
58
    /**
59
     * @var bool Add non-blank alt-text to the image.
60
     * Default true, set to false when image alt just duplicates text in screenreaders.
61
     */
62
    public $alttext = true;
63
 
64
    /**
65
     * @var bool Whether or not to open the link in a popup window.
66
     */
67
    public $popup = false;
68
 
69
    /**
70
     * @var string Image class attribute
71
     */
72
    public $class = 'userpicture';
73
 
74
    /**
75
     * @var bool Whether to be visible to screen readers.
76
     */
77
    public $visibletoscreenreaders = true;
78
 
79
    /**
80
     * @var bool Whether to include the fullname in the user picture link.
81
     */
82
    public $includefullname = false;
83
 
84
    /**
85
     * @var mixed Include user authentication token. True indicates to generate a token for current user, and integer value
86
     * indicates to generate a token for the user whose id is the value indicated.
87
     */
88
    public $includetoken = false;
89
 
90
    /**
91
     * User picture constructor.
92
     *
93
     * @param stdClass $user user record with at least id, picture, imagealt, firstname and lastname set.
94
     *                 It is recommended to add also contextid of the user for performance reasons.
95
     */
96
    public function __construct(stdClass $user) {
97
        global $DB;
98
 
99
        if (empty($user->id)) {
100
            throw new coding_exception('User id is required when printing user avatar image.');
101
        }
102
 
103
        // Only touch the DB if we are missing data and complain loudly...
104
        $needrec = false;
105
        foreach (\core_user\fields::get_picture_fields() as $field) {
106
            if (!property_exists($user, $field)) {
107
                $needrec = true;
108
                debugging(
109
                    "Missing '{$field}' property in \$user object, "
110
                        . "this is a performance problem that needs to be fixed by a developer. "
111
                        . 'Please use the \core_user\fields API to get the full list of required fields.',
112
                    DEBUG_DEVELOPER,
113
                );
114
                break;
115
            }
116
        }
117
 
118
        if ($needrec) {
119
            $this->user = $DB->get_record(
120
                'user',
121
                ['id' => $user->id],
122
                implode(',', \core_user\fields::get_picture_fields()),
123
                MUST_EXIST
124
            );
125
        } else {
126
            $this->user = clone($user);
127
        }
128
    }
129
 
130
    /**
131
     * Returns a list of required user fields, useful when fetching required user info from db.
132
     *
133
     * In some cases we have to fetch the user data together with some other information,
134
     * the idalias is useful there because the id would otherwise override the main
135
     * id of the result record. Please note it has to be converted back to id before rendering.
136
     *
137
     * @param string $tableprefix name of database table prefix in query
138
     * @param null|array $extrafields extra fields to be included in result
139
     *      Do not include TEXT columns because it would break SELECT DISTINCT in MSSQL.
140
     * @param string $idalias alias of id field
141
     * @param string $fieldprefix prefix to add to all columns in their aliases, does not apply to 'id'
142
     * @return string
143
     * @deprecated since Moodle 3.11 MDL-45242
144
     * @see \core_user\fields
145
     */
146
    public static function fields(
147
        $tableprefix = '',
148
        ?array $extrafields = null,
149
        $idalias = 'id',
150
        $fieldprefix = '',
151
    ) {
152
        debugging('user_picture::fields() is deprecated. Please use the \core_user\fields API instead.', DEBUG_DEVELOPER);
153
        $userfields = \core_user\fields::for_userpic();
154
        if ($extrafields) {
155
            $userfields->including(...$extrafields);
156
        }
157
        $selects = $userfields->get_sql($tableprefix, false, $fieldprefix, $idalias, false)->selects;
158
        if ($tableprefix === '') {
159
            // If no table alias is specified, don't add {user}. in front of fields.
160
            $selects = str_replace('{user}.', '', $selects);
161
        }
162
        // Maintain legacy behaviour where the field list was done with 'implode' and no spaces.
163
        $selects = str_replace(', ', ',', $selects);
164
        return $selects;
165
    }
166
 
167
    /**
168
     * Extract the aliased user fields from a given record
169
     *
170
     * Given a record that was previously obtained using {@see self::fields()} with aliases,
171
     * this method extracts user related unaliased fields.
172
     *
173
     * @param stdClass $record containing user picture fields
174
     * @param null|array $extrafields extra fields included in the $record
175
     * @param string $idalias alias of the id field
176
     * @param string $fieldprefix prefix added to all columns in their aliases, does not apply to 'id'
177
     * @return stdClass object with unaliased user fields
178
     */
179
    public static function unalias(
180
        stdClass $record,
181
        ?array $extrafields = null,
182
        $idalias = 'id',
183
        $fieldprefix = '',
184
    ) {
185
        if (empty($idalias)) {
186
            $idalias = 'id';
187
        }
188
 
189
        $return = new stdClass();
190
 
191
        foreach (\core_user\fields::get_picture_fields() as $field) {
192
            if ($field === 'id') {
193
                if (property_exists($record, $idalias)) {
194
                    $return->id = $record->{$idalias};
195
                }
196
            } else {
197
                if (property_exists($record, $fieldprefix . $field)) {
198
                    $return->{$field} = $record->{$fieldprefix . $field};
199
                }
200
            }
201
        }
202
        // Add extra fields if not already there.
203
        if ($extrafields) {
204
            foreach ($extrafields as $e) {
205
                if ($e === 'id' || property_exists($return, $e)) {
206
                    continue;
207
                }
208
                $return->{$e} = $record->{$fieldprefix . $e};
209
            }
210
        }
211
 
212
        return $return;
213
    }
214
 
215
    /**
216
     * Checks if the current user is permitted to view user profile images.
217
     *
218
     * This is based on the forcelogin and forceloginforprofileimage config settings, and the
219
     * moodle/user:viewprofilepictures capability.
220
     *
221
     * Logged-in users are allowed to view their own profile image regardless of capability.
222
     *
223
     * @param int $imageuserid User id of profile image being viewed
224
     * @return bool True if current user can view profile images
225
     */
226
    public static function allow_view(int $imageuserid): bool {
227
        global $CFG, $USER;
228
 
229
        // Not allowed to view profile images if forcelogin is enabled and not logged in (guest
230
        // allowed), or forceloginforprofileimage is enabled and not logged in or guest.
231
        if (
232
            (!empty($CFG->forcelogin) && !isloggedin()) ||
233
            (!empty($CFG->forceloginforprofileimage) && (!isloggedin() || isguestuser()))
234
        ) {
235
            return false;
236
        }
237
 
238
        // Unless one of the forcelogin options is enabled, users can download profile pics
239
        // without login, so the capability should not be checked as it might lead to a
240
        // false sense of security (i.e. you log in as a test user, the HTML page doesn't
241
        // show the picture, but they can still access it if they just log out).
242
        // When the capability is checked, use system context for performance (if we check at
243
        // user level, pages that show a lot of user pictures will individually load a lot of
244
        // user contexts).
245
        if (
246
            (!empty($CFG->forcelogin) || !empty($CFG->forceloginforprofileimage)) &&
247
            $USER->id != $imageuserid &&
248
            !has_capability('moodle/user:viewprofilepictures', \context_system::instance())
249
        ) {
250
            return false;
251
        }
252
 
253
        return true;
254
    }
255
 
256
    /**
257
     * Works out the URL for the users picture.
258
     *
259
     * This method is recommended as it avoids costly redirects of user pictures
260
     * if requests are made for non-existent files etc.
261
     *
262
     * @param moodle_page $page
263
     * @param null|renderer_base $renderer
264
     * @return moodle_url
265
     */
266
    public function get_url(
267
        moodle_page $page,
268
        ?renderer_base $renderer = null,
269
    ) {
270
        global $CFG;
271
 
272
        if (is_null($renderer)) {
273
            $renderer = $page->get_renderer('core');
274
        }
275
 
276
        // Sort out the filename and size. Size is only required for the gravatar
277
        // implementation presently.
278
        if (empty($this->size)) {
279
            $filename = 'f2';
280
            $size = 35;
281
        } else if ($this->size === true || $this->size == 1) {
282
            $filename = 'f1';
283
            $size = 100;
284
        } else if ($this->size > 100) {
285
            $filename = 'f3';
286
            $size = (int)$this->size;
287
        } else if ($this->size >= 50) {
288
            $filename = 'f1';
289
            $size = (int)$this->size;
290
        } else {
291
            $filename = 'f2';
292
            $size = (int)$this->size;
293
        }
294
 
295
        $defaulturl = $renderer->image_url('u/' . $filename); // Default image.
296
 
297
        if (!self::allow_view($this->user->id)) {
298
            return $defaulturl;
299
        }
300
 
301
        // First try to detect deleted users - but do not read from database for performance reasons!
302
        if (!empty($this->user->deleted) || !str_contains($this->user->email, '@')) {
303
            // All deleted users should have email replaced by md5 hash,
304
            // all active users are expected to have valid email.
305
            return $defaulturl;
306
        }
307
 
308
        // Did the user upload a picture?
309
        if ($this->user->picture > 0) {
310
            if (!empty($this->user->contextid)) {
311
                $contextid = $this->user->contextid;
312
            } else {
313
                $context = context_user::instance($this->user->id, IGNORE_MISSING);
314
                if (!$context) {
315
                    // This must be an incorrectly deleted user, all other users have context.
316
                    return $defaulturl;
317
                }
318
                $contextid = $context->id;
319
            }
320
 
321
            $path = '/';
322
            if (clean_param($page->theme->name, PARAM_THEME) == $page->theme->name) {
323
                // We append the theme name to the file path if we have it so that
324
                // in the circumstance that the profile picture is not available
325
                // when the user actually requests it they still get the profile
326
                // picture for the correct theme.
327
                $path .= $page->theme->name . '/';
328
            }
329
            // Set the image URL to the URL for the uploaded file and return.
330
            $url = moodle_url::make_pluginfile_url(
331
                $contextid,
332
                'user',
333
                'icon',
334
                null,
335
                $path,
336
                $filename,
337
                false,
338
                $this->includetoken
339
            );
340
            $url->param('rev', $this->user->picture);
341
            return $url;
342
        }
343
 
344
        if ($this->user->picture == 0 && !empty($CFG->enablegravatar)) {
345
            // Normalise the size variable to acceptable bounds.
346
            if ($size < 1 || $size > 512) {
347
                $size = 35;
348
            }
349
            // Hash the users email address.
350
            $md5 = md5(strtolower(trim($this->user->email)));
351
            // Build a gravatar URL with what we know.
352
 
353
            // Find the best default image URL we can (MDL-35669).
354
            if (empty($CFG->gravatardefaulturl)) {
355
                $absoluteimagepath = $page->theme->resolve_image_location('u/' . $filename, 'core');
356
                if (strpos($absoluteimagepath, $CFG->dirroot) === 0) {
357
                    $gravatardefault = $CFG->wwwroot . substr($absoluteimagepath, strlen($CFG->dirroot));
358
                } else {
359
                    $gravatardefault = $CFG->wwwroot . '/pix/u/' . $filename . '.png';
360
                }
361
            } else {
362
                $gravatardefault = $CFG->gravatardefaulturl;
363
            }
364
 
365
            // If the currently requested page is https then we'll return an
366
            // https gravatar page.
367
            if (is_https()) {
368
                return new moodle_url("https://secure.gravatar.com/avatar/{$md5}", ['s' => $size, 'd' => $gravatardefault]);
369
            } else {
370
                return new moodle_url("http://www.gravatar.com/avatar/{$md5}", ['s' => $size, 'd' => $gravatardefault]);
371
            }
372
        }
373
 
374
        return $defaulturl;
375
    }
376
}
377
 
378
// Alias this class to the old name.
379
// This file will be autoloaded by the legacyclasses autoload system.
380
// In future all uses of this class will be corrected and the legacy references will be removed.
381
class_alias(user_picture::class, \user_picture::class);