php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #77372 Relative file path is removed from uploaded file
Submitted: 2018-12-29 22:49 UTC Modified: 2019-01-03 11:32 UTC
From: nospam at unclassified dot de Assigned:
Status: Open Package: *Directory/Filesystem functions
PHP Version: 7.0.33 OS: Windows 10
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2018-12-29 22:49 UTC] nospam at unclassified dot de
Description:
------------
<input type="file" name="files" multiple webkitdirectory>

This allows the user to select a directory and have all its files uploaded, also from all subdirectories. In Firefox, the POST request correctly contains the relative paths of all uploaded files. In PHP, the paths are removed and only the file names are available.

$_FILES['files']['name'][...]:

Actual value: 'file.png'
Expected value: 'sub/dir/file.png'

This makes the entire directory uploading feature unusable because the structure gets lost and file names may even become duplicate and useless.

Note, I have searches for "upload webkitdirectory" but only got tons of unrelated results, so I might have missed a real duplicate. Please improve your search if you want to avoid duplicates.

Test script:
---------------
See above.

Expected result:
----------------
See above.

Actual result:
--------------
See above.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-01-02 17:39 UTC] cmb@php.net
Hmm, the webkitdirectory attribute[1] is part of the “File and
Directory Entries API” which is a very recent *draft*, so I
wouldn't assess non-compliance with this feature a bug in PHP per
se.

Anyhow, the relevant code[2] that causes this behavior is due to a
quirk of IE, namely that even recent versions of IE 11 allow to
“Include local directory path when uploading files to a server”.
However, while the code originally just catered to backslashes
(like the comment still indicates), it has been replaced with a
more general _basename()[3] which also caters to (forward)
slashes.  So, at the very least, the comment is wrong.

[1] <https://wicg.github.io/entries-api/#dom-htmlinputelement-webkitdirectory>
[2] <https://github.com/php/php-src/blob/php-7.3.0/main/rfc1867.c#L1149-L1154>
[3] <http://github.com/php/php-src/commit/cdb9ee0d1a5ecb843b320c9effb81207f4280795>
 [2019-01-02 18:09 UTC] requinix@php.net
-Type: Bug +Type: Feature/Change Request
 [2019-01-02 18:09 UTC] requinix@php.net
There's no way PHP could know whether it should keep or remove any directory portion of the original filename, and there is far too much code out there that trusts the name to be a basename. The only method I see for this is to introduce another array entry for the whole path - the value submitted by the client, unchanged. Like "original_name" or something. That should be a relatively minor change for PHP and it shouldn't impact any existing code.

Browser support is a bit contradictory:
https://caniuse.com/#search=webkitdirectory
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory#Browser_compatibility
 [2019-01-03 11:32 UTC] nospam at unclassified dot de
I wouldn't call the browser support contradictory. Every current desktop browser supports this feature for a few versions already. 95% of all desktop users should be able to use it today. IE is not current and about to die. The concept of uploading large amounts of files probably doesn't fit into mobile devices anyway so I don't consider it a problem when these platforms don't support it.

The thing is, the HTTP request does contain that information about the provided path. PHP just drops it. And when the PHP manual contains code examples that suggest applying `basename` on the file name, I was assuming that it isn't basename'd already and browsers may or may not send a path there and I must remove it when I don't need it (or my code isn't prepared to validate it). I might need to go down and parse the HTTP request myself in PHP to extract the required information.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Jan 16 12:01:25 2019 UTC