Search

I have never known how to do this.

I need to preserve an existing file upload on an edit form, so I am passing the file path + name as the value of the upload field.

This always fails validation stating that the file is required.

<input name="fields[logo]" id="fields-logo" class="is-invalid is-required" type="file" value="/uploads/promoters/avatar-53f3529bda39c.jpg"/>

Has anyone got a way of doing this?

Shouldn't the type be hidden? or added as a hidden value/variable?

There is no 'value' attribute attached to a 'file' type so we need to pass a hidden input type with the value of the file uploaded after the input type file I think.

If there is no file returned from Datasource we show the input field if not, we show a span representation of the uploaded file similar to how the Symphony backend displays the upload field type.

Well, this is the problem...

I discovered that the field value needs to be root relative, so starting at /workspace..., but this still causes a problem.

If I try and add a hidden field too, I get Symphony errors from the General::getPostData function.

This shouldn't be that complicated to do IMO.

It seems, looking at the backend, that I have to have 'either' a hidden field, or a file field, but not both.

How then am I supposed to allow a user to replace an existing image without using javascript? I shouldn't have to rely on that or customise an event to do something so simple as this.

I think it's done this way for security purposes on all html forms with type of input set to file.

What does this markup do?

   <input type='hidden' name='fields[upload]' value='{blah}' />
   <input type='file' name="fields[upload]' />

I believe that it will ignore the previous key and pass through the new file (if the user adds one), or nothing, will will probably cause Symphony to remove the old file.

The scenario is then, if something is omitted, did you want to delete it, or did you want to keep the existing one?

That would have to be solved some other way, maybe doing something like the password fields.

   <input type='hidden' name='fields[upload][method]' value='{preserve|remove}' />
   <input type='file' name="fields[upload]' />

Having said that, you still might want some Javascript to change that field value depending on if the user hits 'remove file' or not.

Any other ideas?

Hey Brendan,

That's the markup I tried, but the General::getPostData throws a wobbly fatal error at that. If you're expecting that markup to work, and so am I, then I will log this as a bug.

I will be using JS to do things with this site, but it has to function without it for sanity's sake.

I am not sure if I understand your issue correctly. Is keeping an uploaded file on a subsequent form transmission all that you need? In this case you could simply not pass the field with your POST request.

Yes, I know that.

I need to keep the file, and offer the opportunity to replace it by uploading another one.

Ah, I see. I worked around that by showing a preview of the uploaded file accompanied by a link "replace this file". If the user clicks the link, the page will be reloaded with a query parameter appended to the URL. This param is used in XSLT to switch from "preview mode" to "upload field mode".

That's an interesting approach.

Well, it's a bit more complicated in practice (of course). You may also have to check if there already is a value in your datasource. If you don't have a value or the "special URL param" is set, you render the file input. And, to make it work with mutliple files, the GET param also needs a usable value (which is the ID of the field, in my case):

<xsl:choose>
    <xsl:when test="not(/data/.../filename) or /data/params/url-reset-file = $id">
        … (render input, type=file)
    </xsl:when>
    <xsl:otherwise>
        … (show preview)
    </xsl:otherwise>
</xsl:choose>

That's such a neat approach Michael-e, thanks for sharing.

Hadn't thought about the functionality without JS until recently on a Govt project where JS is switched off for their machines internally so this helps overcome any sticking points with uploads here for sure.

I have a problem with my approach. When saving, while keeping the existing file, I get an error:

Symphony Warning: Illegal string offset 'name'
An error occurred in .../symphony/lib/toolkit/class.general.php around line 708
    704
    705 if (is_array($value)) {
    706 merge_file_post_data($type, $value, $post[$key]);
    707 } else {
    708 $post[$key][$type] = $value;
    709 }

This is what I use:

<xsl:choose>
    <xsl:when test="avatar">
        <img src="{$root}/image/avatar{avatar/@path}/{avatar/filename}" alt="name" />
        <input type="file" name="fields[avatar]" />
        <select name="fields[avatar]">
            <option value="{avatar/@path}/{avatar/filename}" selected="selected">Keep existing</option>
            <option value="">Remove or upload new</option>
        </select>
    </xsl:when>
    <xsl:otherwise>
        <input type="file" name="fields[avatar]" />
    </xsl:otherwise>
</xsl:choose>

No errors when selecting the option to remove or upload a new file.

I use this approach on a live server with Symphony 2.4 without errors, while I get the error above on my computer. I got it with 2.4, updated to 2.5.1 but still the same.

Do you think it could depend on the PHP version? I have 5.3.10 on the server, while 5.5.9 on my computer. I can't spot any other problem... Maybe you can see something I did wrong!

Thanks

I couldn't figure this out. Must be an issue with PHP > 5.4. If you have any suggestions, I will test, though I've pretty much tried everything with the position and type of fields.

The closest to what I'm trying to do I can think of is to change the input field type to hidden, in which case, if the first option is selected, the value will be passed:

<input type="hidden" name="fields[avatar]" />
<select name="fields[avatar]">
    <option value="{avatar/@path}/{avatar/filename}" selected="selected">Keep existing</option>
    <option value="">Remove or upload new</option>
</select>

No value is passed if the input field is after the select field (the existing file is kept).

And when the other option is selected ("remove or upload new"), I need to use javascript to change the input field type to file. I really wanted to avoid JS!

Why not prefill the default value for the input with the path from the existing avatar?

<input type="file" value="{avatar/@path}/{avatar/filename}">

Because the error above is thrown, and also to allow the file to be removed or replaced.

If the input type is hidden, even without value, the value from the select's first option (if selected) is passed and the file is preserved. If second option is selected, nothing is passed at all and the file is also preserved (but it shouldn't, as it's passing an empty value for the field).

Isn't it because you like a type=hidden input field to behave as a type=file input. What happens when the input is not hidden but from the type file?

@ellie, passing an empty value should indeed work (if it's really a field with a unique name that is sent by the browser).

Can you try and log the request data in the browser's debugger? Should be possible with Firefox, for example, using the Console Tab of the debugger, setting it to show request and response data, then performing the POST request. Then you can click on the POST request and see the data in a pop-up window.

Please search for your file field name in the response. You should find something like:

Content-Disposition: form-data; name="fields[file]"; filename="" Content-Type: application/octet-stream

Anything else? Does the field occur only once?

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details