Skip to content

Commit de5a1e1

Browse files
committed
Merge branch 'master' into jquery-ui
2 parents 86786bf + aa5ed85 commit de5a1e1

File tree

3 files changed

+191
-49
lines changed

3 files changed

+191
-49
lines changed

server/php/files/.htaccess

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1+
# The following directives force the Content-Type
2+
# "application/octet-stream" for all files except images.
3+
# This prevents executing any uploaded scripts
4+
# and forces a download dialog for non-image files:
15
ForceType application/octet-stream
26
<FilesMatch "(?i)\.(gif|jpe?g|png)$">
37
ForceType none
4-
</FilesMatch>
8+
</FilesMatch>
9+
10+
# Uncomment the following lines to prevent unauthorized download of files:
11+
#AuthName "Authorization required"
12+
#AuthType Basic
13+
#require valid-user

server/php/thumbnails/.htaccess

Whitespace-only changes.

server/php/upload.class.php

Lines changed: 181 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
/*
3-
* jQuery File Upload Plugin PHP Class 5.15
3+
* jQuery File Upload Plugin PHP Class 5.17
44
* https://github.com/blueimp/jQuery-File-Upload
55
*
66
* Copyright 2010, Sebastian Tschan
@@ -38,16 +38,23 @@ function __construct($options = null, $initialize = true) {
3838
'script_url' => $this->get_full_url().'/',
3939
'upload_dir' => dirname($_SERVER['SCRIPT_FILENAME']).'/files/',
4040
'upload_url' => $this->get_full_url().'/files/',
41+
'user_dirs' => false,
42+
'mkdir_mode' => 0755,
4143
'param_name' => 'files',
4244
// Set the following option to 'POST', if your server does not support
4345
// DELETE requests. This is a parameter sent to the client:
4446
'delete_type' => 'DELETE',
4547
'access_control_allow_origin' => '*',
48+
// Enable to provide file downloads via GET requests to the PHP script:
49+
'download_via_php' => false,
50+
// Defines which files can be displayed inline when downloaded:
51+
'inline_file_types' => '/\.(gif|jpe?g|png)$/i',
52+
// Defines which files (based on their names) are accepted for upload:
53+
'accept_file_types' => '/.+$/i',
4654
// The php.ini settings upload_max_filesize and post_max_size
4755
// take precedence over the following max_file_size setting:
4856
'max_file_size' => null,
4957
'min_file_size' => 1,
50-
'accept_file_types' => '/.+$/i',
5158
// The maximum number of files for the upload directory:
5259
'max_number_of_files' => null,
5360
// Image resolution restrictions:
@@ -61,20 +68,23 @@ function __construct($options = null, $initialize = true) {
6168
'orient_image' => false,
6269
'image_versions' => array(
6370
// Uncomment the following version to restrict the size of
64-
// uploaded images. You can also add additional versions with
65-
// their own upload directories:
71+
// uploaded images:
6672
/*
67-
'large' => array(
68-
'upload_dir' => dirname($_SERVER['SCRIPT_FILENAME']).'/files/',
69-
'upload_url' => $this->get_full_url().'/files/',
73+
'' => array(
7074
'max_width' => 1920,
7175
'max_height' => 1200,
7276
'jpeg_quality' => 95
7377
),
7478
*/
79+
// Uncomment the following to create medium sized images:
80+
/*
81+
'medium' => array(
82+
'max_width' => 800,
83+
'max_height' => 600,
84+
'jpeg_quality' => 80
85+
),
86+
*/
7587
'thumbnail' => array(
76-
'upload_dir' => dirname($_SERVER['SCRIPT_FILENAME']).'/thumbnails/',
77-
'upload_url' => $this->get_full_url().'/thumbnails/',
7888
'max_width' => 80,
7989
'max_height' => 80
8090
)
@@ -98,11 +108,7 @@ protected function initialize() {
98108
$this->get();
99109
break;
100110
case 'POST':
101-
if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') {
102-
$this->delete();
103-
} else {
104-
$this->post();
105-
}
111+
$this->post();
106112
break;
107113
case 'DELETE':
108114
$this->delete();
@@ -123,7 +129,39 @@ protected function get_full_url() {
123129
substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
124130
}
125131

126-
protected function set_file_delete_url($file) {
132+
protected function get_user_id() {
133+
@session_start();
134+
return session_id();
135+
}
136+
137+
protected function get_user_path() {
138+
if ($this->options['user_dirs']) {
139+
return $this->get_user_id().'/';
140+
}
141+
return '';
142+
}
143+
144+
protected function get_upload_path($file_name = null, $version = null) {
145+
$file_name = $file_name ? $file_name : '';
146+
$version_path = empty($version) ? '' : $version.'/';
147+
return $this->options['upload_dir'].$this->get_user_path()
148+
.$version_path.$file_name;
149+
}
150+
151+
protected function get_download_url($file_name, $version = null) {
152+
if ($this->options['download_via_php']) {
153+
$url = $this->options['script_url'].'?file='.rawurlencode($file_name);
154+
if ($version) {
155+
$url .= '&version='.rawurlencode($version);
156+
}
157+
return $url.'&download=1';
158+
}
159+
$version_path = empty($version) ? '' : rawurlencode($version).'/';
160+
return $this->options['upload_url'].$this->get_user_path()
161+
.$version_path.rawurlencode($file_name);
162+
}
163+
164+
protected function set_file_delete_properties($file) {
127165
$file->delete_url = $this->options['script_url']
128166
.'?file='.rawurlencode($file->name);
129167
$file->delete_type = $this->options['delete_type'];
@@ -149,35 +187,64 @@ protected function get_file_size($file_path, $clear_stat_cache = false) {
149187

150188
}
151189

152-
protected function get_file_object($file_name) {
153-
$file_path = $this->options['upload_dir'].$file_name;
190+
protected function is_valid_file_object($file_name) {
191+
$file_path = $this->get_upload_path($file_name);
154192
if (is_file($file_path) && $file_name[0] !== '.') {
193+
return true;
194+
}
195+
return false;
196+
}
197+
198+
protected function get_file_object($file_name) {
199+
if ($this->is_valid_file_object($file_name)) {
155200
$file = new stdClass();
156201
$file->name = $file_name;
157-
$file->size = $this->get_file_size($file_path);
158-
$file->url = $this->options['upload_url'].rawurlencode($file->name);
202+
$file->size = $this->get_file_size(
203+
$this->get_upload_path($file_name)
204+
);
205+
$file->url = $this->get_download_url($file->name);
159206
foreach($this->options['image_versions'] as $version => $options) {
160-
if (is_file($options['upload_dir'].$file_name)) {
161-
$file->{$version.'_url'} = $options['upload_url']
162-
.rawurlencode($file->name);
207+
if (!empty($version)) {
208+
if (is_file($this->get_upload_path($file_name, $version))) {
209+
$file->{$version.'_url'} = $this->get_download_url(
210+
$file->name,
211+
$version
212+
);
213+
}
163214
}
164215
}
165-
$this->set_file_delete_url($file);
216+
$this->set_file_delete_properties($file);
166217
return $file;
167218
}
168219
return null;
169220
}
170221

171-
protected function get_file_objects() {
222+
protected function get_file_objects($iteration_method = 'get_file_object') {
223+
$upload_dir = $this->get_upload_path();
224+
if (!is_dir($upload_dir)) {
225+
mkdir($upload_dir, $this->options['mkdir_mode']);
226+
}
172227
return array_values(array_filter(array_map(
173-
array($this, 'get_file_object'),
174-
scandir($this->options['upload_dir'])
228+
array($this, $iteration_method),
229+
scandir($upload_dir)
175230
)));
176231
}
177232

178-
protected function create_scaled_image($file_name, $options) {
179-
$file_path = $this->options['upload_dir'].$file_name;
180-
$new_file_path = $options['upload_dir'].$file_name;
233+
protected function count_file_objects() {
234+
return count($this->get_file_objects('is_valid_file_object'));
235+
}
236+
237+
protected function create_scaled_image($file_name, $version, $options) {
238+
$file_path = $this->get_upload_path($file_name);
239+
if (!empty($version)) {
240+
$version_dir = $this->get_upload_path(null, $version);
241+
if (!is_dir($version_dir)) {
242+
mkdir($version_dir, $this->options['mkdir_mode']);
243+
}
244+
$new_file_path = $version_dir.'/'.$file_name;
245+
} else {
246+
$new_file_path = $file_path;
247+
}
181248
list($img_width, $img_height) = @getimagesize($file_path);
182249
if (!$img_width || !$img_height) {
183250
return false;
@@ -272,7 +339,7 @@ protected function validate($uploaded_file, $file, $error, $index) {
272339
return false;
273340
}
274341
if (is_int($this->options['max_number_of_files']) && (
275-
count($this->get_file_objects()) >= $this->options['max_number_of_files'])
342+
$this->count_file_objects() >= $this->options['max_number_of_files'])
276343
) {
277344
$file->error = $this->get_error_message('max_number_of_files');
278345
return false;
@@ -324,10 +391,13 @@ protected function trim_file_name($name, $type, $index, $content_range) {
324391
preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
325392
$file_name .= '.'.$matches[1];
326393
}
394+
while(is_dir($this->get_upload_path($file_name))) {
395+
$file_name = $this->upcount_name($file_name);
396+
}
327397
$uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1]));
328-
while(is_file($this->options['upload_dir'].$file_name)) {
398+
while(is_file($this->get_upload_path($file_name))) {
329399
if ($uploaded_bytes === $this->get_file_size(
330-
$this->options['upload_dir'].$file_name)) {
400+
$this->get_upload_path($file_name))) {
331401
break;
332402
}
333403
$file_name = $this->upcount_name($file_name);
@@ -376,7 +446,11 @@ protected function handle_file_upload($uploaded_file, $name, $size, $type, $erro
376446
$file->type = $type;
377447
if ($this->validate($uploaded_file, $file, $error, $index)) {
378448
$this->handle_form_data($file, $index);
379-
$file_path = $this->options['upload_dir'].$file->name;
449+
$upload_dir = $this->get_upload_path();
450+
if (!is_dir($upload_dir)) {
451+
mkdir($upload_dir, $this->options['mkdir_mode']);
452+
}
453+
$file_path = $this->get_upload_path($file->name);
380454
$append_file = $content_range && is_file($file_path) &&
381455
$file->size > $this->get_file_size($file_path);
382456
if ($uploaded_file && is_uploaded_file($uploaded_file)) {
@@ -403,12 +477,14 @@ protected function handle_file_upload($uploaded_file, $name, $size, $type, $erro
403477
if ($this->options['orient_image']) {
404478
$this->orient_image($file_path);
405479
}
406-
$file->url = $this->options['upload_url'].rawurlencode($file->name);
480+
$file->url = $this->get_download_url($file->name);
407481
foreach($this->options['image_versions'] as $version => $options) {
408-
if ($this->create_scaled_image($file->name, $options)) {
409-
if ($this->options['upload_dir'] !== $options['upload_dir']) {
410-
$file->{$version.'_url'} = $options['upload_url']
411-
.rawurlencode($file->name);
482+
if ($this->create_scaled_image($file->name, $version, $options)) {
483+
if (!empty($version)) {
484+
$file->{$version.'_url'} = $this->get_download_url(
485+
$file->name,
486+
$version
487+
);
412488
} else {
413489
$file_size = $this->get_file_size($file_path, true);
414490
}
@@ -419,7 +495,7 @@ protected function handle_file_upload($uploaded_file, $name, $size, $type, $erro
419495
$file->error = 'abort';
420496
}
421497
$file->size = $file_size;
422-
$this->set_file_delete_url($file);
498+
$this->set_file_delete_properties($file);
423499
}
424500
return $file;
425501
}
@@ -434,15 +510,69 @@ protected function generate_response($content, $print_response = true) {
434510
return;
435511
}
436512
$this->head();
513+
if (isset($_SERVER['HTTP_CONTENT_RANGE']) && is_array($content) &&
514+
is_object($content[0]) && $content[0]->size) {
515+
header('Range: 0-'.($this->fix_integer_overflow(intval($content[0]->size)) - 1));
516+
}
437517
echo $json;
438518
}
439519
return $content;
440520
}
441521

522+
protected function get_version_param() {
523+
return isset($_GET['version']) ? basename(stripslashes($_GET['version'])) : null;
524+
}
525+
526+
protected function get_file_name_param() {
527+
return isset($_GET['file']) ? basename(stripslashes($_GET['file'])) : null;
528+
}
529+
530+
protected function get_file_type($file_path) {
531+
switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) {
532+
case 'jpeg':
533+
case 'jpg':
534+
return 'image/jpeg';
535+
case 'png':
536+
return 'image/png';
537+
case 'gif':
538+
return 'image/gif';
539+
default:
540+
return '';
541+
}
542+
}
543+
544+
protected function download() {
545+
if (!$this->options['download_via_php']) {
546+
header('HTTP/1.1 403 Forbidden');
547+
return;
548+
}
549+
$file_name = $this->get_file_name_param();
550+
if ($this->is_valid_file_object($file_name)) {
551+
$file_path = $this->get_upload_path($file_name, $this->get_version_param());
552+
if (is_file($file_path)) {
553+
if (!preg_match($this->options['inline_file_types'], $file_name)) {
554+
header('Content-Description: File Transfer');
555+
header('Content-Type: application/octet-stream');
556+
header('Content-Disposition: attachment; filename='.$file_name);
557+
header('Content-Transfer-Encoding: binary');
558+
} else {
559+
// Prevent Internet Explorer from MIME-sniffing the content-type:
560+
header('X-Content-Type-Options: nosniff');
561+
header('Content-Type: '.$this->get_file_type($file_path));
562+
header('Content-Disposition: inline; filename="'.$file_name.'"');
563+
}
564+
header('Content-Length: '.$this->get_file_size($file_path));
565+
header('Last-Modified: '.gmdate('D, d M Y H:i:s T', filemtime($file_path)));
566+
readfile($file_path);
567+
}
568+
}
569+
}
570+
442571
public function head() {
443572
header('Pragma: no-cache');
444573
header('Cache-Control: no-store, no-cache, must-revalidate');
445574
header('Content-Disposition: inline; filename="files.json"');
575+
// Prevent Internet Explorer from MIME-sniffing the content-type:
446576
header('X-Content-Type-Options: nosniff');
447577
if ($this->options['access_control_allow_origin']) {
448578
header('Access-Control-Allow-Origin: '.$this->options['access_control_allow_origin']);
@@ -459,8 +589,10 @@ public function head() {
459589
}
460590

461591
public function get($print_response = true) {
462-
$file_name = isset($_REQUEST['file']) ?
463-
basename(stripslashes($_REQUEST['file'])) : null;
592+
if ($print_response && isset($_GET['download'])) {
593+
return $this->download();
594+
}
595+
$file_name = $this->get_file_name_param();
464596
if ($file_name) {
465597
$info = $this->get_file_object($file_name);
466598
} else {
@@ -471,7 +603,7 @@ public function get($print_response = true) {
471603

472604
public function post($print_response = true) {
473605
if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') {
474-
return $this->delete();
606+
return $this->delete($print_response);
475607
}
476608
$upload = isset($_FILES[$this->options['param_name']]) ?
477609
$_FILES[$this->options['param_name']] : null;
@@ -519,15 +651,16 @@ public function post($print_response = true) {
519651
}
520652

521653
public function delete($print_response = true) {
522-
$file_name = isset($_REQUEST['file']) ?
523-
basename(stripslashes($_REQUEST['file'])) : null;
524-
$file_path = $this->options['upload_dir'].$file_name;
654+
$file_name = $this->get_file_name_param();
655+
$file_path = $this->get_upload_path($file_name);
525656
$success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
526657
if ($success) {
527658
foreach($this->options['image_versions'] as $version => $options) {
528-
$file = $options['upload_dir'].$file_name;
529-
if (is_file($file)) {
530-
unlink($file);
659+
if (!empty($version)) {
660+
$file = $this->get_upload_path($file_name, $version);
661+
if (is_file($file)) {
662+
unlink($file);
663+
}
531664
}
532665
}
533666
}

0 commit comments

Comments
 (0)