Search icon

This was actually an assignment given to me as part of an interview process some time back.

The brief was simple: to have an upload utility that allowed a search term to be specified and a text file to be uploaded, with the contents of the uploaded file then displayed in the browser with the search term highlighted.

My first pass is a pure PHP solution. Please note this is not production code and I would never push code like this!

<?php

/*
 * - check the Execute Permissions of the upload directory
 * 
 * - checking file extensions in code using MIME type, which has some drawbacks as it is browser dependant
 * - added optional ability to restrict file type by extension (.txt) which is easy to extend to other file types - this is more restrictive & therefore more secure
 * - check size of uploaded file
 * - would normally move successfully uploaded file to another location (outside the web directory)
 *
 */

// max file upload size to be used in script
define('FILE_SIZE_LIMIT', 20480);

	if (isset($_POST['submit']))
	{
		// initialise an empty array to hold errors
		$errArr = array();
		
		// check to see if the user wants the search to be case sensitive or not
		$caseSensitive = (isset($_POST['casesensitive']) && $_POST['casesensitive'] == 'on')?'on':'off';
		
		// check to see if the user wants to allow only .txt files, or other text files as well
		$txtOnly = (isset($_POST['txtonly'])&&$_POST['txtonly']=='on')?'on':'off';	
		
		// check for and get the search term
		if(isset($_POST['searchterm']) && $_POST['searchterm'] != '')
		{
			$searchTerm = $_POST['searchterm'];
		}
		else
		{
			$errArr[] = 'You did not enter a search term';	
		}
			
		 // checks for errors and checks that file is uploaded
		if ($_FILES['uploadedfile']['error'] == UPLOAD_ERR_OK && is_uploaded_file($_FILES['uploadedfile']['tmp_name']))
		{
			// check the file type - this gets the MIME type - not neccessarily the best way to check, esp. for image files!!
			$fileType = $_FILES['uploadedfile']['type'];
			
			 // array will make it easier to add other files types later if we want to (csv,htm,html,xml,css,rtf etc)
			 $allowedExtensions = array("txt");
	
			// get the file extension
			$fileext = strtolower(substr(strrchr($_FILES['uploadedfile']['name'],'.'),1));
			
			// checking the MIME type
			if ($fileType == "text/plain")
			{
					
				// explicitely checking file extensions and creating a list of "allowed" extensions offers most control / security
				if($txtOnly == 'on' && !in_array($fileext, $allowedExtensions))
				{
					$errArr[] = "Files with that extension ($fileext) are not allowed!";
				}
				// get the file size
				$fileSize = $_FILES['uploadedfile']['size'];
				
				// check file size
				if($fileSize > 0)
				{
						
					if($fileSize <= FILE_SIZE_LIMIT)
					{
						// read the contents of the file
						$content = file_get_contents($_FILES['uploadedfile']['tmp_name']);
						
						// allow for line-breaks
						$content = str_replace("\n", "<br />", $content);
						
						// we need to have some checks in place on this uploaded content - this would be a start
						$content = htmlentities($content, ENT_QUOTES);
						
						// count number of times search term occurs in content
						// check to see if the user selected case-sensitive or not
						if($caseSensitive == 'on')
						{
							$searchCount = substr_count($content, $searchTerm);
							
							// output the contents of the file with the search term highlighted
							// below line is "first-pass" which obviously doesn't work with case-sensitive
							// would naturally replace it later with the final solution - leaving it in place for now...
							$output = str_replace($searchTerm, '<span class="highlighted-result">'.$searchTerm.'</span>', $content);

						}
						else
						{
							$searchCount = substr_count(strtolower($content), strtolower($searchTerm));
							
							// below is final solution to case sensitive problem when replacing / highlighting text
							// output the contents of the file with the search term highlighted
							$output = preg_replace("|($searchTerm)|Ui", "<span class=\"highlighted-result\">$1</span>", $content);
						}
						
						$output = html_entity_decode($output);
					}
					else
					{
						$errArr[] = 'That file is too big!';
					}
					
				}
				else
				{
					$errArr[] = 'That file is empty!';	
				}
				
				$fileName = $_FILES['uploadedfile']['name'];

			}
			else
			{
				$errArr[] = 'That is not a text file!';	
			}			 
		}
		else
		{
			$errArr[] = 'No file selected or there was an error uploading you file!';	
		}
	}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Text file upload and Highlight utility</title>
<link rel="stylesheet" href="stylee.css" type="text/css" />
</head>
<body>
<h1>Text file upload and Highlight utility</h1>
<?php
	
	if(isset($errArr)) // the array is set
	{
		if(empty($errArr)) // the array is empty - there were no errors - output the search results
		{
			// give info about the search term
			echo '<h2>Your search term <span class="highlighted-result">'.$searchTerm.'</span> occurred '.$searchCount.' times</h2>';
			echo '<p>Search info:</p>';
			echo '<ul><li>Name: '.$fileName.'</li><li>Size: '.$fileSize.'</li><li>Case sensitive:'.$caseSensitive.'</li></ul>';
			echo '<div id="output">'.$output.'</div>';	
		}
		else
		{
			foreach($errArr as $msg) // there were errors - output them
			{
				echo '<p class="error">'.$msg.'</p>';	
			}
		}
	}
	
?>

<ol>
	<li>Select a text file</li>
	<li>Enter a search term</li>
	<li>Submit to see results</li>
</ol>
<form enctype="multipart/form-data" action="index.php" method="post">
<fieldset>	
	<legend>Upload text file:</legend>
	<p><label for="uploadedfile">File:</label><input type="file" name="uploadedfile" /> (limit <?php echo FILE_SIZE_LIMIT; ?>)</p>
	<p><label for="searchterm">Search term:</label><input type="text" name="searchterm" id="searchterm" /></p>
	<p><input type="checkbox" name="casesensitive" /> Case sensitive</p>
	<p><input type="checkbox" name="txtonly" /> .txt extension only</p>
	<p><input name="submit" type="submit" value="submit" /></p>
</fieldset>	
</form>
</body>
</html>

See the demo here…

By foxbeefly

PHP / MySQL Developer

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.