Class it_html:

/**
 * Build a complete url from base-url and params
 * @param ... scalar args and numeric indices build base-url, rest as params
 */
static function U(...$args)
{
    list($base, $params) = it_parse_args($args);

    if (!isset($base))
        $base = preg_replace('/\?.*/', '', $_SERVER['REQUEST_URI']);

    $base = preg_replace('|\0|', '', $base); # kill null chars

    if (!($u = @parse_url($base)))
    {
        $u = [];
        list($u['path'], $u['query']) = explode("?", $base, 2);
    }

    $u['host'] = preg_match('/[^-_.0-9a-z]/i', $u['host']) && function_exists('idn_to_ascii') && ($idnahost = idn_to_ascii($GLOBALS['it_html']->p['charset'] == "iso-8859-1" ? it::utf8_encode($u['host']) : $u['host'])) ? $idnahost : $u['host'];    # Punycode hostname to include into webpage
    $u['host'] = preg_replace_callback('/[^-_.0-9a-z\x80-\xff]/i', function($m) { return rawurlencode($m[0]); }, $u['host']); # Encode garbage chars in host

    # handle scheme, user (urlencoded), password, host
    $hostpart = 
        ($u['user'] ? preg_replace_callback('|[^-a-z0-9_.+!*(),:?@&=/~$%#]|i', function($m) { return rawurlencode($m[0]); }, $u['user'] . ($u['pass'] ? ":" . $u['pass'] : "") . "@") : "") .
        ($u['host'] ? $u['host'] : "") .
        ($u['port'] ? ":" . intval($u['port']) : "");

    # Remove unsupported javascript: scheme as it leads to security problems
    if (it::match('javascript', $u['scheme']))
        $u['scheme'] = '';

    $schemepart = $hostpart ? ($u['scheme'] ? $u['scheme'] . ":" : "") . "//$hostpart" : ($u['scheme'] == "data" || $u['scheme'] == "mailto" ? $u['scheme'] . ":" : "");

    # remove strings that will be interpreted as scheme from path
    if (!$schemepart && !$hostpart)
        $u['path'] = preg_replace('|^([^/]*:)+|', '', $u['path']);

    # sanitize path and fragment
    $u['path'] = preg_replace('|\\\\|', '/', $u['path']); # turn \ to /
    foreach (['path', 'query', 'fragment'] as $key)
        $u[$key] = preg_replace_callback('/[^-a-z0-9_.+!*(),:?@&=\/~$%#]|%(?![0-9a-f]{2})/i', fn($m) => $u['scheme'] != 'data' ? rawurlencode($m[0]) : $m[0], $u[$key]);

    # convert empty http url path to /
    if (!$u['path'] && $hostpart && preg_match('/^(https?)?$/', $u['scheme']))
        $u['path'] = '/';

    # if we supplied params, add/replace them in the existing url, removing empty existing params such as foo=&bar
    if ($params)
    {
        $u['params'] = it_url::parse_str($u['query']);

        # if params replace url parameters that are present in base, replace them but keep their order
        foreach ($u['params'] as $key => $dummy)
            if (isset($params[$key]))
                $u['params'][$key] = $params[$key];

        $u['query'] = it_url::params($u['params'] + $params);
    }

    return $schemepart . $u['path'] . ($u['query'] ? "?" . $u['query'] : "") . ($u['fragment'] ? "#" . $u['fragment'] : "");
}

Global function in file auto_prepend.php:

/****************** functions for class it_text **********************/

/**
 * Build an url
 */
function U(...$args)
{
    return is_a($obj = $GLOBALS['it_html'], 'it_html') ? $obj->U(...$args) : it_html::U(...$args);
}