3 ///////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2007 Inaki Arenaza //
7 // Based on .../admin/uploaduser.php and .../lib/gdlib.php //
9 // This program is free software; you can redistribute it and/or modify //
10 // it under the terms of the GNU General Public License as published by //
11 // the Free Software Foundation; either version 2 of the License, or //
12 // (at your option) any later version. //
14 // This program is distributed in the hope that it will be useful, //
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
17 // GNU General Public License for more details: //
19 // http://www.gnu.org/copyleft/gpl.html //
21 ///////////////////////////////////////////////////////////////////////////
23 require_once('../config.php');
24 require_once($CFG->libdir
.'/uploadlib.php');
25 require_once($CFG->libdir
.'/adminlib.php');
26 require_once($CFG->libdir
.'/gdlib.php');
27 require_once('uploadpicture_form.php');
29 define ('PIX_FILE_UPDATED', 0);
30 define ('PIX_FILE_ERROR', 1);
31 define ('PIX_FILE_SKIPPED', 2);
33 admin_externalpage_setup('uploadpictures');
37 require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM
));
39 if (!$site = get_site()) {
40 error("Could not find site-level course");
43 if (!$adminuser = get_admin()) {
44 error("Could not find site admin");
47 $strfile = get_string('file');
48 $struser = get_string('user');
49 $strusersupdated = get_string('usersupdated');
50 $struploadpictures = get_string('uploadpictures','admin');
57 $userfield = optional_param('userfield', 0, PARAM_INT
);
58 $overwritepicture = optional_param('overwritepicture', 0, PARAM_BOOL
);
61 admin_externalpage_print_header();
62 print_heading_with_help($struploadpictures, 'uploadpictures');
64 $mform = new admin_uploadpicture_form(null, $userfields);
65 if ($formdata = $mform->get_data()) {
66 if (!array_key_exists($userfield, $userfields)) {
67 notify(get_string('uploadpicture_baduserfield','admin'));
69 // Large files are likely to take their time and memory. Let PHP know
70 // that we'll take longer, and that the process should be recycled soon
73 @raise_memory_limit
("192M");
74 if (function_exists('apache_child_terminate')) {
75 @apache_child_terminate
();
78 // Create a unique temporary directory, to process the zip file
80 $zipdir = my_mktempdir($CFG->dataroot
.'/temp/', 'usrpic');
82 if (!$mform->save_files($zipdir)) {
83 notify(get_string('uploadpicture_cannotmovezip','admin'));
86 $dstfile = $zipdir.'/'.$mform->get_new_filename();
87 if(!unzip_file($dstfile, $zipdir, false)) {
88 notify(get_string('uploadpicture_cannotunzip','admin'));
91 // We don't need the zip file any longer, so delete it to make
92 // it easier to process the rest of the files inside the directory.
95 $results = array ('errors' => 0,'updated' => 0);
97 process_directory($zipdir, $userfields[$userfield], $overwritepicture, $results);
99 // Finally remove the temporary directory with all the user images and print some stats.
101 notify(get_string('usersupdated', 'admin') . ": " . $results['updated']);
102 notify(get_string('errors', 'admin') . ": " . $results['errors']);
109 admin_externalpage_print_footer();
112 // ----------- Internal functions ----------------
115 * Create a unique temporary directory with a given prefix name,
116 * inside a given directory, with given permissions. Return the
117 * full path to the newly created temp directory.
119 * @param string $dir where to create the temp directory.
120 * @param string $prefix prefix for the temp directory name (default '')
121 * @param string $mode permissions for the temp directory (default 700)
123 * @return string The full path to the temp directory.
125 function my_mktempdir($dir, $prefix='', $mode=0700) {
126 if (substr($dir, -1) != '/') {
131 $path = $dir.$prefix.mt_rand(0, 9999999);
132 } while (!mkdir($path, $mode));
138 * Recursively process a directory, picking regular files and feeding
139 * them to process_file().
141 * @param string $dir the full path of the directory to process
142 * @param string $userfield the prefix_user table field to use to
143 * match picture files to users.
144 * @param bool $overwrite overwrite existing picture or not.
145 * @param array $results (by reference) accumulated statistics of
146 * users updated and errors.
150 function process_directory ($dir, $userfield, $overwrite, &$results) {
151 if(!($handle = opendir($dir))) {
152 notify(get_string('uploadpicture_cannotprocessdir','admin'));
156 while (false !== ($item = readdir($handle))) {
157 if ($item != '.' && $item != '..') {
158 if (is_dir($dir.'/'.$item)) {
159 process_directory($dir.'/'.$item, $userfield, $overwrite, $results);
160 } else if (is_file($dir.'/'.$item)) {
161 $result = process_file($dir.'/'.$item, $userfield, $overwrite);
164 $results['errors']++
;
166 case PIX_FILE_UPDATED
:
167 $results['updated']++
;
171 // Ignore anything else that is not a directory or a file (e.g.,
172 // symbolic links, sockets, pipes, etc.)
179 * Given the full path of a file, try to find the user the file
180 * corresponds to and assign him/her this file as his/her picture.
181 * Make extensive checks to make sure we don't open any security holes
182 * and report back any success/error.
184 * @param string $file the full path of the file to process
185 * @param string $userfield the prefix_user table field to use to
186 * match picture files to users.
187 * @param bool $overwrite overwrite existing picture or not.
189 * @return integer either PIX_FILE_UPDATED, PIX_FILE_ERROR or
192 function process_file ($file, $userfield, $overwrite) {
193 // Add additional checks on the filenames, as they are user
194 // controlled and we don't want to open any security holes.
195 $path_parts = pathinfo(cleardoubleslashes($file));
196 $basename = $path_parts['basename'];
197 $extension = $path_parts['extension'];
199 // The picture file name (without extension) must match the
200 // userfield attribute.
201 $uservalue = substr($basename, 0,
203 strlen($extension) - 1);
205 // userfield names are safe, so don't quote them.
206 if (!($user = get_record('user', $userfield, addslashes($uservalue),'deleted',0))) {
208 $a->userfield
= clean_param($userfield, PARAM_CLEANHTML
);
209 $a->uservalue
= clean_param($uservalue, PARAM_CLEANHTML
);
210 notify(get_string('uploadpicture_usernotfound', 'admin', $a));
211 return PIX_FILE_ERROR
;
214 $haspicture = get_field('user', 'picture', 'id', $user->id
);
215 if ($haspicture && !$overwrite) {
216 notify(get_string('uploadpicture_userskipped', 'admin', $user->username
));
217 return PIX_FILE_SKIPPED
;
220 if (my_save_profile_image($user->id
, $file)) {
221 set_field('user', 'picture', 1, 'id', $user->id
);
222 notify(get_string('uploadpicture_userupdated', 'admin', $user->username
));
223 return PIX_FILE_UPDATED
;
225 notify(get_string('uploadpicture_cannotsave', 'admin', $user->username
));
226 return PIX_FILE_ERROR
;
231 * Try to save the given file (specified by its full path) as the
232 * picture for the user with the given id.
234 * @param integer $id the internal id of the user to assign the
236 * @param string $originalfile the full path of the picture file.
240 function my_save_profile_image($id, $originalfile) {
241 $destination = create_profile_image_destination($id, 'user');
242 if ($destination === false) {
246 return process_profile_image($originalfile, $destination);