3

I have a url that looks like that

http://example.com/index.php?id=111&title=word1 word2 word3

I need to encode the spaces before requesting the url with curl.

But how to urlencode the right parts of the url.

urlencode and rawurlencode encode the slashes of https the question mark etc.

1
  • Use parse_url to break the URL into its component parts, and then operate on the query string as required. Use http_build_url to stitch back together. Commented Mar 29, 2012 at 9:19

4 Answers 4

6

You can use parse_url() to split the URL into its respective pieces. Use urlencode() on the query element from the array that parse_url returns, then put it back together using http_build_url.

NOTE: http_build_url requires PECL pecl_http >= 0.21.0

Sign up to request clarification or add additional context in comments.

6 Comments

Further use of parse_str and http_build_query are worth mentioning too.
The query is already partly encoded, wouldn't encoding it again result in the existing &'s and ='s being mistakenly substituted?
parse_url will return the query arguments as a string id=111&title=word1 word2 word3 If I urlencode that string i run into the same problem. the & and = will be encoded..
If spaces are the only issue (i.e. word1 word2 etc. can't contain any punctuation) surely a simple regex on the whole thing to replace spaces with + would do the job.
You're not going to get very far trying to make a bullet proof function to convert unknown query strings that may or may not already be properly/fully encoded. You'll get a best guess function and that's all you'll get.
|
0

Replace white spaces with "+".

Comments

0

As @F21 said,...

function fixUrlEncoding(string $url){

    $scheme = parse_url($url, PHP_URL_SCHEME);
    $host   = parse_url($url, PHP_URL_HOST);
    $path   = parse_url($url, PHP_URL_PATH);
    $query  = parse_url($url, PHP_URL_QUERY);

    $f = explode('?', $query,2);
    $file  = $f[0];
    $query = $f[1];

    $ini   = $scheme . '://' . $host . $path ;

    // fix encoding
    parse_str($query, $result);
    foreach ($result as $k => $val){
        $result[$k] = urlencode($val);
    }

    $query = $file . '?' . http_build_query($result);

    if (!Strings::startsWith('http', $url)){
        $url = $ini . '?' . $query;
    } else {
        $url = substr($url, strlen($ini)) . '?' . $query;
        $url = $ini . '?' . $query;
    }

    return $url;
}

2 Comments

as of PHP 8, Strings::startsWith('http',$url) can be replace with str_starts_with($url,'http') OR substr($url,0,4)=='http' for users with older versions of PHP and no 'Strings'
Also, the second instance of "$url = $ini . '?' . $query;" I think should be removed...
0

It's strange that PHP currently doesn't have a function to encode the entire URL, including domain/path/query. My version to encode Full url.

/**
 * To encode full url including domain/path/query
 * https://www.php.net/manual/en/function.parse-url.php
 * https://www.php.net/en/idn_to_ascii
 * https://www.php.net/manual/en/function.urlencode.php
 * 
 * @param string $urlFull
 * @return string
 */
function urlencodeFull(string $urlFull): string
{
    //add scheme if not set
    $urlFull = ((!strstr($urlFull, '://') and strlen($urlFull)) ? 'https://' : '') . $urlFull;
    
    //parse url
    if($url = parse_url($urlFull) and isset($url['host']))
    {    
        //urlencode for url path
        if(isset($url['path']) and strlen($url['path']) > 1)
        {
            $url['pathArray'] = array_filter(array_map(fn($v) => urlencode(urldecode($v)), explode('/', $url['path'])));
        }

        //urlencode for url query
        if(isset($url['query']) and strlen($url['query']) > 1)
        {
            $url['queryArray'] = array_filter(array_map(fn($v) => urlencode(urldecode($v)), explode('&', $url['query'])));
        }

        return $url['scheme'] . '://' . idn_to_ascii($url['host']) .
                (isset($url['port']) ? ':' . $url['port'] : '') . 
                (isset($url['pathArray']) ? '/' . implode('/', $url['pathArray']) . '/' : '') .
                (isset($url['queryArray']) ? '?' . implode('&', $url['queryArray']) : '') .
                (isset($url['fragment']) ? '#' . $url['fragment'] : '');
    }
    else
    {
        return $urlFull;
    }
}

And in result:

echo urlencodeFull('https://täst.de/täst1/täst2?täst3=t r u e');

will be

https://xn--tst-qla.de/t%C3%A4st1/t%C3%A4st2/?t%C3%A4st3%3Dt+r+u+e

2 Comments

else is not necessary this there is an early return in the if block. You can put only return $urlFull; after the if block.
You can use str_contains() instead of strstr(), it's available since PHP 8.0 released in late 2020.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.