A recursive function has many definitions but at it’s core all it means is that it’s a function which calls itself over and over again and usually is stopped when a certain condition is met. A great example of this is when you need to find a factorial of a number. As a factorial of a number is the number multiplied by one less than the number, further multiplied by one less than the number thus formed and so on until you reach 1, e.g. 4! = 4 x 3 x 2 x 1 = 24. There are many ways to do so in php programming and one of them is by recursion.

 

But, in this log I’m not going to explain recursive functions using the factorial example, since you can find it on any other site. In-fact I’m going to share a scenario where this recursive function helped to reduce a lot of work for me and my team mate Naveen Sharma.

 

The requirement:

So, we were given a task to add a snippet of code on the top of all the files in a folder and it’s sub-folder and their files. And not only that, we also had to replace some content (old URL) with a new one. Now sure, you could search and replace the URL in any IDE like Notepad ++, but adding something like say a Doctype Declaration in all the HTML files of the folder was somewhat complicated for Notepad ++. To be honest even if Notepad ++ can perform such action we were/are unaware of the process. So, our solution, write a function which would iterate through all the folders and their files, and, add and replace the content accordingly. The easiest way to do so was undoubtedly using a recursion method.

 

The code:

The first thing to do is to create an HTML form where we could input the folder name which would be the master folder having all the sub-folders and files. Apparently, we could also input multiple folders by providing their names separated by a comma ‘,’.  This matched our requirements but you are free to experiment and alter is as per your needs. The code for the form is as below:


<!DOCTYPE html>
<html>
<head>
	<title>Recursive operation</title>
</head>

<body>


<form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="post">
  Directory name(s):
  <textarea name="dir_name" value=""></textarea>
  

  You can add multiple directory names separated by a comma.
  

  <input type="submit" value="Submit">
  


</form>


</body>

</html>

The form will post to itself and the php code will go below it.

Now, to be safe we were performing this operation locally, but if you are daring enough you can perform this directly on yiur server, assuming you have given the appropriate folder and file permissions like 755 or 777. Also, if you need to perform this in the root folder of your application/site, you might need to alter the code a bit to exclude this php file and also, you would need to give the path using the magic constant __DIR__. You can learn more about http://php.net/manual/en/language.constants.predefined.php

 

So now the form processing:

 

if($_POST && isset($_POST['dir_name'])){
	
	//To make an array of all the directory names posted
	$tmpArr = explode(',', trim($_POST['dir_name']));
	
	foreach($tmpArr as $val){
		$src = trim($val);
		if(is_dir($src)){ //to check if directory exists
			$dirExist = true;
			recursive_func($src, $dirExist); //Call the recursive function for each input folder given
			echo '


';
		}else{
			$dirExist = false;
			$dirError[] = 'No Directory found with the name: '.$src;
		}
		
	}
}

The above code will run only when $_POST is encountered and the dir_name is set. If multiple names are posted, separated by a comma, the explode function will covert this string of folder names into an array. All these names would act as a master folder for the recursive function to iterate through. The is_dir function will check if the folder/directory exists, if not, the folder name will be given in an error string printed at the end of the webpage.

 

And now the main recursive function:


function recursive_func($src, $dirExist = false) { 

	$dir = opendir($src);
	
	while( $dirExist && ( $file = readdir($dir)) !==  false) { 
			if (( $file != '.' ) && ( $file != '..' )) {
					$extn = explode('.',$file);
					$extn = array_pop($extn); //to get the value of the last key i.e. the extension
					$includedExtensions = array('htm','html');
					$excludedExtensions = array('php');
					if( is_dir($src ) && in_array(strtolower($extn),$includedExtensions ) && !in_array(strtolower($extn),$excludedExtensions )) { 

						$file_data	=	"Content to prepend at the top of every file\n";

						$file_data .= file_get_contents($src.'/'.$file);
						
						$file_put_data	=	str_ireplace('Specify the value to find','Specifies the value to replace the found value',$file_data);
						if(file_put_contents($src.'/'.$file, $file_put_data)) {
							echo "
".$src.'/'.$file;
						}else{
							echo "
Fail: ".$src.'/'.$file;
						}	

					}elseif( is_dir($src . '/' . $file )) { 
						recursive_func($src . '/' . $file, $dirExist);

					}
			}
		} 

}


 

The function recursive_func takes two parameters, first being the master folder or the source folder name and second being the state of the folder existing or not, the default being not, in case it’s not provided.
The opendir function, as the name suggests, will open a directory and read its contents. If path is not a valid directory or the directory can not be opened due to permission restrictions or filesystem errors, opendir() returns FALSE and generates a PHP error of level E_WARNING. You can suppress the error output of opendir() by prepending ‘@’ to the front of the function name.
Now, using the while loop we’ll check if the directory exists and if we’re able to read it’s content using the readdir() function. If so, we’ll leave out the ‘.’ and ‘..’ directories and proceed with all the other content. Now we’ll handle if the current source is a file or not. If it’s a file, first we’ll need to find the extension of the file to modify, so to decide whether to include or exclude it from our operation. Since we were only required to modify HTML files, we included .htm and .html files and excluded .php files. To do so we used the function in_array() to validate that only the required files are processed.
Next we initiated a variable $file_data and assigned it the string of content that we wanted to prepend as it’s value. The current file being read was then appended to this by getting all it contents using the function file_get_contents() which returns the file in a string. Next we initiated a variable which will hold the value given by the str_ireplace() function, which function replaces some characters with some other characters in a string. The str_ireplace() function is case insensitive and takes three parameters, the first being the value to find, Second being the value to replace the found value, and third being the string to search in, which in our case is the $file_data variable. Once all the operations are done, we use the file_put_contents() function, which writes a string to a file. If we are successful the function will give us only the path and file name as output on the screen, else it’ll output ‘Fail:’ and the path to the file.
Now if the current source is a directory and not a file, we’ll move to the else condition and in this case we need to go to the whole process again. This is where recursion occurs and we call the function itself. The whole process continues until there’s no more directory left.
Lastly, as I mentioned in the beginning that if the source directory name given is not found we’ll out that error string printed at the end of the webpage. If the source directory is not found, it’s name would be set in the $dirError array variable, so we just need to print it out: The code to do so is as:

if(isset($dirError)){ foreach($dirError as $val){ echo $val.'
'; } }

That’s it.

You can download the script from the below link:

recfunc.zip

Make sure to extract it before use 🙂

 

I hope now you know how a recursive function can solve such tasks with ease. I’m sure there were many better alternatives to solve such problems. Comment below if you know any other method(s).

Happy coding.