AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke TRestClient UploadFile vs PHP
Thema durchsuchen
Ansicht
Themen-Optionen

TRestClient UploadFile vs PHP

Ein Thema von gmc616 · begonnen am 9. Feb 2022 · letzter Beitrag vom 11. Feb 2022
Antwort Antwort
Seite 1 von 2  1 2      
gmc616

Registriert seit: 25. Jun 2004
Ort: Jena
627 Beiträge
 
Delphi 10.3 Rio
 
#1

TRestClient UploadFile vs PHP

  Alt 9. Feb 2022, 21:34
Hallo Delphi-Praxis,
Ich versuche mittels TRestClient einen Datei an einen REST-API-Server zu senden.
Der Server basiert auf PHP.

Ich habe ein Stück JavaScript aus einer HTML-Seite, welches gegen diesen Server funktioniert.
Code:
async function UploadFile(){
    var version = document.getElementById("version").value;
    var file = document.getElementById("files").files;      
    var dateiID = document.getElementById("uploadid").value;

    filename = file[0]["name"];

    let formData = new FormData();
    formData.append("file", file[0], filename);

    let data = await fetch('http://myServer.tld/API.php?action=uploadfile&iddatei='+dateiID+'&version='+version+'&filename='+filename, {  method: 'POST', body: formData });
}
Auf Server-Seite wird im PHP die $_FILES-Variable ausgewertet.
Rufe ich die API über dieses Script/HTML-Seite, kommt mein File beim Server an, d.h. $_FILE ist belegt.

Nun versuche ich das Ganze auf Delphi zu übersetzen, aber egal was ich anstelle, $_FILES bleibt "empty".

Wie muss ich die letzten 3..4 Zeile übersetzen, damit auch per Delphi die Datei "drüben" ankommt?
Leider bin ich mittlerweile seit ca. 15 Jahren raus aus JavaScript und PHP.

Ich hoffe ihr könnt mir wieder mal auf die Sprünge helfen...
Danke.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.445 Beiträge
 
Delphi 12 Athens
 
#2

AW: TRestClient UploadFile vs PHP

  Alt 9. Feb 2022, 22:42
Zeig doch mal was du schon hast.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
gmc616

Registriert seit: 25. Jun 2004
Ort: Jena
627 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: TRestClient UploadFile vs PHP

  Alt 10. Feb 2022, 00:48
Hallo Uwe.

Meine aktuelle Bastel-Funktion:
Delphi-Quellcode:
constructor TccRestAPI.Create(ABaseUrl:string='');
begin
  FbIsUserLoggedIn := FALSE;
  SetBaseUrl ( ABaseUrl );
  FToken := '';

  FRESTClient := TRESTClient.Create(FBaseUrl);
  FRESTRequest := TRESTRequest.Create(nil);
  FRESTResponse := TRESTResponse.Create(nil);
  FFDMemTable := TFDMemTable.Create(nil);
  FDataSource := TDataSource.Create(Nil);

  FRESTResponseDataSetAdapter := TRESTResponseDataSetAdapter.Create(nil);
  FLOAuth2 := NIL;

  FRESTRequest.Client := FRESTClient;
  FRESTRequest.Response := FRESTResponse;

  FRESTResponseDataSetAdapter.Dataset := FFDMemTable;
  FRESTResponseDataSetAdapter.Response := FRESTResponse;

  FDataSource.DataSet := FFDMemTable;

end;

function TccRestAPI.UploadFile(AFunction, ASourceFileName: string): boolean;
var
  fileStream : TFileStream;
  js : TJsonObject;
  sSaveContentType : string;
  sSaveAccept : string;
begin
  Result := FALSE;
  DoNotifyExecute (AFunction); // fürs logging

  sSaveContentType := FRESTClient.ContentType; // merken ... später zurücksetzen
  sSaveAccept := FRESTRequest.Accept; // merken ... später zurücksetzen

  Request.Params.Clear;
  Request.Body.ClearBody;
// FRESTClient.ContentType:= 'application/x-www-form-urlencoded';
  FRESTClient.ContentType:= 'multipart/form-data';
  FRESTRequest.Accept:= '*/*';
  fileStream := TFileStream.Create(ASourceFileName,fmOpenRead);

  FRESTRequest.AddParameter('additionalMetadata', 'file', TRESTRequestParameterKind.pkREQUESTBODY);
  FRESTRequest.Params.AddItem('file', fileStream, TRESTRequestParameterKind.pkREQUESTBODY,
      [TRESTRequestParameterOption.poDoNotEncode],
      TRESTContentType.ctAPPLICATION_OCTET_STREAM);


// fileStream := TFileStream.Create(ASourceFileName, fmOpenRead or fmShareDenyNone);
// Request.AddBody(fileStream,ctAPPLICATION_OCTET_STREAM);


// Request.AddFile('file',ASourceFileName); // kommt nicht an ...

  if self.Execute(AFunction,js,TRESTRequestMethod.rmPost) then
  begin
    js.DisposeOf;
    Result := TRUE;
  end;
  FRESTClient.ContentType:= sSaveContentType; // zurücksetzen
  FRESTRequest.Accept:= sSaveAccept; // zurücksetzen
  fileStream.Free;

end;
Wie gesagt, ich habe schon eine Menge probiert, und mittlerweile irgendwie aufgegeben (ist ein "NiceToHave"). Deswegen steht in diesem Snippet nicht alles drin...

Was ich nicht verstehe, ist im JavaScript der verwendete Code:
Code:
let formData = new FormData();
    formData.append("file", file[0], filename);
Ich finde kein Equivalent dafür im Delphi.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.445 Beiträge
 
Delphi 12 Athens
 
#4

AW: TRestClient UploadFile vs PHP

  Alt 10. Feb 2022, 10:45
Der Code ist etwas verworren. Mal heißt es Request, dann wieder FRESTRequest. Offenbar fehlen auch einige wesentliche Dinge, dafür sind andere überflüssig.

Die Zuweisung an FRESTClient.ContentType:= 'multipart/form-data'; ist überflüssig. Das TCustomRESTRequest.Execute setzt diesen Wert automatisch anhand der vorhandenen Parameter und deren ContentType.

Als straight forward würde ich das erstmal so versuchen (der Code bildet im Prinzip das JavaScript ab):
Delphi-Quellcode:
  client := TRESTClient.Create('http://myServer.tld/API.php');
  try
    request := TRESTRequest.Create(client); // spart das try-finally-Free
    request.Client := client;
    request.Method := rmPOST;
    request.AddParameter('action', 'uploadfile', pkQUERY);
    request.AddParameter('iddatei', dateiID, pkQUERY);
    request.AddParameter('version', version, pkQUERY);
    request.AddParameter('filename', filename, pkQUERY);
    request.AddFile(filename); // setzt implizit ctMULTIPART_FORM_DATA
    request.Execute;
    if request.Response.Status.Success then begin
      { hat geklappt }
    end
    else begin
      { hat nicht geklappt }
    end;
  finally
    client.Free;
  end;
Wenn das nicht funktioniert müsste man mal die genaue Spezifikation vom Server studieren.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
gmc616

Registriert seit: 25. Jun 2004
Ort: Jena
627 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: TRestClient UploadFile vs PHP

  Alt 11. Feb 2022, 15:31
Hallo Uwe.
Ja, der Code ist verworren. Wie gesagt, ist quasi ein Bastel-Code, mit dem ich schon ne Menge rumprobiert habe.

Ich habe deinen Code jetzt entsprechend eingebaut, funktioniert leider auch nicht.
Die ersten Zeilen habe ich allerdings ausgetauscht, da der Upload (ähnlich wie hier, auch per TOAuth2Authenticator) funktionieren soll.
Delphi-Quellcode:
  
  {...}
  FRESTClient.BaseURL := 'http://myServer.tld/API.php';
  try
    request := TRESTRequest.Create(FRESTClient); // spart das try-finally-Free
    request.Client := FRESTClient;
    request.Method := rmPOST;
  {...}
Alle Parameter kommen Server-seitig an. Auch der volle Dateiname.
Nur ist das PHP-seitige $_FILES immernoch leer.
request.Response.Status.Success ist TRUE, war aber zu erwarten, wenn ich dem Server-seitigen Entwickler glauben darf.

Ich glaube auf diese Art hatte ich es auch schon probiert.
Damals hatte ich Fiddler mitlaufen lassen, um herauszufinden, was unterschiedlich ist, in dem was Delphi und das Javascript an den Server sendet.
Ich habe die Request-Header vergleichen, die waren nahezu identisch, zumindest in dem was ich für wichtig halte. In den Raw-Daten konnte ich auch meine Datei "sehen".
Die Datei geht also rüber zum Server. Auch beim Debuggen merkt man an der kurzen Verzögerung, dass da richtig was passiert.
Aber der Server scheint die Datei nicht entgegen zu nehmen. ... per JavaScript gehts

OT:
Blöder weise entwickelt sich diese Bastel-Funktion mittler Weile von einem "NiceToHave" zu einem "MustHave".
Ich habe gestern eine Anfrage bekommen, ob ich mittels REST-API XML-Daten austauschen kann.

"Na klar kann ich das ..."
Leider ist aus der Doku nicht erkennbar, ob der Server XML-Daten oder XML-Dateien erwartet. Die Doku spricht von Dateien, zeigt aber nur XML-Daten. Aber das kommt später.
Das ganze läuft dort über eine Basic Authentication, die in meinem Code schon weitestgehend funktioniert und ich deswegen den Upload (und den Download) an meinen vorhanden FRESTClient gebunden haben möchte, sollte das Ganze tatsächlich über XML-Dateien laufen sollen.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.445 Beiträge
 
Delphi 12 Athens
 
#6

AW: TRestClient UploadFile vs PHP

  Alt 11. Feb 2022, 16:17
Damals hatte ich Fiddler mitlaufen lassen, um herauszufinden, was unterschiedlich ist, in dem was Delphi und das Javascript an den Server sendet.
Ich habe die Request-Header vergleichen, die waren nahezu identisch, zumindest in dem was ich für wichtig halte.
Kannst du das nochmal machen und mir die entsprechenden Protokolle zukommen lassen?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
gmc616

Registriert seit: 25. Jun 2004
Ort: Jena
627 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: TRestClient UploadFile vs PHP

  Alt 11. Feb 2022, 17:49
Delphi, mit dem aktuelle Code von oben.
Code:
POST http://myServer.tld/API.php?action=uploadfile&iddatei=3048&version=1.0.0.5&filename=1466060264095.jpg HTTP/1.1
Connection: Keep-Alive
Content-Type: multipart/form-data; boundary=-------Embt-Boundary--7C912B623C4CE4EF
Accept: application/json, text/plain; q=0.9, text/html;q=0.8,
Accept-Charset: utf-8, *;q=0.8
User-Agent: Embarcadero RESTClient/1.0
Content-Length: 915233
Host: myServer.tld

-----------Embt-Boundary--7C912B623C4CE4EF
Content-Disposition: form-data; name="file"; filename="1466060264095.jpg"
Content-Type: image/jpeg

�����JFIF

{ ... das JPG, wird hier im Forum umcodiert ... }

---------Embt-Boundary--7C912B623C4CE4EF--
JavaScript
Code:
POST http://myServer.tld/API.php?action=uploadfile&iddatei=3048&version=1.0.0.1&filename=1466060264095.jpg HTTP/1.1
Host: myServer.tld
Connection: keep-alive
Content-Length: 915231
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7v1duMCECzltfN0g
Accept: */*
Origin: null
Accept-Encoding: gzip, deflate
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7

------WebKitFormBoundary7v1duMCECzltfN0g
Content-Disposition: form-data; name="file"; filename="1466060264095.jpg"
Content-Type: image/jpeg

�����JFIF

{... das gleiche JPG ...}
------WebKitFormBoundary7v1duMCECzltfN0g--
Ich sehe grad, dass die "version" ist der POST-URL unterschiedlich sind, das ist aber nicht der ausschlaggebende Punkt.

Geändert von gmc616 (11. Feb 2022 um 17:55 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#8

AW: TRestClient UploadFile vs PHP

  Alt 11. Feb 2022, 17:51
Da in dem Javascript für den Feldnamen des "Dateifeldes" explizit "file" angegeben ist, würde ich mal folgende Zeile anpassen:

request.AddFile('file', filename);
Edit: Sieht aber so aus, als ob er bei beiden schon Name="file" setzt...

Geändert von Olli73 (11. Feb 2022 um 17:57 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.445 Beiträge
 
Delphi 12 Athens
 
#9

AW: TRestClient UploadFile vs PHP

  Alt 11. Feb 2022, 18:14
Als erstes fällt der Unterschied im version-Parameter auf. Aber das hast du ja schon geklärt.

Die Differenz bei der Content-Length liegt an der unterschiedlichen Länge der ersten Boundary. Keine Ahnung ob das relevant ist.

Die Unterschiede in den verschiedenen Accept-Headern sollten nicht relevant sein, da es dabei nur um die Antwort geht. Im Zweifel kannst du die ja auch mal entsprechend belegen.

Den User-Agent kannst du ja auch mal probeweise anpassen.

Ansonsten: Mit PHP habe ich nicht so wirklich was am Hut. Da kann ich nicht weiter helfen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
gmc616

Registriert seit: 25. Jun 2004
Ort: Jena
627 Beiträge
 
Delphi 10.3 Rio
 
#10

AW: TRestClient UploadFile vs PHP

  Alt 11. Feb 2022, 18:46
Wie gesagt: Auch für mich sehen die Request-Header quasi identisch aus.
Deswegen auch der verworrene Bastel-Code im #3.

Also könnte man sagen: Der Fehler ist eher auf der Server-Seite zu suchen?

Mit PHP habe ich auch schon seit PHP-4 nichts mehr am Hut.
Hatte damals mit der Umstellung von PHP-3 auf PHP-4 auf einem Gentoo-Linux ausreichend Probleme, um der ganzen Geschichte Adieu zu sagen^^

Aber ist mein Ansatz, mein Gedanke, in #5 korrekt? Macht man das so?
Oder fällt mir das Ganze wieder auf die Füße, wenn mir irgendwann eine neue Authentication-Methode über den Weg läuft?

Uwe, ich danke Dir trotzdem für dein Bemühen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:36 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz