The text/uri-list format

text/uri-list is the standard file listing format for drag and drop. It is specified as follows:

Now the world would not be the world we know if everyone followed the specs. As written on freedesktop.org, there are plenty of implementations, and most cook their own soup.

Let it be the \r\n at the end of the line; most programs do that right but some just forget the \r. Some forget the terminating characters on the last line. That is easy to catch when implementing the routine in php.

The real problem are the URIs, or what the programmers think URIs are.

And beside files, there can be real URLs like http://gtk.php.net in the list. What does that tell us? We will have a hard time finding out where the file really is.

We need a solution which accepts URIs that follow the standard AND is able to guess what files the source applications mean if the URI does not conform to the standard. The resulting code seems to be awkward, but that's the price for compatibility:

Example 4.5. Convert a (misformed) URI to a local path

/**
*   converts a file path gotten from a text/uri-list
*   drop to a usable local filepath
*   @param  string  The line from the uri-list
*   @return string  The usable local filepath
*/
function getPathFromUrilistEntry( $strUriFile)
{
    $strUriFile = urldecode($strUriFile);//should be URL-encoded
    $bUrl = false;
    if (substr($strUriFile, 0, 5) == 'file:')
    {   //(maybe buggy) file protocol
        if (substr($strUriFile, 0, 17) == 'file://localhost/') {
            //correct implementation
            $strFile = substr($strUriFile, 16);
        } else if (substr($strUriFile, 0, 8) == 'file:///') {
            //no hostname, but three slashes - nearly correct
            $strFile = substr($strUriFile, 7);
        } else if ($strUriFile[5] == '/') {
            //theoretically, the hostname should be the first
            //but no one implements it
            $strUriFile = substr($strUriFile, 5);
            for( $n = 1; $n < 5; $n++) {
                if ($strUriFile[$n] != '/') { break; }
            }
            $strUriFile = substr($strUriFile, $n - 1);
            if (!file_exists($strUriFile)) {
                //perhaps a correct implementation with hostname???
                $strUriFileNoHost = strstr(substr($strUriFile, 1), '/');
                if (file_exists($strUriFileNoHost)) {
                    //seems so
                    $strUriFile = $strUriFileNoHost;
                }
            }
            $strFile = $strUriFile;
        } else {
            //NO slash after "file:" - what is that for a crappy program?
            $strFile = substr ($strUriFile, 5);
        }
    } else if (strstr($strUriFile, '://')) {
        //real protocol, but not file
        $strFile = $strUriFile;
        $bUrl    = true;
    } else {
        //local file?
        $strFile = $strUriFile;
    }
    if (!$bUrl && $strFile[2] == ':' && $strFile[0] == '/') {
        //windows file path
        $strFile = str_replace('/', '\\', substr($strFile, 1));
    }
    return $strFile;
}

Now that we have a nice conversion routine, we can extend our source to display the local path in the file tree:

© Copyright 2003-2023 www.php-editors.com. The ultimate PHP Editor and PHP IDE site.