curl_unescape() 函数用于解码URL编码的字符串。这是 curl_escape() 函数的逆操作,可以将百分号编码的字符串转换回原始字符串。
curl_unescape ( CurlHandle $handle , string $string ) : string|false
| 参数 | 描述 |
|---|---|
| handle | 由 curl_init() 返回的 cURL 句柄。 |
| string | 需要解码的URL编码字符串。 |
返回解码后的字符串,失败时返回 false。
// 初始化cURL句柄
$ch = curl_init();
// URL编码的字符串
$encodedString = "Hello%20World%20%26%20Good%20Morning%21";
$decodedString = curl_unescape($ch, $encodedString);
echo "编码字符串: {$encodedString}\n";
echo "解码后字符串: {$decodedString}\n";
// 清理
curl_close($ch);
function testRoundTrip($string) {
$ch = curl_init();
// 编码
$encoded = curl_escape($ch, $string);
echo "原始字符串: " . htmlspecialchars($string, ENT_QUOTES, 'UTF-8') . "\n";
echo "编码后: {$encoded}\n";
// 解码
$decoded = curl_unescape($ch, $encoded);
echo "解码后: " . htmlspecialchars($decoded, ENT_QUOTES, 'UTF-8') . "\n";
// 验证
$isEqual = ($string === $decoded);
echo "是否相等: " . ($isEqual ? '是' : '否') . "\n";
echo "---\n";
curl_close($ch);
return $isEqual;
}
// 测试不同的字符串
$testStrings = [
'Hello World',
'Hello World & Good Morning!',
'你好世界',
'!@#$%^&*()_+',
':/?#[]@!$&\'()*+,;=',
'≶script>alert("test")</script>',
"Line 1\nLine 2",
'🎉 Emoji 😀'
];
foreach ($testStrings as $string) {
testRoundTrip($string);
}
function decodeUrlQuery($url) {
$ch = curl_init();
// 解析URL
$parsedUrl = parse_url($url);
$query = $parsedUrl['query'] ?? '';
echo "原始URL: {$url}\n";
echo "查询字符串: {$query}\n\n";
// 解析查询参数
parse_str($query, $params);
echo "解码前参数:\n";
foreach ($params as $key => $value) {
echo " {$key} => {$value}\n";
}
echo "\n解码后参数:\n";
foreach ($params as $key => $value) {
$decodedKey = curl_unescape($ch, $key);
$decodedValue = curl_unescape($ch, $value);
echo " {$decodedKey} => {$decodedValue}\n";
}
curl_close($ch);
return $params;
}
// 使用示例
$url = 'https://example.com/search?q=Hello%20World%20%26%20PHP&category=programming%2Fweb&filter=price%3E100';
decodeUrlQuery($url);
class UrlDecoder {
private $ch;
public function __construct() {
$this->ch = curl_init();
}
public function safeDecode($encodedString) {
// 首先验证输入是否为有效的URL编码格式
if (!preg_match('/^(?:%[0-9A-Fa-f]{2}|[A-Za-z0-9\-._~])*$/', $encodedString)) {
throw new InvalidArgumentException('无效的URL编码字符串');
}
$decoded = curl_unescape($this->ch, $encodedString);
if ($decoded === false) {
throw new RuntimeException('解码失败');
}
// 验证解码后的字符串是否为有效的UTF-8
if (!mb_check_encoding($decoded, 'UTF-8')) {
throw new RuntimeException('解码结果不是有效的UTF-8字符串');
}
return $decoded;
}
public function decodeUrlComponents($url) {
$components = parse_url($url);
$decodedComponents = [];
foreach ($components as $key => $value) {
if (is_string($value)) {
try {
$decodedComponents[$key] = $this->safeDecode($value);
} catch (Exception $e) {
$decodedComponents[$key] = $value; // 保留原始值
}
} else {
$decodedComponents[$key] = $value;
}
}
return $decodedComponents;
}
public function __destruct() {
if ($this->ch) {
curl_close($this->ch);
}
}
}
// 使用示例
try {
$decoder = new UrlDecoder();
// 解码单个字符串
$encoded = 'Hello%20World%20%26%20PHP%20%E6%95%99%E7%A8%8B';
$decoded = $decoder->safeDecode($encoded);
echo "解码结果: {$decoded}\n\n";
// 解码完整URL
$url = 'https://example.com/search?q=PHP%20%26%20cURL%20%E6%95%99%E7%A8%8B&lang=zh-CN';
$components = $decoder->decodeUrlComponents($url);
echo "URL组件解码:\n";
foreach ($components as $key => $value) {
echo " {$key}: " . htmlspecialchars($value, ENT_QUOTES, 'UTF-8') . "\n";
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
function compareDecodingMethods($encodedString) {
$ch = curl_init();
$methods = [
'curl_unescape' => function($str) use ($ch) {
return curl_unescape($ch, $str);
},
'rawurldecode' => 'rawurldecode',
'urldecode' => 'urldecode'
];
echo "编码字符串: {$encodedString}\n\n";
$results = [];
foreach ($methods as $name => $function) {
if (is_callable($function)) {
$decoded = $function($encodedString);
} else {
$decoded = call_user_func($function, $encodedString);
}
$results[$name] = $decoded;
echo "{$name}: " . htmlspecialchars($decoded, ENT_QUOTES, 'UTF-8') . "\n";
}
curl_close($ch);
// 检查所有方法的结果是否相同
$allSame = (count(array_unique($results)) === 1);
echo "\n所有方法结果相同: " . ($allSame ? '是' : '否') . "\n";
return $results;
}
// 测试不同的编码字符串
$testCases = [
'简单空格' => 'Hello%20World',
'加号编码' => 'Hello+World', // 注意:curl_unescape不会将+解码为空格
'特殊字符' => '%21%40%23%24%25%5E%26%2A%28%29',
'中文字符' => '%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C',
'混合编码' => 'Hello%20World%20%26%20%E4%BD%A0%E5%A5%BD',
'无效编码' => 'Hello%2World', // 无效的百分号编码
'双编码' => 'Hello%2520World' // 双重编码的%20
];
foreach ($testCases as $desc => $encoded) {
echo "\n================================\n";
echo "测试: {$desc}\n";
echo "================================\n";
try {
compareDecodingMethods($encoded);
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
}
| 编码字符串 | curl_unescape | rawurldecode | urldecode | 说明 |
|---|---|---|---|---|
| %20 | 空格 | 空格 | 空格 | 空格解码 |
| + | + | + | 空格 | 加号处理 |
| %26 | & | & | & | 与符号解码 |
| %2F | / | / | / | 斜杠解码 |
| %E4%BD%A0%E5%A5%BD | 你好 | 你好 | 你好 | 中文解码 |
| %2520 | %20 | %20 | %20 | 双重编码 |
| Hello+World | Hello+World | Hello+World | Hello World | 加号不转空格 |
| %2G | false | %2G | %2G | 无效编码处理 |
curl_unescape() 函数需要PHP 5.5.0或更高版本,并且需要cURL 7.15.5或更高版本支持。
curl_unescape() 是 curl_escape() 的逆操作,遵循RFC 3986标准urldecode() 会将 + 解码为空格,而 curl_unescape() 和 rawurldecode() 不会curl_unescape() 对于无效的百分号编码会返回 false,而其他函数可能返回原始字符串rawurldecode()curl_unescape() 前验证输入字符串的格式false,表示解码失败A: 主要区别在于:
1. curl_unescape() 需要cURL句柄作为第一个参数
2. curl_unescape() 对于无效编码返回 false,而 rawurldecode() 可能返回包含无效编码的字符串
3. 两者都不将 + 解码为空格(与 urldecode() 不同)
A: 不会。如果字符串是双重编码的(如 %2520),curl_unescape() 只会解码一层,结果是 %20。如果需要完全解码,需要多次调用解码函数。
A: 始终检查 curl_unescape() 的返回值是否为 false。如果解码失败,可以根据具体情况选择:使用原始字符串、记录错误、抛出异常或使用默认值。