private function installModule()
{
// list of validated files (these files will actually be unpacked)
$files = array();
// shorten field variables
/** @var $fileFile \SpoonFormFile */
$fileFile = $this->frm->getField('file');
// create \ziparchive instance
$zip = new \ZipArchive();
// try and open it
if ($zip->open($fileFile->getTempFileName()) !== true) {
$fileFile->addError(BL::getError('CorruptedFile'));
}
// zip file needs to contain some files
if ($zip->numFiles == 0) {
$fileFile->addError(BL::getError('FileIsEmpty'));
return;
}
// directories we are allowed to upload to
$allowedDirectories = array('src/Backend/Modules/', 'src/Frontend/Modules/', 'library/external/');
// name of the module we are trying to upload
$moduleName = null;
// has the module zip one level of folders too much?
$prefix = '';
// check every file in the zip
for ($i = 0; $i < $zip->numFiles; ++$i) {
// get the file name
$file = $zip->statIndex($i);
$fileName = $file['name'];
if ($i === 0) {
$prefix = $this->extractPrefix($file);
}
// check if the file is in one of the valid directories
foreach ($allowedDirectories as $directory) {
// yay, in a valid directory
if (mb_stripos($fileName, $prefix . $directory) === 0) {
// we have a library file
if ($directory == $prefix . 'library/external/') {
if (!is_file(PATH_WWW . '/' . $fileName)) {
$files[] = $fileName;
}
break;
}
// extract the module name from the url
$tmpName = trim(str_ireplace($prefix . $directory, '', $fileName), '/');
if ($tmpName == '') {
break;
}
$chunks = explode('/', $tmpName);
$tmpName = $chunks[0];
// ignore hidden files
if (mb_substr(basename($fileName), 0, 1) == '.') {
break;
} elseif ($moduleName === null) {
// first module we find, store the name
$moduleName = $tmpName;
} elseif ($moduleName !== $tmpName) {
// the name does not match the previous module we found, skip the file
break;
}
// passed all our tests, store it for extraction
$files[] = $fileName;
// go to next file
break;
}
}
}
// after filtering no files left (nothing useful found)
if (count($files) == 0) {
$fileFile->addError(BL::getError('FileContentsIsUseless'));
return;
}
// module already exists on the filesystem
if (BackendExtensionsModel::existsModule($moduleName)) {
$fileFile->addError(sprintf(BL::getError('ModuleAlreadyExists'), $moduleName));
return;
}
// installer in array?
if (!in_array($prefix . 'src/Backend/Modules/' . $moduleName . '/Installer/Installer.php', $files)) {
$fileFile->addError(sprintf(BL::getError('NoInstallerFile'), $moduleName));
return;
}
// unpack module files
$zip->extractTo(PATH_WWW, $files);
// place all the items in the prefixed folders in the right folders
if (!empty($prefix)) {
$filesystem = new Filesystem();
foreach ($files as &$file) {
$fullPath = PATH_WWW . '/' . $file;
$newPath = str_replace(PATH_WWW . '/' . $prefix, PATH_WWW . '/', $fullPath);
if ($filesystem->exists($fullPath) && is_dir($fullPath)) {
$filesystem->mkdir($newPath);
} elseif ($filesystem->exists($fullPath) && is_file($fullPath)) {
$filesystem->copy($fullPath, $newPath);
}
}
$filesystem->remove(PATH_WWW . '/' . $prefix);
}
// run installer
BackendExtensionsModel::installModule($moduleName);
// return the files
return $moduleName;
}