PHP, MySQL, JavaScript & HTML5 All-in-One For Dummies (2013)

Book IV: PHP

Chapter 3: PHP and Your Operating System

In This Chapter

arrow.png Manipulating files

arrow.png Using operating system commands on files

arrow.png Transferring files from one machine to another

arrow.png Reading and writing files

arrow.png Swapping data with other programs

arrow.png Using SQLite to store data in text files

This book describes using tools like HTML, PHP, MySQL, and CSS together to develop dynamic web applications. The HTML and CSS provide the presentation and markup of pages, while PHP displays web pages and interacts with MySQL to retrieve and store data for the application. For most web applications, PHP needs to interact only with MySQL. However, a few situations require a web application that’s more complex. The web application might need to interact with the operating system or with other software on your system.

A photo gallery is one web application that might need to interact with your operating system. Your photo gallery might allow users to upload graphic files into your application. For such an application, you might need to manage the files that the users upload. You might need to rename them, move them, or delete them. You might need to know when the photos were uploaded or when they were last accessed. PHP provides all the features you need to manage your file system, and we help you understand how to do that.

PHP also allows you to run any program that’s on your computer, regardless of whether it’s a PHP program. With PHP code, you can transfer files between computers by using File Transfer Protocol (FTP). You can store information in files other than databases. This chapter gives you the information you need to use PHP to do pretty much anything you can think of on your computer. This chapter also provides information on the security risks inherent in executing operating system commands. The chapter wraps up with a look at a quick way to store data through a utility called SQLite.

Managing Files

The information you save on your hard drive is organized into files. Rather than storing files in one big file drawer, making them difficult to find, files are stored in many drawers, called directories or folders. The system of files and directories is called a file system.

A file system is organized in a hierarchical structure, with a top level that is a single directory called root, such as c:\ on Windows or / on Linux or Mac. The root directory contains other directories, and each directory can contain other directories, and so on. The file system's structure can go down many levels.

A directory is a type of file that you use to organize other files. It contains a list of files and the information needed for the operating system to find those files. A directory can contain both files and other directories.

Files can be checked (to see if they exist, for example), copied, deleted, and renamed, among other things. Functions for performing these file-management tasks are described in the following sections. You also find out about functions that allow you to manage directories and discover what’s inside them.

tip.eps In this chapter, we cover the most useful functions for managing files, but more functions are available. When you need to perform an action on a file or directory, first check the online PHP documentation at www.php.net/manual to see whether an existing function does what you need to do. Using a function is preferable, if an appropriate function exists. If such a function does not exist, you can use your operating system commands or a program in another language, as described in the Using Operating System Commands section, later in this chapter.

Getting information about files

Often you want to know information about a file. PHP has functions that allow you to find out file information from within a script.

You can find out whether a file exists with the file_exists statement, as follows:

$result = file_exists("stuff.txt");

After this statement, $result contains either true or false. The function is often used in a conditional statement, such as the following:

if(!file_exists("stuff.txt"))

{

    echo "File not found!\n";

}

When you know the file exists, you can find out information about it.

Table 3-1 shows many of the functions that PHP provides for checking files. (Some of the information in Table 3-1 is relevant only for Linux, Unix, and Mac, and some is returned on Windows as well.)

Table 3-1 Functions That Get Information about a File

Function

What It Does

Output

is_file("stuff.txt")

Tests whether the file is a regular file, rather than a directory or other special type of file

true or false

is_dir("stuff.txt")

Tests whether the file is a directory

true or false

is_executable("do.txt")

Tests whether the file is executable

true or false

is_writable("stuff.txt")

Tests whether you can write to the file

true or false

is_readable("stuff.txt")

Tests whether you can read the file

true or false

fileatime("stuff.txt")

Returns the time when the file was last accessed

Unix timestamp (like 1057196122) or false

filectime("stuff.txt")

Returns the time when the file was created

Unix timestamp or false

filemtime("stuff.txt")

Returns the time when the file was last modified

Unix timestamp or false

filegroup("stuff.txt")

Returns the group ID of the file

Integer that is a group ID or false

fileowner("stuff.txt")

Returns the user ID of the owner of the file

Integer that is a user ID or false

filesize("stuff.txt")

Returns the file size in bytes

Integer or false

filetype("stuff.txt")

Returns the file type

File type (such as file, dir, link, char), or false if error or can't identify type

basename("/t1/do.txt")

Returns the filename from the path

do.txt

dirname("/t1/do.txt")

Returns the directory name from the path

/t1

A function that returns useful information about a path/filename is pathinfo(). You can use the following statement:

$pinfo = pathinfo("/topdir/nextdir/stuff.txt");

After the statement, $pinfo is an array that contains the following three elements:

$pinfo[dirname] = /topdir/nextdir

$pinfo[basename] = stuff.txt

$pinfo[extension] = txt

warning_bomb.eps When you're testing a file with one of the is_something functions from Table 3-1, any typing error, such as a misspelling of the filename, gives a false result. For example, is_dir("tyme") returns false if "tyme" is a file, not a directory. But, it also returns false if "tyme" does not exist because you meant to type "type".

tip.eps Unix timestamps are returned by some of the functions given in Table 3-1. You can convert these timestamps to dates with the date function, as described in Chapter 1 in this minibook.

Copying, renaming, and deleting files

You can copy an existing file into a new file. After copying, you have two copies of the file with two different names. Copying a file is often useful for backing up important files. To copy a file, use the copy statement, as follows:

copy("fileold.txt","filenew.txt");

This statement copies fileold.txt, an existing file, into filenew.txt. If a file with the name filenew.txt already exists, it's overwritten. If you don't want to overwrite an existing file, you can prevent it by using the following statements:

If(!file_exists("filenew.txt"))

{

     copy("fileold.txt","filenew.txt");

}

else

{

     echo "File already exists!\n";

}

You can copy a file into a different directory by using a pathname as the destination, as follows:

copy("fileold.txt","newdir/filenew.txt");

You can rename a file by using the rename statement, as follows:

rename("oldname.txt","newname.txt");

If you attempt to rename a file with the name of a file that already exists, a warning is displayed, as follows, and the file is not renamed:

Warning: rename(fileold.txt,filenew.txt): File exists in c:test.php on line 17

To remove an unwanted file, use the unlink statement, as follows:

unlink("badfile.txt");

After this statement, the file is deleted.

warning_bomb.eps If the file doesn't exist to start with, unlink doesn't complain. It acts the same as if it had deleted the file. PHP doesn't let you know if the file doesn't exist. So, watch out for typos.

Organizing files

Files are organized into directories, also called folders. This section describes how to create and remove directories and how to get a list of the files in a directory.

Creating a directory

To create a directory, use the mkdir function, as follows:

mkdir("testdir");

This statement creates a new directory named testdir in the same directory where the script is located. That is, if the script is /test/test.php, the new directory is /test/testdir. If a directory already exists with the same name, a warning is displayed, as follows, and the new directory is not created:

Warning: mkdir(): File exists in d:/test/test.php on line 5

You can check first to see whether the directory already exists by using the following statements:

If(!is_dir("mynewdir"))

{

   mkdir("mynewdir");

}

else

{

   echo "Directory already exists!";

}

After the directory is created, you can organize its contents by copying files into and out of the directory. Copying files is described in the section Copying, renaming, and deleting files, earlier in this chapter.

To create a directory in another directory, use the entire pathname, as follows:

mkdir("/topdir/nextdir/mynewdir");

You can use a relative path to create a new directory, as follows:

mkdir("../mynewdir");

With this statement, if your script is /topdir/test/makedir.php, the new directory is /topdir/mynewdir.

To change to a different directory, use the following statement:

chdir("../anotherdir");

Building a list of all the files in a directory

Getting a list of the files in a directory is often useful. For example, you might want to provide a list of files for users to download or want to display images from files in a specific directory.

PHP provides functions for opening and reading directories. To open a directory, use the opendir statement, as follows:

$dh = opendir("/topdir/testdir");

If you attempt to open a directory that doesn’t exist, a warning is displayed, as follows:

Warning: opendir(testdir): failed to open dir: Invalid argument in test13.php on line 5

In the previous statement, the variable $dh is a directory handle, a pointer to the open directory that you can use later to read from the directory. To read a filename from the directory, use the readdir function, as follows:

$filename = readdir($dh);

After this statement, $filename contains the name of a file. Only the filename is stored in $filename, not the entire path to the file. To read all the filenames in a directory, you can use a while loop, as follows:

while($filename = readdir($dh))

{

   echo $filename."\n";

}

remember.eps The readdir function doesn't provide any control over the order in which filenames are read, so you don't always get the filenames in the order you expect.

Suppose you want to create an image gallery that displays all the images in a specified directory in a web page. You can use the opendir and readdir functions to do this. Listing 3-1 shows a script that creates an image gallery.

Listing 3-1: A Script That Creates an Image Gallery

<?php

/* Script name: displayGallery

  * Description: Displays all the image files that are

  *              stored in a specified directory.

  */

echo "<html><head><title>Image Gallery</title></head>

       <body>";

$dir = "../test1/testdir/"; →8

$dh = opendir($dir); →9

while($filename = readdir($dh)) →10

{

   $filepath = $dir.$filename; →12

   if(is_file($filepath) and ereg("\.jpg$",$filename)) →13

   {

      $gallery[] = $filepath;

   }

}

sort($gallery); →16

foreach($gallery as $image) →17

{

   echo "<hr />";

   echo "<img src='$image' /><br />";

}

?>

</body></html>

Notice the line numbers at the end of some of the lines in Listing 3-1. The following discussion of the script and how it works refers to the line numbers in the script listing:

8 This line stores the name of the directory in $dir for use later in the program. Notice that the / is included at the end of the directory name. Don't use \, even with Windows.

9 This line opens the directory.

10 This line starts a while loop that reads in each filename in the directory.

12 This line creates the variable $filepath, which is the complete path to the file.

warning_bomb.eps If the / isn't included at the end of the directory name on Line 8, $filepath will not be a valid path.

13 This line checks to see whether the file is a graphics file by looking for the .jpg extension. If the file has a .jpg extension, the complete file path is added to an array called $gallery.

16 This line sorts the array so the images are displayed in alphabetical order.

17 This line starts the foreach loop that displays the images in the web page.

Using Operating System Commands

When you need to interact with your operating system, it’s always best to use the PHP functions that are provided for this purpose. Using PHP functions is faster and usually more secure than executing an operating system command directly. However, occasionally PHP doesn’t provide a function to perform the task you need. In such cases, you can use PHP features that enable you to execute an operating system command.

In this section, we assume that you know the format and use of the system commands for your operating system. Describing operating system commands is outside the scope of this book. If you need to run an operating system command from your PHP script, this section shows you how.

PHP allows you to use system commands or run programs in other languages by using any of the following methods:

check backticks: PHP executes the system command that is between two backticks (`) and displays the result.

check system function: This function executes a system command, displays the output, and returns the last line of the output.

check exec function: This function executes a system command, stores the output in an array, and returns the last line of the output.

check passthru function: This function executes a system command and displays the output.

You can execute any command that you can type into the system prompt. The command is executed exactly as is. You can execute simple commands: ls or dir, rename or mv, rm or del, though it's more efficient to use the built-in PHP functions for those, as already discussed.

If your operating system allows you to pipe or redirect output, you can pipe or redirect in the system command you’re executing in PHP. If your operating system allows you to enter two commands on one line, you can put two commands into the single command you’re executing from PHP. The following sample commands are valid to execute from PHP, depending on the operating system:

dir

rm badfile.txt

dir | sort

cd c:\php ; dir     (Not valid in Windows)

"cd c:\php && dir"  (Windows)

dir > dirfile

sort < unsortedfile.txt

technicalstuff.eps On some occasions, you want to run a system command that takes a long time to finish. You can run the system command in the background (if your operating system supports such things) while PHP continues with the script. If you do this, you need to redirect the output to a file, rather than return it to the script, so that PHP can continue before the system command finishes.

The following sections describe the preceding methods in greater detail.

Using backticks

A simple way to execute a system command is to put the command between two backticks (`), as follows:

$result = `dir c:\php`;

The variable $result contains the statement's output — in this case, a list of the files in the c:\php directory. If you echo $result, the following output is displayed:

Volume in drive C has no label.

Volume Serial Number is 58B2-DBD6

Directory of c:\php

10/10/2013  05:43 PM    <DIR>          .

10/10/2013  05:43 PM    <DIR>          ..

10/10/2013  04:53 PM    <DIR>          dev

10/10/2013  04:53 PM    <DIR>          ext

10/10/2013  04:53 PM    <DIR>          extras

08/30/2013  07:11 AM           417,792 fdftk.dll

08/30/2013  07:11 AM            90,112 fribidi.dll

08/30/2013  07:11 AM           346,624 gds32.dll

08/30/2013  07:11 AM                90 go-pear.bat

08/30/2013  07:11 AM            96,317 install.txt

08/30/2013  07:11 AM         1,097,728 libeay32.dll

08/30/2013  07:11 AM           166,912 libmcrypt.dll

08/30/2013  07:11 AM           165,643 libmhash.dll

08/30/2013  07:11 AM         2,035,712 libmysql.dll

08/30/2013  07:11 AM           385,024 libswish-e.dll

08/30/2013  07:11 AM             3,286 license.txt

08/30/2013  07:11 AM            57,344 msql.dll

08/30/2013  07:11 AM           168,858 news.txt

08/30/2013  07:11 AM           278,800 ntwdblib.dll

10/10/2013  04:53 PM    <DIR>          PEAR

08/30/2013  07:11 AM            41,017 php-cgi.exe

08/30/2013  07:11 AM            32,825 php-win.exe

08/30/2013  07:11 AM            32,821 php.exe

08/30/2013  07:11 AM             2,523 php.gif

08/30/2013  07:11 AM            46,311 php.ini-dist

08/30/2013  07:11 AM            49,953 php.ini-recommended

08/30/2013  07:11 AM            36,924 php5apache.dll

08/30/2013  07:11 AM            36,925 php5apache2.dll

08/30/2013  07:11 AM            36,927 php5apache2_2.dll

08/30/2013  07:11 AM            36,932 php5apache2_filter.dll

08/30/2013  07:11 AM            57,410 php5apache_hooks.dll

08/30/2013  07:11 AM           669,318 php5embed.lib

08/30/2013  07:11 AM            28,731 php5isapi.dll

08/30/2013  07:11 AM            28,731 php5nsapi.dll

08/30/2013  07:11 AM         4,796,472 php5ts.dll

08/30/2013  07:11 AM            86,076 php_mysqli.dll

08/30/2013  07:11 AM               135 pws-php5cgi.reg

08/30/2013  07:11 AM               139 pws-php5isapi.reg

08/30/2013  07:11 AM             1,830 snapshot.txt

08/30/2013  07:11 AM           200,704 ssleay32.dll

              35 File(s)     11,569,880 bytes

               6 Dir(s)  180,664,549,376 bytes free

remember.eps The backtick operator is disabled when safe_mode is enabled. On some systems, safe_mode is set to Off by default when PHP is installed. On other systems, safe_mode is set to On. The system administrator can change this value.

Using the system function

The system function executes a system command, displays the output, and returns the last line of the output from the system command. To execute a system command, use the following statement:

$result = system("dir c:\php");

When this statement executes, the directory listing is displayed, and $result contains the last line that was output from the command. If you echo $result, you see something like the following:

11 Dir(s)     566,263,808 bytes free

The contents of $result with the system function is the last line of the output from the dir command.

Using the exec function

The exec function executes a system command but doesn't display the output. Instead, the output can be stored in an array, with each line of the output becoming an element in the array. The last line of the output is returned.

Perhaps you just want to know how many files and free bytes are in a directory. With the following statement, you execute a command without saving the output in an array:

$result = exec("dir c:\php");

The command executes, but the output isn't displayed. The variable $result contains the last line of the output. If you echo $result, the display looks something like this:

11 Dir(s)     566,263,808 bytes free

The output is the last line of the output of the dir command. If you want to store the entire output from the dir command in an array, use the following command:

$result = exec("dir c:\php",$dirout);

After this statement, the array $dirout contains the directory listing, with one line per item. You can display the directory listing as follows:

foreach($dirout as $line)

{

   echo "$line\n";

}

The loop displays the following:

Volume in drive C has no label.

Volume Serial Number is 394E-15E5

Directory of c:\php

10/10/2013  05:43 PM    <DIR>          .

10/10/2013  05:43 PM    <DIR>          ..

10/10/2013  04:53 PM    <DIR>          dev

10/10/2013  04:53 PM    <DIR>          ext

10/10/2013  04:53 PM    <DIR>          extras

08/30/2013  07:11 AM           417,792 fdftk.dll

You can also use the following statements to get specific elements from the output array:

echo $dirout[3];

echo $dirout[7];

The output is as follows:

Directory of C:\PHP

10/10/2013  04:53 PM    <DIR>          dev

Using the passthru function

The passthru function executes a system command and displays the output exactly as it is returned. To execute a system command, use the following statement:

passthru("dir c:\php");

The statement displays the directory listing but doesn’t return anything. Therefore, you don’t use a variable to store the returned data.

The output is displayed in raw form; it isn’t processed. Therefore, this function can be used when binary output is expected.

Accessing error messages from system commands

The methods for executing system commands do not display or return an informational error message when the system command fails. You know the system command didn’t work because you didn’t get the outcome you expected. But because the functions don’t return error messages, you don’t know what went wrong.

You can return or display the operating system error message by adding a few extra characters to the system command you're executing. On most operating systems, if you add the characters 2>&1 after the system command, the error message is sent to wherever the output is directed. For example, you can use the following statement:

$result = system("di c:\php");

The system function displays the directory when the system command executes. However, notice that dir is mistyped. It is di rather than dir. No system command called di exists, so the system command can't execute, and nothing is displayed. Suppose you used the following statement instead:

$result = system("di c:\php 2>&1");

In this case, the error message is displayed. On Windows, the error message displayed is as follows:

'di' is not recognized as an internal or external command, operable program or batch file.

remember.eps Be sure you don't include any spaces in 2>&1. The format requires the characters together, without any spaces.

Understanding security issues

When you execute a system command, you allow a user to perform an action on your computer. If the system command is dir c:\php, that's okay. However, if the system command is rm /bin/* or del c:\*.*, you won't be happy with the results. You need to be careful when using the functions that execute system commands outside your script.

remember.eps As long as you execute only commands that you write yourself, such as dir or ls, you're okay. But when you start executing commands that include data sent by users, you need to be extremely careful. For example, suppose you have an application in which users type a name into a form and your application then creates a directory with the name sent by the user. The user types Smith into the form field named directoryName. Your script that processes the form has a command, as follows:

$directoryName = $_POST['directoryName'];

exec("mkdir $directoryName");

Because $directoryName = Smith, mkdir Smith is the system command that is executed. The directory is created, and everybody is happy.

However, suppose the user types Smith; rm * into the form. In this case, $directoryName =Smith;rm *. The system command that executes is now mkdir Smith;rm *. On many operating systems, such as Unix and Linux, the semicolon character separates two commands so that two commands can be entered on one line. Oops! The commands are executed as follows:

mkdir Smith

rm *

Now you have a problem. The directory Smith is created, and all the files in the current directory are removed.

If you use a variable in a system command, you must use it carefully. You must know where it came from. If it comes from outside the script, you need to check the value in the variable before using it. In the preceding example, you could add code so the script checks the variable to be sure it contains only letters and numbers before using it in the mkdir command. (Chapter 2 in this minibook describes how to use an if statement to perform such checks.)

Using FTP

Transferring files from one computer to another happens a gazillion times a day on the Internet. When colleagues on opposite sides of the country need to share files, it isn’t a problem. A quick transfer takes only seconds, and all parties have the files they need.

File Transfer Protocol (FTP) is a common way to transfer files from one computer to another. FTP allows you to get a directory listing from another computer or to download or upload a single file or several files at once.

FTP is client/server software. To use FTP to transfer files between your computer and a remote computer, you connect to an FTP server on the remote computer and send it requests.

It’s worth noting that FTP is inherently insecure, and not in a way that therapy will help. When you use FTP, your username, password, and the files themselves are passed over the network without encryption. This means that someone with enough knowledge and access to your network could “sniff” the username and password. If you’re looking for a more secure method for transferring files, look to the SCP or SFTP commands. That said, FTP is still in wide use, especially for hosting providers.

To use FTP in your scripts, FTP support needs to be enabled when PHP is installed. If you installed PHP for Windows, you don’t need to do anything extra to enable FTP support. If you’re compiling PHP on Unix, Linux, or Mac and you want to enable FTP support, you can use the FTP support installation option, as follows:

--enable-ftp

In this section, we tell you what you need to know about logging in to your FTP server, accessing a directory listing, transferring files to and from the FTP server, and using various functions to accomplish FTP-related tasks.

Logging in to the FTP server

To connect to the FTP server on the computer you want to exchange files with, use the ftp_connect function, as follows:

$connect = ftp_connect("janet.valade.com");

Or, you can connect by using an IP address, as follows:

$connect = ftp_connect("172.17.204.2");

After you connect, you must log in to the FTP server. You need a user ID and a password to log in. You might have your own personal ID and password, or you might be using a general ID and password that anyone can use. Some public sites on the Internet let anyone log in by using the user ID of anonymous and the user's e-mail address as the password. It's best for security to put the user ID and password into a separate file and to include the file when needed.

The ftp_login function enables you to log in to an FTP server after you've made the connection. This statement assumes you have your account ID and password stored in variables, as follows:

$login_result = ftp_login($connect,$userid,$passwd);

If you try to log in without establishing a connection to the FTP server first, you see the following warning:

Warning: ftp_login() expects parameter 1 to be resource, boolean given in d:\test1\test13.php on line 9

The warning doesn’t stop the program. The login fails, but the script continues, which probably isn’t what you want. Because the rest of your script probably depends on your successful FTP connection, you might want to stop the script if the functions fail. The following statements stop the script if the function fails:

$connect = ftp_connect("janet.valade.com")

           or die("Can't connect to server");

$login_result = ftp_login($connect,$userid,$passwd)

           or die("Can't login to server");

After you log in to the FTP server, you can send it requests to accomplish tasks, such as getting a directory listing or uploading and downloading files, as described in the following sections.

Getting a directory listing

One common task is to get a directory listing. The ftp_nlist statement gets a directory listing from the remote computer and stores it in an array, as follows:

$filesArr = ftp_nlist($connect,"data");

The second parameter in the parentheses is the name of the directory. If you don’t know the name of the directory, you can request the FTP server to send you the name of the current directory, as follows:

$directory_name = ftp_pwd($connect);

$filesArr = ftp_nlist($connect,$directory_name);

The directory listing that FTP sends after the ftp_nlist statement runs is stored in an array, one filename in each element of the array. You can then display the directory listing from the array, as follows:

foreach($filesArr as $value)

{

    echo "$value\n";

}

Downloading and uploading files with FTP

You can download a file from the remote computer with the ftp_get function. The following statement downloads a file from the remote computer after you're logged in to the FTP server:

ftp_get($connect,"newfile.txt","data.txt",FTP_ASCII);

The first filename, newfile.txt, is the name the file will have on your computer after it's downloaded. The second filename, data.txt, is the existing name of the file that you want to download.

The FTP_ASCII term in the statement tells FTP what kind of file is being downloaded. Here are the choices for file mode:

check FTP_ASCII: These are text files.

check FTP_BINARY: Machine language files, basically anything that isn't plain text.

tip.eps You can determine which file mode you need by examining the contents of the file. If the contents are characters that you can read and understand, the file is ASCII. If the contents appear to be garbage, the file is binary. Graphic files, for example, are binary.

You can upload a file with a similar function called ftp_put. The following statement uploads a file:

ftp_put($connect,"newfile.txt","data.txt",FTP_ASCII);

The first filename, newfile.txt, is the name the file will have on the remote computer after it's uploaded. The second filename, data.txt, is the existing name of the file that you want to upload.

When you’re finished transferring files over your FTP connection, you can close the connection with the following statement:

ftp_close($connect);

The script in Listing 3-2 downloads all the files in a directory that have a .txt extension. The files are downloaded from the remote computer over an FTP connection.

Listing 3-2: A Script to Download Files via FTP

<?php

/* Script name: downloadFiles

  * Description: Downloads all the files with a .txt

  *              extension in a directory via FTP.

  */

include("ftpstuff.inc");

$dir_name = "data/";

$connect = ftp_connect($servername)

     or die("Can't connect to FTP server");

$login_result = ftp_login($connect,$userID,$passwd)

     or die("Can't log in");

$filesArr = ftp_nlist($connect,$dir_name);

foreach($filesArr as $value)

{

    if(preg_match("#\.txt$#",$value))

    {

      if(!file_exists($value))

      {

         ftp_get($connect,$value,$dir_name.$value,FTP_ASCII);

      }

      else

      {

         echo "File $value already exists!\n";

      }

    }

}

ftp_close($connect);

?>

The script gets a directory listing from the remote computer and stores it in $filesArr. The foreach statement loops through the filenames in $filesArr and checks to see whether each file has a .txt extension. When a file has a .txt extension, the script tests to see whether a file with the same name already exists on the local computer. If a file with that name doesn't already exist, the file is downloaded; if such a file does exist, a message is printed, and the file isn't downloaded.

The script in Listing 3-2 includes a file named ftpstuff.inc. This file contains the information needed to connect to the server with FTP. The ftpstuff.inc file contains code similar to the following:

<?php

  $servername = "yourserver";

  $userID = "youruserid";

  $passwd = "yourpassword";

?>

Looking at other FTP functions

Additional FTP functions perform other actions, such as change to another directory on the remote computer or create a new directory on the remote computer. Table 3-2 contains most of the FTP functions that are available.

Table 3-2 FTP Functions

Function

What It Does

ftp_cdup($connect)

Changes to the directory directly above the current directory.

ftp_chdir($connect,"directoryname")

Changes directories on the remote computer.

ftp_close($connect)

Closes an FTP connection.

ftp_connect("servername")

Opens a connection to the computer. servername can be a domain name or an IP address.

ftp_delete($connect,"path/filename")

Deletes a file on the remote computer.

ftp_exec($connect,"command")

Executes a system command on the remote computer.

ftp_fget($connect,$fh,"data.txt",FTP_ASCII)

Downloads the file contents from the remote computer into an open file. $fh is the file handle of the open file.

ftp_fput($connect,"new.txt",$fh,FTP_ASCII)

Uploads an open file to the remote computer. $fh is the file handle of the open file.

ftp_get($connect,"d.txt","sr.txt",FTP_ASCII)

Downloads a file from the remote computer. sr.txt is the name of the file to be downloaded, and d.txt is the name of the downloaded file.

ftp_login($connect,$userID,$password)

Logs in to the FTP server.

ftp_mdtm($connect,"filename.txt")

Gets the time when the file was last modified.

ftp_mkdir($connect,"directoryname")

Creates a new directory on the remote computer.

ftp_nlist($connect,"directoryname")

Gets a list of the files in a remote directory. Files are returned in an array.

ftp_put($connect,"d.txt","sr.txt",FTP_ASCII)

Uploads a file to the remote computer. sr.txt is the name of the file to be uploaded, and d.txt is the filename on the remote computer.

ftp_pwd($connect)

Gets the name of the current directory on the remote computer.

ftp_rename($connect,"oldname","newname")

Renames a file on the remote computer.

ftp_rmdir($connect,"directoryname")

Deletes a directory on the remote computer.

ftp_size($connect,"filename.txt")

Returns the size of the file on the remote computer.

ftp_systype($connect)

Returns the system type of the remote file server (for example, Unix).

Reading and Writing Files

This book includes information about using PHP and MySQL together. In most applications, you store the data needed by the application in a MySQL database. However, occasionally you need to read or write information in a text file that isn’t a database. This section describes how to read and write data in a text file, also called a flat file.

You use PHP statements to read from or write to a flat file.

Using a flat file requires three steps:

1. Open the file.

2. Write data into the file or retrieve data from the file.

3. Close the file.

These steps are discussed in detail in the following sections.

Accessing files

The first step, before you can write information into or read information from a file, is to open the file. The following is the general format for the statement that opens a file:

$fh = fopen("filename","mode")

The variable, $fh, referred to as a file handle, is used in the statements that write data to or read data from the open file so that PHP knows which file to write into or read from. The $fh variable contains the information that identifies the location of the open file.

You use a mode when you open the file to let PHP know what you intend to do with the file. Table 3-3 shows the modes you can use.

Table 3-3 Modes for Opening a File

Mode

What It Does

What Happens When the File Doesn’t Exist

r

Read only.

A warning message is displayed.

r+

Reading and writing.

A warning message is displayed.

w

Write only.

PHP attempts to create it. (If the file exists, PHP overwrites it.)

w+

Reading and writing.

PHP attempts to create it. (If the file exists, PHP overwrites it.)

a

Append data at the end of the file.

PHP attempts to create it.

a+

Reading and appending.

PHP attempts to create it.

remember.eps The filename can be a simple filename (filename.txt), a path to the file (c:/data/filename.txt), or a URL (http://yoursite.com/filename.txt).

Opening files in read mode

You can open the file file1.txt to read the information in the file with the following statement:

$fh = fopen("file1.txt","r");

Based on this statement, PHP looks for file1.txt in the current directory, which is the directory where your PHP script is located. If the file can't be found, a warning message, similar to the following, might or might not be displayed, depending on the error level set, as described inChapter 1 of this minibook:

Warning: fopen(file1.txt): failed to open stream: No such file or directory in d:\test2.php on line 15

warning_bomb.eps Remember, a warning condition doesn’t stop the script. The script continues to run, but the file doesn’t open, so any later statements that read or write to the file aren’t executed.

You probably want the script to stop if the file can't be opened. You need to do this yourself with a die statement, as follows:

$fh = fopen("file1.txt","r")

           or die("Can't open file");

The die statement stops the script and displays the specified message.

Opening files in write mode

You can open a file in a specified directory to store information by using the following type of statement:

$fh = fopen("c:/testdir/file1.txt","w");

If the file doesn’t exist, it is created in the indicated directory. However, if the directory doesn’t exist, the directory isn’t created, and a warning is displayed. (You must create the directory before you try to write a file into the directory.)

You can check whether a directory exists before you try to write a file into it by using the following statements:

If(is_dir("c:/tester"))

{

    $fh = fopen("c:/testdir/file1.txt","w");

}

With these statements, the fopen statement is executed only if the path/filename exists and is a directory.

Opening files on another website

You can also open a file on another website by using a statement such as the following:

$fh = fopen("http://janet.valade.com/index.html","r");

tip.eps You can use a URL only with a read mode, not with a write mode, and there are better ways to do this — namely, the cURL functions. See the PHP manual at http://php.net/manual/en/book.curl.php for more information on the cURL functions.

Closing a file

To close a file after you have finished reading or writing it, use the following statement:

fclose($fh);

In this statement, $fh is the file handle variable you created when you opened the file.

Writing to a file

After you open the file, you can write into it by using the fwrite statement, which has the following general format:

fwrite($fh,datatosave);

In this statement, $fh is the file handle that you created when you opened the file containing the pointer to the open file, and datatosave is the information to be stored in the file. The information can be a string or a variable. For example, you can use the following statements:

$today = date("Y-m-d");

$fh = fopen("file2.txt","a");

fwrite($fh,"$today\n");

fclose($fh);

These statements store the current date in a file called file2.txt. Notice that the file is opened in append mode (a). If the file doesn't exist, it is created, and the date is written as the first line. If the file exists, the date is added to the end of the file. In this way, you create a log file that stores a list of the dates on which the script is run. The fwrite statement stores exactly what you send. After the fwrite statement executes twice, file2.txt contains:

2013-10-22

2013-10-22

The dates appear on separate lines because the new line character (\n) is written to the file.

warning_bomb.eps Be sure to open the file with the a mode if you want to add information to a file. If you use a write mode, the file is overwritten each time it's opened.

Reading from a file

You can read from a file by using the fgets statement, which has the following general format:

$line = fgets($fh)

In this statement, $fh holds the pointer to the open file. This statement reads a string until it encounters the end of the line or the end of the file, whichever comes first, and stores the string in $line. To read an entire file, you keep reading lines until you get to the end of the file. PHP recognizes the end of the file and provides a function feof to tell you when you reach the end of the file. The following statements read and display all the lines in the file:

while(!feof($fh))

{

   $line = fgets($fh);

   echo "$line";

}

In the first line, feof($fh) returns true when the end of the file is reached. The exclamation point negates the condition being tested, so that the while statement continues to run as long as the end of the file isn't reached. When the end of the file is reached, while stops.

If you use these statements to read the log file created in the preceding section, you get the following output:

2013-10-22

2013-10-22

As you can see, the new line character is included when the line is read. In some cases, you don’t want the end of line included. If so, you need to remove it by using the following statements:

while(!feof($fh))

{

   $line = rtrim(fgets($fh));

   echo "$line";

}

The rtrim function removes any trailing blank spaces and the new line character. The output from these statements is as follows:

2013-10-222013-10-22

Reading files piece by piece

Sometimes you want to read strings of a certain size from a file. You can tell fgets to read a certain number of characters by using the following format:

$line = fgets($fh,n)

This statement tells PHP to read a string that is n-1 characters long until it reaches the end of the line or the end of the file.

For example, you can use the following statements:

while(!feof($fh))

{

   $char4 = fgets($fh,5);

   echo "$char4\n";

}

These statements read each four-character string until the end of the file. The output is as follows:

2013

-10-

22

2013

-10-

22

Notice that there’s a new line at the end of each line of the file.

Reading a file into an array

It’s often handy to have the entire file in an array. You can do that with the following statements:

$fh = fopen("file2.txt","r");

while(!feof($fh))

{

   $content[] = fgets($fh);

}

fclose($fh);

The result is the array $content with each line of the file as an element of the array. The array keys are numbers.

PHP provides a shortcut function for opening a file and reading the entire contents into an array, one line in each element of the array. The following statement produces the same results as the preceding five lines:

$content = file("file2.txt");

The statement opens file2.txt, puts each line into an element of the array $content, and then closes the file.

warning_bomb.eps The file function can slow down your script if the file you're opening is really large. How large depends on the amount of available computer memory. If your script seems slow, try reading the file with fgets rather than file and see whether that speeds up the script.

You can direct the file function to automatically open files in your include directory (described in Chapter 2 of this minibook) by using the following statement:

$content = file("file2.txt",1);

The 1 tells PHP to look for file2.txt in the include directory rather than in the current directory.

Reading a file into a string

Sometimes putting the entire contents of a file into one long string can be useful. For example, you might want to send the file contents in an e-mail message. PHP provides a function for reading a file into a string, as follows:

$content = file_get_contents("file2.txt",1);

The file_get_contents function works the same as the file function, except that it puts the entire contents of the file into a string rather than an array. After this statement, you can echo $content as follows:

echo $content;

The output is the following:

2013-10-22

2013-10-22

The output appears on separate lines because the end-of-line characters are read and stored as part of the string. Thus, when you echo the string, you also echo the end-of-line characters, which start a new line.

warning_bomb.eps The file_get_contents function was introduced in version 4.3.0. It isn't available in older versions of PHP.

Exchanging Data with Other Programs

You might sometimes need to provide information to other programs or read information into PHP from other programs. Flat files are particularly useful for such a task, and we explain how to perform that kind of task here.

Exchanging data in flat files

Almost all software has the capability to read information from flat files or write information into flat files. For example, by default, your word processor saves your documents in its own format, which only the word processor can understand. However, you can choose to save the document in text format instead. The text document is a flat file containing text that can be read by other software. Your word processor can also read text files, even ones that were written by other software.

When your PHP script saves information into a text file, the information can be read by any software that has the capability to read text files. For example, text files can be read by most word processing software. However, some software requires a specific format in the text file. For example, an address book software application might read data from a flat file but require the information to be in specified locations — for example, the first 20 characters in a line are read as the name, the next 20 characters are read as the street address, and so on. You need to know what format the software requires in a flat file. Then write the flat file in the correct format in your PHP script by using fwrite statements, as discussed in the section Writing to a file, earlier in this chapter.

Exchanging data in comma-delimited format

A comma-separated values (CSV) file — also called a comma-delimited file — is a common format used to transfer information between software programs.

Understanding comma-delimited format

A CSV file is used to transfer information that can be structured as a table, organized as rows and columns. For example, spreadsheet programs organize data as rows and columns and can read and write CSV files. A CSV file is also often used to transfer data between different database software, such as between MySQL and Microsoft Access. Many other software programs can read and write data in CSV files.

A CSV file is organized with each row of the table on a separate line in the file, and the columns in the row are separated by commas. For example, an address book can be organized as a CSV file, as follows:

John Smith,1234 Oak St.,Big City,OR,99999

Mary Jones,5678 Pine St.,Bigger City,ME,11111

Luis Rojas,1234 Elm St.,Biggest City,TX,88888

Excel can read this file into a table with five columns. The comma signals the end of one column and the start of the next.

Creating a comma-delimited file

The following PHP statements create the CSV file:

$address[] = "John Smith,1234 Oak St.,Big City,OR,99999";

$address[] = "Mary Jones,5678 Pine St.,Bigger City,ME,11111";

$address[] = "Luis Rojas,1234 Elm St.,Biggest City,TX,88888";

$fh = fopen("addressbook.txt","a");

for ($i=0;$i<3;$i++)

{

   fwrite($fh,$address[$i]."\n");

}

fclose($fh);

Reading a comma-delimited file

PHP can read the CSV file by using either the file or the fgets function, as described in the section Reading a file into an array, earlier in this chapter. However, PHP provides a function called fgetcsv that's designed specifically to read CSV files. When you use this function to read a line in a CSV file, the line is stored in an array, with each column entry in an element of the array. For example, you can use the function to read the first line of the address book CSV file, as shown here:

$address = fgetcsv($fh,1000);

In this statement, $fh is the file handle, and 1000 is the number of characters to read. To read an entire line, use a number of characters that is longer than the longest line. The result of this statement is an array, as follows:

$address[0] = John Smith

$address[1] = 1234 Oak St.

$address[2] = Big City

$address[3] = OR

$address[4] = 99999

Using other delimiters

The CSV file works well for transferring data in many cases. However, if a comma is part of the data, commas can’t be used to separate the columns. For example, suppose one of the data lines is this:

Smith Company, Inc.,1234 Fir St.,Big City,OR,99999

The comma in the company name would divide the data into two columns — Smith Company in the first and Inc. in the second — making six columns instead of five.

tip.eps When the data contains commas, you can use a different character to separate the columns. For example, tabs are commonly used to separate columns. This file is called a tab-separated values (TSV) file, or a tab-delimited file. You can write a tab-delimited file by storing "\t"rather than a comma in the output file.

You can read a file containing tabs by specifying the column separator in the statement, as follows:

$address = fgetcsv($fh,1000,"\t");

You can use any character to separate columns.

The script in Listing 3-3 contains a function that converts any CSV file into a tab-delimited file.

Listing 3-3: A Script That Converts a CSV File into a Tab-Delimited File

<?php

/* Script name: Convert

  * Description: Reads in a CSV file and outputs a

  * tab-delimited file. The CSV file must have a

  * .CSV extension.

  */

  $myfile = "testing"; →7

  function convert($filename) →8

  {

    if( @$fh_in = fopen("{$filename}.csv","r")) →10

    {

      $fh_out = fopen("{$filename}.tsv","a"); →12

      while( !feof($fh_in)) →13

      {

        $line = fgetcsv($fh_in,1024); →15

        if( $line[0] == "") →16

        {

          fwrite($fh_out,"\n");

        }

        else { →20

          fwrite($fh_out,implode($line,"\t")."\n"); →21

        }

      }

      fclose($fh_in);

      fclose($fh_out);

    }

    else { →27

      echo "File doesn't exist\n";

      return false;

    }

    echo "Conversion completed!\n";

    return true; →32

  }

  convert($myfile); →34

?>

The following points refer to the line numbers in the Listing 3-3:

7 This line defines the filename as testing.

8 This line defines a function named convert() with one parameter, $filename.

10 This line opens a file that has the filename that was passed to the function with a .csv extension. The file is opened in read mode. If the file is opened successfully, the conversion statements in the if block are executed. If the file isn't found, the else block beginning on Line 27 is executed.

12 This line opens a file that has the filename that was passed to the function with a .tsv extension. The file is opened in append mode. The file is in the current directory in this script. If the file is in another directory where you think there is any possibility the file might not open in write mode, use an if statement here to test where the file opened and perform some action if it did not.

13 This line starts a while loop that continues to the end of the file.

15 This statement reads one line from the input file into the array $line. Each column entry is stored in an element of the array.

16 This statement tests whether the line from the input file has any text on it. If the line doesn’t have any text, a new line character is stored in the output file. Thus, any empty lines in the input file are stored in the output file.

20 If the line from the input file isn’t empty, it’s converted to a tab-delimited format and written into the output file.

21 This statement converts the line and writes it to the output file in one statement. The implode function converts the array $line into a string, with the elements separated by a tab.

27 This else block executes when the input file can't be found. An error message is echoed, and the function returns false.

32 The function has completed successfully, so it returns true.

34 This line calls the function, passing a filename to the function in the variable $myfile.

Using SQLite

Beginning with PHP 5.0, PHP includes the SQLite software by default. SQLite is designed to store data in a flat file using SQL queries. (SQL is explained in Book V, Chapter 1.)

SQLite is a quick, easy way to store data in a flat file. However, it’s less secure than a database and can’t handle complex data. In most cases, you should store your data in MySQL, but you occasionally might want to store your data in a flat file. For example, you might want to write the data in a format that can be read by another program, such as Excel.

Storing and retrieving data with SQLite is similar to the methods described in Book V for using MySQL with PHP. You use SQL to communicate with the data file and use PHP functions to send the SQL and retrieve the data. You interact with the data by using the same steps that you use with a database, as follows:

1. Connect to the data file.

2. Send an SQL query.

3. If you retrieved data from the data file, process the data.

4. Close the connection to the data file.

Here are more details on how to complete each of those steps.

To connect to the data file, use the following PHP function:

$db = sqlite_open("testdb");

This statement opens the data file testdb. If the file doesn't exist, the function creates it.

To send an SQL query, use the sqlite_query function, as follows:

$sql = "SELECT * FROM Product";

$result = sqlite_query($db,$sql);

The retrieved data is stored in a temporary table in rows and columns. You can use PHP functions to retrieve one row from the temporary data table and store it in an array, with the field names as the array keys. The statement is as follows:

$row = sqlite_fetch_array($result);

After this statement, $row is an array containing all the fields in the temporary table, such as the following:

$row['firstName'] = John

$row['lastName'] = Smith

To process all the data in the temporary table, you can use a loop to get one row at a time, processing each row until the end of the table is reached, as follows:

while($row=sqlite_fetch_asoc($result))

{

   foreach($row as $value)

   {

      echo "$value<br />";

   }

}

When you finish storing and/or retrieving data, you can close the data file with the following statement:

sqlite_close($db);

Error handling for SQLite is similar to MySQL error handling, as explained in Book V, Chapter 5. Also, as discussed in that chapter, when the query fails, an SQLite error message is generated, but not displayed unless you use a function developed specifically to display it. Thus, the following statements handle errors in addition to sending the SQL query:

--

$sql = "SELECT * FROM Product";

$result = sqlite_query($sql)

       or die("Query failed: ".sqlite_error());

$row = sqlite_fetch_array($result);

Most of the information in Book V about MySQL applies to the use of SQLite as well. What makes SQLite different is that the data is stored in a flat file, rather than stored by MySQL in files that are unique to MySQL.