Skip to content
Snippets Groups Projects
Forked from Stud.IP / Stud.IP
3683 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PluginRepository.class.php 5.00 KiB
<?php

/*
 * PluginRepository.class.php - query plugin meta data
 *
 * Copyright (c) 2008  Elmar Ludwig
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 */

/**
 * Class used to locate plugins available from a plugin repository.
 */
class PluginRepository
{
    /**
     * list and meta data of available plugins
     */
    private $plugins = [];

    /**
     * Initialize a new PluginRepository and read meta data from
     * the given URL or the default list of URLs (if $url is null).
     */
    public function __construct($url = null)
    {
        if (isset($url)) {
            $this->readMetadata($url);
        } else {
            foreach ($GLOBALS['PLUGIN_REPOSITORIES'] as $url) {
                $this->readMetadata($url);
            }
        }
    }

    /**
     * Read plugin meta data from the given URL (using XML format).
     * The structure of the XML is:
     *
     * <plugins>
     *   <plugin name="DummyPlugin"
     *     <release
     *           version="2.0"
     *           url="http://plugins.example.com/dummy-2.0.zip"
     *           studipMinVersion="1.4"
     *           studipMaxVersion="1.9">
     *   </plugin>
     *   [...]
     * </plugins>
     *
     * @param string $url given url for plugin
     */
    public function readMetadata($url)
    {
        $cache = StudipCacheFactory::getCache();
        $cache_key = 'plugin_metadata/'.$url;
        $metadata = $cache->read($cache_key);

        if ($metadata === false) {
            // Set small timeout for the rare case that the repository is not
            // available
            $context = get_default_http_stream_context($url);
            stream_context_set_option($context, ['http' => [
                'timeout' => 5,
            ]]);
            $metadata = @file_get_contents($url, false, $context);
            if ($metadata === false) {
                throw new Exception(sprintf(_('Fehler beim Zugriff auf %s'), $url));
            }

            $cache->write($cache_key, $metadata, 3600);
        }

        $xml = new SimpleXMLElement($metadata);

        if (!isset($xml->plugin)) {
            $cache->expire($cache_key);
            throw new Exception(_('Keine Plugin Meta-Daten gefunden'));
        }

        foreach ($xml->plugin as $plugin) {
            foreach ($plugin->release as $release) {
                $min_version = trim($release['studipMinVersion']);
                $max_version = trim($release['studipMaxVersion']);

                if (($min_version && StudipVersion::olderThan($min_version)) ||
                    ($max_version && StudipVersion::newerThan($max_version))) {
                    // plugin is not compatible, so skip it
                    continue;
                }

                $meta_data = [
                    'version'         => (string) $release['version'],
                    'url'             => (string) $release['url'],
                    'description'     => (string) $plugin['description'],
                    'plugin_url'      => (string) $plugin['homepage'],
                    'image'           => (string) $plugin['image'],
                    'score'           => (float) $plugin['score'],
                    'marketplace_url' => (string) $plugin['marketplace_url'],
                ];

                $this->registerPlugin((string) $plugin['name'], $meta_data);
            }
        }
    }

    /**
     * Register a new plugin in this repository.
     *
     * @param string $name plugin name
     * @param array $meta_data plugin meta data
     */
    protected function registerPlugin($name, $meta_data)
    {
        $old_data = $this->plugins[$name];

        if (!isset($old_data) ||
            version_compare($meta_data['version'], $old_data['version']) > 0) {
            $this->plugins[$name] = $meta_data;
        }
    }

    /**
     * Get meta data for the plugin with the given name (if available).
     * Always chooses the newest compatible version of the plugin.
     * @param string $name name of the plgin
     * @return array meta data for plugin (or null)
     */
    public function getPlugin($name)
    {
        return $this->plugins[$name];
    }

    /**
     * Get meta data for all plugins whose names contain the given
     * string. You may omit the search string to get a list of all
     * available plugins. Returns the newest compatible version of
     * each plugin.
     * @param string $search search string
     * @return array array of meta data for matching plugins
     */
    public function getPlugins($search = null)
    {
        $result = [];

        foreach ($this->plugins as $name => $data) {
            if ($search === null || $search === '' ||
                is_int(mb_stripos($name, $search)) ||
                is_int(mb_stripos($data['description'], $search))) {
                $result[$name] = $data;
            }
        }

        return $result;
    }
}