From 9b8d2f1fd16b3b71659cd5e9fc845bc56a33d41f Mon Sep 17 00:00:00 2001 From: Daniel Sheffield Date: Tue, 25 Jun 2024 13:00:45 +1200 Subject: [PATCH 1/7] #458 - allow user to set formenctype --- sqlpage/templates/form.handlebars | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sqlpage/templates/form.handlebars b/sqlpage/templates/form.handlebars index ebbe6c0f..47852aaa 100644 --- a/sqlpage/templates/form.handlebars +++ b/sqlpage/templates/form.handlebars @@ -2,6 +2,7 @@ {{#if id}}id="{{id}}"{{/if}} class="my-3 {{class}}" method="{{default method "post"}}" + {{#if formenctype}}formenctype="{{formenctype}}"{{/if}} {{#if action}}action="{{action}}" {{else}} {{#if id}}action="#{{id}}"{{/if}} @@ -118,7 +119,7 @@ {{/if}} {{/if}} - {{#if (eq type "file")}} + {{#if and (eq type "file") (not formenctype)}} {{#delay}}formenctype="multipart/form-data"{{/delay}} {{/if}} @@ -131,6 +132,7 @@ {{#if validate_outline}} btn-outline-{{validate_outline}} {{/if}} {{#if validate_size}} btn-{{validate_size}} {{/if}}" {{flush_delayed}} + {{#if formenctype}}formenctype="{{formenctype}}"{{/if}} type="submit" {{#if validate}}value="{{validate}}"{{/if}}> {{/if}} From e37b63b47db7a3c1e40a8fe8ad450c6b768778d4 Mon Sep 17 00:00:00 2001 From: Daniel Sheffield Date: Tue, 25 Jun 2024 13:07:58 +1200 Subject: [PATCH 2/7] just set on each component --- sqlpage/templates/form.handlebars | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlpage/templates/form.handlebars b/sqlpage/templates/form.handlebars index 47852aaa..60c141b1 100644 --- a/sqlpage/templates/form.handlebars +++ b/sqlpage/templates/form.handlebars @@ -2,7 +2,6 @@ {{#if id}}id="{{id}}"{{/if}} class="my-3 {{class}}" method="{{default method "post"}}" - {{#if formenctype}}formenctype="{{formenctype}}"{{/if}} {{#if action}}action="{{action}}" {{else}} {{#if id}}action="#{{id}}"{{/if}} @@ -54,6 +53,7 @@ {{~#if minlength}}minlength="{{minlength}}" {{/if~}} {{~#if maxlength}}maxlength="{{maxlength}}" {{/if~}} {{~#if required}}required="required" {{/if~}} + {{~#if formenctype}}formenctype="{{formenctype}}" {{/if~}} {{~#if autofocus}}autofocus {{/if~}} > {{~#if value}}{{value}}{{/if~}} @@ -62,6 +62,7 @@ {{#delay}}formenctype="multipart/form-data"{{/delay}} + {{else}} + {{#if (and formenctype (eq type "textarea"))}} + {{#delay}} formenctype="{{formenctype}}"{{/delay}} + {{/if}} {{/if}} {{/each_row}} From 7492e2f7f471f3decc8c3f08de1c8a619ce07b47 Mon Sep 17 00:00:00 2001 From: Daniel Sheffield Date: Wed, 26 Jun 2024 10:47:22 +1200 Subject: [PATCH 5/7] update docs and add caution on formenctype behaviour for file type input --- .../official-site/examples/handle_enctype.sql | 9 +++ .../sqlpage/migrations/01_documentation.sql | 72 ++++++++++++++++++- sqlpage/templates/form.handlebars | 9 +-- 3 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 examples/official-site/examples/handle_enctype.sql diff --git a/examples/official-site/examples/handle_enctype.sql b/examples/official-site/examples/handle_enctype.sql new file mode 100644 index 00000000..72795fc1 --- /dev/null +++ b/examples/official-site/examples/handle_enctype.sql @@ -0,0 +1,9 @@ +SET ":enctype" = CASE :percent_encoded IS NOT NULL OR :multipart_form_data IS NOT NULL + WHEN TRUE THEN 'with ``' || COALESCE(:percent_encoded, :multipart_form_data) || '``' + ELSE 'form' +END ||' encoding type' +SELECT 'text' AS component; +SELECT 'The following data was submitted '||:enctype||': +``` +' || :data ||' +```' AS contents_md; \ No newline at end of file diff --git a/examples/official-site/sqlpage/migrations/01_documentation.sql b/examples/official-site/sqlpage/migrations/01_documentation.sql index 937a9e0e..a95f23eb 100644 --- a/examples/official-site/sqlpage/migrations/01_documentation.sql +++ b/examples/official-site/sqlpage/migrations/01_documentation.sql @@ -211,7 +211,23 @@ INSERT INTO component(name, icon, description) VALUES 'The value entered by the user in a field named x will be accessible to the target SQL page as a variable named $x. For instance, you can create a SQL page named "create_user.sql" that would contain "INSERT INTO users(name) VALUES($name)" and a form with its action property set to "create_user.sql" that would contain a field named "name".'); +INSERT INTO parameter(component, name, description_md, type, top_level, optional) SELECT 'form', * FROM (VALUES + -- top level + ('enctype', ' +When ``method="post"``, this specifies how the form-data should be encoded +when submitting it to the server. +', 'TEXT', TRUE, TRUE), + -- item level + ('formenctype', ' +When ``type`` is ``submit`` or ``image``, this specifies how the form-data +should be encoded when submitting it to the server. +Takes precedence over any ``enctype`` set on the ``form`` element. + +NOTE: when a ``file`` type input is present, then ``formenctype="multipart/form-data"`` +is automatically applied to the default validate button. +', 'TEXT', FALSE, TRUE) +); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'form', * FROM (VALUES -- top level ('method', 'Set this to ''GET'' to pass the form contents directly as URL parameters. If the user enters a value v in a field named x, submitting the form will load target.sql?x=v. If target.sql contains SELECT $x, it will display the value v.', 'TEXT', TRUE, TRUE), @@ -401,6 +417,15 @@ But note that SQLPage cookies already have the `SameSite=strict` attribute by de ## File upload You can use the `file` type to allow the user to upload a file. + +> NOTE: It is recommended to use ``multipart/form-data`` to encode the from +data for file uploads. This is because the default encoding +(``application/x-www-form-urlencoded``) applied to arbitrary binary can be up +to 3 times the size of the file. +For now, ``formenctype="multipart/form-data"`` is automatically applied to the +default validate button - but this may change in the future. + + The file will be uploaded to the server, and you will be able to access it using the [`sqlpage.uploaded_file_path`](functions.sql?function=uploaded_file_path#function) function. @@ -410,10 +435,55 @@ Here is how you could save the uploaded file to a table in the database: INSERT INTO uploaded_file(name, data) VALUES(:filename, sqlpage.uploaded_file_data_url(:filename)) ``` ', - json('[{"component":"form", "title": "Upload a picture", "validate": "Upload", "action": "examples/handle_picture_upload.sql"}, + json('[{"component":"form", "enctype": "multipart/form-data", "title": "Upload a picture", "validate": "Upload", "action": "examples/handle_picture_upload.sql"}, {"name": "my_file", "type": "file", "accept": "image/png, image/jpeg", "label": "Picture", "description": "Upload a small picture", "required": true} ]')), ('form', ' +## Form Encoding + +You can specify the way form data should be encoded by setting the `enctype` +top-level property on the form. + +You may also specify `formenctype` on `submit` and `image` type inputs. +This will take precedence over the `enctype` specified on the form and is +useful in the case there are multiple `submit` buttons on the form. +For example, an external site may have specific requirements on encoding type. + +As a rule of thumb, ``multipart/form-data`` is best when fields may contain +copious non-ascii characters or for binary data such as an image or a file. +However, ``application/x-www-form-urlencoded`` creates less overhead when +many short ascii text values are submitted. +', + json('[ + { + "component": "form", + "method": "post", + "enctype": "multipart/form-data", + "title": "Submit with different encoding types", + "validate": "Submit with form encoding type", + "action": "examples/handle_enctype.sql" + }, + {"name": "data", "type": "text", "label": "Data", "required": true}, + { + "name": "percent_encoded", + "type": "submit", + "label": "Submit as", + "width": 4, + "formaction": "examples/handle_enctype.sql", + "formenctype": "application/x-www-form-urlencoded", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "multipart_form_data", + "type": "submit", + "label": "Submit as", + "width": 4, + "formaction": "examples/handle_enctype.sql", + "formenctype": "multipart/form-data", + "value": "multipart/form-data" + } +]')), + ('form', ' ## Bulk data insertion You can use the `file` type to allow the user to upload a [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) diff --git a/sqlpage/templates/form.handlebars b/sqlpage/templates/form.handlebars index 43633ff6..50e3387f 100644 --- a/sqlpage/templates/form.handlebars +++ b/sqlpage/templates/form.handlebars @@ -2,6 +2,7 @@ {{#if id}}id="{{id}}"{{/if}} class="my-3 {{class}}" method="{{default method "post"}}" + {{#if enctype}}enctype="{{enctype}}"{{/if}} {{#if action}}action="{{action}}" {{else}} {{#if id}}action="#{{id}}"{{/if}} @@ -118,13 +119,9 @@ {{/if}} {{/if}} - {{#if (eq type "file")}} - + {{#if eq type "file"}} + {{#delay}}formenctype="multipart/form-data"{{/delay}} - {{else}} - {{#if (and formenctype (eq type "textarea"))}} - {{#delay}} formenctype="{{formenctype}}"{{/delay}} - {{/if}} {{/if}} {{/each_row}} From 20eec0a6f64ad19b326788423b0795c620e48dc1 Mon Sep 17 00:00:00 2001 From: Daniel Sheffield Date: Thu, 27 Jun 2024 08:52:58 +1200 Subject: [PATCH 6/7] Update 01_documentation.sql - remove predictions about the future --- .../official-site/sqlpage/migrations/01_documentation.sql | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/01_documentation.sql b/examples/official-site/sqlpage/migrations/01_documentation.sql index a95f23eb..a1ffae67 100644 --- a/examples/official-site/sqlpage/migrations/01_documentation.sql +++ b/examples/official-site/sqlpage/migrations/01_documentation.sql @@ -418,14 +418,6 @@ But note that SQLPage cookies already have the `SameSite=strict` attribute by de You can use the `file` type to allow the user to upload a file. -> NOTE: It is recommended to use ``multipart/form-data`` to encode the from -data for file uploads. This is because the default encoding -(``application/x-www-form-urlencoded``) applied to arbitrary binary can be up -to 3 times the size of the file. -For now, ``formenctype="multipart/form-data"`` is automatically applied to the -default validate button - but this may change in the future. - - The file will be uploaded to the server, and you will be able to access it using the [`sqlpage.uploaded_file_path`](functions.sql?function=uploaded_file_path#function) function. From 96636f2ff589e40ce028aad4667afcb95e30e28c Mon Sep 17 00:00:00 2001 From: Daniel Sheffield Date: Thu, 27 Jun 2024 11:55:25 +1200 Subject: [PATCH 7/7] Update form.handlebars Revert accidental change --- sqlpage/templates/form.handlebars | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlpage/templates/form.handlebars b/sqlpage/templates/form.handlebars index 50e3387f..896c76d5 100644 --- a/sqlpage/templates/form.handlebars +++ b/sqlpage/templates/form.handlebars @@ -119,8 +119,8 @@ {{/if}} {{/if}} - {{#if eq type "file"}} - + {{#if (eq type "file")}} + {{#delay}}formenctype="multipart/form-data"{{/delay}} {{/if}} {{/each_row}}