<?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/Files&amp;action=history&amp;feed=atom</id>
		<title>PHP Cookbook/Files - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Files&amp;action=history&amp;feed=atom"/>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Files&amp;action=history"/>
		<updated>2013-05-22T00:01:22Z</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/Files&amp;diff=26188&amp;oldid=prev</id>
		<title>Newacct at 00:11, 3 June 2010</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Files&amp;diff=26188&amp;oldid=prev"/>
				<updated>2010-06-03T00:11:01Z</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 00:11, 3 June 2010&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 502:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 502:&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; $lines = file('guestbook.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; $lines = file('guestbook.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: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; for ($i = 0, $j = count($lines); $i &amp;lt;= 10; $i++) {&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; for ($i = 0, $j = count($lines); $i &amp;lt;= 10; $i++) {&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;     print $lines[$j - $i];&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;     print $lines[$j - $i &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;- 1&lt;/ins&gt;];&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;div&gt; }&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; }&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;!-- diff cache key wikicontent:diff:version:1.11a:oldid:7330:newid:26188 --&gt;
&lt;/table&gt;</summary>
		<author><name>Newacct</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=PHP_Cookbook/Files&amp;diff=7330&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/Files&amp;diff=7330&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/Files&amp;diff=3139&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/Files&amp;diff=3139&amp;oldid=prev"/>
				<updated>2008-03-06T22:30:15Z</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/Files&amp;diff=3138&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/Files&amp;diff=3138&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;
The input and output in a web application usually flow between browser, server, and database, but there are many circumstances in which files are involved too. Files are useful for retrieving remote web pages for local processing, storing data without a database, and saving information that other programs need access to. Plus, as PHP becomes a tool for more than just pumping out web pages, the file I/O functions are even more useful.&lt;br /&gt;
&lt;br /&gt;
PHP's interface for file I/O is similar to C's, although less complicated. The fundamental unit of identifying a file to read from or write to is a ''file handle'' . This handle identifies your connection to a specific file, and you use it for operations on the file. This chapter focuses on opening and closing files and manipulating file handles in PHP, as well as what you can do with the file contents once you've opened a file. [[PHP Cookbook/Directories|Chapter 19]] deals with directories and file metadata such as permissions.&lt;br /&gt;
&lt;br /&gt;
Opening ''/tmp/cookie-data'' and writing the contents of a specific cookie to the file looks like this:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('/tmp/cookie-data','w')      or die(&amp;quot;can't open file&amp;quot;);&lt;br /&gt;
 if (-1 == fwrite($fh,$_COOKIE['flavor'])) { die(&amp;quot;can't write data&amp;quot;); }&lt;br /&gt;
 fclose($fh)                              or die(&amp;quot;can't close file&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; returns a file handle if its attempt to open the file is successful. If it can't open the file (because of incorrect permissions, for example), it returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;. [[PHP Cookbook/Files#Creating or Opening a Local File|Section 18.2]] and [[PHP Cookbook/Files#Opening a Remote File|Section 18.4]] cover ways to open files.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt; writes the value of the &amp;lt;tt&amp;gt;flavor&amp;lt;/tt&amp;gt; cookie to the file handle. It returns the number of bytes written. If it can't write the string (not enough disk space, for example), it returns -1.&lt;br /&gt;
&lt;br /&gt;
Last, &amp;lt;tt&amp;gt;fclose( )&amp;lt;/tt&amp;gt; closes the file handle. This is done automatically at the end of a request, but it's a good idea to explicitly close all files you open anyway. It prevents problems using the code in a command-line context and frees up system resources. It also allows you to check the return code from &amp;lt;tt&amp;gt;fclose( )&amp;lt;/tt&amp;gt;. Buffered data might not be actually written to disk until &amp;lt;tt&amp;gt;fclose( )&amp;lt;/tt&amp;gt; is called, so it's here that &amp;quot;disk full&amp;quot; errors are sometimes reported.&lt;br /&gt;
&lt;br /&gt;
As with other processes, PHP must have the correct permissions to read from and write to a file. This is usually straightforward in a command-line context but can cause confusion when running scripts within a web server. Your web server (and consequently your PHP scripts) probably runs as a specific user dedicated to web serving (or perhaps as user &amp;lt;tt&amp;gt;nobody&amp;lt;/tt&amp;gt;). For good security reasons, this user often has restricted permissions on what files it can access. If your script is having trouble with a file operation, make sure the web server's user or group — not yours — has permission to perform that file operation. Some web serving setups may run your script as you, though, in which case you need to make sure that your scripts can't accidentally read or write personal files that aren't part of your web site.&lt;br /&gt;
&lt;br /&gt;
Because most file-handling functions just return &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; on error, you have to do some additional work to find more details about that error. When the &amp;lt;tt&amp;gt;track_errors&amp;lt;/tt&amp;gt; configuration directive is &amp;lt;tt&amp;gt;on&amp;lt;/tt&amp;gt;, each error message is put in the global variable &amp;lt;tt&amp;gt;$php_errormsg&amp;lt;/tt&amp;gt;. Including this variable as part of your error output makes debugging easier:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('/tmp/cookie-data','w')      or die(&amp;quot;can't open: $php_errormsg&amp;quot;);&lt;br /&gt;
 if (-1 == fwrite($fh,$_COOKIE['flavor'])) { die(&amp;quot;can't write: $php_errormsg&amp;quot;) };&lt;br /&gt;
 fclose($fh)                              or die(&amp;quot;can't close: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
If you don't have permission to write to the ''/tmp/cookie-data'', the example dies with this error output:&lt;br /&gt;
&lt;br /&gt;
 can't open: fopen(&amp;quot;/tmp/cookie-data&amp;quot;, &amp;quot;w&amp;quot;) - Permission denied&lt;br /&gt;
&lt;br /&gt;
There are differences in how files are treated by Windows and by Unix. To ensure your file access code works appropriately on Unix and Windows, take care to handle line-delimiter characters and pathnames correctly.&lt;br /&gt;
&lt;br /&gt;
A line delimiter on Windows is two characters: ASCII 13 (carriage return) followed by ASCII 10 ( linefeed or newline). On Unix, it's just ASCII 10. The typewriter-era names for these characters explain why you can get &amp;quot;stair-stepped&amp;quot; text when printing out a Unix-delimited file. Imagine these character names as commands to the platen in a typewriter or character-at-a-time printer. A carriage return sends the platen back to the beginning of the line it's on, and a line feed advances the paper by one line. A misconfigured printer encountering a Unix-delimited file dutifully follows instructions and does a linefeed at the end of each line. This advances to the next line but doesn't move the horizontal printing position back to the left margin. The next stair-stepped line of text begins (horizontally) where the previous line left off.&lt;br /&gt;
&lt;br /&gt;
PHP functions that use a newline as a line-ending delimiter (for example, &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt;) work on both Windows and Unix because a newline is the character at the end of the line on either platform.&lt;br /&gt;
&lt;br /&gt;
To remove any line-delimiter characters, use the PHP function &amp;lt;tt&amp;gt;rtrim( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('/tmp/lines-of-data.txt','r') or die($php_errormsg);&lt;br /&gt;
 while($s = fgets($fh,1024)) {&lt;br /&gt;
     $s = rtrim($s);&lt;br /&gt;
     // do something with $s ... &lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh)                               or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
This function removes any trailing whitespace in the line, including ASCII 13 and ASCII 10 (as well as tab and space). If there's whitespace at the end of a line that you want to preserve, but you still want to remove carriage returns and line feeds, use an appropriate regular expression:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;$fh = fopen('/tmp/lines-of-data.txt','r') or die($php_errormsg);&lt;br /&gt;
while($s = fgets($fh,1024)) {&lt;br /&gt;
    $s = preg_replace('/\r?\n$/','',$s);&lt;br /&gt;
    // do something with $s ... &lt;br /&gt;
}&lt;br /&gt;
fclose($fh)                               or die($php_errormsg);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unix and Windows also differ on the character used to separate directories in pathnames. Unix uses a slash &amp;lt;tt&amp;gt;(/),&amp;lt;/tt&amp;gt; and Windows uses a backslash (&amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;. PHP makes sorting this out easy, however, because the Windows version of PHP also understands &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; as a directory separator. For example, this code successfully prints the contents of ''C:\Alligator\Crocodile Menu.txt'':&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('c:/alligator/crocodile menu.txt','r') or die($php_errormsg);&lt;br /&gt;
 while($s = fgets($fh,1024)) {&lt;br /&gt;
     print $s;&lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh)                                        or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
This piece of code also takes advantage of the fact that Windows filenames aren't case-sensitive. However, Unix filenames are.&lt;br /&gt;
&lt;br /&gt;
Sorting out linebreak confusion isn't only a problem in your code that reads and writes files but in your source code as well. If you have multiple people working on a project, make sure all developers configure their editors to use the same kind of linebreaks.&lt;br /&gt;
&lt;br /&gt;
Once you've opened a file, PHP gives you many tools to process its data. In keeping with PHP's C-like I/O interface, the two basic functions to read data from a file are &amp;lt;tt&amp;gt;fread( )&amp;lt;/tt&amp;gt; , which reads a specified number of bytes, and &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt;, which reads a line at a time (up to a specified number of bytes.) This code handles lines up to 256 bytes long:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('orders.txt','r') or die($php_errormsg);&lt;br /&gt;
 while (! feof($fh)) {&lt;br /&gt;
     $s = fgets($fh,256);&lt;br /&gt;
     process_order($s);&lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
If ''orders.txt'' has a 300-byte line, &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; returns only the first 256 bytes. The next &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; returns the next 44 bytes and stops when it finds the newline. The next &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; moves to the next line of the file. Examples in this chapter generally give &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; a second argument of 1048576: 1 MB. This is longer than lines in most text files, but the presence of such an outlandish number should serve as a reminder to consider your maximum expected line length when using &amp;lt;tt&amp;gt;fgets()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Many operations on file contents, such as picking a line at random (see [[PHP Cookbook/Files#Picking a Random Line from a File|Section 18.11]]) are conceptually simpler (and require less code) if the entire file is read into a string or array. [[PHP Cookbook/Files#Reading a File into a String|Section 18.6]] provides a method for reading a file into a string, and the &amp;lt;tt&amp;gt;file( )&amp;lt;/tt&amp;gt; function puts each line of a file into an array. The tradeoff for simplicity, however, is memory consumption. This can be especially harmful when you are using PHP as a server module. Generally, when a process (such as a web server process with PHP embedded in it) allocates memory (as PHP does to read an entire file into a string or array), it can't return that memory to the operating system until it dies. This means that calling &amp;lt;tt&amp;gt;file( )&amp;lt;/tt&amp;gt; on a 1 MB file from PHP running as an Apache module increases the size of that Apache process by 1 MB until the process dies. Repeated a few times, this decreases server efficiency. There are certainly good reasons for processing an entire file at once, but be conscious of the memory-use implications when you do.&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Files#Escaping Shell Metacharacters|Section 18.21]] through [[PHP Cookbook/Files#Reading Standard Error from a Program|Section 18.24]] deal with running other programs from within a PHP program. Some program-execution operators or functions offer ways to run a program and read its output all at once (backticks) or read its last line of output (&amp;lt;tt&amp;gt;system( )&amp;lt;/tt&amp;gt;). PHP can use pipes to run a program, pass it input, or read its output. Because a pipe is read with standard I/O functions (&amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;fread( )&amp;lt;/tt&amp;gt;), you decide how you want the input and you can do other tasks between reading chunks of input. Similarly, writing to a pipe is done with &amp;lt;tt&amp;gt;fputs( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt;, so you can pass input to a program in arbitrary increments.&lt;br /&gt;
&lt;br /&gt;
Pipes have the same permission issues as regular files. The PHP process must have execute permission on the program being opened as a pipe. If you have trouble opening a pipe, especially if PHP is running as a special web server user, make sure the user is allowed to execute the program you are opening a pipe to.&lt;br /&gt;
&lt;br /&gt;
== Creating or Opening a Local File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to open a local file to read data from it or write data to it.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('file.txt','r') or die(&amp;quot;can't open file.txt: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The first argument to &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; is the file to open; the second argument is the mode to open the file in. The mode specifies what operations can be performed on the file (reading and/or writing), where the file pointer is placed after the file is opened (at the beginning or end of the file), whether the file is truncated to zero length after opening, and whether the file is created if it doesn't exist, as shown in [[PHP Cookbook/Files#phpckbk-CHP-18-TABLE-1|Table 18-1]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-18-TABLE-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Table 18-1. fopen( ) file modes'''&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Mode !! Readable? !! Writeable? !! File pointer !! Truncate? !! Create?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt; || Yes || No || Beginning || No || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;r+&amp;lt;/tt&amp;gt; || Yes || Yes || Beginning || No || No&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; || No || Yes || Beginning || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;w+&amp;lt;/tt&amp;gt; || Yes || Yes || Beginning || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;a&amp;lt;/tt&amp;gt; || No || Yes || End || No || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;a+&amp;lt;/tt&amp;gt; || Yes || Yes || End || No || Yes&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On non-POSIX systems, such as Windows, you need to add a &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; to the mode when opening a binary file, or reads and writes get tripped up on NUL (ASCII 0) characters:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('c:/images/logo.gif','rb');&lt;br /&gt;
&lt;br /&gt;
To operate on a file, pass the file handle returned from &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; to other I/O functions such as &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fputs( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;fclose( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the file given to &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; doesn't have a pathname, the file is opened in the directory of the running script (web context) or in the current directory (command-line context).&lt;br /&gt;
&lt;br /&gt;
You can also tell &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; to search for the file to open in the &amp;lt;tt&amp;gt;include_path&amp;lt;/tt&amp;gt; specified in your ''php.ini'' file by passing 1 as a third argument. For example, this searches for ''file.inc'' in the &amp;lt;tt&amp;gt;include_path&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('file.inc','r',1) or die(&amp;quot;can't open file.inc: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fopen''.&lt;br /&gt;
&lt;br /&gt;
== Creating a Temporary File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You need a file to temporarily hold some data.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;tmpfile( )&amp;lt;/tt&amp;gt; if the file needs to last only the duration of the running script:&lt;br /&gt;
&lt;br /&gt;
 $temp_fh = tmpfile();&lt;br /&gt;
 // write some data to the temp file&lt;br /&gt;
 fputs($temp_fh,&amp;quot;The current time is &amp;quot;.strftime('%c'));&lt;br /&gt;
 // the file goes away when the script ends&lt;br /&gt;
 exit(1);&lt;br /&gt;
&lt;br /&gt;
If the file needs to last longer, generate a filename with &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; , and then use &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 $tempfilename = tempnam('/tmp','data-');&lt;br /&gt;
 $temp_fh = fopen($tempfilename,'w') or die($php_errormsg);&lt;br /&gt;
 fputs($temp_fh,&amp;quot;The current time is &amp;quot;.strftime('%c'));&lt;br /&gt;
 fclose($temp_fh) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;tmpfile( )&amp;lt;/tt&amp;gt; creates a file with a unique name and returns a file handle. The file is removed when &amp;lt;tt&amp;gt;fclose( )&amp;lt;/tt&amp;gt; is called on that file handle, or the script ends.&lt;br /&gt;
&lt;br /&gt;
Alternatively, &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; generates a filename. It takes two arguments: the first is a directory, and the second is a prefix for the filename. If the directory doesn't exist or isn't writeable, &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; uses the system temporary directory — the &amp;lt;tt&amp;gt;TMPDIR&amp;lt;/tt&amp;gt; environment variable in Unix or the &amp;lt;tt&amp;gt;TMP&amp;lt;/tt&amp;gt; environment variable in Windows. For example:&lt;br /&gt;
&lt;br /&gt;
 $tempfilename = tempnam('/tmp','data-');&lt;br /&gt;
 print &amp;quot;Temporary data will be stored in $tempfilename&amp;quot;;&lt;br /&gt;
 '''Temporary data will be stored in /tmp/data-GawVoL'''&lt;br /&gt;
             &lt;br /&gt;
&lt;br /&gt;
Because of the way PHP generates temporary filenames, the filename &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; returns is actually created but left empty, even if your script never explicitly opens the file. This ensures another program won't create a file with the same name between the time that you call &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; and the time you call &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; with the filename.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;tmpfile( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/tmpfile'' and on &amp;lt;tt&amp;gt;tempnam( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/tempnam''.&lt;br /&gt;
&lt;br /&gt;
== Opening a Remote File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to open a file that's accessible to you via HTTP or FTP.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Pass the file's URL to &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;$fh = fopen('http://www.example.com/robots.txt','r') or die($php_errormsg);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; is passed a filename that begins with ''http://'', it retrieves the given page with an HTTP/1.0 GET request (although a &amp;lt;tt&amp;gt;Host&amp;lt;/tt&amp;gt;: header is also passed along to deal with virtual hosts). Only the body of the reply can be accessed using the file handle, not the headers. Files can be read, not written, via HTTP.&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; is passed a filename that begins with ''ftp://'', it returns a pointer to the specified file, obtained via passive mode FTP. You can open files via FTP for either reading or writing, but not both.&lt;br /&gt;
&lt;br /&gt;
To open URLs that require a username and a password with &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt;, embed the authentication information in the URL like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;$fh = fopen('ftp://username:password@ftp.example.com/pub/Index','r');&lt;br /&gt;
$fh = fopen('http://username:password@www.example.com/robots.txt','r');&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Opening remote files with &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; is implemented via a PHP feature called the ''URL fopen wrapper'' . It's enabled by default but is disabled by setting &amp;lt;tt&amp;gt;allow_url_fopen&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;off&amp;lt;/tt&amp;gt; in your ''php.ini'' or web server configuration file. If you can't open remote files with &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt;, check your server configuration.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Web Automation#Fetching a URL with the GET Method|Section 11.2]] through [[PHP Cookbook/Web Automation#Fetching an HTTPS URL|Section 11.6]], which discuss retrieving URLs; documentation on &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fopen'' and on the URL fopen wrapper feature at ''http://www.php.net/features.remote-files''.&lt;br /&gt;
&lt;br /&gt;
== Reading from Standard Input ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read from standard input.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; to open ''php://stdin'':&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('php://stdin','r') or die($php_errormsg);&lt;br /&gt;
 while($s = fgets($fh,1024)) {&lt;br /&gt;
     print &amp;quot;You typed: $s&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Client-Side PHP#Reading from the Keyboard|Section 20.4]] discusses reading data from the keyboard in a command-line context. Reading data from standard input isn't very useful in a web context, because information doesn't arrive via standard input. The bodies of HTTP POST and file-upload requests are parsed by PHP and put into special variables. They can't be read on standard input, as they can in some web server and CGI implementations.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Client-Side PHP#Reading from the Keyboard|Section 20.4]] for reading from the keyboard in a command-line context; documentation on &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fopen''.&lt;br /&gt;
&lt;br /&gt;
== Reading a File into a String ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to load the entire contents of a file into a variable. For example, you want to determine if the text in a file matches a regular expression.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;filesize( )&amp;lt;/tt&amp;gt; to get the size of the file, and then tell &amp;lt;tt&amp;gt;fread( )&amp;lt;/tt&amp;gt; to read that many bytes:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('people.txt','r') or die($php_errormsg);&lt;br /&gt;
 $people = fread($fh,filesize('people.txt'));&lt;br /&gt;
 if (preg_match('/Names:.*(David|Susannah)/i',$people)) {&lt;br /&gt;
     print &amp;quot;people.txt matches.&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
To read a binary file (e.g., an image) on Windows, a &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; must be appended to the file mode:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('people.jpg','rb') or die($php_errormsg);&lt;br /&gt;
 $people = fread($fh,filesize('people.jpg'));&lt;br /&gt;
 fclose($fh);&lt;br /&gt;
&lt;br /&gt;
There are easier ways to print the entire contents of a file than by reading it into a string and then printing the string. PHP provides two functions for this. The first is &amp;lt;tt&amp;gt;fpassthru($fh)&amp;lt;/tt&amp;gt; , which prints everything left on the file handle &amp;lt;tt&amp;gt;$fh&amp;lt;/tt&amp;gt; and then closes it. The second, &amp;lt;tt&amp;gt;readfile($filename)&amp;lt;/tt&amp;gt; , prints the entire contents of &amp;lt;tt&amp;gt;$filename&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;lt;tt&amp;gt;readfile( )&amp;lt;/tt&amp;gt; to implement a wrapper around images that shouldn't always be displayed. This program makes sure a requested image is less than a week old:&lt;br /&gt;
&lt;br /&gt;
 $image_directory = '/usr/local/images';&lt;br /&gt;
 &lt;br /&gt;
 if (preg_match('/^[a-zA-Z0-9]+\.(gif|jpeg)$/',$image,$matches) &amp;amp;&amp;amp;&lt;br /&gt;
     is_readable($image_directory.&amp;quot;/$image&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
     (filemtime($image_directory.&amp;quot;/$image&amp;quot;) &amp;gt;= (time() - 86400 * 7))) {&lt;br /&gt;
 &lt;br /&gt;
   header('Content-Type: image/'.$matches[1]);&lt;br /&gt;
   header('Content-Length: '.filesize($image_directory.&amp;quot;/$image&amp;quot;));&lt;br /&gt;
 &lt;br /&gt;
   readfile($image_directory.&amp;quot;/$image&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 } else {&lt;br /&gt;
   error_log(&amp;quot;Can't serve image: $image&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The directory in which the images are stored, &amp;lt;tt&amp;gt;$image_directory&amp;lt;/tt&amp;gt;, needs to be outside the web server's document root for the wrapper to be effective. Otherwise, users can just access the image files directly. You test the image for three things. First, that the filename passed in &amp;lt;tt&amp;gt;$image&amp;lt;/tt&amp;gt; is just alphanumeric with an ending of either ''.gif'' or ''.jpeg''. You need to ensure that characters such as .. or &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; are not in the filename; this prevents malicious users from retrieving files outside the specified directory. Second, use &amp;lt;tt&amp;gt;is_readable( )&amp;lt;/tt&amp;gt; to make sure you can read the file. Finally, get the file's modification time with &amp;lt;tt&amp;gt;filemtime( )&amp;lt;/tt&amp;gt; and make sure that time is after 86400 × 7 seconds ago. There are 86,400 seconds in a day, so 86400 × 7 is a week.&amp;lt;ref&amp;gt;When switching between standard time and daylight saving time, there are not 86,400 seconds in a day. See [[PHP Cookbook/Dates and Times#Adding to or Subtracting from a Date|Section 3.11]] for details.&amp;lt;/ref&amp;gt; If all of these conditions are met, you're ready to send the image. First, send two headers to tell the browser the image's MIME type and file size. Then use &amp;lt;tt&amp;gt;readfile( )&amp;lt;/tt&amp;gt; to send the entire contents of the file to the user.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;filesize( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/filesize'', &amp;lt;tt&amp;gt;fread( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fread'', &amp;lt;tt&amp;gt;fpassthru( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fpassthru'', and &amp;lt;tt&amp;gt;readfile( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/readfile''.&lt;br /&gt;
&lt;br /&gt;
== Counting Lines, Paragraphs, or Records in a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to count the number of lines, paragraphs, or records in a file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
To count lines, use &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; . Because it reads a line at a time, you can count the number of times it's called before reaching the end of a file:&lt;br /&gt;
&lt;br /&gt;
 $lines = 0;&lt;br /&gt;
 &lt;br /&gt;
 if ($fh = fopen('orders.txt','r')) {&lt;br /&gt;
   while (! feof($fh)) {&lt;br /&gt;
     if (fgets($fh,1048576)) {&lt;br /&gt;
       $lines++;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 print $lines;&lt;br /&gt;
&lt;br /&gt;
To count paragraphs, increment the counter only when you read a blank line:&lt;br /&gt;
&lt;br /&gt;
 $paragraphs = 0;&lt;br /&gt;
 &lt;br /&gt;
 if ($fh = fopen('great-american-novel.txt','r')) {&lt;br /&gt;
   while (! feof($fh)) {&lt;br /&gt;
     $s = fgets($fh,1048576);&lt;br /&gt;
     if ((&amp;quot;\n&amp;quot; == $s) || (&amp;quot;\r\n&amp;quot; == $s)) {&lt;br /&gt;
       $paragraphs++;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 print $paragraphs;&lt;br /&gt;
&lt;br /&gt;
To count records, increment the counter only when the line read contains just the record separator and whitespace:&lt;br /&gt;
&lt;br /&gt;
 $records = 0;&lt;br /&gt;
 $record_separator = '--end--';&lt;br /&gt;
 &lt;br /&gt;
 if ($fh = fopen('great-american-novel.txt','r')) {&lt;br /&gt;
   while (! feof($fh)) {&lt;br /&gt;
     $s = rtrim(fgets($fh,1048576));&lt;br /&gt;
     if ($s == $record_separator) {&lt;br /&gt;
       $records++;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 print $records;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
In the line counter, &amp;lt;tt&amp;gt;$lines&amp;lt;/tt&amp;gt; is incremented only if &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; returns a true value. As &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; moves through the file, it returns each line it retrieves. When it reaches the last line, it returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;, so &amp;lt;tt&amp;gt;$lines&amp;lt;/tt&amp;gt; doesn't get incorrectly incremented. Because EOF has been reached on the file, &amp;lt;tt&amp;gt;feof( )&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;, and the &amp;lt;tt&amp;gt;while&amp;lt;/tt&amp;gt; loop ends.&lt;br /&gt;
&lt;br /&gt;
This paragraph counter works fine on simple text but may produce unexpected results when presented with a long string of blank lines or a file without two consecutive linebreaks. These problems can be remedied with functions based on &amp;lt;tt&amp;gt;preg_split( )&amp;lt;/tt&amp;gt;. If the file is small and can be read into memory, use the &amp;lt;tt&amp;gt;pc_split_paragraphs( )&amp;lt;/tt&amp;gt; function shown in [[PHP Cookbook/Files#phpckbk-CHP-18-EX-1|Example 18-1]]. This function returns an array containing each paragraph in the file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-18-EX-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 18-1. pc_split_paragraphs( )'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;function pc_split_paragraphs($file,$rs=&amp;quot;\r?\n&amp;quot;) {&lt;br /&gt;
    $text = join('',file($file));&lt;br /&gt;
    $matches = preg_split(&amp;quot;/(.*?$rs)(?:$rs)+/s&amp;quot;,$text,-1,&lt;br /&gt;
                          PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);&lt;br /&gt;
    return $matches;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The contents of the file are broken on two or more consecutive newlines and returned in the &amp;lt;tt&amp;gt;$matches&amp;lt;/tt&amp;gt; array. The default record-separation regular expression, &amp;lt;tt&amp;gt;\r?\n&amp;lt;/tt&amp;gt;, matches both Windows and Unix linebreaks. If the file is too big to read into memory at once, use the &amp;lt;tt&amp;gt;pc_split_paragraphs_largefile( )&amp;lt;/tt&amp;gt; function shown in [[PHP Cookbook/Files#phpckbk-CHP-18-EX-2|Example 18-2]], which reads the file in 4K chunks.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-18-EX-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 18-2. pc_split_paragraphs_largefile( )'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;function pc_split_paragraphs_largefile($file,$rs=&amp;quot;\r?\n&amp;quot;) {&lt;br /&gt;
    global $php_errormsg;&lt;br /&gt;
&lt;br /&gt;
    $unmatched_text = '';&lt;br /&gt;
    $paragraphs = array();&lt;br /&gt;
&lt;br /&gt;
    $fh = fopen($file,'r') or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
    while(! feof($fh)) {&lt;br /&gt;
        $s = fread($fh,4096) or die($php_errormsg);&lt;br /&gt;
        $text_to_split = $unmatched_text . $s;&lt;br /&gt;
&lt;br /&gt;
        $matches = preg_split(&amp;quot;/(.*?$rs)(?:$rs)+/s&amp;quot;,$text_to_split,-1,&lt;br /&gt;
                              PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);&lt;br /&gt;
&lt;br /&gt;
        // if the last chunk doesn't end with two record separators, save it&lt;br /&gt;
         * to prepend to the next section that gets read &lt;br /&gt;
        $last_match = $matches[count($matches)-1];&lt;br /&gt;
        if (! preg_match(&amp;quot;/$rs$rs\$/&amp;quot;,$last_match)) {&lt;br /&gt;
            $unmatched_text = $last_match;&lt;br /&gt;
            array_pop($matches);&lt;br /&gt;
        } else {&lt;br /&gt;
            $unmatched_text = '';&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $paragraphs = array_merge($paragraphs,$matches);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // after reading all sections, if there is a final chunk that doesn't&lt;br /&gt;
     * end with the record separator, count it as a paragraph &lt;br /&gt;
    if ($unmatched_text) {&lt;br /&gt;
        $paragraphs[] = $unmatched_text;&lt;br /&gt;
    }&lt;br /&gt;
    return $paragraphs;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function uses the same regular expression as &amp;lt;tt&amp;gt;pc_split_paragraphs( )&amp;lt;/tt&amp;gt; to split the file into paragraphs. When it finds a paragraph end in a chunk read from the file, it saves the rest of the text in the chunk in &amp;lt;tt&amp;gt;$unmatched_text&amp;lt;/tt&amp;gt; and prepends it to the next chunk read. This includes the unmatched text as the beginning of the next paragraph in the file.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fgets'', on &amp;lt;tt&amp;gt;feof( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/feof'', and on &amp;lt;tt&amp;gt;preg_split( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/preg-split''.&lt;br /&gt;
&lt;br /&gt;
== Processing Every Word in a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to do something with every word in a file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Read in each line with &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt;, separate the line into words, and process each word:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('great-american-novel.txt','r') or die($php_errormsg);&lt;br /&gt;
 while (! feof($fh)) {&lt;br /&gt;
     if ($s = fgets($fh,1048576)) {&lt;br /&gt;
         $words = preg_split('/\s+/',$s,-1,PREG_SPLIT_NO_EMPTY);&lt;br /&gt;
         // process words&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Here's how to calculate average word length in a file:&lt;br /&gt;
&lt;br /&gt;
 $word_count = $word_length = 0;&lt;br /&gt;
 &lt;br /&gt;
 if ($fh = fopen('great-american-novel.txt','r')) {&lt;br /&gt;
   while (! feof($fh)) {&lt;br /&gt;
     if ($s = fgets($fh,1048576)) {&lt;br /&gt;
       $words = preg_split('/\s+/',$s,-1,PREG_SPLIT_NO_EMPTY);&lt;br /&gt;
       foreach ($words as $word) {&lt;br /&gt;
         $word_count++;&lt;br /&gt;
         $word_length += strlen($word);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 print sprintf(&amp;quot;The average word length over %d words is %.02f characters.&amp;quot;,&lt;br /&gt;
               $word_count,&lt;br /&gt;
               $word_length/$word_count);&lt;br /&gt;
&lt;br /&gt;
Processing every word proceeds differently depending on how &amp;quot;word&amp;quot; is defined. The code in this recipe uses the Perl-compatible regular-expression engine's &amp;lt;tt&amp;gt;\s&amp;lt;/tt&amp;gt; whitespace metacharacter, which includes space, tab, newline, carriage return, and formfeed. [[PHP Cookbook/Numbers#Generating Random Numbers Within a Range|Section 2.6]] breaks apart a line into words by splitting on a space, which is useful in that recipe because the words have to be rejoined with spaces. The Perl-compatible engine also has a word-boundary assertion (&amp;lt;tt&amp;gt;\b&amp;lt;/tt&amp;gt;) that matches between a word character (alphanumeric) and a nonword character (anything else). Using &amp;lt;tt&amp;gt;\b&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;\s&amp;lt;/tt&amp;gt; to delimit words most noticeably treats differently words with embedded punctuation. The term &amp;lt;tt&amp;gt;6&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;o'clock&amp;lt;/tt&amp;gt; is two words when split by whitespace (&amp;lt;tt&amp;gt;6&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;o'clock&amp;lt;/tt&amp;gt;); it's four words when split by word boundaries (&amp;lt;tt&amp;gt;6&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;o&amp;lt;/tt&amp;gt;, ', and &amp;lt;tt&amp;gt;clock&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Regular Expressions#Matching Words|Section 13.3]] discusses regular expressions to match words; [[PHP Cookbook/Strings#Reversing a String by Word or Character|Section 1.5]] for breaking apart a line by words; documentation on &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fgets'', on &amp;lt;tt&amp;gt;preg_split( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/preg-split'', and on the Perl-compatible regular expression extension at ''http://www.php.net/pcre''.&lt;br /&gt;
&lt;br /&gt;
== Reading a Particular Line in a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read a specific line in a file; for example, you want to read the most recent guestbook entry that's been added on to the end of a guestbook file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
If the file fits into memory, read the file into an array and then select the appropriate array element:&lt;br /&gt;
&lt;br /&gt;
 $lines = file('vacation-hotspots.txt');&lt;br /&gt;
 print $lines[2];&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
Because array indexes start at 0, &amp;lt;tt&amp;gt;$lines[2]&amp;lt;/tt&amp;gt; refers to the third line of the file.&lt;br /&gt;
&lt;br /&gt;
If the file is too big to read into an array, read it line by line and keep track of which line you're on:&lt;br /&gt;
&lt;br /&gt;
 $line_counter = 0;&lt;br /&gt;
 $desired_line = 29;&lt;br /&gt;
 &lt;br /&gt;
 $fh = fopen('vacation-hotspots.txt','r') or die($php_errormsg);&lt;br /&gt;
 while ((! feof($fh)) &amp;amp;&amp;amp; ($line_counter &amp;lt;= $desired_line)) {&lt;br /&gt;
     if ($s = fgets($fh,1048576)) {&lt;br /&gt;
         $line_counter++;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 print $s;&lt;br /&gt;
&lt;br /&gt;
Setting &amp;lt;tt&amp;gt;$desired_line&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;29&amp;lt;/tt&amp;gt; prints the 30th line of the file, to be consistent with the code in the Solution. To print the 29th line of the file, change the &amp;lt;tt&amp;gt;while&amp;lt;/tt&amp;gt; loop line to:&lt;br /&gt;
&lt;br /&gt;
 while ((! feof($fh)) &amp;amp;&amp;amp; ($line_counter &amp;lt; $desired_line)) {&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fgets'' and &amp;lt;tt&amp;gt;feof( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/feof''.&lt;br /&gt;
&lt;br /&gt;
== Processing a File Backward by Line or Paragraph ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to do something with each line of a file, starting at the end. For example, it's easy to add new guestbook entries to the end of a file by opening in append mode, but you want to display the entries with the most recent first, so you need to process the file starting at the end.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
If the file fits in memory, use &amp;lt;tt&amp;gt;file( )&amp;lt;/tt&amp;gt; to read each line in the file into an array and then reverse the array:&lt;br /&gt;
&lt;br /&gt;
 $lines = file('guestbook.txt');&lt;br /&gt;
 $lines = array_reverse($lines);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
You can also iterate through an unreversed array of lines starting at the end. Here's how to print out the last 10 lines in a file, last line first:&lt;br /&gt;
&lt;br /&gt;
 $lines = file('guestbook.txt');&lt;br /&gt;
 for ($i = 0, $j = count($lines); $i &amp;lt;= 10; $i++) {&lt;br /&gt;
     print $lines[$j - $i];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;file( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/file'' and &amp;lt;tt&amp;gt;array_reverse( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/array-reverse''.&lt;br /&gt;
&lt;br /&gt;
== Picking a Random Line from a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to pick a line at random from a file; for example, you want to display a selection from a file of sayings.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use the &amp;lt;tt&amp;gt;pc_randomint( )&amp;lt;/tt&amp;gt; function shown in [[PHP Cookbook/Files#phpckbk-CHP-18-EX-3|Example 18-3]], which spreads the selection odds evenly over all lines in a file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-18-EX-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 18-3. pc_randomint( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_randomint($max = 1) {&lt;br /&gt;
   $m = 1000000;&lt;br /&gt;
   return ((mt_rand(1,$m * $max)-1)/$m);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here's an example that uses the &amp;lt;tt&amp;gt;pc_randomint( )&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&lt;br /&gt;
 $line_number = 0;&lt;br /&gt;
 &lt;br /&gt;
 $fh = fopen('sayings.txt','r') or die($php_errormsg);&lt;br /&gt;
 while (! feof($fh)) {&lt;br /&gt;
     if ($s = fgets($fh,1048576)) {&lt;br /&gt;
         $line_number++;&lt;br /&gt;
         if (pc_randomint($line_number) &amp;lt; 1) {&lt;br /&gt;
             $line = $s;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_randomint( )&amp;lt;/tt&amp;gt; function computes a random decimal number between and &amp;lt;tt&amp;gt;$max&amp;lt;/tt&amp;gt;, including 0 but excluding &amp;lt;tt&amp;gt;$max&amp;lt;/tt&amp;gt;. As each line is read, a line counter is incremented, and &amp;lt;tt&amp;gt;pc_randomint( )&amp;lt;/tt&amp;gt; generates a random number between 0 and &amp;lt;tt&amp;gt;$line_number&amp;lt;/tt&amp;gt;. If the number is less than 1, the current line is selected as the randomly chosen line. After all lines have been read, the last line that was selected as the randomly chosen line is left in &amp;lt;tt&amp;gt;$line&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This algorithm neatly ensures that each line in an ''n'' line file has a &amp;lt;tt&amp;gt;1/&amp;lt;/tt&amp;gt; ''n'' chance of being chosen without having to store all ''n'' lines into memory.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;mt_rand( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/mt-rand''.&lt;br /&gt;
&lt;br /&gt;
== Randomizing All Lines in a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to randomly reorder all lines in a file. You have a file of funny quotes, for example, and you want to pick out one at random.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Read all the lines in the file into an array with &amp;lt;tt&amp;gt;file( )&amp;lt;/tt&amp;gt; , and then shuffle the elements of the array:&lt;br /&gt;
&lt;br /&gt;
 $lines = file('quotes-of-the-day.txt');&lt;br /&gt;
 $lines = pc_array_shuffle($lines);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;pc_array_shuffle( )&amp;lt;/tt&amp;gt; function from [[PHP Cookbook/Arrays#Randomizing an Array|Section 4.21]] is more random than PHP's built-in &amp;lt;tt&amp;gt;shuffle( )&amp;lt;/tt&amp;gt; function, because it uses the Fisher-Yates shuffle, which equally distributes the elements throughout the array.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Arrays#Sorting an Array Using a Method Instead of a Function|Section 4.20]] for &amp;lt;tt&amp;gt;pc_array_shuffle( )&amp;lt;/tt&amp;gt;; documentation on &amp;lt;tt&amp;gt;shuffle( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/shuffle''.&lt;br /&gt;
&lt;br /&gt;
== Processing Variable Length Text Fields ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read delimited text fields from a file. You might, for example, have a database program that prints records one per line, with tabs between each field in the record, and you want to parse this data into an array.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Read in each line and then split the fields based on their delimiter:&lt;br /&gt;
&lt;br /&gt;
 $delim = '|';&lt;br /&gt;
 &lt;br /&gt;
 $fh = fopen('books.txt','r') or die(&amp;quot;can't open: $php_errormsg&amp;quot;);&lt;br /&gt;
 while (! feof($fh)) {&lt;br /&gt;
     $s = rtrim(fgets($fh,1024));&lt;br /&gt;
     $fields = explode($delim,$s);&lt;br /&gt;
     // ... do something with the data ... &lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die(&amp;quot;can't close: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
To parse the following data in ''books.txt'':&lt;br /&gt;
&lt;br /&gt;
 Elmer Gantry|Sinclair Lewis|1927&lt;br /&gt;
 The Scarlatti Inheritance|Robert Ludlum|1971&lt;br /&gt;
 The Parsifal Mosaic|Robert Ludlum|1982&lt;br /&gt;
 Sophie's Choice|William Styron|1979&lt;br /&gt;
&lt;br /&gt;
Process each record like this:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('books.txt','r') or die(&amp;quot;can't open: $php_errormsg&amp;quot;);&lt;br /&gt;
 while (! feof($fh)) {&lt;br /&gt;
     $s = rtrim(fgets($fh,1024));&lt;br /&gt;
     list($title,$author,$publication_year) = explode('|',$s);&lt;br /&gt;
     // ... do something with the data ... &lt;br /&gt;
 }&lt;br /&gt;
 fclose($fh) or die(&amp;quot;can't close: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The line length argument to &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; needs to be at least as long as the longest record, so that a record doesn't get truncated.&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;tt&amp;gt;rtrim( )&amp;lt;/tt&amp;gt; is necessary because &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; includes the trailing whitespace in the line it reads. Without &amp;lt;tt&amp;gt;rtrim( )&amp;lt;/tt&amp;gt;, each &amp;lt;tt&amp;gt;$publication_year&amp;lt;/tt&amp;gt; would have a newline at its end.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Strings#Taking Strings Apart|Section 1.12]] discusses ways to break apart strings into pieces; [[PHP Cookbook/Strings#Parsing Comma-Separated Data|Section 1.10]] and [[PHP Cookbook/Strings#Parsing Fixed-Width Delimited Data|Section 1.11]] cover parsing comma-separated and fixed-width data; documentation on &amp;lt;tt&amp;gt;explode( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/explode'' and &amp;lt;tt&amp;gt;rtrim( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/rtrim''.&lt;br /&gt;
&lt;br /&gt;
== Reading Configuration Files ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to use configuration files to initialize settings in your programs.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $config = parse_ini_file('/etc/myapp.ini');&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt; reads configuration files structured like PHP's main ''php.ini'' file. Instead of applying the settings in the configuration file to PHP's configuration, however, &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt; returns the values from the file in an array.&lt;br /&gt;
&lt;br /&gt;
For example, when &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt; is given a file with these contents:&lt;br /&gt;
&lt;br /&gt;
 ; physical features&lt;br /&gt;
 eyes=brown&lt;br /&gt;
 hair=brown&lt;br /&gt;
 glasses=yes&lt;br /&gt;
 &lt;br /&gt;
 ; other features&lt;br /&gt;
 name=Susannah&lt;br /&gt;
 likes=monkeys,ice cream,reading&lt;br /&gt;
&lt;br /&gt;
The array it returns is:&lt;br /&gt;
&lt;br /&gt;
 Array&lt;br /&gt;
 (&lt;br /&gt;
     [eyes] =&amp;gt; brown&lt;br /&gt;
     [hair] =&amp;gt; brown&lt;br /&gt;
     [glasses] =&amp;gt; 1&lt;br /&gt;
     [name] =&amp;gt; Susannah&lt;br /&gt;
     [likes] =&amp;gt; monkeys,ice cream,reading&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
Blank lines and lines that begin with &amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; in the configuration file are ignored. Other lines with &amp;lt;tt&amp;gt;name=value&amp;lt;/tt&amp;gt; pairs are put into an array with the name as the key and the value, appropriately, as the value. Words such as &amp;lt;tt&amp;gt;on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;yes&amp;lt;/tt&amp;gt; as values are returned as 1, and words such as &amp;lt;tt&amp;gt;off&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;no&amp;lt;/tt&amp;gt; are returned as the empty string.&lt;br /&gt;
&lt;br /&gt;
To parse sections from the configuration file, pass &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; as a second argument to &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt; . Sections are set off by words in square brackets in the file:&lt;br /&gt;
&lt;br /&gt;
 [physical]&lt;br /&gt;
 eyes=brown&lt;br /&gt;
 hair=brown&lt;br /&gt;
 glasses=yes&lt;br /&gt;
 &lt;br /&gt;
 [other]&lt;br /&gt;
 name=Susannah&lt;br /&gt;
 likes=monkeys,ice cream,reading&lt;br /&gt;
&lt;br /&gt;
If this file is in ''/etc/myapp.ini'', then:&lt;br /&gt;
&lt;br /&gt;
 $conf = parse_ini_file('/etc/myapp.ini',1);&lt;br /&gt;
&lt;br /&gt;
Puts this array in &amp;lt;tt&amp;gt;$conf&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 Array&lt;br /&gt;
 (&lt;br /&gt;
     [physical] =&amp;gt; Array&lt;br /&gt;
         (&lt;br /&gt;
             [eyes] =&amp;gt; brown&lt;br /&gt;
             [hair] =&amp;gt; brown&lt;br /&gt;
             [glasses] =&amp;gt; 1&lt;br /&gt;
         )&lt;br /&gt;
 &lt;br /&gt;
     [other] =&amp;gt; Array&lt;br /&gt;
         (&lt;br /&gt;
             [name] =&amp;gt; Susannah&lt;br /&gt;
             [likes] =&amp;gt; monkeys,ice cream,reading&lt;br /&gt;
         )&lt;br /&gt;
 &lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
Your configuration file can also be a valid PHP file that you load with &amp;lt;tt&amp;gt;require&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt;. If the file ''config.php'' contains:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
 // physical features&lt;br /&gt;
 $eyes = 'brown';&lt;br /&gt;
 $hair = 'brown';&lt;br /&gt;
 $glasses = 'yes';&lt;br /&gt;
 &lt;br /&gt;
 // other features&lt;br /&gt;
 $name = 'Susannah';&lt;br /&gt;
 $likes = array('monkeys','ice cream','reading');&lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can set the variables &amp;lt;tt&amp;gt;$eyes&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$hair&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$glasses&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$name&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$likes&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&lt;br /&gt;
 require 'config.php';&lt;br /&gt;
&lt;br /&gt;
The configuration file loaded by &amp;lt;tt&amp;gt;require&amp;lt;/tt&amp;gt; needs to be valid PHP — including the &amp;lt;tt&amp;gt;&amp;lt;?php&amp;lt;/tt&amp;gt; start tag and the &amp;lt;tt&amp;gt;?&amp;gt;&amp;lt;/tt&amp;gt; end tag. The variables named in ''config.php'' are set explicitly, not inside an array, as in &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt;. For simple configuration files, this technique may not be worth the extra attention to syntax, but it is useful for embedding logic in the configuration file:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
 $time_of_day = (date('a') == 'am') ? 'early' : 'late';&lt;br /&gt;
 &lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ability to embed logic in configuration files is a good reason to make the files PHP code, but it is helpful also to have all the variables set in the configuration file inside an array. Upcoming versions of PHP will have a feature called ''namespaces'' , which is the ability to group variables hierarchically in different bunches; you can have a variable called &amp;lt;tt&amp;gt;$hair&amp;lt;/tt&amp;gt; in two different namespaces with two different values. With namespaces, all the values in a configuration file can be loaded into the &amp;lt;tt&amp;gt;Config&amp;lt;/tt&amp;gt; namespace so they don't interfere with other variables.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;parse_ini_file( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/parse-ini-file''; information about namespaces and other upcoming PHP language features is available at ''http://www.php.net/ZEND_CHANGES.txt''.&lt;br /&gt;
&lt;br /&gt;
== Reading from or Writing to a Specific Location in a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read from (or write to) a specific place in a file. For example, you want to replace the third record in a file of 80-byte records, so you have to write starting at the 161st byte.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; to move to a specific number of bytes after the beginning of the file, before the end of the file, or from the current position in the file:&lt;br /&gt;
&lt;br /&gt;
 fseek($fh,26);           // 26 bytes after the beginning of the file&lt;br /&gt;
 fseek($fh,26,SEEK_SET);  // 26 bytes after the beginning of the file&lt;br /&gt;
 fseek($fh,-39,SEEK_END); // 39 bytes before the end of the file&lt;br /&gt;
 fseek($fh,10,SEEK_CUR);  // 10 bytes ahead of the current position&lt;br /&gt;
 fseek($fh,0);            // beginning of the file&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; function moves to the beginning of a file:&lt;br /&gt;
&lt;br /&gt;
 rewind($fh);             // the same as fseek($fh,0)&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; returns 0 if it can move to the specified position, otherwise it returns -1. Seeking beyond the end of the file isn't an error for &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt;. Contrastingly, &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; returns 0 if it encounters an error.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; only with local files, not HTTP or FTP files opened with &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt;. If you pass a file handle of a remote file to &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt;, it throws an &amp;lt;tt&amp;gt;E_NOTICE&amp;lt;/tt&amp;gt; error.&lt;br /&gt;
&lt;br /&gt;
To get the current file position, use &amp;lt;tt&amp;gt;ftell( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 if (0 === ftell($fh)) {&lt;br /&gt;
   print &amp;quot;At the beginning of the file.&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;tt&amp;gt;ftell( )&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; on error, you need to use the &amp;lt;tt&amp;gt;===&amp;lt;/tt&amp;gt; operator to make sure that its return value is really the integer 0.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fseek'', &amp;lt;tt&amp;gt;ftell( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/ftell'', and &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/rewind''.&lt;br /&gt;
&lt;br /&gt;
== Removing the Last Line of a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to remove the last line of a file; for example, someone's added a comment to the end of your guestbook. You don't like it, so you want to get rid of it.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
If the file is small, you can read it into an array with &amp;lt;tt&amp;gt;file( )&amp;lt;/tt&amp;gt; and then remove the last element of the array:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;$lines = file('employees.txt');&lt;br /&gt;
array_pop($lines);&lt;br /&gt;
$file = join('',$lines);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
If the file is large, reading it into an array requires too much memory. Instead, use this code, which seeks to the end of the file and works backwards, stopping when it finds a newline:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;$fh = fopen('employees.txt','r') or die(&amp;quot;can't open: $php_errormsg&amp;quot;);&lt;br /&gt;
$linebreak = $beginning_of_file = 0;&lt;br /&gt;
&lt;br /&gt;
$gap = 80;&lt;br /&gt;
$filesize = filesize('employees.txt');&lt;br /&gt;
fseek($fh,0,SEEK_END);&lt;br /&gt;
&lt;br /&gt;
while (! ($linebreak || $beginning_of_file)) {&lt;br /&gt;
    // save where we are in the file &lt;br /&gt;
&lt;br /&gt;
    $pos = ftell($fh);&lt;br /&gt;
&lt;br /&gt;
    /* move back $gap chars, use rewind() to go to the beginning if&lt;br /&gt;
     * we're less than $gap characters into the file */ &lt;br /&gt;
    if ($pos &amp;lt; $gap) {&lt;br /&gt;
        rewind($fh);&lt;br /&gt;
    } else {&lt;br /&gt;
        fseek($fh,-$gap,SEEK_CUR);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // read the $gap chars we just seeked back over &lt;br /&gt;
    $s = fread($fh,$gap) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
    /* if we read to the end of the file, remove the last character&lt;br /&gt;
     * since if it's a newline, we should ignore it */&lt;br /&gt;
    if ($pos + $gap &amp;gt;= $filesize) {&lt;br /&gt;
        $s = substr_replace($s,'',-1);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // move back to where we were before we read $gap chars into $s &lt;br /&gt;
    if ($pos &amp;lt; $gap) {&lt;br /&gt;
        rewind($fh);&lt;br /&gt;
    } else {&lt;br /&gt;
        fseek($fh,-$gap,SEEK_CUR);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // is there a linebreak in $s ? &lt;br /&gt;
    if (is_integer($lb = strrpos($s,&amp;quot;\n&amp;quot;))) {&lt;br /&gt;
        $linebreak = 1;&lt;br /&gt;
        // the last line of the file begins right after the linebreak &lt;br /&gt;
        $line_end = ftell($fh) + $lb + 1;&lt;br /&gt;
    } &lt;br /&gt;
&lt;br /&gt;
    // break out of the loop if we're at the beginning of the file &lt;br /&gt;
    if (ftell($fh) == 0) { $beginning_of_file = 1; }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
if ($linebreak) {&lt;br /&gt;
    rewind($fh);&lt;br /&gt;
    $file_without_last_line = fread($fh,$line_end) or die($php_errormsg);&lt;br /&gt;
}&lt;br /&gt;
fclose($fh) or die(&amp;quot;can't close: $php_errormsg&amp;quot;);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code starts at the end of the file and moves backwards in &amp;lt;tt&amp;gt;$gap&amp;lt;/tt&amp;gt; character chunks looking for a newline. If it finds one, it knows the last line of the file starts right after that newline. This position is saved in &amp;lt;tt&amp;gt;$line_end&amp;lt;/tt&amp;gt;. After the &amp;lt;tt&amp;gt;while&amp;lt;/tt&amp;gt; loop, if &amp;lt;tt&amp;gt;$linebreak&amp;lt;/tt&amp;gt; is set, the contents of the file from the beginning to &amp;lt;tt&amp;gt;$line_end&amp;lt;/tt&amp;gt; are read into &amp;lt;tt&amp;gt;$file_without_last_line&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The last character of the file is ignored because if it's a newline, it doesn't indicate the start of the last line of the file. Consider the 10-character file whose contents are &amp;lt;tt&amp;gt;asparagus\n&amp;lt;/tt&amp;gt;. It has only one line, consisting of the word &amp;lt;tt&amp;gt;asparagus&amp;lt;/tt&amp;gt; and a newline character. This file without its last line is empty, which the previous code correctly produces. If it starts scanning with the last character, it sees the newline and exits its scanning loop, incorrectly printing out &amp;lt;tt&amp;gt;asparagus&amp;lt;/tt&amp;gt; without the newline.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Files#Reading from or Writing to a Specific Location in a File|Section 18.15]] discusses &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; in more detail; documentation on &amp;lt;tt&amp;gt;array_pop( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/array-pop'', &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fseek'', and &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/rewind''.&lt;br /&gt;
&lt;br /&gt;
== Modifying a File in Place Without a Temporary File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to change a file without using a temporary file to hold the changes.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Read the file into memory, make the changes, and rewrite the file. Open the file with mode &amp;lt;tt&amp;gt;r+&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;rb+&amp;lt;/tt&amp;gt;, if necessary, on Windows) and adjust its length with &amp;lt;tt&amp;gt;ftruncate( )&amp;lt;/tt&amp;gt; after writing out changes:&lt;br /&gt;
&lt;br /&gt;
 // open the file for reading and writing &lt;br /&gt;
 $fh = fopen('pickles.txt','r+')         or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // read the entire file into $s&lt;br /&gt;
 $s = fread($fh,filesize('pickles.txt')) or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // ... modify $s ...&lt;br /&gt;
 &lt;br /&gt;
 // seek back to the beginning of the file and write the new $s&lt;br /&gt;
 rewind($fh);&lt;br /&gt;
 if (-1 == fwrite($fh,$s))                { die($php_errormsg); }&lt;br /&gt;
 &lt;br /&gt;
 // adjust the file's length to just what's been written&lt;br /&gt;
 ftruncate($fh,ftell($fh))               or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // close the file&lt;br /&gt;
 fclose($fh)                             or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The following code turns text emphasized with asterisks or slashes into text with HTML &amp;lt;tt&amp;gt;&amp;amp;lt;b&amp;gt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;amp;lt;i&amp;gt;&amp;lt;/tt&amp;gt; tags:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('message.txt','r+')         or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // read the entire file into $s&lt;br /&gt;
 $s = fread($fh,filesize('message.txt')) or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // convert *word* to &amp;amp;lt;b&amp;gt;word&amp;amp;lt;/b&amp;gt;&lt;br /&gt;
 $s = preg_replace('@\*(.*?)\*@i','&amp;amp;lt;b&amp;gt;$1&amp;amp;lt;/b&amp;gt;',$s);&lt;br /&gt;
 // convert /word/ to &amp;amp;lt;i&amp;gt;word&amp;amp;lt;/i&amp;gt;&lt;br /&gt;
 $s = preg_replace('@/(.*?)/@i','&amp;amp;lt;i&amp;gt;$1&amp;amp;lt;/i&amp;gt;',$s);&lt;br /&gt;
 &lt;br /&gt;
 rewind($fh);&lt;br /&gt;
 if (-1 == fwrite($fh,$s))                { die($php_errormsg); }&lt;br /&gt;
 ftruncate($fh,ftell($fh))               or die($php_errormsg);&lt;br /&gt;
 fclose($fh)                             or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
Because adding HTML tags makes the file grow, the entire file has to be read into memory and then processed. If the changes to a file make each line shrink (or stay the same size), the file can be processed line by line, saving memory. This example converts text marked with &amp;lt;tt&amp;gt;&amp;amp;lt;b&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;amp;lt;i&amp;gt;&amp;lt;/tt&amp;gt; to text marked with asterisks and slashes:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('message.txt','r+')         or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // figure out how many bytes to read&lt;br /&gt;
 $bytes_to_read = filesize('message.txt');&lt;br /&gt;
 &lt;br /&gt;
 // initialize variables that hold file positions&lt;br /&gt;
 $next_read = $last_write = 0;&lt;br /&gt;
 &lt;br /&gt;
 // keep going while there are still bytes to read&lt;br /&gt;
 while ($next_read &amp;lt; $bytes_to_read) {&lt;br /&gt;
     &lt;br /&gt;
     /* move to the position of the next read, read a line, and save&lt;br /&gt;
      * the position of the next read */&lt;br /&gt;
     fseek($fh,$next_read);&lt;br /&gt;
     $s = fgets($fh,1048576)             or die($php_errormsg);&lt;br /&gt;
     $next_read = ftell($fh);&lt;br /&gt;
 &lt;br /&gt;
     // convert &amp;amp;lt;b&amp;gt;word&amp;amp;lt;/b&amp;gt; to *word*&lt;br /&gt;
     $s = preg_replace('@&amp;amp;lt;b[^&amp;gt;]*&amp;gt;(.*?)&amp;amp;lt;/b&amp;gt;@i','*$1*',$s);&lt;br /&gt;
     // convert &amp;amp;lt;i&amp;gt;word&amp;amp;lt;/i&amp;gt; to /word/ &lt;br /&gt;
     $s = preg_replace('@&amp;amp;lt;i[^&amp;gt;]*&amp;gt;(.*?)&amp;amp;lt;/i&amp;gt;@i','/$1/',$s);&lt;br /&gt;
 &lt;br /&gt;
     /* move to the position where the last write ended, write the&lt;br /&gt;
      * converted line, and save the position for the next write */&lt;br /&gt;
     fseek($fh,$last_write);&lt;br /&gt;
     if (-1 == fwrite($fh,$s))            { die($php_errormsg); }&lt;br /&gt;
     $last_write = ftell($fh);&lt;br /&gt;
 }&lt;br /&gt;
   &lt;br /&gt;
 // truncate the file length to what we've already written &lt;br /&gt;
 ftruncate($fh,$last_write)              or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // close the file&lt;br /&gt;
 fclose($fh)                             or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Web Automation#Converting ASCII to HTML|Section 11.10]] and [[PHP Cookbook/Web Automation#Converting HTML to ASCII|Section 11.11]] for additional information on converting between ASCII and HTML; [[PHP Cookbook/Files#Reading from or Writing to a Specific Location in a File|Section 18.15]] discusses &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; in more detail; documentation on &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fseek'', &amp;lt;tt&amp;gt;rewind( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/rewind'', and &amp;lt;tt&amp;gt;ftruncate( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/ftruncate''.&lt;br /&gt;
&lt;br /&gt;
== Flushing Output to a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to force all buffered data to be written to a filehandle.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;fflush( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 fwrite($fh,'There are twelve pumpkins in my house.');&lt;br /&gt;
 fflush($fh);&lt;br /&gt;
&lt;br /&gt;
This ensures that &amp;quot;&amp;lt;tt&amp;gt;There&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;are&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;twelve pumpkins in&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;my&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;house&amp;lt;/tt&amp;gt;.&amp;quot; is written to &amp;lt;tt&amp;gt;$fh&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
To be more efficient, system I/O libraries generally don't write something to a file when you tell them to. Instead, they batch the writes together in a buffer and save all of them to disk at the same time. Using &amp;lt;tt&amp;gt;fflush( )&amp;lt;/tt&amp;gt; forces anything pending in the write buffer to be actually written to disk.&lt;br /&gt;
&lt;br /&gt;
Flushing output can be particularly helpful when generating an access or activity log. Calling &amp;lt;tt&amp;gt;fflush( )&amp;lt;/tt&amp;gt; after each message to log file makes sure that any person or program monitoring the log file sees the message as soon as possible.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fflush( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fflush''.&lt;br /&gt;
&lt;br /&gt;
== Writing to Standard Output ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to write to standard output.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;print&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 print &amp;quot;Where did my pastrami sandwich go?&amp;quot;;&lt;br /&gt;
 echo  &amp;quot;It went into my stomach.&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
While &amp;lt;tt&amp;gt;print( )&amp;lt;/tt&amp;gt; is a function, &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; is a language construct. This means that &amp;lt;tt&amp;gt;print( )&amp;lt;/tt&amp;gt; returns a value, while &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; doesn't. You can include &amp;lt;tt&amp;gt;print( )&amp;lt;/tt&amp;gt; but not &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; in larger expressions:&lt;br /&gt;
&lt;br /&gt;
 // this is OK&lt;br /&gt;
 (12 == $status) ? print 'Status is good' : error_log('Problem with status!');&lt;br /&gt;
 &lt;br /&gt;
 // this gives a parse error&lt;br /&gt;
 (12 == $status) ? echo 'Status is good' : error_log('Problem with status!');&lt;br /&gt;
&lt;br /&gt;
Use ''php://stdout'' as the filename if you're using the file functions:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('php://stdout','w') or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
Writing to standard output via a file handle instead of simply with &amp;lt;tt&amp;gt;print( )&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; is useful if you need to abstract where your output goes, or if you need to print to standard output at the same time as writing to a file. See [[PHP Cookbook/Files#Writing to Many Filehandles Simultaneously|Section 18.20]] for details.&lt;br /&gt;
&lt;br /&gt;
You can also write to standard error by opening ''php://stderr'':&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('php://stderr','w');&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Files#Writing to Many Filehandles Simultaneously|Section 18.20]] for writing to many filehandles simultaneously; documentation on &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; at ''http://www.php.net/echo'' and on &amp;lt;tt&amp;gt;print( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/print''.&lt;br /&gt;
&lt;br /&gt;
== Writing to Many Filehandles Simultaneously ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to send output to more than one file handle; for example, you want to log messages to the screen and to a file.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Wrap your output with a loop that iterates through your filehandles, as shown in [[PHP Cookbook/Files#phpckbk-CHP-18-EX-4|Example 18-4]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-18-EX-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 18-4. pc_multi_fwrite( )'''&lt;br /&gt;
&lt;br /&gt;
 function pc_multi_fwrite($fhs,$s,$length=NULL) {&lt;br /&gt;
   if (is_array($fhs)) {&lt;br /&gt;
     if (is_null($length)) {&lt;br /&gt;
       foreach($fhs as $fh) {&lt;br /&gt;
         fwrite($fh,$s);&lt;br /&gt;
       }&lt;br /&gt;
     } else {&lt;br /&gt;
       foreach($fhs as $fh) {&lt;br /&gt;
         fwrite($fh,$s,$length);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here's an example:&lt;br /&gt;
&lt;br /&gt;
 $fhs['file'] = fopen('log.txt','w') or die($php_errormsg);&lt;br /&gt;
 $fhs['screen'] = fopen('php://stdout','w') or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 pc_multi_fwrite($fhs,'The space shuttle has landed.');&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
If you don't want to pass a length argument to &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt; (or you always want to), you can eliminate that check from your &amp;lt;tt&amp;gt;pc_multi_fwrite( )&amp;lt;/tt&amp;gt;. This version doesn't accept a &amp;lt;tt&amp;gt;$length&amp;lt;/tt&amp;gt; argument:&lt;br /&gt;
&lt;br /&gt;
 function pc_multi_fwrite($fhs,$s) {&lt;br /&gt;
   if (is_array($fhs)) {&lt;br /&gt;
     foreach($fhs as $fh) {&lt;br /&gt;
       fwrite($fh,$s);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/fwrite''.&lt;br /&gt;
&lt;br /&gt;
== Escaping Shell Metacharacters ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You need to incorporate external data in a command line, but you want to escape out special characters so nothing unexpected happens; for example, you want to pass user input as an argument to a program.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;escapeshellarg( )&amp;lt;/tt&amp;gt; to handle arguments:&lt;br /&gt;
&lt;br /&gt;
 system('ls -al '.escapeshellarg($directory));&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;escapeshellcmd( )&amp;lt;/tt&amp;gt; to handle program names:&lt;br /&gt;
&lt;br /&gt;
 system(escapeshellcmd($ls_program).' -al');&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The command line is a dangerous place for unescaped characters. Never pass unmodified user input to one of PHP's shell-execution functions. Always escape the appropriate characters in the command and the arguments. This is crucial. It is unusual to execute command lines that are coming from web forms and not something we recommend lightly. However, sometimes you need to run an external program, so escaping commands and arguments is useful.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;escapeshellarg( )&amp;lt;/tt&amp;gt; surrounds arguments with single quotes (and escapes any existing single quotes). To print the process status for a particular process:&lt;br /&gt;
&lt;br /&gt;
 system('/bin/ps '.escapeshellarg($process_id));&lt;br /&gt;
&lt;br /&gt;
Using &amp;lt;tt&amp;gt;escapeshellarg( )&amp;lt;/tt&amp;gt; ensures that the right process is displayed even if it has an unexpected character (e.g., a space) in it. It also prevents unintended commands from being run. If &amp;lt;tt&amp;gt;$process_id&amp;lt;/tt&amp;gt; contains:&lt;br /&gt;
&lt;br /&gt;
 1; rm -rf /&lt;br /&gt;
&lt;br /&gt;
then:&lt;br /&gt;
&lt;br /&gt;
 system(&amp;quot;/bin/ps $process_id&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
not only displays the status of process 1, but it also executes the command ''rm -rf /'' . However:&lt;br /&gt;
&lt;br /&gt;
 system('/bin/ps '.escapeshellarg($process_id)) &lt;br /&gt;
&lt;br /&gt;
runs the command ''/bin/ps 1; rm -rf'', which produces an error because &amp;quot;1-semicolon-space-rm-space-hyphen-rf&amp;quot; isn't a valid process ID.&lt;br /&gt;
&lt;br /&gt;
Similarly, &amp;lt;tt&amp;gt;escapeshellcmd( )&amp;lt;/tt&amp;gt; prevents unintended command lines from execution. This code runs a different program depending on the value of &amp;lt;tt&amp;gt;$which_program&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 system(&amp;quot;/usr/local/bin/formatter-$which_program&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
For example, if &amp;lt;tt&amp;gt;$which_program&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;pdf 12&amp;lt;/tt&amp;gt;, the script runs ''/usr/local/bin/formatter-pdf'' with an argument of &amp;lt;tt&amp;gt;12&amp;lt;/tt&amp;gt;. But, if &amp;lt;tt&amp;gt;$which_program&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;pdf 12; 56&amp;lt;/tt&amp;gt;, the script runs ''/usr/local/bin/formatter-pdf'' with an argument of &amp;lt;tt&amp;gt;12&amp;lt;/tt&amp;gt;, but then also runs the program ''56'', which is an error. To successfully pass the arguments to ''formatter-pdf'' , you need &amp;lt;tt&amp;gt;escapeshellcmd( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 system(escapeshellcmd(&amp;quot;/usr/local/bin/formatter-$which_program&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This runs ''/usr/local/bin/formatter-pdf'' and passes it two arguments: &amp;lt;tt&amp;gt;12;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;56&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;system( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/system'', &amp;lt;tt&amp;gt;escapeshellarg( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/escapeshellarg'', and &amp;lt;tt&amp;gt;escapeshellcmd( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/escapeshellcmd''.&lt;br /&gt;
&lt;br /&gt;
== Passing Input to a Program ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to pass input to an external program run from inside a PHP script. You might, for example, use a database that requires you to run an external program to index text and want to pass text to that program.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Open a pipe to the program with &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt; , write to the pipe with &amp;lt;tt&amp;gt;fputs( )&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt;, then close the pipe with &amp;lt;tt&amp;gt;pclose( )&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 $ph = popen('program arg1 arg2','w')          or die($php_errormsg);&lt;br /&gt;
 if (-1 == fputs($ph,&amp;quot;first line of input\n&amp;quot;))  { die($php_errormsg); }&lt;br /&gt;
 if (-1 == fputs($ph,&amp;quot;second line of input\n&amp;quot;)) { die($php_errormsg); }&lt;br /&gt;
 pclose($ph)                                   or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
This example uses &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt; to call the ''nsupdate'' command, which submits Dynamic DNS Update requests to name servers:&lt;br /&gt;
&lt;br /&gt;
 $ph = popen('/usr/bin/nsupdate -k keyfile')               or die($php_errormsg);&lt;br /&gt;
 if (-1 == fputs($ph,&amp;quot;update delete test.example.com A\n&amp;quot;)) { die($php_errormsg); }&lt;br /&gt;
 if (-1 == fputs($ph,&amp;quot;update add test.example.com 5 A 192.168.1.1\n&amp;quot;))&lt;br /&gt;
                                                            { die($php_errormsg); }&lt;br /&gt;
 pclose($ph)                                               or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
Two commands are sent to ''nsupdate'' via &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt;. The first deletes the ''test.example.com'' A record, and the second adds a new A record for ''test.example.com'' with the address 192.168.1.1.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/popen'' and &amp;lt;tt&amp;gt;pclose( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/pclose''; Dynamic DNS is described in RFC 2136 at ''http://www.faqs.org/rfcs/rfc2136.html''.&lt;br /&gt;
&lt;br /&gt;
== Reading Standard Output from a Program ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read the output from a program; for example, you want the output of a system utility such as ''route(8)'' that provides network information.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
To read the entire contents of a program's output, use the backtick (&amp;lt;tt&amp;gt;'&amp;lt;/tt&amp;gt;) operator:&lt;br /&gt;
&lt;br /&gt;
 $routing_table = `/sbin/route`;&lt;br /&gt;
&lt;br /&gt;
To read the output incrementally, open a pipe with &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $ph = popen('/sbin/route','r') or die($php_errormsg);&lt;br /&gt;
 while (! feof($ph)) {&lt;br /&gt;
     $s = fgets($ph,1048576)    or die($php_errormsg);&lt;br /&gt;
 }&lt;br /&gt;
 pclose($ph)                    or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The backtick operator (which is not available in safe mode), executes a program and returns all its output as a single string. On a Linux system with 448 MB of RAM, this command:&lt;br /&gt;
&lt;br /&gt;
 $s = `/usr/bin/free`;&lt;br /&gt;
&lt;br /&gt;
puts this multiline string in &amp;lt;tt&amp;gt;$s&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
              total       used       free     shared    buffers     cached&lt;br /&gt;
 Mem:        448620     446384       2236          0      68568     163040&lt;br /&gt;
 -/+ buffers/cache:     214776     233844&lt;br /&gt;
 Swap:       136512          0     136512&lt;br /&gt;
&lt;br /&gt;
If a program generates a lot of output, it is more memory-efficient to read from a pipe one line at a time. If you're printing formatted data to the browser based on the output of the pipe, you can print it as you get it. This example prints information about recent Unix system logins formatted as an HTML table. It uses the ''/usr/bin/last'' command:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;// print table header&lt;br /&gt;
print&amp;lt;&amp;lt;&amp;lt;_HTML_&lt;br /&gt;
&amp;lt;table&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;user&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;login port&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;login from&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;login time&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;time spent logged in&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
_HTML_;&lt;br /&gt;
&lt;br /&gt;
// open the pipe to /usr/bin/last&lt;br /&gt;
$ph = popen('/usr/bin/last','r') or die($php_errormsg);&lt;br /&gt;
while (! feof($ph)) {&lt;br /&gt;
    $line = fgets($ph,80) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
    // don't process blank lines or the info line at the end&lt;br /&gt;
    if (trim($line) &amp;amp;&amp;amp; (! preg_match('/^wtmp begins/',$line))) {&lt;br /&gt;
        $user = trim(substr($line,0,8));&lt;br /&gt;
        $port = trim(substr($line,9,12));&lt;br /&gt;
        $host = trim(substr($line,22,16));&lt;br /&gt;
        $date = trim(substr($line,38,25));&lt;br /&gt;
        $elapsed = trim(substr($line,63,10),' ()');&lt;br /&gt;
        &lt;br /&gt;
        if ('logged in' == $elapsed) {&lt;br /&gt;
            $elapsed = 'still logged in';&lt;br /&gt;
            $date = substr_replace($date,'',-5);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        print &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;$user&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$port&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$host&amp;lt;/td&amp;gt;&amp;quot;;&lt;br /&gt;
        print &amp;quot;&amp;lt;td&amp;gt;$date&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$elapsed&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
pclose($ph) or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
print '&amp;lt;/table&amp;gt;';&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/popen'', &amp;lt;tt&amp;gt;pclose( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/pclose'', and the backtick operator at ''http://www.php.net/language.operators.execution''; safe mode is documented at ''http://www.php.net/features.safe-mode''.&lt;br /&gt;
&lt;br /&gt;
== Reading Standard Error from a Program ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read the error output from a program; for example, you want to capture the system calls displayed by ''strace(1)'' .&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Redirect standard error to standard output by adding &amp;lt;tt&amp;gt;2&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; to the command line passed to &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt; . Read standard output by opening the pipe in &amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
 $ph = popen('strace ls 2&amp;gt;&amp;amp;1','r') or die($php_errormsg);&lt;br /&gt;
 while (!feof($ph)) {&lt;br /&gt;
     $s = fgets($ph,1048576)       or die($php_errormsg);&lt;br /&gt;
 }&lt;br /&gt;
 pclose($ph)                       or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
In both the Unix ''sh'' and the Windows ''cmd.exe'' shells, standard error is file descriptor 2, and standard output is file descriptor 1. Appending &amp;lt;tt&amp;gt;2&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; to a command tells the shell to redirect what's normally sent to file descriptor 2 (standard error) over to file descriptor 1 (standard output). &amp;lt;tt&amp;gt;fgets( )&amp;lt;/tt&amp;gt; then reads both standard error and standard output.&lt;br /&gt;
&lt;br /&gt;
This technique reads in standard error but doesn't provide a way to distinguish it from standard output. To read just standard error, you need to prevent standard output from being returned through the pipe. This is done by redirecting it to ''/dev/null'' on Unix and NUL on Windows:&lt;br /&gt;
&lt;br /&gt;
 // Unix: just read standard error&lt;br /&gt;
 $ph = popen('strace ls 2&amp;gt;&amp;amp;1 1&amp;gt;/dev/null','r') or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // Windows: just read standard error&lt;br /&gt;
 $ph = popen('ipxroute.exe 2&amp;gt;&amp;amp;1 1&amp;gt;NUL','r') or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/popen''; see your ''popen(3)'' manpage for details about the shell your system uses with &amp;lt;tt&amp;gt;popen( )&amp;lt;/tt&amp;gt;; for information about shell redirection, see the Redirection section of the ''sh(1)'' manpage on Unix systems; on Windows, see the entry on redirection in the Command Reference section of your system help.&lt;br /&gt;
&lt;br /&gt;
== Locking a File ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to have exclusive access to a file to prevent it from being changed while you read or update it. If, for example, you are saving guestbook information in a file, two users should be able to add guestbook entries at the same time without clobbering each other's entries.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; to provide advisory locking:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('guestbook.txt','a')         or die($php_errormsg);&lt;br /&gt;
 flock($fh,LOCK_EX)                       or die($php_errormsg);&lt;br /&gt;
 fwrite($fh,$_REQUEST['guestbook_entry']) or die($php_errormsg);&lt;br /&gt;
 fflush($fh)                              or die($php_errormsg);&lt;br /&gt;
 flock($fh,LOCK_UN)                       or die($php_errormsg);&lt;br /&gt;
 fclose($fh)                              or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The file locking &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; provides is called ''advisory'' file locking because &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; doesn't actually prevent other processes from opening a locked file, it just provides a way for processes to voluntarily cooperate on file access. All programs that need to access files being locked with &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; need to set and release locks to make the file locking effective.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of locks you can set with &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt;: exclusive locks and shared locks. An ''exclusive lock'' , specified by &amp;lt;tt&amp;gt;LOCK_EX&amp;lt;/tt&amp;gt; as the second argument to &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt;, can be held only by one process at one time for a particular file. A ''shared lock'' , specified by &amp;lt;tt&amp;gt;LOCK_SH&amp;lt;/tt&amp;gt;, can be held by more than one process at one time for a particular file. Before writing to a file, you should get an exclusive lock. Before reading from a file, you should get a shared lock.&lt;br /&gt;
&lt;br /&gt;
To unlock a file, call &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;LOCK_UN&amp;lt;/tt&amp;gt; as the second argument. It's important to flush any buffered data to be written to the file with &amp;lt;tt&amp;gt;fflush( )&amp;lt;/tt&amp;gt; before you unlock the file. Other processes shouldn't be able to get a lock until that data is written.&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; blocks until it can obtain a lock. To tell it not to block, add &amp;lt;tt&amp;gt;LOCK_NB&amp;lt;/tt&amp;gt; to the second argument:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('guestbook.txt','a')         or die($php_errormsg);&lt;br /&gt;
 $tries = 3;&lt;br /&gt;
 while ($tries &amp;gt; 0) {&lt;br /&gt;
     $locked = flock($fh,LOCK_EX | LOCK_NB);&lt;br /&gt;
     if (! $locked) {&lt;br /&gt;
         sleep(5);&lt;br /&gt;
         $tries--;&lt;br /&gt;
     } else {&lt;br /&gt;
         // don't go through the loop again &lt;br /&gt;
         $tries = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 if ($locked) {&lt;br /&gt;
     fwrite($fh,$_REQUEST['guestbook_entry']) or die($php_errormsg);&lt;br /&gt;
     fflush($fh)                              or die($php_errormsg);&lt;br /&gt;
     flock($fh,LOCK_UN)                       or die($php_errormsg);&lt;br /&gt;
     fclose($fh)                              or die($php_errormsg);&lt;br /&gt;
 } else {&lt;br /&gt;
     print &amp;quot;Can't get lock.&amp;quot;;&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
When the lock is nonblocking, &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; returns right away even if it couldn't get a lock. The previous example tries three times to get a lock on ''guestbook.txt'', sleeping five seconds between each try.&lt;br /&gt;
&lt;br /&gt;
Locking with &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; doesn't work in all circumstances, such as on some NFS implementations. Also, &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; isn't supported on Windows 95, 98, or ME. To simulate file locking in these cases, use a directory as a exclusive lock indicator. This is a separate empty directory whose presence indicates that the data file is locked. Before opening a data file, create a lock directory and then delete the lock directory when you're finished working with the data file. Otherwise, the file access code is the same, as shown here:&lt;br /&gt;
&lt;br /&gt;
 $fh = fopen('guestbook.txt','a')         or die($php_errormsg);&lt;br /&gt;
 &lt;br /&gt;
 // loop until we can successfully make the lock directory &lt;br /&gt;
 $locked = 0;&lt;br /&gt;
 while (! $locked) {&lt;br /&gt;
     if (@mkdir('guestbook.txt.lock',0777)) {&lt;br /&gt;
         $locked = 1;&lt;br /&gt;
     } else {&lt;br /&gt;
         sleep(1);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (-1 == fwrite($fh,$_REQUEST['guestbook_entry'])) {&lt;br /&gt;
     rmdir('guestbook.txt.lock');&lt;br /&gt;
     die($php_errormsg);&lt;br /&gt;
 }&lt;br /&gt;
 if (! fclose($fh)) {&lt;br /&gt;
     rmdir('guestbook.txt.lock');&lt;br /&gt;
     die($php_errormsg);&lt;br /&gt;
 }&lt;br /&gt;
 rmdir('guestbook.txt.lock')              or die($php_errormsg);&lt;br /&gt;
&lt;br /&gt;
A directory is used instead of a file to indicate a lock because the &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; function fails to create a directory if it already exists. This gives you a way, in one operation, to check if the lock indicator exists and create it if it doesn't. Any error trapping after the directory is created, however, needs to clean up by removing the directory before exiting. If the directory is left in place, no future processes can get a lock by creating the directory.&lt;br /&gt;
&lt;br /&gt;
If you use a file as a lock indicator, the code to create it looks like:&lt;br /&gt;
&lt;br /&gt;
 $locked = 0;&lt;br /&gt;
 while (! $locked) {&lt;br /&gt;
     if (! file_exists('guestbook.txt.lock')) {&lt;br /&gt;
         touch('guestbook.txt.lock');&lt;br /&gt;
         $locked = 1;&lt;br /&gt;
     } else {&lt;br /&gt;
         sleep(1);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This might fail under heavy load because you check for the lock's existence with &amp;lt;tt&amp;gt;file_exists( )&amp;lt;/tt&amp;gt; and then create the lock with &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt; . After one process calls &amp;lt;tt&amp;gt;file_exists( )&amp;lt;/tt&amp;gt;, another might call &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt; before the first calls &amp;lt;tt&amp;gt;touch( )&amp;lt;/tt&amp;gt;. Both processes would then think they've got exclusive access to the file when neither does. With &amp;lt;tt&amp;gt;mkdir( )&amp;lt;/tt&amp;gt; there's no gap between the checking for existence and creation, so the process that makes the directory is ensured exclusive access.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
Documentation on &amp;lt;tt&amp;gt;flock( )&amp;lt;/tt&amp;gt; at ''http://www.php.net/flock''.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing Compressed Files ==&lt;br /&gt;
&lt;br /&gt;
=== Problem ===&lt;br /&gt;
&lt;br /&gt;
You want to read or write compressed files.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
Use PHP's ''zlib'' extension to read or write ''gzip'''ed files. To read a compressed file:&lt;br /&gt;
&lt;br /&gt;
 $zh = gzopen('file.gz','r') or die(&amp;quot;can't open: $php_errormsg&amp;quot;);&lt;br /&gt;
 while ($line = gzgets($zh,1024)) {&lt;br /&gt;
     // $line is the next line of uncompressed data, up to 1024 bytes &lt;br /&gt;
 }&lt;br /&gt;
 gzclose($zh) or die(&amp;quot;can't close: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Here's how to write a compressed file:&lt;br /&gt;
&lt;br /&gt;
 $zh = gzopen('file.gz','w') or die(&amp;quot;can't open: $php_errormsg&amp;quot;);&lt;br /&gt;
 if (-1 == gzwrite($zh,$s))   { die(&amp;quot;can't write: $php_errormsg&amp;quot;); }&lt;br /&gt;
 gzclose($zh)                or die(&amp;quot;can't close: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
&lt;br /&gt;
The ''zlib'' extension contains versions of many file-access functions, such as &amp;lt;tt&amp;gt;fopen( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;fread( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt; (called &amp;lt;tt&amp;gt;gzopen( )&amp;lt;/tt&amp;gt; , &amp;lt;tt&amp;gt;gzread( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gzwrite( )&amp;lt;/tt&amp;gt;, etc.) that transparently compress data when writing and uncompress data when reading. The compression algorithm that ''zlib'' uses is compatible with the ''gzip'' and ''gunzip'' utilities.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;gzgets($zp,1024)&amp;lt;/tt&amp;gt; works like &amp;lt;tt&amp;gt;fgets($fh,1024)&amp;lt;/tt&amp;gt;. It reads up to 1023 bytes, stopping earlier if it reaches EOF or a newline. For &amp;lt;tt&amp;gt;gzgets( )&amp;lt;/tt&amp;gt;, this means 1023 uncompressed bytes.&lt;br /&gt;
&lt;br /&gt;
However, &amp;lt;tt&amp;gt;gzseek( )&amp;lt;/tt&amp;gt; works differently than &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt;. It only supports seeking a specified number of bytes from the beginning of the file stream (the &amp;lt;tt&amp;gt;SEEK_SET&amp;lt;/tt&amp;gt; argument to &amp;lt;tt&amp;gt;fseek( )&amp;lt;/tt&amp;gt;). Seeking forward (from the current position) is only supported in files opened for writing (the file is padded with a sequence of compressed zeroes). Seeking backwards is supported in files opened for reading, but it is very slow.&lt;br /&gt;
&lt;br /&gt;
The ''zlib'' extension also has some functions to create compressed strings. The function &amp;lt;tt&amp;gt;gzencode( )&amp;lt;/tt&amp;gt; compresses a string and gives it the correct headers and formatting to be compatible with ''gunzip'' . Here's a simple ''gzip'' program:&lt;br /&gt;
&lt;br /&gt;
 $in_file = $_SERVER['argv'][1];&lt;br /&gt;
 $out_file = $_SERVER['argv'][1].'.gz';&lt;br /&gt;
 &lt;br /&gt;
 $ifh = fopen($in_file,'rb')  or die(&amp;quot;can't open $in_file: $php_errormsg&amp;quot;);&lt;br /&gt;
 $ofh = fopen($out_file,'wb') or die(&amp;quot;can't open $out_file: $php_errormsg&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 $encoded = gzencode(fread($ifh,filesize($in_file)))&lt;br /&gt;
                              or die(&amp;quot;can't encode data: $php_errormsg&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 if (-1 == fwrite($ofh,$encoded)) { die(&amp;quot;can't write: $php_errormsg&amp;quot;); }&lt;br /&gt;
 fclose($ofh)                 or die(&amp;quot;can't close $out_file: $php_errormsg&amp;quot;);&lt;br /&gt;
 fclose($ifh)                 or die(&amp;quot;can't close $in_file: $php_errormsg&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The guts of this program are the lines:&lt;br /&gt;
&lt;br /&gt;
 $encoded = gzencode(fread($ifh,filesize($in_file)))&lt;br /&gt;
                              or die(&amp;quot;can't encode data: $php_errormsg);&lt;br /&gt;
 if (-1 == fwrite($ofh,$encoded)) { die(&amp;quot;can't write: $php_errormsg&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
The compressed contents of &amp;lt;tt&amp;gt;$in_file&amp;lt;/tt&amp;gt; are stored in &amp;lt;tt&amp;gt;$encoded&amp;lt;/tt&amp;gt; and then written to &amp;lt;tt&amp;gt;$out_file&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;fwrite( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can pass a second argument to &amp;lt;tt&amp;gt;gzencode( )&amp;lt;/tt&amp;gt; that indicates compression level. Set no compression with 0 and maximum compression with 9. The default level is 1. To adjust the simple ''gzip'' program for maximum compression, the encoding line becomes:&lt;br /&gt;
&lt;br /&gt;
 $encoded = gzencode(fread($ifh,filesize($in_file)),9)&lt;br /&gt;
                              or die(&amp;quot;can't encode data: $php_errormsg);&lt;br /&gt;
&lt;br /&gt;
You can also compress and uncompress strings without the ''gzip''-compatibility headers by using &amp;lt;tt&amp;gt;gzcompress( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;gzuncompress( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Files#Program: Unzip|Section 18.27]] for a program that extracts files from a ZIP archive; documentation on the ''zlib'' extension at ''http://www.php.net/zlib''; you can download ''zlib'' at ''http://www.gzip.org/zlib/''; the ''zlib'' algorithm is detailed in RFCs 1950 (''http://www.faqs.org/rfcs/rfc1950.html'') and 1951 (''http://www.faqs.org/rfcs/rfc1951.html'').&lt;br /&gt;
&lt;br /&gt;
== Program: Unzip ==&lt;br /&gt;
&lt;br /&gt;
The ''unzip.php'' program, shown in [[PHP Cookbook/Files#phpckbk-CHP-18-EX-5|Example 18-5]], extracts files from a ZIP archive. It uses the &amp;lt;tt&amp;gt;pc_mkdir_parents( )&amp;lt;/tt&amp;gt; function which is defined in [[PHP Cookbook/Directories#Making New Directories|Section 19.11]]. The program also requires PHP's ''zip'' extension to be installed. You can find documentation on the ''zip'' extension at ''http://www.php.net/zip''.&lt;br /&gt;
&lt;br /&gt;
This program takes a few arguments on the command line. The first is the name of the ZIP archive it should unzip. By default, it unzips all files in the archive. If additional command-line arguments are supplied, it only unzips files whose name matches any of those arguments. The full path of the file inside the ZIP archive must be given. If ''turtles.html'' is in the ZIP archive inside the ''animals'' directory, ''unzip.php'' must be passed ''animals/turtles.html'', not just ''turtles.html'', to unzip the file.&lt;br /&gt;
&lt;br /&gt;
Directories are stored as 0-byte files inside ZIP archives, so ''unzip.php'' doesn't try to create them. Instead, before it creates any other file, it uses &amp;lt;tt&amp;gt;pc_mkdir_parents( )&amp;lt;/tt&amp;gt; to create all directories that are parents of that file, if necessary. For example, say ''unzip.php'' sees these entries in the ZIP archive:&lt;br /&gt;
&lt;br /&gt;
 animals (0 bytes)&lt;br /&gt;
 animals/frogs/ribbit.html (2123 bytes)&lt;br /&gt;
 animals/turtles.html   (1232 bytes)&lt;br /&gt;
&lt;br /&gt;
It ignores ''animals'' because it is 0 bytes long. Then it calls &amp;lt;tt&amp;gt;pc_mkdir_parents( )&amp;lt;/tt&amp;gt; on ''animals/frogs'', creating both ''animals'' and ''animals/frogs'', and writes ''ribbit.html'' into ''animals/frogs''. Since ''animals'' already exists when it reaches ''animals/turtles.html'', it writes out ''turtles.html'' without creating any additional directories.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;phpckbk-CHP-18-EX-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 18-5. unzip.php'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;// the first argument is the zip file&lt;br /&gt;
$in_file = $_SERVER['argv'][1];&lt;br /&gt;
&lt;br /&gt;
// any other arguments are specific files in the archive to unzip&lt;br /&gt;
if ($_SERVER['argc'] &amp;gt; 2) {&lt;br /&gt;
    $all_files = 0;&lt;br /&gt;
    for ($i = 2; $i &amp;lt; $_SERVER['argc']; $i++) {&lt;br /&gt;
        $out_files[$_SERVER['argv'][$i]] = true;&lt;br /&gt;
    }&lt;br /&gt;
} else {&lt;br /&gt;
    // if no other files are specified, unzip all files&lt;br /&gt;
    $all_files = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$z = zip_open($in_file) or die(&amp;quot;can't open $in_file: $php_errormsg&amp;quot;);&lt;br /&gt;
while ($entry = zip_read($z)) {&lt;br /&gt;
    &lt;br /&gt;
    $entry_name = zip_entry_name($entry);&lt;br /&gt;
&lt;br /&gt;
    // check if all files should be unzipped, or the name of&lt;br /&gt;
    // this file is on the list of specific files to unzip&lt;br /&gt;
    if ($all_files || $out_files[$entry_name]) {&lt;br /&gt;
&lt;br /&gt;
        // only proceed if the file is not 0 bytes long&lt;br /&gt;
        if (zip_entry_filesize($entry)) {&lt;br /&gt;
            $dir = dirname($entry_name);&lt;br /&gt;
&lt;br /&gt;
            // make all necessary directories in the file's path&lt;br /&gt;
            if (! is_dir($dir)) { pc_mkdir_parents($dir); }&lt;br /&gt;
&lt;br /&gt;
            $file = basename($entry_name);&lt;br /&gt;
&lt;br /&gt;
            if (zip_entry_open($z,$entry)) {&lt;br /&gt;
                if ($fh = fopen($dir.'/'.$file,'w')) {&lt;br /&gt;
                    // write the entire file&lt;br /&gt;
                    fwrite($fh,&lt;br /&gt;
                           zip_entry_read($entry,zip_entry_filesize($entry)))&lt;br /&gt;
                        or error_log(&amp;quot;can't write: $php_errormsg&amp;quot;);&lt;br /&gt;
                    fclose($fh) or error_log(&amp;quot;can't close: $php_errormsg&amp;quot;);&lt;br /&gt;
                } else {&lt;br /&gt;
                    error_log(&amp;quot;can't open $dir/$file: $php_errormsg&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
                zip_entry_close($entry);&lt;br /&gt;
            } else {&lt;br /&gt;
                error_log(&amp;quot;can't open entry $entry_name: $php_errormsg&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== See Also ===&lt;br /&gt;
&lt;br /&gt;
[[PHP Cookbook/Files#Reading and Writing Compressed Files|Section 18.26]] for reading and writing ''zlib'' compressed files; [[PHP Cookbook/Directories#Making New Directories|Section 19.11]] for the &amp;lt;tt&amp;gt;pc_mkdir_parents( )&amp;lt;/tt&amp;gt; function; documentation on the ''zip'' extension at ''http://www.php.net/zip'' .&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	</feed>