<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;action=history&amp;feed=atom</id>
		<title>PHP Cookbook/Directories - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;action=history&amp;feed=atom"/>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;action=history"/>
		<updated>2013-05-20T18:39:26Z</updated>
		<subtitle>Revision history for this page on the wiki</subtitle>
		<generator>MediaWiki 1.11.0</generator>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=26205&amp;oldid=prev</id>
		<title>Newacct at 06:25, 11 August 2010</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=26205&amp;oldid=prev"/>
				<updated>2010-08-11T06:25:17Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 06:25, 11 August 2010&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 191:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 191:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;The mode element of the returned array contains the permissions expressed as a base 10 integer. This is confusing since permissions are usually either expressed symbolically (e.g., ''ls'''s &amp;lt;tt&amp;gt;-rw-r--r--&amp;lt;/tt&amp;gt; output) or as an octal integer (e.g., &amp;lt;tt&amp;gt;0644&amp;lt;/tt&amp;gt;). To convert the permissions to a more understandable format, use &amp;lt;tt&amp;gt;&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;base_convert&lt;/del&gt;( )&amp;lt;/tt&amp;gt; to change the permissions to octal:&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;The mode element of the returned array contains the permissions expressed as a base 10 integer. This is confusing since permissions are usually either expressed symbolically (e.g., ''ls'''s &amp;lt;tt&amp;gt;-rw-r--r--&amp;lt;/tt&amp;gt; output) or as an octal integer (e.g., &amp;lt;tt&amp;gt;0644&amp;lt;/tt&amp;gt;). To convert the permissions to a more understandable format, use &amp;lt;tt&amp;gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;decoct&lt;/ins&gt;( )&amp;lt;/tt&amp;gt; to change the permissions to octal:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; $file_info = stat('/tmp/session.txt');&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; $file_info = stat('/tmp/session.txt');&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; $permissions = &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;base_convert&lt;/del&gt;($file_info['mode']&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;,10,8&lt;/del&gt;);&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; $permissions = &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;decoct&lt;/ins&gt;($file_info['mode']);&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;This results in a six-digit octal number. For example, if ''ls'' displays the following about ''/tmp/session.txt'':&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;This results in a six-digit octal number. For example, if ''ls'' displays the following about ''/tmp/session.txt'':&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:7331:newid:26205 --&gt;
&lt;/table&gt;</summary>
		<author><name>Newacct</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=7331&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=7331&amp;oldid=prev"/>
				<updated>2008-03-07T13:36:04Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:36, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=3141&amp;oldid=prev</id>
		<title>Evanlenz: 1 revision(s)</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=3141&amp;oldid=prev"/>
				<updated>2008-03-06T22:30:16Z</updated>
		
		<summary type="html">&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:30, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Evanlenz</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=3140&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Directories&amp;diff=3140&amp;oldid=prev"/>
				<updated>2008-03-06T22:28:45Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{PHP Cookbook/TOC}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
A filesystem stores a lot of additional information about files aside from their actual contents. This information includes such particulars as the file's size, what directory it's in, and access permissions for the file. If you're working with files, you may also need to manipulate this metadata. PHP gives you a variety of functions to read and manipulate directories, directory entries, and file attributes. Like other file-related parts of PHP, the functions are similar to the C functions that accomplish the same tasks, with some simplifications.&lt;br /&gt;
&lt;br /&gt;
Files are organized with ''inodes'' . Each file (and other parts of the filesystem, such as directories, devices, and links) has its own inode. That inode contains a pointer to where the file's data blocks are as well as all the metadata about the file. The data blocks for a directory hold the names of the files in that directory and the inode of each file.&lt;br /&gt;
&lt;br /&gt;
PHP provides two ways to look in a directory to see what files it holds. The first way is to use &amp;lt;tt&amp;gt;opendir( )&amp;lt;/tt&amp;gt; to get a directory handle, &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt; to iterate through the files, and &amp;lt;tt&amp;gt;closedir( )&amp;lt;/tt&amp;gt; to close the directory handle:&lt;br /&gt;
&lt;br /&gt;
 $d = opendir('/usr/local/images') or die($php_errormsg);&lt;br /&gt;
 while (false !== ($f = readdir($d))) {&lt;br /&gt;
     // process file&lt;br /&gt;
 }&lt;br /&gt;
 closedir($d);&lt;br /&gt;
&lt;br /&gt;
The second method is to use the directory class. Instantiate the class with &amp;lt;tt&amp;gt;dir( )&amp;lt;/tt&amp;gt;, read each filename with the &amp;lt;tt&amp;gt;read( )&amp;lt;/tt&amp;gt; method, and close the directory with &amp;lt;tt&amp;gt;close( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 $d = dir('/usr/local/images') or die($php_errormsg);&lt;br /&gt;
 while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
     // process file&lt;br /&gt;
 }&lt;br /&gt;
 $d-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Directories#Processing All Files in a Directory Recursively|Recipe 19.8]] shows how to use &amp;lt;tt&amp;gt;opendir( )&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;dir( )&amp;lt;/tt&amp;gt; to process each file in a directory. Making new directories is covered in [[PHP Cookbook/Directories#Making New Directories|Recipe 19.11]] and removing directories in [[PHP Cookbook/Directories#Removing a Directory and Its Contents|Recipe 19.12]].&lt;br /&gt;
&lt;br /&gt;
The filesystem holds more than just files and directories. On Unix, it can also hold symbolic links. These are special files whose contents are a pointer to another file. You can delete the link without affecting the file it points to. To create a symbolic link, use &amp;lt;tt&amp;gt;symlink( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 symlink('/usr/local/images','/www/docroot/images') or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
This creates a symbolic link called ''images'' in ''/www/docroot'' that points to ''/usr/local/images''.&lt;br /&gt;
&lt;br /&gt;
To find information about a file, directory, or link you must examine its inode. The function &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; retrieves the metadata in an inode for you. [[PHP Cookbook/Directories#Getting File Information|Recipe 19.3]] discusses &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt;. PHP also has many functions that use &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; internally to give you a specific piece of information about a file. These are listed in [[PHP Cookbook/Directories#phpckbk-CHP-19-TABLE-1|Table 19-1]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-TABLE-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Table 19-1. File information functions'''&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Function name !! What file information does the function provide?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;file_exists( )&amp;lt;/tt&amp;gt; || Does the file exist?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;fileatime( )&amp;lt;/tt&amp;gt; || Last access time&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;filectime( )&amp;lt;/tt&amp;gt; || Last metadata change time&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;filegroup( )&amp;lt;/tt&amp;gt; || Group (numeric)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;fileinode( )&amp;lt;/tt&amp;gt; || Inode number&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;filemtime( )&amp;lt;/tt&amp;gt; || Last change time of contents&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;fileowner( )&amp;lt;/tt&amp;gt; || Owner (numeric)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;fileperms( )&amp;lt;/tt&amp;gt; || Permissions (decimal, numeric)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;filesize( )&amp;lt;/tt&amp;gt; || Size&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;filetype( )&amp;lt;/tt&amp;gt; || Type (fifo, char, dir, block, link, file, unknown)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;is_dir( )&amp;lt;/tt&amp;gt; || Is it a directory?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;is_executable( )&amp;lt;/tt&amp;gt; || Is it executable?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;is_file( )&amp;lt;/tt&amp;gt; || Is it a regular file?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;is_link( )&amp;lt;/tt&amp;gt; || Is it a symbolic link?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;is_readable( )&amp;lt;/tt&amp;gt; || Is it readable?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;is_writable( )&amp;lt;/tt&amp;gt; || Is it writeable?&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On Unix, the file permissions indicate what operations the file's owner, users in the file's group, and all users can perform on the file. The operations are reading, writing, and executing. For programs, executing means the ability to run the program; for directories, it's the ability to search through the directory and see the files in it.&lt;br /&gt;
&lt;br /&gt;
Unix permissions can also contain a setuid bit, a setgid bit, and a sticky bit. The setuid bit means that when a program is run, it runs with the user ID of its owner. The setgid bit means that a program runs with the group ID of its group. For a directory, the setgid bit means that new files in the directory are created by default in the same group as the directory. The sticky bit is useful for directories in which people share files because it prevents nonsuperusers with write permission in a directory from deleting files in that directory unless they own the file or the directory.&lt;br /&gt;
&lt;br /&gt;
When setting permissions with &amp;lt;tt&amp;gt;chmod( )&amp;lt;/tt&amp;gt; (see [[PHP Cookbook/Directories#Changing File Permissions or Ownership|Recipe 19.4]]), they must be expressed as an octal number. This number has four digits. The first digit is any special setting for the file (such as setuid or setgid). The second digit is the user permissions — what the file's owner can do. The third digit is the group permissions — what users in the file's group can do. The fourth digit is the world permissions — what all other users can do. To compute the appropriate value for each digit, add together the permissions you want for that digit using the values in [[PHP Cookbook/Directories#phpckbk-CHP-19-TABLE-2|Table 19-2]]. For example, a permission value of &amp;lt;tt&amp;gt;0644&amp;lt;/tt&amp;gt; means that there are no special settings (the &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;), the file's owner can read and write the file (the &amp;lt;tt&amp;gt;6&amp;lt;/tt&amp;gt;, which is &amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt; (read) + &amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; (write)), users in the file's group can read the file (the first &amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt;), and all other users can also read the file (the second &amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt;). A permission value of &amp;lt;tt&amp;gt;4644&amp;lt;/tt&amp;gt; is the same, except that the file is also setuid.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-TABLE-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Table 19-2. File permission values'''&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Value !! Permission meaning !! Special setting meaning&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Read || setuid&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Write || setgid&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Execute || sticky&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The permissions of newly created files and directories are affected by a setting called the ''umask'' , which is a permission value that is removed, or masked out, from the initial permissions of a file (&amp;lt;tt&amp;gt;0666&amp;lt;/tt&amp;gt; or directory (&amp;lt;tt&amp;gt;0777&amp;lt;/tt&amp;gt;). For example, if the umask is &amp;lt;tt&amp;gt;0022&amp;lt;/tt&amp;gt;, the default permissions for a new file created with &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;0644&amp;lt;/tt&amp;gt; and the default permissions for a new directory created with &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;0755&amp;lt;/tt&amp;gt;. You can get and set the umask with the function &amp;lt;tt&amp;gt;umask( )&amp;lt;/tt&amp;gt; . It returns the current umask and, if an argument is supplied to it, changes the umask to the value of that argument. For example, here's how to make the permissions on newly created files prevent anyone but the file's owner (and the superuser) from accessing the file:&lt;br /&gt;
&lt;br /&gt;
 $old_umask = umask(0077);&lt;br /&gt;
 touch('secret-file.txt');&lt;br /&gt;
 umask($old_umask);&lt;br /&gt;
&lt;br /&gt;
The first call to &amp;lt;tt&amp;gt;umask( )&amp;lt;/tt&amp;gt; masks out all permissions for group and world. After the file is created, the second call to &amp;lt;tt&amp;gt;umask( )&amp;lt;/tt&amp;gt; restores the umask to the previous setting. When PHP is run as a server module, it restores the umask to its default value at the end of each request. Like other permissions-related functions, &amp;lt;tt&amp;gt;umask( )&amp;lt;/tt&amp;gt; doesn't work on Windows.&lt;br /&gt;
&lt;br /&gt;
== Getting and Setting File Timestamps ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to know when a file was last accessed or changed, or you want to update a file's access or change time; for example, you want each page on your web site to display when it was last modified.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;fileatime( )&amp;lt;/tt&amp;gt; , &amp;lt;tt&amp;gt;filemtime( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;filectime( )&amp;lt;/tt&amp;gt; functions return the time of last access, modification, and metadata change of a file:&lt;br /&gt;
&lt;br /&gt;
 $last_access = fileatime('larry.php');&lt;br /&gt;
 $last_modification = filemtime('moe.php');&lt;br /&gt;
 $last_change = filectime('curly.php');&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt; function changes a file's modification time:&lt;br /&gt;
&lt;br /&gt;
 touch('shemp.php');          // set modification time to now&lt;br /&gt;
 touch('joe.php',$timestamp); // set modification time to $timestamp&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;fileatime( )&amp;lt;/tt&amp;gt; function returns the last time a file was opened for reading or writing. The &amp;lt;tt&amp;gt;filemtime( )&amp;lt;/tt&amp;gt; function returns the last time a file's contents were changed. The &amp;lt;tt&amp;gt;filectime( )&amp;lt;/tt&amp;gt; function returns the last time a file's contents or metadata (such as owner or permissions) were changed. Each function returns the time as an epoch timestamp.&lt;br /&gt;
&lt;br /&gt;
A file's modification time can be updated with &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt;. Without a second argument, &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt; sets the modification time to the current date and time. To set a file's modification time to a specific value, pass that value as an epoch timestamp to &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt; as a second argument.&lt;br /&gt;
&lt;br /&gt;
This code prints the time a page on your web site was last updated:&lt;br /&gt;
&lt;br /&gt;
 print &amp;quot;Last Modified: &amp;quot;.strftime('%c',filemtime($_SERVER['SCRIPT_FILENAME']));&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fileatime( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fileatime'', &amp;lt;tt&amp;gt;filemtime( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/filemtime'', and &amp;lt;tt&amp;gt;filectime( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/filectime''.&lt;br /&gt;
&lt;br /&gt;
== Getting File Information ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read a file's metadata; for example, permissions and ownership.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; , which returns an array of information about a file:&lt;br /&gt;
&lt;br /&gt;
 $info = stat('harpo.php');&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; returns an array with both numeric and string indexes with information about a file. The elements of this array are in [[PHP Cookbook/Directories#phpckbk-CHP-19-TABLE-3|Table 19-3]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-TABLE-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Table 19-3. Information returned by stat( )'''&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Numeric index !! String index !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;dev&amp;lt;/tt&amp;gt; || Device&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;ino&amp;lt;/tt&amp;gt; || Inode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; || Permissions&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;3&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;nlink&amp;lt;/tt&amp;gt; || Link count&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;uid&amp;lt;/tt&amp;gt; || Owner's user ID&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;5&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;gid&amp;lt;/tt&amp;gt; || Group's group ID&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;6&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;rdev&amp;lt;/tt&amp;gt; || Device type for inode devices (-1 on Windows)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;7&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; || Size (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;8&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;atime&amp;lt;/tt&amp;gt; || Last access time (epoch timestamp)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;9&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;mtime&amp;lt;/tt&amp;gt; || Last change time of contents (epoch timestamp)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;10&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;ctime&amp;lt;/tt&amp;gt; || Last change time of contents or metadata (epoch timestamp)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;11&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;blksize&amp;lt;/tt&amp;gt; || Block size for I/O (-1 on Windows)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;12&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;blocks&amp;lt;/tt&amp;gt; || Number of block allocated to this file&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The mode element of the returned array contains the permissions expressed as a base 10 integer. This is confusing since permissions are usually either expressed symbolically (e.g., ''ls'''s &amp;lt;tt&amp;gt;-rw-r--r--&amp;lt;/tt&amp;gt; output) or as an octal integer (e.g., &amp;lt;tt&amp;gt;0644&amp;lt;/tt&amp;gt;). To convert the permissions to a more understandable format, use &amp;lt;tt&amp;gt;base_convert( )&amp;lt;/tt&amp;gt; to change the permissions to octal:&lt;br /&gt;
&lt;br /&gt;
 $file_info = stat('/tmp/session.txt');&lt;br /&gt;
 $permissions = base_convert($file_info['mode'],10,8);&lt;br /&gt;
&lt;br /&gt;
This results in a six-digit octal number. For example, if ''ls'' displays the following about ''/tmp/session.txt'':&lt;br /&gt;
&lt;br /&gt;
 -rw-rw-r--    1 sklar    sklar          12 Oct 23 17:55 /tmp/session.txt&lt;br /&gt;
&lt;br /&gt;
Then &amp;lt;tt&amp;gt;$file_info['mode']&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;33204&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$permissions&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;100664&amp;lt;/tt&amp;gt;. The last three digits (&amp;lt;tt&amp;gt;664&amp;lt;/tt&amp;gt;) are the user (read and write), group (read and write), and other (read) permissions for the file. The third digit, &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, means that the file is not setuid or setgid. The leftmost &amp;lt;tt&amp;gt;10&amp;lt;/tt&amp;gt; means that the file is a regular file (and not a socket, symbolic link, or other special file).&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; returns an array with both numeric and string indexes, using &amp;lt;tt&amp;gt;foreach&amp;lt;/tt&amp;gt; to iterate through the returned array produces two copies of each value. Instead, use a &amp;lt;tt&amp;gt;for&amp;lt;/tt&amp;gt; loop from element 0 to element 12 of the returned array.&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; on a symbolic link returns information about the file the symbolic link points to. To get information about the symbolic link itself, use &amp;lt;tt&amp;gt;lstat( )&amp;lt;/tt&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
Similar to &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;fstat( )&amp;lt;/tt&amp;gt; , which takes a file handle (returned from &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt;) as an argument. You can use &amp;lt;tt&amp;gt;fstat( )&amp;lt;/tt&amp;gt; only on local files, however, not URLs passed to &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
PHP's &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; function uses the underlying ''stat(2)'' system call, which is expensive. To minimize overhead, PHP caches the result of calling ''stat(2)''. So, if you call &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; on a file, change its permissions, and call &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; on the same file again, you get the same results. To force PHP to reload the file's metadata, call &amp;lt;tt&amp;gt;clearstatcache( )&amp;lt;/tt&amp;gt; , which flushes PHP's cached information. PHP also uses this cache for the other functions that return file metadata: &amp;lt;tt&amp;gt;file_exists( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fileatime( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;filectime( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;filegroup( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fileinode( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;filemtime( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fileowner( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fileperms( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;filesize( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;filetype( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fstat( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;is_dir( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;is_executable( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;is_file( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;is_link( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;is_readable( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;is_writable( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;lstat( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;stat( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/stat'', &amp;lt;tt&amp;gt;lstat( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/lstat'', &amp;lt;tt&amp;gt;fstat( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fstat'', and &amp;lt;tt&amp;gt;clearstatcache( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/clearstatcache''.&lt;br /&gt;
&lt;br /&gt;
== Changing File Permissions or Ownership ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to change a file's permissions or ownership; for example, you want to prevent other users from being able to look at a file of sensitive data.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;chmod( )&amp;lt;/tt&amp;gt; to change the permissions of a file:&lt;br /&gt;
&lt;br /&gt;
 chmod('/home/user/secrets.txt',0400);&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;chown( )&amp;lt;/tt&amp;gt; to change a file's owner and &amp;lt;tt&amp;gt;chgrp( )&amp;lt;/tt&amp;gt; to change a file's group:&lt;br /&gt;
&lt;br /&gt;
 chown('/tmp/myfile.txt','sklar');           // specify user by name&lt;br /&gt;
 chgrp('/home/sklar/schedule.txt','soccer'); // specify group by name&lt;br /&gt;
 &lt;br /&gt;
 chown('/tmp/myfile.txt',5001);              // specify user by uid&lt;br /&gt;
 chgrp('/home/sklar/schedule.txt',102);      // specify group by gid&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The permissions passed to &amp;lt;tt&amp;gt;chmod( )&amp;lt;/tt&amp;gt; must be specified as an octal number.&lt;br /&gt;
&lt;br /&gt;
The superuser can change the permissions, owner, and group of any file. Other users are restricted. They can change only the permissions and group of files that they own, and can't change the owner at all. Nonsuperusers can also change only the group of a file to a group they belong to.&lt;br /&gt;
&lt;br /&gt;
The functions &amp;lt;tt&amp;gt;chmod( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;chgrp( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;chown( )&amp;lt;/tt&amp;gt; don't work on Windows.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;chmod( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/chmod'', &amp;lt;tt&amp;gt;chown( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/chown'', and &amp;lt;tt&amp;gt;chgrp( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/chgrp''.&lt;br /&gt;
&lt;br /&gt;
== Splitting a Filename into Its Component Parts ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to find a file's path and filename; for example, you want to create a file in the same directory as an existing file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;basename( )&amp;lt;/tt&amp;gt; to get the filename and &amp;lt;tt&amp;gt;dirname( )&amp;lt;/tt&amp;gt; to get the path:&lt;br /&gt;
&lt;br /&gt;
 $full_name = '/usr/local/php/php.ini';&lt;br /&gt;
 $base = basename($full_name);  // $base is php.ini&lt;br /&gt;
 $dir  = dirname($full_name);   // $dir is /usr/local/php&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;pathinfo( )&amp;lt;/tt&amp;gt; to get the directory name, base name, and extension in an associative array:&lt;br /&gt;
&lt;br /&gt;
 $info = pathinfo('/usr/local/php/php.ini');&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
To create a temporary file in the same directory as an existing file, use &amp;lt;tt&amp;gt;dirname( )&amp;lt;/tt&amp;gt; to find the directory, and pass that directory to &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 $dir = dirname($existing_file);&lt;br /&gt;
 $temp = tempnam($dir,'temp');&lt;br /&gt;
 $temp_fh = fopen($temp,'w');&lt;br /&gt;
&lt;br /&gt;
The elements in the associative array returned by &amp;lt;tt&amp;gt;pathinfo( )&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;dirname&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;basename&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;extension&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $info = pathinfo('/usr/local/php/php.ini');&lt;br /&gt;
 print_r($info);&lt;br /&gt;
 '''Array'''&lt;br /&gt;
                '''('''&lt;br /&gt;
                '''    [dirname] =&amp;gt; /usr/local/php'''&lt;br /&gt;
                '''    [basename] =&amp;gt; php.ini'''&lt;br /&gt;
                '''    [extension] =&amp;gt; ini'''&lt;br /&gt;
                ''')'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
You can also pass &amp;lt;tt&amp;gt;basename( )&amp;lt;/tt&amp;gt; an optional suffix to remove it from the filename. This sets &amp;lt;tt&amp;gt;$base&amp;lt;/tt&amp;gt; to ''php'':&lt;br /&gt;
&lt;br /&gt;
 $base = basename('/usr/local/php/php.ini','.ini');&lt;br /&gt;
&lt;br /&gt;
Using functions such as &amp;lt;tt&amp;gt;basename( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;dirname( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;pathinfo( )&amp;lt;/tt&amp;gt; is more portable than just separating a full filename on &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; because they use an operating-system appropriate separator. On Windows, these functions treat both &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;\&amp;lt;/tt&amp;gt; as file and directory separators. On other platforms, only &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; is used.&lt;br /&gt;
&lt;br /&gt;
There's no built-in PHP function to combine the parts produced by &amp;lt;tt&amp;gt;basename( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;dirname( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;pathinfo( )&amp;lt;/tt&amp;gt; back into a full filename. To do this you have to combine the parts with . and &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $dirname = '/usr/local/php';&lt;br /&gt;
 $basename = 'php';&lt;br /&gt;
 $extension = 'ini';&lt;br /&gt;
 &lt;br /&gt;
 $full_name = $dirname . '/' . $basename . '.' . $extension;&lt;br /&gt;
&lt;br /&gt;
You can pass a full filename produced like this to other PHP file functions on Windows, because PHP accepts &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; as a directory separator on Windows.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;basename( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/basename'', &amp;lt;tt&amp;gt;dirname( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/dirname'', and &amp;lt;tt&amp;gt;pathinfo( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/pathinfo''.&lt;br /&gt;
&lt;br /&gt;
== Deleting a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to delete a file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;unlink( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 unlink($file) or die (&amp;quot;can't delete $file: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;unlink( )&amp;lt;/tt&amp;gt; is only able to delete files that the user of the PHP process is able to delete. If you're having trouble getting &amp;lt;tt&amp;gt;unlink( )&amp;lt;/tt&amp;gt; to work, check the permissions on the file and how you're running PHP.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;unlink( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/unlink''.&lt;br /&gt;
&lt;br /&gt;
== Copying or Moving a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to copy or move a file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;copy( )&amp;lt;/tt&amp;gt; to copy a file:&lt;br /&gt;
&lt;br /&gt;
 copy($old,$new) or die(&amp;quot;couldn't copy $old to $new: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;rename( )&amp;lt;/tt&amp;gt; to move a file:&lt;br /&gt;
&lt;br /&gt;
 rename($old,$new) or die(&amp;quot;couldn't move $old to $new: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
On Unix, &amp;lt;tt&amp;gt;rename( )&amp;lt;/tt&amp;gt; can't move files across filesystems. To do so, copy the file to the new location and then delete the old file:&lt;br /&gt;
&lt;br /&gt;
 if (copy(&amp;quot;/tmp/code.c&amp;quot;,&amp;quot;/usr/local/src/code.c&amp;quot;)) {&lt;br /&gt;
   unlink(&amp;quot;/tmp/code.c&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If you have multiple files to copy or move, call &amp;lt;tt&amp;gt;copy( )&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;rename( )&amp;lt;/tt&amp;gt; in a loop. You can operate only on one file each time you call these functions.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;copy( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/copy'' and &amp;lt;tt&amp;gt;rename( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/rename''.&lt;br /&gt;
&lt;br /&gt;
== Processing All Files in a Directory Recursively ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to iterate over all files in a directory. For example, you want to create a &amp;lt;tt&amp;gt;select&amp;lt;/tt&amp;gt; box in a form that lists all the files in a directory.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Get a directory handle with &amp;lt;tt&amp;gt;opendir( )&amp;lt;/tt&amp;gt; and then retrieve each filename with &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $d = opendir('/tmp') or die($php_errormsg);&lt;br /&gt;
 while (false !== ($f = readdir($d))) {&lt;br /&gt;
     print &amp;quot;$f\n&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 closedir($d);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The code in the solution tests the return value of &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt; with the nonidentity operator (&amp;lt;tt&amp;gt;!==&amp;lt;/tt&amp;gt;) so that the code works properly with filenames that evaluate to &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;, such as a file named ''0''.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt; returns each entry in a directory, whether it is a file, directory, or something else (such as a link or a socket). This includes the metaentries &amp;quot;.&amp;quot; (current directory) and &amp;quot;..&amp;quot; (parent directory). To just return files, use the &amp;lt;tt&amp;gt;is_file( )&amp;lt;/tt&amp;gt; function as well:&lt;br /&gt;
&lt;br /&gt;
 print '&amp;lt;select name=&amp;quot;files&amp;quot;&amp;gt;';&lt;br /&gt;
 $d = opendir('/usr/local/upload') or die($php_errormsg);&lt;br /&gt;
 while (false !== ($f = readdir($d))) {&lt;br /&gt;
     if (is_file(&amp;quot;/usr/local/upload/$f&amp;quot;)) {&lt;br /&gt;
         print '&amp;lt;option&amp;gt; ' . $f . '&amp;lt;/option&amp;gt;';&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 closedir($d);&lt;br /&gt;
 print '&amp;lt;/select&amp;gt;';&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt; returns only the filename of each directory entry, not a full pathname, you have to prepend the directory name to &amp;lt;tt&amp;gt;$f&amp;lt;/tt&amp;gt; before you pass it to &amp;lt;tt&amp;gt;is_file( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
PHP also has an object-oriented interface to directory information. The &amp;lt;tt&amp;gt;dir( )&amp;lt;/tt&amp;gt; function returns an object on which you can call &amp;lt;tt&amp;gt;read( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;close( )&amp;lt;/tt&amp;gt; methods, which act like the &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;rewinddir( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;closedir( )&amp;lt;/tt&amp;gt; functions. There's also a &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; property that contains the full path of the opened directory.&lt;br /&gt;
&lt;br /&gt;
Here's how to iterate through files with the object-oriented interface:&lt;br /&gt;
&lt;br /&gt;
 print '&amp;lt;select name=&amp;quot;files&amp;quot;&amp;gt;';&lt;br /&gt;
 $d = dir('/usr/local/upload') or die($php_errormsg);&lt;br /&gt;
 while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
     if (is_file($d-&amp;gt;path.'/'.$f)) {&lt;br /&gt;
         print '&amp;lt;option&amp;gt; ' . $f . '&amp;lt;/option&amp;gt;';&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 $d-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;$d-&amp;gt;path&amp;lt;/tt&amp;gt; is ''/usr/local/upload''.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;opendir( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/opendir'', &amp;lt;tt&amp;gt;readdir( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/readdir'', and the directory class at ''http://www.php.net/class.dir''.&lt;br /&gt;
&lt;br /&gt;
== Getting a List of Filenames Matching a Pattern ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to find all filenames that match a pattern.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
If your pattern is a regular expression, read each file from the directory and test the name with &amp;lt;tt&amp;gt;preg_match( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 $d = dir('/tmp') or die($php_errormsg);&lt;br /&gt;
 while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
     // only match alphabetic names&lt;br /&gt;
     if (preg_match('/^[a-zA-Z]+$/',$f)) {&lt;br /&gt;
         print &amp;quot;$f\n&amp;quot;;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 $d-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
If your pattern is a shell glob (e.g., &amp;lt;tt&amp;gt;*.*&amp;lt;/tt&amp;gt;), use the backtick operator with ''ls'' (Unix) or ''dir'' (Windows) to get the matching filenames. For Unix:&lt;br /&gt;
&lt;br /&gt;
 $files = explode(&amp;quot;\n&amp;quot;,`ls -1 *.gif`);&lt;br /&gt;
 foreach ($files as $file) {&lt;br /&gt;
   print &amp;quot;$b\n&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
For Windows:&lt;br /&gt;
&lt;br /&gt;
 $files = explode(&amp;quot;\n&amp;quot;,`dir /b *.gif`);&lt;br /&gt;
 foreach ($files as $file) {&lt;br /&gt;
   print &amp;quot;$b\n&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Directories#Processing All Files in a Directory Recursively|Recipe 19.8]] details on iterating through each file in a directory; information about shell pattern matching is available at ''http://www.gnu.org/manual/bash/html_node/bashref_35.html''.&lt;br /&gt;
&lt;br /&gt;
== Processing All Files in a Directory ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to do something to all the files in a directory and in any subdirectories.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use the &amp;lt;tt&amp;gt;pc_process_dir( )&amp;lt;/tt&amp;gt; function, shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-1|Example 19-1]], which returns a list of all files in and beneath a given directory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-EX-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 19-1. pc_process_dir( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_process_dir($dir_name,$max_depth = 10,$depth = 0) {&lt;br /&gt;
     if ($depth &amp;gt;= $max_depth) {&lt;br /&gt;
         error_log(&amp;quot;Reached max depth $max_depth in $dir_name.&amp;quot;);&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     $subdirectories = array();&lt;br /&gt;
     $files = array();&lt;br /&gt;
     if (is_dir($dir_name) &amp;amp;&amp;amp; is_readable($dir_name)) {&lt;br /&gt;
         $d = dir($dir_name);&lt;br /&gt;
         while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
             // skip . and .. &lt;br /&gt;
             if (('.' == $f) || ('..' == $f)) {&lt;br /&gt;
                 continue;&lt;br /&gt;
             }&lt;br /&gt;
             if (is_dir(&amp;quot;$dir_name/$f&amp;quot;)) {&lt;br /&gt;
                 array_push($subdirectories,&amp;quot;$dir_name/$f&amp;quot;);&lt;br /&gt;
             } else {&lt;br /&gt;
                 array_push($files,&amp;quot;$dir_name/$f&amp;quot;);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         $d-&amp;gt;close();&lt;br /&gt;
         foreach ($subdirectories as $subdirectory) {&lt;br /&gt;
             $files = array_merge($files,pc_process_dir($subdirectory,$max_depth,$depth+1));&lt;br /&gt;
         }&lt;br /&gt;
     } &lt;br /&gt;
     return $files;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Here's an example: if ''/tmp'' contains the files ''a'' and ''b'', as well as the directory ''c'', and ''/tmp/c'' contains files ''d'' and ''e'', &amp;lt;tt&amp;gt;pc_process_dir('/tmp')&amp;lt;/tt&amp;gt; returns an array with elements ''/tmp/a'', ''/tmp/b'', ''/tmp/c/d'', and ''/tmp/c/e''. To perform an operation on each file, iterate through the array:&lt;br /&gt;
&lt;br /&gt;
 $files = pc_process_dir('/tmp');&lt;br /&gt;
 foreach ($files as $file) {&lt;br /&gt;
   print &amp;quot;$file was last accessed at &amp;quot;.strftime('%c',fileatime($file)).&amp;quot;\n&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Instead of returning an array of files, you can also write a function that processes them as it finds them. The &amp;lt;tt&amp;gt;pc_process_dir2( )&amp;lt;/tt&amp;gt; function, shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-2|Example 19-2]], does this by taking an additional argument, the name of the function to call on each file found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-EX-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 19-2. pc_process_dir2( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_process_dir2($dir_name,$func_name,$max_depth = 10,$depth = 0) {&lt;br /&gt;
     if ($depth &amp;gt;= $max_depth) {&lt;br /&gt;
         error_log(&amp;quot;Reached max depth $max_depth in $dir_name.&amp;quot;);&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     $subdirectories = array();&lt;br /&gt;
     $files = array();&lt;br /&gt;
     if (is_dir($dir_name) &amp;amp;&amp;amp; is_readable($dir_name)) {&lt;br /&gt;
         $d = dir($dir_name);&lt;br /&gt;
         while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
             // skip . and ..&lt;br /&gt;
             if (('.' == $f) || ('..' == $f)) {&lt;br /&gt;
                 continue;&lt;br /&gt;
             }&lt;br /&gt;
             if (is_dir(&amp;quot;$dir_name/$f&amp;quot;)) {&lt;br /&gt;
                 array_push($subdirectories,&amp;quot;$dir_name/$f&amp;quot;);&lt;br /&gt;
             } else {&lt;br /&gt;
                 $func_name(&amp;quot;$dir_name/$f&amp;quot;);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         $d-&amp;gt;close();&lt;br /&gt;
         foreach ($subdirectories as $subdirectory) {&lt;br /&gt;
             pc_process_dir2($subdirectory,$func_name,$max_depth,$depth+1);&lt;br /&gt;
         }&lt;br /&gt;
     } &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_process_dir2( )&amp;lt;/tt&amp;gt; function doesn't return a list of directories; instead, the function &amp;lt;tt&amp;gt;$func_name&amp;lt;/tt&amp;gt; is called with the file as its argument. Here's how to print out the last access times:&lt;br /&gt;
&lt;br /&gt;
 function printatime($file) {&lt;br /&gt;
     print &amp;quot;$file was last accessed at &amp;quot;.strftime('%c',fileatime($file)).&amp;quot;\n&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 pc_process_dir2('/tmp','printatime');&lt;br /&gt;
&lt;br /&gt;
Although the two functions produce the same results, the second version uses less memory because potentially large arrays of files aren't passed around.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_process_dir( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;pc_process_dir2( )&amp;lt;/tt&amp;gt; functions use a ''breadth-first search'' . In this type of search, the functions handle all the files in the current directory; then they recurse into each subdirectory. In a ''depth-first search'' , they recurse into a subdirectory as soon as the subdirectory is found, whether or not there are files remaining in the current directory. The breadth-first search is more memory efficient; each pointer to the current directory is closed (with &amp;lt;tt&amp;gt;$d-&amp;gt;close( )&amp;lt;/tt&amp;gt;) before the function recurses into subdirectories, so there's only one directory pointer open at a time.&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;tt&amp;gt;is_dir( )&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; when passed a symbolic link that points to a directory, both versions of the function follow symbolic links as they traverse down the directory tree. If you don't want to follow links, change the line:&lt;br /&gt;
&lt;br /&gt;
 if (is_dir(&amp;quot;$dir_name/$f&amp;quot;)) {&lt;br /&gt;
&lt;br /&gt;
to:&lt;br /&gt;
&lt;br /&gt;
 if (is_dir(&amp;quot;$dir_name/$f&amp;quot;) &amp;amp;&amp;amp; (! is_link(&amp;quot;$dir_name/$f&amp;quot;))) {&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Functions#Returning Failure|Recipe 6.10]] for a discussion of variable functions; documentation on &amp;lt;tt&amp;gt;is_dir( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/is-dir'' and &amp;lt;tt&amp;gt;is_link( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/is-link''.&lt;br /&gt;
&lt;br /&gt;
== Making New Directories ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to create a directory.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 mkdir('/tmp/apples',0777) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The second argument to &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; is the permission mode for the new directory, which must be an octal number. The current umask is taken away from this permission value to create the permissions for the new directory. So, if the current umask is &amp;lt;tt&amp;gt;0002&amp;lt;/tt&amp;gt;, calling &amp;lt;tt&amp;gt;mkdir('/tmp/apples',0777)&amp;lt;/tt&amp;gt; sets the permissions on the resulting directory to &amp;lt;tt&amp;gt;0775&amp;lt;/tt&amp;gt; (user and group can read, write, and execute; others can only read and execute).&lt;br /&gt;
&lt;br /&gt;
PHP's built-in &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; can make a directory only if its parent exists. For example, if ''/tmp/a'' doesn't exist, you can't create ''/tmp/a/b'' until ''/tmp/a'' is created. To create a directory and its parents, you have two choices: you can call your system's &amp;lt;tt&amp;gt;mkdir&amp;lt;/tt&amp;gt; program, or you can use the &amp;lt;tt&amp;gt;pc_mkdir_parents( )&amp;lt;/tt&amp;gt; function, shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-3|Example 19-3]]. To use your system's ''mkdir'' program, on Unix, use this:&lt;br /&gt;
&lt;br /&gt;
 system('/bin/mkdir -p '.escapeshellarg($directory));&lt;br /&gt;
&lt;br /&gt;
On Windows do:&lt;br /&gt;
&lt;br /&gt;
 system('mkdir '.escapeshellarg($directory));&lt;br /&gt;
&lt;br /&gt;
You can also use the &amp;lt;tt&amp;gt;pc_mkdir_parents( )&amp;lt;/tt&amp;gt; function shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-3|Example 19-3]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-EX-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 19-3. pc_mkdir_parents( )'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;function pc_mkdir_parents($d,$umask = 0777) {&lt;br /&gt;
    $dirs = array($d);&lt;br /&gt;
    $d = dirname($d);&lt;br /&gt;
    $last_dirname = '';&lt;br /&gt;
    while($last_dirname != $d) { &lt;br /&gt;
        array_unshift($dirs,$d);&lt;br /&gt;
        $last_dirname = $d;&lt;br /&gt;
        $d = dirname($d);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    foreach ($dirs as $dir) {&lt;br /&gt;
        if (! file_exists($dir)) {&lt;br /&gt;
            if (! mkdir($dir,$umask)) {&lt;br /&gt;
                error_log(&amp;quot;Can't make directory: $dir&amp;quot;);&lt;br /&gt;
                return false;&lt;br /&gt;
            }&lt;br /&gt;
        } elseif (! is_dir($dir)) {&lt;br /&gt;
            error_log(&amp;quot;$dir is not a directory&amp;quot;);&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return true;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 pc_mkdir_parents('/usr/local/upload/test',0777);&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/mkdir''; your system's ''mkdir'' documentation, such as the Unix ''mkdir(1)'' man page or the Windows ''mkdir /?'' help text.&lt;br /&gt;
&lt;br /&gt;
== Removing a Directory and Its Contents ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to remove a directory and all of its contents, including subdirectories and their contents.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
On Unix, use ''rm'':&lt;br /&gt;
&lt;br /&gt;
 $directory = escapeshellarg($directory);&lt;br /&gt;
 exec(&amp;quot;rm -rf $directory&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
On Windows, use ''rmdir'':&lt;br /&gt;
&lt;br /&gt;
 $directory = escapeshellarg($directory);&lt;br /&gt;
 exec(&amp;quot;rmdir /s /q $directory&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Removing files, obviously, can be dangerous. Be sure to escape &amp;lt;tt&amp;gt;$directory&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;escapeshellarg( )&amp;lt;/tt&amp;gt; so that you don't delete unintended files.&lt;br /&gt;
&lt;br /&gt;
Because PHP's built-in directory removal function, &amp;lt;tt&amp;gt;rmdir( )&amp;lt;/tt&amp;gt; , works only on empty directories, and &amp;lt;tt&amp;gt;unlink( )&amp;lt;/tt&amp;gt; can't accept shell wildcards, calling a system program is much easier than recursively looping through all files in a directory, removing them, and then removing each directory. If an external utility isn't available, however, you can modify the &amp;lt;tt&amp;gt;pc_process_dir( )&amp;lt;/tt&amp;gt; function from [[PHP Cookbook/Directories#Processing All Files in a Directory|Recipe 19.10]] to remove each subdirectory.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;rmdir( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/rmdir''; your system's ''rm'' or ''rmdir'' documentation, such as the Unix ''rm(1)'' manpage or the Windows ''rmdir /?'' help text.&lt;br /&gt;
&lt;br /&gt;
== Program: Web Server Directory Listing ==&lt;br /&gt;
&lt;br /&gt;
The ''web-ls.php'' program shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-4|Example 19-4]] provides a view of the files inside your web server's document root, formatted like the output of the Unix command ''ls''. Filenames are linked so that you can download each file, and directory names are linked so that you can browse in each directory, as shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-FIG-1|Figure 19-1]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-FIG-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 19-1. Web listing'''&lt;br /&gt;
&lt;br /&gt;
[[Image:PHP Cookbook_I_19_tt1117.png|Web listing]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Most lines in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-4|Example 19-4]] are devoted to building an easy-to-read representation of the file's permissions, but the guts of the program are in the &amp;lt;tt&amp;gt;while&amp;lt;/tt&amp;gt; loop at the end. The &amp;lt;tt&amp;gt;$d-&amp;gt;read( )&amp;lt;/tt&amp;gt; method gets the name of each file in the directory. Then, &amp;lt;tt&amp;gt;lstat( )&amp;lt;/tt&amp;gt; retrieves information about that file, and &amp;lt;tt&amp;gt;printf( )&amp;lt;/tt&amp;gt; prints out the formatted information about that file.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode_string( )&amp;lt;/tt&amp;gt; functions and the constants it uses turn the octal representation of a file's mode (e.g., &amp;lt;tt&amp;gt;35316&amp;lt;/tt&amp;gt;) into an easier-to-read string (e.g., &amp;lt;tt&amp;gt;-rwsrw-r--&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-EX-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 19-4. web-ls.php'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/* Bit masks for determining file permissions and type. The names and values&lt;br /&gt;
 * listed below are POSIX-compliant, individual systems may have their own &lt;br /&gt;
 * extensions.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
define('S_IFMT',0170000);   // mask for all types &lt;br /&gt;
define('S_IFSOCK',0140000); // type: socket &lt;br /&gt;
define('S_IFLNK',0120000);  // type: symbolic link &lt;br /&gt;
define('S_IFREG',0100000);  // type: regular file &lt;br /&gt;
define('S_IFBLK',0060000);  // type: block device &lt;br /&gt;
define('S_IFDIR',0040000);  // type: directory &lt;br /&gt;
define('S_IFCHR',0020000);  // type: character device &lt;br /&gt;
define('S_IFIFO',0010000);  // type: fifo &lt;br /&gt;
define('S_ISUID',0004000);  // set-uid bit &lt;br /&gt;
define('S_ISGID',0002000);  // set-gid bit &lt;br /&gt;
define('S_ISVTX',0001000);  // sticky bit &lt;br /&gt;
define('S_IRWXU',00700);    // mask for owner permissions &lt;br /&gt;
define('S_IRUSR',00400);    // owner: read permission &lt;br /&gt;
define('S_IWUSR',00200);    // owner: write permission &lt;br /&gt;
define('S_IXUSR',00100);    // owner: execute permission &lt;br /&gt;
define('S_IRWXG',00070);    // mask for group permissions &lt;br /&gt;
define('S_IRGRP',00040);    // group: read permission &lt;br /&gt;
define('S_IWGRP',00020);    // group: write permission &lt;br /&gt;
define('S_IXGRP',00010);    // group: execute permission &lt;br /&gt;
define('S_IRWXO',00007);    // mask for others permissions &lt;br /&gt;
define('S_IROTH',00004);    // others: read permission &lt;br /&gt;
define('S_IWOTH',00002);    // others: write permission &lt;br /&gt;
define('S_IXOTH',00001);    // others: execute permission &lt;br /&gt;
&lt;br /&gt;
/* mode_string() is a helper function that takes an octal mode and returns&lt;br /&gt;
 * a ten character string representing the file type and permissions that&lt;br /&gt;
 * correspond to the octal mode. This is a PHP version of the mode_string()&lt;br /&gt;
 * function in the GNU fileutils package.&lt;br /&gt;
 */&lt;br /&gt;
function mode_string($mode) {&lt;br /&gt;
  $s = array();&lt;br /&gt;
&lt;br /&gt;
 // set type letter &lt;br /&gt;
  if (($mode &amp;amp; S_IFMT) == S_IFBLK) {&lt;br /&gt;
    $s[0] = 'b';&lt;br /&gt;
  } elseif (($mode &amp;amp; S_IFMT) == S_IFCHR) {&lt;br /&gt;
    $s[0] = 'c';&lt;br /&gt;
  } elseif (($mode &amp;amp; S_IFMT) == S_IFDIR) {&lt;br /&gt;
    $s[0] = 'd';&lt;br /&gt;
  } elseif (($mode &amp;amp; S_IFMT) ==  S_IFREG) {&lt;br /&gt;
    $s[0] = '-';&lt;br /&gt;
  } elseif (($mode &amp;amp; S_IFMT) ==  S_IFIFO) {&lt;br /&gt;
    $s[0] = 'p';&lt;br /&gt;
  } elseif (($mode &amp;amp; S_IFMT) == S_IFLNK) {&lt;br /&gt;
    $s[0] = 'l';&lt;br /&gt;
  } elseif (($mode &amp;amp; S_IFMT) == S_IFSOCK) {&lt;br /&gt;
    $s[0] = 's';&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // set user permissions &lt;br /&gt;
  $s[1] = $mode &amp;amp; S_IRUSR ? 'r' : '-';&lt;br /&gt;
  $s[2] = $mode &amp;amp; S_IWUSR ? 'w' : '-';&lt;br /&gt;
  $s[3] = $mode &amp;amp; S_IXUSR ? 'x' : '-';&lt;br /&gt;
&lt;br /&gt;
  // set group permissions &lt;br /&gt;
  $s[4] = $mode &amp;amp; S_IRGRP ? 'r' : '-';&lt;br /&gt;
  $s[5] = $mode &amp;amp; S_IWGRP ? 'w' : '-';&lt;br /&gt;
  $s[6] = $mode &amp;amp; S_IXGRP ? 'x' : '-';&lt;br /&gt;
&lt;br /&gt;
  // set other permissions &lt;br /&gt;
  $s[7] = $mode &amp;amp; S_IROTH ? 'r' : '-';&lt;br /&gt;
  $s[8] = $mode &amp;amp; S_IWOTH ? 'w' : '-';&lt;br /&gt;
  $s[9] = $mode &amp;amp; S_IXOTH ? 'x' : '-';&lt;br /&gt;
&lt;br /&gt;
  // adjust execute letters for set-uid, set-gid, and sticky &lt;br /&gt;
  if ($mode &amp;amp; S_ISUID) {&lt;br /&gt;
    if ($s[3] != 'x') {&lt;br /&gt;
      // set-uid but not executable by owner &lt;br /&gt;
      $s[3] = 'S';&lt;br /&gt;
    } else {&lt;br /&gt;
      $s[3] = 's';&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ($mode &amp;amp; S_ISGID) {&lt;br /&gt;
    if ($s[6] != 'x') {&lt;br /&gt;
      // set-gid but not executable by group &lt;br /&gt;
      $s[6] = 'S';&lt;br /&gt;
    } else {&lt;br /&gt;
      $s[6] = 's';&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ($mode &amp;amp; S_ISVTX) {&lt;br /&gt;
    if ($s[9] != 'x') {&lt;br /&gt;
      // sticky but not executable by others &lt;br /&gt;
      $s[9] = 'T';&lt;br /&gt;
    } else {&lt;br /&gt;
      $s[9] = 't';&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // return formatted string &lt;br /&gt;
  return join('',$s);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Start at the document root if not specified&lt;br /&gt;
if (isset($_REQUEST['dir'])) {&lt;br /&gt;
    $dir = $_REQUEST['dir'];&lt;br /&gt;
} else {&lt;br /&gt;
    $dir = '';&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// locate $dir in the filesystem&lt;br /&gt;
$real_dir = realpath($_SERVER['DOCUMENT_ROOT'].$dir);&lt;br /&gt;
&lt;br /&gt;
// make sure $real_dir is inside document root&lt;br /&gt;
if (! preg_match('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/',&lt;br /&gt;
                 $real_dir)) {&lt;br /&gt;
    die(&amp;quot;$dir is not inside the document root&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// canonicalize $dir by removing the document root from its beginning &lt;br /&gt;
$dir = substr_replace($real_dir,'',0,strlen($_SERVER['DOCUMENT_ROOT']));&lt;br /&gt;
&lt;br /&gt;
// are we opening a directory?&lt;br /&gt;
if (! is_dir($real_dir)) {&lt;br /&gt;
    die(&amp;quot;$real_dir is not a directory&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// open the specified directory &lt;br /&gt;
$d = dir($real_dir) or die(&amp;quot;can't open $real_dir: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
print '&amp;lt;table&amp;gt;';&lt;br /&gt;
&lt;br /&gt;
// read each entry in the directory &lt;br /&gt;
while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
&lt;br /&gt;
    // get information about this file &lt;br /&gt;
    $s = lstat($d-&amp;gt;path.'/'.$f);&lt;br /&gt;
    &lt;br /&gt;
    // translate uid into user name &lt;br /&gt;
    $user_info = posix_getpwuid($s['uid']);&lt;br /&gt;
&lt;br /&gt;
    // translate gid into group name &lt;br /&gt;
    $group_info = posix_getgrgid($s['gid']);&lt;br /&gt;
&lt;br /&gt;
    // format the date for readability &lt;br /&gt;
    $date = strftime('%b %e %H:%M',$s['mtime']);&lt;br /&gt;
&lt;br /&gt;
    // translate the octal mode into a readable string &lt;br /&gt;
    $mode = mode_string($s['mode']);&lt;br /&gt;
&lt;br /&gt;
    $mode_type = substr($mode,0,1);&lt;br /&gt;
    if (($mode_type == 'c') || ($mode_type == 'b')) {&lt;br /&gt;
        /* if it's a block or character device, print out the major and&lt;br /&gt;
         * minor device type instead of the file size */&lt;br /&gt;
        $major = ($s['rdev'] &amp;gt;&amp;gt; 8) &amp;amp; 0xff;&lt;br /&gt;
        $minor = $s['rdev'] &amp;amp; 0xff;&lt;br /&gt;
        $size = sprintf('%3u, %3u',$major,$minor);&lt;br /&gt;
    } else {&lt;br /&gt;
        $size = $s['size'];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // format the &amp;lt;a href=&amp;quot;&amp;quot;&amp;gt; around the filename&lt;br /&gt;
    // no link for the current directory&lt;br /&gt;
    if ('.' == $f) {&lt;br /&gt;
        $href = $f;&lt;br /&gt;
    } else {&lt;br /&gt;
        // don't include the &amp;quot;..&amp;quot; in the parent directory link&lt;br /&gt;
        if ('..' == $f) {&lt;br /&gt;
            $href = urlencode(dirname($dir));&lt;br /&gt;
        } else {&lt;br /&gt;
            $href = urlencode($dir) . '/' . urlencode($f);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        /* everything but &amp;quot;/&amp;quot; should be urlencoded */&lt;br /&gt;
        $href = str_replace('%2F','/',$href);&lt;br /&gt;
&lt;br /&gt;
        // browse other directories with web-ls&lt;br /&gt;
        if (is_dir(realpath($d-&amp;gt;path . '/' . $f))) {&lt;br /&gt;
            $href = sprintf('&amp;lt;a href=&amp;quot;%s?dir=%s&amp;quot;&amp;gt;%s&amp;lt;/a&amp;gt;',&lt;br /&gt;
                            $_SERVER['PHP_SELF'],$href,$f);&lt;br /&gt;
        } else {&lt;br /&gt;
            // link to files to download them&lt;br /&gt;
            $href= sprintf('&amp;lt;a href=&amp;quot;%s&amp;quot;&amp;gt;%s&amp;lt;/a&amp;gt;',$href,$f);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // if it's a link, show the link target, too&lt;br /&gt;
        if ('l' == $mode_type) {&lt;br /&gt;
            $href .= ' -&amp;amp;amp;gt; ' . readlink($d-&amp;gt;path.'/'.$f);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // print out the appropriate info for this file &lt;br /&gt;
    printf('&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;%s&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;%3u&amp;lt;/td&amp;gt;&amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;%s&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;%s&amp;lt;/td&amp;gt;&amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;%s&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;%s&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;%s&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;',&lt;br /&gt;
           $mode,                // formatted mode string &lt;br /&gt;
           $s['nlink'],          // number of links to this file &lt;br /&gt;
           $user_info['name'],   // owner's user name &lt;br /&gt;
           $group_info['name'],  // group name &lt;br /&gt;
           $size,                // file size (or device numbers) &lt;br /&gt;
           $date,                // last modified date and time &lt;br /&gt;
           $href);               // link to browse or download &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
print '&amp;lt;/table&amp;gt;';&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Program: Site Search ==&lt;br /&gt;
&lt;br /&gt;
You can use ''site-search.php'', shown in [[PHP Cookbook/Directories#phpckbk-CHP-19-EX-5|Example 19-5]], as a search engine for a small-to-medium size, file-based site.&lt;br /&gt;
&lt;br /&gt;
The program looks for a search term (in &amp;lt;tt&amp;gt;$_REQUEST['term']&amp;lt;/tt&amp;gt;) in all files within a specified set of directories under the document root. Those directories are set in &amp;lt;tt&amp;gt;$search_dirs&amp;lt;/tt&amp;gt;. It also recurses into subdirectories and follows symbolic links but keeps track of which files and directories it has seen so that it doesn't get caught in an endless loop.&lt;br /&gt;
&lt;br /&gt;
If any pages are found that contain the search term, it prints list of links to those pages, alphabetically ordered by each page's title. If a page doesn't have a title (between the &amp;lt;tt&amp;gt;&amp;lt;title&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;lt;/title&amp;gt;&amp;lt;/tt&amp;gt; tags), the page's relative URI from the document root is used.&lt;br /&gt;
&lt;br /&gt;
The program looks for the search term between the &amp;lt;tt&amp;gt;&amp;lt;body&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/tt&amp;gt; tags in each file. If you have a lot of text in your pages inside &amp;lt;tt&amp;gt;&amp;lt;body&amp;gt;&amp;lt;/tt&amp;gt; tags that you want to exclude from the search, surround the text that should be searched with specific HTML comments and then modify &amp;lt;tt&amp;gt;$body_regex&amp;lt;/tt&amp;gt; to look for those tags instead. Say, for example, if your page looks like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;body&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Some HTML for menus, headers, etc.&lt;br /&gt;
 &lt;br /&gt;
 &amp;amp;lt;!-- search-start --&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;amp;lt;h1&amp;gt;Aliens Invade Earth&amp;amp;lt;/h1&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;amp;lt;h3&amp;gt;by H.G. Wells&amp;amp;lt;/h3&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;amp;lt;p&amp;gt;Aliens invaded earth today. Uh Oh.&amp;amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // More of the story&lt;br /&gt;
 &lt;br /&gt;
 &amp;amp;lt;!-- search-end --&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Some HTML for footers, etc.&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;/body&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To match the search term against just the title, author, and story inside the HTML comments, change &amp;lt;tt&amp;gt;$body_regex&amp;lt;/tt&amp;gt; to:&lt;br /&gt;
&lt;br /&gt;
 $body_regex = '#&amp;amp;lt;!-- search-start --&amp;gt;(.*' . preg_quote($_REQUEST['term'],'#'). &lt;br /&gt;
               '.*)&amp;amp;lt;!-- search-end --&amp;gt;#Sis';&lt;br /&gt;
&lt;br /&gt;
If you don't want the search term to match text that's inside HTML or PHP tags in your pages, add a call to &amp;lt;tt&amp;gt;strip_tags( )&amp;lt;/tt&amp;gt; to the code that loads the contents of the file for searching:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;// load the contents of the file into $file&lt;br /&gt;
$file = strip_tags(join('',file($path)));&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-19-EX-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 19-5. site-search.php'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;function pc_search_dir($dir) { &lt;br /&gt;
    global $body_regex,$title_regex,$seen;&lt;br /&gt;
&lt;br /&gt;
    // array to hold pages that match&lt;br /&gt;
    $pages = array();&lt;br /&gt;
&lt;br /&gt;
    // array to hold directories to recurse into&lt;br /&gt;
    $dirs = array();&lt;br /&gt;
&lt;br /&gt;
    // mark this directory as seen so we don't look in it again&lt;br /&gt;
    $seen[realpath($dir)] = true;&lt;br /&gt;
    &lt;br /&gt;
    // if we can get a directory handle for this directory&lt;br /&gt;
    if (is_readable($dir) &amp;amp;&amp;amp; ($d = dir($dir))) {&lt;br /&gt;
        // get each file name in the directory&lt;br /&gt;
        while (false !== ($f = $d-&amp;gt;read())) {&lt;br /&gt;
            // build the full path of the file&lt;br /&gt;
            $path = $d-&amp;gt;path.'/'.$f;&lt;br /&gt;
            // if it's a regular file and we can read it&lt;br /&gt;
            if (is_file($path) &amp;amp;&amp;amp; is_readable($path)) {&lt;br /&gt;
                &lt;br /&gt;
                $realpath = realpath($path);&lt;br /&gt;
                // if we've seen this file already,&lt;br /&gt;
                if ($seen[$realpath]) {&lt;br /&gt;
                    // then skip it&lt;br /&gt;
                    continue;&lt;br /&gt;
                } else {&lt;br /&gt;
                    // otherwise, mark it as seen so we skip it&lt;br /&gt;
                    // if we come to it again&lt;br /&gt;
                    $seen[$realpath] = true;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                // load the contents of the file into $file&lt;br /&gt;
                $file = join('',file($path));&lt;br /&gt;
&lt;br /&gt;
                // if the search term is inside the body delimiters&lt;br /&gt;
                if (preg_match($body_regex,$file)) {&lt;br /&gt;
&lt;br /&gt;
                    // construct the relative URI of the file by removing&lt;br /&gt;
                    // the document root from the full path&lt;br /&gt;
                    $uri = substr_replace($path,'',0,strlen($_SERVER['DOCUMENT_ROOT']));&lt;br /&gt;
&lt;br /&gt;
                    // If the page has a title, find it&lt;br /&gt;
                    if (preg_match('#&amp;lt;title&amp;gt;(.*?)&amp;lt;/title&amp;gt;#Sis',$file,$match)) {&lt;br /&gt;
                        // and add the title and URI to $pages&lt;br /&gt;
                        array_push($pages,array($uri,$match[1]));&lt;br /&gt;
                    } else {&lt;br /&gt;
                        // otherwise use the URI as the title&lt;br /&gt;
                        array_push($pages,array($uri,$uri));&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                // if the directory entry is a valid subdirectory&lt;br /&gt;
                if (is_dir($path) &amp;amp;&amp;amp; ('.' != $f) &amp;amp;&amp;amp; ('..' != $f)) {&lt;br /&gt;
                    // add it to the list of directories to recurse into&lt;br /&gt;
                    array_push($dirs,$path);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        $d-&amp;gt;close();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* look through each file in each subdirectory of this one, and add&lt;br /&gt;
       the matching pages in those directories to $pages. only look in&lt;br /&gt;
       a subdirectory if we haven't seen it yet.&lt;br /&gt;
    */&lt;br /&gt;
    foreach ($dirs as $subdir) {&lt;br /&gt;
        $realdir = realpath($subdir);&lt;br /&gt;
        if (! $seen[$realdir]) {&lt;br /&gt;
            $seen[$realdir] = true;&lt;br /&gt;
            $pages = array_merge($pages,pc_search_dir($subdir));&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return $pages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// helper function to sort matched pages alphabetically by title&lt;br /&gt;
function pc_page_sort($a,$b) {&lt;br /&gt;
    if ($a[1] == $b[1]) {&lt;br /&gt;
        return strcmp($a[0],$b[0]);&lt;br /&gt;
    } else {&lt;br /&gt;
        return ($a[1] &amp;gt; $b[1]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// array to hold the pages that match the search term&lt;br /&gt;
$matching_pages = array();&lt;br /&gt;
// array to hold pages seen while scanning for the search term&lt;br /&gt;
$seen = array();&lt;br /&gt;
// directories underneath the document root to search&lt;br /&gt;
$search_dirs = array('sports','movies','food');&lt;br /&gt;
// regular expression to use in searching files. The &amp;quot;S&amp;quot; pattern&lt;br /&gt;
// modifier tells the PCRE engine to &amp;quot;study&amp;quot; the regex for greater&lt;br /&gt;
// efficiency.&lt;br /&gt;
$body_regex = '#&amp;lt;body&amp;gt;(.*' . preg_quote($_REQUEST['term'],'#'). &lt;br /&gt;
              '.*)&amp;lt;/body&amp;gt;#Sis';&lt;br /&gt;
&lt;br /&gt;
// add the files that match in each directory to $matching pages&lt;br /&gt;
foreach ($search_dirs as $dir) {&lt;br /&gt;
    $matching_pages = array_merge($matching_pages,&lt;br /&gt;
                                  pc_search_dir($_SERVER['DOCUMENT_ROOT'].'/'.$dir));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (count($matching_pages)) {&lt;br /&gt;
    // sort the matching pages by title&lt;br /&gt;
    usort($matching_pages,'pc_page_sort');&lt;br /&gt;
    print '&amp;lt;ul&amp;gt;';&lt;br /&gt;
    // print out each title with a link to the page&lt;br /&gt;
    foreach ($matching_pages as $k =&amp;gt; $v) {&lt;br /&gt;
        print sprintf('&amp;lt;li&amp;gt; &amp;lt;a href=&amp;quot;%s&amp;quot;&amp;gt;%s&amp;lt;/a&amp;gt;',$v[0],$v[1]);&lt;br /&gt;
    }&lt;br /&gt;
    print '&amp;lt;/ul&amp;gt;';&lt;br /&gt;
} else {&lt;br /&gt;
    print 'No pages found.';&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	</feed>