MDL-53139 admin: case diff issue with email
[moodle.git] / admin / tool / uploaduser / picture.php
CommitLineData
9e492db0 1<?php
ce15d56d
PS
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/>.
b352b2e9 16
ce15d56d
PS
17/**
18 * Bulk upload of user pictures
19 *
20 * Based on .../admin/uploaduser.php and .../lib/gdlib.php
21 *
22 * @package tool
23 * @subpackage uploaduser
24 * @copyright (C) 2007 Inaki Arenaza
25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 */
27
28require('../../../config.php');
b352b2e9 29require_once($CFG->libdir.'/adminlib.php');
30require_once($CFG->libdir.'/gdlib.php');
ce15d56d 31require_once('picture_form.php');
b352b2e9 32
c74ca0e9 33define ('PIX_FILE_UPDATED', 0);
34define ('PIX_FILE_ERROR', 1);
20207b82
PS
35define ('PIX_FILE_SKIPPED', 2);
36
ce15d56d 37admin_externalpage_setup('tooluploaduserpictures');
b352b2e9 38
39require_login();
40
4eb42f49 41require_capability('tool/uploaduser:uploaduserpictures', context_system::instance());
b352b2e9 42
2a250a0b 43$site = get_site();
b352b2e9 44
45if (!$adminuser = get_admin()) {
8e9d88f2 46 print_error('noadmins', 'error');
b352b2e9 47}
48
49$strfile = get_string('file');
50$struser = get_string('user');
ce15d56d
PS
51$strusersupdated = get_string('usersupdated', 'tool_uploaduser');
52$struploadpictures = get_string('uploadpictures','tool_uploaduser');
b352b2e9 53
54$userfields = array (
55 0 => 'username',
56 1 => 'idnumber',
57 2 => 'id' );
58
59$userfield = optional_param('userfield', 0, PARAM_INT);
60$overwritepicture = optional_param('overwritepicture', 0, PARAM_BOOL);
61
62/// Print the header
61ef8f9f 63echo $OUTPUT->header();
9e492db0 64
ce15d56d 65echo $OUTPUT->heading_with_help($struploadpictures, 'uploadpictures', 'tool_uploaduser');
b352b2e9 66
70f01544 67$mform = new admin_uploadpicture_form(null, $userfields);
294ce987 68if ($formdata = $mform->get_data()) {
b352b2e9 69 if (!array_key_exists($userfield, $userfields)) {
ce15d56d 70 echo $OUTPUT->notification(get_string('uploadpicture_baduserfield', 'tool_uploaduser'));
b352b2e9 71 } else {
72 // Large files are likely to take their time and memory. Let PHP know
73 // that we'll take longer, and that the process should be recycled soon
74 // to free up memory.
3ef7279f 75 core_php_time_limit::raise();
c22473a2 76 raise_memory_limit(MEMORY_EXTRA);
20207b82 77
b352b2e9 78 // Create a unique temporary directory, to process the zip file
79 // contents.
7aa06e6d 80 $zipdir = my_mktempdir($CFG->tempdir.'/', 'usrpic');
941c3027 81 $dstfile = $zipdir.'/images.zip';
669a9e56 82
941c3027 83 if (!$mform->save_file('userpicturesfile', $dstfile, true)) {
ce15d56d 84 echo $OUTPUT->notification(get_string('uploadpicture_cannotmovezip', 'tool_uploaduser'));
b352b2e9 85 @remove_dir($zipdir);
86 } else {
8d3950ea
SH
87 $fp = get_file_packer('application/zip');
88 $unzipresult = $fp->extract_to_pathname($dstfile, $zipdir);
89 if (!$unzipresult) {
ce15d56d 90 echo $OUTPUT->notification(get_string('uploadpicture_cannotunzip', 'tool_uploaduser'));
b352b2e9 91 @remove_dir($zipdir);
92 } else {
93 // We don't need the zip file any longer, so delete it to make
94 // it easier to process the rest of the files inside the directory.
95 @unlink($dstfile);
20207b82 96
c74ca0e9 97 $results = array ('errors' => 0,'updated' => 0);
98
99 process_directory($zipdir, $userfields[$userfield], $overwritepicture, $results);
100
20207b82 101
b352b2e9 102 // Finally remove the temporary directory with all the user images and print some stats.
103 remove_dir($zipdir);
ce15d56d
PS
104 echo $OUTPUT->notification(get_string('usersupdated', 'tool_uploaduser') . ": " . $results['updated'], 'notifysuccess');
105 echo $OUTPUT->notification(get_string('errors', 'tool_uploaduser') . ": " . $results['errors'], ($results['errors'] ? 'notifyproblem' : 'notifysuccess'));
b352b2e9 106 echo '<hr />';
107 }
108 }
109 }
110}
111$mform->display();
73d6f52f 112echo $OUTPUT->footer();
b352b2e9 113exit;
114
115// ----------- Internal functions ----------------
116
c74ca0e9 117/**
118 * Create a unique temporary directory with a given prefix name,
119 * inside a given directory, with given permissions. Return the
120 * full path to the newly created temp directory.
121 *
122 * @param string $dir where to create the temp directory.
123 * @param string $prefix prefix for the temp directory name (default '')
c74ca0e9 124 *
125 * @return string The full path to the temp directory.
126 */
48183b41
PS
127function my_mktempdir($dir, $prefix='') {
128 global $CFG;
129
b352b2e9 130 if (substr($dir, -1) != '/') {
131 $dir .= '/';
132 }
133
134 do {
135 $path = $dir.$prefix.mt_rand(0, 9999999);
48183b41
PS
136 } while (file_exists($path));
137
138 check_dir_exists($path);
b352b2e9 139
140 return $path;
141}
142
c74ca0e9 143/**
144 * Recursively process a directory, picking regular files and feeding
145 * them to process_file().
146 *
147 * @param string $dir the full path of the directory to process
148 * @param string $userfield the prefix_user table field to use to
149 * match picture files to users.
150 * @param bool $overwrite overwrite existing picture or not.
151 * @param array $results (by reference) accumulated statistics of
152 * users updated and errors.
153 *
154 * @return nothing
155 */
156function process_directory ($dir, $userfield, $overwrite, &$results) {
8fbce1c8 157 global $OUTPUT;
c74ca0e9 158 if(!($handle = opendir($dir))) {
ce15d56d 159 echo $OUTPUT->notification(get_string('uploadpicture_cannotprocessdir', 'tool_uploaduser'));
c74ca0e9 160 return;
161 }
162
163 while (false !== ($item = readdir($handle))) {
164 if ($item != '.' && $item != '..') {
165 if (is_dir($dir.'/'.$item)) {
166 process_directory($dir.'/'.$item, $userfield, $overwrite, $results);
167 } else if (is_file($dir.'/'.$item)) {
168 $result = process_file($dir.'/'.$item, $userfield, $overwrite);
169 switch ($result) {
170 case PIX_FILE_ERROR:
171 $results['errors']++;
172 break;
173 case PIX_FILE_UPDATED:
174 $results['updated']++;
175 break;
176 }
177 }
178 // Ignore anything else that is not a directory or a file (e.g.,
179 // symbolic links, sockets, pipes, etc.)
180 }
181 }
182 closedir($handle);
183}
184
185/**
186 * Given the full path of a file, try to find the user the file
187 * corresponds to and assign him/her this file as his/her picture.
188 * Make extensive checks to make sure we don't open any security holes
189 * and report back any success/error.
190 *
191 * @param string $file the full path of the file to process
192 * @param string $userfield the prefix_user table field to use to
193 * match picture files to users.
194 * @param bool $overwrite overwrite existing picture or not.
195 *
196 * @return integer either PIX_FILE_UPDATED, PIX_FILE_ERROR or
197 * PIX_FILE_SKIPPED
198 */
199function process_file ($file, $userfield, $overwrite) {
8fbce1c8 200 global $DB, $OUTPUT;
20207b82 201
c74ca0e9 202 // Add additional checks on the filenames, as they are user
203 // controlled and we don't want to open any security holes.
204 $path_parts = pathinfo(cleardoubleslashes($file));
205 $basename = $path_parts['basename'];
206 $extension = $path_parts['extension'];
669a9e56 207
c74ca0e9 208 // The picture file name (without extension) must match the
209 // userfield attribute.
210 $uservalue = substr($basename, 0,
211 strlen($basename) -
212 strlen($extension) - 1);
213
214 // userfield names are safe, so don't quote them.
086f0e6f 215 if (!($user = $DB->get_record('user', array ($userfield => $uservalue, 'deleted' => 0)))) {
8c6521bb 216 $a = new stdClass();
c74ca0e9 217 $a->userfield = clean_param($userfield, PARAM_CLEANHTML);
218 $a->uservalue = clean_param($uservalue, PARAM_CLEANHTML);
ce15d56d 219 echo $OUTPUT->notification(get_string('uploadpicture_usernotfound', 'tool_uploaduser', $a));
c74ca0e9 220 return PIX_FILE_ERROR;
221 }
222
223 $haspicture = $DB->get_field('user', 'picture', array('id'=>$user->id));
224 if ($haspicture && !$overwrite) {
ce15d56d 225 echo $OUTPUT->notification(get_string('uploadpicture_userskipped', 'tool_uploaduser', $user->username));
c74ca0e9 226 return PIX_FILE_SKIPPED;
227 }
228
4d254790
PS
229 if ($newrev = my_save_profile_image($user->id, $file)) {
230 $DB->set_field('user', 'picture', $newrev, array('id'=>$user->id));
ce15d56d 231 echo $OUTPUT->notification(get_string('uploadpicture_userupdated', 'tool_uploaduser', $user->username), 'notifysuccess');
c74ca0e9 232 return PIX_FILE_UPDATED;
233 } else {
ce15d56d 234 echo $OUTPUT->notification(get_string('uploadpicture_cannotsave', 'tool_uploaduser', $user->username));
c74ca0e9 235 return PIX_FILE_ERROR;
236 }
237}
238
239/**
240 * Try to save the given file (specified by its full path) as the
241 * picture for the user with the given id.
242 *
243 * @param integer $id the internal id of the user to assign the
244 * picture file to.
245 * @param string $originalfile the full path of the picture file.
246 *
4d254790 247 * @return mixed new unique revision number or false if not saved
c74ca0e9 248 */
b352b2e9 249function my_save_profile_image($id, $originalfile) {
bf006d2c 250 $context = context_user::instance($id);
edfd6a5e 251 return process_new_icon($context, 'user', 'icon', 0, $originalfile);
b352b2e9 252}
253
0df0df23 254