
Show HN: Host your own minimal file sharing site (now with expiring files) - nikosch86
https://github.com/nikosch86/file-upload
======
stephenr
Please investigate 'safe' php file upload handling, specifically: the
`is_uploaded_file` and `move_uploaded_file` functions.

Also perhaps consider the `mkdir` function, and perhaps 'file_put_contents'.
Your reliance on shell functions via `exec` is quite concerning, given what
you're doing.

Lastly, I'd suggest either `random_int` or `random_bytes` (combined with e.g.
bin2hex, or a hashing function to get an ascii string) instead of uniqid.

I'm not quite sure why there's a check on user agent, to carry out the same
logic regardless?

~~~
eps
I think OP's code is actually markedly better than your first two suggestions
_exactly_ because it doesn't use any of the advanced PHP APIs. It's all there,
bare and easy to check, with no gotchas, ini-dependent caveats and what not.

I agree that uniqid(), as used, is not the best choice, but that's only
because it may produce dupes if the machine's clock is rolled back (ie by
ntpd). Regardless of the prng choice, the code could use a check for whether
selected folder already exists.

~~~
stephenr
What "gotchas" or caveats are you expecting from `is_uploaded_file` or
`move_uploaded_file`?

 _Any_ use of `exec` should be considered dangerous, when there's native
language/stdlib support for achieving the same thing.

Edit: corrected function name.

~~~
huhtenberg
`is_uploaded_file` and `move_uploaded_file` are the band-aid API meant for
broken code that may be mistakenly working with some random local files
instead of uploaded ones.

This is akin to using "if (3 == x)" notation in C in a fear of accidentally
writing "if (x = 3)".

For this particular case the use of both `rename` and `exec` would've been
perfectly fine.

> Any _use of `exec` should be considered dangerous_

By whom? It _may_ be a red flag if used by an inexperienced programmer or if
it appears in an otherwise messy code base. But if I know what I'm doing, then
it's just another API that's perfectly OK when used with due care.

~~~
meritt
> `is_uploaded_file` and `move_uploaded_file` are the band-aid

It's not a band-aid. When a file is uploaded (see RFC 1867) via HTTP POST, PHP
internally allocates a hash table that tracks which files on the filesystem
have been uploaded. When the process terminates, it uses that hashtable to
remove any remaining uploaded files in the tmp space.

move_uploaded_file() confirms that the filename was indeed created as a result
of an upload, and additionally removes that entry from the hash table.

~~~
huhtenberg
> _move_uploaded_file() confirms that the filename was indeed created as a
> result of an upload, and additionally removes that entry from the hash
> table._

In other words, move_uploaded_file() protects against moving a non-uploaded
file or moving one more than once.

So it's for an upload processing code that, at some point, is becoming unsure
of what the heck it is doing.

It is a band-aid.

~~~
eganist
> In other words, move_uploaded_file() protects against moving a non-uploaded
> file or moving one more than once.

Sure.

> So it's for an upload processing code that, at some point, is becoming
> unsure of what the heck it is doing.

How do you get to this conclusion from the above?

> It is a band-aid.

Nope. Uploaded file checking would seem to be necessary, though rather than
requiring the developer to implement it, there's some lang-sec value in php
doing the check automatically with any $_FILES references and instead allowing
the developer to suppress it. That's an area where implementation can be
refined, but it doesn't make the current solution a band-aid by any stretch.

Edit: as an example, I'd much rather see the example given in php docs
actually implemented as part of the framework rather than delegated to the
developer. But aside from just dumping all uploaded files in one quarantined
location, this solution is a functional pattern.
[https://www.php.net/manual/en/function.is-uploaded-
file.php](https://www.php.net/manual/en/function.is-uploaded-file.php)

(I'm not a php dev, and docs on the relevant functions date back to 2003, so
for all I know, this has been rectified in the intervening 17 years)

------
oefrha
There are already transfer.sh [1] and other established projects (which I
can’t recall right now) that serve this purpose. With more fine-grained
control too. A golang compiled executable is also arguably more lightweight
than a php app, whether the feature set/code is simpler or not.

[1]
[https://github.com/dutchcoders/transfer.sh/](https://github.com/dutchcoders/transfer.sh/)

Edit: Since more than one person has replied with non-self-hosted solutions, I
should note that _transfer.sh can be self-hosted_ , although you can also use
the website itself.

~~~
nikosch86
The goal was a minimum viable implementation of a file sharing service that
can be self hosted. Simplicity to this extreme serves many purposes, it is
easy to understand and debug, has less attack surface, less dependencies and
is small (in terms of lines of Code, less than 100, and size, less than 50K).

If one needs more features or more control, there are certainly many options
out there, I created this not to compete with other projects but to provide a
super simple solution to a specific problem.

~~~
Pako
I like the idea of a really small MVP; I might give this a try later in Prolog
to see how they compare.

~~~
Pako
Definitely not as concise as your PHP impl but meh
[https://gist.github.com/MagnificentPako/b67b081d5cac0d0185ef...](https://gist.github.com/MagnificentPako/b67b081d5cac0d0185efd52c4a20a595)

------
hashworks
If you want something with a bit more features, there is filebin[1]. It has
clients for Linux, BSD and Android, runs on PHP with support for various
databases, offers syntax highlighting for multiple formats and other stuff
like plain view, multipaste, tar download and LDAP integration.

[1] [http://git.server-speed.net/users/flo/filebin/](http://git.server-
speed.net/users/flo/filebin/)

~~~
sebazzz
I built something similar (I call it IFS[0]). Uses no database, and x-plat via
.NET Core.

[0]: [https://github.com/Sebazzz/IFS/](https://github.com/Sebazzz/IFS/)

------
radialbrain
There's also dl, which supports creating single use links for third parties to
upload files:
[https://www.thregr.org/~wavexx/software/dl/](https://www.thregr.org/~wavexx/software/dl/)

~~~
nexxer
I've been hosting dl at work for many years and it's filled our needs
admirably. Simple, zero maintenance, just works.

It even has a useful Thunderbird extension that auto-uploads any large
attachment using the FileLink API when composing a new mail, adding the dl URL
in the email's body. Unfortunately the extension stopped working after the
migration to WebExtensions.

------
elkos
That's pretty handy actually

------
AibrahimRiyadh
Awesome, thanks!

