#	Uploading a ZIP File

It is easy enough to upload and process a single file in PHP, but uploading a folder full of data will need a different approach.

The simplest way to upload a folder is to Zip it first and upload the file. At the server end, we can unzip it and put the contents into a nominated folder.

Here will look at how to process a zip file full of individual files. In this case, we won’t have any nested folders, which will simplify the process.

##	The Upload Button

To begin with, we will need an upload button.

```html
<form method="post" enctype="multipart/form-data" action="">
	<label for="import-folder">Import Folder</label>
	<input type="file" name="import-folder" accept="application/zip">
</form>
```

-	Like all upload forms, you need to include `method="post"` and the `enctype="multipart/form-data"`. The action can be anywhere, of course.
-	For convenience we can include `accept="application/zip"` which will cause the browser to check for a zip file; however, we will check the uploaded file at the PHP end as well.

##	Processing the File

When we upload the file, we will first need to check the Mime Type. Here, we can write a `MimeType()` function which is a wrapper around something more complex, and it would be a good idea to include it in whatever library you normally use.

```php
function MimeType($filename) {
	$finfo = new finfo(FILEINFO_MIME_TYPE);
	return $finfo->file($filename);
}
```

This is more reliable than depending on the Mime Type from the `$_FILES` array, since that can be faked, or, at least, inaccurate.

Like all uploaded files, the data will appear in the `$_FILES` array. In our example, it will be in `$_FILES['import-folder']`.

For convenience we can assign this to a simple variable, to make the rest of the code easier to manage.

```php
//	Import Images Folder
	$import = $_FILES['import-folder'];
	if(!$import['error'] && MimeType($import['tmp_name']) == 'application/zip') {

	}
```

`$import['tmp_name']` has the current location of the uploaded file, which we can leave where it is. If we decide we don’t want to go ahead, for example if the Mime Type is wrong, the file will be automatically deleted when the script is complete.

`$import['error']` will be non-zero if there is an error, or 0 if it has been successfully uploaded. Here we foregoing proper error handling.

Apart from the Mime Type, the most obvious error will be `Error 2`, which is that the uploaded file is too big. The maximum file size is preset in PHP, but can be overridden using the `.htaccess` file:

```conf
#	Uploads
	php_value	post_max_size 40M
	php_value	upload_max_filesize 20M
```

The `post_max_size` is the maximum for the whole of the form, while the `upload_max_filesize` is for a single file.

##	Extracting the Files

We will copy all of the files into a designated upload folder. PHP has a built-in class, called `ZipArchive`, to do this, but the process will be complicated by the fact that the ZIP file probably contains a folder with the files; we want the contents, but not the folder.

To use the `ZipArchive` class, we create a new object, and then `open()` the archive, process it, and `close()` it.

```php
$zip = new ZipArchive;
$zip->open($import['tmp_name']);
$zip->close();
```



Although there is a a built-in `extractTo()` method, it includes the folders, so we will have to iterate through the files ourselves, and read off the individual file names using the `getNameIndex()` method.

```php
for($i=0; $i<$zip->numFiles; $i++) {
     $source=$zip->getNameIndex($i);
     if(substr($source,-1) == '/') continue;
}
```

`substr($source,-1)` is the last character of a string. If it is `/`, then the string must be a folder, so we skip it.


After that, we will use `basename()` to read only the file name without preceding folders, and copy from the ZIP file to our upload folder using the special `zip://` protocol:

```php
$name=basename($source);
copy("zip://{$import['tmp_name']}#$source","upload/$name");
```

##	The Complete Code

The whole process is as follows:

```php
$import = $_FILES['import-folder'];
if(!$import['error'] && MimeType($import['tmp_name']) == 'application/zip') {
   $zip = new ZipArchive;
   $zip->open($import['tmp_name']);
		for($i=0; $i<$zip->numFiles; $i++) {
			$source=$zip->getNameIndex($i);
			if(substr($source,-1) == '/') continue;
			$name=basename($source);
			copy("zip://{$import['tmp_name']}#$source","upload/$name");
		}
	$zip->close();
}
```

###	An Unzip Function

If you’re going to make a habit of uploading zip files, you might want to add the following function to your library:

```php
function unzip(string $zipFile, string $destination) {
	$zip = new ZipArchive();
	$zip->open($zipFile);
	for($i=0; $i<$zip->numFiles; $i++) {
		$file=$zip->getNameIndex($i);
		if(substr($file,-1) == '/') continue;
		$name=basename($file);
		copy("zip://$zipFile#$file","$destination/$name");
	 }
	$zip->close();		
}
```

The preceding example would then look like this:

```php
$import = $_FILES['import-folder'];
if(!$import['error'] && MimeType($import['tmp_name']) == 'application/zip') {
	unzip($import['tmp_name'],"upload/$name");
}
```
