JSFormData question

Here's some code I found for TFile.Upload in WEBLib.WebCtrls.pas #3748:

procedure TFile.Upload(AAction: string);
var
  f: TJSHTMLFile;
  fd: TJSFormData;
  ptrProgress, ptrComplete, ptrError, ptrAbort: pointer;
begin
  f := FileObject;

  fd := TJSFormData.new;
  fd.Append('file1',f);

  FReq := TJSXMLHttpRequest.new;

  . . . event handler assignments . . .

  FReq.Open('POST',AAction, true);
  FReq.Send(fd);
end;

For the line in the middle, fd.Append('file1',f); how does one find the name of the header var this is being assigned to?

And on the server side, what would a PHP script use to refer to it?

I'm doing this in my PHP script to extract the data from the Append call and save it to a file; it's not working properly, and I'm not sure why. The thing I'm most unclear about is whether the attachment is found using $_FILES['file1'] or some other header variable. The interface unit in WEB Core (web.pas #4028) shows the Append method interfaces, but not the implementation. That's as far down this rabbit hole I know how to go.

$fn = $destinationFolder . $_GET['filename'];
$data = base64_decode($_FILES['file1']);   <-------
$file = fopen($fn, 'w');
fwrite($file, $data);
fclose($file);

My web console debugger shows this:

image

How do I extract this on the server side in PHP?

And ... is there actually anything there?

How would that be written in both PHP and Python so it works?

I have no PHP knowledge.
There is a sample for uploading that has the client part and the server part under
Demo\Basics\Upload

I had ChatGPT write that PHP routine for me. I tweaked it a little bit, and it has worked perfectly for THttpClient in VCL ever since.

Sending the same file using TFile.Upload with the same parameters, sent to the same script is not working.

What does that suggest to you?

This is definitely happening on the client side.

It does not appear to be injecting the upload file between the boundary tag lines in the UL packet header.

I have not determined the problem yet, but the Demo app is not calling any of the GetFileAs... methods. It seems to be leaving it to the default. What is that, exactly?

BTW, the intended host environment is running Linux, so PHP or Python is preferred over a Delphi solution. They'd also be much shorter code.

Your question was followed up via direct email.

Well, I said the documentation was incomplete.

And then ... I discovered this. It's not described in the manual, and isn't even obvious from the sample Demo code -- at least, not to me.

$_FILES
array(1) {
  ["file1"]=>
  array(6) {
    ["name"]=>
    string(21) "money-Intro-tune1.mp3"
    ["full_path"]=>
    string(21) "money-Intro-tune1.mp3"
    ["type"]=>
    string(10) "audio/mpeg"
    ["tmp_name"]=>
    string(14) "/tmp/phpsBiChj"
    ["error"]=>
    int(0)
    ["size"]=>
    int(66247)
  }
}

It's sending a JSON request that's an array of elements containing file details, that each contain six elements.

It's what I meant by saying the documentation is incomplete.

This required dumping all of the server's session vars (in PHP) to identify what was actually sent. This is what was in the $_FILES session var.

It also looks like these parameters don't need to be sent as querystring args.

It's easy to extract this in PHP or Python or pretty much any scripting language, but you need to know what's there first -- what you're expecting to get.

(Shout-out to @AndrewSimard for the idea and code to see this!)

Please bear in mind that this is stuff on the PHP side of things, and this isn't a PHP support forum :laughing:

I disagree.

The code on the CLIENT side is sending a JSON packet with a specific definition.

It's basically sending a database record.

If you're looking for things sent as querystring args and not finding other details, and you don't know they're hiding inside of a JSON object, that's not very helpful.

You'd have the same problem in Python or any other server-side language. If you don't know you're receiving a structured data object that happens to be a JSON object, you're not going to have a lot of luck ingesting the data.

The Demo code uses Delphi on the server side, as well as the Indy library. There's nothing anywhere that suggests there's a JSON packet, that there are six fields in it, or what their names are.

In fact, there are fields full_path and error that aren't even used, but might be at some point. I put a var on the querystring to indicate the folder I want the file to go into.

The doc refers to Name (aka name), MimeType (aka type), and Size (aka size).

It also mentions Modified, which isn't there, but full_path and error ARE there. Actually, the full_path value would be very handy to have, or something to suggest any subfolder that the file might go into.

But access to this JSON packet is competely hidden and inaccessible to the sending code. And to be clear, it IS being created on the SENDER'S SIDE. The recipient on the Server's side can't do anything unless / until it gets that JSON packet and parses it to extract the relevant fields and data from it.

It is not a JSON packet, it is multipart-formdata.

We give an example in Delphi code. We target Delphi users. We do not do PHP development our selves and have no plans to do PHP development.

This is my final answer on this thread.

David - have you seen this one ? There is a PHP-Script for uploading files from WebCore to PHP/Server...

PHP upload handler on linux - WEB / TMS Web Core VSC - TMS Support Center (tmssoftware.com)

1 Like

YAY! I finally got the correct incantation needed to get this to work in a PHP script! (With the help of @AndrewSimard and the above script that mostly confirmed things.)

<?php

// a lot of safety and security checks go here, along with the folder:

$destinationFolder = 'dest/folder/goes/here/';

$data = file_get_contents( $_FILES['file1']['tmp_name'] );
$fn   = $destinationFolder . $_FILES['file1']['name'];
$file = fopen($fn, 'w');
fwrite($file, $data);
fclose($file);

http_response_code(200);
echo 'File ' . $_FILES['file1']['name'] . ' uploaded to: ' . $fn;

?>