title: How can I unescape / urldecode query URL query variables in perl?
body: <p>I have a perl script that processes URLs - it was working fine until the server got upgraded. Now it seems to be double encoding the URL string that it returns.</p>
  <p>Here is an example of the URL the script used to return:</p>
  <pre><code>https://processor.com/?&amp;streetOne=johndoe%40test%2Ecom&amp;key=1234
  </code></pre>
  <p>and here is what it is returning now</p>
  <pre><code>https://processor.com/?&amp;email=johndoe%2540test%252Ecom&amp;key=1234
  </code></pre>
  <p>They key difference is that the <code>@</code> in the URL used to be encoded correctly as <code>%40</code> but now the percent sign is getting encoded (double encoding) so it is <code>%2540</code> which is what happens if you encode the <code>@</code> and then encode it again.</p>
  <p>I'm not sure what would have changed on the server to cause this behavior. I'm a PHP guy and it reminds me of the &quot;magic quotes&quot; where it would auto-escape all of the query variables to received before the script processed it.</p>
  <p>I don't have root access to this server, so if it is not possible to make a change with an <code>.htaccess</code> file or some local configuration option (in the perl script?) then I might need to change what is happening in this function, which gets each of the URL values requested:</p>
  <h3>First the script reads the Query Variables</h3>
  <p>(I think this is where the problem could be - I don't understand the regex - something about looking for KEY between white space, and what the <code>$obj-&gt;{'key'};</code> part is doing)</p>
  <pre><code>sub getValue
  {
    my $obj = shift;
    my $name = shift;
  
    if ($name =~ /^\s*KEY\s*$/i)
      {
        return $obj-&gt;{'key'};
      }
  
    if (! $obj-&gt;isValid($name))
      {
        $obj-&gt;addError(&quot;Cannot obtain information for field '$name' since field is invalid&quot;);
        return 0;
      }
  
    if (! $obj-&gt;isAssigned($name))
      {
        $obj-&gt;addError(&quot;Cannot obtain value from field '$name' since field has not be assigned a value.&quot;);
        return 0;
      }
  
    return $obj-&gt;{'parameters'}-&gt;{ $name }-&gt;{ 'value'};
  }
  </code></pre>
  <h3>Then script builds the query variables back into a URL to return:</h3>
  <p>There is another part of the script that builds the URL that it returns - but I don't think this is the culprit. I tried removing the <code>CGI::escape</code> from the <code>CGI::escape($value))</code> part and it did not help.</p>
  <pre><code>sub create_results
  {
    my $obj = shift;
  
    my ($seconds, $microseconds) = gettimeofday();
    my $timestamp = int($seconds*1000 + $microseconds/1000);
  
    $obj-&gt;assign('timestamp',$timestamp);
  
    # create query string and hash data
  
    my $hash_data = '';
  
    my @query_string = qw();
  
    foreach my $name (@{ $obj-&gt;{'parameter_order'} })
      {
        my $node = $obj-&gt;{'parameters'}-&gt;{ $name };
  
        if (defined($node-&gt;{'value'}))
          {
            my $value = $node-&gt;{'value'};
            $hash_data .= $value;
  
            # $query-&gt;param(-name=&gt;&quot;$name&quot;,   -value=&gt;&quot;$value&quot;);
            push(@query_string,$name . &quot;=&quot; . CGI::escape($value));
          }
      }
  
    # Hash
    $hash_data .= $obj-&gt;get('key');
    my $hash_digest = md5_hex( $hash_data );
  
    push(@query_string, &quot;hash=$hash_digest&quot;);
  
    $obj-&gt;{'query_string'} = join(&quot;&amp;&quot;,@query_string);
    $obj-&gt;{'hash_digest'} = $hash_digest; 
  }
  </code></pre>
  <p>The script is a perl package that I'm using. I didn't write it. I posted the full script here: <a href="http://pastebin.com/eZr8rQ0t" rel="nofollow noreferrer">http://pastebin.com/eZr8rQ0t</a></p>