Question
When building a URL in PHP from a variable, both urlencode() and rawurlencode() can encode a string. What is the exact difference between these functions, and which one should be preferred in different parts of a URL?
Short Answer
You will learn why URL encoding is necessary, how PHP's urlencode() and rawurlencode() handle spaces and special characters differently, and how to choose the correct function for URL path segments and query-string values.
Concept
URLs have special characters with structural meanings. For example, / separates path segments, ? begins a query string, & separates query parameters, and # begins a fragment. If one of these characters appears inside user-provided data, it must be encoded so it is treated as data rather than URL structure.
PHP offers two closely related encoding functions:
urlencode()uses theapplication/x-www-form-urlencodedconvention used by HTML forms and traditional query strings. A space becomes+.rawurlencode()follows RFC 3986 percent encoding. A space becomes%20.
$text = 'red shoes & bags';
echo urlencode($text); // red+shoes+%26+bags
echo rawurlencode($text); // red%20shoes%20%26%20bags
Both functions encode & as %26, preventing it from accidentally creating another query parameter. Their important visible difference is how they represent spaces.
A practical rule is:
- Use
rawurlencode()for an individual URL path segment. - Use
http_build_query()for query strings. When choosing manually, useurlencode()for form-style query values orrawurlencode()for RFC 3986-style query values, depending on the convention your API requires.
Do not encode an entire URL at once. Encode only the data inserted into a specific URL component.
Mental Model
Think of a URL as a shipping label with separate fields:
- The path is the street address.
- The query string is a set of labelled notes.
- Your variable is the text written inside one field.
If the text itself contains a separator such as /, &, or ?, it can be mistaken for part of the label's format. Encoding replaces those reserved characters with safe representations.
rawurlencode() uses %20 to write a space. urlencode() follows the older form convention of writing a space as +. Both protect the contents; the correct choice depends on which URL field and protocol convention you are working with.
Syntax and Examples
Encode one value before inserting it into a URL.
$value = 'C++ & PHP';
$formStyle = urlencode($value);
$rfc3986Style = rawurlencode($value);
echo $formStyle; // C%2B%2B+%26+PHP
echo $rfc3986Style; // C%2B%2B%20%26%20PHP
For a path segment, use rawurlencode():
$username = 'Ada Lovelace/Team A';
$url = 'https://example.com/users/' . rawurlencode($username);
echo $url;
// https://example.com/users/Ada%20Lovelace%2FTeam%20A
Encoding / as %2F is important here. Without encoding, it would create an unintended extra path segment.
For a query string, let http_build_query() build it instead of concatenating values manually:
$params = [
'q' => 'C++ & PHP',
'page' => 1,
];
$url = 'https://example.com/search?' . http_build_query($params);
echo $url;
// https://example.com/search?q=C%2B%2B+%26+PHP&page=1
To generate an RFC 3986 query string with %20 instead of +, pass PHP_QUERY_RFC3986:
$query = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
echo $query;
// q=C%2B%2B%20%26%20PHP&page=1
Step by Step Execution
Consider this path-building example:
$category = 'science fiction/fantasy';
$url = 'https://example.com/books/' . rawurlencode($category);
echo $url;
Step by step:
$categorycontains the textscience fiction/fantasy.- The space must not remain a literal space in a URL, so
rawurlencode()changes it to%20. - The slash is data in the category name, not a path separator, so it becomes
%2F. rawurlencode($category)producesscience%20fiction%2Ffantasy.- PHP concatenates that encoded value after
/books/. - The final URL is:
https://example.com/books/science%20fiction%2Ffantasy
Now compare a query value:
$term = 'science fiction';
$url = 'https://example.com/search?q=' . urlencode($term);
echo $url;
// https://example.com/search?q=science+fiction
Here the space becomes +, which is the standard form-style query-string representation used by urlencode().
Real World Use Cases
- Profile URLs: Encode a username before placing it in
/users/{username}. Names may contain spaces,@, or/. - Search pages: Build URLs such as
/search?q=wireless+headphonesfrom a search input. - API requests: Encode query parameters such as filters, redirect destinations, and pagination tokens.
- File download links: Encode a file name when it is used as one path segment, especially when it contains spaces or
#. - OAuth redirect parameters: A callback URL placed inside another URL's query parameter must be encoded as the parameter value.
- Server-side integrations: Generate safe links for emails, reports, and redirects from database values.
Real Codebase Usage
In production PHP applications, developers usually avoid manually joining many query parameters. http_build_query() handles separators and encoding consistently.
$filters = [
'status' => 'in progress',
'owner' => 'sam@example.com',
];
$redirectUrl = '/tasks?' . http_build_query($filters, '', '&', PHP_QUERY_RFC3986);
For routes, encode each dynamic segment individually:
function userProfileUrl(string $username): string
{
return '/users/' . rawurlencode($username);
}
This is safer than encoding the entire route because the route's real slashes must remain slashes.
A common validation pattern is to reject invalid application data first, then encode it for URL transport:
function productUrl(string $slug): string
{
if ($slug === '') {
throw new InvalidArgumentException('Product slug is required.');
}
return '/products/' . rawurlencode($slug);
}
Encoding is not validation and is not HTML escaping. If the URL will later be printed in HTML, use htmlspecialchars() at the HTML output boundary as well.
Common Mistakes
Encoding the whole URL
Broken example:
$url = 'https://example.com/search?q=red shoes';
echo rawurlencode($url);
This encodes :, /, ?, and =, destroying the URL structure.
https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dred%20shoes
Instead, keep structural characters and encode only the value:
$url = 'https://example.com/search?q=' . rawurlencode('red shoes');
Forgetting to encode query values
Broken example:
$term = 'books & music';
$url = '/search?q=' . $term;
The & can be interpreted as a new query parameter. Use http_build_query() or encode the value.
$url = '/search?' . http_build_query(['q' => $term]);
Using urlencode() for a path segment
$name = 'Team Alpha';
echo '/groups/' . urlencode($name);
// /groups/Team+Alpha
+ is associated with form-style query strings, not general path encoding. Prefer:
echo '/groups/' . rawurlencode($name);
// /groups/Team%20Alpha
Double encoding
$value = rawurlencode('hello world'); // hello%20world
echo rawurlencode($value); // hello%2520world
The % is encoded as %25. Keep raw values in variables where possible and encode exactly once when constructing the URL.
Confusing URL encoding with HTML escaping
rawurlencode() makes data safe for a URL component. It does not make a URL safe to insert into HTML. When outputting a URL in an HTML attribute, escape it for HTML too:
$url = '/search?q=' . rawurlencode($term);
echo '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '">Search</a>';
Comparisons
| Situation | Recommended approach | Why |
|---|---|---|
One path segment, such as /users/{name} | rawurlencode($name) | Uses RFC 3986 percent encoding; spaces become %20. |
| Several query parameters | http_build_query($params) | Builds key=value&key=value safely. |
| Query string requiring RFC 3986 spaces | http_build_query($params, '', '&', PHP_QUERY_RFC3986) | Produces %20 instead of +. |
| Form-style query value encoded manually | urlencode($value) | Uses application/x-www-form-urlencoded; spaces become +. |
| Complete URL | Do not encode it as one string | Encode each inserted component separately. |
| Function | Space output | Typical use |
|---|---|---|
urlencode() | + | Form-style query-string values |
rawurlencode() | %20 | URL path segments and RFC 3986 components |
http_build_query() | + by default | Constructing a complete query string |
http_build_query(..., PHP_QUERY_RFC3986) | %20 | RFC 3986 query strings |
Cheat Sheet
// Form-style encoding: spaces become +
urlencode('a b'); // a+b
// RFC 3986 encoding: spaces become %20
rawurlencode('a b'); // a%20b
// Dynamic path segment
$url = '/posts/' . rawurlencode($slug);
// Query string, default form-style encoding
$url = '/search?' . http_build_query(['q' => $term]);
// Query string, RFC 3986 encoding
$url = '/search?' . http_build_query(
['q' => $term],
'',
'&',
PHP_QUERY_RFC3986
);
- Encode data, not an entire URL.
- Encode every dynamic path segment separately.
- Use
rawurlencode()for path segments. - Prefer
http_build_query()over manually assembling query strings. +represents a space in form-style query parsing;%20is the standard percent-encoded space.- Avoid encoding a value twice.
- URL encoding is different from HTML escaping.
FAQ
What is the main difference between urlencode() and rawurlencode() in PHP?
The key difference is spaces: urlencode() converts spaces to +, while rawurlencode() converts them to %20. They also follow different encoding conventions: form encoding and RFC 3986 encoding respectively.
Which function should I use for a URL path in PHP?
Use rawurlencode() for each dynamic path segment. It safely encodes spaces as %20 and prevents data such as / from changing the route structure.
Should I use urlencode() or rawurlencode() for query parameters?
Prefer http_build_query() for complete query strings. Its default output is form-style encoding; use PHP_QUERY_RFC3986 when an API requires RFC 3986 encoding.
Is %20 better than + in URLs?
Neither is universally better. %20 is the RFC 3986 percent-encoded form and is appropriate for path segments. + is conventional in application/x-www-form-urlencoded query strings.
Can I use rawurlencode() on a complete URL?
No. It will encode structural characters such as :, /, ?, and =, so the result is no longer a usable URL. Encode only variable components.
Does urlencode() protect against XSS?
No. URL encoding protects URL structure. Use htmlspecialchars() when inserting a URL into HTML, and use parameterized queries for database values.
Why does % become %25 after encoding?
% is itself a reserved character in percent encoding. If you encode an already encoded value, %20 becomes %2520; this is double encoding.
Mini Project
Description
Build a small PHP URL generator for a product page. The product category is placed in the path, while search and sorting options are placed in the query string. This demonstrates encoding each URL component correctly rather than encoding the complete URL.
Goal
Generate a valid product URL even when category names and search terms contain spaces, slashes, ampersands, or plus signs.
Requirements
Create a category path segment from a variable containing special characters. Build query parameters for a search term, sort order, and page number. Use RFC 3986 encoding for the generated query string. Do not encode the base URL or its structural slashes. Print the final URL.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.