| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @file 5 * File-handling and attaching files to nodes. 6 * 7 */ 8 9 /** 10 * Implementation of hook_help(). 11 */ 12 function upload_help($path, $arg) { 13 switch ($path) { 14 case 'admin/help#upload': 15 $output = '<p>'. t('The upload module allows users to upload files to the site. The ability to upload files is important for members of a community who want to share work. It is also useful to administrators who want to keep uploaded files connected to posts.') .'</p>'; 16 $output .= '<p>'. t('Users with the upload files permission can upload attachments to posts. Uploads may be enabled for specific content types on the content types settings page. Each user role can be customized to limit or control the file size of uploads, or the maximum dimension of image files.') .'</p>'; 17 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@upload">Upload module</a>.', array('@upload' => 'http://drupal.org/handbook/modules/upload/')) .'</p>'; 18 return $output; 19 case 'admin/settings/uploads': 20 return '<p>'. t('Users with the <a href="@permissions">upload files permission</a> can upload attachments. Users with the <a href="@permissions">view uploaded files permission</a> can view uploaded attachments. You can choose which post types can take attachments on the <a href="@types">content types settings</a> page.', array('@permissions' => url('admin/user/permissions', array('fragment' => 'module-upload')), '@types' => url('admin/content/types'))) .'</p>'; 21 } 22 } 23 24 /** 25 * Implementation of hook_theme() 26 */ 27 function upload_theme() { 28 return array( 29 'upload_attachments' => array( 30 'arguments' => array('files' => NULL), 31 ), 32 'upload_form_current' => array( 33 'arguments' => array('form' => NULL), 34 ), 35 'upload_form_new' => array( 36 'arguments' => array('form' => NULL), 37 ), 38 ); 39 } 40 41 /** 42 * Implementation of hook_perm(). 43 */ 44 function upload_perm() { 45 return array('upload files', 'view uploaded files'); 46 } 47 48 /** 49 * Implementation of hook_link(). 50 */ 51 function upload_link($type, $node = NULL, $teaser = FALSE) { 52 $links = array(); 53 54 // Display a link with the number of attachments 55 if ($teaser && $type == 'node' && isset($node->files) && user_access('view uploaded files')) { 56 $num_files = 0; 57 foreach ($node->files as $file) { 58 if ($file->list) { 59 $num_files++; 60 } 61 } 62 if ($num_files) { 63 $links['upload_attachments'] = array( 64 'title' => format_plural($num_files, '1 attachment', '@count attachments'), 65 'href' => "node/$node->nid", 66 'attributes' => array('title' => t('Read full article to view attachments.')), 67 'fragment' => 'attachments' 68 ); 69 } 70 } 71 72 return $links; 73 } 74 75 /** 76 * Implementation of hook_menu(). 77 */ 78 function upload_menu() { 79 $items['upload/js'] = array( 80 'page callback' => 'upload_js', 81 'access arguments' => array('upload files'), 82 'type' => MENU_CALLBACK, 83 ); 84 $items['admin/settings/uploads'] = array( 85 'title' => 'File uploads', 86 'description' => 'Control how files may be attached to content.', 87 'page callback' => 'drupal_get_form', 88 'page arguments' => array('upload_admin_settings'), 89 'access arguments' => array('administer site configuration'), 90 'type' => MENU_NORMAL_ITEM, 91 'file' => 'upload.admin.inc', 92 ); 93 return $items; 94 } 95 96 function upload_menu_alter(&$items) { 97 $items['system/files']['access arguments'] = array('view uploaded files'); 98 } 99 100 /** 101 * Determine the limitations on files that a given user may upload. The user 102 * may be in multiple roles so we select the most permissive limitations from 103 * all of their roles. 104 * 105 * @param $user 106 * A Drupal user object. 107 * @return 108 * An associative array with the following keys: 109 * 'extensions' 110 * A white space separated string containing all the file extensions this 111 * user may upload. 112 * 'file_size' 113 * The maximum size of a file upload in bytes. 114 * 'user_size' 115 * The total number of bytes for all for a user's files. 116 * 'resolution' 117 * A string specifying the maximum resolution of images. 118 */ 119 function _upload_file_limits($user) { 120 $file_limit = variable_get('upload_uploadsize_default', 1); 121 $user_limit = variable_get('upload_usersize_default', 1); 122 $all_extensions = explode(' ', variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp')); 123 foreach ($user->roles as $rid => $name) { 124 $extensions = variable_get("upload_extensions_$rid", variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp')); 125 $all_extensions = array_merge($all_extensions, explode(' ', $extensions)); 126 127 // A zero value indicates no limit, take the least restrictive limit. 128 $file_size = variable_get("upload_uploadsize_$rid", variable_get('upload_uploadsize_default', 1)) * 1024 * 1024; 129 $file_limit = ($file_limit && $file_size) ? max($file_limit, $file_size) : 0; 130 131 $user_size = variable_get("upload_usersize_$rid", variable_get('upload_usersize_default', 1)) * 1024 * 1024; 132 $user_limit = ($user_limit && $user_size) ? max($user_limit, $user_size) : 0; 133 } 134 $all_extensions = implode(' ', array_unique($all_extensions)); 135 return array( 136 'extensions' => $all_extensions, 137 'file_size' => $file_limit, 138 'user_size' => $user_limit, 139 'resolution' => variable_get('upload_max_resolution', 0), 140 ); 141 } 142 143 /** 144 * Implementation of hook_file_download(). 145 */ 146 function upload_file_download($filepath) { 147 $filepath = file_create_path($filepath); 148 $result = db_query("SELECT f.*, u.nid FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid WHERE filepath = '%s'", $filepath); 149 while ($file = db_fetch_object($result)) { 150 if ($filepath !== $file->filepath) { 151 // Since some database servers sometimes use a case-insensitive 152 // comparison by default, double check that the filename is an exact 153 // match. 154 continue; 155 } 156 if (user_access('view uploaded files') && ($node = node_load($file->nid)) && node_access('view', $node)) { 157 return array( 158 'Content-Type: ' . $file->filemime, 159 'Content-Length: ' . $file->filesize, 160 ); 161 } 162 else { 163 return -1; 164 } 165 } 166 } 167 168 /** 169 * Save new uploads and store them in the session to be associated to the node 170 * on upload_save. 171 * 172 * @param $node 173 * A node object to associate with uploaded files. 174 */ 175 function upload_node_form_submit(&$form, &$form_state) { 176 global $user; 177 178 $limits = _upload_file_limits($user); 179 $validators = array( 180 'file_validate_extensions' => array($limits['extensions']), 181 'file_validate_image_resolution' => array($limits['resolution']), 182 'file_validate_size' => array($limits['file_size'], $limits['user_size']), 183 ); 184 185 // Save new file uploads. 186 if (user_access('upload files') && ($file = file_save_upload('upload', $validators, file_directory_path()))) { 187 $file->list = variable_get('upload_list_default', 1); 188 $file->description = $file->filename; 189 $file->weight = 0; 190 $file->new = TRUE; 191 $form['#node']->files[$file->fid] = $file; 192 $form_state['values']['files'][$file->fid] = (array)$file; 193 } 194 195 if (isset($form_state['values']['files'])) { 196 foreach ($form_state['values']['files'] as $fid => $file) { 197 // If the node was previewed prior to saving, $form['#node']->files[$fid] 198 // is an array instead of an object. Convert file to object for compatibility. 199 $form['#node']->files[$fid] = (object) $form['#node']->files[$fid]; 200 $form_state['values']['files'][$fid]['new'] = !empty($form['#node']->files[$fid]->new); 201 } 202 } 203 204 // Order the form according to the set file weight values. 205 if (!empty($form_state['values']['files'])) { 206 $microweight = 0.001; 207 foreach ($form_state['values']['files'] as $fid => $file) { 208 if (is_numeric($fid)) { 209 $form_state['values']['files'][$fid]['#weight'] = $file['weight'] + $microweight; 210 $microweight += 0.001; 211 } 212 } 213 uasort($form_state['values']['files'], 'element_sort'); 214 } 215 } 216 217 function upload_form_alter(&$form, $form_state, $form_id) { 218 if ($form_id == 'node_type_form' && isset($form['identity']['type'])) { 219 $form['workflow']['upload'] = array( 220 '#type' => 'radios', 221 '#title' => t('Attachments'), 222 '#default_value' => variable_get('upload_'. $form['#node_type']->type, 1), 223 '#options' => array(t('Disabled'), t('Enabled')), 224 ); 225 } 226 227 if (isset($form['type']) && isset($form['#node'])) { 228 $node = $form['#node']; 229 if ($form['type']['#value'] .'_node_form' == $form_id && variable_get("upload_$node->type", TRUE)) { 230 // Attachments fieldset 231 $form['attachments'] = array( 232 '#type' => 'fieldset', 233 '#access' => user_access('upload files'), 234 '#title' => t('File attachments'), 235 '#collapsible' => TRUE, 236 '#collapsed' => empty($node->files), 237 '#description' => t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.'), 238 '#prefix' => '<div class="attachments">', 239 '#suffix' => '</div>', 240 '#weight' => 30, 241 ); 242 243 // Wrapper for fieldset contents (used by ahah.js). 244 $form['attachments']['wrapper'] = array( 245 '#prefix' => '<div id="attach-wrapper">', 246 '#suffix' => '</div>', 247 ); 248 249 // Make sure necessary directories for upload.module exist and are 250 // writable before displaying the attachment form. 251 $path = file_directory_path(); 252 $temp = file_directory_temp(); 253 // Note: pass by reference 254 if (!file_check_directory($path, FILE_CREATE_DIRECTORY) || !file_check_directory($temp, FILE_CREATE_DIRECTORY)) { 255 $form['attachments']['#description'] = t('File attachments are disabled. The file directories have not been properly configured.'); 256 if (user_access('administer site configuration')) { 257 $form['attachments']['#description'] .= ' '. t('Please visit the <a href="@admin-file-system">file system configuration page</a>.', array('@admin-file-system' => url('admin/settings/file-system'))); 258 } 259 else { 260 $form['attachments']['#description'] .= ' '. t('Please contact the site administrator.'); 261 } 262 } 263 else { 264 $form['attachments']['wrapper'] += _upload_form($node); 265 $form['#attributes']['enctype'] = 'multipart/form-data'; 266 } 267 $form['#submit'][] = 'upload_node_form_submit'; 268 } 269 } 270 } 271 272 /** 273 * Implementation of hook_nodeapi(). 274 */ 275 function upload_nodeapi(&$node, $op, $teaser = NULL) { 276 switch ($op) { 277 278 case 'load': 279 $output = ''; 280 if (variable_get("upload_$node->type", 1) == 1) { 281 $output['files'] = upload_load($node); 282 return $output; 283 } 284 break; 285 286 case 'view': 287 if (isset($node->files) && user_access('view uploaded files')) { 288 // Add the attachments list to node body with a heavy 289 // weight to ensure they're below other elements 290 if (count($node->files)) { 291 if (!$teaser && user_access('view uploaded files')) { 292 $node->content['files'] = array( 293 '#value' => theme('upload_attachments', $node->files), 294 '#weight' => 50, 295 ); 296 } 297 } 298 } 299 break; 300 301 case 'insert': 302 case 'update': 303 if (user_access('upload files')) { 304 upload_save($node); 305 } 306 break; 307 308 case 'delete': 309 upload_delete($node); 310 break; 311 312 case 'delete revision': 313 upload_delete_revision($node); 314 break; 315 316 case 'search result': 317 return isset($node->files) && is_array($node->files) ? format_plural(count($node->files), '1 attachment', '@count attachments') : NULL; 318 319 case 'rss item': 320 if (is_array($node->files)) { 321 $files = array(); 322 foreach ($node->files as $file) { 323 if ($file->list) { 324 $files[] = $file; 325 } 326 } 327 if (count($files) > 0) { 328 // RSS only allows one enclosure per item 329 $file = array_shift($files); 330 return array( 331 array( 332 'key' => 'enclosure', 333 'attributes' => array( 334 'url' => file_create_url($file->filepath), 335 'length' => $file->filesize, 336 'type' => $file->filemime 337 ) 338 ) 339 ); 340 } 341 } 342 return array(); 343 } 344 } 345 346 /** 347 * Displays file attachments in table 348 * 349 * @ingroup themeable 350 */ 351 function theme_upload_attachments($files) { 352 $header = array(t('Attachment'), t('Size')); 353 $rows = array(); 354 foreach ($files as $file) { 355 $file = (object)$file; 356 if ($file->list && empty($file->remove)) { 357 $href = file_create_url($file->filepath); 358 $text = $file->description ? $file->description : $file->filename; 359 $rows[] = array(l($text, $href), format_size($file->filesize)); 360 } 361 } 362 if (count($rows)) { 363 return theme('table', $header, $rows, array('id' => 'attachments')); 364 } 365 } 366 367 /** 368 * Determine how much disk space is occupied by a user's uploaded files. 369 * 370 * @param $uid 371 * The integer user id of a user. 372 * @return 373 * The amount of disk space used by the user in bytes. 374 */ 375 function upload_space_used($uid) { 376 return file_space_used($uid); 377 } 378 379 /** 380 * Determine how much disk space is occupied by uploaded files. 381 * 382 * @return 383 * The amount of disk space used by uploaded files in bytes. 384 */ 385 function upload_total_space_used() { 386 return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid')); 387 } 388 389 function upload_save(&$node) { 390 if (empty($node->files) || !is_array($node->files)) { 391 return; 392 } 393 394 foreach ($node->files as $fid => $file) { 395 // Convert file to object for compatibility 396 $file = (object)$file; 397 398 // Remove file. Process removals first since no further processing 399 // will be required. 400 if (!empty($file->remove)) { 401 db_query('DELETE FROM {upload} WHERE fid = %d AND vid = %d', $fid, $node->vid); 402 403 // If the file isn't used by any other revisions delete it. 404 $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $fid)); 405 if ($count < 1) { 406 file_delete($file->filepath); 407 db_query('DELETE FROM {files} WHERE fid = %d', $fid); 408 } 409 410 // Remove it from the session in the case of new uploads, 411 // that you want to disassociate before node submission. 412 unset($node->files[$fid]); 413 // Move on, so the removed file won't be added to new revisions. 414 continue; 415 } 416 417 // Create a new revision, or associate a new file needed. 418 if (!empty($node->old_vid) || $file->new) { 419 db_query("INSERT INTO {upload} (fid, nid, vid, list, description, weight) VALUES (%d, %d, %d, %d, '%s', %d)", $file->fid, $node->nid, $node->vid, $file->list, $file->description, $file->weight); 420 file_set_status($file, FILE_STATUS_PERMANENT); 421 } 422 // Update existing revision. 423 else { 424 db_query("UPDATE {upload} SET list = %d, description = '%s', weight = %d WHERE fid = %d AND vid = %d", $file->list, $file->description, $file->weight, $file->fid, $node->vid); 425 file_set_status($file, FILE_STATUS_PERMANENT); 426 } 427 } 428 } 429 430 function upload_delete($node) { 431 $files = array(); 432 $result = db_query('SELECT DISTINCT f.* FROM {upload} u INNER JOIN {files} f ON u.fid = f.fid WHERE u.nid = %d', $node->nid); 433 while ($file = db_fetch_object($result)) { 434 $files[$file->fid] = $file; 435 } 436 437 foreach ($files as $fid => $file) { 438 // Delete all files associated with the node 439 db_query('DELETE FROM {files} WHERE fid = %d', $fid); 440 file_delete($file->filepath); 441 } 442 443 // Delete all file revision information associated with the node 444 db_query('DELETE FROM {upload} WHERE nid = %d', $node->nid); 445 } 446 447 function upload_delete_revision($node) { 448 if (is_array($node->files)) { 449 foreach ($node->files as $file) { 450 // Check if the file will be used after this revision is deleted 451 $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $file->fid)); 452 453 // if the file won't be used, delete it 454 if ($count < 2) { 455 db_query('DELETE FROM {files} WHERE fid = %d', $file->fid); 456 file_delete($file->filepath); 457 } 458 } 459 } 460 461 // delete the revision 462 db_query('DELETE FROM {upload} WHERE vid = %d', $node->vid); 463 } 464 465 function _upload_form($node) { 466 global $user; 467 468 $form = array( 469 '#theme' => 'upload_form_new', 470 '#cache' => TRUE, 471 ); 472 473 if (!empty($node->files) && is_array($node->files)) { 474 $form['files']['#theme'] = 'upload_form_current'; 475 $form['files']['#tree'] = TRUE; 476 foreach ($node->files as $key => $file) { 477 $file = (object)$file; 478 $description = file_create_url($file->filepath); 479 $description = "<small>". check_plain($description) ."</small>"; 480 $form['files'][$key]['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description ); 481 $form['files'][$key]['size'] = array('#value' => format_size($file->filesize)); 482 $form['files'][$key]['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove)); 483 $form['files'][$key]['list'] = array('#type' => 'checkbox', '#default_value' => $file->list); 484 $form['files'][$key]['weight'] = array('#type' => 'weight', '#delta' => count($node->files), '#default_value' => $file->weight); 485 $form['files'][$key]['filename'] = array('#type' => 'value', '#value' => $file->filename); 486 $form['files'][$key]['filepath'] = array('#type' => 'value', '#value' => $file->filepath); 487 $form['files'][$key]['filemime'] = array('#type' => 'value', '#value' => $file->filemime); 488 $form['files'][$key]['filesize'] = array('#type' => 'value', '#value' => $file->filesize); 489 $form['files'][$key]['fid'] = array('#type' => 'value', '#value' => $file->fid); 490 $form['files'][$key]['new'] = array('#type' => 'value', '#value' => FALSE); 491 } 492 } 493 494 if (user_access('upload files')) { 495 $limits = _upload_file_limits($user); 496 $form['new']['#weight'] = 10; 497 $form['new']['upload'] = array( 498 '#type' => 'file', 499 '#title' => t('Attach new file'), 500 '#size' => 40, 501 '#description' => ($limits['resolution'] ? t('Images are larger than %resolution will be resized. ', array('%resolution' => $limits['resolution'])) : '') . t('The maximum upload size is %filesize. Only files with the following extensions may be uploaded: %extensions. ', array('%extensions' => $limits['extensions'], '%filesize' => format_size($limits['file_size']))), 502 ); 503 $form['new']['attach'] = array( 504 '#type' => 'submit', 505 '#value' => t('Attach'), 506 '#name' => 'attach', 507 '#ahah' => array( 508 'path' => 'upload/js', 509 'wrapper' => 'attach-wrapper', 510 'progress' => array('type' => 'bar', 'message' => t('Please wait...')), 511 ), 512 '#submit' => array('node_form_submit_build_node'), 513 ); 514 } 515 516 return $form; 517 } 518 519 /** 520 * Theme the attachments list. 521 * 522 * @ingroup themeable 523 */ 524 function theme_upload_form_current($form) { 525 $header = array('', t('Delete'), t('List'), t('Description'), t('Weight'), t('Size')); 526 drupal_add_tabledrag('upload-attachments', 'order', 'sibling', 'upload-weight'); 527 528 foreach (element_children($form) as $key) { 529 // Add class to group weight fields for drag and drop. 530 $form[$key]['weight']['#attributes']['class'] = 'upload-weight'; 531 532 $row = array(''); 533 $row[] = drupal_render($form[$key]['remove']); 534 $row[] = drupal_render($form[$key]['list']); 535 $row[] = drupal_render($form[$key]['description']); 536 $row[] = drupal_render($form[$key]['weight']); 537 $row[] = drupal_render($form[$key]['size']); 538 $rows[] = array('data' => $row, 'class' => 'draggable'); 539 } 540 $output = theme('table', $header, $rows, array('id' => 'upload-attachments')); 541 $output .= drupal_render($form); 542 return $output; 543 } 544 545 /** 546 * Theme the attachment form. 547 * Note: required to output prefix/suffix. 548 * 549 * @ingroup themeable 550 */ 551 function theme_upload_form_new($form) { 552 drupal_add_tabledrag('upload-attachments', 'order', 'sibling', 'upload-weight'); 553 $output = drupal_render($form); 554 return $output; 555 } 556 557 function upload_load($node) { 558 $files = array(); 559 560 if ($node->vid) { 561 $result = db_query('SELECT * FROM {files} f INNER JOIN {upload} r ON f.fid = r.fid WHERE r.vid = %d ORDER BY r.weight, f.fid', $node->vid); 562 while ($file = db_fetch_object($result)) { 563 $files[$file->fid] = $file; 564 } 565 } 566 567 return $files; 568 } 569 570 /** 571 * Menu-callback for JavaScript-based uploads. 572 */ 573 function upload_js() { 574 $cached_form_state = array(); 575 $files = array(); 576 577 // Load the form from the Form API cache. 578 if (!($cached_form = form_get_cache($_POST['form_build_id'], $cached_form_state)) || !isset($cached_form['#node']) || !isset($cached_form['attachments'])) { 579 form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.')); 580 $output = theme('status_messages'); 581 print drupal_to_js(array('status' => TRUE, 'data' => $output)); 582 exit(); 583 } 584 585 $form_state = array('values' => $_POST); 586 587 // Handle new uploads, and merge tmp files into node-files. 588 upload_node_form_submit($cached_form, $form_state); 589 590 if(!empty($form_state['values']['files'])) { 591 foreach ($form_state['values']['files'] as $fid => $file) { 592 if (isset($cached_form['#node']->files[$fid])) { 593 $files[$fid] = $cached_form['#node']->files[$fid]; 594 } 595 } 596 } 597 598 $node = $cached_form['#node']; 599 600 $node->files = $files; 601 602 $form = _upload_form($node); 603 604 unset($cached_form['attachments']['wrapper']['new']); 605 $cached_form['attachments']['wrapper'] = array_merge($cached_form['attachments']['wrapper'], $form); 606 607 $cached_form['attachments']['#collapsed'] = FALSE; 608 609 form_set_cache($_POST['form_build_id'], $cached_form, $cached_form_state); 610 611 foreach ($files as $fid => $file) { 612 if (is_numeric($fid)) { 613 $form['files'][$fid]['description']['#default_value'] = $form_state['values']['files'][$fid]['description']; 614 $form['files'][$fid]['list']['#default_value'] = !empty($form_state['values']['files'][$fid]['list']); 615 $form['files'][$fid]['remove']['#default_value'] = !empty($form_state['values']['files'][$fid]['remove']); 616 $form['files'][$fid]['weight']['#default_value'] = $form_state['values']['files'][$fid]['weight']; 617 } 618 } 619 620 // Render the form for output. 621 $form += array( 622 '#post' => $_POST, 623 '#programmed' => FALSE, 624 '#tree' => FALSE, 625 '#parents' => array(), 626 ); 627 628 $empty_form_state = array(); 629 $data = &$form; 630 $data['__drupal_alter_by_ref'] = array(&$empty_form_state); 631 drupal_alter('form', $data, 'upload_js'); 632 633 $form_state = array('submitted' => FALSE); 634 $form = form_builder('upload_js', $form, $form_state); 635 $output = theme('status_messages') . drupal_render($form); 636 637 // We send the updated file attachments form. 638 // Don't call drupal_json(). ahah.js uses an iframe and 639 // the header output by drupal_json() causes problems in some browsers. 640 print drupal_to_js(array('status' => TRUE, 'data' => $output)); 641 exit; 642 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |