【问题标题】:Test if string is URL encoded in PHP测试字符串是否是用 PHP 编码的 URL
【发布时间】:2009-10-28 14:50:20
【问题描述】:

如何测试字符串是否经过 URL 编码?

以下哪种方法更好?

  • 在字符串中搜索将被编码的字符,哪些不是,如果存在则它没有被编码,或者
  • 使用我制作的类似的东西:

function is_urlEncoded($string){
 $test_string = $string;
 while(urldecode($test_string) != $test_string){
  $test_string = urldecode($test_string);
 }
 return (urlencode($test_string) == $string)?True:False; 
}

$t = "Hello World > how are you?";
if(is_urlEncoded($sreq)){
 print "Was Encoded.\n";
}else{
 print "Not Encoded.\n";
 print "Should be ".urlencode($sreq)."\n";
}

上述代码有效,但在字符串被双重编码的情况下无效,如以下示例:

  • $t = "Hello%2BWorld%2B%253E%2Bhow%2Bare%2Byou%253F";
  • $t = "Hello+World%2B%253E%2Bhow%2Bare%2Byou%253F";

【问题讨论】:

  • 当您的 PHP 脚本看到该字符串时,它是如何进行 URL 编码的?问题真的是您的脚本需要对传入的字符串进行 URL 解码,还是您的脚本不需要对链接 href 或输入值进行双重编码?
  • 如何使用 urldecode 并将其与原始字符串进行比较。如果它们匹配,则尚未编码。

标签: php testing url-encoding


【解决方案1】:

我有一个窍门:

您可以这样做以防止双重编码。 每次先解码再编码;

$string = urldecode($string);

然后再做一次

$string = urlencode($string);

这样我们可以避免双重编码:)

【讨论】:

  • 错了!一旦解码的 URL 不能以相同的方式编码。有关更多信息检查:blog.lunatech.com/2009/02/03/… 例如“a+b”作为路径参数是有效的。然后如果你解码它你有相同的字符串(a + b),然后编码结果是“a%2Bb”!
  • 这会造成麻烦。例如。如果你有一个带有加号的纯文本字符串,像这样:“TestString Super Mega +” 如果你通过 urldecode() 管道将加号删除;
  • 来自 blog.lunatech 的链接已关闭。这是替代网址:web.archive.org/web/20151229061347/http://blog.lunatech.com/…
  • @instead 我认为这取决于使用什么功能。如果你想严格遵守 RFC 3986 或 rawurlxxxxxx,那么 + 将是 %20b,但如果你使用 urlxxxxxx,那么它仍然是 + 符号,但所有空格字符也将是 + 符号。 :)
【解决方案2】:

这是我刚刚整理的。

if ( urlencode(urldecode($data)) === $data){
    echo 'string urlencoded';
} else {
    echo 'string is NOT urlencoded';
}

【讨论】:

  • @suther 请用各种输入测试它,我不记得但有时它不能按预期工作。
【解决方案3】:

您永远无法确定字符串是否经过 URL 编码,或者它是否应该包含序列 %2B。相反,它可能取决于字符串的来源,即它是手工制作的还是来自某个应用程序。

最好在字符串中搜索要编码的字符,哪些不编码,如果存在则不编码。

我认为这是一种更好的方法,因为它会处理以编程方式完成的事情(假设应用程序不会留下未编码的字符)。

这里会让人感到困惑...从技术上讲,如果 % 出现在最终值中,则“应该”对其进行编码,因为它是一个特殊字符。您可能必须结合您的方法来查找应该编码的字符,并验证字符串是否成功解码(如果没有找到)。

【讨论】:

  • “应该有序列%2B在里面”,他的decode-check-encode-check是为了解决这个问题(解码到空格,编码到%2B,不编码)跨度>
  • 是的,除非打算将该序列作为最终值传递...您的算术示例是一个更好的示例,但它会失败。相反,通过检查“应该”被编码的字符,应用程序可以更好地了解字符串是否已经被编码。
  • 特别是 : 字符,它是有效 uri (tools.ietf.org/html/rfc3986) 中必需的分隔符,不会出现在 urlencoded 字符串中。
【解决方案4】:

我认为没有万无一失的方法。例如,考虑以下情况:

$t = "A+B";

那个 URL 是编码为“A B”还是需要编码为“A%2BB”?

【讨论】:

    【解决方案5】:

    好吧,“url 编码”这个词有点含糊,也许简单的正则表达式检查就可以解决问题

    $is_encoded = preg_match('~%[0-9A-F]{2}~i', $string);
    

    【讨论】:

    • 嗯,我认为 '+' 是 url 中空格的有效编码?
    【解决方案6】:

    怎么样:

    if (urldecode(trim($url)) == trim($url)) { $url_form = 'decoded'; }
      else { $url_form = 'encoded'; }
    

    不适用于双重编码,但我想这超出了范围?

    【讨论】:

    • 用字符串“1+1=2”试试
    【解决方案7】:

    没有可靠的方法来做到这一点,因为有些字符串在编码过程中保持不变,即“abc”是否编码?没有明确的答案。另外,正如你所遇到的,有些字符有多种编码......但是......

    您的 decode-check-encode-check 方案失败,因为某些字符可能以不止一种方式编码。但是,对您的函数稍作修改应该是相当可靠的,只需检查解码器是否修改了字符串,如果是,则它已被编码。

    这当然不是万无一失的,因为 "10+20=30" 将返回 true(+ 被转换为空格),但我们实际上只是在做算术。我想这就是你的计划试图反击的,很抱歉我认为没有完美的解决方案。

    HTH。

    编辑:
    正如我在自己的评论中提到的(为了清楚起见,这里只是重申一下),一个好的折衷办法可能是检查你的 url 中的无效字符(例如空格),如果有一些它没有编码。如果没有,请尝试解码并查看字符串是否更改。这仍然无法处理上面的算术(这是不可能的),但希望它就足够了。

    【讨论】:

    • "然而,对你的函数稍加修改应该是相当可靠的,只要检查解码是否修改了字符串,如果是,它被编码了。"我是这么想的,但是如果这是字符串“Hello+World how are you”,那么解码它会产生变化,但它不会被完全编码。
    • @Psytronic:非常正确,+ 是个混蛋,不是吗。如果您能找到一种方法来确定它是否是有效的 URL,然后解码以检查更改可能是一个更好的解决方案。您应该能够设计一个正则表达式来查找像空格这样的“坏”字符(如果它无效,则它没有被编码)。
    【解决方案8】:

    @user187291 代码有效且仅在 + 未编码时失败。

    我知道这是很老的帖子。但这对我有用。

    $is_encoded = preg_match('~%[0-9A-F]{2}~i', $string);
    if($is_encoded) {
     $string  = urlencode(urldecode(str_replace(['+','='], ['%2B','%3D'], $string)));
    } else {
      $string = urlencode($string);
    }
    

    【讨论】:

    • 如果编码如 RFC 3986 中所述,则正则表达式必须是另一个
    【解决方案9】:

    当您已经从 url 获取数据时,发送一个标记解码的变量。

    ?path=folder/new%20file.txt&decode=1
    

    【讨论】:

      【解决方案10】:

      在我的例子中,我想检查一个完整的 URL 是否被编码,所以我已经知道 URL 必须包含字符串 https://,我所做的是检查该字符串是否具有 https:// 的编码版本在其中 (https%3A%2F%2F) 如果没有,那么我知道它没有被编码:

      //make sure $completeUrl is encoded
      if (strpos($completeUrl, urlencode('https://')) === false) {
          // not encoded, need to encode it
          $completeUrl = urlencode($completeUrl);
      }
      

      理论上,此解决方案可用于任何具有已编码字符的字符串,只要您知道字符串的一部分(在此示例中为https://)将始终存在于您要检查的内容中​​。

      【讨论】:

        【解决方案11】:

        我正在使用以下测试来查看字符串是否已被 urlencoded:

        if(urlencode($str) != str_replace(['%','+'], ['%25','%2B'], $str))
        

        如果一个字符串已经被urlencoded,唯一会被双重编码改变的字符是%(它开始所有编码的字符串)和+(它替换空格。)把它们改回来,你应该有原始字符串。

        让我知道这是否适合你。

        【讨论】:

        • 应该将!= 替换为==
        【解决方案12】:

        我找到了。
        网址例如:https://example.com/xD?foo=bar&uri=https%3A%2F%2Fexample.com%2FxD
        您需要发现 $_GET['uri'] 是否已编码:

        preg_match("/.*uri=(.*)&?.*/", $_SERVER['REQUEST_URI'], $r);
        if (isset($_GET['uri']) && urldecode($r['1']) === $r['1']) {
          // Code Here if url is not encoded
        }
        

        【讨论】:

          【解决方案13】:

          私有静态布尔 isEncodedText(String val, String... encoding) 抛出 UnsupportedEncodingException { String decodedText = URLDecoder.decode(val, TransformFetchConstants.DEFAULT_CHARSET);

              if(encoding != null && encoding.length > 0){
                  decodedText = URLDecoder.decode(val, encoding[0]);
              }
          
              String encodedText =  URLEncoder.encode(decodedText);
          
              return encodedText.equalsIgnoreCase(val) || !decodedText.equalsIgnoreCase(val);
          
          }
          

          【讨论】:

            猜你喜欢
            • 2012-01-06
            • 2011-02-28
            • 2013-08-05
            • 1970-01-01
            • 2022-11-20
            • 2012-04-25
            相关资源
            最近更新 更多