/** * Import a Yaga transport file */ public function Import() { $this->Title(T('Yaga.Import')); $this->SetData('TransportType', 'Import'); if (!class_exists('ZipArchive')) { $this->Form->AddError(T('Yaga.Error.TransportRequirements')); } if ($this->Form->IsPostBack() == TRUE) { // Handle the file upload $Upload = new Gdn_Upload(); $TmpZip = $Upload->ValidateUpload('FileUpload', FALSE); $ZipFile = FALSE; if ($TmpZip) { // Generate the target name $TargetFile = $Upload->GenerateTargetName(PATH_UPLOADS, 'zip'); $BaseName = pathinfo($TargetFile, PATHINFO_BASENAME); // Save the uploaded zip $Parts = $Upload->SaveAs($TmpZip, $BaseName); $ZipFile = PATH_UPLOADS . DS . $Parts['SaveName']; $this->SetData('TransportPath', $ZipFile); } $Include = $this->_FindIncludes(); if (count($Include)) { $Info = $this->_ExtractZip($ZipFile); $this->_ImportData($Info, $Include); Gdn_FileSystem::RemoveFolder(PATH_UPLOADS . DS . 'import' . DS . 'yaga'); } else { $this->Form->AddError(T('Yaga.Error.Includes')); } } if ($this->Form->ErrorCount() == 0 && $this->Form->IsPostBack()) { $this->Render('transport-success'); } else { $this->Render(); } }
/** * * * @param $Path * @param $InfoPaths * @param bool $TmpPath * @param bool $ThrowError * @return array|bool * @throws Exception */ protected static function _GetInfoZip($Path, $InfoPaths, $TmpPath = false, $ThrowError = true) { // Extract the zip file so we can make sure it has appropriate information. $Zip = null; if (class_exists('ZipArchive', false)) { $Zip = new ZipArchive(); $ZipOpened = $Zip->open($Path); if ($ZipOpened !== true) { $Zip = null; } } if (!$Zip) { require_once PATH_LIBRARY . "/vendors/pclzip/class.pclzipadapter.php"; $Zip = new PclZipAdapter(); $ZipOpened = $Zip->open($Path); } if ($ZipOpened !== true) { if ($ThrowError) { $Errors = array(ZIPARCHIVE::ER_EXISTS => 'ER_EXISTS', ZIPARCHIVE::ER_INCONS => 'ER_INCONS', ZIPARCHIVE::ER_INVAL => 'ER_INVAL', ZIPARCHIVE::ER_MEMORY => 'ER_MEMORY', ZIPARCHIVE::ER_NOENT => 'ER_NOENT', ZIPARCHIVE::ER_NOZIP => 'ER_NOZIP', ZIPARCHIVE::ER_OPEN => 'ER_OPEN', ZIPARCHIVE::ER_READ => 'ER_READ', ZIPARCHIVE::ER_SEEK => 'ER_SEEK'); throw new Exception(t('Could not open addon file. Addons must be zip files.') . ' (' . $Path . ' ' . GetValue($ZipOpened, $Errors, 'Unknown Error') . ')' . $Worked, 400); } return false; } if ($TmpPath === false) { $TmpPath = dirname($Path) . '/' . basename($Path, '.zip') . '/'; } if (file_exists($TmpPath)) { Gdn_FileSystem::RemoveFolder($TmpPath); } $Result = array(); for ($i = 0; $i < $Zip->numFiles; $i++) { $Entry = $Zip->statIndex($i); if (preg_match('#(\\.\\.[\\/])#', $Entry['name'])) { throw new Gdn_UserException("Invalid path in zip file: " . htmlspecialchars($Entry['name'])); } $Name = '/' . ltrim($Entry['name'], '/'); foreach ($InfoPaths as $InfoPath) { $Preg = '`(' . str_replace(array('.', '*'), array('\\.', '.*'), $InfoPath) . ')$`'; if (preg_match($Preg, $Name, $Matches)) { $Base = trim(substr($Name, 0, -strlen($Matches[1])), '/'); if (strpos($Base, '/') !== false) { continue; // file nested too deep. } if (!file_exists($TmpPath)) { mkdir($TmpPath, 0777, true); } $Zip->extractTo($TmpPath, $Entry['name']); $Result[] = array('Name' => $Matches[1], 'Path' => $TmpPath . rtrim($Entry['name'], '/'), 'Base' => $Base); } } } return $Result; }
/** * Remove the plugin folder. * * @param string $PluginFolder * @return void */ private function _RemovePluginFolder($PluginFolder) { Gdn_FileSystem::RemoveFolder(PATH_PLUGINS . DS . $PluginFolder); }
/** * Check an addon's file to extract the addon information out of it. * * @param string $Path The path to the file. * @param bool $Fix Whether or not to fix files that have been zipped incorrectly. * @return array An array of addon information. */ public static function AnalyzeAddon($Path, $Fix = FALSE, $ThrowError = TRUE) { $Result = array(); // Extract the zip file so we can make sure it has appropriate information. $Zip = NULL; if (class_exists('ZipArchive', FALSE)) { $Zip = new ZipArchive(); $ZipOpened = $Zip->open($Path); if ($ZipOpened !== TRUE) { $Zip = NULL; } } if (!$Zip) { require_once PATH_LIBRARY . "/vendors/pclzip/class.pclzipadapter.php"; $Zip = new PclZipAdapter(); $ZipOpened = $Zip->open($Path); } if ($ZipOpened !== TRUE) { if ($ThrowError) { $Errors = array(ZIPARCHIVE::ER_EXISTS => 'ER_EXISTS', ZIPARCHIVE::ER_INCONS => 'ER_INCONS', ZIPARCHIVE::ER_INVAL => 'ER_INVAL', ZIPARCHIVE::ER_MEMORY => 'ER_MEMORY', ZIPARCHIVE::ER_NOENT => 'ER_NOENT', ZIPARCHIVE::ER_NOZIP => 'ER_NOZIP', ZIPARCHIVE::ER_OPEN => 'ER_OPEN', ZIPARCHIVE::ER_READ => 'ER_READ', ZIPARCHIVE::ER_SEEK => 'ER_SEEK'); throw new Exception(T('Could not open addon file. Addons must be zip files.') . ' (' . $Path . ' ' . GetValue($ZipOpened, $Errors, 'Unknown Error') . ')' . $Worked, 400); } return FALSE; } $Entries = array(); for ($i = 0; $i < $Zip->numFiles; $i++) { $Entries[] = $Zip->statIndex($i); } // Figure out which system files to delete. $Deletes = array(); foreach ($Entries as $Index => $Entry) { $Name = $Entry['name']; $Delete = strpos($Name, '__MACOSX') !== FALSE | strpos($Name, '.DS_Store') !== FALSE | strpos($Name, 'thumbs.db') !== FALSE | strpos($Name, '.gitignore') !== FALSE; if ($Delete) { $Deletes[] = $Entry; unset($Entries[$Index]); } } // Get a folder ready for checking the addon. $FolderPath = dirname($Path) . '/' . basename($Path, '.zip') . '/'; if (file_exists($FolderPath)) { Gdn_FileSystem::RemoveFolder($FolderPath); } // Figure out what kind of addon this is. $Root = ''; $NewRoot = ''; $Addon = FALSE; foreach ($Entries as $Entry) { $Name = '/' . ltrim($Entry['name'], '/'); $Filename = basename($Name); $Folder = substr($Name, 0, -strlen($Filename)); $NewRoot = ''; // Check to see if the entry is a plugin file. if ($Filename == 'default.php' || StringEndsWith($Filename, '.plugin.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a plugin file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'PluginInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } // Check to see if the info array conforms to a plugin spec. $Key = key($Info); $Info = $Info[$Key]; $Root = trim($Folder, '/'); $Valid = TRUE; // Make sure the key matches the folder name. if ($Root && strcasecmp($Root, $Key) != 0) { $Result[] = "{$Name}: The plugin's key is not the same as its folder name."; $Valid = FALSE; } else { $NewRoot = $Root; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The plugin was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_PLUGIN, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } continue; } // Check to see if the entry is an application file. if (StringEndsWith($Name, '/settings/about.php')) { if (count(explode('/', $Folder)) > 4) { $Result[] = "{$Name}: The application's info array was not in the correct location."; // The file is too deep to be a plugin file. continue; } // This could be a plugin file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'ApplicationInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { $Result[] = "{$Name}: The application's info array could not be parsed."; continue; } $Key = key($Info); $Info = $Info[$Key]; $Root = trim(substr($Name, 0, -strlen('/settings/about.php')), '/'); $Valid = TRUE; // Make sure the key matches the folder name. if ($Root && strcasecmp($Root, $Key) != 0) { $Result[] = "{$Name}: The application's key is not the same as its folder name."; $Valid = FALSE; } else { $NewRoot = $Root; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The application was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_APPLICATION, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } continue; } // Check to see if the entry is a theme file. if (StringEndsWith($Name, '/about.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a theme file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'ThemeInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } $Key = key($Info); $Info = $Info[$Key]; $Valid = TRUE; $Root = trim(substr($Name, 0, -strlen('/about.php')), '/'); // Make sure the theme is at least one folder deep. if (strlen($Root) == 0) { $Result[] = $Name . ': The theme must be in a folder.'; $Valid = FALSE; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The application was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_THEME, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } } if (StringEndsWith($Name, '/definitions.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a locale pack, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'LocaleInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } $Key = key($Info); $Info = $Info[$Key]; $Valid = TRUE; $Root = trim(substr($Name, 0, -strlen('/definitions.php')), '/'); // Make sure the locale is at least one folder deep. if ($Root != $Key) { $Result[] = $Name . ': The locale pack\'s key must be the same as its folder name.'; $Valid = FALSE; } if (!GetValue('Locale', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Locale')); $Valud = FALSE; } elseif (strcasecmp($Info['Locale'], $Key) == 0) { $Result[] = $Name . ': ' . T('The locale\'s key cannot be the same as the name of the locale.'); $Valid = FALSE; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The locale pack was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_LOCALE, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } } // Check to see if the entry is a core file. if (StringEndsWith($Name, '/index.php')) { if (count(explode('/', $Folder)) != 3) { // The file is too deep to be the core's index.php continue; } // This could be a theme file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); // Get the version number from the core. $Version = self::ParseCoreVersion($FilePath); if (!$Version) { continue; } // The application was confirmed. $Addon = array('AddonKey' => 'vanilla', 'AddonTypeID' => ADDON_TYPE_CORE, 'Name' => 'Vanilla', 'Description' => 'Vanilla is an open-source, standards-compliant, multi-lingual, fully extensible discussion forum for the web. Anyone who has web-space that meets the requirements can download and use Vanilla for free!', 'Version' => $Version, 'Path' => $Path); $Info = array(); break; } } if ($Addon) { // Add the requirements. $Requirements = ArrayTranslate($Info, array('RequiredApplications' => 'Applications', 'RequiredPlugins' => 'Plugins', 'RequiredThemes' => 'Themes')); foreach ($Requirements as $Type => $Items) { if (!is_array($Items)) { unset($Requirements[$Type]); } } $Addon['Requirements'] = serialize($Requirements); $Addon['Checked'] = TRUE; $UploadsPath = PATH_ROOT . '/uploads/'; if (StringBeginsWith($Addon['Path'], $UploadsPath)) { $Addon['File'] = substr($Addon['Path'], strlen($UploadsPath)); } if ($Fix) { // Delete extraneous files. foreach ($Deletes as $Delete) { $Zip->deleteName($Delete['name']); } } } $Zip->close(); if (file_exists($FolderPath)) { Gdn_FileSystem::RemoveFolder($FolderPath); } if ($Addon) { $Addon['MD5'] = md5_file($Path); return $Addon; } else { if ($ThrowError) { $Msg = implode("\n", $Result); throw new Exception($Msg, 400); } else { return FALSE; } } }
public function Flush() { foreach ($this->Containers as &$Container) { $CacheLocation = $Container[Gdn_Filecache::CONTAINER_LOCATION]; if (is_dir($CacheLocation)) { Gdn_FileSystem::RemoveFolder($CacheLocation); @mkdir($CacheLocation, 0755, TRUE); } } }