2012-10-08

PHP provides an enormous list of [functions to interact with the file system][1]. There's a separate listing of [directory functions][2]. They may not all be meaningful on every operating system. Some functions report or manipulate information about a file (e.g. file_exists, filesize) and some functions are more focused on reading or writing the contents of files (e.g. fread, fputs). The first type of function is very common in command line scripts; automating a process with a script requires doing a lot of checking on files' status before attempting something. In a previous script, the dirname() function was used. It returns the directory for a full file path.

echo dirname (__FILE__);

C:\Users\grantwparks\workspace\phpweb\public

Notice this is the file system path to the script directory. And since it's running on Windows, the path separator is the backslash.

**Directory Listing**

`scandir()` returns a directories file names in an array

.
[1] => ..
[2] => 6.1.php
[3] => edit_profile.php
[4] => form.php
[5] => fs.php
[6] => index.html
[7] => index.php
[8] => simpleform.html
[9] => test.php
)

This is the list of files in my /public directory. That's interesting, but only shows the file names. Let's print some information about the files.

file name

readable?

.”
writable?

file?/td>

size
"
);

foreach ($files as $file) {
$fullPath = $dir .DIRECTORY_SEPARATOR .$file;
$html[] = sprintf ("

%s

%s

%s

%s

%s

",
$file,
(is_readable($fullPath) ? "yes" : "no"),
(is_writable($fullPath) ? "yes" : "no"),
(is_file($fullPath) ? "yes" : "no"),
filesize($fullPath));
}
return implode ('', $html);
}
?>

file name readable? writable? file? size
. yes yes no 4096
.. yes yes no 4096
6.1.php yes yes yes 862
6.2.php yes yes yes 465
edit_profile.php yes yes yes 1796
file.csv yes yes yes 61
form.php yes yes yes 540
fs.php yes yes yes 342
index.html yes yes yes 161
index.php yes yes yes 328
simpleform.html yes yes yes 506
test.php yes yes yes 4816

Notice the “files” . and .., they represent the current and parent directory so is_file() returned false for them.

**File Input/Output**

The most basic thing would be reading the contents of a file. There happen to be many functions to do that. fread, fscanf and a few that begin with “fget”. If sample.txt contains some text to read

';
echo fgets ($fp);
rewind ($fp);
echo '
';
echo fgetc ($fp);
fclose ($fp);
}
?>

some text to read
some text to read
s

The `rewind()` calls are necessary, because the file pointer is at the end of file after each of the first two reads.

Use [fopen() to open a “resource”][3] (it will open URLs as well as files). The arguments are a file name (a full path can be used, here the current directory is the default) and “mode”. There are many mode options, and one should research to find if there are operating system-dependent flags to use. But the primary flags control

- Opening for reading, writing or both (r, w, r+, w+)
- What the behavior should be if the file exists. In write mode, an existing file will normally be reused, but fopen(file, 'x') will fail if the file exists.
- Where to position the file pointer. Beginning of file is the default, use 'a', 'a+' – for append – to position at the end of file.

**Working With CSV Files**

Jumping right ahead to writing, how about saving an array as a comma-separated value file (.csv) which can be opened by any spreadsheet,

if ($fp = fopen('file.csv', 'w')) {

fputcsv ($fp, array (
'id' => 124,
'name' => "John Doe",
'age' => 32,
'eyes' => 'green',
'social' => '111-555-0101'
));

fclose ($fp);
}

After opening the file for writing `fputcsv()` saves the array. Open file.csv in a spreadsheet application (you might have to tell it to use comma separators).

![file CSV][4]

`fputcsv()` really only puts the values of the array, and the data doesn't mean much by itself. It should be easy to add column headers. The array_keys function will return an array whose values are the keys of its argument array. If the code is changed to also save the array_keys, then the output will contain a row for column headers, in the form of the keys.

$myArray = array (
'id' => 124,
'name' => "John Doe",
'age' => 32,
'eyes' => 'green',
'social' => '111-555-0101'
);
fputcsv ($fp, array_keys ($myArray));
fputcsv ($fp, $myArray);

The keys of the array now appear as the first line of the file.

![csv headers][5]

How about reading a .csv? Most Web email applications (e.g. gmail) allow exporting a contact list to .csv. Such a file can be read

if ($fp = fopen('google.csv', 'r')) {
$columns = fgetcsv ($fp);
print_r($columns);
fclose ($fp);
}

This file has column headers in its first row, like the one we just wrote. We can essentially reverse the process by reading the first row and using its values as keys for the rest of the rows' columns. Adding a loop to read the rest of the rows in the file after reading `$columns`

$keyedRows = array ();
while (($row = fgetcsv($fp)) !== false) {
$keyedRows[] = array_combine ($columns, $row);
}

`fgetcsv`, like a lot of file functions, returns false at end of file. array_combine() returns a new array whose keys are the values of the first argument and values come from the second argument. Now `$keyedRows` is an array of all my contact information and every entry in the array is a key/value array for a single contact.

Array (
[Name] => Joe Contact
[Given Name] => Joe
[Additional Name] =>
[Family Name] => Contact
...
[Organization 1 - Location] =>
[Organization 1 - Job Description] =>
[Website 1 - Type] =>
[Website 1 - Value] =>
[Jot 1 - Type] =>
[Jot 1 - Value] =>
)

There are generally many unused fields in the contact file, making it very hard to read. An advanced array function, `array_map()`, can be used to create an array from an existing one. There are other ways to do the same thing, but “map” is a more recent concept that promotes separating the logic of working with one entry in the array from looping through it. First, we create the function to return a new array entry in place of each original entry.

function unsparseIt ($contact) {
foreach ($contact as $key => $value) {
if ($value == '')
unset ($contact[$key]);
}
return $contact;
}

Recall that the $contact argument is a copy of the original value, so even though its fields are unset in the loop that only changes the copy, which still has to be returned as the new array entry. Unsetting array entries “destroys” them and removes them from the array. array_map then calls this function for every entry in its second array argument

$prunedArray = array_map ('unsparseIt', $keyedRows);

`$prunedArray` now contains a compact version of `$keyedRows`, with all empty fields removed.

Array (
[Name] => Joe Contact
[Given Name] => Joe
[Family Name] => Contact
[Group Membership] => * My Contacts
[E-mail 1 - Type] => *
[E-mail 1 - Value] => contactj@acme.com
[Phone 1 - Type] => Work
[Phone 1 - Value] => 303-555-3000
[Organization 1 - Name] => Acme Board of Directors
)

The convenient thing about fgetcsv and fputcsv is that they handle things like escaping commas in values.

**Simplest Reading for Small Files**

[file_get_contents($filename)][6] is one of the simplest, most versatile ways to read files. The filename argument may be a URL. “Proxying” another page or embedding an RSS feed is easy. If you open a script with the following in your browser, you'll see the php.net documentation as if it were your own page.

**Using PHP's Configuration Parsing**

It's very common in PHP to need configuration information defined in its own file and used by the code. A useful function is [parse_ini_file][7] function. Instead of inventing a new configuration file format, it allows one to use the same format as in php.ini and read settings into an array so that values can be directly accessed without creating a bunch of global variables.

[section 1]
env = prod
foo = bar

[othersettings]
bar = foo

$config = parse_ini_file ("myconfig.ini", true);
print_r ($config);

// passing true as 2nd arg will return an array that's
// indexed by [sections]
$config = parse_ini_file ("myconfig.ini", true);
print_r ($config);

Array (
[env] => prod
[foo] => bar
[bar] => foo
)

Array (
[section 1] => Array (
[env] => prod
[foo] => bar
)
[othersettings] => Array (
[bar] => foo
)
)

If I created a file myconfig.ini with

[1]: http://www.php.net/manual/en/ref.filesystem.php
[2]: http://www.php.net/manual/en/ref.dir.php
[3]: http://www.php.net/manual/en/function.fopen.php
[4]: http://beyondrelational.com/images/images.ashx?id=dc0a1996392340258d9d4cf47f2fe00e&w=0&h=0
[5]: http://beyondrelational.com/images/images.ashx?id=f4f4c73290da48efa57f2f97f8ea7d29&w=0&h=0
[6]: http://php.net/manual/en/function.file-get-contents.php
[7]: http://www.php.net/manual/en/function.parse-ini-file.php

Show more