Welcome to the archive of the old FlatPress support forum. Browse more than a decade of FlatPress wisdom! Login is disabled.

The current FlatPress support forum is available here: forum.flatpress.org
Download Counter 1.3
  • I couldn't find any existing plugin for this, and the only thing I found was a request for one, so I decided to write one myself. The plugin adds a BBCode 'download' tag and keeps track of how many times the linked file was downloaded.

    The result looks like this:

    The BBCode is like this:


    You can download it from here.

    Edit: Updated it to version 1.1 with the ability to display the file size and fixed the issue with files being sent to the browser with the wrong name if the file was inside a directory under fp-content.

    Edit: Updated it to version 1.2 by fixing a security bug that allowed sensitive files to be downloaded from fp-content directory, changed the size attribute to accept size types in lower case and fixed the 404/403 error pages to be valid html.

    Edit: Updated it to version 1.3 by using io_load_file() in the download.php file to avoid some errors.
  • I have two suggestions: displaying the size of the file, and language support.
  • Nice, but can you make it not to change file names? I put my files in fp-content/store, and called them with [download=store/filename]. But now they download as “store_filename”. You don’t expect people to put their files immediately in fp-content, do you?
  • Easily done, just change the following line in plugin.downloadctr.php:

    header('Content-disposition: attachment; filename=' . $_GET["x"]);


    header('Content-disposition: attachment; filename=' . basename($_GET["x"]));

    I didn't have a requirement for this myself, but I'll update the code. I'll look into adding the file size display and language support when I get the time.

    Thanks for the suggestions :)
  • Also make sure that your fl-content/store directory is writable by the web server user otherwise the download count will not be updated.
  • Ok I've done a quick update, the renaming bug is fixed and now you can tell it to show the file size too in bytes, Kilobytes, etc, see the details on the download page.
  • Hi,
    nice plugin. The idea is great.

    However I think that there are some problems.

    The first is a nasty security bug. If you know Flatpress, you can download the password of the administrator and the salt to generate it.
    That's very, very, very, very dangerous.
    If you have a good video card and the password is easy you can get the password of the administrator in a short time.
    So you should limit the locations of download.

    The second problem is that the error pages aren't valid (X)HTML. Compilance to standards is one of FP's targets.

    The rest is well done.

    However if I were you I would use more FP's APIs, so io_write_file instead of fwrite etc and maybe use the index.php instead of the fp-plugins/downloadctr/res/download.php (res directory is only for resources like stylesheets and scripts). If you use the index.php you could also use PrettyURLs or RewriteURLs with the hook prettyurls_unhandled_url (if I remember correctly).
  • What about specifying (one or more) download folder(s) and disallow downloads from any other place? For example, creating a settings page in the admin section, storing paths there, and skipping specifying the path in the BBCode?
  • Two things more. I recommend not to store the counters in separate files. If a blogger has a lot of downloadable files, this results in a lot of small files, like in PostViews plugin. Once I made a version of it to store the entries in a single file. I recommend you to do something alike.
    The other one is a question. I don’t have the time to try it now, but peeking in the code I believe it won’t accept the size attribute in lowercase (size=k). Am I wrong?
  • I was thinking to allow only the attachs_dir and its subdirectories.

    Then you could use realpath of the download file and realpath of ATTACHS_DIR.
    If the later isn't equal to the first part of the former, then output 403.
    Realpath can fail, in that case I don't know what's the better thing to do.

    However the idea of white list is better then mine. You could use an array to check it with the same method of mine.
  • LAttilaD: I think you are right about small files. There are providers that limits your inodes.
    However I would accept lowercase attributes.
  • I've got a fix in place to limit to just the fp-content/download directory. I just check for '..' and '/' at the start of the string and '..' anywhere else in the string. It seems that ATTACHS_DIR is not defined, for me at least, so I didn't want to use that. Thanks pierovdfn for catching this!

    I'll fix the other things with html and lower case for the size and will upload a new zip.

    For the size, technically there is a difference between K and k (1024 vs 1000 i.e. binary vs decimal), I'll make it just use the binary size calculation though.

    Things I don't want to address:
    Settings - I don't see a huge need to store a list of allowed directories, this is just a simple counter plugin.
    Separate counter files - Same kind of deal, I don't intend this to be used for hosting a big file repository, so I won't change how the download counter is recorded.
  • Just a moment, ikromin. This isn’t a simple counter plugin only. This is a downloader plugin! There wasn’t a downloader so far for FP, you made the first one. Congrats! This can be developed into a full-fledged downloader aid, and that’s what happens now, by adding counting, file size display and place limitation. Limiting the folders users can download from makes them unable to pass round the downloader, so you can control your users with it. (I’m in the habit of not liking to let users know where do I keep my files on the server, but that’s just my silliness, I know.)
  • I didn't know about k and K. I just knew about KB and KiB, MiB etc and B b for Bytes and bits.

    ATTACHS_DIR is defined on defaults.php and it's fp-content/attachs .
    I think it would be better fix on the hardcoded string too (so fp-contents/attachs insted of fp-content/downloads) even because BBCode uses attachs dir by default.

    Actually there is the setting BBCODE_USE_WRAPPER to be used with BBCode. However it's a constant, so it's quite useless, unless you create the getfile.php...
    I'll open a thread to discuss about this.
  • I don’t remember seeing a K and k difference, only KB and KiB. But I believe most users (at least I) will forget typing an uppercase K, M, G, T there, so I recommended to take it caseless.
  • Thanks guys, I've changed it so it only allows files in the ATTACHS_DIR now, this solves the problem of defining the location of the files and keeps it in line with the rest of the FP code. I've also updated the response HTML to be valid and changed the size attribute to accept lower case parameters.

    Let me know if you see any other issues with it.
  • I get some freaky erros, I think it occurs if there are numbers in the name="test 1"
    Nope, I don't know why this occurs. some files work, some others not...

    Warning: fopen() [function.fopen]: Unable to access ../../../fp-content/attachs/testfolder/test.mp3.dlctr in /var/www/html/blog/fp-plugins/downloadctr/res/download.php on line 35

    Warning: fopen(../../../fp-content/attachs/testfolder/test.mp3.dlctr) [function.fopen]: failed to open stream: No such file or directory in /var/www/html/blog/fp-plugins/downloadctr/res/download.php on line 35

    Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/blog/fp-plugins/downloadctr/res/download.php:35) in /var/www/html/blog/fp-plugins/downloadctr/res/download.php on line 62

    Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/blog/fp-plugins/downloadctr/res/download.php:35) in /var/www/html/blog/fp-plugins/downloadctr/res/download.php on line 63

    Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/blog/fp-plugins/downloadctr/res/download.php:35) in /var/www/html/blog/fp-plugins/downloadctr/res/download.php on line 64

    Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/blog/fp-plugins/downloadctr/res/download.php:35) in /var/www/html/blog/fp-plugins/downloadctr/res/download.php on line 65

    ÿãˆInfoèL@ !$&),.1368;=ACEHJMORTWZ\_adfilnqsvx{}ƒ…ˆŠ’”—šœŸ¡¤¦©¬®±³¶¸»½ÁÃÅÈÊÍÏÒÔ×ÚÜßáäæéìîñóöøûý9LAME3.98r(@$h&@L@ÿªþÍÿãˆÎDŠ¦$5¬€UOH ^ý€A؆ Á¸–fx±bÅ‹Ÿ¯^½y™ûýŒ,800Ô ¡&ŠÑ£ž¨+ŠÅapL'ÕÑ‘ŠÅhÑ£F( ‡¹ÿê bá óœüF¬VNˆ b»tº  EPÀ¡žú†áÿëŠÁ@0( „ Îsœç:G°@FA"!hÛœç=©ÎsŸÿÂÎ{H0LV...... it goes on for several pages...
  • This looks like it cannot open the counter file that's been created, permissions error on your server perhaps? You can make it fail silently by changing like 35 and 50 to have '@' in front of the open(), like this:

    Line 35: $file = @fopen($f, "r");
    Line 50: $file = @fopen($f, "w");

  • I checked with an info.php allow_url_fopen is off. Isn't it a security issue to activate it?

    the .dlctr files have the permission 644 (-rw-r--r--), is this correct? The counter files get updated so
  • Are you saying it is working now? I suspect you are only seeing an error on the first time you try to download a file? The permissions look right.

    Could you check what display_errors is set in your php info? My server has it set to off, which might also explain the differences.
  • Yep, with the @s its working, thanks :)
    display_errors is on.
  • Cool :) I'll update the plugin later on tonight my time to use the FP file read function instead, which checks if the file exists first, the @ is just a workaround for now to suppress the file open error.
  • Thank you for your help and the great support :)
  • Excellent stuff Igor. Great blog you have too - some more useful stuff I saw on on there for FP users.
  • Thanks and glad to help. I've updated the plugin now to use io_load_file() so that the error you were getting will not happen.
  • A cosmetic suggestion: the code will be shorter and nicer if you write
                switch (strtolower($attr['size'])) {
    Then you can remove half of the case clauses.
  • What about some addition? When executing the BBCode, the plugin could check if the file exists. This helps bloggers to check mistyped file names. If the file doesn’t exist, is outside ATTACH_DIR, or any problem is found, the file name may appear strikethrough, for example.
  • Do you mean like this?

    Instead of me making changes for every request, I think it's better to get a couple of requests together before I make an update, however, don't start making up requests for the sake of making more work :)

    I would like to add the following:
    • Ability to specify the mime-type of your file (defaulting to application/octet-stream if nothing is specified)
    • Resumable downloads
    • Check if download counter can be updated (flag this somehow, maybe grey out the counter)
    • Strikethrough the file name if file doesn't exist
    Not sure when I will have the time to add all of those at this point.
  • Yes, I would like this appearance.
Start a New Discussion

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion