UpdateModel::analyzeAddon PHP Method

analyzeAddon() public static method

Check an addon's file to extract the addon information out of it.
public static analyzeAddon ( string $Path, boolean $ThrowError = true ) : array
$Path string The path to the file.
$ThrowError boolean Whether or not to throw an exception if there is a problem analyzing the addon.
return array An array of addon information.
    public static function analyzeAddon($Path, $ThrowError = true)
    {
        if (!file_exists($Path)) {
            if ($ThrowError) {
                throw new Exception("{$Path} not found.", 404);
            }
            return false;
        }
        $Addon = [];
        $Result = [];
        $InfoPaths = array('/settings/about.php', '/default.php', '/class.*.plugin.php', '/about.php', '/definitions.php', '/index.php', 'vanilla2export.php');
        // Get the list of potential files to analyze.
        if (is_dir($Path)) {
            $Entries = self::getInfoFiles($Path, $InfoPaths);
            $DeleteEntries = false;
        } else {
            $Entries = self::getInfoZip($Path, $InfoPaths, false, $ThrowError);
            $DeleteEntries = true;
        }
        foreach ($Entries as $Entry) {
            if ($Entry['Name'] == '/index.php') {
                // This could be the core vanilla package.
                $Version = self::parseCoreVersion($Entry['Path']);
                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, 'License' => 'GPLv2', 'Path' => $Entry['Path']);
                break;
            } elseif ($Entry['Name'] == 'vanilla2export.php') {
                // This could be the vanilla porter.
                $Version = self::parseCoreVersion($Entry['Path']);
                if (!$Version) {
                    continue;
                }
                $Addon = array('AddonKey' => 'porter', 'AddonTypeID' => ADDON_TYPE_CORE, 'Name' => 'Vanilla Porter', 'Description' => 'Drop this script in your existing site and navigate to it in your web browser to export your existing forum data to the Vanilla 2 import format.', 'Version' => $Version, 'License' => 'GPLv2', 'Path' => $Entry['Path']);
                break;
            } else {
                // This could be an addon.
                $Info = self::parseInfoArray($Entry['Path']);
                if (!is_array($Info) && count($Info)) {
                    continue;
                }
                $Key = key($Info);
                $Variable = $Info['Variable'];
                $Info = $Info[$Key];
                // Validate the addon.
                $Name = $Entry['Name'];
                $Valid = true;
                if (!val('Name', $Info)) {
                    $Info['Name'] = $Key;
                }
                // Validate basic fields.
                $checkResult = self::checkRequiredFields($Info);
                if (count($checkResult)) {
                    $Result = array_merge($Result, $checkResult);
                    $Valid = false;
                }
                // Validate folder name matches key.
                if (isset($Entry['Base']) && strcasecmp($Entry['Base'], $Key) != 0 && $Variable != 'ThemeInfo') {
                    $Result[] = "{$Name}: The addon's key is not the same as its folder name.";
                    $Valid = false;
                }
                if (!$Valid) {
                    continue;
                }
                // The addon is valid.
                $Addon = array_merge(array('AddonKey' => $Key, 'AddonTypeID' => ''), $Info);
                switch ($Variable) {
                    case 'ApplicationInfo':
                        $Addon['AddonTypeID'] = ADDON_TYPE_APPLICATION;
                        break;
                    case 'LocaleInfo':
                        $Addon['AddonTypeID'] = ADDON_TYPE_LOCALE;
                        break;
                    case 'PluginInfo':
                        $Addon['AddonTypeID'] = ADDON_TYPE_PLUGIN;
                        break;
                    case 'ThemeInfo':
                        $Addon['AddonTypeID'] = ADDON_TYPE_THEME;
                        break;
                }
            }
        }
        if ($DeleteEntries) {
            $FolderPath = substr($Path, 0, -4);
            Gdn_FileSystem::removeFolder($FolderPath);
        }
        // Add the addon requirements.
        if (!empty($Addon)) {
            $Requirements = arrayTranslate($Addon, ['RequiredApplications' => 'Applications', 'RequiredPlugins' => 'Plugins', 'RequiredThemes' => 'Themes']);
            foreach ($Requirements as $Type => $Items) {
                if (!is_array($Items)) {
                    unset($Requirements[$Type]);
                }
            }
            $Addon['Requirements'] = dbencode($Requirements);
            $Addon['Checked'] = true;
            $Addon['Path'] = $Path;
            $UploadsPath = PATH_UPLOADS . '/';
            if (stringBeginsWith($Addon['Path'], $UploadsPath)) {
                $Addon['File'] = substr($Addon['Path'], strlen($UploadsPath));
            }
            if (is_file($Path)) {
                $Addon['MD5'] = md5_file($Path);
                $Addon['FileSize'] = filesize($Path);
            }
        } elseif ($ThrowError) {
            $Msg = implode("\n", $Result);
            throw new Gdn_UserException($Msg, 400);
        } else {
            return false;
        }
        return $Addon;
    }

Usage Example

 /**
  * Handle form upload of an addon zip archive.
  *
  * @return array
  */
 protected function handleAddonUpload()
 {
     $Upload = new Gdn_Upload();
     $Upload->allowFileExtension(null);
     $Upload->allowFileExtension('zip');
     $AnalyzedAddon = [];
     try {
         // Validate the upload.
         $TmpFile = $Upload->validateUpload('File');
         $Extension = pathinfo($Upload->getUploadedFileName(), PATHINFO_EXTENSION);
         // Generate the target name.
         $TargetFile = $Upload->generateTargetName('addons', $Extension);
         $TargetPath = PATH_UPLOADS . '/' . $TargetFile;
         if (!file_exists(dirname($TargetPath))) {
             mkdir(dirname($TargetPath), 0777, true);
         }
         // Save the file to a temporary location for parsing.
         if (!move_uploaded_file($TmpFile, $TargetPath)) {
             throw new Exception("We couldn't save the file you uploaded. Please try again later.", 400);
         }
         $AnalyzedAddon = UpdateModel::analyzeAddon($TargetPath, true);
         // If the long description is blank, load up the readme if it exists
         $formDescription = $this->Form->getFormValue('Description2', '');
         if ($formDescription == '') {
             $Readme = $this->parseReadme($TargetPath);
             if ($Readme) {
                 $AnalyzedAddon['Description2'] = $Readme;
             }
         } else {
             $AnalyzedAddon['Description2'] = $formDescription;
         }
         // Get an icon if one exists.
         $Icon = $this->extractIcon($TargetPath, val('Icon', $AnalyzedAddon, ''));
         if ($Icon) {
             // Overwrite info array value with the path to the saved file.
             $AnalyzedAddon['Icon'] = $Icon;
         }
         // Set the filename for the CDN.
         $Upload->EventArguments['OriginalFilename'] = AddonModel::slug($AnalyzedAddon, true) . '.zip';
         // Save the uploaded file. After this, we no longer have a local copy to analyze.
         $Parsed = $Upload->saveAs($TargetPath, $TargetFile);
         $AnalyzedAddon['File'] = $Parsed['SaveName'];
         unset($AnalyzedAddon['Path']);
         trace($AnalyzedAddon, 'Analyzed Addon');
         $this->Form->formValues($AnalyzedAddon);
     } catch (Exception $ex) {
         $this->Form->addError($ex);
         // Delete the erroneous file.
         try {
             if (isset($AnalyzedAddon) && isset($AnalyzedAddon['File'])) {
                 $Upload->delete($AnalyzedAddon['File']);
             }
         } catch (Exception $Ex2) {
         }
     }
     if (isset($TargetPath) && file_exists($TargetPath)) {
         unlink($TargetPath);
     }
     return $AnalyzedAddon;
 }
All Usage Examples Of UpdateModel::analyzeAddon