如何仅 url 编码 url 的一部分?

How to urlencode part of the url only?

我有一个 WordPress 网站,有两个自定义 post 类型,bookarticle

由于设计需要,我想为 post 特色图片的 returnurl 创建简码。我无法使用 built-in 函数 get_the_post_thumbnail_url(),因为我将图像缓存在 wordpress.com 网络上(使用 Jetpack),而此函数 returns 缓存 url,这不符合我的设计要求。

我创建了以下简码:

function wp_featured_image_url( $atts ) {
   global $post;
    $url = get_the_post_thumbnail_url($post->ID); 
    if (is_singular($post_types = 'book')) {      
        if ( has_post_thumbnail() )  {
                return $url;    
                    }
        else {
                echo 'https://example.com/wp-content/uploads/year/month/generic-featured-image-for-books.png';  
            }   
        }

    else
        if (is_singular($post_types = 'article')) {
            if ( has_post_thumbnail() )  {
                    return $url;    
                    }
            else {
                echo 'https://example.com/wp-content/uploads/year/month/generic-featured-image-for-articles.png';   
                }   
        }       

}
add_shortcode( 'featured_image_url', 'wp_featured_image_url' );

它工作正常,除了图像文件标题是阿拉伯语 (UTF-8),所以这个函数将 return url 像这样:

https://example.com/wp-content/uploads/2019/10/كلام-عربي-كتير.jpg

我只想要return图像文件名的urlencode。但是,如果我将 return $url; 更改为 return urlencode($url);return rawurlencode($url); 它将 return 整个 url 为 urlencode:

https%3A%2F%2Fexample.com%2Fwp-content%2Fuploads%2F2019%2F10%2F%D9%83%D9%84%D8%A7%D9%85-%D8%B9%D8%B1%D8%A8%D9%8A-%D9%83%D8%AA%D9%8A%D8%B1.jpg

我希望能够调整函数,使 url 的第一部分保持不变,只有图像文件名得到 urlencode,像这样:

https://example.com/wp-content/uploads/2019/10/%D9%83%D9%84%D8%A7%D9%85-%D8%B9%D8%B1%D8%A8%D9%8A-%D9%83%D8%AA%D9%8A%D8%B1.jpg

有人能给我指出正确的方向吗? 提前致谢。

将 url 分成两部分:第一部分 - 从开始到最后一个斜杠的所有内容,第二部分 - 其他所有直到结束都没有斜杠的内容。 然后将它们组合回去,url仅对第二部分进行编码。

<?php

  function url_onlyfile_encode($url) {
    if (preg_match('#^(.*/)([^/]+)$#u', $url, $res)) {
      return $res[1] . urlencode($res[2]);
    }
    return urlencode($url);
  }

  // test
  $s = 'https://example.com/wp-content/uploads/2019/10/كلام-عربي-كتير.jpg';
  print url_onlyfile_encode($s);
  // https://example.com/wp-content/uploads/2019/10/%D9%83%D9%84%D8%A7%D9%85-%D8%B9%D8%B1%D8%A8%D9%8A-%D9%83%D8%AA%D9%8A%D8%B1.jpg

已更新

如果您想要最快的代码,请尝试直接使用字符串,如下所示:

  function url_onlyfile_encode($url) {
    $p = strrpos($url, '/'); // Find the last slash
    if ($p !== false) {
      // Encode only the part after the last slash
      return substr($url, 0, $p + 1) . urlencode(substr($url, $p + 1)); 
    } else {
      return urlencode($url);
    }
  }

我用这样的循环做了一个简单的测试:

  // test string
  $s = 'https://example.com/wp-content/uploads/2019/10/كلام-عربي-كتير.jpg';

  $repeat_count = 1000000;

  $tm = microtime(true);
  for ($i = 0 ; $i < $repeat_count ; $i++) {
    tested_func($s);
  }
  $tm = microtime(true) - $tm;
  print "Time: " . round($tm * 1000) . " ms" . PHP_EOL;

完整代码为here

结果如下:

php 5.6.40:

(Blank): 17 ms

AterLux (regexp): 1907 ms

AterLux (str): 641 ms

Emanuele: 3583 ms

Petter Harsem: 1269 ms

Yeeooow: 1884 ms

(注:"Blank"是一个空循环,里面没有任何函数调用)

php 7.3.4 (x64):

(Blank): 9 ms

AterLux (regexp): 499 ms

AterLux (str): 284 ms

Emanuele: 2820 ms

Petter Harsem: 477 ms

Yeeooow: 804 ms

如您所见,strrpos 的变体在任何一种情况下都是最快的。

其中,Petter Harsem 的 explode -> count -> implode 显示出比正则表达式更好的结果,尽管在 php7 中差异并不大.

Yeeooow 的答案,它也使用 explodecount,但使用 for 循环到 assemble 字符串返回,比 [= 上的正则表达式工作得更快61=]5 但在 php7 中显示两倍的时间。

Emanuele 的回答,涉及调用 parse_url 是最耗时的。

无论哪种方式,差异都在几微秒之内,这在现实世界中可以忽略不计。

另一种方式是粗鲁但更容易理解。

<?php
$url = "https://example.com/wp-content/uploads/2019/10/كلام-عربي-كتير.jpg";
$e = explode('/', $url); // seperate it ou using the /
$c = count($e); // get the number of elements
$ne = $c - 1; // the last element
$file = $e[$ne]; // كلام-عربي-كتير.jpg
$newURL = ''; // empty var
for ($i = 0; $i < $ne; $i++) {
    $newURL .= $e[$i] . '/'; // rebuild the url
}
echo $newURL . urlencode($file); //put it all togeather again

响应将是

https://example.com/wp-content/uploads/2019/10/%D9%83%D9%84%D8%A7%D9%85-%D8%B9%D8%B1%D8%A8%D9%8A-%D9%83%D8%AA%D9%8A%D8%B1.jpg 

简而言之,您需要拆分 url,将 urlencode 应用于文件名,然后将 URL 放回原处。有几种方法可以做到这一点,例如使用正则表达式来挑选最后一个 / 之后的部分。

或者另一个简单的解决方案,使用 explode and implode:

// Split the URL on '/'
$urlParts = explode('/', $url);

// URL encode the last part
$numParts = count($urlParts);
$urlParts[$numParts - 1] = urlencode($urlParts[$numParts - 1]);

// Put the parts back together to a string
$formattedUrl = implode('/', $urlParts);

试试这个:

$url = "https://example.com/wp-content/uploads/2019/10/كلام-عربي-كتير.jpg";
$parsed = parse_url($url);
$pathFragments = explode('/', $parsed['path']);
$fileAndExt = array_pop($pathFragments);
list($file, $ext) = explode(".", $fileAndExt);

return $parsed['scheme']."://".$parsed['host'].implode("/", $pathFragments)."/".urlencode($file).".".$ext;