# Scripts

When a directory listing is generated through a script, the server gathers the information related to the files inside the listed directory and packs it in a special string. Then the script is executed and the special string is POSTed to it inside a variable called `files`. The server also POSTs the directory virtual path in a variable which name is `path` as well as an URL encoded (escaped) version of the virtual path in a variable named `encoded_path`.

This special string passed in the `files` variable is of the form:

name1→ | url1→ | size1→ | date1→ | MIME-type1[CR]
name2→ | url2→ | size2→ | date2→ | MIME-type2[CR]
. | . | . | . |
. | . | . | . |
namen-1→ | urln-1→ | sizen-1→ | daten-1→ | MIME-typen-1[CR]
namen→ | urln→ | sizen→ | daten→ | MIME-typen

→ represents the tabulation character (ASCII code 9 - `\t`) and [CR] represents the carriage return character (ASCII code 13 - `\n`). The tuple `(namei, urli, sizei, datei, MIME-typei)` is the information related to the ith file in the listing.

The name and the URL of every file are UTF-8 encoded. The size is in bytes. The date is conforming to the format `YYYY-MM-DD hh:mm:ss` which is equivalent in `strftime` semantics to `%Y-%m-%d %H:%M:%S`.

The MIME type of a directory is empty, i.e. it is equal to the empty string. The name of a directory contains always a trailing slash.

The script should split the `files` variable value on the carriage return characters then split each line on the tabulation character to have the information related to each file.

Example 8-2. A very simple directory listing script (PHP version)

       <HTML>
         <HEAD>
           <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
           <TITLE>
               Index of <?php echo $_POST['path']; ?>
           </TITLE>
         </HEAD>

         <BODY>

           <TABLE BORDER="0">

             <TR>
               <TD>Name</TD>
               <TD>Size</TD>
               <TD>Date</TD>
               <TD>MIME Type</TD>
             </TR>

             <?php

               /* Split and get the lines */
               $lines = explode("\n", $_POST['files']);

               /* For each line do... */
               foreach ($lines as $line)
               {
                 /* Split the line and get the file information */
                 list($name, $url, $size, $date, $mimetype) = explode("\t", $line);

                 if ($mimetype == "")
                   $mimetype = "Directory";

                 echo "<TR><TD><A HREF=\"$url\">" . htmlentities($name) .
                           "</A></TD><TD>$size</TD><TD>$date</TD><TD>$mimetype</TD></TR>";
               }
            ?>

            </TABLE>
          </BODY>
       </HTML>

Example 8-3. A very simple directory listing script (Python 3 version with the legacy cgi package)

       # This script makes use of the cgi package which was available by default
       # until Python 3.12.
       # If using Python 3.13 or later, you'll need to install the legacy-cgi
       # package from https://pypi.org/project/legacy-cgi/ or with the command:
       #     python3 -m pip install legacy-cgi
       # Alternatively, check the next example for a way to write an equivalent
       # script without using the cgi package.

       import cgi, html

       posted_data = cgi.FieldStorage()

       # Write the CGI header
       print ('Content-Type: text/html; charset=utf-8')
       print ()

       print ('<HTML><HEAD>')
       print ('<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">')
       print ('<TITLE>Index of %s</TITLE></HEAD>' % posted_data['path'].value)

       print ('<TABLE><TR><TD>Name</TD><TD>Size</TD><TD>Date</TD><TD>MIME Type</TD></TR>')

       # Split and get the lines
       lines = (posted_data['files'].value).split('\n')

       # for each line do...
       for line in lines:
       	# Split the line and get the file information
       	(name, url, size, date, mimetype) = line.split('\t')

       	if (mimetype == ''):
       		mimetype = 'Directory'

       	print ('<TR><TD><A HREF="%s">%s</A></TD>' % ( url, html.escape(name) ))
       	print ('<TD>%d</TD><TD>%s</TD><TD>%s</TD></TR>' % (int(size), date, mimetype))

       print ('</TABLE></BODY></HTML>')

Example 8-4. A very simple directory listing script (Python 3 version with no legacy or deprecated packages)

       # Alternative version which works with the default
       # wsgiref.handlers.CGIHandler module and requires
       # no additional packages.

       from wsgiref.handlers import CGIHandler
       from urllib.parse import parse_qs
       import html

       def app(environ, start_response):
       	# the environment variable CONTENT_LENGTH may be empty or missing
       	try:
       		request_body_size = int(environ.get('CONTENT_LENGTH', 0))
       	except (ValueError):
       		request_body_size = 0

       	# When the method is POST, the variables are sent
       	# in the HTTP request body which is passed by the WSGI server
       	# in a file inside the wsgi.input environment variable.
       	request_body = environ['wsgi.input'].read(request_body_size).decode('utf-8')
       	d = parse_qs(request_body)

       	path = d.get('path', [''])[0] # Returns the first path value.
       	files = d.get('files', [''])[0] # Returns the first files value.

       	response_body = [ '<HTML><HEAD>' ]
       	response_body.append('<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">')
       	response_body.append('<TITLE>Index of %s</TITLE></HEAD>' % path)

       	response_body.append('<TABLE><TR><TD>Name</TD><TD>Size</TD><TD>Date</TD><TD>MIME Type</TD></TR>')

       	# Split and get the lines
       	lines = files.split('\n')

       	# for each line do...
       	for line in lines:
       		# Split the line and get the file information
       		(name, url, size, date, mimetype) = line.split('\t')

       		if (mimetype == ''):
       			mimetype = 'Directory'

       		response_body.append('<TR><TD><A HREF="%s">%s</A></TD>' % ( url, html.escape(name) ))
       		response_body.append('<TD>%d</TD><TD>%s</TD><TD>%s</TD></TR>' % (int(size), date, mimetype))

       	response_body.append('</TABLE></BODY></HTML>')

       	status = '200 OK'

       	response_headers = [
       		('Content-Type', 'text/html; charset=utf-8')
       	]

       	start_response(status, response_headers)
       	return ( r.encode('utf-8') for r in response_body )

       CGIHandler().run(app)