/**
  * 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);
 }
Exemple #4
0
 /**
  * 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);
         }
     }
 }