1 package Koha
::Uploader
;
3 # Copyright 2007 LibLime, Galen Charlton
4 # Copyright 2011-2012 BibLibre
5 # Copyright 2015 Rijksmuseum
7 # This file is part of Koha.
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 3 of the License, or (at your option) any later
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License along
19 # with Koha; if not, write to the Free Software Foundation, Inc.,
20 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 Koha::Uploader - Facilitate file uploads (temporary and permanent)
29 use Koha::UploadedFile;
30 use Koha::UploadedFiles;
32 # add an upload (see tools/upload-file.pl)
33 # the public flag allows retrieval via OPAC
34 my $upload = Koha::Uploader->new( public => 1, category => 'A' );
35 my $cgi = $upload->cgi;
36 # Do something with $upload->count, $upload->result or $upload->err
38 # get some upload records (in staff) via Koha::UploadedFiles
39 my @uploads1 = Koha::UploadedFiles->search({ filename => $name });
40 my @uploads2 = Koha::UploadedFiles->search_term({ term => $term });
42 # staff download (via Koha::UploadedFile[s])
43 my $rec = Koha::UploadedFiles->find( $id );
44 my $fh = $rec->file_handle;
45 print Encode::encode_utf8( $input->header( $rec->httpheaders ) );
46 while( <$fh> ) { print $_; }
51 This module is a refactored version of C4::UploadedFile but adds on top
52 of that the new functions from report 6874 (Upload plugin in editor).
53 That report added module UploadedFiles.pm. This module contains the
54 functionality of both.
56 The module has been revised to use Koha::Object[s]; the delete method
57 has been moved to Koha::UploadedFile[s], as well as the get method.
61 use constant KOHA_UPLOAD
=> 'koha_upload';
62 use constant BYTES_DIGEST
=> 2048;
65 use CGI
; # no utf8 flag, since it may interfere with binary uploads
72 use base
qw(Class::Accessor);
76 use Koha
::UploadedFile
;
77 use Koha
::UploadedFiles
;
79 __PACKAGE__
->mk_ro_accessors( qw
|| );
81 =head1 INSTANCE METHODS
85 Returns new object based on Class::Accessor.
86 Use tmp or temp flag for temporary storage.
87 Use public flag to mark uploads as available in OPAC.
88 The category parameter is only useful for permanent storage.
93 my ( $class, $params ) = @_;
94 my $self = $class->SUPER::new
();
95 $self->_init( $params );
101 Returns CGI object. The CGI hook is used to store the uploaded files.
108 # Next call handles the actual upload via CGI hook.
109 # The third parameter (0) below means: no CGI temporary storage.
110 # Cancelling an upload will make CGI abort the script; no problem,
111 # the file(s) without db entry will be removed later.
112 my $query = CGI
::->new( sub { $self->_hook(@_); }, {}, 0 );
121 Returns number of uploaded files without errors
127 return scalar grep { !exists $self->{files
}->{$_}->{errcode
} } keys %{ $self->{files
} };
132 Returns a string of id's for each successful upload separated by commas.
138 my @a = map { $self->{files
}->{$_}->{id
} }
139 grep { !exists $self->{files
}->{$_}->{errcode
} }
140 keys %{ $self->{files
} };
141 return @a?
( join ',', @a ): undef;
146 Returns hash with errors in format { file => err, ... }
147 Undefined if there are no errors.
154 foreach my $f ( keys %{ $self->{files
} } ) {
155 my $e = $self->{files
}->{$f}->{errcode
};
156 $err->{ $f } = $e if $e;
165 allows_add_by checks if $userid has permission to add uploaded files
170 my ( $class, $userid ) = @_; # do not confuse with borrowernumber
172 { tools
=> 'upload_general_files' },
173 { circulate
=> 'circulate_remaining_permissions' },
174 { tools
=> 'stage_marc_import' },
175 { tools
=> 'upload_local_cover_images' },
179 return 1 if C4
::Auth
::haspermission
( $userid, $_ );
184 =head1 INTERNAL ROUTINES
189 my ( $self, $params ) = @_;
191 $self->{rootdir
} = Koha
::UploadedFile
->permanent_directory;
192 $self->{tmpdir
} = Koha
::UploadedFile
->temporary_directory;
194 $params->{tmp
} = $params->{temp
} if !exists $params->{tmp
};
195 $self->{temporary
} = $params->{tmp
}?
1: 0; #default false
196 if( $params->{tmp
} ) {
197 my $db = C4
::Context
->config('database');
198 $self->{category
} = KOHA_UPLOAD
;
199 $self->{category
} =~ s/koha/$db/;
201 $self->{category
} = $params->{category
} || KOHA_UPLOAD
;
205 $self->{uid
} = C4
::Context
->userenv->{number
} if C4
::Context
->userenv;
206 $self->{public
} = $params->{public
}?
1: undef;
210 my ( $self, $filename ) = @_;
211 if( $self->{files
}->{$filename} ) {
212 return $self->{files
}->{$filename}->{fh
};
217 my ( $self, $filename ) = @_;
219 if( $self->{files
}->{$filename} &&
220 $self->{files
}->{$filename}->{errcode
} ) {
222 } elsif( !$self->{temporary
} && !$self->{rootdir
} ) {
223 $self->{files
}->{$filename}->{errcode
} = 3; #no rootdir
224 } elsif( $self->{temporary
} && !$self->{tmpdir
} ) {
225 $self->{files
}->{$filename}->{errcode
} = 4; #no tempdir
227 my $dir = $self->_dir;
228 my $hashval = $self->{files
}->{$filename}->{hash
};
229 my $fn = $hashval. '_'. $filename;
231 # if the file exists and it is registered, then set error
232 # if it exists, but is not in the database, we will overwrite
234 Koha
::UploadedFiles
->search({
235 hashvalue
=> $hashval,
236 uploadcategorycode
=> $self->{category
},
238 $self->{files
}->{$filename}->{errcode
} = 1; #already exists
242 $fh = IO
::File
->new( "$dir/$fn", "w");
245 $self->{files
}->{$filename}->{fh
}= $fh;
247 $self->{files
}->{$filename}->{errcode
} = 2; #not writable
255 my $dir = $self->{temporary
}?
$self->{tmpdir
}: $self->{rootdir
};
256 $dir.= '/'. $self->{category
};
257 mkdir $dir if !-d
$dir;
262 my ( $self, $filename, $buffer, $bytes_read, $data ) = @_;
263 $filename= Encode
::decode_utf8
( $filename ); # UTF8 chars in filename
264 $self->_compute( $filename, $buffer );
265 my $fh = $self->_fh( $filename ) // $self->_create_file( $filename );
266 print $fh $buffer if $fh;
272 foreach my $f ( keys %{ $self->{files
} } ) {
273 my $fh = $self->_fh($f);
274 $self->_register( $f, $fh?
tell( $fh ): undef )
275 if !$self->{files
}->{$f}->{errcode
};
281 my ( $self, $filename, $size ) = @_;
282 my $rec = Koha
::UploadedFile
->new({
283 hashvalue
=> $self->{files
}->{$filename}->{hash
},
284 filename
=> $filename,
285 dir
=> $self->{category
},
287 owner
=> $self->{uid
},
288 uploadcategorycode
=> $self->{category
},
289 public
=> $self->{public
},
290 permanent
=> $self->{temporary
}?
0: 1,
292 $self->{files
}->{$filename}->{id
} = $rec->id if $rec;
296 # Computes hash value when sub hook feeds the first block
297 # For temporary files, the id is made unique with time
298 my ( $self, $name, $block ) = @_;
299 if( !$self->{files
}->{$name}->{hash
} ) {
300 my $str = $name. ( $self->{uid
} // '0' ).
301 ( $self->{temporary
}? Time
::HiRes
::time(): '' ).
302 $self->{category
}. substr( $block, 0, BYTES_DIGEST
);
303 # since Digest cannot handle wide chars, we need to encode here
304 # there could be a wide char in the filename or the category
305 my $h = Digest
::MD5
::md5_hex
( Encode
::encode_utf8
( $str ) );
306 $self->{files
}->{$name}->{hash
} = $h;
312 Koha Development Team
313 Larger parts from Galen Charlton, Julian Maurice and Marcel de Rooy