Simple Download Monitor - Version 0.22

Version Description

  • Matheus Bratfisch (http://matbra.com) suggested and implemented an intermediate download page. You can use this page to tell the user that his download is about to begin, instead of just sending the file directly. To do so, please enter the plugin's configuration, check the "Use the intermediate download page." checkbox and provide a file path (not a web path!) to the page's source code. An example page download-example.php is provided in the plugin's directory.

Note that if you are already used of Simple Download Monitor and want to use this functionality, you'll need to modify your .htaccess file (new users are not affected as they must have used the configuration listed in the documentation and that is the required one already): Change the line RewriteRule ^(files/.*) /index.php?sdmon=$1 [L] to read RewriteRule ^(files/.*) /index.php?sdmon=$1 [L,QSA] (that is, add ,QSA to the SDMon's rewrite rule's options). Then you can open the SDMon configuration and in the "Use an intermediate Download page" section enable the intermediate download page. A demo page is provided, but you can of course use a different one.

I'd like to thank Matheus Bratfisch (http://matbra.com) very much for first providing this functionality and then being patient and insistent enough for me to incorporate it.

Download this release

Release Info

Developer pepak.net
Plugin Icon 128x128 Simple Download Monitor
Version 0.22
Comparing to
See all releases

Code changes from version 0.21 to 0.22

download-example-js.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php get_header(); ?>
2
+
3
+
4
+ <div id="content">
5
+ <div id="content-inner">
6
+
7
+ <div id="main">
8
+
9
+
10
+ <div align="center">
11
+ <br /><br />
12
+ Your download will begin in 5 seconds! <br /> If it does not, <a href="/<? echo $filename; ?>?download=true" rel="nofollow">click here</a>.
13
+ <br /><br />
14
+ </div>
15
+
16
+
17
+
18
+
19
+ </div>
20
+ <script>
21
+ setTimeout("updateIframe()",5000);
22
+
23
+ var exec = true;
24
+
25
+ function updateIframe() {
26
+ if(exec == true) {
27
+ exec = false;
28
+ var ifrm = document.getElementById("frame1");
29
+ ifrm.src = "/<? echo $filename; ?>?download=true";
30
+ }
31
+ }
32
+ </script>
33
+ <?php get_sidebar(); ?>
34
+ <iframe id="frame1" rel="nofollow" style="display:none"></iframe>
35
+ <?php get_footer(); ?>
36
+
37
+
download-example.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $GLOBALS['sdmon_filename'] = $filename;
4
+ add_action('wp_head', 'sdmon_redirect');
5
+ get_header();
6
+
7
+ function sdmon_redirect() {
8
+ global $sdmon_filename;
9
+ echo "<meta http-equiv=\"refresh\" content=\"5;/${sdmon_filename}?download=true\" />\n";
10
+ }
11
+
12
+ ?>
13
+ <div id="content">
14
+ <div id="content-inner">
15
+
16
+ <div id="main">
17
+
18
+ <div align="center">
19
+ <br /><br />
20
+ <p>Your download will begin in 5 seconds!</p>
21
+ <p>If it does not, <a href="/<? echo $filename; ?>?download=true" rel="nofollow">click here</a>.</p>
22
+ <br /><br />
23
+ </div>
24
+
25
+ </div>
26
+ <?php get_sidebar(); ?>
27
+ <?php get_footer(); ?>
lang/cs_CZ.mo CHANGED
Binary file
lang/cs_CZ.po CHANGED
@@ -2,9 +2,9 @@ msgid ""
2
  msgstr ""
3
  "Project-Id-Version: Simple Download Monitor v0.19\n"
4
  "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: 2011-05-15 17:44+0100\n"
6
  "PO-Revision-Date: \n"
7
- "Last-Translator: pepak <http://www.pepak.net>\n"
8
  "Language-Team: Pepak <pepak@pepak.net>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
@@ -16,302 +16,327 @@ msgstr ""
16
  "X-Poedit-Basepath: .\n"
17
  "X-Poedit-SearchPath-0: ..\n"
18
 
19
- #: ../simple-download-monitor.php:283
20
  msgid "Simple Download Monitor error"
21
  msgstr "Simple Download Monitor: chyba"
22
 
23
- #: ../simple-download-monitor.php:324
24
  #, php-format
25
  msgid "You have exceeded your download quota today. Please try again in %d hours and %d minutes."
26
  msgstr "Překročil jste svůj dnešní povolený počet downloadů. Zkuste to prosím znovu za %d hodin a %d minut."
27
 
28
- #: ../simple-download-monitor.php:364
29
  #, php-format
30
  msgid "Requested file <strong>%s</strong> not found."
31
  msgstr "Požadovaný soubor <strong>%s</strong> nebyl nalezen."
32
 
33
- #: ../simple-download-monitor.php:468
34
- #: ../simple-download-monitor.php:954
35
  msgid "Simple Download Monitor options"
36
  msgstr "Simple Download Monitor - nastavení"
37
 
38
- #: ../simple-download-monitor.php:469
39
  msgid "Access rights"
40
  msgstr "Přístupová práva"
41
 
42
- #: ../simple-download-monitor.php:470
43
  msgid "You can set up user rights required to access various functions of Simple Download Monitor. Rights are assigned through capabilities (see <a href=\"http://codex.wordpress.org/Roles_and_Capabilities#Roles\">Roles and Capabilities</a> in WordPress Codex). Predefined values are <strong>read</strong> (\"any registered user\") for displaying stats, <strong>delete_users</strong> (\"administrator\") for reseting stats and <strong>manage_options</strong> (\"administrator\") for changing options."
44
  msgstr "Zde můžete nastavit uživatelská práva potřebná pro přístup k jednotlivým funkcím Simple Download Monitoru. Práva jsou definována prostřednictvím schopností (capabilities, viz <a href=\"http://codex.wordpress.org/Roles_and_Capabilities#Roles\">Roles and Capabilities</a> ve WordPress Codex). Výchozí hodnoty jsou <strong>read</strong> (\"každý registrovaný uživatel) pro zobrazení statistik, <strong>delete_users</strong> (\"administrátor\") pro mazání statistik a <strong>manage_options</strong> (\"administrátor\") pro změnu nastavení."
45
 
46
- #: ../simple-download-monitor.php:471
47
  msgid "Capability required for viewing download stats:"
48
  msgstr "Schopnost (capability) pro zobrazení statistik:"
49
 
50
- #: ../simple-download-monitor.php:473
51
  msgid "Capability required for reseting download stats:"
52
  msgstr "Schopnost (capability) pro smazání statistik:"
53
 
54
- #: ../simple-download-monitor.php:475
55
  msgid "Capability required for setting SDMON options:"
56
  msgstr "Schopnost (capability) pro nastavení:"
57
 
58
- #: ../simple-download-monitor.php:477
59
  msgid "Allowed directories"
60
  msgstr "Povolené adresáře"
61
 
62
- #: ../simple-download-monitor.php:478
63
  msgid "Only requested files whose full names (relative to document root) start with this regular expression will be processed. It is strongly recommended to place all downloadable files (and ONLY downloadable files) into a designated directory and then placing that directory's name followed by a slash here. It is possible to use the power of PREG to allow multiple directories, but make sure there are ONLY files which you are comfortable with malicious users downloading. Do not EVER allow directories which contain PHP files here! That could lead to disclosure of sensitive data, including username and password used to connect to WordPress database."
64
  msgstr "Zpracovávány budou pouze soubory, jejichž plná jména (relativní vůči kořenovému adresáři webu) začínají tímto regulárním výrazem. Silně doporučuji umístit všechny stažitelné soubory (a JENOM stažitelné soubory) do jednoho určeného adresáře a vepsat sem název tohoto adresáře zakončený lomítkem. Lze také využít všech možností, které dává PREG, pro povolení více adresářů, ale dejte si pozor, ať v nich jsou JEDINĚ soubory, u kterých vám nevadí, když si je stáhne útočník. NIKDY do těchto adresářů neukládejte žádné PHP soubory! To by mohlo vést k zveřejnění citlivých dat, včetně uživatelského jména a hesla pro připojení k databázi."
65
 
66
- #: ../simple-download-monitor.php:479
67
  msgid "Default value is <code>files/</code>, which only allows download from /files directory (the leading <code>/</code> is implicit)."
68
  msgstr "Výchozí hodnota je <code>files/</code>, která dovolí stahovat pouze soubory z adresáře /files (úvodní <code>/</code> je dosazeno automaticky)."
69
 
70
- #: ../simple-download-monitor.php:481
71
  msgid "Allowed extensions"
72
  msgstr "Povolené přípony"
73
 
74
- #: ../simple-download-monitor.php:482
75
  msgid "Only files with extensions matching this regular expressions will be processed. This is another important security value. Make sure you only add extensions which are safe for malicious users to have, e.g. archives and possibly images. Do NOT use any expression that could allow a user to download PHP files, even if you think it safe given the Allowed Directories option above."
76
  msgstr "Zpracovávány budou pouze soubory, jejichž přípony odpovídají tomuto regulárnímu výrazu. Jde o další důležitý bezpečnostní prvek. Dejte si pozor, ať jsou zde uvedeny pouze takové přípony, které nemohou být zneužity útočníky, tzn. komprimované archívy a případně obrázky. NEPOUŽÍVEJTE výrazy, které by mohly uživateli dovolit download PHP souborů, ani kdyby tyto soubory vylučovalo nastavení \"Povolené adresáře\" výše."
77
 
78
- #: ../simple-download-monitor.php:483
79
  msgid "Default value is <code>zip|rar|7z</code> which only allows download of files ending with <code>.zip</code>, <code>.rar</code> and <code>.7z</code> (the leading <code>.</code> is implicit)."
80
  msgstr "Výchozí hodnota je <code>zip|rar|7z</code>, která povolí pouze stahování souborů s příponou <code>.zip</code>, <code>.rar</code> a <code>.7z</code> (úvodní <code>.</code> je dosazena automaticky)."
81
 
82
- #: ../simple-download-monitor.php:485
83
  msgid "Inline files"
84
  msgstr "Soubory pro inline zobrazení"
85
 
86
- #: ../simple-download-monitor.php:486
87
  msgid "Files whose names match this regular expression will be displayed inline (within a HTML page) rather than downloaded."
88
  msgstr "Soubory, které vyhovují tomuto regulárnímu výrazu, budou zobrazeny inline (jako objekt - např. obrázek nebo video - uvnitř HTML stránky) místo aby se stahovaly."
89
 
90
- #: ../simple-download-monitor.php:487
91
  msgid "By default, this value is empty - no files will appear inline, all will be downloaded. You may want to place something like <code>\\.(jpe?g|gif|png|swf)$</code> here to make images and Flash videos appear inline."
92
  msgstr "Výchozí hodnotou je prázdný řetězec - všechny soubory se budou stahovat, žádný nebude zobrazen inline. Vepište sem něco jako <code>\\.(jpe?g|gif|png|swf)$</code> pro zobrazování obrázků a Flashů inline."
93
 
94
- #: ../simple-download-monitor.php:488
95
  msgid "Note: Unlike the options above, nothing is implied in this regular expression. You <em>must</em> use an explicit <code>\\.</code> to denote \"start of extension\", you <em>must</em> use an explicit <code>$</code> to mark \"end of filename\", etc."
96
  msgstr "Pozn.: Narozdíl od nastavení uvedených výše se do tohoto regulárního výrazu nic nedoplňuje. Pokud chcete vyznačit \"začátek přípony\", <em>musíte</em> sem napsat <code>\\.</code>; pokud chcete vyznačit \"konec názvu souboru\", <em>musíte</em> sem napsat <code>$</code>, a podobně."
97
 
98
- #: ../simple-download-monitor.php:489
99
  msgid "Also note that this plugin uses PCRE-compatible regular expressions, NOT the better-known POSIX-compatible regular expressions. As a result, a valid regular expression must be at least three characters long - separator twice, and at least one character for a meaningful r.e."
100
  msgstr "Dále upozorňuji, že plugin používá PCRE-kompatibilní regulární výrazy a ne známější POSIX-kompatibilní. Z tohoto důvodu je vyžadováno, aby regulární výraz byl aspoň tři znaky dlouhý - dva znaky na dva výskyty oddělovače a aspoň jeden znak pro smysluplný r.e."
101
 
102
- #: ../simple-download-monitor.php:491
103
  msgid "Store detailed logs?"
104
  msgstr "Ukládat detailní záznamy?"
105
 
106
- #: ../simple-download-monitor.php:492
107
  msgid "If detailed logs are allowed, various information (including exact time of download, user's IP address, referrer etc.) is stored. This can fill your database quickly if you have only a little space or a lot of popular downloads. Otherwise just the total numbers of downloads are stored, consuming significantly less space."
108
  msgstr "Pokud je tato volba zapnuta, ukládají se detailní informace (jako přesný čas, IP adresa uživatele nebo referer) o každém downloadu. To může rychle zahltit databázi, pokud máte jen málo prostoru nebo populární downloady. Normálně se ukládá jen celkový počet stažení, který zabírá podstatně méně místa."
109
 
110
- #: ../simple-download-monitor.php:493
111
  msgid "Use detailed statistics."
112
  msgstr "Používat detailní statistiky"
113
 
114
- #: ../simple-download-monitor.php:494
115
  msgid "Ignored users"
116
  msgstr "Ignorovaní uživatelé"
117
 
118
- #: ../simple-download-monitor.php:495
119
  msgid "List of users whose downloads are not monitored. Separate multiple users with pipe character <code>|</code>. It is useful to prevent administrator damaging the statistics by testing that downloads work."
120
  msgstr "Seznam uživatelů, jejichž downloady nejsou sledovány. Uživatelská jména oddělujte znakem roury <code>|</code>. Funkce se hodí pro administrátory, kteří chtějí ověřovat funkčnost odkazů, ale nepřejí si, aby se jejich testy zaznamenávaly do statistik."
121
 
122
- #: ../simple-download-monitor.php:497
123
  msgid "Ignore quick re-downloads"
124
  msgstr "Ignorovat rychlé opakované downloady"
125
 
126
- #: ../simple-download-monitor.php:498
127
  msgid "If one IP address requests the same download several times within a given time interval, only the first time will be recorded. If a zero or a negative value is entered, all downloads will get recorded regardless of how quickly they occur after each other."
128
  msgstr "Pokud se jedna IP adresa pokusí stáhnout jeden soubor několikrát po sobě v daném časovém intervalu, zaznamená se do statistik jen první pokus. Pokud je rozpětí stanoveno na nula nebo záporné číslo, budou se zaznamenávat všechny downloady, bez ohledu na to, jak rychle po sobě následují."
129
 
130
- #: ../simple-download-monitor.php:499
131
  msgid "seconds"
132
  msgstr "sekund"
133
 
134
- #: ../simple-download-monitor.php:500
135
  msgid "Limit number of downloads per IP address"
136
  msgstr "Omezit počet downloadů z jedné IP adresy"
137
 
138
- #: ../simple-download-monitor.php:501
139
  msgid "Limit the number of files an IP address can download per day. The default value of zero means 'no limits' - an IP address can download as many files as it likes. Note that various download managers can initiate several downloads for each file, so make sure the limit is high enough not to interfere with the normal usage of your site. Also, please understand that this is NOT a perfect solution: One IP address can be shared by multiple users, and one user can easily use more than one IP address."
140
  msgstr "Omezit počet souborů, které může jedna IP adresa stáhnout za jeden den. Výchozí hodnota nula značí \"bez omezení\" - IP adresa může stáhnout libovolné množství souborů. Pozor, různé download managery mohou spustit pro jeden soubor několik stahování najednou; ujistěte se, že je limit dost velký na to, aby bránil v běžném používání vašich stránek. Také si prosím uvědomte, že toto NENÍ dokonalé řešení: Jednu IP adresu může sdílet mnoho uživatelů, a naopak jeden uživatel může mít mnoho IP adres."
141
 
142
- #: ../simple-download-monitor.php:502
143
  msgid "Users listed in the <strong>Ignored users</strong> section above can always download an unlimited number of files."
144
  msgstr "Uživatelé uvedení v sekci <strong>Ignorovaní uživatelé</strong> výše mohou stahovat neomezený počet souborů."
145
 
146
- #: ../simple-download-monitor.php:503
147
  msgid "Visitors:"
148
  msgstr "Návštěvníci:"
149
 
150
- #: ../simple-download-monitor.php:504
151
  msgid "Registered users:"
152
  msgstr "Registrovaní uživatelé"
153
 
154
- #: ../simple-download-monitor.php:505
155
  msgid "Error message:"
156
  msgstr "Chybová zpráva:"
157
 
158
- #: ../simple-download-monitor.php:507
159
  #, php-format
160
  msgid "(The first <code>%d</code> will be replaced by number of hours, the second one by number of minutes.)"
161
  msgstr "(První <code>%d</code> bude nahrazeno počtem hodin, druhé počtem minut.)"
162
 
163
- #: ../simple-download-monitor.php:509
164
- #: ../simple-download-monitor.php:825
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  msgid "Update settings"
166
  msgstr "Uložit nastavení"
167
 
168
- #: ../simple-download-monitor.php:634
169
  msgid "First"
170
  msgstr "První"
171
 
172
- #: ../simple-download-monitor.php:635
173
  msgid "Previous"
174
  msgstr "Předchozí"
175
 
176
- #: ../simple-download-monitor.php:642
177
  msgid "Next"
178
  msgstr "Další"
179
 
180
- #: ../simple-download-monitor.php:643
181
  msgid "Last"
182
  msgstr "Poslední"
183
 
184
- #: ../simple-download-monitor.php:763
185
- #: ../simple-download-monitor.php:853
186
- #: ../simple-download-monitor.php:954
187
- #: ../simple-download-monitor.php:955
188
  msgid "Simple Download Monitor"
189
  msgstr "Simple Download Monitor"
190
 
191
- #: ../simple-download-monitor.php:764
192
  msgid "Nonexistent downloads"
193
  msgstr "Neexistující soubory"
194
 
195
- #: ../simple-download-monitor.php:764
196
  msgid "All downloads"
197
  msgstr "Všechny downloady"
198
 
199
- #: ../simple-download-monitor.php:765
200
  msgid "Show all downloads"
201
  msgstr "Zobrazit všechny soubory"
202
 
203
- #: ../simple-download-monitor.php:765
204
  msgid "Show nonexistent downloads"
205
  msgstr "Zobrazit neexistující soubory"
206
 
207
- #: ../simple-download-monitor.php:781
208
  msgid "Filename"
209
  msgstr "Název souboru"
210
 
211
- #: ../simple-download-monitor.php:782
212
  msgid "Download count"
213
  msgstr "Počet stažení"
214
 
215
- #: ../simple-download-monitor.php:783
216
  msgid "Last date"
217
  msgstr "Poslední datum"
218
 
219
- #: ../simple-download-monitor.php:784
220
  msgid "Hide from sidebar"
221
  msgstr "Skrýt z postranního panelu"
222
 
223
- #: ../simple-download-monitor.php:785
224
  msgid "Reset to zero"
225
  msgstr "Vynulovat"
226
 
227
- #: ../simple-download-monitor.php:810
228
  msgid "Hidden"
229
  msgstr "Skrytý"
230
 
231
- #: ../simple-download-monitor.php:815
232
  msgid "Reset"
233
  msgstr "Vynulovat"
234
 
235
- #: ../simple-download-monitor.php:826
236
  msgid "Reset checked statistics"
237
  msgstr "Vymazat označené statistiky"
238
 
239
- #: ../simple-download-monitor.php:827
240
  msgid "Reset all statistics"
241
  msgstr "Vymazat všechny statistiky"
242
 
243
- #: ../simple-download-monitor.php:827
244
- #: ../simple-download-monitor.php:924
245
  msgid "Yes, I am sure"
246
  msgstr "Ano, chci to udělat"
247
 
248
- #: ../simple-download-monitor.php:854
249
  #, php-format
250
  msgid "Detailed data for <strong>%s</strong>:"
251
  msgstr "Detailní data pro <strong>%s</strong>:"
252
 
253
- #: ../simple-download-monitor.php:855
254
  #, php-format
255
  msgid "Total number of downloads: <strong>%d</strong>."
256
  msgstr "Celkový počet stažení: <strong>%d</strong>."
257
 
258
- #: ../simple-download-monitor.php:872
259
  msgid "Date"
260
  msgstr "Datum"
261
 
262
- #: ../simple-download-monitor.php:873
263
  msgid "Country"
264
  msgstr "Země"
265
 
266
- #: ../simple-download-monitor.php:874
267
  msgid "IP address"
268
  msgstr "IP adresa"
269
 
270
- #: ../simple-download-monitor.php:875
271
  msgid "Referer"
272
  msgstr "Referer"
273
 
274
- #: ../simple-download-monitor.php:876
275
  msgid "Username"
276
  msgstr "Uživatel"
277
 
278
- #: ../simple-download-monitor.php:913
279
  msgid "Delete this statistic"
280
  msgstr "Vymazat tuto statistiku"
281
 
282
- #: ../simple-download-monitor.php:921
283
  msgid "Delete checked statistics"
284
  msgstr "Vymazat označené statistiky"
285
 
286
- #: ../simple-download-monitor.php:924
287
  msgid "Delete all statistics"
288
  msgstr "Vymazat všechny statistiky"
289
 
290
- #: ../simple-download-monitor.php:928
291
  msgid "Return to full list."
292
  msgstr "Návrat do úplného seznamu"
293
 
294
- #: ../simple-download-monitor.php:969
295
  msgid "Allows you to display the most popular downloads in the sidebar."
296
  msgstr "Dovoluje zobrazit v postranním panelu seznam nejoblíbenějších souborů."
297
 
298
- #: ../simple-download-monitor.php:1014
299
  msgid "Popular files"
300
  msgstr "Oblíbené soubory"
301
 
302
- #: ../simple-download-monitor.php:1020
303
  msgid "Title:"
304
  msgstr "Zobrazovaný název:"
305
 
306
- #: ../simple-download-monitor.php:1024
307
  msgid "Number of files to show:"
308
  msgstr "Počet zobrazených souborů:"
309
 
310
- #: ../simple-download-monitor.php:1027
311
  msgid "Only show filenames which match this LIKE condition:"
312
  msgstr "Zobrazovat pouze soubory, které vyhovují této LIKE podmínce:"
313
 
314
- #: ../simple-download-monitor.php:1029
315
  msgid "Empty string matches all filenames and is useful for most usage scenarios. You would only use a non-empty value if you wanted to create multiple SDMon widgets, each showing a different list of files: only filenames which match the given string in a LIKE condition of a SQL query will be shown. The most common values would be something like <code>files/documents/%</code> (meaning \"The filename must begin with <code>files/documents/</code>\") or <code>%.mp3</code> (meaning \"The filename must end with <code>.mp3</code>\") - the percentage symbol <code>%</code> means \"anything\", the underscore symbol <code>_</code> means \"Any one character\"."
316
  msgstr "Prázdný řetězec neomezuje seznam souborů a je vhodný pro nejběžnější typy použití. Neprázdnou hodnotu použijte, pokud chcete zobrazit několik nezávislých widgetů, kde každý bude zobrazovat jiný seznam souborů - pak budou zobrazeny jen ty soubory, jejichž názvy vyhoví podmínce. Typické hodnoty vypadají jako <code>files/dokumenty/%</code> (\"Jméno souboru musí začínat <code>files/dokumenty/</code>\") nebo <code>%.mp3</code> (\"Jméno souboru musí končit <code>.mp3</code>\") - symbol procenta <code>%</code> značí \"cokoliv\", symbol podtržítka <code>_</code> značí \"právě jeden libovolný znak\"."
317
 
2
  msgstr ""
3
  "Project-Id-Version: Simple Download Monitor v0.19\n"
4
  "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2012-07-14 17:00+0100\n"
6
  "PO-Revision-Date: \n"
7
+ "Last-Translator: Pepak <pepak@pepak.net>\n"
8
  "Language-Team: Pepak <pepak@pepak.net>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
16
  "X-Poedit-Basepath: .\n"
17
  "X-Poedit-SearchPath-0: ..\n"
18
 
19
+ #: ../simple-download-monitor.php:288
20
  msgid "Simple Download Monitor error"
21
  msgstr "Simple Download Monitor: chyba"
22
 
23
+ #: ../simple-download-monitor.php:329
24
  #, php-format
25
  msgid "You have exceeded your download quota today. Please try again in %d hours and %d minutes."
26
  msgstr "Překročil jste svůj dnešní povolený počet downloadů. Zkuste to prosím znovu za %d hodin a %d minut."
27
 
28
+ #: ../simple-download-monitor.php:369
29
  #, php-format
30
  msgid "Requested file <strong>%s</strong> not found."
31
  msgstr "Požadovaný soubor <strong>%s</strong> nebyl nalezen."
32
 
33
+ #: ../simple-download-monitor.php:512
34
+ #: ../simple-download-monitor.php:1004
35
  msgid "Simple Download Monitor options"
36
  msgstr "Simple Download Monitor - nastavení"
37
 
38
+ #: ../simple-download-monitor.php:513
39
  msgid "Access rights"
40
  msgstr "Přístupová práva"
41
 
42
+ #: ../simple-download-monitor.php:514
43
  msgid "You can set up user rights required to access various functions of Simple Download Monitor. Rights are assigned through capabilities (see <a href=\"http://codex.wordpress.org/Roles_and_Capabilities#Roles\">Roles and Capabilities</a> in WordPress Codex). Predefined values are <strong>read</strong> (\"any registered user\") for displaying stats, <strong>delete_users</strong> (\"administrator\") for reseting stats and <strong>manage_options</strong> (\"administrator\") for changing options."
44
  msgstr "Zde můžete nastavit uživatelská práva potřebná pro přístup k jednotlivým funkcím Simple Download Monitoru. Práva jsou definována prostřednictvím schopností (capabilities, viz <a href=\"http://codex.wordpress.org/Roles_and_Capabilities#Roles\">Roles and Capabilities</a> ve WordPress Codex). Výchozí hodnoty jsou <strong>read</strong> (\"každý registrovaný uživatel) pro zobrazení statistik, <strong>delete_users</strong> (\"administrátor\") pro mazání statistik a <strong>manage_options</strong> (\"administrátor\") pro změnu nastavení."
45
 
46
+ #: ../simple-download-monitor.php:515
47
  msgid "Capability required for viewing download stats:"
48
  msgstr "Schopnost (capability) pro zobrazení statistik:"
49
 
50
+ #: ../simple-download-monitor.php:517
51
  msgid "Capability required for reseting download stats:"
52
  msgstr "Schopnost (capability) pro smazání statistik:"
53
 
54
+ #: ../simple-download-monitor.php:519
55
  msgid "Capability required for setting SDMON options:"
56
  msgstr "Schopnost (capability) pro nastavení:"
57
 
58
+ #: ../simple-download-monitor.php:521
59
  msgid "Allowed directories"
60
  msgstr "Povolené adresáře"
61
 
62
+ #: ../simple-download-monitor.php:522
63
  msgid "Only requested files whose full names (relative to document root) start with this regular expression will be processed. It is strongly recommended to place all downloadable files (and ONLY downloadable files) into a designated directory and then placing that directory's name followed by a slash here. It is possible to use the power of PREG to allow multiple directories, but make sure there are ONLY files which you are comfortable with malicious users downloading. Do not EVER allow directories which contain PHP files here! That could lead to disclosure of sensitive data, including username and password used to connect to WordPress database."
64
  msgstr "Zpracovávány budou pouze soubory, jejichž plná jména (relativní vůči kořenovému adresáři webu) začínají tímto regulárním výrazem. Silně doporučuji umístit všechny stažitelné soubory (a JENOM stažitelné soubory) do jednoho určeného adresáře a vepsat sem název tohoto adresáře zakončený lomítkem. Lze také využít všech možností, které dává PREG, pro povolení více adresářů, ale dejte si pozor, ať v nich jsou JEDINĚ soubory, u kterých vám nevadí, když si je stáhne útočník. NIKDY do těchto adresářů neukládejte žádné PHP soubory! To by mohlo vést k zveřejnění citlivých dat, včetně uživatelského jména a hesla pro připojení k databázi."
65
 
66
+ #: ../simple-download-monitor.php:523
67
  msgid "Default value is <code>files/</code>, which only allows download from /files directory (the leading <code>/</code> is implicit)."
68
  msgstr "Výchozí hodnota je <code>files/</code>, která dovolí stahovat pouze soubory z adresáře /files (úvodní <code>/</code> je dosazeno automaticky)."
69
 
70
+ #: ../simple-download-monitor.php:525
71
  msgid "Allowed extensions"
72
  msgstr "Povolené přípony"
73
 
74
+ #: ../simple-download-monitor.php:526
75
  msgid "Only files with extensions matching this regular expressions will be processed. This is another important security value. Make sure you only add extensions which are safe for malicious users to have, e.g. archives and possibly images. Do NOT use any expression that could allow a user to download PHP files, even if you think it safe given the Allowed Directories option above."
76
  msgstr "Zpracovávány budou pouze soubory, jejichž přípony odpovídají tomuto regulárnímu výrazu. Jde o další důležitý bezpečnostní prvek. Dejte si pozor, ať jsou zde uvedeny pouze takové přípony, které nemohou být zneužity útočníky, tzn. komprimované archívy a případně obrázky. NEPOUŽÍVEJTE výrazy, které by mohly uživateli dovolit download PHP souborů, ani kdyby tyto soubory vylučovalo nastavení \"Povolené adresáře\" výše."
77
 
78
+ #: ../simple-download-monitor.php:527
79
  msgid "Default value is <code>zip|rar|7z</code> which only allows download of files ending with <code>.zip</code>, <code>.rar</code> and <code>.7z</code> (the leading <code>.</code> is implicit)."
80
  msgstr "Výchozí hodnota je <code>zip|rar|7z</code>, která povolí pouze stahování souborů s příponou <code>.zip</code>, <code>.rar</code> a <code>.7z</code> (úvodní <code>.</code> je dosazena automaticky)."
81
 
82
+ #: ../simple-download-monitor.php:529
83
  msgid "Inline files"
84
  msgstr "Soubory pro inline zobrazení"
85
 
86
+ #: ../simple-download-monitor.php:530
87
  msgid "Files whose names match this regular expression will be displayed inline (within a HTML page) rather than downloaded."
88
  msgstr "Soubory, které vyhovují tomuto regulárnímu výrazu, budou zobrazeny inline (jako objekt - např. obrázek nebo video - uvnitř HTML stránky) místo aby se stahovaly."
89
 
90
+ #: ../simple-download-monitor.php:531
91
  msgid "By default, this value is empty - no files will appear inline, all will be downloaded. You may want to place something like <code>\\.(jpe?g|gif|png|swf)$</code> here to make images and Flash videos appear inline."
92
  msgstr "Výchozí hodnotou je prázdný řetězec - všechny soubory se budou stahovat, žádný nebude zobrazen inline. Vepište sem něco jako <code>\\.(jpe?g|gif|png|swf)$</code> pro zobrazování obrázků a Flashů inline."
93
 
94
+ #: ../simple-download-monitor.php:532
95
  msgid "Note: Unlike the options above, nothing is implied in this regular expression. You <em>must</em> use an explicit <code>\\.</code> to denote \"start of extension\", you <em>must</em> use an explicit <code>$</code> to mark \"end of filename\", etc."
96
  msgstr "Pozn.: Narozdíl od nastavení uvedených výše se do tohoto regulárního výrazu nic nedoplňuje. Pokud chcete vyznačit \"začátek přípony\", <em>musíte</em> sem napsat <code>\\.</code>; pokud chcete vyznačit \"konec názvu souboru\", <em>musíte</em> sem napsat <code>$</code>, a podobně."
97
 
98
+ #: ../simple-download-monitor.php:533
99
  msgid "Also note that this plugin uses PCRE-compatible regular expressions, NOT the better-known POSIX-compatible regular expressions. As a result, a valid regular expression must be at least three characters long - separator twice, and at least one character for a meaningful r.e."
100
  msgstr "Dále upozorňuji, že plugin používá PCRE-kompatibilní regulární výrazy a ne známější POSIX-kompatibilní. Z tohoto důvodu je vyžadováno, aby regulární výraz byl aspoň tři znaky dlouhý - dva znaky na dva výskyty oddělovače a aspoň jeden znak pro smysluplný r.e."
101
 
102
+ #: ../simple-download-monitor.php:535
103
  msgid "Store detailed logs?"
104
  msgstr "Ukládat detailní záznamy?"
105
 
106
+ #: ../simple-download-monitor.php:536
107
  msgid "If detailed logs are allowed, various information (including exact time of download, user's IP address, referrer etc.) is stored. This can fill your database quickly if you have only a little space or a lot of popular downloads. Otherwise just the total numbers of downloads are stored, consuming significantly less space."
108
  msgstr "Pokud je tato volba zapnuta, ukládají se detailní informace (jako přesný čas, IP adresa uživatele nebo referer) o každém downloadu. To může rychle zahltit databázi, pokud máte jen málo prostoru nebo populární downloady. Normálně se ukládá jen celkový počet stažení, který zabírá podstatně méně místa."
109
 
110
+ #: ../simple-download-monitor.php:537
111
  msgid "Use detailed statistics."
112
  msgstr "Používat detailní statistiky"
113
 
114
+ #: ../simple-download-monitor.php:538
115
  msgid "Ignored users"
116
  msgstr "Ignorovaní uživatelé"
117
 
118
+ #: ../simple-download-monitor.php:539
119
  msgid "List of users whose downloads are not monitored. Separate multiple users with pipe character <code>|</code>. It is useful to prevent administrator damaging the statistics by testing that downloads work."
120
  msgstr "Seznam uživatelů, jejichž downloady nejsou sledovány. Uživatelská jména oddělujte znakem roury <code>|</code>. Funkce se hodí pro administrátory, kteří chtějí ověřovat funkčnost odkazů, ale nepřejí si, aby se jejich testy zaznamenávaly do statistik."
121
 
122
+ #: ../simple-download-monitor.php:541
123
  msgid "Ignore quick re-downloads"
124
  msgstr "Ignorovat rychlé opakované downloady"
125
 
126
+ #: ../simple-download-monitor.php:542
127
  msgid "If one IP address requests the same download several times within a given time interval, only the first time will be recorded. If a zero or a negative value is entered, all downloads will get recorded regardless of how quickly they occur after each other."
128
  msgstr "Pokud se jedna IP adresa pokusí stáhnout jeden soubor několikrát po sobě v daném časovém intervalu, zaznamená se do statistik jen první pokus. Pokud je rozpětí stanoveno na nula nebo záporné číslo, budou se zaznamenávat všechny downloady, bez ohledu na to, jak rychle po sobě následují."
129
 
130
+ #: ../simple-download-monitor.php:543
131
  msgid "seconds"
132
  msgstr "sekund"
133
 
134
+ #: ../simple-download-monitor.php:544
135
  msgid "Limit number of downloads per IP address"
136
  msgstr "Omezit počet downloadů z jedné IP adresy"
137
 
138
+ #: ../simple-download-monitor.php:545
139
  msgid "Limit the number of files an IP address can download per day. The default value of zero means 'no limits' - an IP address can download as many files as it likes. Note that various download managers can initiate several downloads for each file, so make sure the limit is high enough not to interfere with the normal usage of your site. Also, please understand that this is NOT a perfect solution: One IP address can be shared by multiple users, and one user can easily use more than one IP address."
140
  msgstr "Omezit počet souborů, které může jedna IP adresa stáhnout za jeden den. Výchozí hodnota nula značí \"bez omezení\" - IP adresa může stáhnout libovolné množství souborů. Pozor, různé download managery mohou spustit pro jeden soubor několik stahování najednou; ujistěte se, že je limit dost velký na to, aby bránil v běžném používání vašich stránek. Také si prosím uvědomte, že toto NENÍ dokonalé řešení: Jednu IP adresu může sdílet mnoho uživatelů, a naopak jeden uživatel může mít mnoho IP adres."
141
 
142
+ #: ../simple-download-monitor.php:546
143
  msgid "Users listed in the <strong>Ignored users</strong> section above can always download an unlimited number of files."
144
  msgstr "Uživatelé uvedení v sekci <strong>Ignorovaní uživatelé</strong> výše mohou stahovat neomezený počet souborů."
145
 
146
+ #: ../simple-download-monitor.php:547
147
  msgid "Visitors:"
148
  msgstr "Návštěvníci:"
149
 
150
+ #: ../simple-download-monitor.php:548
151
  msgid "Registered users:"
152
  msgstr "Registrovaní uživatelé"
153
 
154
+ #: ../simple-download-monitor.php:549
155
  msgid "Error message:"
156
  msgstr "Chybová zpráva:"
157
 
158
+ #: ../simple-download-monitor.php:551
159
  #, php-format
160
  msgid "(The first <code>%d</code> will be replaced by number of hours, the second one by number of minutes.)"
161
  msgstr "(První <code>%d</code> bude nahrazeno počtem hodin, druhé počtem minut.)"
162
 
163
+ #: ../simple-download-monitor.php:552
164
+ msgid "Use an intermediate Download page"
165
+ msgstr "Zobrazovat uživateli stránku informující o downloadu"
166
+
167
+ #: ../simple-download-monitor.php:553
168
+ msgid "Before sending the actual requested file, display an intermediate download page which tells the user that the download is about to start."
169
+ msgstr "Před odesláním vyžádaného souboru bude zobrazena stránka, která uživatele informuje o tom, že jeho download co nevidět začne."
170
+
171
+ #: ../simple-download-monitor.php:554
172
+ msgid "Use the intermediate download page."
173
+ msgstr "Zobrazovat informační stránku."
174
+
175
+ #: ../simple-download-monitor.php:555
176
+ msgid "Path to your download page:"
177
+ msgstr "Cesta k informační stránce:"
178
+
179
+ #: ../simple-download-monitor.php:556
180
+ #, php-format
181
+ msgid "You can use <strong>%s</strong> to use a demo page provided with the plugin."
182
+ msgstr "Můžete zde vyplnit <strong>%s</strong> - tím použijete demonstrační stránku dodávanou s pluginem."
183
+
184
+ #: ../simple-download-monitor.php:557
185
+ msgid "This functionality was suggested and for the most part programmed by <a href=\"http://matbra.com\">Matheus Bratfisch</a>, I (Pepak) just cleaned it up and added it to the plugin's distribution."
186
+ msgstr "Tuto funkci navrhl a z větší části naprogramoval <a href=\"http://matbra.com\">Matheus Bratfisch</a>, já (Pepak) jsem ji pouze učesal a přidal do distribučního archívu pluginu."
187
+
188
+ #: ../simple-download-monitor.php:559
189
+ #: ../simple-download-monitor.php:875
190
  msgid "Update settings"
191
  msgstr "Uložit nastavení"
192
 
193
+ #: ../simple-download-monitor.php:684
194
  msgid "First"
195
  msgstr "První"
196
 
197
+ #: ../simple-download-monitor.php:685
198
  msgid "Previous"
199
  msgstr "Předchozí"
200
 
201
+ #: ../simple-download-monitor.php:692
202
  msgid "Next"
203
  msgstr "Další"
204
 
205
+ #: ../simple-download-monitor.php:693
206
  msgid "Last"
207
  msgstr "Poslední"
208
 
209
+ #: ../simple-download-monitor.php:813
210
+ #: ../simple-download-monitor.php:903
211
+ #: ../simple-download-monitor.php:1004
212
+ #: ../simple-download-monitor.php:1005
213
  msgid "Simple Download Monitor"
214
  msgstr "Simple Download Monitor"
215
 
216
+ #: ../simple-download-monitor.php:814
217
  msgid "Nonexistent downloads"
218
  msgstr "Neexistující soubory"
219
 
220
+ #: ../simple-download-monitor.php:814
221
  msgid "All downloads"
222
  msgstr "Všechny downloady"
223
 
224
+ #: ../simple-download-monitor.php:815
225
  msgid "Show all downloads"
226
  msgstr "Zobrazit všechny soubory"
227
 
228
+ #: ../simple-download-monitor.php:815
229
  msgid "Show nonexistent downloads"
230
  msgstr "Zobrazit neexistující soubory"
231
 
232
+ #: ../simple-download-monitor.php:831
233
  msgid "Filename"
234
  msgstr "Název souboru"
235
 
236
+ #: ../simple-download-monitor.php:832
237
  msgid "Download count"
238
  msgstr "Počet stažení"
239
 
240
+ #: ../simple-download-monitor.php:833
241
  msgid "Last date"
242
  msgstr "Poslední datum"
243
 
244
+ #: ../simple-download-monitor.php:834
245
  msgid "Hide from sidebar"
246
  msgstr "Skrýt z postranního panelu"
247
 
248
+ #: ../simple-download-monitor.php:835
249
  msgid "Reset to zero"
250
  msgstr "Vynulovat"
251
 
252
+ #: ../simple-download-monitor.php:860
253
  msgid "Hidden"
254
  msgstr "Skrytý"
255
 
256
+ #: ../simple-download-monitor.php:865
257
  msgid "Reset"
258
  msgstr "Vynulovat"
259
 
260
+ #: ../simple-download-monitor.php:876
261
  msgid "Reset checked statistics"
262
  msgstr "Vymazat označené statistiky"
263
 
264
+ #: ../simple-download-monitor.php:877
265
  msgid "Reset all statistics"
266
  msgstr "Vymazat všechny statistiky"
267
 
268
+ #: ../simple-download-monitor.php:877
269
+ #: ../simple-download-monitor.php:974
270
  msgid "Yes, I am sure"
271
  msgstr "Ano, chci to udělat"
272
 
273
+ #: ../simple-download-monitor.php:904
274
  #, php-format
275
  msgid "Detailed data for <strong>%s</strong>:"
276
  msgstr "Detailní data pro <strong>%s</strong>:"
277
 
278
+ #: ../simple-download-monitor.php:905
279
  #, php-format
280
  msgid "Total number of downloads: <strong>%d</strong>."
281
  msgstr "Celkový počet stažení: <strong>%d</strong>."
282
 
283
+ #: ../simple-download-monitor.php:922
284
  msgid "Date"
285
  msgstr "Datum"
286
 
287
+ #: ../simple-download-monitor.php:923
288
  msgid "Country"
289
  msgstr "Země"
290
 
291
+ #: ../simple-download-monitor.php:924
292
  msgid "IP address"
293
  msgstr "IP adresa"
294
 
295
+ #: ../simple-download-monitor.php:925
296
  msgid "Referer"
297
  msgstr "Referer"
298
 
299
+ #: ../simple-download-monitor.php:926
300
  msgid "Username"
301
  msgstr "Uživatel"
302
 
303
+ #: ../simple-download-monitor.php:963
304
  msgid "Delete this statistic"
305
  msgstr "Vymazat tuto statistiku"
306
 
307
+ #: ../simple-download-monitor.php:971
308
  msgid "Delete checked statistics"
309
  msgstr "Vymazat označené statistiky"
310
 
311
+ #: ../simple-download-monitor.php:974
312
  msgid "Delete all statistics"
313
  msgstr "Vymazat všechny statistiky"
314
 
315
+ #: ../simple-download-monitor.php:978
316
  msgid "Return to full list."
317
  msgstr "Návrat do úplného seznamu"
318
 
319
+ #: ../simple-download-monitor.php:1019
320
  msgid "Allows you to display the most popular downloads in the sidebar."
321
  msgstr "Dovoluje zobrazit v postranním panelu seznam nejoblíbenějších souborů."
322
 
323
+ #: ../simple-download-monitor.php:1064
324
  msgid "Popular files"
325
  msgstr "Oblíbené soubory"
326
 
327
+ #: ../simple-download-monitor.php:1070
328
  msgid "Title:"
329
  msgstr "Zobrazovaný název:"
330
 
331
+ #: ../simple-download-monitor.php:1074
332
  msgid "Number of files to show:"
333
  msgstr "Počet zobrazených souborů:"
334
 
335
+ #: ../simple-download-monitor.php:1077
336
  msgid "Only show filenames which match this LIKE condition:"
337
  msgstr "Zobrazovat pouze soubory, které vyhovují této LIKE podmínce:"
338
 
339
+ #: ../simple-download-monitor.php:1079
340
  msgid "Empty string matches all filenames and is useful for most usage scenarios. You would only use a non-empty value if you wanted to create multiple SDMon widgets, each showing a different list of files: only filenames which match the given string in a LIKE condition of a SQL query will be shown. The most common values would be something like <code>files/documents/%</code> (meaning \"The filename must begin with <code>files/documents/</code>\") or <code>%.mp3</code> (meaning \"The filename must end with <code>.mp3</code>\") - the percentage symbol <code>%</code> means \"anything\", the underscore symbol <code>_</code> means \"Any one character\"."
341
  msgstr "Prázdný řetězec neomezuje seznam souborů a je vhodný pro nejběžnější typy použití. Neprázdnou hodnotu použijte, pokud chcete zobrazit několik nezávislých widgetů, kde každý bude zobrazovat jiný seznam souborů - pak budou zobrazeny jen ty soubory, jejichž názvy vyhoví podmínce. Typické hodnoty vypadají jako <code>files/dokumenty/%</code> (\"Jméno souboru musí začínat <code>files/dokumenty/</code>\") nebo <code>%.mp3</code> (\"Jméno souboru musí končit <code>.mp3</code>\") - symbol procenta <code>%</code> značí \"cokoliv\", symbol podtržítka <code>_</code> značí \"právě jeden libovolný znak\"."
342
 
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: Pepak
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=paypal.com@pepak.net&currency_code=USD
4
  Tags: files, counter, count, tracking, download monitor, monitor, downloads, download
5
  Requires at least: 2.8.0
6
- Tested up to: 3.0.3
7
- Stable tag: 0.21
8
 
9
  Count the number of downloads without having to maintain a comprehensive download page.
10
 
@@ -45,7 +45,7 @@ username of people who download my files.
45
  This is easy enough to do: Open your '.htaccess' file and locate line
46
  `RewriteCond %{REQUEST_FILENAME} !-f`
47
  Add this line directly above it:
48
- `RewriteRule ^(files/.*) /index.php?sdmon=$1 [L]`
49
  (replace 'files/' with your download directory).
50
  1. (Optional step) If you want to see country flags in the download stats page, download,
51
  install, activate and set up my Country-To-IP Plugin ( http://wordpress.org/extend/plugins/ip-to-country/ ).
@@ -118,6 +118,31 @@ http://www.pepak.net/wordpress/simple-download-monitor-plugin/#comment-4729
118
 
119
  == Changelog ==
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  = 0.21 =
122
 
123
  * A fix for the "feature" of WordPress 3.1 which requires manual deactivation
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=paypal.com@pepak.net&currency_code=USD
4
  Tags: files, counter, count, tracking, download monitor, monitor, downloads, download
5
  Requires at least: 2.8.0
6
+ Tested up to: 3.4.1
7
+ Stable tag: 0.22
8
 
9
  Count the number of downloads without having to maintain a comprehensive download page.
10
 
45
  This is easy enough to do: Open your '.htaccess' file and locate line
46
  `RewriteCond %{REQUEST_FILENAME} !-f`
47
  Add this line directly above it:
48
+ `RewriteRule ^(files/.*) /index.php?sdmon=$1 [L,QSA]`
49
  (replace 'files/' with your download directory).
50
  1. (Optional step) If you want to see country flags in the download stats page, download,
51
  install, activate and set up my Country-To-IP Plugin ( http://wordpress.org/extend/plugins/ip-to-country/ ).
118
 
119
  == Changelog ==
120
 
121
+ = 0.22 =
122
+
123
+ * Matheus Bratfisch (http://matbra.com) suggested and implemented an intermediate
124
+ download page. You can use this page to tell the user that his download is
125
+ about to begin, instead of just sending the file directly. To do so, please
126
+ enter the plugin's configuration, check the "Use the intermediate download page."
127
+ checkbox and provide a file path (not a web path!) to the page's source code.
128
+ An example page `download-example.php` is provided in the plugin's directory.
129
+
130
+ Note that if you are already used of Simple Download Monitor and want to use
131
+ this functionality, you'll need to modify your `.htaccess` file (new users
132
+ are not affected as they must have used the configuration listed in the
133
+ documentation and that is the required one already): Change the line
134
+ `RewriteRule ^(files/.*) /index.php?sdmon=$1 [L]`
135
+ to read
136
+ `RewriteRule ^(files/.*) /index.php?sdmon=$1 [L,QSA]`
137
+ (that is, add `,QSA` to the SDMon's rewrite rule's options). Then you can
138
+ open the SDMon configuration and in the "Use an intermediate Download page"
139
+ section enable the intermediate download page. A demo page is provided, but
140
+ you can of course use a different one.
141
+
142
+ I'd like to thank Matheus Bratfisch (http://matbra.com) very much for first
143
+ providing this functionality and then being patient and insistent enough for
144
+ me to incorporate it.
145
+
146
  = 0.21 =
147
 
148
  * A fix for the "feature" of WordPress 3.1 which requires manual deactivation
simple-download-monitor.php CHANGED
@@ -1,1047 +1,1095 @@
1
- <?php
2
-
3
- /*
4
- Plugin Name: Simple Download Monitor
5
- Plugin URI: http://www.pepak.net/wordpress/simple-download-monitor-plugin
6
- Description: Count the number of downloads without having to maintain a comprehensive download page.
7
- Version: 0.21
8
- Author: Pepak
9
- Author URI: http://www.pepak.net
10
- */
11
-
12
- /* Copyright 2009, 2010 Pepak (email: wordpress@pepak.net)
13
-
14
- This program is free software; you can redistribute it and/or modify
15
- it under the terms of the GNU General Public License as published by
16
- the Free Software Foundation; either version 2 of the License, or
17
- (at your option) any later version.
18
-
19
- This program is distributed in the hope that it will be useful,
20
- but WITHOUT ANY WARRANTY; without even the implied warranty of
21
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
- GNU General Public License for more details.
23
-
24
- You should have received a copy of the GNU General Public License
25
- along with this program; if not, write to the Free Software
26
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
- */
28
-
29
- if (!class_exists('SimpleDownloadMonitor'))
30
- {
31
- class SimpleDownloadMonitor
32
- {
33
-
34
- const VERSION = '0.21';
35
- const PREFIX = 'sdmon_';
36
- const PREG_DELIMITER = '`';
37
- const GET_PARAM = 'sdmon';
38
- const RECORDS_PER_PAGE = 20;
39
- const GETTEXT_REALM = 'simple-download-monitor';
40
-
41
- protected $plugin_url = '';
42
- protected $plugin_dir = '';
43
- protected $plugin_dir_relative = '';
44
-
45
- public function SimpleDownloadMonitor()
46
- {
47
- $this->plugin_url = WP_PLUGIN_URL . '/' . dirname(plugin_basename(__FILE__));
48
- $this->plugin_dir = WP_PLUGIN_DIR . '/' . dirname(plugin_basename(__FILE__));
49
- if (strpos($this->plugin_dir, ABSPATH) === 0)
50
- $this->plugin_dir_relative = substr($this->plugin_dir, strlen(ABSPATH));
51
- else
52
- $this->plugin_dir_relative = $this->plugin_dir;
53
- register_activation_hook(__FILE__, array('SimpleDownloadMonitor', 'Install'));
54
- add_action('init', array(&$this, 'ActionInit'));
55
- add_action('admin_menu', 'SimpleDownloadMonitor_BuildAdminMenu');
56
- if (self::VERSION != get_option(self::PREFIX . 'version'))
57
- self::Install();
58
- }
59
-
60
- public static function Install()
61
- {
62
- global $wpdb;
63
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
64
- $table_downloads = $wpdb->prefix . self::PREFIX . 'downloads';
65
- $sql = "CREATE TABLE ${table_downloads} (
66
- id INTEGER NOT NULL AUTO_INCREMENT,
67
- filename VARCHAR(1024) NOT NULL,
68
- download_count INTEGER NOT NULL,
69
- last_date TIMESTAMP NOT NULL,
70
- file_exists TINYINT,
71
- hide_from_sidebar TINYINT,
72
- PRIMARY KEY id (id),
73
- KEY download_count (download_count),
74
- KEY last_date (last_date)
75
- );";
76
- dbDelta($sql);
77
- $table_details = $wpdb->prefix . self::PREFIX . 'details';
78
- $sql = "CREATE TABLE ${table_details} (
79
- id INTEGER NOT NULL AUTO_INCREMENT,
80
- download INTEGER NOT NULL,
81
- download_date TIMESTAMP NOT NULL,
82
- ip VARCHAR(64) NOT NULL,
83
- referer TEXT,
84
- userid INTEGER,
85
- username VARCHAR(64),
86
- PRIMARY KEY id (id),
87
- KEY download (download),
88
- KEY download_date (download_date)
89
- );";
90
- dbDelta($sql);
91
- update_option(self::PREFIX . 'table_downloads', $table_downloads);
92
- update_option(self::PREFIX . 'table_details', $table_details);
93
- update_option(self::PREFIX . 'version', self::VERSION);
94
- add_option(self::PREFIX . 'directories', 'files/');
95
- add_option(self::PREFIX . 'extensions', 'zip|rar|7z');
96
- add_option(self::PREFIX . 'detailed', '0');
97
- add_option(self::PREFIX . 'inline', '');
98
- add_option(self::PREFIX . 'ignored_users', '');
99
- add_option(self::PREFIX . 'group_within', '0');
100
- add_option(self::PREFIX . 'rights_view', 'read');
101
- add_option(self::PREFIX . 'rights_delete', 'delete_users');
102
- add_option(self::PREFIX . 'rights_options', 'manage_options');
103
- add_option(self::PREFIX . 'max_downloads_per_ip_and_day', '0');
104
- add_option(self::PREFIX . 'max_downloads_per_ip_and_day_registered', '0');
105
- add_option(self::PREFIX . 'error_download_limit', '');
106
- }
107
-
108
- public function table_downloads()
109
- {
110
- static $table = null;
111
- if ($table == null)
112
- $table = get_option(self::PREFIX . 'table_downloads');
113
- return $table;
114
- }
115
-
116
- public function table_details()
117
- {
118
- static $table = null;
119
- if ($table == null)
120
- $table = get_option(self::PREFIX . 'table_details');
121
- return $table;
122
- }
123
-
124
- //-----------------------------------------------------------------------------------
125
- // Methods set_range, buffered_read, byteserve adapted from
126
- // http://www.coneural.org/florian/papers/04_byteserving.php
127
-
128
- function set_range($range, $filesize, &$first, &$last){
129
- /*
130
- Sets the first and last bytes of a range, given a range expressed as a string
131
- and the size of the file.
132
-
133
- If the end of the range is not specified, or the end of the range is greater
134
- than the length of the file, $last is set as the end of the file.
135
-
136
- If the begining of the range is not specified, the meaning of the value after
137
- the dash is "get the last n bytes of the file".
138
-
139
- If $first is greater than $last, the range is not satisfiable, and we should
140
- return a response with a status of 416 (Requested range not satisfiable).
141
-
142
- Examples:
143
- $range='0-499', $filesize=1000 => $first=0, $last=499 .
144
- $range='500-', $filesize=1000 => $first=500, $last=999 .
145
- $range='500-1200', $filesize=1000 => $first=500, $last=999 .
146
- $range='-200', $filesize=1000 => $first=800, $last=999 .
147
-
148
- */
149
- $dash=strpos($range,'-');
150
- $first=trim(substr($range,0,$dash));
151
- $last=trim(substr($range,$dash+1));
152
- if ($first=='') {
153
- //suffix byte range: gets last n bytes
154
- $suffix=$last;
155
- $last=$filesize-1;
156
- $first=$filesize-$suffix;
157
- if($first<0) $first=0;
158
- } else {
159
- if ($last=='' || $last>$filesize-1) $last=$filesize-1;
160
- }
161
- if($first>$last){
162
- //unsatisfiable range
163
- header("Status: 416 Requested range not satisfiable");
164
- header("Content-Range: */$filesize");
165
- exit;
166
- }
167
- }
168
-
169
- function buffered_read($file, $bytes, $buffer_size=65536){
170
- /*
171
- Outputs up to $bytes from the file $file to standard output, $buffer_size bytes at a time.
172
- */
173
- $bytes_left=$bytes;
174
- while($bytes_left>0 && !feof($file)){
175
- if($bytes_left>$buffer_size)
176
- $bytes_to_read=$buffer_size;
177
- else
178
- $bytes_to_read=$bytes_left;
179
- $bytes_left-=$bytes_to_read;
180
- $contents=fread($file, $bytes_to_read);
181
- echo $contents;
182
- flush();
183
- }
184
- }
185
-
186
- function byteserve($filename, $mimetype, $disposition = ''){
187
- /*
188
- Byteserves the file $filename.
189
-
190
- When there is a request for a single range, the content is transmitted
191
- with a Content-Range header, and a Content-Length header showing the number
192
- of bytes actually transferred.
193
-
194
- When there is a request for multiple ranges, these are transmitted as a
195
- multipart message. The multipart media type used for this purpose is
196
- "multipart/byteranges".
197
- */
198
-
199
- // Clean all buffering components, if any.
200
- while (ob_list_handlers())
201
- ob_end_clean();
202
-
203
- $filesize=filesize($filename);
204
- $file=fopen($filename,"rb");
205
-
206
- $ranges=NULL;
207
- if ($_SERVER['REQUEST_METHOD']=='GET' && isset($_SERVER['HTTP_RANGE']) && $range=stristr(trim($_SERVER['HTTP_RANGE']),'bytes=')){
208
- $range=substr($range,6);
209
- $boundary=sha1(uniqid());//set a random boundary
210
- $ranges=explode(',',$range);
211
- }
212
-
213
- if($ranges && count($ranges)){
214
- header("HTTP/1.1 206 Partial content");
215
- header("Accept-Ranges: bytes");
216
- if(count($ranges)>1){
217
- /*
218
- More than one range is requested.
219
- */
220
-
221
- //compute content length
222
- $content_length=0;
223
- foreach ($ranges as $range){
224
- $this->set_range($range, $filesize, $first, $last);
225
- $content_length+=strlen("\r\n--$boundary\r\n");
226
- $content_length+=strlen("Content-type: $mimetype\r\n");
227
- $content_length+=strlen("Content-range: bytes $first-$last/$filesize\r\n\r\n");
228
- $content_length+=$last-$first+1;
229
- }
230
- $content_length+=strlen("\r\n--$boundary--\r\n");
231
-
232
- //output headers
233
- header("Content-Length: $content_length");
234
- //see http://httpd.apache.org/docs/misc/known_client_problems.html for an discussion of x-byteranges vs. byteranges
235
- header("Content-Type: multipart/x-byteranges; boundary=$boundary");
236
-
237
- //output the content
238
- foreach ($ranges as $range){
239
- $this->set_range($range, $filesize, $first, $last);
240
- echo "\r\n--$boundary\r\n";
241
- echo "Content-type: $mimetype\r\n";
242
- echo "Content-range: bytes $first-$last/$filesize\r\n\r\n";
243
- fseek($file,$first);
244
- $this->buffered_read ($file, $last-$first+1);
245
- }
246
- echo "\r\n--$boundary--\r\n";
247
- } else {
248
- /*
249
- A single range is requested.
250
- */
251
- $range=$ranges[0];
252
- $this->set_range($range, $filesize, $first, $last);
253
- header("Content-Length: ".($last-$first+1) );
254
- header("Content-Range: bytes $first-$last/$filesize");
255
- header("Content-Type: $mimetype");
256
- if ($disposition)
257
- header("Content-Disposition: $disposition");
258
- fseek($file,$first);
259
- $this->buffered_read($file, $last-$first+1);
260
- }
261
- } else{
262
- //no byteserving
263
- header("Accept-Ranges: bytes");
264
- header("Content-Length: $filesize");
265
- header("Content-Type: $mimetype");
266
- if ($disposition)
267
- header("Content-Disposition: $disposition");
268
- $this->buffered_read($file, $filesize);
269
- }
270
- fclose($file);
271
- }
272
- //-----------------------------------------------------------------------------------
273
-
274
- protected function ErrorMessage($code, $message, $shortmessage)
275
- {
276
- $code = intval($code);
277
- // Clean all buffering components, if any.
278
- while (ob_list_handlers())
279
- ob_end_clean();
280
- header('Cache-control: no-cache');
281
- if ($code >= 200)
282
- header(sprintf('%s %d %s', $_SERVER["SERVER_PROTOCOL"], $code, $shortmessage));
283
- get_header();
284
- ?><div class="error">
285
- <h2><?php echo __("Simple Download Monitor error", self::GETTEXT_REALM); ?></h2>
286
- <p><?php echo $message; ?></p>
287
- <?php
288
- get_sidebar();
289
- get_footer();
290
- die();
291
- }
292
-
293
- public function Download($filename)
294
- {
295
- global $wpdb, $user_login, $user_ID;
296
- $store_details = intval(get_option(self::PREFIX . 'detailed'));
297
- $details = $this->table_details();
298
- $downloads = $this->table_downloads();
299
- $ip_addr = $_SERVER['REMOTE_ADDR'];
300
- // Normalize the filename
301
- $fullfilename = realpath(ABSPATH . '/' . $filename);
302
- $relfilename = substr($fullfilename, strlen(ABSPATH));
303
- $relfilename = strtr($relfilename, '\\', '/');
304
- $exists = (file_exists($fullfilename) AND !is_dir($fullfilename)) ? 1 : 0;
305
- // Make sure it is a valid request
306
- $dirregexp = self::PREG_DELIMITER . '^' . get_option(self::PREFIX . 'directories') . self::PREG_DELIMITER;
307
- $extregexp = self::PREG_DELIMITER . '\\.' . get_option(self::PREFIX . 'extensions') . '$' . self::PREG_DELIMITER;
308
- $valid = (preg_match($dirregexp, $relfilename) AND preg_match($extregexp, $relfilename)) ? 1 : 0;
309
- // Get user information and decide if this user should be ignored
310
- get_currentuserinfo();
311
- $userid = $user_ID ? $user_ID : null;
312
- $username = $user_login ? $user_login : null;
313
- $ignored_users = get_option(self::PREFIX . 'ignored_users');
314
- $monitor = empty($username) || empty($ignored_users) || (!in_array($username, explode('|', $ignored_users)));
315
- if ($monitor)
316
- {
317
- // Check the number of downloads per IP and day
318
- $max_downloads = intval(get_option(self::PREFIX . (is_user_logged_in() ? 'max_downloads_per_ip_and_day_registered' : 'max_downloads_per_ip_and_day')));
319
- if ($max_downloads > 0)
320
- {
321
- $row = $wpdb->get_row($wpdb->prepare("SELECT COUNT(*) count, MIN(TIMESTAMPDIFF(MINUTE, NOW(), TIMESTAMPADD(DAY, 1, download_date))) retry FROM ${details} WHERE (download_date > TIMESTAMPADD(DAY, -1, NOW())) AND ip=%s", $ip_addr), ARRAY_N);
322
- list($download_count, $retry_minutes) = $row;
323
- if ($download_count >= $max_downloads)
324
- {
325
- $msg = get_option(self::PREFIX . 'error_download_limit');
326
- if ($msg == '') $msg = __("You have exceeded your download quota today. Please try again in %d hours and %d minutes.", self::GETTEXT_REALM);
327
- $this->ErrorMessage(403, sprintf($msg, $retry_minutes/60, abs($retry_minutes%60)), 'Forbidden');
328
- }
329
- }
330
- // Store uncorrected request name to database for security/mistake review
331
- $id = $wpdb->get_var($wpdb->prepare("SELECT id FROM ${downloads} WHERE filename=%s", $filename));
332
- if ($id)
333
- {
334
- // Ignore quick downloads by the same user
335
- if ($store_details && (($group_within = intval(get_option(self::PREFIX . 'group_within'))) > 0))
336
- {
337
- $grouped_id = $wpdb->get_var($wpdb->prepare("SELECT MIN(id) FROM ${details} WHERE download=%d AND (download_date > DATE_ADD(NOW(), INTERVAL -%d SECOND)) AND ip=%s", $id, $group_within, $ip_addr));
338
- if (intval($grouped_id) > 0)
339
- $monitor = FALSE;
340
- }
341
- if ($monitor)
342
- {
343
- $sql = "UPDATE ${downloads} SET download_count=download_count+1, last_date=NOW(), file_exists=%d WHERE id=%d";
344
- $wpdb->query($wpdb->prepare($sql, $exists * $valid, $id));
345
- }
346
- }
347
- else
348
- {
349
- $sql = "INSERT INTO ${downloads} (filename, download_count, last_date, file_exists) VALUES (%s, 1, NOW(), %d)";
350
- $wpdb->query($wpdb->prepare($sql, $filename, $exists * $valid));
351
- $id = $wpdb->insert_id;
352
- }
353
- // If details are requested, store them as well
354
- if ($monitor && $store_details)
355
- {
356
- $sql = "INSERT INTO ${details} (download, download_date, ip, referer, username, userid) VALUES (%d, NOW(), %s, %s, %s, %d)";
357
- $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
358
- if (!$username AND isset($_COOKIE['comment_author_'.COOKIEHASH]))
359
- $username = utf8_encode($_COOKIE['comment_author_'.COOKIEHASH]);
360
- $wpdb->query($wpdb->prepare($sql, $id, $ip_addr, $referer, $username, $userid));
361
- }
362
- }
363
- // If the file exists and is valid, download it
364
- // Make sure the file is available for download
365
- if (!$exists OR !$valid)
366
- $this->ErrorMessage(404, sprintf(__("Requested file <strong>%s</strong> not found."), htmlspecialchars($filename)), 'Not found');
367
- // Generate proper headers
368
- $mimetype = '';
369
- if (function_exists('finfo_open') AND defined('FILEINFO_MIME_TYPE'))
370
- {
371
- $finfo = finfo_open(FILEINFO_MIME_TYPE);
372
- $mimetype = finfo_file($finfo, $fullfilename);
373
- }
374
- if (!$mimetype && function_exists('mime_content_type'))
375
- $mimetype = mime_content_type($fullfilename);
376
- if (!$mimetype || ((strpos($mimetype, '/')) === FALSE))
377
- $mimetype = 'application/octet-stream';
378
- $disposition = 'attachment';
379
- $inlineregexp = self::PREG_DELIMITER . get_option(self::PREFIX . 'inline') . self::PREG_DELIMITER;
380
- if ($inlineregexp && preg_match($inlineregexp, $relfilename))
381
- $disposition = 'inline';
382
- $disposition = $disposition . '; filename="' . basename($fullfilename) . '"';
383
- $this->byteserve($fullfilename, $mimetype, $disposition);
384
- // Successful end
385
- return TRUE;
386
- }
387
-
388
- public function ActionInit() {
389
- // Function is called in 'init' hook. It checks for download and if so, stops normal WordPress processing
390
- // and replaces it with its monitoring functions.
391
- $currentLocale = get_locale();
392
- if(!empty($currentLocale))
393
- {
394
- $moFile = $this->plugin_dir . "/lang/" . $currentLocale . ".mo";
395
- if(@file_exists($moFile) && is_readable($moFile))
396
- load_textdomain(self::GETTEXT_REALM, $moFile);
397
- }
398
- //load_plugin_textdomain(self::GETTEXT_REALM, $this->plugin_dir . '/lang');
399
- if (isset($_GET[self::GET_PARAM]) && ($filename = $_GET[self::GET_PARAM]))
400
- {
401
- if ($this->Download($filename))
402
- die();
403
- else
404
- wp_redirect(get_option('site_url'));
405
- }
406
- }
407
-
408
- public function AdminPanel()
409
- {
410
- // Function draws the admin panel.
411
- // First, post any modified options
412
- if (isset($_POST['SimpleDownloadMonitor_Submit']))
413
- {
414
- // Read options from the form
415
- $directories = strval($_POST[self::PREFIX . 'directories']);
416
- $extensions = strval($_POST[self::PREFIX . 'extensions']);
417
- $detailed = intval($_POST[self::PREFIX . 'detailed']);
418
- $inline = strval($_POST[self::PREFIX . 'inline']);
419
- $ignored_users = strval($_POST[self::PREFIX . 'ignored_users']);
420
- $group_within = intval($_POST[self::PREFIX . 'group_within']);
421
- $rights_view = strval($_POST[self::PREFIX . 'rights_view']);
422
- $rights_delete = strval($_POST[self::PREFIX . 'rights_delete']);
423
- $rights_options = strval($_POST[self::PREFIX . 'rights_options']);
424
- $downloads_per_day = intval($_POST[self::PREFIX . 'max_downloads_per_ip_and_day']);
425
- $downloads_per_day_registered = intval($_POST[self::PREFIX . 'max_downloads_per_ip_and_day_registered']);
426
- $error_download_limit = strval($_POST[self::PREFIX . 'error_download_limit']);
427
- // Remove slashes if necessary
428
- if (get_magic_quotes_gpc())
429
- {
430
- $directories = stripslashes($directories);
431
- $extensions = stripslashes($extensions);
432
- $inline = stripslashes($inline);
433
- $ignored_users = stripslashes($ignored_users);
434
- $error_download_limit = stripslashes($error_download_limit);
435
- }
436
- // Escape the delimiter
437
- list($directories, $extensions) = str_replace(self::PREG_DELIMITER, '\\'.self::PREG_DELIMITER, array($directories, $extensions));
438
- // Write the changes to database
439
- update_option(self::PREFIX . 'directories', $directories);
440
- update_option(self::PREFIX . 'extensions', $extensions);
441
- update_option(self::PREFIX . 'detailed', $detailed);
442
- if (($inline == '') OR (strlen($inline) >= 3))
443
- update_option(self::PREFIX . 'inline', $inline);
444
- update_option(self::PREFIX . 'ignored_users', $ignored_users);
445
- update_option(self::PREFIX . 'group_within', $group_within);
446
- update_option(self::PREFIX . 'rights_view', $rights_view);
447
- update_option(self::PREFIX . 'rights_delete', $rights_delete);
448
- update_option(self::PREFIX . 'rights_options', $rights_options);
449
- update_option(self::PREFIX . 'max_downloads_per_ip_and_day', $downloads_per_day);
450
- update_option(self::PREFIX . 'max_downloads_per_ip_and_day_registered', $downloads_per_day_registered);
451
- update_option(self::PREFIX . 'error_download_limit', $error_download_limit);
452
- }
453
- // Load options from the database
454
- $directories = get_option(self::PREFIX . 'directories');
455
- $extensions = get_option(self::PREFIX . 'extensions');
456
- $detailed = get_option(self::PREFIX . 'detailed');
457
- $inline = get_option(self::PREFIX . 'inline');
458
- $ignored_users = get_option(self::PREFIX . 'ignored_users');
459
- $group_within = intval(get_option(self::PREFIX . 'group_within'));
460
- $rights_view = get_option(self::PREFIX . 'rights_view');
461
- $rights_delete = get_option(self::PREFIX . 'rights_delete');
462
- $rights_options = get_option(self::PREFIX . 'rights_options');
463
- $downloads_per_day = get_option(self::PREFIX . 'max_downloads_per_ip_and_day');
464
- $downloads_per_day_registered = get_option(self::PREFIX . 'max_downloads_per_ip_and_day_registered');
465
- $error_download_limit = get_option(self::PREFIX . 'error_download_limit');
466
- // Build the form
467
- ?>
468
- <div class="wrap">
469
- <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
470
- <h2><?php echo __('Simple Download Monitor options', self::GETTEXT_REALM); ?></h2>
471
- <h3><?php echo __('Access rights', self::GETTEXT_REALM); ?></h3>
472
- <p><?php echo __('You can set up user rights required to access various functions of Simple Download Monitor. Rights are assigned through capabilities (see <a href="http://codex.wordpress.org/Roles_and_Capabilities#Roles">Roles and Capabilities</a> in WordPress Codex). Predefined values are <strong>read</strong> ("any registered user") for displaying stats, <strong>delete_users</strong> ("administrator") for reseting stats and <strong>manage_options</strong> ("administrator") for changing options.', self::GETTEXT_REALM); ?></p>
473
- <p><?php echo __('Capability required for viewing download stats:', self::GETTEXT_REALM); ?></p>
474
- <p><input type="text" name="<?php echo self::PREFIX; ?>rights_view" value="<?php echo esc_attr($rights_view); ?>" /></p>
475
- <p><?php echo __('Capability required for reseting download stats:', self::GETTEXT_REALM); ?></p>
476
- <p><input type="text" name="<?php echo self::PREFIX; ?>rights_delete" value="<?php echo esc_attr($rights_delete); ?>" /></p>
477
- <p><?php echo __('Capability required for setting SDMON options:', self::GETTEXT_REALM); ?></p>
478
- <p><input type="text" name="<?php echo self::PREFIX; ?>rights_options" value="<?php echo esc_attr($rights_options); ?>" /></p>
479
- <h3><?php echo __('Allowed directories', self::GETTEXT_REALM); ?></h3>
480
- <p><?php echo __("Only requested files whose full names (relative to document root) start with this regular expression will be processed. It is strongly recommended to place all downloadable files (and ONLY downloadable files) into a designated directory and then placing that directory's name followed by a slash here. It is possible to use the power of PREG to allow multiple directories, but make sure there are ONLY files which you are comfortable with malicious users downloading. Do not EVER allow directories which contain PHP files here! That could lead to disclosure of sensitive data, including username and password used to connect to WordPress database.", self::GETTEXT_REALM); ?></p>
481
- <p><?php echo __("Default value is <code>files/</code>, which only allows download from /files directory (the leading <code>/</code> is implicit).", self::GETTEXT_REALM); ?></p>
482
- <p><input type="text" name="<?php echo self::PREFIX; ?>directories" value="<?php echo esc_attr($directories); ?>" /></p>
483
- <h3><?php echo __('Allowed extensions', self::GETTEXT_REALM); ?></h3>
484
- <p><?php echo __('Only files with extensions matching this regular expressions will be processed. This is another important security value. Make sure you only add extensions which are safe for malicious users to have, e.g. archives and possibly images. Do NOT use any expression that could allow a user to download PHP files, even if you think it safe given the Allowed Directories option above.', self::GETTEXT_REALM); ?></p>
485
- <p><?php echo __("Default value is <code>zip|rar|7z</code> which only allows download of files ending with <code>.zip</code>, <code>.rar</code> and <code>.7z</code> (the leading <code>.</code> is implicit).", self::GETTEXT_REALM); ?></p>
486
- <p><input type="text" name="<?php echo self::PREFIX; ?>extensions" value="<?php echo esc_attr($extensions); ?>" /></p>
487
- <h3><?php echo __('Inline files', self::GETTEXT_REALM); ?></h3>
488
- <p><?php echo __('Files whose names match this regular expression will be displayed inline (within a HTML page) rather than downloaded.', self::GETTEXT_REALM); ?></p>
489
- <p><?php echo __("By default, this value is empty - no files will appear inline, all will be downloaded. You may want to place something like <code>\.(jpe?g|gif|png|swf)$</code> here to make images and Flash videos appear inline.", self::GETTEXT_REALM); ?></p>
490
- <p><?php echo __('Note: Unlike the options above, nothing is implied in this regular expression. You <em>must</em> use an explicit <code>\.</code> to denote "start of extension", you <em>must</em> use an explicit <code>$</code> to mark "end of filename", etc.', self::GETTEXT_REALM); ?></p>
491
- <p><?php echo __('Also note that this plugin uses PCRE-compatible regular expressions, NOT the better-known POSIX-compatible regular expressions. As a result, a valid regular expression must be at least three characters long - separator twice, and at least one character for a meaningful r.e.', self::GETTEXT_REALM); ?></p>
492
- <p><input type="text" name="<?php echo self::PREFIX; ?>inline" value="<?php echo esc_attr($inline); ?>" /></p>
493
- <h3><?php echo __("Store detailed logs?", self::GETTEXT_REALM); ?></h3>
494
- <p><?php echo __("If detailed logs are allowed, various information (including exact time of download, user's IP address, referrer etc.) is stored. This can fill your database quickly if you have only a little space or a lot of popular downloads. Otherwise just the total numbers of downloads are stored, consuming significantly less space.", self::GETTEXT_REALM); ?></p>
495
- <p><label for="<?php echo self::PREFIX; ?>detailed"><input type="checkbox" name="<?php echo self::PREFIX; ?>detailed" value="1" <?php if ($detailed) echo 'checked="checked" '; ?>/> <?php echo __('Use detailed statistics.', self::GETTEXT_REALM); ?></label></p>
496
- <h3><?php echo __("Ignored users", self::GETTEXT_REALM); ?></h3>
497
- <p><?php echo __("List of users whose downloads are not monitored. Separate multiple users with pipe character <code>|</code>. It is useful to prevent administrator damaging the statistics by testing that downloads work.", self::GETTEXT_REALM); ?></p>
498
- <p><input type="text" name="<?php echo self::PREFIX; ?>ignored_users" value="<?php echo esc_attr($ignored_users); ?>" /></p>
499
- <h3><?php echo __("Ignore quick re-downloads", self::GETTEXT_REALM); ?></h3>
500
- <p><?php echo __("If one IP address requests the same download several times within a given time interval, only the first time will be recorded. If a zero or a negative value is entered, all downloads will get recorded regardless of how quickly they occur after each other.", self::GETTEXT_REALM); ?></p>
501
- <p><input type="text" name="<?php echo self::PREFIX; ?>group_within" value="<?php echo esc_attr($group_within); ?>" /> <?php echo __('seconds', self::GETTEXT_REALM); ?></p>
502
- <h3><?php echo __("Limit number of downloads per IP address", self::GETTEXT_REALM); ?></h3>
503
- <p><?php echo __("Limit the number of files an IP address can download per day. The default value of zero means 'no limits' - an IP address can download as many files as it likes. Note that various download managers can initiate several downloads for each file, so make sure the limit is high enough not to interfere with the normal usage of your site. Also, please understand that this is NOT a perfect solution: One IP address can be shared by multiple users, and one user can easily use more than one IP address.", self::GETTEXT_REALM); ?></p>
504
- <p><?php echo __("Users listed in the <strong>Ignored users</strong> section above can always download an unlimited number of files.", self::GETTEXT_REALM); ?></p>
505
- <p><?php echo __("Visitors:", self::GETTEXT_REALM); ?> <input type="text" name="<?php echo self::PREFIX; ?>max_downloads_per_ip_and_day" value="<?php echo esc_attr($downloads_per_day); ?>" /></p>
506
- <p><?php echo __("Registered users:", self::GETTEXT_REALM); ?> <input type="text" name="<?php echo self::PREFIX; ?>max_downloads_per_ip_and_day_registered" value="<?php echo esc_attr($downloads_per_day_registered); ?>" /></p>
507
- <p><?php echo __("Error message:", self::GETTEXT_REALM); ?></p>
508
- <p><textarea name="<?php echo self::PREFIX; ?>error_download_limit" rows="4" cols="64"><?php echo htmlspecialchars($error_download_limit); ?></textarea></p>
509
- <p><?php echo __("(The first <code>%d</code> will be replaced by number of hours, the second one by number of minutes.)", self::GETTEXT_REALM); ?>
510
- <p>&nbsp;</p>
511
- <div class="submit"><input type="submit" name="SimpleDownloadMonitor_Submit" value="<?php echo __("Update settings", self::GETTEXT_REALM) ?>" /></div>
512
- </form>
513
- </div><?php
514
- }
515
-
516
- public function ToolsPanel()
517
- {
518
- $download = isset($_GET['download']) ? intval($_GET['download']) : 0;
519
- $from = isset($_GET['from']) ? intval($_GET['from']) : 0;
520
- $order = isset($_GET['order']) ? $_GET['order'] : '';
521
- $flags = isset($_GET['flags']) ? intval($_GET['flags']) : 0;
522
- $detailed = get_option(self::PREFIX . 'detailed');
523
- $options = array('download' => $download, 'from' => $from, 'order' => $order, 'flags' => $flags);
524
- if ($this->IsAdmin())
525
- {
526
- if (isset($_POST['SimpleDownloadMonitor_Update']) && isset($_POST['SimpleDownloadMonitor_HideIds']) && is_array($_POST['SimpleDownloadMonitor_HideIds']) && isset($_POST['SimpleDownloadMonitor_ShowIds']) && is_array($_POST['SimpleDownloadMonitor_ShowIds']))
527
- {
528
- $this->HideDownloads($_POST['SimpleDownloadMonitor_ShowIds'], $_POST['SimpleDownloadMonitor_HideIds']);
529
- }
530
- if (isset($_POST['SimpleDownloadMonitor_Delete']) && isset($_POST['SimpleDownloadMonitor_DeleteIds']) && is_array($_POST['SimpleDownloadMonitor_DeleteIds']))
531
- {
532
- $this->DeleteDownloads($_POST['SimpleDownloadMonitor_DeleteIds']);
533
- }
534
- elseif (isset($_POST['SimpleDownloadMonitor_DeleteAll']) && ($_POST['SimpleDownloadMonitor_DeleteAllReally'] == 'yes'))
535
- {
536
- $this->DeleteAllDownloads();
537
- }
538
- if (isset($_POST['SimpleDownloadMonitor_DeleteDetail']) && isset($_POST['SimpleDownloadMonitor_DeleteIds']) && is_array($_POST['SimpleDownloadMonitor_DeleteIds']))
539
- {
540
- $this->DeleteDownloadDetails($_POST['SimpleDownloadMonitor_DeleteIds']);
541
- }
542
- }
543
- if ($detailed && $download)
544
- $this->DetailedDownloadList($options);
545
- else
546
- $this->DownloadList($options);
547
- }
548
-
549
- const ORDER_NAME = 'name';
550
- const ORDER_COUNT = 'count';
551
- const ORDER_DATE = 'date';
552
- const ORDER_IP = 'ip';
553
- const ORDER_REFERER = 'referer';
554
- const ORDER_USER = 'user';
555
-
556
- protected function GetOrderBy($order = '')
557
- {
558
- static $orders = array(
559
- self::ORDER_NAME => 'filename',
560
- self::ORDER_COUNT => 'download_count DESC, filename',
561
- self::ORDER_DATE => 'last_date DESC, filename',
562
- );
563
- $result = isset($orders[$order]) ? $orders[$order] : $orders[self::ORDER_COUNT];
564
- $result = " ORDER BY ${result} ";
565
- return $result;
566
- }
567
-
568
- protected function GetDetailOrderBy($order = '')
569
- {
570
- static $orders = array(
571
- self::ORDER_DATE => 'download_date DESC',
572
- self::ORDER_IP => 'ip, download_date DESC',
573
- self::ORDER_REFERER => 'referer, download_date DESC',
574
- self::ORDER_USER => 'username, download_date DESC',
575
- );
576
- $result = isset($orders[$order]) ? $orders[$order] : $orders[self::ORDER_DATE];
577
- $result = " ORDER BY ${result} ";
578
- return $result;
579
- }
580
-
581
- const FLAGS_NOTEXISTING = 1;
582
-
583
- protected function GetWhere($flags = 0)
584
- {
585
- $conditions = array();
586
- if ($flags & self::FLAGS_NOTEXISTING)
587
- $conditions[] = '(file_exists=0)';
588
- else
589
- $conditions[] = '(file_exists<>0)';
590
- if ($conditions)
591
- $result = ' WHERE ' . implode(' AND ', $conditions);
592
- else
593
- $result = '';
594
- return $result;
595
- }
596
-
597
- protected function GetDetailWhere($flags = 0)
598
- {
599
- $conditions = array();
600
- if ($conditions)
601
- $result = ' AND ' . implode(' AND ', $conditions);
602
- else
603
- $result = '';
604
- return $result;
605
- }
606
-
607
- protected function GetLimit($from = 0)
608
- {
609
- $from = intval($from);
610
- if ($from < 0)
611
- $from = 0;
612
- $count = self::RECORDS_PER_PAGE;
613
- $result = " LIMIT ${from}, ${count} ";
614
- return $result;
615
- }
616
-
617
- protected function GetUrlForList($options = array(), $html = TRUE)
618
- {
619
- $amp = $html ? '&amp;' : '&';
620
- $result = get_option('site_url') . 'tools.php?page=' . basename(__FILE__);
621
- foreach ($options as $name => $value)
622
- if ($value)
623
- $result .= $amp . ($html ? htmlspecialchars($name) : $name) . '=' . ($html ? htmlspecialchars($value) : $value);
624
- return $result;
625
-
626
- }
627
-
628
- protected function Paginator($options, $count)
629
- {
630
- $from = intval($options['from']);
631
- $count = intval($count);
632
- $pages = array();
633
- if ($from > 0)
634
- {
635
- $pages[] = '<div style="float: left;">';
636
- $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>0))) . '">' . __("First", self::GETTEXT_REALM) . '</a>';
637
- $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>($from>self::RECORDS_PER_PAGE ? $from-self::RECORDS_PER_PAGE : 0)))) . '">' . __("Previous", self::GETTEXT_REALM) . '</a>';
638
- $pages[] = '</div>';
639
- }
640
-
641
- if (($from + self::RECORDS_PER_PAGE) < $count)
642
- {
643
- $pages[] = '<div style="float: right;">';
644
- $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>$from+self::RECORDS_PER_PAGE))) . '">' . __("Next", self::GETTEXT_REALM) . '</a>';
645
- $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>$count-self::RECORDS_PER_PAGE))) . '">' . __("Last", self::GETTEXT_REALM) . '</a>';
646
- $pages[] = '</div>';
647
- }
648
- $result = $pages ? '<div class="pages-list">' . implode(' ', $pages) . '<div style="clear: both;" /></div>' : '';
649
- return $result;
650
- }
651
-
652
- protected function IsAdmin()
653
- {
654
- if (current_user_can(get_option(self::PREFIX . 'rights_delete')))
655
- /*
656
- global $user_level;
657
- get_currentuserinfo();
658
- if ($user_level >= 10)
659
- */
660
- return TRUE;
661
- else
662
- return FALSE;
663
- }
664
-
665
- protected function HideDownloads($show_ids, $hide_ids = array())
666
- {
667
- global $wpdb;
668
- $show_ids = implode(',', array_map('intval', $show_ids));
669
- $hide_ids = implode(',', array_map('intval', $hide_ids));
670
- $downloads = $this->table_downloads();
671
- if ($show_ids)
672
- {
673
- $sql = "UPDATE ${downloads} SET hide_from_sidebar=0, last_date=last_date WHERE id IN (${show_ids})";
674
- // The last_date is used to prevent automatic update to current_timestamp
675
- $wpdb->query($sql);
676
- }
677
- if ($hide_ids)
678
- {
679
- $sql = "UPDATE ${downloads} SET hide_from_sidebar=1, last_date=last_date WHERE id IN (${hide_ids})";
680
- // The last_date is used to prevent automatic update to current_timestamp
681
- $wpdb->query($sql);
682
- }
683
- //wp_redirect($_SERVER['REQUEST_URI']);
684
- //die();
685
- }
686
-
687
- protected function DeleteDownloadDetails($ids = array())
688
- {
689
- global $wpdb;
690
- $ids = array_map('intval', $ids);
691
- if ($ids)
692
- {
693
- $ids = implode(',', $ids);
694
- $downloads = $this->table_downloads();
695
- $details = $this->table_details();
696
- $downloadids = array();
697
- $sql = "SELECT DISTINCT download FROM ${details} WHERE id IN (${ids})";
698
- $results = $wpdb->get_results($sql, ARRAY_N);
699
- if (is_array($results))
700
- foreach ($results as $row)
701
- {
702
- list($downloadid) = $row;
703
- $downloadids[] = $downloadid;
704
- }
705
- if ($downloadids) {
706
- $sql = "DELETE FROM ${details} WHERE id IN (${ids})";
707
- $wpdb->query($sql);
708
- foreach ($downloadids as $downloadid)
709
- {
710
- $sql = "SELECT COUNT(*), MAX(download_date) FROM ${details} WHERE download=%d";
711
- $result = $wpdb->get_row($wpdb->prepare($sql, $downloadid), ARRAY_N);
712
- if (is_array($result))
713
- {
714
- list($count, $date) = $result;
715
- $sql = "UPDATE ${downloads} SET download_count=%d, last_date=%s WHERE id=%d";
716
- $wpdb->query($wpdb->prepare($sql, $count, $date, $downloadid));
717
- }
718
- }
719
- }
720
- }
721
- //wp_redirect($_SERVER['REQUEST_URI']);
722
- //die();
723
- }
724
-
725
- protected function DeleteDownloads($ids = array())
726
- {
727
- global $wpdb;
728
- $ids = array_map('intval', $ids);
729
- if ($ids)
730
- {
731
- $ids = implode(',', $ids);
732
- $downloads = $this->table_downloads();
733
- $details = $this->table_details();
734
- $sql = "DELETE FROM ${downloads} WHERE id IN (${ids})";
735
- $wpdb->query($sql);
736
- $sql = "DELETE FROM ${details} WHERE download IN (${ids})";
737
- $wpdb->query($sql);
738
- }
739
- //wp_redirect($_SERVER['REQUEST_URI']);
740
- //die();
741
- }
742
-
743
- protected function DeleteAllDownloads()
744
- {
745
- global $wpdb;
746
- $downloads = $this->table_downloads();
747
- $details = $this->table_details();
748
- $sql = "DELETE FROM ${downloads}";
749
- $wpdb->query($sql);
750
- $sql = "DELETE FROM ${details}";
751
- $wpdb->query($sql);
752
- //wp_redirect($_SERVER['REQUEST_URI']);
753
- //die();
754
- }
755
-
756
- protected function DownloadList($options)
757
- {
758
- global $wpdb;
759
- $flags = $options['flags'];
760
- $from = $options['from'];
761
- $order = $options['order'];
762
- $detailed = get_option(self::PREFIX . 'detailed');
763
- ?>
764
- <div class="wrap">
765
- <h2><?php echo __('Simple Download Monitor', self::GETTEXT_REALM); ?></h2>
766
- <h3><?php echo ($options['flags'] & self::FLAGS_NOTEXISTING) ? __('Nonexistent downloads', self::GETTEXT_REALM) : __('All downloads', self::GETTEXT_REALM); ?></h3>
767
- <p><a href="<?php echo $this->GetUrlForList(array_merge($options, array('from' => 0, 'flags' => $options['flags']^self::FLAGS_NOTEXISTING))); ?>"><?php echo ($options['flags'] & self::FLAGS_NOTEXISTING) ? __('Show all downloads', self::GETTEXT_REALM) : __('Show nonexistent downloads', self::GETTEXT_REALM); ?></a></p>
768
- <?php if ($this->isAdmin()): ?>
769
- <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
770
- <?php endif; ?>
771
- <table id="sdmon">
772
- <colgroup>
773
- <col class="sdmon-rownum" align="right" width="32" />
774
- <col class="sdmon-filename" />
775
- <col class="sdmon-count" align="right" width="64" />
776
- <col class="sdmon-date" align="center" />
777
- <col class="sdmon-hidden" />
778
- <col class="sdmon-delete" />
779
- </colgroup>
780
- <thead>
781
- <tr>
782
- <th>&nbsp;</th>
783
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_NAME ))); ?>"><?php echo __("Filename", self::GETTEXT_REALM); ?></a></th>
784
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_COUNT))); ?>"><?php echo __("Download count", self::GETTEXT_REALM); ?></a></th>
785
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_DATE ))); ?>"><?php echo __("Last date", self::GETTEXT_REALM); ?></a></th>
786
- <th><?php echo __('Hide from sidebar', self::GETTEXT_REALM); ?></th>
787
- <th><?php echo __('Reset to zero', self::GETTEXT_REALM); ?></th>
788
- </tr>
789
- </thead>
790
- <tbody><?php
791
- $table_downloads = $this->table_downloads();
792
- $where = $this->GetWhere($flags);
793
- $orderby = $this->GetOrderBy($order);
794
- $limit = $this->GetLimit($from);
795
- $sql = "SELECT id, filename, download_count, last_date, file_exists, hide_from_sidebar FROM ${table_downloads} ${where} ${orderby} ${limit}";
796
- $totalcount = $wpdb->get_var("SELECT COUNT(*) FROM ${table_downloads} ${where}");
797
- $results = $wpdb->get_results($sql, ARRAY_N);
798
- $rownum = intval($options['from']);
799
- if (is_array($results)) {
800
- foreach ($results as $row) {
801
- $rownum++;
802
- list($download, $filename, $count, $date, $exists, $hidden) = $row;
803
- ?>
804
- <tr<?php if (!$exists) echo ' class="not-exist"'; ?>>
805
- <td><?php echo $rownum; ?>.</td>
806
- <td><?php if ($detailed): ?><a href="<?php echo $this->GetUrlForList(array('download' => $download)); ?>"><?php endif; echo htmlspecialchars($filename); if ($detailed): ?></a><?php endif; ?></td>
807
- <td><?php echo $count; ?></td>
808
- <td><?php echo mysql2date('Y-m-d H:i:s', $date, TRUE); ?></td>
809
- <td><?php if ($this->IsAdmin()): ?>
810
- <input type="checkbox" name="SimpleDownloadMonitor_HideIds[]" value="<?php echo $download; ?>" <?php if ($hidden) echo ' checked="checked"'; ?> />
811
- <input type="hidden" name="SimpleDownloadMonitor_ShowIds[]" value="<?php echo $download; ?>" />
812
- <label for="SimpleDownloadMonitor_HideIds[]" /> <?php echo __('Hidden', self::GETTEXT_REALM); ?></label>
813
- <?php else: ?>&nbsp;<?php endif; ?>
814
- </td>
815
- <td><?php if ($this->IsAdmin()): ?>
816
- <input type="checkbox" name="SimpleDownloadMonitor_DeleteIds[]" value="<?php echo $download; ?>" />
817
- <label for="SimpleDownloadMonitor_DeleteIds[]"> <?php echo __('Reset', self::GETTEXT_REALM); ?></label>
818
- <?php else: ?>&nbsp;<?php endif; ?>
819
- </td>
820
- </tr>
821
- </tbody><?php
822
- }
823
- }
824
- ?>
825
- </table>
826
- <?php if ($this->isAdmin()): ?>
827
- <div><input type="submit" name="SimpleDownloadMonitor_Update" value="<?php echo __('Update settings', self::GETTEXT_REALM); ?>" /></div>
828
- <div><input type="submit" name="SimpleDownloadMonitor_Delete" value="<?php echo __('Reset checked statistics', self::GETTEXT_REALM); ?>" /></div>
829
- <div><input type="submit" name="SimpleDownloadMonitor_DeleteAll" value="<?php echo __('Reset all statistics', self::GETTEXT_REALM); ?>" /> - <input type="checkbox" name="SimpleDownloadMonitor_DeleteAllReally" value="yes" /><label for="SimpleDownloadMonitor_DeleteAllReally"> <?php echo __('Yes, I am sure', self::GETTEXT_REALM); ?></label></div>
830
- </form>
831
- <?php endif; ?>
832
- <?php echo $this->Paginator($options, $totalcount); ?>
833
- </div><?php
834
- }
835
-
836
- protected function DetailedDownloadList($options)
837
- {
838
- global $wpdb;
839
- $flags = $options['flags'];
840
- $from = $options['from'];
841
- $order = $options['order'];
842
- $download = $options['download'];
843
- $detailed = $options['detailed'];
844
- $table_downloads = $this->table_downloads();
845
- list($id, $filename, $count) = $wpdb->get_row($wpdb->prepare("SELECT id, filename, download_count FROM ${table_downloads} WHERE id=%d", $download), ARRAY_N);
846
- if (!$id)
847
- {
848
- $this->DownloadList($options);
849
- return;
850
- }
851
- else
852
- {
853
- ?>
854
- <div class="wrap">
855
- <h2><?php echo __('Simple Download Monitor', self::GETTEXT_REALM); ?></h2>
856
- <h3><?php printf(__('Detailed data for <strong>%s</strong>:', self::GETTEXT_REALM), $filename); ?></h3>
857
- <p><?php printf(__('Total number of downloads: <strong>%d</strong>.', self::GETTEXT_REALM), $count); ?></p>
858
- <?php if ($this->isAdmin()): ?>
859
- <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
860
- <?php endif; ?>
861
- <table id="sdmon">
862
- <colgroup>
863
- <col class="sdmon-rownum" align="right" width="32" />
864
- <col class="sdmon-date" align="center" />
865
- <col class="sdmon-ipaddr" />
866
- <col class="sdmon-country" />
867
- <col class="sdmon-referer" />
868
- <col class="sdmon-username" />
869
- <col class="sdmon-tools" />
870
- </colgroup>
871
- <thead>
872
- <tr>
873
- <th>&nbsp;</th>
874
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_DATE ))); ?>"><?php echo __("Date", self::GETTEXT_REALM); ?></a></th>
875
- <th><?php echo __("Country", self::GETTEXT_REALM); ?></th>
876
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_IP ))); ?>"><?php echo __("IP address", self::GETTEXT_REALM); ?></a></th>
877
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_REFERER))); ?>"><?php echo __("Referer", self::GETTEXT_REALM); ?></a></th>
878
- <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_USER ))); ?>"><?php echo __("Username", self::GETTEXT_REALM); ?></a></th>
879
- <th>&nbsp;</th>
880
- </tr>
881
- </thead>
882
- <tbody><?php
883
- $table_details = $this->table_details();
884
- $where = $this->GetDetailWhere($flags);
885
- $orderby = $this->GetDetailOrderBy($order);
886
- $limit = $this->GetLimit($from);
887
- if (class_exists('PepakIpToCountry'))
888
- {
889
- $ip_loc = PepakIpToCountry::Subselect("INET_ATON(${table_details}.ip)", 'iso_code2');
890
- }
891
- else
892
- $ip_loc = 'NULL';
893
- $sql = "SELECT id, download_date, ip, referer, userid, username, ${ip_loc} iso_code2 FROM ${table_details} WHERE download=%d ${where} ${orderby} ${limit}";
894
- $totalcount = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM ${table_details} WHERE download=%d ${where}", $download));
895
- $results = $wpdb->get_results($wpdb->prepare($sql, $download), ARRAY_N);
896
- $rownum = intval($options['from']);
897
- foreach ($results as $row) {
898
- $rownum++;
899
- list($id, $date, $ip, $referer, $userid, $username, $country) = $row;
900
- if (class_exists('PepakIpToCountry') AND (PepakIpToCountry::VERSION>='0.03'))
901
- $country_flag = PepakIpToCountry::IP_to_Country_Flag($ip);
902
- else
903
- {
904
- $country = strtolower($country);
905
- $country_flag = ($country && file_exists($this->plugin_dir.'/flags/'.$country.'.png')) ? '<img src="'.$this->plugin_url.'/flags/'.$country.'.png" alt="'.$country.'" />' : '';
906
- }
907
- ?>
908
- <tr>
909
- <td><?php echo $rownum; ?>.</td>
910
- <td><?php echo mysql2date('Y-m-d H:i:s', $date, TRUE); ?></td>
911
- <td><?php echo ($country_flag) ? $country_flag : '&nbsp;'; ?></td>
912
- <td><?php echo htmlspecialchars($ip); ?></td>
913
- <td><?php echo htmlspecialchars($referer); ?></td>
914
- <td><?php echo htmlspecialchars($username); ?></td>
915
- <td><?php if ($this->IsAdmin()): ?><input type="checkbox" name="SimpleDownloadMonitor_DeleteIds[]" value="<?php echo $id; ?>" /><label for="SimpleDownloadMonitor_DeleteIds[]"> <?php echo __('Delete this statistic', self::GETTEXT_REALM); ?></label><?php else: ?>&nbsp;<?php endif; ?></td>
916
- </tr>
917
- </tbody><?php
918
- }
919
- }
920
- ?>
921
- </table>
922
- <?php if ($this->isAdmin()): ?>
923
- <div><input type="submit" name="SimpleDownloadMonitor_DeleteDetail" value="<?php echo __('Delete checked statistics', self::GETTEXT_REALM); ?>" /></div>
924
- </form>
925
- <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
926
- <div><input type="submit" name="SimpleDownloadMonitor_Delete" value="<?php echo __('Delete all statistics', self::GETTEXT_REALM); ?>" /> - <input type="checkbox" name="SimpleDownloadMonitor_DeleteIds[]" value="<?php echo $download; ?>" /> <?php echo __('Yes, I am sure', self::GETTEXT_REALM); ?></label></div>
927
- </form>
928
- <?php endif; ?>
929
- <?php echo $this->Paginator($options, $totalcount); ?>
930
- <p><a href="<?php echo $this->GetUrlForList(); ?>"><?php echo __('Return to full list.', self::GETTEXT_REALM); ?></a></p>
931
- </div><?php
932
- }
933
-
934
- public function ActionHead()
935
- {
936
- echo '<link type="text/css" rel="stylesheet" href="' . $this->plugin_url . '/css/sdmon.css" />'."\n";
937
- }
938
-
939
- }
940
- }
941
-
942
- if (!isset($sdmon))
943
- $sdmon = new SimpleDownloadMonitor();
944
-
945
- if (!function_exists('SimpleDownloadMonitor_BuildAdminMenu'))
946
- {
947
- function SimpleDownloadMonitor_BuildAdminMenu()
948
- {
949
- global $sdmon;
950
- if (isset($sdmon))
951
- {
952
- $rights_options = get_option(SimpleDownloadMonitor::PREFIX . 'rights_options');
953
- $rights_view = get_option(SimpleDownloadMonitor::PREFIX . 'rights_view');
954
- if (!$rights_options) $rights_options = 'manage_options';
955
- if (!$rights_view) $rights_view = 'read';
956
- $options_page = add_options_page(__('Simple Download Monitor options', SimpleDownloadMonitor::GETTEXT_REALM), __('Simple Download Monitor', SimpleDownloadMonitor::GETTEXT_REALM), $rights_options, basename(__FILE__), array(&$sdmon, 'AdminPanel'));
957
- $tool_page = add_submenu_page('tools.php', __('Simple Download Monitor', SimpleDownloadMonitor::GETTEXT_REALM), __('Simple Download Monitor', SimpleDownloadMonitor::GETTEXT_REALM), $rights_view, basename(__FILE__), array(&$sdmon, 'ToolsPanel'));
958
- add_action('admin_head-'.$tool_page, array(&$sdmon, 'ActionHead'));
959
- }
960
- }
961
- }
962
-
963
- if (!class_exists('SimpleDownloadMonitor_Widget'))
964
- {
965
- class SimpleDownloadMonitor_Widget extends WP_Widget
966
- {
967
- function SimpleDownloadMonitor_Widget()
968
- {
969
- $widget_options = array(
970
- 'classname' => 'sdmon',
971
- 'description' => __('Allows you to display the most popular downloads in the sidebar.', SimpleDownloadMonitor::GETTEXT_REALM)
972
- );
973
- $control_options = array(
974
- //'width' => 250,
975
- //'height' => 0,
976
- 'id_base' => 'sdmon-widget'
977
- );
978
- $this->WP_Widget('sdmon-widget', 'Simple Download Monitor', $widget_options, $control_options);
979
- }
980
-
981
- function widget($arguments, $instance)
982
- {
983
- global $wpdb;
984
- $title = apply_filters('widget_title', $instance['title']);
985
- $count = intval(isset($instance['count']) ? intval($instance['count']) : 0);
986
- if ($count <= 0) $count = 10;
987
- $like = isset($instance['like']) ? $instance['like'] : '';
988
- echo $arguments['before_widget'];
989
- if ($title) echo $arguments['before_title'] . $title . $arguments['after_title'];
990
- $downloads = SimpleDownloadMonitor::table_downloads();
991
- $liketest = $like ? ' AND filename LIKE "%s"' : '';
992
- $sql = "SELECT id, filename, download_count FROM ${downloads} WHERE file_exists<>0 AND COALESCE(hide_from_sidebar,0)=0 ${liketest} ORDER BY download_count DESC LIMIT ${count}";
993
- $results = $wpdb->get_results($wpdb->prepare($sql, $like), ARRAY_N);
994
- echo "<ul>\n";
995
- foreach ($results as $row)
996
- {
997
- list($id, $filename, $downloadcount) = $row;
998
- ?><li><a href="/<?php echo esc_attr($filename); ?>"><?php echo htmlspecialchars(basename($filename)); ?></a> <strong><?php echo $downloadcount; ?></strong></li><?php
999
- }
1000
- echo "</ul>\n";
1001
- echo $arguments['after_widget'];
1002
- }
1003
-
1004
- function update($new_instance, $old_instance)
1005
- {
1006
- $instance = $old_instance;
1007
- $instance['title'] = strip_tags($new_instance['title']);
1008
- $instance['count'] = intval($new_instance['count']);
1009
- $instance['like'] = $new_instance['like'];
1010
- return $instance;
1011
- }
1012
-
1013
- function form($instance)
1014
- {
1015
- $defaults = array(
1016
- 'title' => __('Popular files', SimpleDownloadMonitor::GETTEXT_REALM),
1017
- 'count' => '10',
1018
- 'like' => ''
1019
- );
1020
- $instance = wp_parse_args((array) $instance, $defaults);
1021
- ?><p>
1022
- <label for="<?php echo $this->get_field_id('title'); ?>"><?php echo __('Title:', SimpleDownloadMonitor::GETTEXT_REALM); ?></label>
1023
- <input id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title']); ?>" type="text" style="width: 100%;" />
1024
- </p>
1025
- <p>
1026
- <label for="<?php echo $this->get_field_id('count'); ?>"><?php echo __('Number of files to show:', SimpleDownloadMonitor::GETTEXT_REALM); ?></label>
1027
- <input id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>" value="<?php echo esc_attr($instance['count']); ?>" type="text" />
1028
- </p><p>
1029
- <label for="<?php echo $this->get_field_id('like'); ?>"><?php echo __('Only show filenames which match this LIKE condition:', SimpleDownloadMonitor::GETTEXT_REALM); ?></label>
1030
- <input id="<?php echo $this->get_field_id('like'); ?>" name="<?php echo $this->get_field_name('like'); ?>" value="<?php echo esc_attr($instance['like']); ?>" type="text" style="width: 100%;" />
1031
- <br /><?php echo __("Empty string matches all filenames and is useful for most usage scenarios. You would only use a non-empty value if you wanted to create multiple SDMon widgets, each showing a different list of files: only filenames which match the given string in a LIKE condition of a SQL query will be shown. The most common values would be something like <code>files/documents/%</code> (meaning \"The filename must begin with <code>files/documents/</code>\") or <code>%.mp3</code> (meaning \"The filename must end with <code>.mp3</code>\") - the percentage symbol <code>%</code> means \"anything\", the underscore symbol <code>_</code> means \"Any one character\".", SimpleDownloadMonitor::GETTEXT_REALM); ?>
1032
- </p><?php
1033
- }
1034
-
1035
- }
1036
- }
1037
-
1038
- if (!function_exists('SimpleDownloadMonitorWidget_Init'))
1039
- {
1040
- function SimpleDownloadMonitorWidget_Init()
1041
- {
1042
- register_widget('SimpleDownloadMonitor_Widget');
1043
- }
1044
-
1045
- }
1046
-
1047
- add_action('widgets_init', 'SimpleDownloadMonitorWidget_Init');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Plugin Name: Simple Download Monitor
5
+ Plugin URI: http://www.pepak.net/wordpress/simple-download-monitor-plugin
6
+ Description: Count the number of downloads without having to maintain a comprehensive download page.
7
+ Version: 0.22
8
+ Author: Pepak | contributors: matheusbrat (http://matbra.com)
9
+ Author URI: http://www.pepak.net
10
+ */
11
+
12
+ /* Copyright 2009, 2010 Pepak (email: wordpress@pepak.net)
13
+
14
+ This program is free software; you can redistribute it and/or modify
15
+ it under the terms of the GNU General Public License as published by
16
+ the Free Software Foundation; either version 2 of the License, or
17
+ (at your option) any later version.
18
+
19
+ This program is distributed in the hope that it will be useful,
20
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
21
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
+ GNU General Public License for more details.
23
+
24
+ You should have received a copy of the GNU General Public License
25
+ along with this program; if not, write to the Free Software
26
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
+ */
28
+
29
+ if (!class_exists('SimpleDownloadMonitor'))
30
+ {
31
+ class SimpleDownloadMonitor
32
+ {
33
+
34
+ const VERSION = '0.22';
35
+ const PREFIX = 'sdmon_';
36
+ const PREG_DELIMITER = '`';
37
+ const GET_PARAM = 'sdmon';
38
+ const RECORDS_PER_PAGE = 20;
39
+ const GETTEXT_REALM = 'simple-download-monitor';
40
+
41
+ protected $plugin_url = '';
42
+ protected $plugin_dir = '';
43
+ protected $plugin_dir_relative = '';
44
+
45
+ public function SimpleDownloadMonitor()
46
+ {
47
+ $this->plugin_url = WP_PLUGIN_URL . '/' . dirname(plugin_basename(__FILE__));
48
+ $this->plugin_dir = WP_PLUGIN_DIR . '/' . dirname(plugin_basename(__FILE__));
49
+ if (strpos($this->plugin_dir, ABSPATH) === 0)
50
+ $this->plugin_dir_relative = substr($this->plugin_dir, strlen(ABSPATH));
51
+ else
52
+ $this->plugin_dir_relative = $this->plugin_dir;
53
+ register_activation_hook(__FILE__, array('SimpleDownloadMonitor', 'Install'));
54
+ add_action('init', array(&$this, 'ActionInit'));
55
+ add_action('admin_menu', 'SimpleDownloadMonitor_BuildAdminMenu');
56
+ if (self::VERSION != get_option(self::PREFIX . 'version'))
57
+ self::Install();
58
+ }
59
+
60
+ public static function Install()
61
+ {
62
+ global $wpdb;
63
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
64
+ $table_downloads = $wpdb->prefix . self::PREFIX . 'downloads';
65
+ $sql = "CREATE TABLE ${table_downloads} (
66
+ id INTEGER NOT NULL AUTO_INCREMENT,
67
+ filename VARCHAR(1024) NOT NULL,
68
+ download_count INTEGER NOT NULL,
69
+ last_date TIMESTAMP NOT NULL,
70
+ file_exists TINYINT,
71
+ hide_from_sidebar TINYINT,
72
+ PRIMARY KEY id (id),
73
+ KEY download_count (download_count),
74
+ KEY last_date (last_date)
75
+ );";
76
+ dbDelta($sql);
77
+ $table_details = $wpdb->prefix . self::PREFIX . 'details';
78
+ $sql = "CREATE TABLE ${table_details} (
79
+ id INTEGER NOT NULL AUTO_INCREMENT,
80
+ download INTEGER NOT NULL,
81
+ download_date TIMESTAMP NOT NULL,
82
+ ip VARCHAR(64) NOT NULL,
83
+ referer TEXT,
84
+ userid INTEGER,
85
+ username VARCHAR(64),
86
+ PRIMARY KEY id (id),
87
+ KEY download (download),
88
+ KEY download_date (download_date)
89
+ );";
90
+ dbDelta($sql);
91
+ update_option(self::PREFIX . 'table_downloads', $table_downloads);
92
+ update_option(self::PREFIX . 'table_details', $table_details);
93
+ update_option(self::PREFIX . 'version', self::VERSION);
94
+ add_option(self::PREFIX . 'directories', 'files/');
95
+ add_option(self::PREFIX . 'extensions', 'zip|rar|7z');
96
+ add_option(self::PREFIX . 'detailed', '0');
97
+ add_option(self::PREFIX . 'inline', '');
98
+ add_option(self::PREFIX . 'ignored_users', '');
99
+ add_option(self::PREFIX . 'group_within', '0');
100
+ add_option(self::PREFIX . 'rights_view', 'read');
101
+ add_option(self::PREFIX . 'rights_delete', 'delete_users');
102
+ add_option(self::PREFIX . 'rights_options', 'manage_options');
103
+ add_option(self::PREFIX . 'max_downloads_per_ip_and_day', '0');
104
+ add_option(self::PREFIX . 'max_downloads_per_ip_and_day_registered', '0');
105
+ add_option(self::PREFIX . 'error_download_limit', '');
106
+ add_option(self::PREFIX . 'download_page', plugin_dir_path(__FILE__) . '/download-example.php');
107
+ add_option(self::PREFIX . 'show_download_page', '0');
108
+ }
109
+
110
+ public function table_downloads()
111
+ {
112
+ static $table = null;
113
+ if ($table == null)
114
+ $table = get_option(self::PREFIX . 'table_downloads');
115
+ return $table;
116
+ }
117
+
118
+ public function table_details()
119
+ {
120
+ static $table = null;
121
+ if ($table == null)
122
+ $table = get_option(self::PREFIX . 'table_details');
123
+ return $table;
124
+ }
125
+
126
+ //-----------------------------------------------------------------------------------
127
+ // Methods set_range, buffered_read, byteserve adapted from
128
+ // http://www.coneural.org/florian/papers/04_byteserving.php
129
+
130
+ function set_range($range, $filesize, &$first, &$last){
131
+
132
+ /*
133
+ Sets the first and last bytes of a range, given a range expressed as a string
134
+ and the size of the file.
135
+
136
+ If the end of the range is not specified, or the end of the range is greater
137
+ than the length of the file, $last is set as the end of the file.
138
+
139
+ If the begining of the range is not specified, the meaning of the value after
140
+ the dash is "get the last n bytes of the file".
141
+
142
+ If $first is greater than $last, the range is not satisfiable, and we should
143
+ return a response with a status of 416 (Requested range not satisfiable).
144
+
145
+ Examples:
146
+ $range='0-499', $filesize=1000 => $first=0, $last=499 .
147
+ $range='500-', $filesize=1000 => $first=500, $last=999 .
148
+ $range='500-1200', $filesize=1000 => $first=500, $last=999 .
149
+ $range='-200', $filesize=1000 => $first=800, $last=999 .
150
+
151
+ */
152
+ $dash=strpos($range,'-');
153
+ $first=trim(substr($range,0,$dash));
154
+ $last=trim(substr($range,$dash+1));
155
+ if ($first=='') {
156
+ //suffix byte range: gets last n bytes
157
+ $suffix=$last;
158
+ $last=$filesize-1;
159
+ $first=$filesize-$suffix;
160
+ if($first<0) $first=0;
161
+ } else {
162
+ if ($last=='' || $last>$filesize-1) $last=$filesize-1;
163
+ }
164
+ if($first>$last){
165
+ //unsatisfiable range
166
+ header("Status: 416 Requested range not satisfiable");
167
+ header("Content-Range: */$filesize");
168
+ exit;
169
+ }
170
+ }
171
+
172
+ function buffered_read($file, $bytes, $buffer_size=65536){
173
+ /*
174
+ Outputs up to $bytes from the file $file to standard output, $buffer_size bytes at a time.
175
+ */
176
+ $bytes_left=$bytes;
177
+ while($bytes_left>0 && !feof($file)){
178
+ if($bytes_left>$buffer_size)
179
+ $bytes_to_read=$buffer_size;
180
+ else
181
+ $bytes_to_read=$bytes_left;
182
+ $bytes_left-=$bytes_to_read;
183
+ $contents=fread($file, $bytes_to_read);
184
+ echo $contents;
185
+ flush();
186
+ }
187
+ }
188
+
189
+ function byteserve($filename, $mimetype, $disposition = ''){
190
+ /*
191
+ Byteserves the file $filename.
192
+
193
+ When there is a request for a single range, the content is transmitted
194
+ with a Content-Range header, and a Content-Length header showing the number
195
+ of bytes actually transferred.
196
+
197
+ When there is a request for multiple ranges, these are transmitted as a
198
+ multipart message. The multipart media type used for this purpose is
199
+ "multipart/byteranges".
200
+ */
201
+
202
+ // Clean all buffering components, if any.
203
+ while (ob_list_handlers())
204
+ ob_end_clean();
205
+
206
+ $filesize=filesize($filename);
207
+ $file=fopen($filename,"rb");
208
+
209
+ $ranges=NULL;
210
+ if ($_SERVER['REQUEST_METHOD']=='GET' && isset($_SERVER['HTTP_RANGE']) && $range=stristr(trim($_SERVER['HTTP_RANGE']),'bytes=')){
211
+ $range=substr($range,6);
212
+ $boundary=sha1(uniqid());//set a random boundary
213
+ $ranges=explode(',',$range);
214
+ }
215
+
216
+ if($ranges && count($ranges)){
217
+ header("HTTP/1.1 206 Partial content");
218
+ header("Accept-Ranges: bytes");
219
+ if(count($ranges)>1){
220
+ /*
221
+ More than one range is requested.
222
+ */
223
+
224
+ //compute content length
225
+ $content_length=0;
226
+ foreach ($ranges as $range){
227
+ $this->set_range($range, $filesize, $first, $last);
228
+ $content_length+=strlen("\r\n--$boundary\r\n");
229
+ $content_length+=strlen("Content-type: $mimetype\r\n");
230
+ $content_length+=strlen("Content-range: bytes $first-$last/$filesize\r\n\r\n");
231
+ $content_length+=$last-$first+1;
232
+ }
233
+ $content_length+=strlen("\r\n--$boundary--\r\n");
234
+
235
+ //output headers
236
+ header("Content-Length: $content_length");
237
+ //see http://httpd.apache.org/docs/misc/known_client_problems.html for an discussion of x-byteranges vs. byteranges
238
+ header("Content-Type: multipart/x-byteranges; boundary=$boundary");
239
+
240
+ //output the content
241
+ foreach ($ranges as $range){
242
+ $this->set_range($range, $filesize, $first, $last);
243
+ echo "\r\n--$boundary\r\n";
244
+ echo "Content-type: $mimetype\r\n";
245
+ echo "Content-range: bytes $first-$last/$filesize\r\n\r\n";
246
+ fseek($file,$first);
247
+ $this->buffered_read ($file, $last-$first+1);
248
+ }
249
+ echo "\r\n--$boundary--\r\n";
250
+ } else {
251
+ /*
252
+ A single range is requested.
253
+ */
254
+ $range=$ranges[0];
255
+ $this->set_range($range, $filesize, $first, $last);
256
+ header("Content-Length: ".($last-$first+1) );
257
+ header("Content-Range: bytes $first-$last/$filesize");
258
+ header("Content-Type: $mimetype");
259
+ if ($disposition)
260
+ header("Content-Disposition: $disposition");
261
+ fseek($file,$first);
262
+ $this->buffered_read($file, $last-$first+1);
263
+ }
264
+ } else{
265
+ //no byteserving
266
+ header("Accept-Ranges: bytes");
267
+ header("Content-Length: $filesize");
268
+ header("Content-Type: $mimetype");
269
+ if ($disposition)
270
+ header("Content-Disposition: $disposition");
271
+ $this->buffered_read($file, $filesize);
272
+ }
273
+ fclose($file);
274
+ }
275
+ //-----------------------------------------------------------------------------------
276
+
277
+ protected function ErrorMessage($code, $message, $shortmessage)
278
+ {
279
+ $code = intval($code);
280
+ // Clean all buffering components, if any.
281
+ while (ob_list_handlers())
282
+ ob_end_clean();
283
+ header('Cache-control: no-cache');
284
+ if ($code >= 200)
285
+ header(sprintf('%s %d %s', $_SERVER["SERVER_PROTOCOL"], $code, $shortmessage));
286
+ get_header();
287
+ ?><div class="error">
288
+ <h2><?php echo __("Simple Download Monitor error", self::GETTEXT_REALM); ?></h2>
289
+ <p><?php echo $message; ?></p>
290
+ <?php
291
+ get_sidebar();
292
+ get_footer();
293
+ die();
294
+ }
295
+
296
+ public function Download($filename)
297
+ {
298
+ global $wpdb, $user_login, $user_ID;
299
+ $store_details = intval(get_option(self::PREFIX . 'detailed'));
300
+ $details = $this->table_details();
301
+ $downloads = $this->table_downloads();
302
+ $ip_addr = $_SERVER['REMOTE_ADDR'];
303
+ // Normalize the filename
304
+ $fullfilename = realpath(ABSPATH . '/' . $filename);
305
+ $relfilename = substr($fullfilename, strlen(ABSPATH));
306
+ $relfilename = strtr($relfilename, '\\', '/');
307
+ $exists = (file_exists($fullfilename) AND !is_dir($fullfilename)) ? 1 : 0;
308
+ // Make sure it is a valid request
309
+ $dirregexp = self::PREG_DELIMITER . '^' . get_option(self::PREFIX . 'directories') . self::PREG_DELIMITER;
310
+ $extregexp = self::PREG_DELIMITER . '\\.' . get_option(self::PREFIX . 'extensions') . '$' . self::PREG_DELIMITER;
311
+ $valid = (preg_match($dirregexp, $relfilename) AND preg_match($extregexp, $relfilename)) ? 1 : 0;
312
+ // Get user information and decide if this user should be ignored
313
+ get_currentuserinfo();
314
+ $userid = $user_ID ? $user_ID : null;
315
+ $username = $user_login ? $user_login : null;
316
+ $ignored_users = get_option(self::PREFIX . 'ignored_users');
317
+ $monitor = empty($username) || empty($ignored_users) || (!in_array($username, explode('|', $ignored_users)));
318
+ if ($monitor)
319
+ {
320
+ // Check the number of downloads per IP and day
321
+ $max_downloads = intval(get_option(self::PREFIX . (is_user_logged_in() ? 'max_downloads_per_ip_and_day_registered' : 'max_downloads_per_ip_and_day')));
322
+ if ($max_downloads > 0)
323
+ {
324
+ $row = $wpdb->get_row($wpdb->prepare("SELECT COUNT(*) count, MIN(TIMESTAMPDIFF(MINUTE, NOW(), TIMESTAMPADD(DAY, 1, download_date))) retry FROM ${details} WHERE (download_date > TIMESTAMPADD(DAY, -1, NOW())) AND ip=%s", $ip_addr), ARRAY_N);
325
+ list($download_count, $retry_minutes) = $row;
326
+ if ($download_count >= $max_downloads)
327
+ {
328
+ $msg = get_option(self::PREFIX . 'error_download_limit');
329
+ if ($msg == '') $msg = __("You have exceeded your download quota today. Please try again in %d hours and %d minutes.", self::GETTEXT_REALM);
330
+ $this->ErrorMessage(403, sprintf($msg, $retry_minutes/60, abs($retry_minutes%60)), 'Forbidden');
331
+ }
332
+ }
333
+ // Store uncorrected request name to database for security/mistake review
334
+ $id = $wpdb->get_var($wpdb->prepare("SELECT id FROM ${downloads} WHERE filename=%s", $filename));
335
+ if ($id)
336
+ {
337
+ // Ignore quick downloads by the same user
338
+ if ($store_details && (($group_within = intval(get_option(self::PREFIX . 'group_within'))) > 0))
339
+ {
340
+ $grouped_id = $wpdb->get_var($wpdb->prepare("SELECT MIN(id) FROM ${details} WHERE download=%d AND (download_date > DATE_ADD(NOW(), INTERVAL -%d SECOND)) AND ip=%s", $id, $group_within, $ip_addr));
341
+ if (intval($grouped_id) > 0)
342
+ $monitor = FALSE;
343
+ }
344
+ if ($monitor)
345
+ {
346
+ $sql = "UPDATE ${downloads} SET download_count=download_count+1, last_date=NOW(), file_exists=%d WHERE id=%d";
347
+ $wpdb->query($wpdb->prepare($sql, $exists * $valid, $id));
348
+ }
349
+ }
350
+ else
351
+ {
352
+ $sql = "INSERT INTO ${downloads} (filename, download_count, last_date, file_exists) VALUES (%s, 1, NOW(), %d)";
353
+ $wpdb->query($wpdb->prepare($sql, $filename, $exists * $valid));
354
+ $id = $wpdb->insert_id;
355
+ }
356
+ // If details are requested, store them as well
357
+ if ($monitor && $store_details)
358
+ {
359
+ $sql = "INSERT INTO ${details} (download, download_date, ip, referer, username, userid) VALUES (%d, NOW(), %s, %s, %s, %d)";
360
+ $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
361
+ if (!$username AND isset($_COOKIE['comment_author_'.COOKIEHASH]))
362
+ $username = utf8_encode($_COOKIE['comment_author_'.COOKIEHASH]);
363
+ $wpdb->query($wpdb->prepare($sql, $id, $ip_addr, $referer, $username, $userid));
364
+ }
365
+ }
366
+ // If the file exists and is valid, download it
367
+ // Make sure the file is available for download
368
+ if (!$exists OR !$valid)
369
+ $this->ErrorMessage(404, sprintf(__("Requested file <strong>%s</strong> not found."), htmlspecialchars($filename)), 'Not found');
370
+ // Generate proper headers
371
+ $mimetype = '';
372
+ if (function_exists('finfo_open') AND defined('FILEINFO_MIME_TYPE'))
373
+ {
374
+ $finfo = finfo_open(FILEINFO_MIME_TYPE);
375
+ $mimetype = finfo_file($finfo, $fullfilename);
376
+ }
377
+ if (!$mimetype && function_exists('mime_content_type'))
378
+ $mimetype = mime_content_type($fullfilename);
379
+ if (!$mimetype || ((strpos($mimetype, '/')) === FALSE))
380
+ $mimetype = 'application/octet-stream';
381
+ $disposition = 'attachment';
382
+ $inlineregexp = self::PREG_DELIMITER . get_option(self::PREFIX . 'inline') . self::PREG_DELIMITER;
383
+ if ($inlineregexp && preg_match($inlineregexp, $relfilename))
384
+ $disposition = 'inline';
385
+ $disposition = $disposition . '; filename="' . basename($fullfilename) . '"';
386
+ $this->byteserve($fullfilename, $mimetype, $disposition);
387
+ // Successful end
388
+ return TRUE;
389
+ }
390
+
391
+ public function Download_Page($filename) {
392
+ $page = get_option(self::PREFIX . 'download_page');
393
+ if ($page && file_exists($page))
394
+ include($page);
395
+ else
396
+ $this->Download($filename);
397
+ }
398
+
399
+ public function ActionInit() {
400
+
401
+ // Function is called in 'init' hook. It checks for download and if so, stops normal WordPress processing
402
+ // and replaces it with its monitoring functions.
403
+ $currentLocale = get_locale();
404
+ if(!empty($currentLocale))
405
+ {
406
+ $moFile = $this->plugin_dir . "/lang/" . $currentLocale . ".mo";
407
+ if(@file_exists($moFile) && is_readable($moFile))
408
+ load_textdomain(self::GETTEXT_REALM, $moFile);
409
+ }
410
+ //load_plugin_textdomain(self::GETTEXT_REALM, $this->plugin_dir . '/lang');
411
+ if (isset($_GET[self::GET_PARAM]) && ($filename = $_GET[self::GET_PARAM]))
412
+ {
413
+ // If it is setup so, show the download page
414
+ $usedownloadpage = intval(get_option(self::PREFIX . 'show_download_page'));
415
+ // Skip the download page if 'download' parameter is used
416
+ if ($usedownloadpage && isset($_GET['download']) && $_GET['download'])
417
+ $usedownloadpage = FALSE;
418
+ if ($usedownloadpage && isset($_SERVER['HTTP_REFERER'])) {
419
+ $referer = $_SERVER['HTTP_REFERER'];
420
+ $site_url = get_option('site_url');
421
+ if ($site_url)
422
+ $found = strpos($referer, $site_url . strval($_POST[self::PREFIX . 'directories']) . $filename) === 0;
423
+ else
424
+ $found = strpos($referer, strval($_POST[self::PREFIX . 'directories']) . $filename) !== FALSE;
425
+ if ($found)
426
+ $usedownloadpage = FALSE;
427
+ }
428
+ // Also skip the download page if the file is intended for inline use
429
+ if ($usedownloadpage && ($inlineregexp = get_option(self::PREFIX . 'inline')) && preg_match(self::PREG_DELIMITER . $inlineregexp . self::PREG_DELIMITER, $filename))
430
+ $usedownloadpage = FALSE;
431
+ // Go to it
432
+ if ($usedownloadpage)
433
+ $this->Download_Page($filename);
434
+ else
435
+ if ($this->Download($filename))
436
+ die();
437
+ else
438
+ wp_redirect(get_option('site_url'));
439
+ }
440
+ }
441
+
442
+ public function AdminPanel()
443
+ {
444
+ // Function draws the admin panel.
445
+ // First, post any modified options
446
+ if (isset($_POST['SimpleDownloadMonitor_Submit']))
447
+ {
448
+ // Read options from the form
449
+ $directories = strval($_POST[self::PREFIX . 'directories']);
450
+ $extensions = strval($_POST[self::PREFIX . 'extensions']);
451
+ $detailed = intval($_POST[self::PREFIX . 'detailed']);
452
+ $inline = strval($_POST[self::PREFIX . 'inline']);
453
+ $ignored_users = strval($_POST[self::PREFIX . 'ignored_users']);
454
+ $group_within = intval($_POST[self::PREFIX . 'group_within']);
455
+ $rights_view = strval($_POST[self::PREFIX . 'rights_view']);
456
+ $rights_delete = strval($_POST[self::PREFIX . 'rights_delete']);
457
+ $rights_options = strval($_POST[self::PREFIX . 'rights_options']);
458
+ $downloads_per_day = intval($_POST[self::PREFIX . 'max_downloads_per_ip_and_day']);
459
+ $downloads_per_day_registered = intval($_POST[self::PREFIX . 'max_downloads_per_ip_and_day_registered']);
460
+ $error_download_limit = strval($_POST[self::PREFIX . 'error_download_limit']);
461
+ $show_download_page = intval($_POST[self::PREFIX . 'show_download_page']);
462
+ $download_page = strval($_POST[self::PREFIX . 'download_page']);
463
+ // Remove slashes if necessary
464
+ if (get_magic_quotes_gpc())
465
+ {
466
+ $directories = stripslashes($directories);
467
+ $extensions = stripslashes($extensions);
468
+ $inline = stripslashes($inline);
469
+ $ignored_users = stripslashes($ignored_users);
470
+ $error_download_limit = stripslashes($error_download_limit);
471
+ }
472
+ // Escape the delimiter
473
+ list($directories, $extensions) = str_replace(self::PREG_DELIMITER, '\\'.self::PREG_DELIMITER, array($directories, $extensions));
474
+ // Write the changes to database
475
+ update_option(self::PREFIX . 'directories', $directories);
476
+ update_option(self::PREFIX . 'extensions', $extensions);
477
+ update_option(self::PREFIX . 'detailed', $detailed);
478
+ if (($inline == '') OR (strlen($inline) >= 3))
479
+ update_option(self::PREFIX . 'inline', $inline);
480
+ update_option(self::PREFIX . 'ignored_users', $ignored_users);
481
+ update_option(self::PREFIX . 'group_within', $group_within);
482
+ update_option(self::PREFIX . 'rights_view', $rights_view);
483
+ update_option(self::PREFIX . 'rights_delete', $rights_delete);
484
+ update_option(self::PREFIX . 'rights_options', $rights_options);
485
+ update_option(self::PREFIX . 'max_downloads_per_ip_and_day', $downloads_per_day);
486
+ update_option(self::PREFIX . 'max_downloads_per_ip_and_day_registered', $downloads_per_day_registered);
487
+ update_option(self::PREFIX . 'error_download_limit', $error_download_limit);
488
+ if (file_exists($download_page))
489
+ update_option(self::PREFIX . 'download_page', $download_page);
490
+ update_option(self::PREFIX . 'show_download_page', $show_download_page);
491
+
492
+ }
493
+ // Load options from the database
494
+ $directories = get_option(self::PREFIX . 'directories');
495
+ $extensions = get_option(self::PREFIX . 'extensions');
496
+ $detailed = get_option(self::PREFIX . 'detailed');
497
+ $inline = get_option(self::PREFIX . 'inline');
498
+ $ignored_users = get_option(self::PREFIX . 'ignored_users');
499
+ $group_within = intval(get_option(self::PREFIX . 'group_within'));
500
+ $rights_view = get_option(self::PREFIX . 'rights_view');
501
+ $rights_delete = get_option(self::PREFIX . 'rights_delete');
502
+ $rights_options = get_option(self::PREFIX . 'rights_options');
503
+ $downloads_per_day = get_option(self::PREFIX . 'max_downloads_per_ip_and_day');
504
+ $downloads_per_day_registered = get_option(self::PREFIX . 'max_downloads_per_ip_and_day_registered');
505
+ $error_download_limit = get_option(self::PREFIX . 'error_download_limit');
506
+ $download_page = get_option(self::PREFIX . 'download_page');
507
+ $show_download_page = get_option(self::PREFIX . 'show_download_page');
508
+ // Build the form
509
+ ?>
510
+ <div class="wrap">
511
+ <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
512
+ <h2><?php echo __('Simple Download Monitor options', self::GETTEXT_REALM); ?></h2>
513
+ <h3><?php echo __('Access rights', self::GETTEXT_REALM); ?></h3>
514
+ <p><?php echo __('You can set up user rights required to access various functions of Simple Download Monitor. Rights are assigned through capabilities (see <a href="http://codex.wordpress.org/Roles_and_Capabilities#Roles">Roles and Capabilities</a> in WordPress Codex). Predefined values are <strong>read</strong> ("any registered user") for displaying stats, <strong>delete_users</strong> ("administrator") for reseting stats and <strong>manage_options</strong> ("administrator") for changing options.', self::GETTEXT_REALM); ?></p>
515
+ <p><?php echo __('Capability required for viewing download stats:', self::GETTEXT_REALM); ?></p>
516
+ <p><input type="text" name="<?php echo self::PREFIX; ?>rights_view" value="<?php echo esc_attr($rights_view); ?>" /></p>
517
+ <p><?php echo __('Capability required for reseting download stats:', self::GETTEXT_REALM); ?></p>
518
+ <p><input type="text" name="<?php echo self::PREFIX; ?>rights_delete" value="<?php echo esc_attr($rights_delete); ?>" /></p>
519
+ <p><?php echo __('Capability required for setting SDMON options:', self::GETTEXT_REALM); ?></p>
520
+ <p><input type="text" name="<?php echo self::PREFIX; ?>rights_options" value="<?php echo esc_attr($rights_options); ?>" /></p>
521
+ <h3><?php echo __('Allowed directories', self::GETTEXT_REALM); ?></h3>
522
+ <p><?php echo __("Only requested files whose full names (relative to document root) start with this regular expression will be processed. It is strongly recommended to place all downloadable files (and ONLY downloadable files) into a designated directory and then placing that directory's name followed by a slash here. It is possible to use the power of PREG to allow multiple directories, but make sure there are ONLY files which you are comfortable with malicious users downloading. Do not EVER allow directories which contain PHP files here! That could lead to disclosure of sensitive data, including username and password used to connect to WordPress database.", self::GETTEXT_REALM); ?></p>
523
+ <p><?php echo __("Default value is <code>files/</code>, which only allows download from /files directory (the leading <code>/</code> is implicit).", self::GETTEXT_REALM); ?></p>
524
+ <p><input type="text" name="<?php echo self::PREFIX; ?>directories" value="<?php echo esc_attr($directories); ?>" /></p>
525
+ <h3><?php echo __('Allowed extensions', self::GETTEXT_REALM); ?></h3>
526
+ <p><?php echo __('Only files with extensions matching this regular expressions will be processed. This is another important security value. Make sure you only add extensions which are safe for malicious users to have, e.g. archives and possibly images. Do NOT use any expression that could allow a user to download PHP files, even if you think it safe given the Allowed Directories option above.', self::GETTEXT_REALM); ?></p>
527
+ <p><?php echo __("Default value is <code>zip|rar|7z</code> which only allows download of files ending with <code>.zip</code>, <code>.rar</code> and <code>.7z</code> (the leading <code>.</code> is implicit).", self::GETTEXT_REALM); ?></p>
528
+ <p><input type="text" name="<?php echo self::PREFIX; ?>extensions" value="<?php echo esc_attr($extensions); ?>" /></p>
529
+ <h3><?php echo __('Inline files', self::GETTEXT_REALM); ?></h3>
530
+ <p><?php echo __('Files whose names match this regular expression will be displayed inline (within a HTML page) rather than downloaded.', self::GETTEXT_REALM); ?></p>
531
+ <p><?php echo __("By default, this value is empty - no files will appear inline, all will be downloaded. You may want to place something like <code>\.(jpe?g|gif|png|swf)$</code> here to make images and Flash videos appear inline.", self::GETTEXT_REALM); ?></p>
532
+ <p><?php echo __('Note: Unlike the options above, nothing is implied in this regular expression. You <em>must</em> use an explicit <code>\.</code> to denote "start of extension", you <em>must</em> use an explicit <code>$</code> to mark "end of filename", etc.', self::GETTEXT_REALM); ?></p>
533
+ <p><?php echo __('Also note that this plugin uses PCRE-compatible regular expressions, NOT the better-known POSIX-compatible regular expressions. As a result, a valid regular expression must be at least three characters long - separator twice, and at least one character for a meaningful r.e.', self::GETTEXT_REALM); ?></p>
534
+ <p><input type="text" name="<?php echo self::PREFIX; ?>inline" value="<?php echo esc_attr($inline); ?>" /></p>
535
+ <h3><?php echo __("Store detailed logs?", self::GETTEXT_REALM); ?></h3>
536
+ <p><?php echo __("If detailed logs are allowed, various information (including exact time of download, user's IP address, referrer etc.) is stored. This can fill your database quickly if you have only a little space or a lot of popular downloads. Otherwise just the total numbers of downloads are stored, consuming significantly less space.", self::GETTEXT_REALM); ?></p>
537
+ <p><label for="<?php echo self::PREFIX; ?>detailed"><input type="checkbox" name="<?php echo self::PREFIX; ?>detailed" value="1" <?php if ($detailed) echo 'checked="checked" '; ?>/> <?php echo __('Use detailed statistics.', self::GETTEXT_REALM); ?></label></p>
538
+ <h3><?php echo __("Ignored users", self::GETTEXT_REALM); ?></h3>
539
+ <p><?php echo __("List of users whose downloads are not monitored. Separate multiple users with pipe character <code>|</code>. It is useful to prevent administrator damaging the statistics by testing that downloads work.", self::GETTEXT_REALM); ?></p>
540
+ <p><input type="text" name="<?php echo self::PREFIX; ?>ignored_users" value="<?php echo esc_attr($ignored_users); ?>" /></p>
541
+ <h3><?php echo __("Ignore quick re-downloads", self::GETTEXT_REALM); ?></h3>
542
+ <p><?php echo __("If one IP address requests the same download several times within a given time interval, only the first time will be recorded. If a zero or a negative value is entered, all downloads will get recorded regardless of how quickly they occur after each other.", self::GETTEXT_REALM); ?></p>
543
+ <p><input type="text" name="<?php echo self::PREFIX; ?>group_within" value="<?php echo esc_attr($group_within); ?>" /> <?php echo __('seconds', self::GETTEXT_REALM); ?></p>
544
+ <h3><?php echo __("Limit number of downloads per IP address", self::GETTEXT_REALM); ?></h3>
545
+ <p><?php echo __("Limit the number of files an IP address can download per day. The default value of zero means 'no limits' - an IP address can download as many files as it likes. Note that various download managers can initiate several downloads for each file, so make sure the limit is high enough not to interfere with the normal usage of your site. Also, please understand that this is NOT a perfect solution: One IP address can be shared by multiple users, and one user can easily use more than one IP address.", self::GETTEXT_REALM); ?></p>
546
+ <p><?php echo __("Users listed in the <strong>Ignored users</strong> section above can always download an unlimited number of files.", self::GETTEXT_REALM); ?></p>
547
+ <p><?php echo __("Visitors:", self::GETTEXT_REALM); ?> <input type="text" name="<?php echo self::PREFIX; ?>max_downloads_per_ip_and_day" value="<?php echo esc_attr($downloads_per_day); ?>" /></p>
548
+ <p><?php echo __("Registered users:", self::GETTEXT_REALM); ?> <input type="text" name="<?php echo self::PREFIX; ?>max_downloads_per_ip_and_day_registered" value="<?php echo esc_attr($downloads_per_day_registered); ?>" /></p>
549
+ <p><?php echo __("Error message:", self::GETTEXT_REALM); ?></p>
550
+ <p><textarea name="<?php echo self::PREFIX; ?>error_download_limit" rows="4" cols="64"><?php echo htmlspecialchars($error_download_limit); ?></textarea></p>
551
+ <p><?php echo __("(The first <code>%d</code> will be replaced by number of hours, the second one by number of minutes.)", self::GETTEXT_REALM); ?>
552
+ <h3><?php echo __("Use an intermediate Download page", self::GETTEXT_REALM); ?></h3>
553
+ <p><?php echo __("Before sending the actual requested file, display an intermediate download page which tells the user that the download is about to start.", self::GETTEXT_REALM); ?></p>
554
+ <p><label for="<?php echo self::PREFIX; ?>show_download_page"><input type="checkbox" name="<?php echo self::PREFIX; ?>show_download_page" value="1" <?php if ($show_download_page) echo 'checked="checked" '; ?>/> <?php echo __('Use the intermediate download page.', self::GETTEXT_REALM); ?></label></p>
555
+ <p><?php echo __("Path to your download page:", self::GETTEXT_REALM); ?><input type="text" name="<?php echo self::PREFIX; ?>download_page" value="<?php echo esc_attr($download_page); ?>" size="80" /></p>
556
+ <p><?php printf(__("You can use <strong>%s</strong> to use a demo page provided with the plugin.", self::GETTEXT_REALM), htmlspecialchars($this->plugin_dir . '/download-example.php')); ?></p>
557
+ <p><?php echo __("This functionality was suggested and for the most part programmed by <a href=\"http://matbra.com\">Matheus Bratfisch</a>, I (Pepak) just cleaned it up and added it to the plugin's distribution.", self::GETTEXT_REALM); ?></p>
558
+ <p>&nbsp;</p>
559
+ <div class="submit"><input type="submit" name="SimpleDownloadMonitor_Submit" value="<?php echo __("Update settings", self::GETTEXT_REALM) ?>" /></div>
560
+ </form>
561
+ </div><?php
562
+ }
563
+
564
+ public function ToolsPanel()
565
+ {
566
+ $download = isset($_GET['download']) ? intval($_GET['download']) : 0;
567
+ $from = isset($_GET['from']) ? intval($_GET['from']) : 0;
568
+ $order = isset($_GET['order']) ? $_GET['order'] : '';
569
+ $flags = isset($_GET['flags']) ? intval($_GET['flags']) : 0;
570
+ $detailed = get_option(self::PREFIX . 'detailed');
571
+ $options = array('download' => $download, 'from' => $from, 'order' => $order, 'flags' => $flags);
572
+ if ($this->IsAdmin())
573
+ {
574
+ if (isset($_POST['SimpleDownloadMonitor_Update']) && isset($_POST['SimpleDownloadMonitor_HideIds']) && is_array($_POST['SimpleDownloadMonitor_HideIds']) && isset($_POST['SimpleDownloadMonitor_ShowIds']) && is_array($_POST['SimpleDownloadMonitor_ShowIds']))
575
+ {
576
+ $this->HideDownloads($_POST['SimpleDownloadMonitor_ShowIds'], $_POST['SimpleDownloadMonitor_HideIds']);
577
+ }
578
+ if (isset($_POST['SimpleDownloadMonitor_Delete']) && isset($_POST['SimpleDownloadMonitor_DeleteIds']) && is_array($_POST['SimpleDownloadMonitor_DeleteIds']))
579
+ {
580
+ $this->DeleteDownloads($_POST['SimpleDownloadMonitor_DeleteIds']);
581
+ }
582
+ elseif (isset($_POST['SimpleDownloadMonitor_DeleteAll']) && ($_POST['SimpleDownloadMonitor_DeleteAllReally'] == 'yes'))
583
+ {
584
+ $this->DeleteAllDownloads();
585
+ }
586
+ if (isset($_POST['SimpleDownloadMonitor_DeleteDetail']) && isset($_POST['SimpleDownloadMonitor_DeleteIds']) && is_array($_POST['SimpleDownloadMonitor_DeleteIds']))
587
+ {
588
+ $this->DeleteDownloadDetails($_POST['SimpleDownloadMonitor_DeleteIds']);
589
+ }
590
+ }
591
+ if ($detailed && $download)
592
+ $this->DetailedDownloadList($options);
593
+ else
594
+ $this->DownloadList($options);
595
+ }
596
+
597
+ const ORDER_NAME = 'name';
598
+ const ORDER_COUNT = 'count';
599
+ const ORDER_DATE = 'date';
600
+ const ORDER_IP = 'ip';
601
+ const ORDER_REFERER = 'referer';
602
+ const ORDER_USER = 'user';
603
+
604
+ protected function GetOrderBy($order = '')
605
+ {
606
+ static $orders = array(
607
+ self::ORDER_NAME => 'filename',
608
+ self::ORDER_COUNT => 'download_count DESC, filename',
609
+ self::ORDER_DATE => 'last_date DESC, filename',
610
+ );
611
+ $result = isset($orders[$order]) ? $orders[$order] : $orders[self::ORDER_COUNT];
612
+ $result = " ORDER BY ${result} ";
613
+ return $result;
614
+ }
615
+
616
+ protected function GetDetailOrderBy($order = '')
617
+ {
618
+ static $orders = array(
619
+ self::ORDER_DATE => 'download_date DESC',
620
+ self::ORDER_IP => 'ip, download_date DESC',
621
+ self::ORDER_REFERER => 'referer, download_date DESC',
622
+ self::ORDER_USER => 'username, download_date DESC',
623
+ );
624
+ $result = isset($orders[$order]) ? $orders[$order] : $orders[self::ORDER_DATE];
625
+ $result = " ORDER BY ${result} ";
626
+ return $result;
627
+ }
628
+
629
+ const FLAGS_NOTEXISTING = 1;
630
+
631
+ protected function GetWhere($flags = 0)
632
+ {
633
+ $conditions = array();
634
+ if ($flags & self::FLAGS_NOTEXISTING)
635
+ $conditions[] = '(file_exists=0)';
636
+ else
637
+ $conditions[] = '(file_exists<>0)';
638
+ if ($conditions)
639
+ $result = ' WHERE ' . implode(' AND ', $conditions);
640
+ else
641
+ $result = '';
642
+ return $result;
643
+ }
644
+
645
+ protected function GetDetailWhere($flags = 0)
646
+ {
647
+ $conditions = array();
648
+ if ($conditions)
649
+ $result = ' AND ' . implode(' AND ', $conditions);
650
+ else
651
+ $result = '';
652
+ return $result;
653
+ }
654
+
655
+ protected function GetLimit($from = 0)
656
+ {
657
+ $from = intval($from);
658
+ if ($from < 0)
659
+ $from = 0;
660
+ $count = self::RECORDS_PER_PAGE;
661
+ $result = " LIMIT ${from}, ${count} ";
662
+ return $result;
663
+ }
664
+
665
+ protected function GetUrlForList($options = array(), $html = TRUE)
666
+ {
667
+ $amp = $html ? '&amp;' : '&';
668
+ $result = get_option('site_url') . 'tools.php?page=' . basename(__FILE__);
669
+ foreach ($options as $name => $value)
670
+ if ($value)
671
+ $result .= $amp . ($html ? htmlspecialchars($name) : $name) . '=' . ($html ? htmlspecialchars($value) : $value);
672
+ return $result;
673
+
674
+ }
675
+
676
+ protected function Paginator($options, $count)
677
+ {
678
+ $from = intval($options['from']);
679
+ $count = intval($count);
680
+ $pages = array();
681
+ if ($from > 0)
682
+ {
683
+ $pages[] = '<div style="float: left;">';
684
+ $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>0))) . '">' . __("First", self::GETTEXT_REALM) . '</a>';
685
+ $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>($from>self::RECORDS_PER_PAGE ? $from-self::RECORDS_PER_PAGE : 0)))) . '">' . __("Previous", self::GETTEXT_REALM) . '</a>';
686
+ $pages[] = '</div>';
687
+ }
688
+
689
+ if (($from + self::RECORDS_PER_PAGE) < $count)
690
+ {
691
+ $pages[] = '<div style="float: right;">';
692
+ $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>$from+self::RECORDS_PER_PAGE))) . '">' . __("Next", self::GETTEXT_REALM) . '</a>';
693
+ $pages[] = '<a href="' . $this->GetUrlForList(array_merge($options, array('from'=>$count-self::RECORDS_PER_PAGE))) . '">' . __("Last", self::GETTEXT_REALM) . '</a>';
694
+ $pages[] = '</div>';
695
+ }
696
+ $result = $pages ? '<div class="pages-list">' . implode(' ', $pages) . '<div style="clear: both;" /></div>' : '';
697
+ return $result;
698
+ }
699
+
700
+ protected function IsAdmin()
701
+ {
702
+ if (current_user_can(get_option(self::PREFIX . 'rights_delete')))
703
+ /*
704
+ global $user_level;
705
+ get_currentuserinfo();
706
+ if ($user_level >= 10)
707
+ */
708
+ return TRUE;
709
+ else
710
+ return FALSE;
711
+ }
712
+
713
+ protected function HideDownloads($show_ids, $hide_ids = array())
714
+ {
715
+ global $wpdb;
716
+ $show_ids = implode(',', array_map('intval', $show_ids));
717
+ $hide_ids = implode(',', array_map('intval', $hide_ids));
718
+ $downloads = $this->table_downloads();
719
+ if ($show_ids)
720
+ {
721
+ $sql = "UPDATE ${downloads} SET hide_from_sidebar=0, last_date=last_date WHERE id IN (${show_ids})";
722
+ // The last_date is used to prevent automatic update to current_timestamp
723
+ $wpdb->query($sql);
724
+ }
725
+ if ($hide_ids)
726
+ {
727
+ $sql = "UPDATE ${downloads} SET hide_from_sidebar=1, last_date=last_date WHERE id IN (${hide_ids})";
728
+ // The last_date is used to prevent automatic update to current_timestamp
729
+ $wpdb->query($sql);
730
+ }
731
+ //wp_redirect($_SERVER['REQUEST_URI']);
732
+ //die();
733
+ }
734
+
735
+ protected function DeleteDownloadDetails($ids = array())
736
+ {
737
+ global $wpdb;
738
+ $ids = array_map('intval', $ids);
739
+ if ($ids)
740
+ {
741
+ $ids = implode(',', $ids);
742
+ $downloads = $this->table_downloads();
743
+ $details = $this->table_details();
744
+ $downloadids = array();
745
+ $sql = "SELECT DISTINCT download FROM ${details} WHERE id IN (${ids})";
746
+ $results = $wpdb->get_results($sql, ARRAY_N);
747
+ if (is_array($results))
748
+ foreach ($results as $row)
749
+ {
750
+ list($downloadid) = $row;
751
+ $downloadids[] = $downloadid;
752
+ }
753
+ if ($downloadids) {
754
+ $sql = "DELETE FROM ${details} WHERE id IN (${ids})";
755
+ $wpdb->query($sql);
756
+ foreach ($downloadids as $downloadid)
757
+ {
758
+ $sql = "SELECT COUNT(*), MAX(download_date) FROM ${details} WHERE download=%d";
759
+ $result = $wpdb->get_row($wpdb->prepare($sql, $downloadid), ARRAY_N);
760
+ if (is_array($result))
761
+ {
762
+ list($count, $date) = $result;
763
+ $sql = "UPDATE ${downloads} SET download_count=%d, last_date=%s WHERE id=%d";
764
+ $wpdb->query($wpdb->prepare($sql, $count, $date, $downloadid));
765
+ }
766
+ }
767
+ }
768
+ }
769
+ //wp_redirect($_SERVER['REQUEST_URI']);
770
+ //die();
771
+ }
772
+
773
+ protected function DeleteDownloads($ids = array())
774
+ {
775
+ global $wpdb;
776
+ $ids = array_map('intval', $ids);
777
+ if ($ids)
778
+ {
779
+ $ids = implode(',', $ids);
780
+ $downloads = $this->table_downloads();
781
+ $details = $this->table_details();
782
+ $sql = "DELETE FROM ${downloads} WHERE id IN (${ids})";
783
+ $wpdb->query($sql);
784
+ $sql = "DELETE FROM ${details} WHERE download IN (${ids})";
785
+ $wpdb->query($sql);
786
+ }
787
+ //wp_redirect($_SERVER['REQUEST_URI']);
788
+ //die();
789
+ }
790
+
791
+ protected function DeleteAllDownloads()
792
+ {
793
+ global $wpdb;
794
+ $downloads = $this->table_downloads();
795
+ $details = $this->table_details();
796
+ $sql = "DELETE FROM ${downloads}";
797
+ $wpdb->query($sql);
798
+ $sql = "DELETE FROM ${details}";
799
+ $wpdb->query($sql);
800
+ //wp_redirect($_SERVER['REQUEST_URI']);
801
+ //die();
802
+ }
803
+
804
+ protected function DownloadList($options)
805
+ {
806
+ global $wpdb;
807
+ $flags = $options['flags'];
808
+ $from = $options['from'];
809
+ $order = $options['order'];
810
+ $detailed = get_option(self::PREFIX . 'detailed');
811
+ ?>
812
+ <div class="wrap">
813
+ <h2><?php echo __('Simple Download Monitor', self::GETTEXT_REALM); ?></h2>
814
+ <h3><?php echo ($options['flags'] & self::FLAGS_NOTEXISTING) ? __('Nonexistent downloads', self::GETTEXT_REALM) : __('All downloads', self::GETTEXT_REALM); ?></h3>
815
+ <p><a href="<?php echo $this->GetUrlForList(array_merge($options, array('from' => 0, 'flags' => $options['flags']^self::FLAGS_NOTEXISTING))); ?>"><?php echo ($options['flags'] & self::FLAGS_NOTEXISTING) ? __('Show all downloads', self::GETTEXT_REALM) : __('Show nonexistent downloads', self::GETTEXT_REALM); ?></a></p>
816
+ <?php if ($this->isAdmin()): ?>
817
+ <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
818
+ <?php endif; ?>
819
+ <table id="sdmon">
820
+ <colgroup>
821
+ <col class="sdmon-rownum" align="right" width="32" />
822
+ <col class="sdmon-filename" />
823
+ <col class="sdmon-count" align="right" width="64" />
824
+ <col class="sdmon-date" align="center" />
825
+ <col class="sdmon-hidden" />
826
+ <col class="sdmon-delete" />
827
+ </colgroup>
828
+ <thead>
829
+ <tr>
830
+ <th>&nbsp;</th>
831
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_NAME ))); ?>"><?php echo __("Filename", self::GETTEXT_REALM); ?></a></th>
832
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_COUNT))); ?>"><?php echo __("Download count", self::GETTEXT_REALM); ?></a></th>
833
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_DATE ))); ?>"><?php echo __("Last date", self::GETTEXT_REALM); ?></a></th>
834
+ <th><?php echo __('Hide from sidebar', self::GETTEXT_REALM); ?></th>
835
+ <th><?php echo __('Reset to zero', self::GETTEXT_REALM); ?></th>
836
+ </tr>
837
+ </thead>
838
+ <tbody><?php
839
+ $table_downloads = $this->table_downloads();
840
+ $where = $this->GetWhere($flags);
841
+ $orderby = $this->GetOrderBy($order);
842
+ $limit = $this->GetLimit($from);
843
+ $sql = "SELECT id, filename, download_count, last_date, file_exists, hide_from_sidebar FROM ${table_downloads} ${where} ${orderby} ${limit}";
844
+ $totalcount = $wpdb->get_var("SELECT COUNT(*) FROM ${table_downloads} ${where}");
845
+ $results = $wpdb->get_results($sql, ARRAY_N);
846
+ $rownum = intval($options['from']);
847
+ if (is_array($results)) {
848
+ foreach ($results as $row) {
849
+ $rownum++;
850
+ list($download, $filename, $count, $date, $exists, $hidden) = $row;
851
+ ?>
852
+ <tr<?php if (!$exists) echo ' class="not-exist"'; ?>>
853
+ <td><?php echo $rownum; ?>.</td>
854
+ <td><?php if ($detailed): ?><a href="<?php echo $this->GetUrlForList(array('download' => $download)); ?>"><?php endif; echo htmlspecialchars($filename); if ($detailed): ?></a><?php endif; ?></td>
855
+ <td><?php echo $count; ?></td>
856
+ <td><?php echo mysql2date('Y-m-d H:i:s', $date, TRUE); ?></td>
857
+ <td><?php if ($this->IsAdmin()): ?>
858
+ <input type="checkbox" name="SimpleDownloadMonitor_HideIds[]" value="<?php echo $download; ?>" <?php if ($hidden) echo ' checked="checked"'; ?> />
859
+ <input type="hidden" name="SimpleDownloadMonitor_ShowIds[]" value="<?php echo $download; ?>" />
860
+ <label for="SimpleDownloadMonitor_HideIds[]" /> <?php echo __('Hidden', self::GETTEXT_REALM); ?></label>
861
+ <?php else: ?>&nbsp;<?php endif; ?>
862
+ </td>
863
+ <td><?php if ($this->IsAdmin()): ?>
864
+ <input type="checkbox" name="SimpleDownloadMonitor_DeleteIds[]" value="<?php echo $download; ?>" />
865
+ <label for="SimpleDownloadMonitor_DeleteIds[]"> <?php echo __('Reset', self::GETTEXT_REALM); ?></label>
866
+ <?php else: ?>&nbsp;<?php endif; ?>
867
+ </td>
868
+ </tr>
869
+ </tbody><?php
870
+ }
871
+ }
872
+ ?>
873
+ </table>
874
+ <?php if ($this->isAdmin()): ?>
875
+ <div><input type="submit" name="SimpleDownloadMonitor_Update" value="<?php echo __('Update settings', self::GETTEXT_REALM); ?>" /></div>
876
+ <div><input type="submit" name="SimpleDownloadMonitor_Delete" value="<?php echo __('Reset checked statistics', self::GETTEXT_REALM); ?>" /></div>
877
+ <div><input type="submit" name="SimpleDownloadMonitor_DeleteAll" value="<?php echo __('Reset all statistics', self::GETTEXT_REALM); ?>" /> - <input type="checkbox" name="SimpleDownloadMonitor_DeleteAllReally" value="yes" /><label for="SimpleDownloadMonitor_DeleteAllReally"> <?php echo __('Yes, I am sure', self::GETTEXT_REALM); ?></label></div>
878
+ </form>
879
+ <?php endif; ?>
880
+ <?php echo $this->Paginator($options, $totalcount); ?>
881
+ </div><?php
882
+ }
883
+
884
+ protected function DetailedDownloadList($options)
885
+ {
886
+ global $wpdb;
887
+ $flags = $options['flags'];
888
+ $from = $options['from'];
889
+ $order = $options['order'];
890
+ $download = $options['download'];
891
+ $detailed = $options['detailed'];
892
+ $table_downloads = $this->table_downloads();
893
+ list($id, $filename, $count) = $wpdb->get_row($wpdb->prepare("SELECT id, filename, download_count FROM ${table_downloads} WHERE id=%d", $download), ARRAY_N);
894
+ if (!$id)
895
+ {
896
+ $this->DownloadList($options);
897
+ return;
898
+ }
899
+ else
900
+ {
901
+ ?>
902
+ <div class="wrap">
903
+ <h2><?php echo __('Simple Download Monitor', self::GETTEXT_REALM); ?></h2>
904
+ <h3><?php printf(__('Detailed data for <strong>%s</strong>:', self::GETTEXT_REALM), $filename); ?></h3>
905
+ <p><?php printf(__('Total number of downloads: <strong>%d</strong>.', self::GETTEXT_REALM), $count); ?></p>
906
+ <?php if ($this->isAdmin()): ?>
907
+ <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
908
+ <?php endif; ?>
909
+ <table id="sdmon">
910
+ <colgroup>
911
+ <col class="sdmon-rownum" align="right" width="32" />
912
+ <col class="sdmon-date" align="center" />
913
+ <col class="sdmon-ipaddr" />
914
+ <col class="sdmon-country" />
915
+ <col class="sdmon-referer" />
916
+ <col class="sdmon-username" />
917
+ <col class="sdmon-tools" />
918
+ </colgroup>
919
+ <thead>
920
+ <tr>
921
+ <th>&nbsp;</th>
922
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_DATE ))); ?>"><?php echo __("Date", self::GETTEXT_REALM); ?></a></th>
923
+ <th><?php echo __("Country", self::GETTEXT_REALM); ?></th>
924
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_IP ))); ?>"><?php echo __("IP address", self::GETTEXT_REALM); ?></a></th>
925
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_REFERER))); ?>"><?php echo __("Referer", self::GETTEXT_REALM); ?></a></th>
926
+ <th><a href="<?php echo $this->GetUrlForList(array_merge($options, array('order' => self::ORDER_USER ))); ?>"><?php echo __("Username", self::GETTEXT_REALM); ?></a></th>
927
+ <th>&nbsp;</th>
928
+ </tr>
929
+ </thead>
930
+ <tbody><?php
931
+ $table_details = $this->table_details();
932
+ $where = $this->GetDetailWhere($flags);
933
+ $orderby = $this->GetDetailOrderBy($order);
934
+ $limit = $this->GetLimit($from);
935
+ if (class_exists('PepakIpToCountry'))
936
+ {
937
+ $ip_loc = PepakIpToCountry::Subselect("INET_ATON(${table_details}.ip)", 'iso_code2');
938
+ }
939
+ else
940
+ $ip_loc = 'NULL';
941
+ $sql = "SELECT id, download_date, ip, referer, userid, username, ${ip_loc} iso_code2 FROM ${table_details} WHERE download=%d ${where} ${orderby} ${limit}";
942
+ $totalcount = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM ${table_details} WHERE download=%d ${where}", $download));
943
+ $results = $wpdb->get_results($wpdb->prepare($sql, $download), ARRAY_N);
944
+ $rownum = intval($options['from']);
945
+ foreach ($results as $row) {
946
+ $rownum++;
947
+ list($id, $date, $ip, $referer, $userid, $username, $country) = $row;
948
+ if (class_exists('PepakIpToCountry') AND (PepakIpToCountry::VERSION>='0.03'))
949
+ $country_flag = PepakIpToCountry::IP_to_Country_Flag($ip);
950
+ else
951
+ {
952
+ $country = strtolower($country);
953
+ $country_flag = ($country && file_exists($this->plugin_dir.'/flags/'.$country.'.png')) ? '<img src="'.$this->plugin_url.'/flags/'.$country.'.png" alt="'.$country.'" />' : '';
954
+ }
955
+ ?>
956
+ <tr>
957
+ <td><?php echo $rownum; ?>.</td>
958
+ <td><?php echo mysql2date('Y-m-d H:i:s', $date, TRUE); ?></td>
959
+ <td><?php echo ($country_flag) ? $country_flag : '&nbsp;'; ?></td>
960
+ <td><?php echo htmlspecialchars($ip); ?></td>
961
+ <td><?php echo htmlspecialchars($referer); ?></td>
962
+ <td><?php echo htmlspecialchars($username); ?></td>
963
+ <td><?php if ($this->IsAdmin()): ?><input type="checkbox" name="SimpleDownloadMonitor_DeleteIds[]" value="<?php echo $id; ?>" /><label for="SimpleDownloadMonitor_DeleteIds[]"> <?php echo __('Delete this statistic', self::GETTEXT_REALM); ?></label><?php else: ?>&nbsp;<?php endif; ?></td>
964
+ </tr>
965
+ </tbody><?php
966
+ }
967
+ }
968
+ ?>
969
+ </table>
970
+ <?php if ($this->isAdmin()): ?>
971
+ <div><input type="submit" name="SimpleDownloadMonitor_DeleteDetail" value="<?php echo __('Delete checked statistics', self::GETTEXT_REALM); ?>" /></div>
972
+ </form>
973
+ <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
974
+ <div><input type="submit" name="SimpleDownloadMonitor_Delete" value="<?php echo __('Delete all statistics', self::GETTEXT_REALM); ?>" /> - <input type="checkbox" name="SimpleDownloadMonitor_DeleteIds[]" value="<?php echo $download; ?>" /> <?php echo __('Yes, I am sure', self::GETTEXT_REALM); ?></label></div>
975
+ </form>
976
+ <?php endif; ?>
977
+ <?php echo $this->Paginator($options, $totalcount); ?>
978
+ <p><a href="<?php echo $this->GetUrlForList(); ?>"><?php echo __('Return to full list.', self::GETTEXT_REALM); ?></a></p>
979
+ </div><?php
980
+ }
981
+
982
+ public function ActionHead()
983
+ {
984
+ echo '<link type="text/css" rel="stylesheet" href="' . $this->plugin_url . '/css/sdmon.css" />'."\n";
985
+ }
986
+
987
+ }
988
+ }
989
+
990
+ if (!isset($sdmon))
991
+ $sdmon = new SimpleDownloadMonitor();
992
+
993
+ if (!function_exists('SimpleDownloadMonitor_BuildAdminMenu'))
994
+ {
995
+ function SimpleDownloadMonitor_BuildAdminMenu()
996
+ {
997
+ global $sdmon;
998
+ if (isset($sdmon))
999
+ {
1000
+ $rights_options = get_option(SimpleDownloadMonitor::PREFIX . 'rights_options');
1001
+ $rights_view = get_option(SimpleDownloadMonitor::PREFIX . 'rights_view');
1002
+ if (!$rights_options) $rights_options = 'manage_options';
1003
+ if (!$rights_view) $rights_view = 'read';
1004
+ $options_page = add_options_page(__('Simple Download Monitor options', SimpleDownloadMonitor::GETTEXT_REALM), __('Simple Download Monitor', SimpleDownloadMonitor::GETTEXT_REALM), $rights_options, basename(__FILE__), array(&$sdmon, 'AdminPanel'));
1005
+ $tool_page = add_submenu_page('tools.php', __('Simple Download Monitor', SimpleDownloadMonitor::GETTEXT_REALM), __('Simple Download Monitor', SimpleDownloadMonitor::GETTEXT_REALM), $rights_view, basename(__FILE__), array(&$sdmon, 'ToolsPanel'));
1006
+ add_action('admin_head-'.$tool_page, array(&$sdmon, 'ActionHead'));
1007
+ }
1008
+ }
1009
+ }
1010
+
1011
+ if (!class_exists('SimpleDownloadMonitor_Widget'))
1012
+ {
1013
+ class SimpleDownloadMonitor_Widget extends WP_Widget
1014
+ {
1015
+ function SimpleDownloadMonitor_Widget()
1016
+ {
1017
+ $widget_options = array(
1018
+ 'classname' => 'sdmon',
1019
+ 'description' => __('Allows you to display the most popular downloads in the sidebar.', SimpleDownloadMonitor::GETTEXT_REALM)
1020
+ );
1021
+ $control_options = array(
1022
+ //'width' => 250,
1023
+ //'height' => 0,
1024
+ 'id_base' => 'sdmon-widget'
1025
+ );
1026
+ $this->WP_Widget('sdmon-widget', 'Simple Download Monitor', $widget_options, $control_options);
1027
+ }
1028
+
1029
+ function widget($arguments, $instance)
1030
+ {
1031
+ global $wpdb;
1032
+ $title = apply_filters('widget_title', $instance['title']);
1033
+ $count = intval(isset($instance['count']) ? intval($instance['count']) : 0);
1034
+ if ($count <= 0) $count = 10;
1035
+ $like = isset($instance['like']) ? $instance['like'] : '';
1036
+ echo $arguments['before_widget'];
1037
+ if ($title) echo $arguments['before_title'] . $title . $arguments['after_title'];
1038
+ $downloads = SimpleDownloadMonitor::table_downloads();
1039
+ $liketest = $like ? ' AND filename LIKE "%s"' : '';
1040
+ $sql = "SELECT id, filename, download_count FROM ${downloads} WHERE file_exists<>0 AND COALESCE(hide_from_sidebar,0)=0 ${liketest} ORDER BY download_count DESC LIMIT ${count}";
1041
+ $results = $wpdb->get_results($wpdb->prepare($sql, $like), ARRAY_N);
1042
+ echo "<ul>\n";
1043
+ foreach ($results as $row)
1044
+ {
1045
+ list($id, $filename, $downloadcount) = $row;
1046
+ ?><li><a href="/<?php echo esc_attr($filename); ?>"><?php echo htmlspecialchars(basename($filename)); ?></a> <strong><?php echo $downloadcount; ?></strong></li><?php
1047
+ }
1048
+ echo "</ul>\n";
1049
+ echo $arguments['after_widget'];
1050
+ }
1051
+
1052
+ function update($new_instance, $old_instance)
1053
+ {
1054
+ $instance = $old_instance;
1055
+ $instance['title'] = strip_tags($new_instance['title']);
1056
+ $instance['count'] = intval($new_instance['count']);
1057
+ $instance['like'] = $new_instance['like'];
1058
+ return $instance;
1059
+ }
1060
+
1061
+ function form($instance)
1062
+ {
1063
+ $defaults = array(
1064
+ 'title' => __('Popular files', SimpleDownloadMonitor::GETTEXT_REALM),
1065
+ 'count' => '10',
1066
+ 'like' => ''
1067
+ );
1068
+ $instance = wp_parse_args((array) $instance, $defaults);
1069
+ ?><p>
1070
+ <label for="<?php echo $this->get_field_id('title'); ?>"><?php echo __('Title:', SimpleDownloadMonitor::GETTEXT_REALM); ?></label>
1071
+ <input id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title']); ?>" type="text" style="width: 100%;" />
1072
+ </p>
1073
+ <p>
1074
+ <label for="<?php echo $this->get_field_id('count'); ?>"><?php echo __('Number of files to show:', SimpleDownloadMonitor::GETTEXT_REALM); ?></label>
1075
+ <input id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>" value="<?php echo esc_attr($instance['count']); ?>" type="text" />
1076
+ </p><p>
1077
+ <label for="<?php echo $this->get_field_id('like'); ?>"><?php echo __('Only show filenames which match this LIKE condition:', SimpleDownloadMonitor::GETTEXT_REALM); ?></label>
1078
+ <input id="<?php echo $this->get_field_id('like'); ?>" name="<?php echo $this->get_field_name('like'); ?>" value="<?php echo esc_attr($instance['like']); ?>" type="text" style="width: 100%;" />
1079
+ <br /><?php echo __("Empty string matches all filenames and is useful for most usage scenarios. You would only use a non-empty value if you wanted to create multiple SDMon widgets, each showing a different list of files: only filenames which match the given string in a LIKE condition of a SQL query will be shown. The most common values would be something like <code>files/documents/%</code> (meaning \"The filename must begin with <code>files/documents/</code>\") or <code>%.mp3</code> (meaning \"The filename must end with <code>.mp3</code>\") - the percentage symbol <code>%</code> means \"anything\", the underscore symbol <code>_</code> means \"Any one character\".", SimpleDownloadMonitor::GETTEXT_REALM); ?>
1080
+ </p><?php
1081
+ }
1082
+
1083
+ }
1084
+ }
1085
+
1086
+ if (!function_exists('SimpleDownloadMonitorWidget_Init'))
1087
+ {
1088
+ function SimpleDownloadMonitorWidget_Init()
1089
+ {
1090
+ register_widget('SimpleDownloadMonitor_Widget');
1091
+ }
1092
+
1093
+ }
1094
+
1095
+ add_action('widgets_init', 'SimpleDownloadMonitorWidget_Init');