Karsten Frohwein, Geschäftsführer
Geschäftsführer der comm-press GmbH und absoluter Drupal Evanglist.

Dateiverarbeitung mit Drupal

Dateien mit Drupal programmatisch verarbeiten

Dateien programmatisch zu verarbeiten kann recht kompliziert werden, wenn man ein paar Dinge nicht weiß.

Ich versuche mal meine Erfahrungen der letzten Tage zusammenzufassen. Ich gehe davon aus, dass das Media Modul mit File Entity läuft und von daher auch Entity API.

Dateien programmatisch zu verarbeiten kann recht kompliziert werden, wenn man ein paar Dinge nicht weiß. Ich versuche mal meine Erfahrungen der letzten Tage zusammenzufassen. Ich gehe davon aus, dass das Media Modul mit File Entity läuft und von daher auch Entity API.

Daten

Der Entity-Typ ist "file". Die Daten liegen in der Tabelle "file_managed". Es gibt zwei Unique Indizes. Einmal der Primärschlüssel – die File ID (FID) – und der lokale Pfad – die URI. Die URI ist mit stream wrapper immer in der Form "public://ordner/meinbild.jpg". Das bedeutet auch, dass man Dateien eindeutig über die URI laden kann – zum Beispiel mit einer Entity Field Query (EFQ). Wenn ich also mit einem Algorythmus die URI erstellt habe und dieser immer das gleiche Ergebnis bringt, kann man auch ohne die FID eindeutig Dateien verarbeiten. Die Spalte "filename" enthält den originalen Dateinamen. Dieser ist jedoch nicht dafür geeignet die Datei eindeutig zu identifizieren. Die URI überschreibt eine vorhandene Datei oder es wird nach Drupal Manier ein Suffix in Form von "_123" vergeben um die URI eindeutig zu halten. Einen neuen Suffix zu erstellen ist auch das Standard Verhalten.

Uploads

Wenn eine Datei über ein Formular hochgeladen wurde, kann man sie mit file_save_upload() speichern. Man muss aber beachten, dass die Datei danach nur temporär vorhanden ist. Erst wenn wir den Status auf "1" setzen und nochmal speichern, wird die Datei beim nächsten Cron Lauf nicht gelöscht.

Beispiel

Bespiel von drupal.org
<?php
// Upload the file as temporary
$file = file_save_upload('myfile');

// Change the status
$file->status = FILE_STATUS_PERMANENT;

// Update the file status into the database
file_save($file);
?>

Bilder herunterladen

Mit der API Funktion file_save_data() kann man einen beliebigen String / Binary in einer Datei speichern. Diese Datei ist dann auch gleich als permanent markiert.

Beispiel

Hier kann man sehen, wie man erst prüft, ob die Datei schon in der Datenbank vorhanden ist – und wenn nicht, wie diese heruntergeladen wird. Das Beispiel erfordert das Transliteration Modul wegen transliteration_get(). Die Funktion ist sehr nützlich um sicher zu stellen, dass der Dateiname nur ASCII Zeichen enthält. Das Beispiel zielt darauf die neue FID als passendes Array an ein File Field zu übergeben.
<?php
function import_file($uri, $expected_content_type, $folder) {

 
$path = pathinfo($uri);
 
$file_name = strtolower(transliteration_get($path['filename'] . '.' . $path['extension'], '-'));
 
$destination = "public://$folder/$file_name";

 
// Check if there is already a file we can use.
 
$efq = new EntityFieldQuery();
 
$result = $efq->entityCondition('entity_type', 'file')
    ->
propertyCondition('uri', $destination)
    ->
execute();

  if (!empty(
$result)) {
    return array(
'fid' => current($result['file'])->fid);
  }

 
// If the file is new we try to download and save the new file.
 
$request = drupal_http_request($uri);
  if (
$request->code == 200 && $request->data && in_array($request->headers['content-type'], $expected_content_type)) {

    if (
$file = file_save_data($request->data, $destination)) {
      return array(
'fid' => $file->fid);
    }
  }

  return
FALSE;
}
?>
Aus dem File Modul hätte man auch file_uri_to_object() benutzen können. Ich finde das aber nicht so praktisch und ich wollte extra EFQ an Stelle von entity_load() benutzen.

Aktualisieren

Aktualisieren kann man die Datei immer mit file_save(). Dabei ist zu beachten, dass sich die Timestamps der Datei sofort aktualisieren.

Datei in ein File Field geben

Für ein File Field reicht es, die FID an das Feld zu geben. Den Rest erledigt Drupal dann automatisch. Das ist natürlich weniger fehleranfällig.

Kommentare

Karsten Frohwein - 7. Dezember 2012 - 11:32
<p>Hab ich ergänzt :)</p>
Klemens Heinen - 7. Dezember 2012 - 10:57
<p>klitzekleine Ergänzung zu der schönen Zusammenfassung:</p><p>Im Core findet man auch eine Konstante für die "1":</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Change status to permanent.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $file-&gt;status = FILE_STATUS_PERMANENT;</p>