Command Line PHP – Part 1

Posted by Nessa | Posted in ,,, | Posted on May 18, 2010

15

PHP isn’t just for websites anymore. In fact, almost every script I’ve written to perform server-side functions is either written in bash or PHP, rather than Perl or Python as preferred by my colleagues. It’s a common belief that PHP isn’t suited for CLI programming since it’s mainly used in web applications, but PHP has over a hundred functions specifically intended for system management.

These kinds of posts can be rather lengthy, so I’m making this into a series with three parts.  Part 1 will go over the basic filesystem functions. You can find a complete listing here, but I’ll just go over a few of the more important and common ones.

The hashbang

As with any CLI script, the first line of your PHP script should contain the executable binary for PHP. You can usually find this by running:

which php

On my server the location is /usr/bin/php, so here’s the first line of my script:

#!/usr/bin/php

If you installed PHP in a custom location, you’ll need to specify that binary instead. You can also specify command line options like -f, -c, etc.  Then set the permissions of your script to 755 to allow it to execute.

Accepting arguments with PHP

A major part of CLI scripting is the ability to accept arguments. For this, we’ll write a simple script called asl.php which will parse my name, sex, and location as arguments:

[nessa@server] ./test.php 23 female virginia

Here’s the script:

#!/usr/bin/php
<?php

print_r($argv);

?>

The $argv variable is native, and parses as an array. So running this script will produce the following output:

Array
(
[0] => ./asl.php
[1] => 23
[2] => female
[3] => virginia
)

So if I only wanted to echo out my age, I can use the following code:

echo $argv[1];

If you notice, there are four values instead of the three that I passed. As with most scripting languages, PHP considers the filename as the first (0) variable. To remove the first variable, use the array_shift function:

array_shift($argv);

This means now that using value #1 as shown in the example above will output “female” instead of 23, making the command line order more correct, but this tends to be confusing for some people since it makes the first value 0 instead of 1. I usually prefer NOT to shift the array unless having the file name in there is going to adversely affect the intended functionality of the script.

From here ( keeping in mind that I’m not shifting the array anymore), I can assign the arguments to variables and access them from the script:

$age = $argv[1];
$gender = $argv[2];
$location = $argv[3];
// echo out the values
echo "Hello, I am $age-year-old $gender from $location";

In some cases you may want to validate the number of arguments passed, or what they contain. For instance, the below example is requiring that all three variables are passed (however, the code says four, since you have to include the script name as the first “argument”, as mentioned before):

if ($argc != 4) {
die("Usage: asl.php <age> <gender> <location>\n");
}

You can of course specify less than (<) or greater than (>) values operators.  In the next example, I want to make sure that the “age” argument is a number:

if (!is_numeric($age)){
die("$age is not a number");
}

I’m sure by now you get the idea =)

PHP File and Folder Management

Creating files and folders, and checking their accessibility

Continuing my above example, I want to end up with a file in /opt/app/users called “users.txt” that contains a list of all the output of asl.php. I first need to see if  /opt/app/users exists using the is_dir function, and if it doesn’t, create it with mkdir, then enter into that directory with chdir:

$dirname = "/opt/app/users;
if(!is_dir($dirname)){
mkdir($dirname, 0755);
}
chdir($dirname);

What if /opt/app doesn’t exist and I need to create the entire structure? The mkdir function has a recursive flag that is set to false by default, but can be enabled as so:

$dirstructure = "/opt/app/users";

if (!mkdir($dirstructure, 0, true)) {
die('Failed to create folders!');
}

Now that the folders are created and verified, I use file_exists and is_readable to make sure that my users.txt file is there and can be seen. If not, we’ll use one of the file functions to create it:

$cwd = getcwd();
$filename = $cwd . "/users.txt;
if(file_exists($filename) && is_readable($filename)){
echo "File Exists and is readable";
}else{
echo "File does not exist or is not readable";

touch($filename);
}

If you notice, I added the getcwd function to look for a file called users.txt in my current directory. If you need to see whether a file is executable instead of readable, you can simply use the is_executable function, or to see if it’s writable, use is_writable:

$filename = '/opt/app/users/users.txt';

if (!is_executable($filename)) {
echo $filename.' is not executable';
}
if (!is_writable($filename)) {
echo $filename.' is not writable';
}

Note that the result of these commands is based on the user running them. For instance, if the file is owned by the user root and is set to 600 permissions (root read/write only), but the user ‘user1′ is running the script, the tests in the above lines of code will fail since that user does not have permissions to the file in question.

Creating and deleting files

There are a few functions you can use to create files with PHP. Here are the most commonly used: fopen, file_put_contents, touch, If you want to delete a file, simply use unlink.  In the below example

$filename = "/opt/app/users/users.txt";
unlink($filename);

Unlink is not to be confused with the opposite of symlink, which creates a symbolic link  (shortbut) between files:

symlimk("/opt/app/users/users.txt", "/home/nessa/Desktop/users.txt-shortcut");

And rmdir will remove a folder:

if (!is_dir('temp')) {
mkdir('temp');
}
rmdir('temp');

Writing to files

The most common way to write to files is using the fopen function. Using my original example, asl.php is going to write the values of the arguments to a file called users.txt:

$filename = "/opt/app/users/users.txt";
$fh = fopen($filename, 'w') or die("can't open file");
$data = $age . $gender . $location;
fwrite($fh, $date);
fclose($fh);

Reading contents of a file

If you want the script to read the file, you can use a number of function such as readfile, file_get_contents, fopen, fread, and file. The actual function you would use depends on what you’re planning on doing with the data. If you simply want to display the contents of the file as a string:

$filename = "/opt/app/users/users.txt";
$data = file_get_contents($filename);
echo $data;

Will display:

23 female virginia

If you need a more programmatic way of displaying the data, such as reading each column as a set of values (like if you’re inserting all this into a database), you’d use the file() function which will load the contents of the file into an array. Here’s a simple loop that echoes out each line in the file:

$filename = "/opt/app/users/users.txt";
$lines = file($filename);

foreach ($lines as $line_num => $line)
{
print "{$line_num} : " . $line . "\n";
}

Reading contents of a folder

You can use the opendir function to run a loop and read the contents of a folder:

// open the current directory by opendir

$dirname = "/opt/app";
$handle=opendir($dirname);

while (($file = readdir($handle))!==false) {
echo "$file \n";
}

closedir($handle);

Changing permissions and ownership:

In the above example where I was checking to see if the file was readable, I didn’t actually specify anything to address permissions – instead, I just created the file. To change the permissions or ownership of files, you can use the chmod and chown functions.

$filename = "/opt/appf/users/users.txt";
$username = posix_getpwuid(fileowner($filename));

// Get the octal value of permissions
$perms = substr(sprintf('%o', fileperms($filename')), -4);

if($username[name] != "nessa" && $perms != "0755" ){
chmod($filename, 0755);
chown($filename, "nessa");
echo "Permissions fixed";
}else{
echo "Permissions are correct";

If you want to change the umask (that is, the default permissions of files created by the script), you can use the umask function – which actually revokes permissions instead of setting them.

Copying, moving, and renaming

Say I want to rename the /opt/app folder to /etc/app. I’d use the rename function as so, validating on whether of not it was renamed successfully:

if(!rename("/opt/app","/etc/app")){
echo "Rename failed";
}

You can also use the copy function to copy files, noting that if the “new” file or folder already exists, it will be overwritten.

if(!copy("/opt/app","/etc/app")){
echo "Copy failed";
}

User and File information

Getting user and group data

The fileowner function as shown above will return the UID of the file, but I specified the username. You can use posix_getpwuid to return an array with the user’s information in a more usable format:

$filename = "/opt/app/users/users.txt";
$username = posix_getpwuid(fileowner($filename));print_r($username);

Will return:

Array
(
[name] => nessa
[passwd] => x
[uid] => 1000
[gid] => 1000
[gecos] => Vanessa V.,,,
[dir] => /home/nessa
[shell] => /bin/bash
)

So you can simply echo out the array values of $username based on the keys. For example, to get the shell of the user in the above example, simply echo to the ‘shell’ key from the $username array:

echo $username[shell];

If you want to get group information for a file, you can use the same method, but with filegroup and posix_getgrgid:

$filename = "/opt/app/users/users.txt";
print_r(posix_getgrgid(filegroup($filename)));

Getting file information

You can also get information about a file using the stat or fstat functions, which return the results to an array:

$filename = "/opt/app/users/users.txt";
$stat = stat($filename);
print_r($stat);

Will return a giant array of information for the file. If you only want to return one value, say, the size, echo it out like you would a normal array:

echo $stat[size];

So here we’ve finished the first part of PHP command line scripting, which covered the use of files, folder, and users. The next parts will go over command execution and process management.

See: Command Line PHP: Part 2, Command Line PHP: Part 3

Be Sociable, Share!

Comments (15)

Any alternative to running which then entering the output ( and for better support of different systems ) try this for the hashbang:

#!/bin/env php

Marco

[...] Więcej: v-nessa.net » Post Archive » Command Line PHP – Part 1 [...]

Great article! But I got a remark:
PHP caches the results of file_exists(), is_readable() a.s.o. I am not sure whether this behaviour is disabled on CLI scripts by default.
If not you might want to use clearstatcache(). I am not very familiar with those thing but maybe you want to do some research on this.

Best regards
Benjamin

I’ve have written a ton of CLI PHP apps for things ranging from simple DB stuff to Daemons to do COMET stuff with an Asterisk PBX. PHP rocks. =)

[...] post is continuing on my three-part series on command line PHP programming. Missed part one? It’s right behind you. This part will go over command execution and [...]

@Marco that should probably be #!/usr/bin/env

[...] Command Line PHP – Part 1 [...]

[...] Command Line PHP: Part 1 [...]

This site is very good, It has very good articles.

thanks dear

cheers………..

[...] largement ignorée par les développeurs PHP. Pour remédier à cela Vanessa Vasile a publié une série d'articles montrant comment utiliser PHP pour créer des scripts exécutables en ligne de [...]

@Marco that should probably be #!/usr/bin/env

To learn php,html,javascript,ajax,mysql,jquery with advanced concepts, you can visit Advanced PHP Tutorial

Though this people become perfect

setting help line36 error

Post a comment