| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: comment_upload.module,v 1.7.2.24 2009/06/06 01:51:55 netaustin Exp $ 3 4 /** 5 * @file 6 * Provides file attachment functionality for comments. 7 * 8 * Written by Heine Deelstra. Copyright (c) 2008 by Ustima (http://ustima.com). 9 * 10 * This module is licensed under GPL v2. See LICENSE.txt for more information. 11 */ 12 13 /** 14 * @todo views integration 15 * @todo Single file attachments. 16 * @todo React to content type changes 17 */ 18 19 20 /** 21 * Implementation of hook_menu(). 22 */ 23 function comment_upload_menu() { 24 $items = array(); 25 26 $items['comment-upload/js'] = array( 27 'type' => MENU_CALLBACK, 28 'page callback' => 'comment_upload_js', 29 'access arguments' => array('upload files to comments'), 30 ); 31 32 return $items; 33 } 34 35 /** 36 * Implementation of hook_perm(). 37 */ 38 function comment_upload_perm() { 39 return array('upload files to comments', 'view files uploaded to comments'); 40 } 41 42 function comment_upload_theme() { 43 return array( 44 'comment_upload_attachments' => array( 45 'template' => 'comment-upload-attachments', 46 'arguments' => array('files' => NULL, 'display_images' => FALSE, 'preset' => NULL), 47 ), 48 'comment_upload_form_current' => array( 49 'arguments' => array('form' => NULL), 50 ), 51 'comment_upload_form_new' => array( 52 'arguments' => array('form' => NULL), 53 ), 54 ); 55 } 56 57 58 /** 59 * Add an Attachments for comments setting to the content type settings forms. 60 * 61 * Implementation of hook_form_alter(). 62 */ 63 function comment_upload_form_alter(&$form, $form_state, $form_id) { 64 if ($form_id == 'node_type_form' && isset($form['identity']['type'])) { 65 $form['comment']['comment_upload'] = array( 66 '#type' => 'radios', 67 '#title' => t('Attachments on comments'), 68 '#default_value' => variable_get('comment_upload_'. $form['#node_type']->type, 0), 69 '#options' => array(t('Disabled'), t('Enabled')), 70 '#weight' => 20, 71 ); 72 73 $image_options = array( 74 'none' => t('Display as attachment'), 75 'inline' => t('Display as full image'), 76 ); 77 if (module_exists('imagecache')) { 78 $presets = imagecache_presets(); 79 foreach ($presets as $preset_id => $preset) { 80 $image_options[$preset_id] = t('Display via imagecache preset !preset', array('!preset' => $preset['presetname'])); 81 } 82 } 83 $form['comment']['comment_upload_images'] = array( 84 '#type' => 'select', 85 '#title' => t('Image attachments on comments'), 86 '#default_value' => variable_get('comment_upload_images_'. $form['#node_type']->type, 'none'), 87 '#options' => $image_options, 88 '#weight' => 20, 89 ); 90 } 91 elseif ($form_id == 'comment_form') { 92 comment_upload_alter_comment_form($form, $form_state); 93 } 94 } 95 96 /** 97 * Alter the comment form to support AHAH uploads. 98 * 99 * Note; not a hook implementation. 100 */ 101 function comment_upload_alter_comment_form(&$form, $form_state) { 102 if (!user_access('upload files to comments')) { 103 return; 104 } 105 106 // Check whether attachments are enabled for comments on this content type. 107 $node = node_load($form['nid']['#value']); 108 if (!variable_get('comment_upload_'. $node->type, 0)) { 109 return; 110 } 111 112 $files = array(); 113 $cid = $form['cid']['#value']; 114 115 // Rebuild indicates whether we have a pristine form (FALSE) or one that has been trough validation -> submission once. 116 if (empty($form_state['rebuild'])) { 117 if ($cid) { 118 // Attempt to load files for an existing comment. 119 $files = comment_upload_load_files($cid); 120 } 121 } 122 else { 123 // Using the Attach button without JS does not generate a preview. 124 125 // Rape the comment form. 126 // Comment_form was not build to rebuild a form and fetch values from $form_state. 127 // To preserve changes made by the user, we build the part of the form we just received, 128 // mapping $_POST values to #default_values. 129 // Because rebuild is TRUE, $_POST has been validated. Nevertheless this is insane. 130 131 $copy_form = $form; 132 $copy_form['#post'] = $_POST; 133 unset($copy_form['#post']['op']); 134 unset($copy_form['#after_build']); 135 136 $build_form = form_builder('comment_form', $copy_form, $state); 137 comment_upload_value_to_default($build_form, $form); 138 139 form_clean_id(NULL, TRUE); 140 141 if (isset($form_state['storage']['comment_upload_storage'])) { 142 $files = $form_state['storage']['comment_upload_storage']; 143 if (count($files) > 1) { 144 uasort($files, 'comment_upload_sort_files'); 145 } 146 } 147 } 148 149 $form['#comment_upload_storage'] = $files; 150 151 $form['attachments'] = array( 152 '#type' => 'fieldset', 153 '#title' => t('File attachments'), 154 '#collapsible' => TRUE, 155 '#collapsed' => count($files) == 0, 156 '#description' => t('Changes made to the attachments are not permanent until you save this post.'), 157 '#prefix' => '<div class="attachments">', 158 '#suffix' => '</div>', 159 ); 160 161 // Wrapper for fieldset contents (used by ahah.js). 162 $form['attachments']['wrapper'] = array( 163 '#prefix' => '<div id="attach-wrapper">', 164 '#suffix' => '</div>', 165 ); 166 167 $form['attachments']['wrapper'] += comment_upload_upload_form($files); 168 $form['#attributes']['enctype'] = 'multipart/form-data'; 169 170 // Comment_form dynamically adds buttons such as preview / save in the 171 // formbuilder. As the attachment fieldset contains an AHAH element, the 172 // #cache property of the form will be set to TRUE and the formbuilder will 173 // no longer be called. Therefore, comment_upload needs to implement preview 174 // functionality as well. 175 176 $form['#validate'][] = 'comment_upload_comment_form_validate'; 177 } 178 179 /** 180 * Implementation of hook_file_download(). 181 */ 182 function comment_upload_file_download($filepath) { 183 $filepath = file_create_path($filepath); 184 $result = db_query("SELECT f.*, cu.nid FROM {files} f INNER JOIN {comment_upload} cu ON f.fid = cu.fid WHERE filepath = '%s'", $filepath); 185 if ($file = db_fetch_object($result)) { 186 if (user_access('view files uploaded to comments') && ($node = node_load($file->nid)) && node_access('view', $node)) { 187 return array( 188 'Content-Type: '. mime_header_encode($file->filemime), 189 'Content-Length: '. $file->filesize, 190 ); 191 } 192 else { 193 return -1; 194 } 195 } 196 } 197 198 /* 199 * Listen to node deletion and delete files from comments on that node. 200 * 201 * (comment_nodeapi does not call comment APIs when deleting). 202 * 203 * Implementation of hook_nodeapi(). 204 */ 205 function comment_upload_nodeapi(&$node, $op, $arg = 0) { 206 if ($op == 'delete') { 207 $result = db_query("SELECT cu.fid, cu.nid, f.filepath FROM {comment_upload} cu INNER JOIN {files} f ON cu.fid = f.fid WHERE cu.nid = %d", $node->nid); 208 while ($row = db_fetch_array($result)) { 209 // comment_upload_delete_file just needs a filepath and a fid. 210 comment_upload_delete_file($row); 211 } 212 } 213 } 214 215 /** 216 * Implementation of hook_comment(). 217 */ 218 function comment_upload_comment(&$a1, $op) { 219 220 switch ($op) { 221 case 'insert': 222 case 'update': 223 comment_upload_save($a1); 224 break; 225 case 'delete': 226 comment_upload_comment_delete($a1); 227 break; 228 case 'view': 229 comment_upload_comment_view($a1); 230 break; 231 } 232 } 233 234 /** 235 * Traverse a build form and copy #value to corresponding #default_values in an unbuild form. 236 * 237 * @param array $build_form 238 * @param array $form 239 */ 240 function comment_upload_value_to_default($build_form, &$form) { 241 if (!is_array($build_form)) { 242 return; 243 } 244 foreach (element_children($build_form) as $key) { 245 if (isset($form[$key]) && isset($build_form[$key]['#value'])) { 246 $form[$key]['#default_value'] = $build_form[$key]['#value']; 247 } 248 comment_upload_value_to_default($build_form[$key], $form[$key]); 249 } 250 } 251 252 /** 253 * Build the section of the upload_form that holds the attachments table and upload element. 254 * 255 * @param array $files 256 * @return array 257 */ 258 function comment_upload_upload_form($files = array()) { 259 260 $form = array('#theme' => 'comment_upload_form_new'); 261 262 if (!empty($files) && is_array($files)) { 263 $count = count($files); 264 $form['files']['#theme'] = 'comment_upload_form_current'; 265 $form['files']['#tree'] = TRUE; 266 267 foreach ($files as $key => $file) { 268 $file = (object) $file; 269 $form['files'][$key] = comment_upload_create_file_element($file, $count); 270 } 271 } 272 273 $limits = _upload_file_limits($GLOBALS['user']); 274 275 $form['new']['upload'] = array( 276 '#type' => 'file', 277 '#title' => t('Attach new file'), 278 '#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']))), 279 ); 280 281 $form['new']['attach'] = array( 282 '#type' => 'submit', 283 '#value' => t('Attach'), 284 '#name' => 'attach', 285 '#ahah' => array( 286 'path' => 'comment-upload/js', 287 'wrapper' => 'attach-wrapper', 288 'progress' => array('type' => 'bar', 'message' => t('Please wait...')), 289 ), 290 '#submit' => array(), 291 '#validate' => array('comment_upload_comment_form_validate'), 292 ); 293 294 return $form; 295 } 296 297 /** 298 * Create the form elements for one file in the attachments table. 299 * 300 * @param object $file 301 * @param integer $count 302 * @return array 303 */ 304 function comment_upload_create_file_element($file, $count) { 305 $element = array(); 306 307 $description = "<small>". check_plain(file_create_url($file->filepath)) ."</small>"; 308 309 $element['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description ); 310 $element['size'] = array('#value' => format_size($file->filesize)); 311 $element['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove)); 312 $element['list'] = array('#type' => 'checkbox', '#default_value' => $file->list); 313 $element['weight'] = array('#type' => 'weight', '#delta' => $count, '#default_value' => $file->weight); 314 $element['filename'] = array('#type' => 'value', '#value' => $file->filename); 315 $element['filepath'] = array('#type' => 'value', '#value' => $file->filepath); 316 $element['filemime'] = array('#type' => 'value', '#value' => $file->filemime); 317 $element['filesize'] = array('#type' => 'value', '#value' => $file->filesize); 318 $element['fid'] = array('#type' => 'value', '#value' => $file->fid); 319 $element['new'] = array('#type' => 'value', '#value' => FALSE); 320 return $element; 321 } 322 323 324 /** 325 * Remove files when the comment is deleted. 326 * 327 * @param object $comment 328 */ 329 function comment_upload_comment_delete($comment) { 330 $files = comment_upload_load_files($comment->cid); 331 if (!empty($files)) { 332 foreach ($files as $fid => $file) { 333 comment_upload_delete_file($file); 334 } 335 } 336 } 337 338 /** 339 * Add attachments to the comment on view or preview. 340 * 341 * @param object $comment 342 */ 343 function comment_upload_comment_view(&$comment) { 344 $display_images = FALSE; $preset_name = ''; 345 346 if (isset($comment->files)) { 347 $files = $comment->files; 348 } 349 else { 350 $files = comment_upload_load_files($comment->cid); 351 } 352 353 if (isset($files) && count($files)) { 354 if (user_access('view files uploaded to comments')) { 355 $node = node_load($comment->nid); 356 357 $display_setting = variable_get('comment_upload_images_'. $node->type, 'none'); 358 359 if ($display_setting != 'none') { 360 $display_images = TRUE; 361 if (is_numeric($display_setting)) { 362 $imagecache_preset = imagecache_preset($display_setting); 363 $preset_name = $imagecache_preset['presetname']; 364 } 365 } 366 $comment->files = $files; 367 $comment->comment .= theme('comment_upload_attachments', $files, $display_images, $preset_name); 368 } 369 } 370 } 371 372 /** 373 * Save the changes made to attachments. 374 * 375 * @param array $comment 376 */ 377 function comment_upload_save($comment) { 378 if (!user_access('upload files to comments')) { 379 return; 380 } 381 382 if (!isset($comment['files']) || !is_array($comment['files'])) { 383 return; 384 } 385 386 foreach ($comment['files'] as $fid => $file) { 387 if (!empty($file['remove'])) { 388 comment_upload_delete_file($file); 389 } 390 391 if (!empty($file['new'])) { 392 db_query("INSERT INTO {comment_upload} (fid, cid, nid, list, description, weight) VALUES (%d, %d, %d, %d, '%s', %d)", $fid, $comment['cid'], $comment['nid'], $file['list'], $file['description'], $file['weight']); 393 $file = (object)$file; 394 file_set_status($file, FILE_STATUS_PERMANENT); 395 } 396 else { 397 db_query("UPDATE {comment_upload} SET list = %d, description = '%s', weight = %d WHERE fid = %d", $file['list'], $file['description'], $file['weight'], $fid); 398 } 399 } 400 } 401 402 /** 403 * React to the Attach button; update file information on AHAH request. 404 */ 405 function comment_upload_js() { 406 $cached_form_state = array(); 407 $files = array(); 408 // Load the form from the Form API cache. 409 if (empty($_POST) || !($cached_form = form_get_cache($_POST['form_build_id'], $cached_form_state)) || !isset($cached_form['#comment_upload_storage']) || !isset($cached_form['attachments'])) { 410 form_set_error('form_token', t('Validation error, please try again. The file you attempted to upload may be too large. If this error persists, please contact the site administrator.')); 411 $output = theme('status_messages'); 412 print drupal_to_js(array('status' => TRUE, 'data' => $output)); 413 exit(); 414 } 415 416 $form_state = array('values' => $_POST); 417 418 comment_upload_process_files($cached_form, $form_state); 419 if (!empty($form_state['values']['files'])) { 420 foreach ($form_state['values']['files'] as $fid => $file) { 421 if (isset($cached_form['#comment_upload_storage'][$fid])) { 422 $files[$fid] = $cached_form['#comment_upload_storage'][$fid]; 423 } 424 } 425 } 426 427 $form = comment_upload_upload_form($files); 428 429 unset($cached_form['attachments']['wrapper']['new']); 430 $cached_form['attachments']['wrapper'] = array_merge($cached_form['attachments']['wrapper'], $form); 431 $cached_form['attachments']['#collapsed'] = FALSE; 432 form_set_cache($_POST['form_build_id'], $cached_form, $cached_form_state); 433 434 foreach ($files as $fid => $file) { 435 if (is_numeric($fid)) { 436 $form['files'][$fid]['description']['#default_value'] = $form_state['values']['files'][$fid]['description']; 437 $form['files'][$fid]['list']['#default_value'] = !empty($form_state['values']['files'][$fid]['list']); 438 $form['files'][$fid]['remove']['#default_value'] = !empty($form_state['values']['files'][$fid]['remove']); 439 $form['files'][$fid]['weight']['#default_value'] = $form_state['values']['files'][$fid]['weight']; 440 } 441 } 442 443 // Render the form for output. 444 $form += array( 445 '#post' => $_POST, 446 '#programmed' => FALSE, 447 '#tree' => FALSE, 448 '#parents' => array(), 449 ); 450 451 drupal_alter('form', $form, array(), 'comment_upload_js'); 452 $form_state = array('submitted' => FALSE); 453 454 $form = form_builder('comment_upload_js', $form, $form_state); 455 $output = theme('status_messages') . drupal_render($form); 456 457 // We send the updated file attachments form. 458 // Don't call drupal_json(). ahah.js uses an iframe and 459 // the header output by drupal_json() causes problems in some browsers. 460 $GLOBALS['devel_shutdown'] = FALSE; 461 echo drupal_to_js(array('status' => TRUE, 'data' => $output)); 462 exit(); 463 } 464 465 /** 466 * Process file uploads. 467 * 468 * @param array $form 469 * @param array $form_state 470 */ 471 function comment_upload_process_files(&$form, &$form_state) { 472 $limits = _upload_file_limits($GLOBALS['user']); 473 $validators = array( 474 'file_validate_extensions' => array($limits['extensions']), 475 'file_validate_image_resolution' => array($limits['resolution']), 476 'file_validate_size' => array($limits['file_size'], $limits['user_size']), 477 ); 478 479 // Save new file uploads. 480 if (user_access('upload files to comments') && ($file = file_save_upload('upload', $validators, file_directory_path()))) { 481 $file->list = variable_get('upload_list_default', 1); 482 $file->description = $file->filename; 483 $file->weight = 0; 484 $file->remove = 0; 485 if (!isset($form_state['values']['files'][$file->fid]['filepath'])) { 486 $form_state['values']['files'][$file->fid] = (array) $file; 487 $file->new = TRUE; 488 $form['#comment_upload_storage'][$file->fid] = (array) $file; 489 } 490 } 491 else { 492 $errors = form_get_errors(); 493 if (!empty($errors)) { 494 return 0; 495 } 496 else { 497 // If no file has been entered, we have an empty upload element in files. 498 unset($form_state['values']['files']['upload']); 499 } 500 } 501 if (isset($form_state['values']['files'])) { 502 foreach ($form_state['values']['files'] as $fid => $file) { 503 $form_state['values']['files'][$fid]['new'] = !empty($form['#comment_upload_storage'][$fid]['new']) ? TRUE : FALSE; 504 } 505 } 506 507 // Order the form according to the set file weight values. 508 if (!empty($form_state['values']['files'])) { 509 $microweight = 0.001; 510 foreach ($form_state['values']['files'] as $fid => $file) { 511 if (is_numeric($fid)) { 512 $form_state['values']['files'][$fid]['#weight'] = $file['weight'] + $microweight; 513 $microweight += 0.001; 514 } 515 } 516 uasort($form_state['values']['files'], 'element_sort'); 517 } 518 } 519 520 /** 521 * Additional submit handler for the comment form. 522 * 523 * @param array $form 524 * @param array $form_state 525 */ 526 function comment_upload_comment_form_submit($form, &$form_state) { 527 comment_upload_process_files($form, $form_state); 528 unset($form_state['storage']); 529 } 530 531 /** 532 * Submit handler for the preview and attach button. 533 * 534 * @param array $form 535 * @param array $form_state 536 */ 537 function comment_upload_comment_form_validate($form, &$form_state) { 538 if (empty($form_state['values']['op']) && (isset($form_state['clicked_button']) && $form_state['clicked_button']['#value'] != 'Attach')) { 539 return; 540 } 541 elseif(!empty($form_state['rebuild'])) { 542 return; 543 } 544 545 comment_upload_process_files($form, $form_state); 546 foreach ($form['#comment_upload_storage'] as $fid => $file) { 547 if (is_numeric($fid)) { 548 $form['#comment_upload_storage'][$fid]['description'] = $form_state['values']['files'][$fid]['description']; 549 $form['#comment_upload_storage'][$fid]['list'] = $form_state['values']['files'][$fid]['list']; 550 $form['#comment_upload_storage'][$fid]['remove'] = $form_state['values']['files'][$fid]['remove']; 551 $form['#comment_upload_storage'][$fid]['weight'] = $form_state['values']['files'][$fid]['weight']; 552 553 $form_state['storage']['comment_upload_storage'][$fid] = $form['#comment_upload_storage'][$fid]; 554 } 555 } 556 if ((isset($form_state['values']['op']) && $form_state['values']['op'] == 'Preview') || (isset($form_state['clicked_button']) && $form_state['clicked_button']['#value'] == 'Attach')) { 557 $form_state['rebuild'] = TRUE; 558 } 559 elseif (!empty($form_state['submitted'])) { 560 unset($form_state['storage']); 561 } 562 return; 563 } 564 565 /** 566 * Load attachments that belong to the comment. 567 * 568 * @param integer $cid 569 * @return array 570 */ 571 function comment_upload_load_files($cid) { 572 $files = array(); 573 574 $result = db_query('SELECT * FROM {files} f INNER JOIN {comment_upload} cu ON f.fid = cu.fid WHERE cu.cid = %d ORDER BY cu.weight, f.fid', $cid); 575 while ($file = db_fetch_array($result)) { 576 $files[$file['fid']] = $file; 577 } 578 return $files; 579 } 580 581 /** 582 * Delete a file and its associated records. 583 * 584 * @param array $file 585 */ 586 function comment_upload_delete_file($file) { 587 file_delete($file['filepath']); 588 db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']); 589 db_query("DELETE FROM {comment_upload} WHERE fid = %d", $file['fid']); 590 } 591 592 /** 593 * Sort on weight, if weights are equal compare fid. 594 * 595 * uasort callback. 596 */ 597 function comment_upload_sort_files($a, $b) { 598 if ($a['weight'] == $b['weight']) { 599 return ($a['fid'] < $b['fid']) ? -1 : 1; 600 } 601 return ($a['weight'] < $b['weight']) ? -1 : 1; 602 } 603 604 /** 605 * Theme the attachments list in the upload form. 606 * 607 * Taken from upload.module. 608 * 609 * @ingroup themeable 610 */ 611 function theme_comment_upload_form_current(&$form) { 612 $header = array('', t('Delete'), t('List'), t('Description'), t('Weight'), t('Size')); 613 drupal_add_tabledrag('comment-upload-attachments', 'order', 'sibling', 'comment-upload-weight'); 614 615 foreach (element_children($form) as $key) { 616 // Add class to group weight fields for drag and drop. 617 $form[$key]['weight']['#attributes']['class'] = 'comment-upload-weight'; 618 619 $row = array(''); 620 $row[] = drupal_render($form[$key]['remove']); 621 $row[] = drupal_render($form[$key]['list']); 622 $row[] = drupal_render($form[$key]['description']); 623 $row[] = drupal_render($form[$key]['weight']); 624 $row[] = drupal_render($form[$key]['size']); 625 $rows[] = array('data' => $row, 'class' => 'draggable'); 626 } 627 $output = theme('table', $header, $rows, array('id' => 'comment-upload-attachments')); 628 $output .= drupal_render($form); 629 return $output; 630 } 631 632 /** 633 * Theme the upload a new attachment part of the upload form. 634 * 635 * Taken from upload.module. 636 * 637 * @ingroup themeable 638 */ 639 function theme_comment_upload_form_new($form) { 640 drupal_add_tabledrag('comment-upload-attachments', 'order', 'sibling', 'comment-upload-weight'); 641 $output = drupal_render($form); 642 return $output; 643 } 644 645 function template_preprocess_comment_upload_attachments(&$variables) { 646 $row = 0; 647 $variables['images'] = array(); 648 $variables['attachments'] = array(); 649 foreach ($variables['files'] as $fid => $file) { 650 if ($file['list'] && empty($file['remove'])) { 651 $text = $file['description'] ? $file['description'] : $file['filename']; 652 653 if ($variables['display_images'] && strpos($file['filemime'], 'image/') === 0) { 654 if ($variables['preset']) { 655 $variables['images'][$fid]['image'] = theme('imagecache', $variables['preset'], file_create_path($file['filepath']), $text, $text); 656 } 657 else { 658 $variables['images'][$fid]['image'] = theme('image', file_create_path($file['filepath']), $text, $text); 659 } 660 $variables['images'][$fid]['url'] = check_url(file_create_url($file['filepath'])); 661 } 662 else { 663 $variables['attachments'][$fid]['zebra'] = $row % 2 == 0 ? 'odd' : 'even'; 664 $variables['attachments'][$fid]['text'] = check_plain($text); 665 $variables['attachments'][$fid]['url'] = check_url(file_create_url($file['filepath'])); 666 $variables['attachments'][$fid]['size'] = format_size($file['filesize']); 667 $row++; 668 } 669 } 670 } 671 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |