PHP 1.29 - Working With File System In PHP
You will need to work with the files and file system in PHP at some point, so let's cover the basics. The first function is the scandir()
, and that will just list all files and directories within the given path:
<?php
$dir = scandir(__DIR__);
var_dump($dir);
array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(9) "index.php" }
I use the magic constant __DIR__
to specify the current directory.
We get . which refers to the current directory, we get .. which refers to the parent directory, and we get index.php which is the only file in this directory.
You could then use a loop to loop through these files and determine what you want to do with them. You could use things like is_dir()
or is_file()
to check whether a file is a directory or a file. We could access the third element of the array, which is index.php, and we can check if it's a file, and it will print true. And we can check if it's a directory, and it will print false:
<?php
$dir = scandir(__DIR__);
var_dump(is_dir($dir[2]));
var_dump(is_file($dir[2]));
bool(false) bool(true)
You could create a new directory using mkdir()
function and delete a directory using rmdir()
. So for example, we could do mkdir('foo'), and then you could pass the permissions as a second argument, and the third argument is whether you want to create directories recursively or not. So let's create a directory foo, and if we refresh, we open the project, we see the directory foo is created:
<?php
mkdir('foo');
We can then delete the directory foo using rmdir()
, and if we refresh the page, the directory is gone:
<?php
rmdir('foo');
Just a quick note that when deleting a directory, it has to be an empty directory, otherwise you'll get a warning.
As mentioned, you could create directories recursively, so you could do mkdir('foo/bar', recursive: true), and now if we refresh the page and we open the project, we have foo folder and bar folder inside.
You could check if a file or directory exists and print the file size using file_exists()
and filesize()
. If the file or directory exists, you can use a function called file_exists()
. So we could do:
<?php
if (file_exists('foo.txt')) {
echo filesize('foo.txt');
} else {
echo 'File not found';
}
File not found
If we refresh the page, we'll get "file not found". Let's create a boot.txt and put "hello world" in there. And if we refresh, now we get 12:
<?php
if (file_exists('foo.txt')) {
echo filesize('foo.txt');
} else {
echo 'File not found';
}
12
Something to be aware of here is that you can clear cached values of functions like filesize()
using clearstatcache()
. PHP will cache the return values of some of the file-related functions for better performance. The function filesize()
is one of them. Just something to keep in mind when working with these functions.
Alright, let's actually move on to opening files and working with the resource data type using fopen()
. So let's try to open foo.txt. We can do:
<?php
$file = fopen('foo.txt', 'r');
And the second parameter 'r' specify the mode here. I will leave the link at the end of the lesson where you can check all the available modes. But for now, let's open that file for reading.
The result of fopen() is what's called a resource. A resource is a data type that refers to an external resource. It is a reference to that external resource, which can be a stream, file, and so on. There are functions in PHP that create, return, and work with resources, and fopen() is one of them.
In addition to opening local files, you can also open remote files by specifying a URL. However, that might not always work because opening files remotely might be disabled by the server.
Using the error control operator '@' to suppress warnings: fopen() will return false and emit a warning if the file is not found. Sometimes developers use the error control operator @ to suppress this warning. You may or may not have seen this before, but you might come across it eventually in some code bases.
So if we try to open a file that doesn't exist, something like fullbar.txt, we're going to get a warning and it will return false:
<?php
$file = fopen('foobar.txt', 'r');
Warning: fopen(foobar.txt): Failed to open stream: No such file or directory
And what they do is that they suppress this warning using the '@' symbol. So the warning is gone, and they check if their return is false to see if the file was opened successfully or not.
This is not good, and you should avoid suppressing any errors. Instead, consider building a better error handling mechanism. Instead of suppressing errors, what you can do is use other functions to check if the file actually exists. So you could do:
<?php
if (!file_exists('foobar.txt')) {
echo 'File not found';
return;
}
File not found
Now let's read this file line by line using fgets()
and fclose()
. We could use a loop here:
<?php
if (!file_exists('foo.txt')) {
echo 'File not found';
return;
}
$file = fopen('foo.txt', 'r');
while (($line = fgets($file)) !== false) {
echo $line . '<br />';
}
hello world
If we refresh the page, we see "Hello world" because that's the only line in the file.
Let's split the line in 'foo.txt' into two lines. If we refresh again, now we see two lines:
hello
world
What's happening here is that we read a line from the file using fgets()
function and assign it to a variable called $line
. Then we loop for every line until the returned value from fgets()
is false. Note the use of strict comparison here because the returned value from fgets()
might be a value that could evaluate to false, so doing a loose comparison could result in unexpected bugs. Finally, after we're done working with the resource or file, we just close that file using the fclose()
function.
You can also write into a file using the fwrite()
function, and you can also read from a CSV file using fgetcsv()
. fgetcsv()
is similar to fgets()
, but it parses the line when it reads it and returns an array that contains the fields it has read. The default delimiter for fields is a comma, but you can change that by specifying it as one of the arguments.
So if we change this fgets() to fgetcsv() and let's put a comma-separated file here, let's save that. And now we can do print_r($line), let's remove the line break, and if we refresh, we see that the zeroth index is a, one is b, and two is c. And then the second line is f, and the third line is g h i.
Another way of reading file content is by using the file_get_contents() function, which will store the file content into a variable. So we could do $content = file_get_contents('full.txt'), and you could specify the full path here. And then echo $content. If we refresh, we get "Hello world".
You can also specify the offset and length to get the content at a specific location. So we could use named arguments for that, and we could do offset: 3, length: 2. If we refresh, we get "l" and "o".
You can also get the content of a remote file by specifying the URL, though this might not always work depending on the configuration on that server. I would not necessarily use file_get_contents() to get the content of a remote file. There is a better way to get the content of a file from a remote server and make HTTP requests by using a library called cURL. We'll cover cURL in a separate video, so don't worry about it now.
You can write content to a file using the file_put_contents() function, which basically does the same thing as fopen(), fwrite(), and fclose() combined. If the file does not exist, it will create it; otherwise, it will overwrite it. You can also have content appended instead of overwriting it by specifying the FILE_APPEND flag as the third argument.
For example, we're trying to put "Hello" into bar.txt, and because bar.txt does not exist, it will create that file and put "Hello" in it. So if we refresh the page, we see that bar.txt was created and it contains the content that we passed.
Let's call it again and now let's put the word "world". If we refresh the page, we open bar.txt, and as you can see, "Hello" was overwritten by "world". We could append this instead of overwriting by specifying the third argument, which is the constant FILE_APPEND. Now, if we refresh the page, we'll get "Hello world".
To delete files, you could use a function called unlink(). So we could do unlink('bar.txt'), and if we refresh, we see that bar.txt is gone.
You could copy a file using a function called copy(). So let's copy boot.txt into bar.txt. If we refresh the page, we see that bar.txt was created, which is identical to boot.txt. If the file already existed at the destination, it would overwrite it instead.
If you want to move the file instead of copying, you could use a function called rename(). rename() will work for both files and directories. So we could do rename('boot.txt', 'bar.txt'), and if we refresh the page, we see that boot.txt is gone, and we're just left with bar.txt.
Finally, to get information about a file, you can use a function called pathinfo(), which will return an array containing things like the file name, extension, base name, and so on.
That's it for this video. Thank you so much for watching. If you liked my tutorials, please give this video a thumbs up, share, and subscribe. I will see you in the next one.