summaryrefslogtreecommitdiff
path: root/app/Core/Plugin/Installer.php
blob: 057ded940ce807ca2cc86eb61ea6f1d18268a225 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php

namespace Kanboard\Core\Plugin;

use ZipArchive;
use Kanboard\Core\Tool;

/**
 * Class Installer
 *
 * @package Kanboard\Core\Plugin
 * @author  Frederic Guillot
 */
class Installer extends \Kanboard\Core\Base
{
    /**
     * Return true if Kanboard is configured to install plugins
     *
     * @static
     * @access public
     * @return bool
     */
    public static function isConfigured()
    {
        return PLUGIN_INSTALLER && is_writable(PLUGINS_DIR) && extension_loaded('zip');
    }

    /**
     * Install a plugin
     *
     * @access public
     * @param  string $archiveUrl
     * @throws PluginInstallerException
     */
    public function install($archiveUrl)
    {
        $zip = $this->downloadPluginArchive($archiveUrl);

        if (! $zip->extractTo(PLUGINS_DIR)) {
            $this->cleanupArchive($zip);
            throw new PluginInstallerException(t('Unable to extract plugin archive.'));
        }

        $this->cleanupArchive($zip);
    }

    /**
     * Uninstall a plugin
     *
     * @access public
     * @param  string $pluginId
     * @throws PluginInstallerException
     */
    public function uninstall($pluginId)
    {
        $pluginFolder = PLUGINS_DIR.DIRECTORY_SEPARATOR.basename($pluginId);

        if (! file_exists($pluginFolder)) {
            throw new PluginInstallerException(t('Plugin not found.'));
        }

        if (! is_writable($pluginFolder)) {
            throw new PluginInstallerException(e('You don\'t have the permission to remove this plugin.'));
        }

        Tool::removeAllFiles($pluginFolder);
    }

    /**
     * Update a plugin
     *
     * @access public
     * @param  string $archiveUrl
     * @throws PluginInstallerException
     */
    public function update($archiveUrl)
    {
        $zip = $this->downloadPluginArchive($archiveUrl);

        $firstEntry = $zip->statIndex(0);
        $this->uninstall($firstEntry['name']);

        if (! $zip->extractTo(PLUGINS_DIR)) {
            $this->cleanupArchive($zip);
            throw new PluginInstallerException(t('Unable to extract plugin archive.'));
        }

        $this->cleanupArchive($zip);
    }

    /**
     * Download archive from URL
     *
     * @access protected
     * @param  string $archiveUrl
     * @return ZipArchive
     * @throws PluginInstallerException
     */
    protected function downloadPluginArchive($archiveUrl)
    {
        $zip = new ZipArchive();
        $archiveData = $this->httpClient->get($archiveUrl);
        $archiveFile = tempnam(ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(), 'kb_plugin');

        if (empty($archiveData)) {
            unlink($archiveFile);
            throw new PluginInstallerException(t('Unable to download plugin archive.'));
        }

        if (file_put_contents($archiveFile, $archiveData) === false) {
            unlink($archiveFile);
            throw new PluginInstallerException(t('Unable to write temporary file for plugin.'));
        }

        if ($zip->open($archiveFile) !== true) {
            unlink($archiveFile);
            throw new PluginInstallerException(t('Unable to open plugin archive.'));
        }

        if ($zip->numFiles === 0) {
            unlink($archiveFile);
            throw new PluginInstallerException(t('There is no file in the plugin archive.'));
        }

        return $zip;
    }

    /**
     * Remove archive file
     *
     * @access protected
     * @param ZipArchive $zip
     */
    protected function cleanupArchive(ZipArchive $zip)
    {
        unlink($zip->filename);
        $zip->close();
    }
}