/usr/share/perl5/CGI/Uploader/Cookbook.pod is in libcgi-uploader-perl 2.18-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | =head1 NAME
CGI::Uploader::Cookbook - Examples of CGI::Uploader usage
=head1 Description
C<CGI::Uploader::Cookbook> is a tutorial that accompanies the B<CGI::Uploader>
distribution. It shows example syntax for common uses.
C<CGI::Uploader> module is designed to help with the task of managing files
uploaded through a CGI application. The files are stored on the file system,
and the file attributes stored in a SQL database.
=head1 Introduction to CGI::Uploader
=head2 A Little History
The release of this module represents a culmination of seven years of experience
managing file uploads as a professional website developer for
Summersault, LLC (L<http://www.summersault.com/>). Over that time I noticed patterns
that were re-usable from project to project. I went through several versions
and rewrites of modules that attempted to be 'generic' and not need
modification when the next project came along. With CGI::Uploader, I believe I
finally have a solution that I will continue to be happy with and I think others
will be find generally useful. Enjoy!
=head2 Freedom of Choice
I endeavored to make CGI::Uploader to work within a variety of system designs.
It offers you freedom choice in the following areas:
=over
=item * Database Choice
MySQL and Postgres are supported directly. The SQL used is very simple-- support
for additional databases should be trivial.
=item * Choice of Query Provider
The query object used may provided by C<CGI.pm>, C<CGI::Simple> or
C<Apache::Request>. Another source could be used by overriding the C<upload>
method.
=item * File Storage Schemes for Large and Small Projects
For small projects, all uploads can be stored in a single directory. For large
projects, we provide the C<md5> file scheme, which should scale well to
millions of images, without burdening any single directory with storing too
many of them.
=item * Choice of Data Display
Because the meta data is stored in a straightforward SQL database table, you
can retrieve your data and display in any number of custom ways. Several functions
are also built in to help with common display tasks. The C<build_loc()> method is
used to construct the file system or URL path of an image, given it's ID and extension.
C<fk_meta()> provides an easy way to get the meta data of an upload by relating it to a foreign
key in another table.
Finally, C<transform_meta()> is a basic function which transforms a hashref of data from the database
into a format more useful for display, producing a hash that looks like this:
{
my_custom_prefix_id => 523,
my_custom_prefix_url => 'http://localhost/images/uploads/523.pdf',
my_custom_prefix_width => 23,
my_custom_prefix_height => 46,
}
=item * Image Processor
While C<CGI::Uploader> works with all types of file uploads, it contains a number
of features to help with common tasks associated with image uploads.
C<Image::Magick> is the preferred image processing module for to use when
creating the thumbnails. Support for C<GD> is in progress. C<GD> supports many
fewer formats, but also has much fewer dependencies to get installed than
C<Image::Magick> does. Another providers could be used by extending or
overriding the C<gen_thumb()> method.
=back
=head2 Just Three Essential Methods to Learn
A goal of <CGI::Uploader> is to provide a high-level interface to make managing
file uploads easy. Only three methods are needed to manage all the functions needed
to store, update, delete and view the uploads attached to some database entity. Those
methods are C<store_uploads()>, C<delete_checked_uploads()> and C<fk_meta>.
=head2 More methods when you need them
When your needs before more complex, you can call the lower-level functions in C<CGI::Uploader>
to meet your needs. Most functions use file names to access file uploads, so it's easy to use the
module to manipulate files from other sources than the browser upload field.
For example, the C<gen_thumb()> method is general purpose thumbnail creating routine.
=head1 Browse, Read, Edit, Add, Delete (BREAD) Example Application
The following sections will provide a walk through of a simple application
using CGI::Uploader. This is intended to provide the picture of how this module
can be used. Some details have been glossed over. For a complete, working
example application, please see the C<examples> directory of the distribution.
Before C<CGI::Uploader> can be useful, some setup needs to be done.
You need some database tables to store the information in.
=head2 Example Database
For these examples, we'll set up some tables to manage photos of friends.
Here is the SQL to create such tables with Postgres:
-- Note the Postgres specific syntax here
CREATE SEQUENCE upload_id_seq;
CREATE TABLE uploads (
upload_id int primary key not null
default nextval('upload_id_seq'),
mime_type character varying(64),
extension character varying(8), -- file extension
width integer,
height integer,
gen_from_id integer
);
CREATE SEQUENCE friend_id_seq;
CREATE TABLE address_book (
friend_id int primary key NOT NULL DEFAULT nextval('friend_id_seq'),
full_name varchar(64),
-- these two reference uploads('upload_id'),
photo_id int,
photo_thumbnail_id int
);
(I<MySQL> is also supported. Check in the distribution for sample SQL 'Create'
scripts for both I<MySQL> and I<Postgresql> databases).
=head2 Object Creation
You can create one C<CGI::Uploader> object and use it for adding, updating,
viewing and deleting uploads. So don't despair that it has a few required
parameters-- you only need to type them once! :)
use CGI::Uploader::Transform::ImageMagick;
my $u = CGI::Uploader->new(
spec => {
photo => {
gen_files => {
photo_thumbnail => gen_thumb({ w => 100, h => 100}),
}
}
}
updir_url => 'http://localhost/uploads',
updir_path => '/home/friends/www/uploads',
dbh => $dbh,
);
=head1 Adding a Database Record and Related Uploads
Before we can do anything else with the uploads, we need to get some added into
the system.
C<CGI::Uploader> is designed to make this happening easily as part
of the normal process of adding a normal database record. In this
case, we'll be adding a friend.
=head2 Example 'Add Form'
Here's the form used to add a friend. It includes fields
for the friend's name, and a photo of them.
<form action="your-script.cgi" enctype="multipart/form-data" METHOD="POST">
Friend Name: <input type="text" name="full_name"> <br />
Image: <input type="file" name="photo">
<input type="submit">
</form>
Notice that the 'enctype' is important for file uploads to work.
Notice we have a text field for a 'full_name' and a file upload field named
'photo'.
=head2 Processing the Add Form
AS a first step for processing the 'add form', I recommend validating
the form with L<Data::FormValidator|Data::FormValidator>. It includes several
routines just to validate file uploads. However, it's not necessary
to validate the form.
# CGI::Simple provides a CGI.pm-like interface with much better performance
use CGI::Simple;
my $q = CGI::Simple->new();
my $form = $q->Vars;
my $friend = $u->store_uploads($form);
# Now the $friend hash been transformed so it can easily inserted
# It now looks like this:
# {
# full_name => 'M. Lewis',
# photo_id => 3,
# photo_thumbnail_id => 4,
# }
# I like to use SQL::Interp for easy inserts.
# See DBIx::Simple for an even more friendly wrapper.
use SQL::Interp 'sql_interp';
$dbh->do(sql_interp "INSERT INTO address_book",$friend);
=head2 Database Result of Adding
Here's what ended up in the database:
address_book table:
friend_id | full_name | photo_id | photo_thumbnail_id
-----------------------------------------------------
2 | M. Lewis | 3 | 4
uploads table:
upload_id | mime_type | extension | width | height | gen_from_id
--------------------------------------------------------------------
3 | image/png | .png | 200 | 400 |
4 | image/png | .png | 50 | 100 | 3
The files are stored on the file system. '4.png' was generated on
the server a thumbnail of 3.png.
/home/friends/www/uploads/3.png
/home/friends/www/uploads/4.png
=head1 Displaying & Linking to Uploads
You don't strictly need this module to display the uploaded image. You could construct
your own database queries and URLs instead. However, the C<fk_meta> method is provided
to simplify things for you.
Continuing with the example above, we would use this code to generate the details we need to
display and link to the photo and thumbnail:
my $href = $u->fk_meta(
table => 'address_book',
where => { friend_id => 2 },
prefixes => [qw/photo photo_thumbnail/],
);
That will fetch the details of the photo and thumbnail associated with the friend who is an
ID of "2".
The resulting hashref will look something like this:
{
photo_id => 3,
photo_url =>'http://localhost/uploads/3.png?23',
photo_width => 200,
photo_height => 400',
photo_thumbnail_id => 4,
photo_thumbnail_url =>'http://localhost/uploads/4.png?23',
photo_thumbnail_width => 50,
photo_thumbnail_height => 200',
}
This hashref can often be passed directly to a templating system such as
L<HTML::Template|HTML::Template> for display.
You may be wondering about the query strings on the URLS. These are random
numbers to defeat browser image caching, which is very useful on "edit"
forms. This behavior may change or become optional in a future release.
=head1 Displaying an Update Form
So now we've added 'M. Lewis' to our friend database and displayed his photo
on the web. M. Lewis turned out not to be happy about this. He reports
that the photo used was not his 'good side' and has sent a 'better' photo
to use.
So now we need to have a form to update the photo from.
The form to update the upload will be a lot like the 'add form'. Additionally,
it's nice to display a link to current upload on the form. This can be done
using C<fk_meta>, as demonstrated above.
Our Update Form might look like this if we are using L<HTML::Template|HTML::Template>
for display:
<form action="your-script.cgi" enctype="multipart/form-data" METHOD="POST">
<P>Friend Name: <input type="text" name="full_name"> </p>
<P>
<a href="<tmpl_var photo_url>">Current Image</a> <br/>
<input type="checkbox" value="1" name="photo_delete"> Delete Image?
</P>
<input type="hidden" name="photo_id" value="<tmpl_var photo_id>">
<p>Image: <input type="file" name="photo"></p>
<input type="submit">
</form>
=head2 Processing an Update Form
Processing an update form is the most complicated part of application. From
this form it's possible to add, update and delete uploads
To process the update form, we'll first delete any uploads that the user has
requested to remove. Next, add and update any other uploads as need.
my $friend = $q->Vars;
my @fk_names = $u->delete_checked_uploads;
map { $friend->{$_} = undef } @fk_names;
delete $friend->{photo_delete};
$friend = $u->store_uploads($friend);
Although the call to C<store_uploads()> looks the same as it did for
adding a record, it works a little different now. Notice we passed
a photo_id through the form above. Because this is present, that record
will be updated instead of creating a new one.
=head1 Recipe Idea: Put an existing directory of photos on line
You have an existing directory full of JIGS that you want to put on-line
as a photo gallery, with medium and small versions created of all the images.
C<CGI::Uploader> is versatile enough to help in this situation as well.
Your spec might look like this:
large_jpeg => [
{ name => 'medium', w => 500, },
{ name => 'small', w => 250,
],
From there, read in all the file names and store all the files, with the
smaller versions being created automatically for you along the way.
for my $jpeg (<*.jpg>) {
my %entity_upload_extra = $self->store_upload(
file_field => 'large_jpeg',
src_file => $jpeg,
uploaded_mt => 'image/jpeg',
file_name => $jpeg,
);
}
Now you may want to display a page containing all of the smallest thumbnails.
If these IDs had been stored in another table, we could use fk_meta() to get
all of the small thumbnails.
In this case, it is still possible to get a reasonable result by selecting images
based on their size.
[TODO: example code for this needs to be written. ]
=head1 Recipe Idea: Handling anonymous image uploads
It is also possible with CGI::Uploader to have many "anynonmous" uploads
associated with another entity in the database.
[ TODO: And the documentation for how to that still needs to be written. :) ]
=head1 See Also
L<CGI::Uploader|CGI::Uploader>
=head1 Author
Mark Stosberg <mark@summersault.com>
=cut
|