2

I'm getting some very strange behaviour from a file input element in both Chrome and Opera (possibly more, haven't tested).

I have the following HTML:

<div id="profileImgContainer" class="formFile">
    <label>Profile Picture</label><div>
        <input type="text" id="profileImgText"><input type="button" value="Choose File" id="profileImgButton">
    </div>
    <input type="file" id="profileImg" name="profileImg">
</div>

And the following jQuery to get the file input's value and put it in the (visible) textbox. The actual file input is hidden.

$(".formFile input[type='file']").live('change', function()
{
    $(this).parents(".formFile").find("input[type='text']").val($(this).val());
});

I've made a JSFiddle for you try out. In Firefox, the text box happily takes the filename (don't care about the path) of the file element. In Chrome and Opera, however, when a file is selected the file path in the visible text box changes to C:\fakepath\[filename] where [filename] is the name of the file chosen. This path is obviously fake but what I want to know is why it's changed to it, and whether the file in the hidden upload element will still upload fine. I'm guessing it's a security feature, but I may be wrong.

Bojangles
  • 99,427
  • 50
  • 170
  • 208

2 Answers2

3

This is one attempt to mitigate the security issues you get from allowing arbitrary foreign code to run in your browser: The script (which we assume could come from a malicious attacker) does not get to see (and possibly communicate back via AJAX) information about your local files.

Imagine what could happen if a script could just freely set file uploads and submit forms.

This behaviour concerning file upload controls and scripting is mandated by some sort of standard (I believe part of the DOM specification) for this very reason.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thanks for the info. I would have thought that only _reading_ the input value would be ok, but it appears not. Shame :C – Bojangles Jun 24 '11 at 10:20
  • @Jam: With all the possibilities of AJAX and referrers and iframes and you-name-it, even reading would constitute a gross breach of security. Just think about it: By merely _visiting_ a website, information about your personal circumstances could immediately and unbeknown to you be communicated to third parties without your consent. Client-side scripting is really a complete security nightmare and you have to think _very_ carefully about all the avenues of attack. – Kerrek SB Jun 24 '11 at 10:22
  • I've found a solution by using a bit of regex to get the filename from the end of the path. It might be a little hacky, but I just need a bit of feedback for the user. – Bojangles Jun 24 '11 at 11:35
  • It's mandated by the HTML spec. (A lot of code expects the filename to come after a slash, and if we're having a fake prefix it's better to just have one cross-platform.) – gsnedders Feb 10 '15 at 14:39
  • 1
    if you just want the filename, your best bet is not to rely on the fakepath behaviour because that's not covered by any standards. Find the DOM element and access `myelement.files[0].name` and you're guaranteed it will only contain the name part. – Andy Jan 25 '22 at 08:36
0

I just want to add a new answer for people facing this issue nowadays. Similar to one of the comments, it's better to use the input element itself. For example:

document.getElementById('file-input').files[0].path

This worked for me.

Similar solution for React:

const inpRef = useRef(null)

return (
<input type="file" onChange={() => { 
    const filePath = inpRef.current.files[0].path
    // You can use more properties by looking at the files object
 }} />
)
YSLdev
  • 142
  • 1
  • 11