Projet

Général

Profil

Paste
Télécharger (24,7 ko) Statistiques
| Branche: | Révision:

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

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 omitted, 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
  $build = array();
79

    
80
  $entities_by_view_mode = entity_view_mode_prepare('file', $files, $view_mode, $langcode);
81
  foreach ($entities_by_view_mode as $entity_view_mode => $entities) {
82
    field_attach_prepare_view('file', $entities, $entity_view_mode, $langcode);
83
    entity_prepare_view('file', $entities, $langcode);
84

    
85
    foreach ($entities as $entity) {
86
      $build['files'][$entity->fid] = file_view($entity, $entity_view_mode, $langcode);
87
    }
88
  }
89

    
90
  foreach ($files as $file) {
91
    $build['files'][$file->fid]['#weight'] = $weight;
92
    $weight++;
93
  }
94
  // Sort here, to preserve the input order of the entities that were passed to
95
  // this function.
96
  uasort($build['files'], 'element_sort');
97
  $build['files']['#sorted'] = TRUE;
98

    
99
  return $build;
100
}
101

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

    
121
  // Populate $file->content with a render() array.
122
  file_build_content($file, $view_mode, $langcode);
123

    
124
  $build = $file->content;
125
  // We don't need duplicate rendering info in $file->content.
126
  unset($file->content);
127

    
128
  $build += array(
129
    '#theme' => 'file_entity',
130
    '#file' => $file,
131
    '#view_mode' => $view_mode,
132
    '#language' => $langcode,
133
  );
134

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

    
143
  // Allow modules to modify the structured file.
144
  $type = 'file';
145
  drupal_alter(array('file_view', 'entity_view'), $build, $type);
146

    
147
  return $build;
148
}
149

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

    
166
  // Remove previously built content, if exists.
167
  $file->content = array();
168

    
169
  // In case of a multiple view, file_view_multiple() already ran the
170
  // 'prepare_view' step. An internal flag prevents the operation from running
171
  // twice.
172
  // Allow modules to change the view mode.
173
  $view_mode = key(entity_view_mode_prepare('file', array($file->fid => $file), $view_mode, $langcode));
174
  field_attach_prepare_view('file', array($file->fid => $file), $view_mode, $langcode);
175
  entity_prepare_view('file', array($file->fid => $file), $langcode);
176

    
177
  // Build the actual file display.
178
  // @todo Figure out how to clean this crap up.
179
  $file->content['file'] = file_view_file($file, $view_mode, $langcode);
180
  if (isset($file->content['file'])) {
181
    if (isset($file->content['file']['#theme']) && $file->content['file']['#theme'] != 'file_link') {
182
      unset($file->content['file']['#file']);
183
    }
184
    unset($file->content['file']['#view_mode']);
185
    unset($file->content['file']['#language']);
186
  }
187
  else {
188
    unset($file->content['file']);
189
  }
190

    
191
  // Build fields content.
192
  $file->content += field_attach_view('file', $file, $view_mode, $langcode);
193

    
194
  $links = array();
195
  $file->content['links'] = array(
196
    '#theme' => 'links__file',
197
    '#pre_render' => array('drupal_pre_render_links'),
198
    '#attributes' => array('class' => array('links', 'inline')),
199
  );
200
  $file->content['links']['file'] = array(
201
    '#theme' => 'links__file__file',
202
    '#links' => $links,
203
    '#attributes' => array('class' => array('links', 'inline')),
204
  );
205

    
206
  // Allow modules to make their own additions to the file.
207
  module_invoke_all('file_view', $file, $view_mode, $langcode);
208
  module_invoke_all('entity_view', $file, 'file', $view_mode, $langcode);
209
}
210

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

    
232
  // Prepare incoming display specifications.
233
  if (is_string($displays)) {
234
    // Allow modules to change the view mode.
235
    $view_mode = key(entity_view_mode_prepare('file', array($file->fid => $file), $displays, $langcode));
236
    $displays = file_displays($file->type, $view_mode);
237
  }
238
  else {
239
    $view_mode = '_custom_display';
240
  }
241
  drupal_alter('file_displays', $displays, $file, $view_mode);
242
  _file_sort_array_by_weight($displays);
243

    
244
  // Since $file->alt and $file->title were set in file_entity_file_load()
245
  // (which is a language-agnostic hook) they will not be in the correct
246
  // language if the file is being displayed in a language other than the
247
  // default one. Set them again here, using the correct language. This must
248
  // run after hook_file_displays_alter() since the Media module sets
249
  // $file->alt and $file->title again during that hook.
250
  if ($langcode != $GLOBALS['language_content']->language) {
251
    $languages = language_list();
252
    if (isset($languages[$langcode])) {
253
      file_entity_set_title_alt_properties(array($file), $languages[$langcode]);
254
    }
255
  }
256

    
257
  // Attempt to display the file with each of the possible displays. Stop after
258
  // the first successful one. See file_displays() for details.
259
  $element = NULL;
260
  foreach ($displays as $formatter_type => $display) {
261
    if (!empty($display['status'])) {
262
      $formatter_info = file_info_formatter_types($formatter_type);
263
      // Under normal circumstances, the UI prevents enabling formatters for
264
      // incompatible MIME types. In case this was somehow circumvented (for
265
      // example, a module updated its formatter definition without updating
266
      // existing display settings), perform an extra check here.
267
      if (isset($formatter_info['mime types'])) {
268
        if (!file_entity_match_mimetypes($formatter_info['mime types'], $file->filemime)) {
269
          continue;
270
        }
271
      }
272
      if (isset($formatter_info['view callback']) && ($function = $formatter_info['view callback']) && function_exists($function)) {
273
        $display['type'] = $formatter_type;
274
        if (!empty($formatter_info['default settings'])) {
275
          if (empty($display['settings'])) {
276
            $display['settings'] = array();
277
          }
278
          $display['settings'] += $formatter_info['default settings'];
279
        }
280
        $element = $function($file, $display, $langcode);
281
        if (isset($element)) {
282
          break;
283
        }
284
      }
285
    }
286
  }
287

    
288
  // As a last resort, fall back to showing a link to the file.
289
  if (!isset($element)) {
290
    $element = array(
291
      '#theme' => 'file_link',
292
      '#file' => $file,
293
    );
294
  }
295

    
296
  // Add defaults and return the element.
297
  $element += array(
298
    '#file' => $file,
299
    '#view_mode' => $view_mode,
300
    '#language' => $langcode,
301
  );
302

    
303
  return $element;
304
}
305

    
306
/**
307
 * @defgroup file_displays File displays API
308
 * @{
309
 * Functions to load and save information about file displays.
310
 */
311

    
312
/**
313
 * Returns an array of displays to use for a file type in a given view mode.
314
 *
315
 * It is common for a site to be configured with broadly defined file types
316
 * (e.g., 'video'), and to have different files of this type require different
317
 * displays (for example, the code required to display a YouTube video is
318
 * different than the code required to display a local QuickTime video).
319
 * Therefore, the site administrator can configure multiple displays for a given
320
 * file type. This function returns all of the displays that the administrator
321
 * enabled for the given file type in the given view mode. file_view_file() then
322
 * invokes each of these, and passes the specific file to display. Each display
323
 * implementation can inspect the file, and either return a render array (if it
324
 * is capable of displaying the file), or return nothing (if it is incapable of
325
 * displaying the file). The first render array returned is the one used.
326
 *
327
 * @param string $file_type
328
 *   The type of file.
329
 * @param string $view_mode
330
 *   The view mode.
331
 *
332
 * @return array
333
 *   An array keyed by the formatter type name. Each item in the array contains
334
 *   the following key/value pairs:
335
 *   - status: Whether this display is enabled. If not TRUE, file_view_file()
336
 *     skips over it.
337
 *   - weight: An integer that determines the order of precedence within the
338
 *     returned array. The lowest weight display capable of displaying the file
339
 *     is used.
340
 *   - settings: An array of key/value pairs specific to the formatter type. See
341
 *     hook_file_formatter_info() for details.
342
 *
343
 * @see hook_file_formatter_info()
344
 * @see file_view_file()
345
 */
346
function file_displays($file_type, $view_mode) {
347
  $cache = &drupal_static(__FUNCTION__, array());
348

    
349
  // If the requested view mode isn't configured to use a custom display for its
350
  // fields, then don't use a custom display for its file either.
351
  if ($view_mode != 'default') {
352
    $view_mode_settings = field_view_mode_settings('file', $file_type);
353
    $view_mode = !empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default';
354
  }
355

    
356
  if (!isset($cache[$file_type][$view_mode])) {
357
    // Load the display configurations for the file type and view mode. If none
358
    // exist for the view mode, use the default view mode.
359
    $displays = file_displays_load($file_type, $view_mode, TRUE);
360
    if (empty($displays) && $view_mode != 'default') {
361
      $cache[$file_type][$view_mode] = file_displays($file_type, 'default');
362
    }
363
    else {
364
      // Convert the display objects to arrays and remove unnecessary keys.
365
      foreach ($displays as $formatter_name => $display) {
366
        $displays[$formatter_name] = array_intersect_key((array) $display, drupal_map_assoc(array('status', 'weight', 'settings')));
367
      }
368
      $cache[$file_type][$view_mode] = $displays;
369
    }
370
  }
371

    
372
  return $cache[$file_type][$view_mode];
373
}
374

    
375
/**
376
 * Returns an array of {file_display} objects for the file type and view mode.
377
 */
378
function file_displays_load($file_type, $view_mode, $key_by_formatter_name = FALSE) {
379
  ctools_include('export');
380

    
381
  $display_names = array();
382
  $prefix = $file_type . '__' . $view_mode . '__';
383
  foreach (array_keys(file_info_formatter_types()) as $formatter_name) {
384
    $display_names[] = $prefix . $formatter_name;
385
  }
386
  $displays = ctools_export_load_object('file_display', 'names', $display_names);
387

    
388
  if ($key_by_formatter_name) {
389
    $prefix_length = strlen($prefix);
390
    $rekeyed_displays = array();
391
    foreach ($displays as $name => $display) {
392
      $rekeyed_displays[substr($name, $prefix_length)] = $display;
393
    }
394
    $displays = $rekeyed_displays;
395
  }
396

    
397
  return $displays;
398
}
399

    
400
/**
401
 * Saves a {file_display} object to the database.
402
 */
403
function file_display_save($display) {
404
  ctools_include('export');
405
  ctools_export_crud_save('file_display', $display);
406
  file_info_cache_clear();
407
}
408

    
409
/**
410
 * Creates a new {file_display} object.
411
 */
412
function file_display_new($file_type, $view_mode, $formatter_name) {
413
  ctools_include('export');
414
  $display = ctools_export_crud_new('file_display');
415
  file_info_cache_clear();
416
  $display->name = implode('__', array($file_type, $view_mode, $formatter_name));
417
  return $display;
418
}
419

    
420
/**
421
 * @} End of "defgroup file_displays".
422
 */
423

    
424
/**
425
 * @defgroup file_types File types API
426
 * @{
427
 * Functions to load and save information about file types.
428
 */
429

    
430
/**
431
 * Load a file type configuration object.
432
 *
433
 * @param string $name
434
 *   The file type machine name to load.
435
 *
436
 * @return object
437
 *   The file type object, or FALSE if it does not exist.
438
 */
439
function file_type_load($name) {
440
  ctools_include('export');
441
  $type = ctools_export_crud_load('file_type', $name);
442
  return isset($type) ? $type : FALSE;
443
}
444

    
445
/**
446
 * Load multiple file type configuration objects.
447
 *
448
 * @param array $names
449
 *   An array of file type machine names to load.
450
 *
451
 * @return array
452
 *   An array of file type objects, keyed by machine name.
453
 */
454
function file_type_load_multiple(array $names) {
455
  ctools_include('export');
456
  return ctools_export_crud_load_multiple('file_type', $names);
457
}
458

    
459
/**
460
 * Load all file type configuration objects.
461
 *
462
 * This includes all enabled and disabled file types.
463
 *
464
 * @param bool $reset
465
 *   If TRUE, the static cache of all file types will be flushed prior to
466
 *   loading. This can be important on listing pages where file types might
467
 *   have changed on the page load.
468
 *
469
 * @return array
470
 *   An array of file type objects, keyed by machine name.
471
 *
472
 * @see file_type_get_enabled_types()
473
 * @see file_type_get_disabled_types()
474
 */
475
function file_type_load_all($reset = FALSE) {
476
  ctools_include('export');
477
  return ctools_export_crud_load_all('file_type', $reset);
478
}
479

    
480
/**
481
 * Returns an array of enabled file types.
482
 */
483
function file_type_get_enabled_types() {
484
  $types = file_type_load_all();
485
  return array_filter($types, 'file_type_is_enabled');
486
}
487

    
488
/**
489
 * Returns an array of disabled file types.
490
 */
491
function file_type_get_disabled_types() {
492
  $types = file_type_load_all();
493
  return array_filter($types, 'file_type_is_disabled');
494
}
495

    
496
/**
497
 * Returns TRUE if a file type is enabled, FALSE otherwise.
498
 */
499
function file_type_is_enabled($type) {
500
  return empty($type->disabled);
501
}
502

    
503
/**
504
 * Returns TRUE if a file type is disabled, FALSE otherwise.
505
 */
506
function file_type_is_disabled($type) {
507
  return !empty($type->disabled);
508
}
509

    
510
/**
511
 * Returns an array of valid file extensions.
512
 */
513
function file_type_get_valid_extensions($type) {
514
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
515
  $mapping = file_mimetype_mapping();
516

    
517
  $type_extensions = array();
518
  $type_ext_keys = array();
519
  if (!empty($type->mimetypes)) {
520
    foreach ($mapping['mimetypes'] as $ext_key => $mimetype) {
521
      if (file_entity_match_mimetypes($mimetype, $type->mimetypes)) {
522
        $type_ext_keys[] = $ext_key;
523
      }
524
    }
525

    
526
    if ($type_ext_keys) {
527
      $type_extensions = array_intersect($mapping['extensions'], $type_ext_keys);
528
      $type_extensions = array_keys($type_extensions);
529
    }
530
  }
531

    
532
  return $type_extensions;
533
}
534

    
535
/**
536
 * Updates an existing file type or creates a new one.
537
 *
538
 * This function can be called on its own, or via the CTools exportables
539
 * 'save callback' for {file_type} objects.
540
 */
541
function file_type_save($type) {
542
  // Get the old type object, so we now can issue the correct insert/update
543
  // queries.
544
  if (!empty($type->old_type) && $type->old_type != $type->type) {
545
    $rename_bundle = TRUE;
546
    $old_type = file_type_load($type->old_type);
547
  }
548
  else {
549
    $rename_bundle = FALSE;
550
    $old_type = file_type_load($type->type);
551
  }
552

    
553
  // The type and label fields are required, but description is optional.
554
  if (!isset($type->description)) {
555
    $type->description = '';
556
  }
557
  $fields = array(
558
    'type' => $type->type,
559
    'label' => $type->label,
560
    'description' => $type->description,
561
    'mimetypes' => serialize($type->mimetypes),
562
  );
563

    
564
  // Update an existing type object, whether with a modified 'type' property or
565
  // not.
566
  if ($old_type) {
567
    if ($old_type->export_type & EXPORT_IN_DATABASE) {
568
      db_update('file_type')
569
        ->fields($fields)
570
        ->condition('type', $old_type->type)
571
        ->execute();
572
    }
573
    else {
574
      db_insert('file_type')
575
        ->fields($fields)
576
        ->execute();
577
    }
578
    if ($rename_bundle) {
579
      field_attach_rename_bundle('file', $old_type->type, $type->type);
580
    }
581
    module_invoke_all('file_type_update', $type);
582
    $status = SAVED_UPDATED;
583
  }
584
  // Insert a new type object.
585
  else {
586
    db_insert('file_type')
587
      ->fields($fields)
588
      ->execute();
589
    field_attach_create_bundle('file', $type->type);
590
    module_invoke_all('file_type_insert', $type);
591
    $status = SAVED_NEW;
592
  }
593

    
594
  // Clear the necessary caches.
595
  file_info_cache_clear();
596

    
597
  // Ensure the type has the correct export_type in case the $type parameter
598
  // continues to be used by the calling function after this function completes.
599
  if (empty($type->export_type)) {
600
    $type->export_type = 0;
601
  }
602
  $type->export_type |= EXPORT_IN_DATABASE;
603

    
604
  return $status;
605
}
606

    
607
/**
608
 * Deletes a file type from the database.
609
 *
610
 * This function can be called on its own, or via the CTools exportables
611
 * 'delete callback' for {file_type} objects.
612
 *
613
 * @param object|string $type
614
 *   Either a loaded file type object or the machine-name of the type.
615
 */
616
function file_type_delete($type) {
617
  $type = is_string($type) ? file_type_load($type) : $type;
618

    
619
  db_delete('file_type')
620
    ->condition('type', $type->type)
621
    ->execute();
622

    
623
  // Remove this type from CToolS status variable.
624
  $status = variable_get('default_file_type', array());
625
  unset($status[$type->type]);
626
  variable_set('default_file_type', $status);
627

    
628
  file_info_cache_clear();
629

    
630
  // After deleting from the database, check if the type still exists as a
631
  // code-provided default type. If not, consider the type fully deleted and
632
  // invoke the needed hooks.
633
  if (!file_type_load($type->type)) {
634
    field_attach_delete_bundle('file', $type->type);
635
    module_invoke_all('file_type_delete', $type);
636
  }
637
}
638

    
639

    
640
/**
641
 * Enable a file type.
642
 *
643
 * @param string $type
644
 *   Type of the file_type to disable
645
 */
646
function file_type_enable($type) {
647
  ctools_include('export');
648
  ctools_export_crud_enable('file_type', $type);
649
}
650

    
651

    
652
/**
653
 * Disable a file type.
654
 *
655
 * @param string $type
656
 *   Type of the file_type to disable
657
 */
658
function file_type_disable($type) {
659
  ctools_include('export');
660
  ctools_export_crud_disable('file_type', $type);
661
}
662

    
663

    
664
/**
665
 * Determines file type for a given file.
666
 *
667
 * @param object $file
668
 *   File object.
669
 *
670
 * @return string
671
 *   Machine name of file type that should be used for given file.
672
 */
673
function file_get_type($file) {
674
  $types = module_invoke_all('file_type', $file);
675
  drupal_alter('file_type', $types, $file);
676

    
677
  return empty($types) ? NULL : reset($types);
678
}
679

    
680
/**
681
 * @} End of "defgroup file_types".
682
 */
683

    
684
/**
685
 * Sorts an array by weight.
686
 *
687
 * Helper function to sort an array by the value of each item's 'weight' key,
688
 * while preserving relative order of items that have equal weight.
689
 */
690
function _file_sort_array_by_weight(&$a) {
691
  $i = 0;
692
  foreach ($a as $key => $item) {
693
    if (!isset($a[$key]['weight'])) {
694
      $a[$key]['weight'] = 0;
695
    }
696
    $original_weight[$key] = $a[$key]['weight'];
697
    $a[$key]['weight'] += $i / 1000;
698
    $i++;
699
  }
700
  uasort($a, 'drupal_sort_weight');
701
  foreach ($a as $key => $item) {
702
    $a[$key]['weight'] = $original_weight[$key];
703
  }
704
}
705

    
706
/**
707
 * User sort function to sort by weight, then label/name.
708
 */
709
function _file_entity_sort_weight_label($a, $b) {
710
  $a_weight = isset($a['weight']) ? $a['weight'] : 0;
711
  $b_weight = isset($b['weight']) ? $b['weight'] : 0;
712
  if ($a_weight == $b_weight) {
713
    $a_label = isset($a['label']) ? $a['label'] : '';
714
    $b_label = isset($b['label']) ? $b['label'] : '';
715
    return strcasecmp($a_label, $b_label);
716
  }
717
  else {
718
    return $a_weight < $b_weight ? -1 : 1;
719
  }
720
}
721

    
722
/**
723
 * Returns a file object which can be passed to file_save().
724
 *
725
 * @param string $uri
726
 *   A string containing the URI, path, or filename.
727
 * @param bool $use_existing
728
 *   (Optional) If TRUE and there's an existing file in the {file_managed}
729
 *   table with the passed in URI, then that file object is returned.
730
 *   Otherwise, a new file object is returned. Default is TRUE.
731
 *
732
 * @return object|bool
733
 *   A file object, or FALSE on error.
734
 *
735
 * @todo This should probably be named
736
 *   file_load_by_uri($uri, $create_if_not_exists).
737
 * @todo Remove this function when http://drupal.org/node/685818 is fixed.
738
 */
739
function file_uri_to_object($uri, $use_existing = TRUE) {
740
  $file = FALSE;
741
  $uri = file_stream_wrapper_uri_normalize($uri);
742

    
743
  if ($use_existing) {
744
    // We should always attempt to re-use a file if possible.
745
    $files = entity_load('file', FALSE, array('uri' => $uri));
746
    $file = !empty($files) ? reset($files) : FALSE;
747
  }
748

    
749
  if (empty($file)) {
750
    $file = new stdClass();
751
    $file->uid = $GLOBALS['user']->uid;
752
    $file->filename = drupal_basename($uri);
753
    $file->uri = $uri;
754
    $file->filemime = file_get_mimetype($uri);
755
    // This is gagged because some uris will not support it.
756
    $file->filesize = @filesize($uri);
757
    $file->timestamp = REQUEST_TIME;
758
    $file->status = FILE_STATUS_PERMANENT;
759
  }
760

    
761
  return $file;
762
}
763

    
764
/**
765
 * Delete multiple files.
766
 *
767
 * Unlike core's file_delete(), this function does not care about file usage
768
 * or skip on invalid URIs. Just deletes the damn file like it should.
769
 *
770
 * @param array $fids
771
 *   An array of file IDs.
772
 */
773
function file_delete_multiple(array $fids) {
774
  $transaction = db_transaction();
775
  if (!empty($fids) && $files = file_load_multiple($fids)) {
776
    try {
777
      foreach ($files as $fid => $file) {
778
        module_invoke_all('file_delete', $file);
779
        module_invoke_all('entity_delete', $file, 'file');
780
        // Skip calling field_attach_delete as file_entity_file_delete()
781
        // does this.
782
        // field_attach_delete('file', $file);
783
        // Remove this file from the search index if needed.
784
        // This code is implemented in file_entity module rather than in search
785
        // module, because node module is implementing search module's API,
786
        // not the other way around.
787
        if (module_exists('search')) {
788
          search_reindex($fid, 'file');
789
        }
790

    
791
        // Make sure the file is deleted before removing its row from the
792
        // database, so UIs can still find the file in the database.
793
        if (file_valid_uri($file->uri)) {
794
          file_unmanaged_delete($file->uri);
795
        }
796
      }
797

    
798
      db_delete('file_managed')
799
        ->condition('fid', $fids, 'IN')
800
        ->execute();
801
      db_delete('file_usage')
802
        ->condition('fid', $fids, 'IN')
803
        ->execute();
804
    }
805
    catch (Exception $e) {
806
      $transaction->rollback();
807
      watchdog_exception('file', $e);
808
      throw $e;
809
    }
810

    
811
    // Clear the page and block and file_load_multiple caches.
812
    entity_get_controller('file')->resetCache();
813
  }
814
}