Fileupload - eine Kleinigkeit

Anleitungen und Quellcode-Auszüge die den Start vereinfachen sollen.

Fileupload - eine Kleinigkeit

Beitragvon havanna am Mo 23. Feb 2009, 23:23

Nachdem ich heute Abend kurz einen Fileupload erstellt habe und das, was ich so im großen Netz fand nicht ganz weitergeholfen hatte, dachte ich das es eine gute Idee ist, ein kurzes Tutorial dazu zu schreiben.
Die beiden englischsprachigen Blogs verraten auch nur die halbe Wahrheit und die deutschsprachigen Seiten, die man so findet, schaffen es gerade einmal einen Link auf diese Blogs zu setzen (mit Ausnahme DIEEVOLUTION).
Auch die Doku bei cakePHP ist nicht ganz vollständig zu diesem Thema.
Zum Thema:
Die Beispiele, die man zum Thema Fileupload mit cakePHP im Internet findet, beschreiben alle das Speichern der Daten in einer Datenbank-Tabelle. Ich denke nicht, dass das die meisten Anwender möchten. Vielmehr möchte man doch die Datei in ein Verzeichnis schieben und dann einfach verlinken.
Was brauchen wir: einen Controller, ein Modell und einen View (Formular für File-Upload).
Der View fileupload/index.ctp:
Code: Alles auswählen

<p>W&amp;auml;hlen Sie eine lokale Datei aus.</p>
<?php
  echo $form->create(null, array('action' => 'add', 'type' => 'file', 'name'=>'Fileupload'));
  echo $form->file('File');
  echo $form->submit('Upload');
  echo $form->end();
?>
 

Folgende Anmerkungen sind hier zu machen:
Der erste Parameter null besagt, dass wir kein(!) Modell hier mitgeben. Eine Sache, die einen zur Verzweiflung treiben kann. Würden wir hier "fileupload" schreiben, würde cakePHP verzweifelt einen Controller fileuploads suchen (und nicht finden). Der Parameter name fehlt in der Doku. Ich fand ihn zufällig in einer Meldung bei cakePHP. Gerade diesen Parameter benötigen wir aber unbedingt, wenn wir keine Datenbanktabelle und somit kein "echtes" Modell verwenden.

Nun das Modell:
Code: Alles auswählen
<?php

class Fileupload extends AppModel {  
     var $name = 'Fileupload';  
     var $useTable = false;  // Keine Tabelle, wie gesagt.  
   
  // Validierung wie gewünscht  
  var $validate = array(  
    'filename' => array(  
      'allowEmpty' => false,  
      'required' => true,
      'message' => 'Bitte geben Sie eine Datei an'            
    )
  );  
}  
?>

Ich denke da gibt es nichts besonderes zu sagen.

Der Controller:
Code: Alles auswählen
<?php
class FileuploadController extends AppController {

  var $name  = 'Fileupload';
  var $uses  = 'Fileupload';
  var $helpers = array('Html','Form');
 
/******************************************************************************
 Function   : index()
 Arguments : -                      
 Description: Einstiegsseite    
 Template   : fileupload/index.ctp

*******************************************************************************/
   
  function index() {
  }
 
/******************************************************************************
 Function   : add()
 Arguments : -                      
 Description: Upload und verschieben der Datei    
 Template   : add.ctp

*******************************************************************************/
   
  function add() {
    if (!empty($this->data) &amp;&amp;
    is_uploaded_file($this->data['Fileupload']['File']['tmp_name'])) {
      $fileData = fread(fopen($this->data['Fileupload']['File']['tmp_name'], "r"),
      $this->data['Fileupload']['File']['size']);

      $this->data['Fileupload']['name'] = $this->data['Fileupload']['File']['name'];
      $this->data['Fileupload']['type'] = $this->data['Fileupload']['File']['type'];
      $this->data['Fileupload']['size'] = $this->data['Fileupload']['File']['size'];
      $this->data['Fileupload']['data'] = $fileData;

      move_uploaded_file($this->data['Fileupload']['File']['tmp_name'], 'img/'.$this->data['Fileupload']['name']);
      $this->redirect('/fileupload');
    }
  }
}
?>

O.k. zum Controller noch ein paar Sätze: Über 'Fileupload' (da findet sich der Name unseres Formulars wieder) identifizieren wir das Formular und damit die Datei.
Mit move_uploaded_file verschieben wir die Datei in das Zielverzeichnis (hier das Bilder-Verzeichnis img).

Vielleicht hilft dem einen oder anderen das kleine Beispiel ein paar Minuten zu sparen.
Ciao Thomas
Benutzeravatar
havanna
 
Beiträge: 174
Registriert: Mi 15. Okt 2008, 23:12
Wohnort: Bodman-Ludwigshafen
CakePHP-Version: 1.2.x
OS: WIN

Re: Fileupload - eine Kleinigkeit

Beitragvon euromark am Di 24. Feb 2009, 15:51

was ist der sinn von
Code: Alles auswählen
$fileData = fread(fopen($this->data['Fileupload']['File']['tmp_name'], "r"),
      $this->data['Fileupload']['File']['size']);

?

man kann doch direkt verschieben - oder?
indem man $this->data['Fileupload']['File']['tmp_name'] verwendet...

auch die 3 zeilen sind überflüssig:
Code: Alles auswählen
      $this->data['Fileupload']['name'] = $this->data['Fileupload']['File']['name'];
      $this->data['Fileupload']['type'] = $this->data['Fileupload']['File']['type'];
      $this->data['Fileupload']['size'] = $this->data['Fileupload']['File']['size'];

wobei ich vermute dass du die 3 aus anschauungszwecken eingebaut hast
um zu zeigen wie man drauf zugreift - bzw wie man diese validieren könnte etc.

ansonsten sehr nett gemacht :)
euromark
 
Beiträge: 397
Registriert: Fr 27. Jun 2008, 22:17
Wohnort: München
CakePHP-Version: 1.2.4
OS: Windows

Re: Fileupload - eine Kleinigkeit

Beitragvon havanna am Di 24. Feb 2009, 21:55

Da hast du vollkommen Recht, Mark. Könnte man verwenden, um den Anwender zu zeigen "Datei mit 4711 kB wurde hochgeladen" oder um eine Validierung zu machen (wie ich sie mache) ob es sich um ein jpg handelt oder zu verhindern, das zu große Dateien hochgeladen werden.

Und $filedata verwende ich, um die Daten ggf. in einer Datenbank-Tabelle zu speichern.

Was in dem Beispiel nicht stimmt (und wo ich jetzt erst einmal nach 3 h aufgebe) ist die Validierung im Model. Die funktioniert nicht. Ich habe jetzt mehrere Sachen ausprobiert. Aber mir scheint, dass die Variable $validate im Model nicht ausgelesen wird, wenn "$useTable = false" ist.

Ciao Thomas
Benutzeravatar
havanna
 
Beiträge: 174
Registriert: Mi 15. Okt 2008, 23:12
Wohnort: Bodman-Ludwigshafen
CakePHP-Version: 1.2.x
OS: WIN

Re: Fileupload - eine Kleinigkeit

Beitragvon euromark am Di 24. Feb 2009, 23:57

verstehe..
Dazu macht es natürlich sinn :)

wobei ich damit noch recht wenig gemacht habe - auch der DB-Tabellen-Größe wegen.
ist halt für import/export bestimmt schöner, als das immer manuell mit einzelnen files machen zu müssen
die noch irgendwie auf der Platte in /files/ oder /webroot/ rumliegen etc
euromark
 
Beiträge: 397
Registriert: Fr 27. Jun 2008, 22:17
Wohnort: München
CakePHP-Version: 1.2.4
OS: Windows

Re: Fileupload - eine Kleinigkeit

Beitragvon Flo am Mi 25. Feb 2009, 10:32

habe damit zwar keiner Erfahrung, aber für solche Fälle sollte laut meinem Verständnis dashier gedacht sein.
http://api.cakephp.org/class/controller ... ervalidate
Flo
 
Beiträge: 67
Registriert: Mi 11. Jun 2008, 20:48
Wohnort: Bielefeld
CakePHP-Version: 1.3
OS: Mac OSX 10.6

Re: Fileupload - eine Kleinigkeit

Beitragvon Kratos am Mi 25. Feb 2009, 13:15

Servus Havanna!

Ich würde dir davon abraten die Daten in die DB zu speichern, den Die ist das schwächste Glied (bei guter Programmierung :D )und kann daraus schnell zum Flaschenhals werden. Bei der Validierung musst du aufjedenfall noch was machen, sonst ist es "AUS" mit deiner Applikation: Auf Dateiendungen, Größe & Content-Type prüfen; Anzahl der erlaubten Uploads pro User (Stichwort: Denial of Service); Speicherplatz idealerweise ausserhalb des Webroots oder zumindest über htaccess-Dateien vor direktem Zugriff schützen; Dateiname ändern (Nullbyte Character könnte eingefügt sein, das zu einer Remote Code Execution-Lücke führen würde) und hochgeladene Dateien nur an User mit den nötigen Zugriffsrechten ausliefern (falls möglich).
Kratos
 
Beiträge: 14
Registriert: So 18. Jan 2009, 01:56

Re: Fileupload - eine Kleinigkeit

Beitragvon havanna am Mi 25. Feb 2009, 15:34

@Flo: so ganz habe ich jetzt nicht verstanden, was du damit sagen wolltest. AppController ist ja von Controller abgeleitet und die "normale" Validierung (z.B. beim Kontaktformular) funktioniert bei mir auch bestens über die Feldprüfung im Model und die Prüfung im Controller. So habe ich bei meiner Suche z.B. herausgefunden, wird die Validierung autom. durchgeführt, wenn im Controller die Methode save aufgerufen wird. Beispiel:

Code: Alles auswählen
if($this->Post->save($this->data)) {
    // kein Fehler
} else {
    // Fehler
}


Wobei kein Fehler / Fehler aus der Validierungsregel im Model kommt.

Alternativ kann man wohl auch dies im Controller tun.
Code: Alles auswählen
if ($this->Post->validates()) {
         // tue was er will
      } else {
     // Fehlermeldung senden
}


Und dann gibt es wohl noch die Methode beforeVaildates, die man überdefinieren könnte.

Wenn ich mal Zeit und Lust habe, werde ich mich noch einmal zwei Stunden über das Thema hermachen - vielleicht findet sich die Lösung noch.

@Kratos: Es ging mir hier lediglich darum in wenigen Zeilen ein kleines deutssprachiges Tutorial zur Verfügung zu stellen. Natürlich mache ich in meinem Controller noch div. Prüfungen (habe ich ja auch geschrieben). Z.B. lasse ich nur Daten eines bestimmten Dateityps zu und bis zu einer bestimmten Dateigrösse.
Über das Thema der Datenhaltung binärer Daten in der DB kann man lange diskutieren. Es gibt Argumente die dafür sprechen und Argumente dagegen. Und ich habe auch gar keine Lust, an dieser Stelle eine solche Diskussion loszutreten. Ich arbeite seit über 10 Jahren beruflich mit SAP. Du wirst hier nie irgendwelche Daten in einem Filesystem finden - das liegt alles schön in einer Datenbank. Ich wollte mit dem Beispiel nur zeigen, wie man auf welche Daten unter Nutzung von Cakes Funktionen zugreifen kann.

Ciao Thomas
Benutzeravatar
havanna
 
Beiträge: 174
Registriert: Mi 15. Okt 2008, 23:12
Wohnort: Bodman-Ludwigshafen
CakePHP-Version: 1.2.x
OS: WIN

Re: Fileupload - eine Kleinigkeit

Beitragvon Kratos am Mi 25. Feb 2009, 22:10

Thomas, Thomas, Thomas!!!

havanna schrieb:
Könnte man verwenden, um den Anwender zu zeigen "Datei mit 4711 kB wurde hochgeladen" oder um eine Validierung zu machen (wie ich sie mache) ob es sich um ein jpg handelt oder zu verhindern, das zu große Dateien hochgeladen werden.


1). Naja, ob man das ausreichende Validierung nennen kann lass ich mal dahin gestellt sein. Wenn du hier schon ein Tutorial anbietest, dann richtig oder lass es sein. Hier gibt es auch Anfänger die wegen deinem sogenannten TUTORIAL auf deutsch Sch.... programmieren.

havanna schrieb:
Du wirst hier nie irgendwelche Daten in einem Filesystem finden - das liegt alles schön in einer Datenbank.

2). Daten in die DB zu schreiben ist auch nicht verkehrt. Aber binäre Daten ab einer gewissen Größe sollten nicht in der Datenbank zu finden sein(nur der Pfad zu Ihnen). Aber probiers ruhig aus!

Tipp fürs nächste Tutorial: Wenn du schon keine Lust hast professionell ausführliche Tutorials zu schreiben - damit auch Anfänger keine Sicherheitslücken programmieren- weisse wenigstens dezent auf Gefahren hin oder lass dir einen guten Rat geben wenn jemand (wie ich) helfen will.
Solche unprofessionellen Sachen gibt es schon viel zu viel im Internet.
Kratos
 
Beiträge: 14
Registriert: So 18. Jan 2009, 01:56


Zurück zu Tutorials und Snippets

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

cron