From 0325a9c7d28bed542257d8ea3047dda810854bcc Mon Sep 17 00:00:00 2001 From: Pierrick Le Gall Date: Thu, 4 May 2023 18:16:43 +0200 Subject: [PATCH] copy from DokuWiki --- pwg.images.add-&-pwg.images.addChunk.md | 228 ++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 pwg.images.add-&-pwg.images.addChunk.md diff --git a/pwg.images.add-&-pwg.images.addChunk.md b/pwg.images.add-&-pwg.images.addChunk.md new file mode 100644 index 0000000..5b54426 --- /dev/null +++ b/pwg.images.add-&-pwg.images.addChunk.md @@ -0,0 +1,228 @@ +Add a photo. + +To avoid limitations on HTTP POST maximum size, the pwg.images.add was +"splitted" into several calls to pwg.images.addChunk and then a single +call to pwg.images.add. + +To avoid high CPU usage on server side, the photo must be resized on +sender side, at least in 2 sizes : the thumbnail and the "web resized" +photo. You can optionally send a "high resolution" photo. + +## pwg.images.addChunk + +pwg.images.addChunk adds a chunk in the "upload/buffer" directory. The +uploaded chunk filename follows the following format: +\-\-\.block + +### Parameters + +- *data* : substring of the base64 encoded binary file +- *original_sum* : md5sum of the original photo, used as a unique + identifier, not to check the chunk upload +- *type* : a value among {thumb, file, high} +- *position* : the numeric position of the chunk among all chunks of + the given file + +Tip: 500KB is a good size for a chunk, don't go too high because you'll +encounter problems related to POST maximum size, don't go too low +because you'll take more time to perform the numerous requests than +really sending the chunked content. + +## pwg.images.add + +Now that thumbnail, web resized and optionnaly the high resolution +chunks have been added, pwg.images.add merge the chunks, copy the +produced files into their final directory, checks the produced files +against their expected md5sums, register the photo in the database. + +### Parameters + +- *original_sum* : md5sum that makes the photo unique +- *categories* : list of category identifiers where you want the photo + to be shown. Optionnaly, you can set a rank inside the each + category. Example : "19,3;16,0;134" will associate the photo to + category 19 at rank 3, to category 16 at rank 0 (first position) and + to category 134 with an automatic rank (last position). +- (optional) *original_filename* +- (optional) *name* +- (optional) *author* +- (optional) *date_creation* : formatted as "2009-03-26" +- (optional) *comment* : the description you can read just below the + photo +- (optional) *tag_ids* : list of tag numeric identifiers, separated + with commas. Example "23,31,18" will associate the photo to tags 23, + 31 and 18. +- (optional) *level* : 0 (----), 1 (Contacts), 2 (Friends), 4 + (Family), 8 (Admins) +- (optional) *check_uniqueness* : check if file already exists (based + on filename or md5sum, see $conf\['uniqueness_mode'\] in + include/config_default.inc.php) +- (optional) *image_id* : give an image_id if you want to update an + existing photo +- (deprecated) *high_sum* +- (deprecated) *thumbnail_sum* + +## Examples + +### Perl + +piwigo-remote.pl is included into Piwigo. You can found this script in +the "tools" directory. + +``` perl +#!/usr/bin/perl + +#### +# Usage examples +# +# time perl piwigo_remote.pl \ +# --file=erwann_rocher-web.jpg \ +# --define categories=9 \ +# --chunk_size=200_000 + +use strict; +use warnings; + +use JSON; +use LWP::UserAgent; +use Getopt::Long; +use Encode qw/is_utf8 decode/; +use POSIX qw(ceil floor); + +my %opt = (); +GetOptions( + \%opt, + qw/action=s file=s categories=s chunk_size=i define=s%/ +); + +our $ua = LWP::UserAgent->new; +$ua->cookie_jar({}); + +my %conf; +$conf{base_url} = 'http://localhost/piwigo/dev/branches/2.7'; +$conf{response_format} = 'json'; +$conf{username} = 'plg'; +$conf{password} = 'plg'; +$conf{chunk_size} = defined $opt{chunk_size} ? $opt{chunk_size} : 500_000; + +my $result = undef; +my $query = undef; + +binmode STDOUT, ":encoding(utf-8)"; + +# TODO : don't connect at each script call, use the session duration instead. +my $form = { + method => 'pwg.session.login', + username => $conf{username}, + password => $conf{password}, +}; + +$result = $ua->post( + $conf{base_url}.'/ws.php?format=json', + $form +); + +use MIME::Base64 qw(encode_base64); +use Digest::MD5::File qw/file_md5_hex/; +use File::Slurp; + +$form = {}; +$form->{method} = 'pwg.images.add'; + +my $original_sum = file_md5_hex($opt{file}); +$form->{original_sum} = $original_sum; + +send_chunks( + filepath => $opt{file}, + type => 'file', + original_sum => $original_sum, +); + +foreach my $key (keys %{ $opt{define} }) { + $form->{$key} = $opt{define}{$key}; +} + +my $response = $ua->post( + $conf{base_url}.'/ws.php?format=json', + $form +); + +print "-" x 50, "\n"; +printf("response code : %u\n", $response->code); +printf("response message : %s\n", $response->message); +print "-" x 50, "\n"; +print "\n"; + +if ($response->is_success) { + print "upload successful\n"; +} +else { + warn 'A problem has occured during upload', "\n"; + warn $response->decoded_content, "\n"; + die $response->status_line; +} + +$query = pwg_ws_get_query( + method => 'pwg.session.logout' +); +$ua->get($query); + +sub pwg_ws_get_query { + my %params = @_; + + my $query = $conf{base_url}.'/ws.php?format='.$conf{response_format}; + + foreach my $key (keys %params) { + $query .= '&'.$key.'='.$params{$key}; + } + + return $query; +} + +sub send_chunks { + my %params = @_; + + use MIME::Base64 qw(encode_base64); + use File::Slurp; + + my $content = read_file($params{filepath}); + my $content_length = length($content); + my $nb_chunks = ceil($content_length / $conf{chunk_size}); + + my $chunk_pos = 0; + my $chunk_id = 1; + while ($chunk_pos < $content_length) { + my $chunk = substr( + $content, + $chunk_pos, + $conf{chunk_size} + ); + $chunk_pos += $conf{chunk_size}; + + my $response = $ua->post( + $conf{base_url}.'/ws.php?format=json', + { + method => 'pwg.images.addChunk', + data => encode_base64($chunk), + original_sum => $params{original_sum}, + position => $chunk_id, + type => $params{type}, + } + ); + + printf( + 'chunk %05u of %05u for %s "%s"'."\n", + $chunk_id, + $nb_chunks, + $params{type}, + $params{filepath} + ); + if ($response->code != 200) { + printf("response code : %u\n", $response->code); + printf("response message : %s\n", $response->message); + } + + $chunk_id++; + } +} +``` \ No newline at end of file