Projet

Général

Profil

Paste
Télécharger (23,5 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / file_entity / file_entity.file_api.inc @ ca0757b9

1
<?php
2

    
3
/**
4
 * @file
5
 * API extensions of Drupal core's file.inc.
6
 */
7

    
8
/**
9
 * The {file_managed}.type value when the file type has not yet been determined.
10
 */
11
define('FILE_TYPE_NONE', 'undefined');
12

    
13
/**
14
 * Returns information about file formatters from hook_file_formatter_info().
15
 *
16
 * @param string $formatter_type
17
 *   (optional) A file formatter type name. If ommitted, all file formatter
18
 *   will be returned.
19
 *
20
 * @return string|array
21
 *   Either a file formatter description, as provided by
22
 *   hook_file_formatter_info(), or an array of all existing file formatters,
23
 *   keyed by formatter type name.
24
 */
25
function file_info_formatter_types($formatter_type = NULL) {
26
  $info = &drupal_static(__FUNCTION__);
27
  if (!isset($info)) {
28
    $info = module_invoke_all('file_formatter_info');
29
    drupal_alter('file_formatter_info', $info);
30
    uasort($info, '_file_entity_sort_weight_label');
31
  }
32
  if ($formatter_type) {
33
    if (isset($info[$formatter_type])) {
34
      return $info[$formatter_type];
35
    }
36
  }
37
  else {
38
    return $info;
39
  }
40
}
41

    
42
/**
43
 * Clears caches that are related to file entity.
44
 *
45
 * Clears all cached configuration related to file types, formatters, and
46
 * display settings.
47
 */
48
function file_info_cache_clear() {
49
  // Clear the CTools managed caches.
50
  ctools_include('export');
51
  ctools_export_load_object_reset('file_type');
52
  ctools_export_load_object_reset('file_display');
53

    
54
  // Clear the formatter type cache, managed by file_info_formatter_types().
55
  drupal_static_reset('file_info_formatter_types');
56

    
57
  // Clear file type caches.
58
  drupal_static_reset('file_type_get_names');
59
}
60

    
61
/**
62
 * Construct a drupal_render() style array from an array of loaded files.
63
 *
64
 * @param array $files
65
 *   An array of files as returned by file_load_multiple().
66
 * @param string $view_mode
67
 *   View mode.
68
 * @param int $weight
69
 *   An integer representing the weight of the first file in the list.
70
 * @param string $langcode
71
 *   A string indicating the language field values are to be shown in. If no
72
 *   language is provided the current content language is used.
73
 *
74
 * @return array
75
 *   An array in the format expected by drupal_render().
76
 */
77
function file_view_multiple($files, $view_mode = 'full', $weight = 0, $langcode = NULL) {
78
  if (empty($files)) {
79
    return array();
80
  }
81

    
82
  field_attach_prepare_view('file', $files, $view_mode, $langcode);
83
  entity_prepare_view('file', $files, $langcode);
84

    
85
  $build = array();
86
  foreach ($files as $file) {
87
    $build['files'][$file->fid] = file_view($file, $view_mode, $langcode);
88
    $build['files'][$file->fid]['#weight'] = $weight;
89
    $weight++;
90
  }
91
  $build['files']['#sorted'] = TRUE;
92

    
93
  return $build;
94
}
95

    
96
/**
97
 * Generate an array for rendering the given file.
98
 *
99
 * @param object $file
100
 *   A file object.
101
 * @param string $view_mode
102
 *   View mode.
103
 * @param string $langcode
104
 *   (optional) A language code to use for rendering. Defaults to the global
105
 *   content language of the current request.
106
 *
107
 * @return array
108
 *   An array as expected by drupal_render().
109
 */
110
function file_view($file, $view_mode = 'full', $langcode = NULL) {
111
  if (!isset($langcode)) {
112
    $langcode = $GLOBALS['language_content']->language;
113
  }
114

    
115
  // Populate $file->content with a render() array.
116
  file_build_content($file, $view_mode, $langcode);
117

    
118
  $build = $file->content;
119
  // We don't need duplicate rendering info in $file->content.
120
  unset($file->content);
121

    
122
  $build += array(
123
    '#theme' => 'file_entity',
124
    '#file' => $file,
125
    '#view_mode' => $view_mode,
126
    '#language' => $langcode,
127
  );
128

    
129
  // Add contextual links for this file, except when the file is already being
130
  // displayed on its own page. Modules may alter this behavior (for example,
131
  // to restrict contextual links to certain view modes) by implementing
132
  // hook_file_view_alter().
133
  if (!empty($file->fid) && !($view_mode == 'full' && file_entity_is_page($file))) {
134
    $build['#contextual_links']['file'] = array('file', array($file->fid));
135
  }
136

    
137
  // Allow modules to modify the structured file.
138
  $type = 'file';
139
  drupal_alter(array('file_view', 'entity_view'), $build, $type);
140

    
141
  return $build;
142
}
143

    
144
/**
145
 * Builds a structured array representing the file's content.
146
 *
147
 * @param object $file
148
 *   A file object.
149
 * @param string $view_mode
150
 *   View mode, e.g. 'default', 'full', etc.
151
 * @param string $langcode
152
 *   (optional) A language code to use for rendering. Defaults to the global
153
 *   content language of the current request.
154
 */
155
function file_build_content($file, $view_mode = 'full', $langcode = NULL) {
156
  if (!isset($langcode)) {
157
    $langcode = $GLOBALS['language_content']->language;
158
  }
159

    
160
  // Remove previously built content, if exists.
161
  $file->content = array();
162

    
163
  // Build the actual file display.
164
  // @todo Figure out how to clean this crap up.
165
  $file->content['file'] = file_view_file($file, $view_mode, $langcode);
166
  if (isset($file->content['file'])) {
167
    if (isset($file->content['file']['#theme']) && $file->content['file']['#theme'] != 'file_link') {
168
      unset($file->content['file']['#file']);
169
    }
170
    unset($file->content['file']['#view_mode']);
171
    unset($file->content['file']['#language']);
172
  }
173
  else {
174
    unset($file->content['file']);
175
  }
176

    
177
  // Build fields content.
178
  // In case of a multiple view, file_view_multiple() already ran the
179
  // 'prepare_view' step. An internal flag prevents the operation from running
180
  // twice.
181
  field_attach_prepare_view('file', array($file->fid => $file), $view_mode, $langcode);
182
  entity_prepare_view('file', array($file->fid => $file), $langcode);
183
  $file->content += field_attach_view('file', $file, $view_mode, $langcode);
184

    
185
  $links = array();
186
  $file->content['links'] = array(
187
    '#theme' => 'links__file',
188
    '#pre_render' => array('drupal_pre_render_links'),
189
    '#attributes' => array('class' => array('links', 'inline')),
190
  );
191
  $file->content['links']['file'] = array(
192
    '#theme' => 'links__file__file',
193
    '#links' => $links,
194
    '#attributes' => array('class' => array('links', 'inline')),
195
  );
196

    
197
  // Allow modules to make their own additions to the file.
198
  module_invoke_all('file_view', $file, $view_mode, $langcode);
199
  module_invoke_all('entity_view', $file, 'file', $view_mode, $langcode);
200
}
201

    
202
/**
203
 * Generate an array for rendering just the file portion of a file entity.
204
 *
205
 * @param object $file
206
 *   A file object.
207
 * @param string|array $displays
208
 *   Can be either:
209
 *   - the name of a view mode;
210
 *   - or an array of custom display settings, as returned by file_displays().
211
 * @param string $langcode
212
 *   (optional) A language code to use for rendering. Defaults to the global
213
 *   content language of the current request.
214
 *
215
 * @return array
216
 *   An array as expected by drupal_render().
217
 */
218
function file_view_file($file, $displays = 'full', $langcode = NULL) {
219
  if (!isset($langcode)) {
220
    $langcode = $GLOBALS['language_content']->language;
221
  }
222

    
223
  // Prepare incoming display specifications.
224
  if (is_string($displays)) {
225
    $view_mode = $displays;
226
    $displays = file_displays($file->type, $view_mode);
227
  }
228
  else {
229
    $view_mode = '_custom_display';
230
  }
231
  drupal_alter('file_displays', $displays, $file, $view_mode);
232
  _file_sort_array_by_weight($displays);
233

    
234
  // Attempt to display the file with each of the possible displays. Stop after
235
  // the first successful one. See file_displays() for details.
236
  $element = NULL;
237
  foreach ($displays as $formatter_type => $display) {
238
    if (!empty($display['status'])) {
239
      $formatter_info = file_info_formatter_types($formatter_type);
240
      // Under normal circumstances, the UI prevents enabling formatters for
241
      // incompatible MIME types. In case this was somehow circumvented (for
242
      // example, a module updated its formatter definition without updating
243
      // existing display settings), perform an extra check here.
244
      if (isset($formatter_info['mime types'])) {
245
        if (!file_entity_match_mimetypes($formatter_info['mime types'], $file->filemime)) {
246
          continue;
247
        }
248
      }
249
      if (isset($formatter_info['view callback']) && ($function = $formatter_info['view callback']) && function_exists($function)) {
250
        $display['type'] = $formatter_type;
251
        if (!empty($formatter_info['default settings'])) {
252
          if (empty($display['settings'])) {
253
            $display['settings'] = array();
254
          }
255
          $display['settings'] += $formatter_info['default settings'];
256
        }
257
        $element = $function($file, $display, $langcode);
258
        if (isset($element)) {
259
          break;
260
        }
261
      }
262
    }
263
  }
264

    
265
  // As a last resort, fall back to showing a link to the file.
266
  if (!isset($element)) {
267
    $element = array(
268
      '#theme' => 'file_link',
269
      '#file' => $file,
270
    );
271
  }
272

    
273
  // Add defaults and return the element.
274
  $element += array(
275
    '#file' => $file,
276
    '#view_mode' => $view_mode,
277
    '#language' => $langcode,
278
  );
279

    
280
  return $element;
281
}
282

    
283
/**
284
 * @defgroup file_displays File displays API
285
 * @{
286
 * Functions to load and save information about file displays.
287
 */
288

    
289
/**
290
 * Returns an array of displays to use for a file type in a given view mode.
291
 *
292
 * It is common for a site to be configured with broadly defined file types
293
 * (e.g., 'video'), and to have different files of this type require different
294
 * displays (for example, the code required to display a YouTube video is
295
 * different than the code required to display a local QuickTime video).
296
 * Therefore, the site administrator can configure multiple displays for a given
297
 * file type. This function returns all of the displays that the administrator
298
 * enabled for the given file type in the given view mode. file_view_file() then
299
 * invokes each of these, and passes the specific file to display. Each display
300
 * implementation can inspect the file, and either return a render array (if it
301
 * is capable of displaying the file), or return nothing (if it is incapable of
302
 * displaying the file). The first render array returned is the one used.
303
 *
304
 * @param string $file_type
305
 *   The type of file.
306
 * @param string $view_mode
307
 *   The view mode.
308
 *
309
 * @return array
310
 *   An array keyed by the formatter type name. Each item in the array contains
311
 *   the following key/value pairs:
312
 *   - status: Whether this display is enabled. If not TRUE, file_view_file()
313
 *     skips over it.
314
 *   - weight: An integer that determines the order of precedence within the
315
 *     returned array. The lowest weight display capable of displaying the file
316
 *     is used.
317
 *   - settings: An array of key/value pairs specific to the formatter type. See
318
 *     hook_file_formatter_info() for details.
319
 *
320
 * @see hook_file_formatter_info()
321
 * @see file_view_file()
322
 */
323
function file_displays($file_type, $view_mode) {
324
  $cache = &drupal_static(__FUNCTION__, array());
325

    
326
  // If the requested view mode isn't configured to use a custom display for its
327
  // fields, then don't use a custom display for its file either.
328
  if ($view_mode != 'default') {
329
    $view_mode_settings = field_view_mode_settings('file', $file_type);
330
    $view_mode = !empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default';
331
  }
332

    
333
  if (!isset($cache[$file_type][$view_mode])) {
334
    // Load the display configurations for the file type and view mode. If none
335
    // exist for the view mode, use the default view mode.
336
    $displays = file_displays_load($file_type, $view_mode, TRUE);
337
    if (empty($displays) && $view_mode != 'default') {
338
      $cache[$file_type][$view_mode] = file_displays($file_type, 'default');
339
    }
340
    else {
341
      // Convert the display objects to arrays and remove unnecessary keys.
342
      foreach ($displays as $formatter_name => $display) {
343
        $displays[$formatter_name] = array_intersect_key((array) $display, drupal_map_assoc(array('status', 'weight', 'settings')));
344
      }
345
      $cache[$file_type][$view_mode] = $displays;
346
    }
347
  }
348

    
349
  return $cache[$file_type][$view_mode];
350
}
351

    
352
/**
353
 * Returns an array of {file_display} objects for the file type and view mode.
354
 */
355
function file_displays_load($file_type, $view_mode, $key_by_formatter_name = FALSE) {
356
  ctools_include('export');
357

    
358
  $display_names = array();
359
  $prefix = $file_type . '__' . $view_mode . '__';
360
  foreach (array_keys(file_info_formatter_types()) as $formatter_name) {
361
    $display_names[] = $prefix . $formatter_name;
362
  }
363
  $displays = ctools_export_load_object('file_display', 'names', $display_names);
364

    
365
  if ($key_by_formatter_name) {
366
    $prefix_length = strlen($prefix);
367
    $rekeyed_displays = array();
368
    foreach ($displays as $name => $display) {
369
      $rekeyed_displays[substr($name, $prefix_length)] = $display;
370
    }
371
    $displays = $rekeyed_displays;
372
  }
373

    
374
  return $displays;
375
}
376

    
377
/**
378
 * Saves a {file_display} object to the database.
379
 */
380
function file_display_save($display) {
381
  ctools_include('export');
382
  ctools_export_crud_save('file_display', $display);
383
  file_info_cache_clear();
384
}
385

    
386
/**
387
 * Creates a new {file_display} object.
388
 */
389
function file_display_new($file_type, $view_mode, $formatter_name) {
390
  ctools_include('export');
391
  $display = ctools_export_crud_new('file_display');
392
  file_info_cache_clear();
393
  $display->name = implode('__', array($file_type, $view_mode, $formatter_name));
394
  return $display;
395
}
396

    
397
/**
398
 * @} End of "defgroup file_displays".
399
 */
400

    
401
/**
402
 * @defgroup file_types File types API
403
 * @{
404
 * Functions to load and save information about file types.
405
 */
406

    
407
/**
408
 * Load a file type configuration object.
409
 *
410
 * @param string $name
411
 *   The file type machine name to load.
412
 *
413
 * @return object
414
 *   The file type object, or FALSE if it does not exist.
415
 */
416
function file_type_load($name) {
417
  ctools_include('export');
418
  $type = ctools_export_crud_load('file_type', $name);
419
  return isset($type) ? $type : FALSE;
420
}
421

    
422
/**
423
 * Load multiple file type configuration objects.
424
 *
425
 * @param array $names
426
 *   An array of file type machine names to load.
427
 *
428
 * @return array
429
 *   An array of file type objects, keyed by machine name.
430
 */
431
function file_type_load_multiple(array $names) {
432
  ctools_include('export');
433
  return ctools_export_crud_load_multiple('file_type', $names);
434
}
435

    
436
/**
437
 * Load all file type configuration objects.
438
 *
439
 * This includes all enabled and disabled file types.
440
 *
441
 * @param bool $reset
442
 *   If TRUE, the static cache of all file types will be flushed prior to
443
 *   loading. This can be important on listing pages where file types might
444
 *   have changed on the page load.
445
 *
446
 * @return array
447
 *   An array of file type objects, keyed by machine name.
448
 *
449
 * @see file_type_get_enabled_types()
450
 * @see file_type_get_disabled_types()
451
 */
452
function file_type_load_all($reset = FALSE) {
453
  ctools_include('export');
454
  return ctools_export_crud_load_all('file_type', $reset);
455
}
456

    
457
/**
458
 * Returns an array of enabled file types.
459
 */
460
function file_type_get_enabled_types() {
461
  $types = file_type_load_all();
462
  return array_filter($types, 'file_type_is_enabled');
463
}
464

    
465
/**
466
 * Returns an array of disabled file types.
467
 */
468
function file_type_get_disabled_types() {
469
  $types = file_type_load_all();
470
  return array_filter($types, 'file_type_is_disabled');
471
}
472

    
473
/**
474
 * Returns TRUE if a file type is enabled, FALSE otherwise.
475
 */
476
function file_type_is_enabled($type) {
477
  return empty($type->disabled);
478
}
479

    
480
/**
481
 * Returns TRUE if a file type is disabled, FALSE otherwise.
482
 */
483
function file_type_is_disabled($type) {
484
  return !empty($type->disabled);
485
}
486

    
487
/**
488
 * Returns an array of valid file extensions.
489
 */
490
function file_type_get_valid_extensions($type) {
491
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
492
  $mapping = file_mimetype_mapping();
493

    
494
  $type_extensions = array();
495
  $type_ext_keys = array();
496
  if (!empty($type->mimetypes)) {
497
    foreach ($mapping['mimetypes'] as $ext_key => $mimetype) {
498
      if (file_entity_match_mimetypes($mimetype, $type->mimetypes)) {
499
        $type_ext_keys[] = $ext_key;
500
      }
501
    }
502

    
503
    if ($type_ext_keys) {
504
      $type_extensions = array_intersect($mapping['extensions'], $type_ext_keys);
505
      $type_extensions = array_keys($type_extensions);
506
    }
507
  }
508

    
509
  return $type_extensions;
510
}
511

    
512
/**
513
 * Updates an existing file type or creates a new one.
514
 *
515
 * This function can be called on its own, or via the CTools exportables
516
 * 'save callback' for {file_type} objects.
517
 */
518
function file_type_save($type) {
519
  // Get the old type object, so we now can issue the correct insert/update
520
  // queries.
521
  if (!empty($type->old_type) && $type->old_type != $type->type) {
522
    $rename_bundle = TRUE;
523
    $old_type = file_type_load($type->old_type);
524
  }
525
  else {
526
    $rename_bundle = FALSE;
527
    $old_type = file_type_load($type->type);
528
  }
529

    
530
  // The type and label fields are required, but description is optional.
531
  if (!isset($type->description)) {
532
    $type->description = '';
533
  }
534
  $fields = array(
535
    'type' => $type->type,
536
    'label' => $type->label,
537
    'description' => $type->description,
538
    'mimetypes' => serialize($type->mimetypes),
539
  );
540

    
541
  // Update an existing type object, whether with a modified 'type' property or
542
  // not.
543
  if ($old_type) {
544
    if ($old_type->export_type & EXPORT_IN_DATABASE) {
545
      db_update('file_type')
546
        ->fields($fields)
547
        ->condition('type', $old_type->type)
548
        ->execute();
549
    }
550
    else {
551
      db_insert('file_type')
552
        ->fields($fields)
553
        ->execute();
554
    }
555
    if ($rename_bundle) {
556
      field_attach_rename_bundle('file', $old_type->type, $type->type);
557
    }
558
    module_invoke_all('file_type_update', $type);
559
    $status = SAVED_UPDATED;
560
  }
561
  // Insert a new type object.
562
  else {
563
    db_insert('file_type')
564
      ->fields($fields)
565
      ->execute();
566
    field_attach_create_bundle('file', $type->type);
567
    module_invoke_all('file_type_insert', $type);
568
    $status = SAVED_NEW;
569
  }
570

    
571
  // Clear the necessary caches.
572
  file_info_cache_clear();
573

    
574
  // Ensure the type has the correct export_type in case the $type parameter
575
  // continues to be used by the calling function after this function completes.
576
  if (empty($type->export_type)) {
577
    $type->export_type = 0;
578
  }
579
  $type->export_type |= EXPORT_IN_DATABASE;
580

    
581
  return $status;
582
}
583

    
584
/**
585
 * Deletes a file type from the database.
586
 *
587
 * This function can be called on its own, or via the CTools exportables
588
 * 'delete callback' for {file_type} objects.
589
 *
590
 * @param object|string $type
591
 *   Either a loaded file type object or the machine-name of the type.
592
 */
593
function file_type_delete($type) {
594
  $type = is_string($type) ? file_type_load($type) : $type;
595

    
596
  db_delete('file_type')
597
    ->condition('type', $type->type)
598
    ->execute();
599

    
600
  // Remove this type from CToolS status variable.
601
  $status = variable_get('default_file_type', array());
602
  unset($status[$type->type]);
603
  variable_set('default_file_type', $status);
604

    
605
  file_info_cache_clear();
606

    
607
  // After deleting from the database, check if the type still exists as a
608
  // code-provided default type. If not, consider the type fully deleted and
609
  // invoke the needed hooks.
610
  if (!file_type_load($type->type)) {
611
    field_attach_delete_bundle('file', $type->type);
612
    module_invoke_all('file_type_delete', $type);
613
  }
614
}
615

    
616

    
617
/**
618
 * Enable a file type.
619
 *
620
 * @param string $type
621
 *   Type of the file_type to disable
622
 */
623
function file_type_enable($type) {
624
  ctools_include('export');
625
  ctools_export_crud_enable('file_type', $type);
626
}
627

    
628

    
629
/**
630
 * Disable a file type.
631
 *
632
 * @param string $type
633
 *   Type of the file_type to disable
634
 */
635
function file_type_disable($type) {
636
  ctools_include('export');
637
  ctools_export_crud_disable('file_type', $type);
638
}
639

    
640

    
641
/**
642
 * Determines file type for a given file.
643
 *
644
 * @param object $file
645
 *   File object.
646
 *
647
 * @return string
648
 *   Machine name of file type that should be used for given file.
649
 */
650
function file_get_type($file) {
651
  $types = module_invoke_all('file_type', $file);
652
  drupal_alter('file_type', $types, $file);
653

    
654
  return empty($types) ? NULL : reset($types);
655
}
656

    
657
/**
658
 * @} End of "defgroup file_types".
659
 */
660

    
661
/**
662
 * Sorts an array by weight.
663
 *
664
 * Helper function to sort an array by the value of each item's 'weight' key,
665
 * while preserving relative order of items that have equal weight.
666
 */
667
function _file_sort_array_by_weight(&$a) {
668
  $i = 0;
669
  foreach ($a as $key => $item) {
670
    if (!isset($a[$key]['weight'])) {
671
      $a[$key]['weight'] = 0;
672
    }
673
    $original_weight[$key] = $a[$key]['weight'];
674
    $a[$key]['weight'] += $i / 1000;
675
    $i++;
676
  }
677
  uasort($a, 'drupal_sort_weight');
678
  foreach ($a as $key => $item) {
679
    $a[$key]['weight'] = $original_weight[$key];
680
  }
681
}
682

    
683
/**
684
 * User sort function to sort by weight, then label/name.
685
 */
686
function _file_entity_sort_weight_label($a, $b) {
687
  $a_weight = isset($a['weight']) ? $a['weight'] : 0;
688
  $b_weight = isset($b['weight']) ? $b['weight'] : 0;
689
  if ($a_weight == $b_weight) {
690
    $a_label = isset($a['label']) ? $a['label'] : '';
691
    $b_label = isset($b['label']) ? $b['label'] : '';
692
    return strcasecmp($a_label, $b_label);
693
  }
694
  else {
695
    return $a_weight < $b_weight ? -1 : 1;
696
  }
697
}
698

    
699
/**
700
 * Returns a file object which can be passed to file_save().
701
 *
702
 * @param string $uri
703
 *   A string containing the URI, path, or filename.
704
 * @param bool $use_existing
705
 *   (Optional) If TRUE and there's an existing file in the {file_managed}
706
 *   table with the passed in URI, then that file object is returned.
707
 *   Otherwise, a new file object is returned. Default is TRUE.
708
 *
709
 * @return object|bool
710
 *   A file object, or FALSE on error.
711
 *
712
 * @todo This should probably be named
713
 *   file_load_by_uri($uri, $create_if_not_exists).
714
 * @todo Remove this function when http://drupal.org/node/685818 is fixed.
715
 */
716
function file_uri_to_object($uri, $use_existing = TRUE) {
717
  $file = FALSE;
718
  $uri = file_stream_wrapper_uri_normalize($uri);
719

    
720
  if ($use_existing) {
721
    // We should always attempt to re-use a file if possible.
722
    $files = entity_load('file', FALSE, array('uri' => $uri));
723
    $file = !empty($files) ? reset($files) : FALSE;
724
  }
725

    
726
  if (empty($file)) {
727
    $file = new stdClass();
728
    $file->uid = $GLOBALS['user']->uid;
729
    $file->filename = drupal_basename($uri);
730
    $file->uri = $uri;
731
    $file->filemime = file_get_mimetype($uri);
732
    // This is gagged because some uris will not support it.
733
    $file->filesize = @filesize($uri);
734
    $file->timestamp = REQUEST_TIME;
735
    $file->status = FILE_STATUS_PERMANENT;
736
  }
737

    
738
  return $file;
739
}
740

    
741
/**
742
 * Delete multiple files.
743
 *
744
 * Unlike core's file_delete(), this function does not care about file usage
745
 * or skip on invalid URIs. Just deletes the damn file like it should.
746
 *
747
 * @param array $fids
748
 *   An array of file IDs.
749
 */
750
function file_delete_multiple(array $fids) {
751
  $transaction = db_transaction();
752
  if (!empty($fids) && $files = file_load_multiple($fids)) {
753
    try {
754
      foreach ($files as $fid => $file) {
755
        module_invoke_all('file_delete', $file);
756
        module_invoke_all('entity_delete', $file, 'file');
757
        // Skip calling field_attach_delete as file_entity_file_delete()
758
        // does this.
759
        // field_attach_delete('file', $file);
760
        // Remove this file from the search index if needed.
761
        // This code is implemented in file_entity module rather than in search
762
        // module, because node module is implementing search module's API,
763
        // not the other way around.
764
        if (module_exists('search')) {
765
          search_reindex($fid, 'file');
766
        }
767

    
768
        // Make sure the file is deleted before removing its row from the
769
        // database, so UIs can still find the file in the database.
770
        if (file_valid_uri($file->uri)) {
771
          file_unmanaged_delete($file->uri);
772
        }
773
      }
774

    
775
      db_delete('file_managed')
776
        ->condition('fid', $fids, 'IN')
777
        ->execute();
778
      db_delete('file_usage')
779
        ->condition('fid', $fids, 'IN')
780
        ->execute();
781
    }
782
    catch (Exception $e) {
783
      $transaction->rollback();
784
      watchdog_exception('file', $e);
785
      throw $e;
786
    }
787

    
788
    // Clear the page and block and file_load_multiple caches.
789
    entity_get_controller('file')->resetCache();
790
  }
791
}