| [ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements the UI controller for file upload. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * (dh please re-add) 10 * 11 * {@internal License choice 12 * - If you have received this file as part of a package, please find the license.txt file in 13 * the same folder or the closest folder above for complete license terms. 14 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 15 * then you must choose one of the following licenses before using the file: 16 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 17 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 18 * }} 19 * 20 * {@internal Open Source relicensing agreement: 21 * (dh please re-add) 22 * }} 23 * 24 * @package admin 25 * 26 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 27 * @author fplanque: Francois PLANQUE. 28 * (dh please re-add) 29 * 30 * @version $Id: upload.ctrl.php,v 1.2 2007/09/26 23:32:39 fplanque Exp $ 31 */ 32 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 33 34 /** 35 * Filelist 36 * fp>> TODO: When the user is viewing details for a file he should (by default) not be presented with the filelist in addition to the file properties 37 * In cases like that, we should try to avoid instanciating a Filelist. 38 */ 39 load_class('files/model/_filelist.class.php'); 40 41 /** 42 * @var User 43 */ 44 global $current_User; 45 46 // Check global access permissions: 47 if( ! $Settings->get( 'fm_enabled' ) ) 48 { 49 bad_request_die( 'The filemanager is disabled.' ); 50 } 51 52 // Check permission: 53 $current_User->check_perm( 'files', 'add', true ); 54 55 56 $AdminUI->set_path( 'files', 'upload' ); 57 58 // Params that may need to be passed through: 59 param( 'fm_mode', 'string', NULL, true ); 60 param( 'item_ID', 'integer', NULL, true ); 61 62 $action = param_action(); 63 64 65 // INIT params: 66 if( param( 'root_and_path', 'string', '', false ) /* not memorized (default) */ && strpos( $root_and_path, '::' ) ) 67 { // root and path together: decode and override (used by "radio-click-dirtree") 68 list( $root, $path ) = explode( '::', $root_and_path, 2 ); 69 // Memorize new root: 70 memorize_param( 'root', 'string', NULL ); 71 memorize_param( 'path', 'string', NULL ); 72 } 73 else 74 { 75 param( 'root', 'string', NULL, true ); // the root directory from the dropdown box (user_X or blog_X; X is ID - 'user' for current user (default)) 76 param( 'path', 'string', '/', true ); // the path relative to the root dir 77 if( param( 'new_root', 'string', '' ) 78 && $new_root != $root ) 79 { // We have changed root in the select list 80 $root = $new_root; 81 $path = ''; 82 } 83 } 84 85 // Get root: 86 $ads_list_path = false; // false by default, gets set if we have a valid root 87 /** 88 * @var FileRoot 89 */ 90 $fm_FileRoot = NULL; 91 92 $FileRootCache = & get_Cache( 'FileRootCache' ); 93 94 $available_Roots = $FileRootCache->get_available_FileRoots(); 95 96 if( ! empty($root) ) 97 { // We have requested a root folder by string: 98 $fm_FileRoot = & $FileRootCache->get_by_ID($root, true); 99 100 if( ! $fm_FileRoot || ! isset( $available_Roots[$fm_FileRoot->ID] ) ) 101 { // Root not found or not in list of available ones 102 $Messages->add( T_('You don\'t have access to the requested root directory.'), 'error' ); 103 $fm_FileRoot = false; 104 } 105 } 106 107 if( ! $fm_FileRoot ) 108 { // No root requested (or the requested is invalid), get the first one available: 109 if( $available_Roots 110 && ( $tmp_keys = array_keys( $available_Roots ) ) 111 && $first_Root = & $available_Roots[ $tmp_keys[0] ] ) 112 { // get the first one 113 $fm_FileRoot = & $first_Root; 114 } 115 else 116 { 117 $Messages->add( T_('You don\'t have access to any root directory.'), 'error' ); 118 } 119 } 120 121 if( $fm_FileRoot ) 122 { // We have access to a file root: 123 if( empty($fm_FileRoot->ads_path) ) 124 { // Not sure it's possible to get this far, but just in case... 125 $Messages->add( sprintf( T_('The root directory «%s» does not exist.'), $fm_FileRoot->ads_path ), 'error' ); 126 } 127 else 128 { // Root exists 129 // Let's get into requested list dir... 130 $non_canonical_list_path = $fm_FileRoot->ads_path.$path; 131 132 // Dereference any /../ just to make sure, and CHECK if directory exists: 133 $ads_list_path = get_canonical_path( $non_canonical_list_path ); 134 135 if( !is_dir( $ads_list_path ) ) 136 { // This should never happen, but just in case the diretory does not exist: 137 $Messages->add( sprintf( T_('The directory «%s» does not exist.'), $path ), 'error' ); 138 $path = ''; // fp> added 139 $ads_list_path = NULL; 140 } 141 elseif( ! preg_match( '#^'.preg_quote($fm_FileRoot->ads_path, '#').'#', $ads_list_path ) ) 142 { // cwd is OUTSIDE OF root! 143 $Messages->add( T_( 'You are not allowed to go outside your root directory!' ), 'error' ); 144 $path = ''; // fp> added 145 $ads_list_path = $fm_FileRoot->ads_path; 146 } 147 elseif( $ads_list_path != $non_canonical_list_path ) 148 { // We have reduced the absolute path, we should also reduce the relative $path (used in urls params) 149 $path = get_canonical_path( $path ); 150 } 151 } 152 } 153 154 155 // If there were errors, display them and exit (especially in case there's no valid FileRoot ($fm_FileRoot)): 156 // TODO: dh> this prevents users from uploading if _any_ blog media directory is not writable. 157 // See http://forums.b2evolution.net/viewtopic.php?p=49001#49001 158 if( $Messages->count('error') ) 159 { 160 // Display <html><head>...</head> section! (Note: should be done early if actions do not redirect) 161 $AdminUI->disp_html_head(); 162 163 // Display title, menu, messages, etc. (Note: messages MUST be displayed AFTER the actions) 164 $AdminUI->disp_body_top(); 165 $AdminUI->disp_payload_begin(); 166 $AdminUI->disp_payload_end(); 167 168 $AdminUI->disp_global_footer(); 169 exit(); 170 } 171 172 173 $Debuglog->add( 'FM root: '.var_export( $fm_FileRoot, true ), 'files' ); 174 $Debuglog->add( 'FM _ads_list_path: '.var_export( $ads_list_path, true ), 'files' ); 175 176 177 if( empty($ads_list_path) ) 178 { // We have no Root / list path, there was an error. Unset any action. 179 $action = ''; 180 } 181 182 183 184 185 // Check permissions: 186 if( ! $Settings->get('upload_enabled') ) 187 { // Upload is globally disabled 188 $Messages->add( T_('Upload is disabled.'), 'error' ); 189 } 190 191 if( ! $current_User->check_perm( 'files', 'add' ) ) 192 { // We do not have permission to add files 193 $Messages->add( T_('You have no permission to add/upload files.'), 'error' ); 194 } 195 196 197 // If there were errors, display them and exit (especially in case there's no valid FileRoot ($fm_FileRoot)): 198 if( $Messages->count('error') ) 199 { 200 $AdminUI->disp_html_head(); 201 // Display title, menu, messages, etc. (Note: messages MUST be displayed AFTER the actions) 202 $AdminUI->disp_body_top(); 203 $AdminUI->disp_global_footer(); 204 exit(); 205 } 206 207 208 // Quick mode means "just upload and leave mode when successful" 209 param( 'upload_quickmode', 'integer', 0 ); 210 211 /** 212 * Remember failed files (and the error messages) 213 * @var array 214 */ 215 $failedFiles = array(); 216 217 // Process uploaded files: 218 if( isset($_FILES) && count( $_FILES ) ) 219 { // Some files have been uploaded: 220 param( 'uploadfile_title', 'array', array() ); 221 param( 'uploadfile_alt', 'array', array() ); 222 param( 'uploadfile_desc', 'array', array() ); 223 param( 'uploadfile_name', 'array', array() ); 224 225 foreach( $_FILES['uploadfile']['name'] as $lKey => $lName ) 226 { 227 if( empty( $lName ) ) 228 { // No file name 229 if( $upload_quickmode 230 || !empty( $uploadfile_title[$lKey] ) 231 || !empty( $uploadfile_alt[$lKey] ) 232 || !empty( $uploadfile_desc[$lKey] ) 233 || !empty( $uploadfile_name[$lKey] ) ) 234 { // User specified params but NO file!!! 235 // Remember the file as failed when additional info provided. 236 $failedFiles[$lKey] = T_( 'Please select a local file to upload.' ); 237 } 238 // Abort upload for this file: 239 continue; 240 } 241 242 if( $Settings->get( 'upload_maxkb' ) 243 && $_FILES['uploadfile']['size'][$lKey] > $Settings->get( 'upload_maxkb' )*1024 ) 244 { // bigger than defined by blog 245 $failedFiles[$lKey] = sprintf( 246 /* TRANS: %s will be replaced by the difference */ T_('The file is too large: %s but the maximum allowed is %s.'), 247 bytesreadable( $_FILES['uploadfile']['size'][$lKey] ), 248 bytesreadable($Settings->get( 'upload_maxkb' )*1024) ); 249 // Abort upload for this file: 250 continue; 251 } 252 253 if( $_FILES['uploadfile']['error'][$lKey] ) 254 { // PHP has detected an error!: 255 switch( $_FILES['uploadfile']['error'][$lKey] ) 256 { 257 case UPLOAD_ERR_FORM_SIZE: 258 // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form. 259 260 // This can easily be changed, so we do not use it.. file size gets checked for real just above. 261 break; 262 263 case UPLOAD_ERR_INI_SIZE: // bigger than allowed in php.ini 264 $failedFiles[$lKey] = T_('The file exceeds the upload_max_filesize directive in php.ini.'); 265 // Abort upload for this file: 266 continue; 267 268 case UPLOAD_ERR_PARTIAL: 269 $failedFiles[$lKey] = T_('The file was only partially uploaded.'); 270 // Abort upload for this file: 271 continue; 272 273 case UPLOAD_ERR_NO_FILE: 274 // Is probably the same as empty($lName) before. 275 $failedFiles[$lKey] = T_('No file was uploaded.'); 276 // Abort upload for this file: 277 continue; 278 279 case 6: // numerical value of UPLOAD_ERR_NO_TMP_DIR 280 # (min_php: 4.3.10, 5.0.3) case UPLOAD_ERR_NO_TMP_DIR: 281 // Missing a temporary folder. 282 $failedFiles[$lKey] = T_('Missing a temporary folder (upload_tmp_dir in php.ini).'); 283 // Abort upload for this file: 284 continue; 285 286 default: 287 $failedFiles[$lKey] = T_('Unknown error.').' #'.$_FILES['uploadfile']['error'][$lKey]; 288 // Abort upload for this file: 289 continue; 290 } 291 } 292 293 if( !is_uploaded_file( $_FILES['uploadfile']['tmp_name'][$lKey] ) ) 294 { // Ensure that a malicious user hasn't tried to trick the script into working on files upon which it should not be working. 295 $failedFiles[$lKey] = T_('The file does not seem to be a valid upload! It may exceed the upload_max_filesize directive in php.ini.'); 296 // Abort upload for this file: 297 continue; 298 } 299 300 // Use new name on server if specified: 301 $newName = !empty( $uploadfile_name[ $lKey ] ) ? $uploadfile_name[ $lKey ] : $lName; 302 303 if( $error_filename = validate_filename( $newName ) ) 304 { // Not a file name or not an allowed extension 305 $failedFiles[$lKey] = $error_filename; 306 // Abort upload for this file: 307 continue; 308 } 309 310 // Get File object for requested target location: 311 $FileCache = & get_Cache( 'FileCache' ); 312 $newFile = & $FileCache->get_by_root_and_path( $fm_FileRoot->type, $fm_FileRoot->in_type_ID, trailing_slash($path).$newName, true ); 313 314 if( $newFile->exists() ) 315 { // The file already exists in the target location! 316 // TODO: Rename/Overwriting (save as filename_<numeric_extension> and provide interface to confirm, rename or overwrite) 317 $failedFiles[$lKey] = sprintf( T_('The file «%s» already exists.'), $newFile->dget('name') ); 318 // Abort upload for this file: 319 continue; 320 } 321 322 // Attempt to move the uploaded file to the requested target location: 323 if( !move_uploaded_file( $_FILES['uploadfile']['tmp_name'][$lKey], $newFile->get_full_path() ) ) 324 { 325 $failedFiles[$lKey] = T_('An unknown error occurred when moving the uploaded file on the server.'); 326 // Abort upload for this file: 327 continue; 328 } 329 330 // change to default chmod settings 331 if( $newFile->chmod( NULL ) === false ) 332 { // add a note, this is no error! 333 $Messages->add( sprintf( T_('Could not change permissions of «%s» to default chmod setting.'), $newFile->dget('name') ), 'note' ); 334 } 335 336 // Refreshes file properties (type, size, perms...) 337 $newFile->load_properties(); 338 339 // Store extra info about the file into File Object: 340 if( isset( $uploadfile_title[$lKey] ) ) 341 { // If a title text has been passed... (does not happen in quick upload mode) 342 $newFile->set( 'title', trim( strip_tags($uploadfile_title[$lKey])) ); 343 } 344 if( isset( $uploadfile_alt[$lKey] ) ) 345 { // If an alt text has been passed... (does not happen in quick upload mode) 346 $newFile->set( 'alt', trim( strip_tags($uploadfile_alt[$lKey])) ); 347 } 348 if( isset( $uploadfile_desc[$lKey] ) ) 349 { // If a desc text has been passed... (does not happen in quick upload mode) 350 $newFile->set( 'desc', trim( strip_tags($uploadfile_desc[$lKey])) ); 351 } 352 353 $success_msg = sprintf( T_('The file «%s» has been successfully uploaded.'), $newFile->dget('name') ); 354 if( $mode == 'upload' ) 355 { 356 // TODO: Add plugin hook to allow generating JS insert code(s) 357 $img_tag = format_to_output( $newFile->get_tag(), 'formvalue' ); 358 $success_msg .= 359 '<ul>' 360 .'<li>'.T_("Here's the code to display it:").' <input type="text" value="'.$img_tag.'" /></li>' 361 .'<li><a href="#" onclick="if( window.focus && window.opener ){ window.opener.focus(); textarea_wrap_selection( window.opener.document.getElementById(\'itemform_post_content\'), \''.format_to_output( $newFile->get_tag(), 'formvalue' ).'\', \'\', 1, window.opener.document ); } return false;">'.T_('Add the code to your post !').'</a></li>' 362 .'</ul>'; 363 } 364 365 $Messages->add( $success_msg, 'success' ); 366 367 // Store File object into DB: 368 $newFile->dbsave(); 369 370 } 371 372 if( $upload_quickmode && !empty($failedFiles) ) 373 { // Transmit file error to next page! 374 $Messages->add( $failedFiles[0], 'error' ); 375 unset($failedFiles); 376 } 377 if( empty($failedFiles) ) 378 { // quick mode or no failed files, Go back to Browsing 379 // header_redirect( 'admin.php?ctrl=files&root='.$fm_FileRoot->ID.'&path='.rawurlencode($path) ); 380 header_redirect( regenerate_url( 'ctrl', 'ctrl=files', '', '&' ) ); 381 } 382 } 383 384 385 // Update sub-menu: 386 if( $current_User->check_perm( 'files', 'add' ) ) 387 { // Permission to upload: (no subtabs needed otherwise) 388 $AdminUI->add_menu_entries( 389 'files', 390 array( 391 'browse' => array( 392 'text' => T_('Browse'), 393 'href' => regenerate_url( 'ctrl', 'ctrl=files' ) ), 394 'upload' => array( 395 'text' => T_('Upload multiple'), 396 'href' => regenerate_url( 'ctrl', 'ctrl=upload' ) ), 397 ) 398 ); 399 } 400 401 402 // Display <html><head>...</head> section! (Note: should be done early if actions do not redirect) 403 $AdminUI->disp_html_head(); 404 405 // Display title, menu, messages, etc. (Note: messages MUST be displayed AFTER the actions) 406 $AdminUI->disp_body_top(); 407 408 409 /* 410 * Display payload: 411 */ 412 $AdminUI->disp_view( 'files/views/_file_upload.view.php' ); 413 414 415 // Display body bottom, debug info and close </html>: 416 $AdminUI->disp_global_footer(); 417 418 419 /* 420 * $Log: upload.ctrl.php,v $ 421 * Revision 1.2 2007/09/26 23:32:39 fplanque 422 * upload context saving 423 * 424 * Revision 1.1 2007/06/25 10:59:53 fplanque 425 * MODULES (refactored MVC) 426 * 427 * Revision 1.10 2007/04/26 00:11:13 fplanque 428 * (c) 2007 429 * 430 * Revision 1.9 2007/04/20 01:42:32 fplanque 431 * removed excess javascript 432 * 433 * Revision 1.8 2007/02/22 18:36:57 fplanque 434 * better error messages 435 * 436 * Revision 1.7 2007/01/24 13:44:56 fplanque 437 * cleaned up upload 438 * 439 * Revision 1.6 2007/01/24 02:35:42 fplanque 440 * refactoring 441 * 442 * Revision 1.5 2007/01/24 01:40:15 fplanque 443 * Upload tab now stays in context 444 * 445 * Revision 1.4 2007/01/10 21:41:51 blueyed 446 * todo: any "error" does not allow uploading and "blog media directory could not be created" is such an error, which may not be relevant 447 * 448 * Revision 1.3 2006/12/23 22:53:11 fplanque 449 * extra security 450 * 451 * Revision 1.2 2006/12/22 01:09:30 fplanque 452 * cleanup 453 * 454 * Revision 1.1 2006/12/22 00:51:34 fplanque 455 * dedicated upload tab - proof of concept 456 * (interlinking to be done) 457 * 458 */ 459 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
|