There is no simple solution. As a starting point, you can manually parse the component parts. In your example, this option will give a ride, but catch errors when the parts are not announced. For example, I now had a break in checking for the presence of the path and request parameters.
/ ** rough draft solution * / function unsafe_url_encode ($ url) {$ url_parts = parse_url ($ url); / ** split url into parts * / $ path = preg_split ('# / #', $ url_parts ['path']); / ** split the path into parts * / $ path = array_map ('urlencode', $ path); / * encode each part of the path * / $ url_parts ['path'] = implode ('/', $ path); $ args = preg_split ('# & #', $ url_parts ['query']); / ** split parameters into parts, and process them * / foreach ($ args as $ k => $ v) {$ argument = preg_split ('# = #', $ v); $ argument = array_map ('urlencode', $ argument); $ args [$ k] = implode ('=', $ argument); } / ** put everything in a heap * / $ args = implode ('&', $ args); $ url_parts ['query'] = $ args; extract ($ url_parts); $ retval = "$ {scheme}: // $ {host} $ {path}"; if (strlen ($ query)) $ retval. = "? $ {query}"; if (isset ($ fragment)) $ retval. = '#'. urlencode ($ fragment); return $ retval; } echo unsafe_url_encode ("https://yandex.ru/search/?text= hello"); An online sandbox with an example: http://sandbox.onlinephpfunctions.com/code/fd073f99c4a76f08ec34aef44e810ce4aafdaf47