Understanding URL Encoding: Best Practices and Common Pitfalls

"URL encoding" sounds like one technique. In practice, it’s a family of rules for different contexts—URLs, HTML text, and HTML attributes—each with failure modes that look like broken links, corrupted characters, and occasional security bugs.

When you search for this topic, you usually want answers to questions like: What exactly is URL encoding? When do I encode vs decode (and how do I avoid double-encoding)? Why do some characters break in PHP? and what are the best practices for safe output?

Encoding errors are common because systems disagree about responsibilities: browsers percent-encode URLs, servers decode them, and templates escape them again. The safest mental model is to encode for the destination context (URL parameter, HTML text, HTML attribute), not for your “input” string. For a foundation, see the W3C guidance on URL/percent-encoding and the PHP manual for rawurlencode() and urldecode().

By the end of this guide, you’ll be able to implement URL encoding correctly in PHP, spot the most common pitfalls, and build small test cases that catch problems before they ship.

Table of Contents

\"Screenshot
Encoded vs unencoded query strings can look similar in PHP, but behave differently once they hit the browser and the server.

What is URL Encoding?

URL encoding (often called percent-encoding) is the process of converting characters that are not safe in a URL into a standardized format using %HH where HH is the hexadecimal value of the byte.

Two terms you’ll see together:

  • rawurlencode(): percent-encodes everything except unreserved characters. It’s usually what you want for URL parameter values.
  • urlencode(): historically similar, but it encodes spaces as + (which is appropriate for application/x-www-form-urlencoded contexts).

Under the hood, URL encoding is byte-level. That means your result depends on the string’s character encoding (typically UTF‑8) and on whether you’re encoding at the right layer (value vs whole URL).

Why URL Encoding is Important

Correct encoding prevents three classes of problems:

  1. Broken navigation: links don’t land on the expected resource because special characters got interpreted as URL syntax.
  2. Data corruption: names, emails, and non-ASCII text arrive mangled because decoding happened twice (or not enough).
  3. Safety issues: if you print unsafely decoded strings into HTML, you can create output-context vulnerabilities. URL encoding itself isn’t a security boundary—HTML escaping is.

For output safety, pair URL logic with proper HTML escaping. In PHP templates, use htmlspecialchars() for HTML contexts; in some workflows you may also prefer WordPress’ escaping helpers if you’re inside WP templates. (See the PHP htmlspecialchars() documentation.)

Common Mistakes in URL Encoding

1) Encoding the whole URL instead of the parameter value

If you encode https://example.com/search?q=hello world as one string, you’ll double-escape separators like :// and =. The browser can’t parse it as a proper URL.

2) Double-encoding (or storing already-encoded strings)

The classic symptom: a query value turns into %2520 (where %25 is the encoding of a percent sign). This happens when you encode something that was already percent-encoded.

3) Decoding too early (before you know the destination context)

Decoding a parameter immediately after receiving it is often correct, but don’t decode blindly and then re-encode for a different purpose. Make sure each step matches its “destination.”

4) Confusing + with spaces in query strings

+ is special for application/x-www-form-urlencoded. In a URL query string, spaces may arrive percent-encoded as %20 depending on how the link was generated.

5) Encoding for URL but escaping for HTML (mixing contexts)

Encoding for URL helps keep URLs valid. It does not replace HTML escaping when you render the value into an HTML page.

Best Practices for URL Encoding in PHP

  1. Encode at the boundary: encode right before you build the URL/query string.
  2. Use the right encoder for the right format:
    • Prefer rawurlencode() for URL parameter values.
    • Use urlencode() when you’re building x-www-form-urlencoded bodies.
  3. Avoid double-encoding:
    • Don’t percent-encode values before storing them unless you have a documented invariant.
    • Store the decoded canonical form, and encode only when you render a URL.
  4. Decode only when you need the data (and then treat it as plain text):
    • Use urldecode() or let your framework handle decoding.
    • Then escape for HTML output with htmlspecialchars().
  5. Build and test with edge characters: spaces, &, =, %, slashes, plus non-ASCII characters like é and emoji.

A simple decision rule

If your string goes into a URL query value, encode it as a value. If it goes into HTML, escape it for HTML. Don’t rely on “it looks encoded” as a proxy for correctness.

For the URL encoding basics, also review the W3C overview and percent-encoding rules: W3C: IRIs, IRIs and URIs.

Practical Examples of URL Encoding

Example 1: Building a search URL safely

Input from a user might include spaces, &, or %. You want the server to receive exactly that text.

$term = $userInput; // plain text (UTF-8)
$query = http_build_query(['q' => $term]);
$url = '/search?' . $query;

Why this works: http_build_query() handles percent-encoding for query parameters. You avoid manual mistakes like encoding the whole URL or double-encoding values.

Example 2: Encoding a single parameter value

$value = 'a & b = c';
$encoded = rawurlencode($value); // a%20%26%20b%20%3D%20c
$href = '/page?ref=' . $encoded;

If you later display $value in an HTML page, use htmlspecialchars($value, ENT_QUOTES, 'UTF-8') for HTML context.

Example 3: Spotting double-encoding via percent patterns

If you see values like %2520 instead of %20, you likely encoded something twice (because %25 is literally “%” encoded).

  • Correct form for a space: %20
  • Double-encoded space: %2520

Example 4: Decoding for use, then escaping for output

// From a request (already decoded by PHP superglobals in most cases)
$fromUrl = $_GET['q'] ?? '';

// Use it as text, not as URL or HTML
// Render in HTML safely
echo htmlspecialchars($fromUrl, ENT_QUOTES, 'UTF-8');

This keeps your encoding responsibilities consistent: decode for data, escape for HTML.

Conclusion

URL encoding is not one thing. It’s a context-specific operation, and the reliable approach is simple: encode right before you build a URL, decode when you need plain text, and escape for HTML output separately.

If you want one practical next step, build a tiny “encoding test table” in your dev environment: run the same input values through your URL builder, load them in a browser, and confirm the server receives the same decoded text you started with.


Internal links: Explore more web workflow guidance on our main page, browse related articles in the blog index, and get implementation help via Support.

Scroll to Top