'); } $requested_flower_dname = $_GET['flower_dname']; /* * Only allow directories listed in flower_dirs.txt. * * This prevents directory traversal such as: * ../../some-directory * ../../../etc * * It also means the URL cannot select an arbitrary directory. */ $allowed_dirs = []; $dir_handle = fopen('flower_dirs.txt', 'r'); if ($dir_handle === false) { die('Could not open flower directory list
'); } while (fscanf($dir_handle, '%s', $dir_name)) { $allowed_dirs[] = $dir_name; } fclose($dir_handle); if (!in_array($requested_flower_dname, $allowed_dirs, true)) { die('Invalid flower directory
'); } $flower_dname = $requested_flower_dname; /* * Read the flower name. */ $handle = fopen($flower_dname . '/name.txt', 'r'); if ($handle === false) { die('Could not open flower name file
'); } $flower_name = trim(fread($handle, 256)); fclose($handle); /* * Escape the flower name whenever it is placed into HTML. */ $safe_flower_name = htmlspecialchars( $flower_name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); /* * Read the main text. */ $handle = fopen($flower_dname . '/main_text.txt', 'r'); if ($handle === false) { die('Could not open main text file
'); } $main_text = fread($handle, 100000); fclose($handle); /* * Read and parse locations.txt if it exists. */ $location_array = []; $location_file = $flower_dname . '/locations.txt'; if (file_exists($location_file)) { $handle = fopen($location_file, 'r'); if ($handle === false) { die('Could not open locations.txt
'); } $location_text = fread($handle, 100000); fclose($handle); /* * Parse: * * [place name] {description} */ $count = 0; while ( preg_match( '/\[([^\]]*)\]/', $location_text, $captured ) && $count < 1000 ) { $place_name = $captured[1]; $location_text = strstr( $location_text, '[' . $place_name . ']' ); if ( preg_match( '/\{([^}]*)\}/', $location_text, $captured ) ) { $description = $captured[1]; $location_text = strstr( $location_text, '{' . $description . '}' ); $location_array[$place_name] = $description; } $count++; } } /* * Read links.txt. */ $handle = fopen('links.txt', 'r'); if ($handle === false) { die('Could not open links.txt
'); } $link_text = fread($handle, 100000); fclose($handle); /* * Parse: * * [key text] {url} */ $link_array = []; $count = 0; while ( preg_match( '/\[([^\]]*)\]/', $link_text, $captured ) && $count < 1000 ) { $link_key = $captured[1]; $link_text = strstr( $link_text, '[' . $link_key . ']' ); if ( preg_match( '/\{([^}]*)\}/', $link_text, $captured ) ) { $link_url = trim($captured[1]); $link_text = strstr( $link_text, '{' . $link_url . '}' ); /* * Only permit normal web URLs. * * In particular, reject: * javascript: * data: * vbscript: * * and other dangerous schemes. */ $parsed_url = parse_url($link_url); if ( $parsed_url !== false && isset($parsed_url['scheme']) && in_array( strtolower($parsed_url['scheme']), ['http', 'https'], true ) ) { $link_array[strtolower($link_key)] = $link_url; } } $count++; } /* * Expand [[link keys]] in main_text. * * The link text is escaped. * The URL is escaped separately for the HTML attribute. */ while ( preg_match( '/\[\[([[:alnum:][:space:]_.\/,\-]*)\]\]/', $main_text, $captured ) ) { $original_tag = $captured[0]; $link_key = strtolower($captured[1]); if (array_key_exists($link_key, $link_array)) { $safe_link_text = htmlspecialchars( $captured[1], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); $safe_link_url = htmlspecialchars( $link_array[$link_key], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); $replacement = '' . $safe_link_text . ''; $main_text = str_replace( $original_tag, $replacement, $main_text ); } else { $safe_link_text = htmlspecialchars( $captured[1], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); $main_text = str_replace( $original_tag, $safe_link_text . ' UNMATCHED', $main_text ); } } /* * Main image. * * The filename is generated from the validated flower directory, * so encode it when putting it into HTML. */ $main_image_fname = $flower_dname . '/main_image.jpg'; $safe_main_image_fname = htmlspecialchars( $main_image_fname, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); ?>

<?php echo $safe_flower_name; ?>

'); } $i = 0; while (fscanf($handle, '%s', $cur_thumb_fname)) { /* * Only accept a filename, not a path. * * This prevents contents.txt from introducing: * ../ * directory/path */ if ( basename($cur_thumb_fname) === $cur_thumb_fname && $cur_thumb_fname !== '' ) { $thumb_fname[$i++] = $flower_dname . '/images_thumb/' . $cur_thumb_fname; } } fclose($handle); /* * Read large/display filenames. */ $display_fname = []; $handle = fopen( $flower_dname . '/images_large/contents.txt', 'r' ); if ($handle === false) { die('Could not open large image contents file
'); } $i = 0; while (fscanf($handle, '%s', $cur_display_fname)) { if ( basename($cur_display_fname) === $cur_display_fname && $cur_display_fname !== '' ) { $display_fname[$i++] = $flower_dname . '/images_large/' . $cur_display_fname; } } fclose($handle); /* * Generate thumbnail block. */ echo '

'; foreach ($thumb_fname as $i => $cur_thumb_fname) { /* * Make sure a corresponding large image exists. */ if (!isset($display_fname[$i])) { continue; } $cur_display_fname = $display_fname[$i]; /* * Encode URL parameters. */ $image_url = 'display_image.php?image_fname=' . rawurlencode($cur_display_fname) . '&image_title=' . rawurlencode($flower_name); /* * Escape the complete URL because it is going into href. */ $safe_image_url = htmlspecialchars( $image_url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); $safe_thumb_fname = htmlspecialchars( $cur_thumb_fname, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' ); echo ''; echo '' .
         $safe_flower_name . ''; echo ''; } echo '


'; ?>