bug 3272: preserve formatting when editing help
[koha.git] / C4 / UploadedFile.pm
1 package C4::UploadedFile;
2
3 # Copyright (C) 2007 LibLime
4 # Galen Charlton <galen.charlton@liblime.com>
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
11 # version.
12 #
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA  02111-1307 USA
20
21 use strict;
22 use C4::Context;
23 use C4::Auth qw/get_session/;
24 use IO::File;
25
26 use vars qw($VERSION);
27
28 BEGIN {
29         # set the version for version checking
30         $VERSION = 3.00;
31 }
32
33 =head1 NAME
34
35 C4::UploadedFile - manage files uploaded by the user
36 for later processing.
37
38 =head1 SYNOPSIS
39
40 =over 4
41
42 # create and store data
43 my $uploaded_file = C4::UploadedFile->new($sessionID);
44 my $fileID = $uploaded_file->id();
45 $uploaded_file->name('c:\temp\file.mrc');
46 $uploaded_file->max_size(1024);
47 while ($have_more_data) {
48     $uploaded_file->stash($data, $bytes_read);
49 }
50 $uploaded_file->done();
51
52 # check status of current file upload
53 my $progress = C4::UploadedFile->upload_progress($sessionID);
54
55 # get file handle for reading uploaded file
56 my $uploaded_file = C4::UploadedFile->fetch($fileID);
57 my $fh = $uploaded_file->fh();
58
59 =back
60
61 Stores files uploaded by the user from their web browser.  The
62 uploaded files are temporary and at present are not guaranteed
63 to survive beyond the life of the user's session.
64
65 This module allows for tracking the progress of the file
66 currently being uploaded.
67
68 TODO: implement secure persistant storage of uploaded files.
69
70 =cut
71
72 =head1 METHODS
73
74 =cut
75
76 =head2 new
77
78 =over 4
79
80 my $uploaded_file = C4::UploadedFile->new($sessionID);
81
82 =back
83
84 Creates a new object to represent the uploaded file.  Requires
85 the current session ID.
86
87 =cut
88
89 sub new {
90     my $class = shift;
91     my $sessionID = shift;
92
93     my $self = {};
94
95     $self->{'sessionID'} = $sessionID;
96     $self->{'fileID'} = Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().{}.$$));
97     # FIXME - make staging area configurable
98     my $TEMPROOT = "/tmp";
99     my $OUTPUTDIR = "$TEMPROOT/$sessionID";
100     mkdir $OUTPUTDIR;
101     my $tmp_file_name = "$OUTPUTDIR/$self->{'fileID'}";
102     my $fh = new IO::File $tmp_file_name, "w";
103     unless (defined $fh) {
104         return undef;
105     }
106     $fh->binmode(); # Windows compatibility
107     $self->{'fh'} = $fh;
108     $self->{'tmp_file_name'} = $tmp_file_name;
109     $self->{'max_size'} = 0;
110     $self->{'progress'} = 0;
111     $self->{'name'} = '';
112
113     bless $self, $class;
114     $self->_serialize();
115
116     my $session = get_session($sessionID);
117     $session->param('current_upload', $self->{'fileID'});
118     $session->flush();
119
120     return $self;
121
122 }
123
124 sub _serialize {
125     my $self = shift;
126
127     my $prefix = "upload_" . $self->{'fileID'};
128     my $session = get_session($self->{'sessionID'});
129
130     # temporarily take file handle out of structure
131     my $fh = $self->{'fh'};
132     delete $self->{'fh'};
133     $session->param($prefix, $self);
134     $session->flush();
135     $self->{'fh'} =$fh;
136 }
137
138 =head2 id
139
140 =over 4
141
142 my $fileID = $uploaded_file->id();
143
144 =back
145
146 =cut
147
148 sub id {
149     my $self = shift;
150     return $self->{'fileID'};
151 }
152
153 =head2 name
154
155 =over 4
156
157 my $name = $uploaded_file->name();
158 $uploaded_file->name($name);
159
160 =back
161
162 Accessor method for the name by which the file is to be known.
163
164 =cut
165
166 sub name {
167     my $self = shift;
168     if (@_) {
169         $self->{'name'} = shift;
170         $self->_serialize();
171     } else {
172         return $self->{'name'};
173     }
174 }
175
176 =head2 max_size
177
178 =over 4
179
180 my $max_size = $uploaded_file->max_size();
181 $uploaded_file->max_size($max_size);
182
183 =back
184
185 Accessor method for the maximum size of the uploaded file.
186
187 =cut
188
189 sub max_size {
190     my $self = shift;
191     @_ ? $self->{'max_size'} = shift : $self->{'max_size'};
192 }
193
194 =head2 stash
195
196 =over 4
197
198 $uploaded_file->stash($dataref, $bytes_read);
199
200 =back
201
202 Write C<$dataref> to the temporary file.  C<$bytes_read> represents
203 the number of bytes (out of C<$max_size>) transmitted so far.
204
205 =cut
206
207 sub stash {
208     my $self = shift;
209     my $dataref = shift;
210     my $bytes_read = shift;
211
212     my $fh = $self->{'fh'};
213     print $fh $$dataref;
214
215     my $percentage = int(($bytes_read / $self->{'max_size'}) * 100);
216     if ($percentage > $self->{'progress'}) {
217         $self->{'progress'} = $percentage;
218         $self->_serialize();
219     }
220 }
221
222 =head2 done
223
224 =over 4
225
226 $uploaded_file->done();
227
228 =back
229
230 Indicates that all of the bytes have been uploaded.
231
232 =cut
233
234 sub done {
235     my $self = shift;
236     $self->{'progress'} = 'done';
237     $self->{'fh'}->close();
238     $self->_serialize();
239 }
240
241 =head2 upload_progress
242
243 =over 4
244
245 my $upload_progress = C4::UploadFile->upload_progress($sessionID);
246
247 =back
248
249 Returns (as an integer from 0 to 100) the percentage
250 progress of the current file upload.
251
252 =cut
253
254 sub upload_progress {
255     my ($class, $sessionID) = shift;
256
257     my $session = get_session($sessionID);
258
259     my $fileID = $session->param('current_upload');
260
261     my $reported_progress = 0;
262     if (defined $fileID and $fileID ne "") {
263         my $file = C4::UploadedFile->fetch($sessionID, $fileID);
264         my $progress = $file->{'progress'};
265         if (defined $progress) {
266             if ($progress eq "done") {
267                 $reported_progress = 100;
268             } else {
269                 $reported_progress = $progress;
270             }
271         }
272     }
273     return $reported_progress;
274 }
275
276 =head2 fetch
277
278 =over 4
279
280     my $uploaded_file = C4::UploadedFile->fetch($sessionID, $fileID);
281
282 =back
283
284 Retrieves an uploaded file object from the current session.
285
286 =cut
287
288 sub fetch {
289     my $class = shift;
290     my $sessionID = shift;
291     my $fileID = shift;
292
293     my $session = get_session($sessionID);
294     my $prefix = "upload_$fileID";
295     my $self = $session->param($prefix);
296     my $fh = new IO::File $self->{'tmp_file_name'}, "r";
297     $self->{'fh'} = $fh;
298
299     bless $self, $class;
300     return $self;
301 }
302
303 =head2 fh
304
305 =over
306
307 my $fh = $uploaded_file->fh();
308
309 =back
310
311 Returns an IO::File handle to read the uploaded file.
312
313 =cut
314
315 sub fh {
316     my $self = shift;
317     return $self->{'fh'};
318 }
319
320 1;
321 __END__
322
323 =head1 AUTHOR
324
325 Koha Development Team <info@koha.org>
326
327 Galen Charlton <galen.charlton@liblime.com>
328
329 =cut