preg_quote
Escapes regular expression special characters so a string can be used literally in a pattern.
preg_quote(string $str, ?string $delimiter = null): string- Added in PHP 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$str | string | The input string to escape. |
$delimiteroptional | ?string= null | An extra character to escape, normally the delimiter you are about to wrap the pattern in, such as '/'. |
Return value
stringThe input string with every regex metacharacter (and the delimiter, if given) prefixed by a backslash.
Changelog
- PHP 7.3.0The # character is now quoted, so patterns built with preg_quote() are safe under the x (extended) modifier.
- PHP 7.2.0delimiter is nullable.
preg_quote() backslash-escapes every character PCRE treats as special: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : - # and, since PHP 7.3, #. NUL bytes become \000. Everything else, including spaces and /, is left alone.
When to reach for it
Any time part of a pattern comes from outside your source code — a search box, a filename, a configuration value, a database column. Without it, a user typing c++ or ( either breaks your pattern with a compile warning or, worse, turns their input into a working regex against your data. Wrap the dynamic part and leave your own anchors and modifiers outside the call.
What trips people up
/ is not escaped by default because it is not a metacharacter; if you delimit with / you must pass it as the second argument, or a slash in the input ends your pattern early. Never run it on a replacement string for preg_replace() — the escaping rules there are different, and you only need to guard $ and \. And escaping does not make a pattern fast: a quoted 5 KB blob is still a 5 KB pattern.
Example
When to use it
- Build a case-insensitive search pattern from a user-supplied search term
- Match a literal filename or path fragment that may contain dots and brackets
- Highlight every occurrence of a keyword in a page of text without breaking on punctuation
Frequently asked questions
Does preg_quote escape the forward slash?
Not by default, because / is not a regex metacharacter. Pass it as the second argument — preg_quote($s, '/') — whenever you build a pattern delimited with slashes.
Should I use preg_quote on the replacement string of preg_replace?
No. Replacement strings have different rules; escaping them with preg_quote leaves visible backslashes in the output. To make a replacement literal, escape only backslashes and dollar signs, or use preg_replace_callback.
Which characters does preg_quote escape?
It escapes . \ + * ? [ ^ ] $ ( ) { } = ! < > | : - and, since PHP 7.3, #. NUL bytes are converted to \000, and the optional delimiter argument is escaped too.
More examples
What happens without it
The first call does not fail — it returns 1. In PCRE2 the second '+' makes the first one possessive, so '/c++/' compiles fine and matches a bare run of c's: $matches[0] is just 'c', and the same pattern would match 'a cat' too. That is the real danger of unescaped input — it silently becomes a different pattern, not necessarily a broken one. The second call returns 1 because preg_quote turned the input into 'c\+\+', which matches the literal text 'c++'. (For input that genuinely fails to compile, use something like '(' or 'c(*'.)
<?php
$userInput = 'c++';
// Unescaped: '/c++/' compiles - the second '+' only makes the first
// possessive - so it matches a bare 'c' anywhere, not the literal 'c++'.
preg_match('/' . $userInput . '/', 'a cat', $m);
var_dump($m[0]); // string(1) "c"
// Escaped: matched literally.
var_dump(preg_match('/' . preg_quote($userInput, '/') . '/', 'c++ is fine')); // int(1)
// Input that really does break the pattern:
var_dump(@preg_match('/' . '(' . '/', '(')); // bool(false)
var_dump(preg_match('/' . preg_quote('(', '/') . '/', '(')); // int(1)The slash trap
The first line prints 'wp\-content/uploads': the hyphen IS on preg_quote's list and gets escaped, while the slash is left alone — which is what would terminate a '/...' pattern at the slash. Passing '/' as the delimiter argument produces 'wp\-content\/uploads', which is safe to embed.
<?php
$path = 'wp-content/uploads';
echo preg_quote($path), "\n"; // slash left alone
echo preg_quote($path, '/'), "\n"; // slash escaped
var_dump((bool) preg_match('/' . preg_quote($path, '/') . '/', 'in wp-content/uploads/2026'));Highlighting a search term
Both the dollar sign and the dot in the search term are escaped, so only the literal $9.99 is wrapped and $19.99 is left alone. Note that $0 in the replacement string is deliberately not quoted — preg_quote is for patterns, never for replacements.
<?php
$text = 'Prices: $9.99 and $19.99 (incl. VAT)';
$term = '$9.99';
$out = preg_replace(
'/' . preg_quote($term, '/') . '/',
'[$0]',
$text
);
echo $out, "\n";
Discussion