forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 1
/
uploadpicture.php
247 lines (212 loc) · 9.35 KB
/
uploadpicture.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<?php
///////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2007 Inaki Arenaza //
// //
// Based on .../admin/uploaduser.php and .../lib/gdlib.php //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/gdlib.php');
require_once('uploadpicture_form.php');
define ('PIX_FILE_UPDATED', 0);
define ('PIX_FILE_ERROR', 1);
define ('PIX_FILE_SKIPPED', 2);
admin_externalpage_setup('uploadpictures');
require_login();
require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM));
$site = get_site();
if (!$adminuser = get_admin()) {
print_error('noadmins', 'error');
}
$strfile = get_string('file');
$struser = get_string('user');
$strusersupdated = get_string('usersupdated', 'admin');
$struploadpictures = get_string('uploadpictures','admin');
$userfields = array (
0 => 'username',
1 => 'idnumber',
2 => 'id' );
$userfield = optional_param('userfield', 0, PARAM_INT);
$overwritepicture = optional_param('overwritepicture', 0, PARAM_BOOL);
/// Print the header
echo $OUTPUT->header();
echo $OUTPUT->heading_with_help($struploadpictures, 'uploadpictures', 'admin');
$mform = new admin_uploadpicture_form(null, $userfields);
if ($formdata = $mform->get_data()) {
if (!array_key_exists($userfield, $userfields)) {
echo $OUTPUT->notification(get_string('uploadpicture_baduserfield','admin'));
} else {
// Large files are likely to take their time and memory. Let PHP know
// that we'll take longer, and that the process should be recycled soon
// to free up memory.
@set_time_limit(0);
@raise_memory_limit("192M");
if (function_exists('apache_child_terminate')) {
@apache_child_terminate();
}
// Create a unique temporary directory, to process the zip file
// contents.
$zipdir = my_mktempdir($CFG->dataroot.'/temp/', 'usrpic');
$dstfile = $zipdir.'/images.zip';
if (!$mform->save_file('userpicturesfile', $dstfile, true)) {
echo $OUTPUT->notification(get_string('uploadpicture_cannotmovezip','admin'));
@remove_dir($zipdir);
} else {
if (!unzip_file($dstfile, $zipdir, false)) {
echo $OUTPUT->notification(get_string('uploadpicture_cannotunzip','admin'));
@remove_dir($zipdir);
} else {
// We don't need the zip file any longer, so delete it to make
// it easier to process the rest of the files inside the directory.
@unlink($dstfile);
$results = array ('errors' => 0,'updated' => 0);
process_directory($zipdir, $userfields[$userfield], $overwritepicture, $results);
// Finally remove the temporary directory with all the user images and print some stats.
remove_dir($zipdir);
echo $OUTPUT->notification(get_string('usersupdated', 'admin') . ": " . $results['updated']);
echo $OUTPUT->notification(get_string('errors', 'admin') . ": " . $results['errors']);
echo '<hr />';
}
}
}
}
$mform->display();
echo $OUTPUT->footer();
exit;
// ----------- Internal functions ----------------
/**
* Create a unique temporary directory with a given prefix name,
* inside a given directory, with given permissions. Return the
* full path to the newly created temp directory.
*
* @param string $dir where to create the temp directory.
* @param string $prefix prefix for the temp directory name (default '')
* @param string $mode permissions for the temp directory (default 700)
*
* @return string The full path to the temp directory.
*/
function my_mktempdir($dir, $prefix='', $mode=0700) {
if (substr($dir, -1) != '/') {
$dir .= '/';
}
do {
$path = $dir.$prefix.mt_rand(0, 9999999);
} while (!mkdir($path, $mode));
return $path;
}
/**
* Recursively process a directory, picking regular files and feeding
* them to process_file().
*
* @param string $dir the full path of the directory to process
* @param string $userfield the prefix_user table field to use to
* match picture files to users.
* @param bool $overwrite overwrite existing picture or not.
* @param array $results (by reference) accumulated statistics of
* users updated and errors.
*
* @return nothing
*/
function process_directory ($dir, $userfield, $overwrite, &$results) {
global $OUTPUT;
if(!($handle = opendir($dir))) {
echo $OUTPUT->notification(get_string('uploadpicture_cannotprocessdir','admin'));
return;
}
while (false !== ($item = readdir($handle))) {
if ($item != '.' && $item != '..') {
if (is_dir($dir.'/'.$item)) {
process_directory($dir.'/'.$item, $userfield, $overwrite, $results);
} else if (is_file($dir.'/'.$item)) {
$result = process_file($dir.'/'.$item, $userfield, $overwrite);
switch ($result) {
case PIX_FILE_ERROR:
$results['errors']++;
break;
case PIX_FILE_UPDATED:
$results['updated']++;
break;
}
}
// Ignore anything else that is not a directory or a file (e.g.,
// symbolic links, sockets, pipes, etc.)
}
}
closedir($handle);
}
/**
* Given the full path of a file, try to find the user the file
* corresponds to and assign him/her this file as his/her picture.
* Make extensive checks to make sure we don't open any security holes
* and report back any success/error.
*
* @param string $file the full path of the file to process
* @param string $userfield the prefix_user table field to use to
* match picture files to users.
* @param bool $overwrite overwrite existing picture or not.
*
* @return integer either PIX_FILE_UPDATED, PIX_FILE_ERROR or
* PIX_FILE_SKIPPED
*/
function process_file ($file, $userfield, $overwrite) {
global $DB, $OUTPUT;
// Add additional checks on the filenames, as they are user
// controlled and we don't want to open any security holes.
$path_parts = pathinfo(cleardoubleslashes($file));
$basename = $path_parts['basename'];
$extension = $path_parts['extension'];
// The picture file name (without extension) must match the
// userfield attribute.
$uservalue = substr($basename, 0,
strlen($basename) -
strlen($extension) - 1);
// userfield names are safe, so don't quote them.
if (!($user = $DB->get_record('user', array ($userfield => $uservalue, 'deleted' => 0)))) {
$a = new Object();
$a->userfield = clean_param($userfield, PARAM_CLEANHTML);
$a->uservalue = clean_param($uservalue, PARAM_CLEANHTML);
echo $OUTPUT->notification(get_string('uploadpicture_usernotfound', 'admin', $a));
return PIX_FILE_ERROR;
}
$haspicture = $DB->get_field('user', 'picture', array('id'=>$user->id));
if ($haspicture && !$overwrite) {
echo $OUTPUT->notification(get_string('uploadpicture_userskipped', 'admin', $user->username));
return PIX_FILE_SKIPPED;
}
if (my_save_profile_image($user->id, $file)) {
$DB->set_field('user', 'picture', 1, array('id'=>$user->id));
echo $OUTPUT->notification(get_string('uploadpicture_userupdated', 'admin', $user->username));
return PIX_FILE_UPDATED;
} else {
echo $OUTPUT->notification(get_string('uploadpicture_cannotsave', 'admin', $user->username));
return PIX_FILE_ERROR;
}
}
/**
* Try to save the given file (specified by its full path) as the
* picture for the user with the given id.
*
* @param integer $id the internal id of the user to assign the
* picture file to.
* @param string $originalfile the full path of the picture file.
*
* @return bool
*/
function my_save_profile_image($id, $originalfile) {
$context = get_context_instance(CONTEXT_USER, $id);
return process_new_icon($context, 'user', 'icon', 0, $originalfile);
}