Bug 9504: URL escape in OPAC more searches
authorFridolyn SOMERS <fridolyn.somers@biblibre.com>
Tue, 29 Jan 2013 17:03:02 +0000 (18:03 +0100)
committerJared Camins-Esakov <jcamins@cpbibliography.com>
Wed, 20 Mar 2013 12:36:44 +0000 (08:36 -0400)
OPACSearchForTitleIn is a syspref used to add links as "more searches" in OPAC record detail page.
The links can contain vars depending on record values like title, ISBN, ...
Thoses values must be URL-escaped because they can contain special characters that will brake URL and/or HTML.

This patch add a method C4::Output::parametrized_url() that replaces vars in URL usign escape and UTF-8 encoding.

Test plan :
- Define in OPACSearchForTitleIn a link with all possible vars : TITLE, AUTHOR, ISBN, ISSN, CONTROLNUMBER, BIBLIONUMBER
- Edit a record to add special characters in title : ", &, ? ...
- Go to OPAC detail pages of this record
=> Check that URL is well encoded
=> Click on link to check the term is well encoded (diacritical characters, ...)

Signed-off-by: Liz Rea <liz@catalyst.net.nz>
Nice test plan, thanks!

Verified bug and fix - both look good.
Signed-off-by: Mason James <mtj@kohaaloha.com>
Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>
C4/Output.pm
opac/opac-ISBDdetail.pl
opac/opac-MARCdetail.pl
opac/opac-detail.pl

index e1be3e7..6e2c89a 100644 (file)
@@ -28,6 +28,8 @@ package C4::Output;
 use strict;
 #use warnings; FIXME - Bug 2505
 
+use URI::Escape;
+
 use C4::Context;
 use C4::Dates qw(format_date);
 use C4::Budgets qw(GetCurrency);
@@ -42,13 +44,13 @@ BEGIN {
 
  @ISA    = qw(Exporter);
     @EXPORT_OK = qw(&is_ajax ajax_fail); # More stuff should go here instead
-    %EXPORT_TAGS = ( all =>[qw(setlanguagecookie pagination_bar
+    %EXPORT_TAGS = ( all =>[qw(setlanguagecookie pagination_bar parametrized_url
                                 &output_with_http_headers &output_ajax_with_http_headers &output_html_with_http_headers)],
                     ajax =>[qw(&output_with_http_headers &output_ajax_with_http_headers is_ajax)],
                     html =>[qw(&output_with_http_headers &output_html_with_http_headers)]
                 );
     push @EXPORT, qw(
-        setlanguagecookie getlanguagecookie pagination_bar
+        setlanguagecookie getlanguagecookie pagination_bar parametrized_url
     );
     push @EXPORT, qw(
         &output_html_with_http_headers &output_ajax_with_http_headers &output_with_http_headers FormatData FormatNumber
@@ -327,6 +329,18 @@ sub is_ajax {
     return ( $x_req and $x_req =~ /XMLHttpRequest/i ) ? 1 : 0;
 }
 
+sub parametrized_url {
+    my $url = shift || ''; # ie page.pl?ln={LANG}
+    my $vars = shift || {}; # ie { LANG => en }
+    my $ret = $url;
+    while ( my ($key,$val) = each %$vars) {
+        my $val_url = URI::Escape::uri_escape_utf8($val);
+        $ret =~ s/\{$key\}/$val_url/g;
+    }
+    $ret =~ s/\{[^\{]*\}//g; # remove not defined vars
+    return $ret;
+}
+
 END { }    # module clean-up code here (global destructor)
 
 1;
index be62879..94055a9 100755 (executable)
@@ -181,15 +181,20 @@ my $marcissns = GetMarcISSN ( $record, $marcflavour );
 my $issn = $marcissns->[0] || '';
 
 if (my $search_for_title = C4::Context->preference('OPACSearchForTitleIn')){
-    $dat->{author} ? $search_for_title =~ s/{AUTHOR}/$dat->{author}/g : $search_for_title =~ s/{AUTHOR}//g;
     $dat->{title} =~ s/\/+$//; # remove trailing slash
     $dat->{title} =~ s/\s+$//; # remove trailing space
-    $dat->{title} ? $search_for_title =~ s/{TITLE}/$dat->{title}/g : $search_for_title =~ s/{TITLE}//g;
-    $isbn ? $search_for_title =~ s/{ISBN}/$isbn/g : $search_for_title =~ s/{ISBN}//g;
-    $issn ? $search_for_title =~ s/{ISSN}/$issn/g : $search_for_title =~ s/{ISSN}//g;
-    $marccontrolnumber ? $search_for_title =~ s/{CONTROLNUMBER}/$marccontrolnumber/g : $search_for_title =~ s/{CONTROLNUMBER}//g;
-    $search_for_title =~ s/{BIBLIONUMBER}/$biblionumber/g;
- $template->param('OPACSearchForTitleIn' => $search_for_title);
+    $search_for_title = parametrized_url(
+        $search_for_title,
+        {
+            TITLE         => $dat->{title},
+            AUTHOR        => $dat->{author},
+            ISBN          => $isbn,
+            ISSN          => $issn,
+            CONTROLNUMBER => $marccontrolnumber,
+            BIBLIONUMBER  => $biblionumber,
+        }
+    );
+    $template->param('OPACSearchForTitleIn' => $search_for_title);
 }
 
 output_html_with_http_headers $query, $cookie, $template->output;
index ac13a9d..2a69244 100755 (executable)
@@ -296,15 +296,20 @@ my $marcissns = GetMarcISSN( $record, $marcflavour );
 my $issn = $marcissns->[0] || '';
 
 if (my $search_for_title = C4::Context->preference('OPACSearchForTitleIn')){
-    $dat->{author} ? $search_for_title =~ s/{AUTHOR}/$dat->{author}/g : $search_for_title =~ s/{AUTHOR}//g;
     $dat->{title} =~ s/\/+$//; # remove trailing slash
     $dat->{title} =~ s/\s+$//; # remove trailing space
-    $dat->{title} ? $search_for_title =~ s/{TITLE}/$dat->{title}/g : $search_for_title =~ s/{TITLE}//g;
-    $isbn ? $search_for_title =~ s/{ISBN}/$isbn/g : $search_for_title =~ s/{ISBN}//g;
-    $issn ? $search_for_title =~ s/{ISSN}/$issn/g : $search_for_title =~ s/{ISSN}//g;
-    $marccontrolnumber ? $search_for_title =~ s/{CONTROLNUMBER}/$marccontrolnumber/g : $search_for_title =~ s/{CONTROLNUMBER}//g;
-    $search_for_title =~ s/{BIBLIONUMBER}/$biblionumber/g;
- $template->param('OPACSearchForTitleIn' => $search_for_title);
+    $search_for_title = parametrized_url(
+        $search_for_title,
+        {
+            TITLE         => $dat->{title},
+            AUTHOR        => $dat->{author},
+            ISBN          => $isbn,
+            ISSN          => $issn,
+            CONTROLNUMBER => $marccontrolnumber,
+            BIBLIONUMBER  => $biblionumber,
+        }
+    );
+    $template->param('OPACSearchForTitleIn' => $search_for_title);
 }
 
 $template->param(
index 068122e..883ea7c 100755 (executable)
@@ -966,14 +966,19 @@ my $marcissns = GetMarcISSN ( $record, $marcflavour );
 my $issn = $marcissns->[0] || '';
 
 if (my $search_for_title = C4::Context->preference('OPACSearchForTitleIn')){
-    $dat->{author} ? $search_for_title =~ s/{AUTHOR}/$dat->{author}/g : $search_for_title =~ s/{AUTHOR}//g;
     $dat->{title} =~ s/\/+$//; # remove trailing slash
     $dat->{title} =~ s/\s+$//; # remove trailing space
-    $dat->{title} ? $search_for_title =~ s/{TITLE}/$dat->{title}/g : $search_for_title =~ s/{TITLE}//g;
-    $isbn ? $search_for_title =~ s/{ISBN}/$isbn/g : $search_for_title =~ s/{ISBN}//g;
-    $issn ? $search_for_title =~ s/{ISSN}/$issn/g : $search_for_title =~ s/{ISSN}//g;
-    $marccontrolnumber ? $search_for_title =~ s/{CONTROLNUMBER}/$marccontrolnumber/g : $search_for_title =~ s/{CONTROLNUMBER}//g;
-    $search_for_title =~ s/{BIBLIONUMBER}/$biblionumber/g;
+    $search_for_title = parametrized_url(
+        $search_for_title,
+        {
+            TITLE         => $dat->{title},
+            AUTHOR        => $dat->{author},
+            ISBN          => $isbn,
+            ISSN          => $issn,
+            CONTROLNUMBER => $marccontrolnumber,
+            BIBLIONUMBER  => $biblionumber,
+        }
+    );
     $template->param('OPACSearchForTitleIn' => $search_for_title);
 }