Può capitare di dover installare un pacchetto con numerosi file in un hosting da luoghi dove non è consentito l’accesso ai domini di tipo ftp.
Un webmaster non può vivere senza un buon client ftp, che gli consente di trasferire in maniera pratica ogni tipo di files verso e da un hosting web. Non è però sempre possibile poter utilizzare questi strumenti ovunque, perché esistono reti limitate (uffici, scuole) dove il protocollo ftp è bloccato, e quindi sarà difficoltoso raggiungere il vostro hosting per poter caricare/scaricare files. L’unica soluzione è usare un webclient ftp, ma quali sono i limiti?
Il problema nell’uso di un webclient ftp si presenta quando dobbiamo installare un pacchetto contenente tantissimi files, perché lo svantaggio del webclient ftp è che è possibile creare 1 cartella, e caricare 1 file alla volta (a seconda del webclient). Ciò significa che se vogliamo caricare un’installazione di WordPress, di phpBB, o altri strumenti tramite webclient sarà tanto difficile. Con un client come Filezilla o WinSCP è possibile caricare direttamente tutta la cartella già scompattata con un semplice drag&drop, operazione non possibile con un webclient.
Parecchi hosting offrono webclient FTP che permettono il caricamento in formato archivio, in modo da caricare un file pacchetto.zip, e di ritrovarci sull’host una cartella chiamata pacchetto, ma non sempre quest’operazione è fattibile perché a volte il numero di files all’interno di questi archivi è così elevato da mandare la procedura in timeout o generare altri errori.
La migliore soluzione che ho trovato è proposta da Andreas Tasch, austriaco, che permette l’estrazione di un pacchetto .zip tramite uno script in PHP in modo facile e veloce, e senza rischiare timeout. Ho testato la potenza di questo script, e sono riuscito a scompattare archivi di oltre 10 MB contenenti milioni di piccolissimi files, in pochissimo tempo.
La soluzione
- Per installare un nuovo pacchetto da webclient FTP, basta inserire in un file zip tutti i files che vogliamo caricare, chiamando il file zip con lo stesso nome che dovrà avere la cartella che conterrà tutti i nostri files.
- Carichiamo il pacchetto nella stessa posizione dove vogliamo che venga estratta la nostra cartella
- Creare un file php contenente il codice preso dal repository GitHub di Andreas Tasch
- Aprire il file php che abbiamo creato, selezioniamo il file zip che vogliamo estrarre, e clicchiamo su Unzip Archive
- Eliminiamo da ftp il file zip e/o il file php della procedura, per evitare che altri possano sovrascrivere files senza il vostro permesso
Riporto qui il codice del file php, per precauzione
<?php
$timestart = microtime(TRUE);
$arc = new Unzipper;
$timeend = microtime(TRUE);
$time = $timeend - $timestart;
class Unzipper {
public $localdir = '.';
public $zipfiles = array();
public static $status = '';
public function __construct() {
//read directory and pick .zip and .gz files
if ($dh = opendir($this->localdir)) {
while (($file = readdir($dh)) !== FALSE) {
if (pathinfo($file, PATHINFO_EXTENSION) === 'zip'
|| pathinfo($file, PATHINFO_EXTENSION) === 'gz'
) {
$this->zipfiles[] = $file;
}
}
closedir($dh);
if(!empty($this->zipfiles)) {
self::$status = '.zip or .gz files found, ready for extraction';
}
else {
self::$status = '<span style="color:red; font-weight:bold;font-size:120%;">Error: No .zip or .gz files found.</span>';
}
}
//check if an archive was selected for unzipping
//check if archive has been selected
$input = '';
$input = strip_tags($_POST['zipfile']);
//allow only local existing archives to extract
if ($input !== '') {
if (in_array($input, $this->zipfiles)) {
self::extract($input, $this->localdir);
}
}
}
public static function extract($archive, $destination) {
$ext = pathinfo($archive, PATHINFO_EXTENSION);
if ($ext === 'zip') {
self::extractZipArchive($archive, $destination);
}
else {
if ($ext === 'gz') {
self::extractGzipFile($archive, $destination);
}
}
}
/**
* Decompress/extract a zip archive using ZipArchive.
*
* @param $archive
* @param $destination
*/
public static function extractZipArchive($archive, $destination) {
//Check if webserver supports unzipping.
if(!class_exists('ZipArchive')) {
self::$status = '<span style="color:red; font-weight:bold;font-size:120%;">Error: Your PHP version does not support unzip functionality.</span>';
return;
}
$zip = new ZipArchive;
//Check if archive is readable.
if ($zip->open($archive) === TRUE) {
//Check if destination is writable
if(is_writeable($destination . '/')) {
$zip->extractTo($destination);
$zip->close();
self::$status = '<span style="color:green; font-weight:bold;font-size:120%;">Files unzipped successfully</span>';
}
else {
self::$status = '<span style="color:red; font-weight:bold;font-size:120%;">Error: Directory not writeable by webserver.</span>';
}
}
else {
self::$status = '<span style="color:red; font-weight:bold;font-size:120%;">Error: Cannot read .zip archive.</span>';
}
}
/**
* Decompress a .gz File.
*
* @param $archive
* @param $destination
*/
public static function extractGzipFile($archive, $destination) {
//Check if zlib is enabled
if(!function_exists('gzopen')) {
self::$status = '<span style="color:red; font-weight:bold;font-size:120%;">Error: Your PHP has no zlib support enabled.</span>';
return;
}
$filename = pathinfo($archive, PATHINFO_FILENAME);
$gzipped = gzopen($archive, "rb");
$file = fopen($filename, "w");
while ($string = gzread($gzipped, 4096)) {
fwrite($file, $string, strlen($string));
}
gzclose($gzipped);
fclose($file);
//Check if file was extracted.
if(file_exists($destination . '/' . $filename)) {
self::$status = '<span style="color:green; font-weight:bold;font-size:120%;">File unzipped successfully.</span>';
}
else {
self::$status = '<span style="color:red; font-weight:bold;font-size:120%;">Error unzipping file.</span>';
}
}
}
?>
<!DOCTYPE html>
<head>
<title>File Unzipper</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
<!--
body {
font-family: Arial, serif;
line-height: 150%;
}
fieldset {
border: 0px solid #000;
}
.select {
padding: 5px;
font-size: 110%;
}
.status {
margin-top: 20px;
padding: 5px;
font-size: 80%;
background: #EEE;
border: 1px dotted #DDD;
}
.submit {
-moz-box-shadow: inset 0px 1px 0px 0px #bbdaf7;
-webkit-box-shadow: inset 0px 1px 0px 0px #bbdaf7;
box-shadow: inset 0px 1px 0px 0px #bbdaf7;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #79bbff), color-stop(1, #378de5));
background: -moz-linear-gradient(center top, #79bbff 5%, #378de5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#79bbff', endColorstr='#378de5');
background-color: #79bbff;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
border: 1px solid #84bbf3;
display: inline-block;
color: #ffffff;
font-family: arial;
font-size: 15px;
font-weight: bold;
padding: 10px 24px;
text-decoration: none;
text-shadow: 1px 1px 0px #528ecc;
}
.submit:hover {
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #378de5), color-stop(1, #79bbff));
background: -moz-linear-gradient(center top, #378de5 5%, #79bbff 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#378de5', endColorstr='#79bbff');
background-color: #378de5;
}
.submit:active {
position: relative;
top: 1px;
}
/* This imageless css button was generated by CSSButtonGenerator.com */
-->
</style>
</head>
<body>
<h1>Archive Unzipper</h1>
<p>Select .zip archive or .gz file you want to extract:</p>
<form action="" method="POST">
<fieldset>
<select name="zipfile" size="1" class="select">
<?php foreach ($arc->zipfiles as $zip) {
echo "<option>$zip</option>";
}
?>
</select>
<br/>
<input type="submit" name="submit" class="submit" value="Unzip Archive"/>
</fieldset>
</form>
<p class="status">
Status: <?php echo $arc::$status; ?>
<br/>
Processingtime: <?php echo $time; ?> ms
</p>
</body>
</html>