Bug 6874: Attach files to bibliographic records
[koha.git] / C4 / UploadedFiles.pm
blob246b02b8eec3163431fb081159044c71a692823d
1 package C4::UploadedFiles;
3 # Copyright 2011-2012 BibLibre
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 =head1 NAME
22 C4::UploadedFiles - Functions to deal with files uploaded with cataloging plugin upload.pl
24 =head1 SYNOPSIS
26 use C4::UploadedFiles;
28 my $filename = $cgi->param('uploaded_file');
29 my $file = $cgi->upload('uploaded_file');
30 my $dir = $input->param('dir');
32 # upload file
33 my $id = C4::UploadedFiles::UploadFile($filename, $dir, $file->handle);
35 # retrieve file infos
36 my $uploaded_file = C4::UploadedFiles::GetUploadedFile($id);
38 # delete file
39 C4::UploadedFiles::DelUploadedFile($id);
41 =head1 DESCRIPTION
43 This module provides basic functions for adding, retrieving and deleting files related to
44 cataloging plugin upload.pl.
46 It uses uploaded_files table.
48 It is not related to C4::UploadedFile
50 =head1 FUNCTIONS
52 =cut
54 use Modern::Perl;
55 use Digest::SHA;
56 use Fcntl;
57 use Encode;
59 use C4::Context;
61 sub _get_file_path {
62 my ($id, $dirname, $filename) = @_;
64 my $uploadPath = C4::Context->preference('uploadPath');
65 my $filepath = "$uploadPath/$dirname/${id}_$filename";
66 $filepath =~ s|/+|/|g;
68 return $filepath;
71 =head2 GetUploadedFile
73 my $file = C4::UploadedFiles::GetUploadedFile($id);
75 Returns a hashref containing infos on uploaded files.
76 Hash keys are:
78 =over 2
80 =item * id: id of the file (same as given in argument)
82 =item * filename: name of the file
84 =item * dir: directory where file is stored (relative to syspref 'uploadPath')
86 =back
88 It returns undef if file is not found
90 =cut
92 sub GetUploadedFile {
93 my ($id) = @_;
95 return unless $id;
97 my $dbh = C4::Context->dbh;
98 my $query = qq{
99 SELECT id, filename, dir
100 FROM uploaded_files
101 WHERE id = ?
103 my $sth = $dbh->prepare($query);
104 $sth->execute($id);
105 my $file = $sth->fetchrow_hashref;
106 if ($file) {
107 $file->{filepath} = _get_file_path($file->{id}, $file->{dir},
108 $file->{filename});
111 return $file;
114 =head2 UploadFile
116 my $id = C4::UploadedFiles::UploadFile($filename, $dir, $io_handle);
118 Upload a new file and returns its id (its SHA-1 sum, actually).
120 Parameters:
122 =over 2
124 =item * $filename: name of the file
126 =item * $dir: directory where to store the file (path relative to syspref 'uploadPath'
128 =item * $io_handle: valid IO::Handle object, can be retrieved with
129 $cgi->upload('uploaded_file')->handle;
131 =back
133 =cut
135 sub UploadFile {
136 my ($filename, $dir, $handle) = @_;
138 $filename = decode_utf8($filename);
139 if($filename =~ m#(^|/)\.\.(/|$)# or $dir =~ m#(^|/)\.\.(/|$)#) {
140 warn "Filename or dirname contains '..'. Aborting upload";
141 return;
144 my $buffer;
145 my $data = '';
146 while($handle->read($buffer, 1024)) {
147 $data .= $buffer;
149 $handle->close;
151 my $sha = new Digest::SHA;
152 $sha->add($data);
153 my $id = $sha->hexdigest;
155 # Test if this id already exist
156 my $file = GetUploadedFile($id);
157 if ($file) {
158 return $file->{id};
161 my $file_path = _get_file_path($id, $dir, $filename);
163 my $out_fh;
164 # Create the file only if it doesn't exist
165 unless( sysopen($out_fh, $file_path, O_WRONLY|O_CREAT|O_EXCL) ) {
166 warn "Failed to open file '$file_path': $!";
167 return;
170 print $out_fh $data;
171 close $out_fh;
173 my $dbh = C4::Context->dbh;
174 my $query = qq{
175 INSERT INTO uploaded_files (id, filename, dir)
176 VALUES (?,?, ?);
178 my $sth = $dbh->prepare($query);
179 if($sth->execute($id, $filename, $dir)) {
180 return $id;
183 return undef;
186 =head2 DelUploadedFile
188 C4::UploadedFiles::DelUploadedFile($id);
190 Remove a previously uploaded file, given its id.
192 Returns a false value if an error occurs.
194 =cut
196 sub DelUploadedFile {
197 my ($id) = @_;
199 my $file = GetUploadedFile($id);
200 if($file) {
201 my $file_path = $file->{filepath};
202 my $file_deleted = 0;
203 unless( -f $file_path ) {
204 warn "Id $file->{id} is in database but not in filesystem, removing id from database";
205 $file_deleted = 1;
206 } else {
207 if(unlink $file_path) {
208 $file_deleted = 1;
212 unless($file_deleted) {
213 warn "File $file_path cannot be deleted: $!";
216 my $dbh = C4::Context->dbh;
217 my $query = qq{
218 DELETE FROM uploaded_files
219 WHERE id = ?
221 my $sth = $dbh->prepare($query);
222 return $sth->execute($id);