Simple Download Monitor - Version 0.09

Version Description

  • Fixed incorrect header for file size. That should fix incompatibility with some plugins and downloaders.

  • Support for resumed transfers.

Download this release

Release Info

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

Code changes from version 0.08 to 0.09

Files changed (3) hide show
  1. readme.txt +9 -2
  2. sdmon.css +10 -0
  3. simple-download-monitor.php +150 -8
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: Pepak
3
  Donate link:
4
  Tags: files, counter, count, tracking, download monitor, monitor, downloads, download
5
  Requires at least: 2.8.0
6
- Tested up to: 2.8.4
7
- Stable tag: 0.08
8
 
9
  Count the number of downloads without having to maintain a comprehensive download page.
10
 
@@ -84,6 +84,13 @@ webhosting.
84
 
85
  == Changelog ==
86
 
 
 
 
 
 
 
 
87
  = 0.08 =
88
  * Administrators can now delete download statistics from the Tools panel:
89
  A checkbox is shown next to each record, and a button for deleting checked
3
  Donate link:
4
  Tags: files, counter, count, tracking, download monitor, monitor, downloads, download
5
  Requires at least: 2.8.0
6
+ Tested up to: 2.9.1
7
+ Stable tag: 0.09
8
 
9
  Count the number of downloads without having to maintain a comprehensive download page.
10
 
84
 
85
  == Changelog ==
86
 
87
+ = 0.09 =
88
+
89
+ * Fixed incorrect header for file size. That should fix incompatibility
90
+ with some plugins and downloaders.
91
+
92
+ * Support for resumed transfers.
93
+
94
  = 0.08 =
95
  * Administrators can now delete download statistics from the Tools panel:
96
  A checkbox is shown next to each record, and a button for deleting checked
sdmon.css ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ #sdmon .sdmon-rownum { width: 3ex; text-align: right; }
2
+ #sdmon .sdmon-filename { }
3
+ #sdmon .sdmon-count { text-align: right; }
4
+ #sdmon .sdmon-date { width: 24ex; text-align: center; }
5
+ #sdmon .sdmon-nonex { width: 5ex; text-align: center; }
6
+ #sdmon .sdmon-ipaddr { }
7
+ #sdmon .sdmon-referer { }
8
+ #sdmon .sdmon-username { }
9
+ #sdmon th {text-align: center; }
10
+ #sdmon th, #sdmon td { padding-left: 1ex; padding-right: 1ex; }
simple-download-monitor.php CHANGED
@@ -4,12 +4,12 @@
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.08
8
  Author: Pepak
9
  Author URI: http://www.pepak.net
10
  */
11
 
12
- /* Copyright 2009 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
@@ -110,6 +110,152 @@ if (!class_exists('SimpleDownloadMonitor'))
110
  return $table;
111
  }
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  public function Download($filename)
114
  {
115
  global $wpdb, $user_login, $user_ID;
@@ -169,12 +315,8 @@ if (!class_exists('SimpleDownloadMonitor'))
169
  $inlineregexp = self::PREG_DELIMITER . get_option(self::PREFIX . 'inline') . self::PREG_DELIMITER;
170
  if ($inlineregexp && preg_match($inlineregexp, $relfilename))
171
  $disposition = 'inline';
172
- header('Content-type: ' . $mimetype);
173
- header('Content-disposition: '.$disposition.'; filename=' . basename($fullfilename));
174
- header('Content-size: ' . filesize($fullfilename));
175
- // Send the file to user.
176
- $fp = fopen($fullfilename, 'rb');
177
- fpassthru($fp);
178
  // Successful end
179
  return TRUE;
180
  }
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.09
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
110
  return $table;
111
  }
112
 
113
+ //-----------------------------------------------------------------------------------
114
+ // Methods set_range, buffered_read, byteserve adapted from
115
+ // http://www.coneural.org/florian/papers/04_byteserving.php
116
+
117
+ function set_range($range, $filesize, &$first, &$last){
118
+ /*
119
+ Sets the first and last bytes of a range, given a range expressed as a string
120
+ and the size of the file.
121
+
122
+ If the end of the range is not specified, or the end of the range is greater
123
+ than the length of the file, $last is set as the end of the file.
124
+
125
+ If the begining of the range is not specified, the meaning of the value after
126
+ the dash is "get the last n bytes of the file".
127
+
128
+ If $first is greater than $last, the range is not satisfiable, and we should
129
+ return a response with a status of 416 (Requested range not satisfiable).
130
+
131
+ Examples:
132
+ $range='0-499', $filesize=1000 => $first=0, $last=499 .
133
+ $range='500-', $filesize=1000 => $first=500, $last=999 .
134
+ $range='500-1200', $filesize=1000 => $first=500, $last=999 .
135
+ $range='-200', $filesize=1000 => $first=800, $last=999 .
136
+
137
+ */
138
+ $dash=strpos($range,'-');
139
+ $first=trim(substr($range,0,$dash));
140
+ $last=trim(substr($range,$dash+1));
141
+ if ($first=='') {
142
+ //suffix byte range: gets last n bytes
143
+ $suffix=$last;
144
+ $last=$filesize-1;
145
+ $first=$filesize-$suffix;
146
+ if($first<0) $first=0;
147
+ } else {
148
+ if ($last=='' || $last>$filesize-1) $last=$filesize-1;
149
+ }
150
+ if($first>$last){
151
+ //unsatisfiable range
152
+ header("Status: 416 Requested range not satisfiable");
153
+ header("Content-Range: */$filesize");
154
+ exit;
155
+ }
156
+ }
157
+
158
+ function buffered_read($file, $bytes, $buffer_size=1024){
159
+ /*
160
+ Outputs up to $bytes from the file $file to standard output, $buffer_size bytes at a time.
161
+ */
162
+ $bytes_left=$bytes;
163
+ while($bytes_left>0 && !feof($file)){
164
+ if($bytes_left>$buffer_size)
165
+ $bytes_to_read=$buffer_size;
166
+ else
167
+ $bytes_to_read=$bytes_left;
168
+ $bytes_left-=$bytes_to_read;
169
+ $contents=fread($file, $bytes_to_read);
170
+ echo $contents;
171
+ flush();
172
+ }
173
+ }
174
+
175
+ function byteserve($filename, $mimetype, $disposition = ''){
176
+ /*
177
+ Byteserves the file $filename.
178
+
179
+ When there is a request for a single range, the content is transmitted
180
+ with a Content-Range header, and a Content-Length header showing the number
181
+ of bytes actually transferred.
182
+
183
+ When there is a request for multiple ranges, these are transmitted as a
184
+ multipart message. The multipart media type used for this purpose is
185
+ "multipart/byteranges".
186
+ */
187
+
188
+ $filesize=filesize($filename);
189
+ $file=fopen($filename,"rb");
190
+
191
+ $ranges=NULL;
192
+ if ($_SERVER['REQUEST_METHOD']=='GET' && isset($_SERVER['HTTP_RANGE']) && $range=stristr(trim($_SERVER['HTTP_RANGE']),'bytes=')){
193
+ $range=substr($range,6);
194
+ $boundary=sha1(uniqid());//set a random boundary
195
+ $ranges=explode(',',$range);
196
+ }
197
+
198
+ if($ranges && count($ranges)){
199
+ header("HTTP/1.1 206 Partial content");
200
+ header("Accept-Ranges: bytes");
201
+ if(count($ranges)>1){
202
+ /*
203
+ More than one range is requested.
204
+ */
205
+
206
+ //compute content length
207
+ $content_length=0;
208
+ foreach ($ranges as $range){
209
+ $this->set_range($range, $filesize, $first, $last);
210
+ $content_length+=strlen("\r\n--$boundary\r\n");
211
+ $content_length+=strlen("Content-type: $mimetype\r\n");
212
+ $content_length+=strlen("Content-range: bytes $first-$last/$filesize\r\n\r\n");
213
+ $content_length+=$last-$first+1;
214
+ }
215
+ $content_length+=strlen("\r\n--$boundary--\r\n");
216
+
217
+ //output headers
218
+ header("Content-Length: $content_length");
219
+ //see http://httpd.apache.org/docs/misc/known_client_problems.html for an discussion of x-byteranges vs. byteranges
220
+ header("Content-Type: multipart/x-byteranges; boundary=$boundary");
221
+
222
+ //output the content
223
+ foreach ($ranges as $range){
224
+ $this->set_range($range, $filesize, $first, $last);
225
+ echo "\r\n--$boundary\r\n";
226
+ echo "Content-type: $mimetype\r\n";
227
+ echo "Content-range: bytes $first-$last/$filesize\r\n\r\n";
228
+ fseek($file,$first);
229
+ $this->buffered_read ($file, $last-$first+1);
230
+ }
231
+ echo "\r\n--$boundary--\r\n";
232
+ } else {
233
+ /*
234
+ A single range is requested.
235
+ */
236
+ $range=$ranges[0];
237
+ $this->set_range($range, $filesize, $first, $last);
238
+ header("Content-Length: ".($last-$first+1) );
239
+ header("Content-Range: bytes $first-$last/$filesize");
240
+ header("Content-Type: $mimetype");
241
+ if ($disposition)
242
+ header("Content-Disposition: $disposition");
243
+ fseek($file,$first);
244
+ $this->buffered_read($file, $last-$first+1);
245
+ }
246
+ } else{
247
+ //no byteserving
248
+ header("Accept-Ranges: bytes");
249
+ header("Content-Length: $filesize");
250
+ header("Content-Type: $mimetype");
251
+ if ($disposition)
252
+ header("Content-Disposition: $disposition");
253
+ readfile($filename);
254
+ }
255
+ fclose($file);
256
+ }
257
+ //-----------------------------------------------------------------------------------
258
+
259
  public function Download($filename)
260
  {
261
  global $wpdb, $user_login, $user_ID;
315
  $inlineregexp = self::PREG_DELIMITER . get_option(self::PREFIX . 'inline') . self::PREG_DELIMITER;
316
  if ($inlineregexp && preg_match($inlineregexp, $relfilename))
317
  $disposition = 'inline';
318
+ $disposition = $disposition . '; filename=' . basename($fullfilename);
319
+ $this->byteserve($fullfilename, $mimetype, $disposition);
 
 
 
 
320
  // Successful end
321
  return TRUE;
322
  }