GRAV_ROOT, 'overwrite' => true, 'ignore_symlinks' => true, 'skip_invalid' => true, 'install_deps' => true, 'theme' => false ]; /** * @param Package[]|string[]|string $packages * @param array $options * * @return string|bool */ public static function install($packages, array $options) { $options = array_merge(self::$options, $options); if (!Installer::isGravInstance($options['destination']) || !Installer::isValidDestination($options['destination'], [Installer::EXISTS, Installer::IS_LINK]) ) { return false; } $packages = is_array($packages) ? $packages : [$packages]; $count = count($packages); $packages = array_filter(array_map(function ($p) { return !is_string($p) ? $p instanceof Package ? $p : false : self::GPM()->findPackage($p); }, $packages)); if (!$options['skip_invalid'] && $count !== count($packages)) { return false; } $messages = ''; foreach ($packages as $package) { if (isset($package->dependencies) && $options['install_deps']) { $result = static::install($package->dependencies, $options); if (!$result) { return false; } } // Check destination Installer::isValidDestination($options['destination'] . DS . $package->install_path); if (!$options['overwrite'] && Installer::lastErrorCode() === Installer::EXISTS) { return false; } if (!$options['ignore_symlinks'] && Installer::lastErrorCode() === Installer::IS_LINK) { return false; } $license = Licenses::get($package->slug); $local = static::download($package, $license); Installer::install($local, $options['destination'], ['install_path' => $package->install_path, 'theme' => $options['theme']]); Folder::delete(dirname($local)); $errorCode = Installer::lastErrorCode(); if ($errorCode) { $msg = Installer::lastErrorMsg(); throw new \RuntimeException($msg); } if (count($packages) === 1) { $message = Installer::getMessage(); if ($message) { return $message; } $messages .= $message; } } return $messages ?: true; } /** * @param Package[]|string[]|string $packages * @param array $options * * @return string|bool */ public static function update($packages, array $options) { $options['overwrite'] = true; return static::install($packages, $options); } /** * @param Package[]|string[]|string $packages * @param array $options * * @return string|bool */ public static function uninstall($packages, array $options) { $options = array_merge(self::$options, $options); $packages = (array)$packages; $count = count($packages); $packages = array_filter(array_map(function ($p) { if (is_string($p)) { $p = strtolower($p); $plugin = static::GPM()->getInstalledPlugin($p); $p = $plugin ?: static::GPM()->getInstalledTheme($p); } return $p instanceof Package ? $p : false; }, $packages)); if (!$options['skip_invalid'] && $count !== count($packages)) { return false; } foreach ($packages as $package) { $location = Grav::instance()['locator']->findResource($package->package_type . '://' . $package->slug); // Check destination Installer::isValidDestination($location); if (!$options['ignore_symlinks'] && Installer::lastErrorCode() === Installer::IS_LINK) { return false; } Installer::uninstall($location); $errorCode = Installer::lastErrorCode(); if ($errorCode && $errorCode !== Installer::IS_LINK && $errorCode !== Installer::EXISTS) { $msg = Installer::lastErrorMsg(); throw new \RuntimeException($msg); } if (count($packages) === 1) { $message = Installer::getMessage(); if ($message) { return $message; } } } return true; } /** * Direct install a file * * @param string $package_file * * @return string|bool */ public static function directInstall($package_file) { if (!$package_file) { return Admin::translate('PLUGIN_ADMIN.NO_PACKAGE_NAME'); } $tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true); $tmp_zip = $tmp_dir . '/Grav-' . uniqid('', false); if (Response::isRemote($package_file)) { $zip = GravGPM::downloadPackage($package_file, $tmp_zip); } else { $zip = GravGPM::copyPackage($package_file, $tmp_zip); } if (file_exists($zip)) { $tmp_source = $tmp_dir . '/Grav-' . uniqid('', false); $extracted = Installer::unZip($zip, $tmp_source); if (!$extracted) { Folder::delete($tmp_source); Folder::delete($tmp_zip); return Admin::translate('PLUGIN_ADMIN.PACKAGE_EXTRACTION_FAILED'); } $type = GravGPM::getPackageType($extracted); if (!$type) { Folder::delete($tmp_source); Folder::delete($tmp_zip); return Admin::translate('PLUGIN_ADMIN.NOT_VALID_GRAV_PACKAGE'); } if ($type === 'grav') { Installer::isValidDestination(GRAV_ROOT . '/system'); if (Installer::IS_LINK === Installer::lastErrorCode()) { Folder::delete($tmp_source); Folder::delete($tmp_zip); return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS'); } static::upgradeGrav($zip, $extracted); } else { $name = GravGPM::getPackageName($extracted); if (!$name) { Folder::delete($tmp_source); Folder::delete($tmp_zip); return Admin::translate('PLUGIN_ADMIN.NAME_COULD_NOT_BE_DETERMINED'); } $install_path = GravGPM::getInstallPath($type, $name); $is_update = file_exists($install_path); Installer::isValidDestination(GRAV_ROOT . DS . $install_path); if (Installer::lastErrorCode() === Installer::IS_LINK) { Folder::delete($tmp_source); Folder::delete($tmp_zip); return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS'); } Installer::install($zip, GRAV_ROOT, ['install_path' => $install_path, 'theme' => $type === 'theme', 'is_update' => $is_update], $extracted); } Folder::delete($tmp_source); if (Installer::lastErrorCode()) { return Installer::lastErrorMsg(); } } else { return Admin::translate('PLUGIN_ADMIN.ZIP_PACKAGE_NOT_FOUND'); } Folder::delete($tmp_zip); return true; } /** * @param Package $package * * @return string */ private static function download(Package $package, $license = null) { $query = ''; if ($package->premium) { $query = \json_encode(array_merge($package->premium, [ 'slug' => $package->slug, 'filename' => $package->premium['filename'], 'license_key' => $license ])); $query = '?d=' . base64_encode($query); } try { $contents = Response::get($package->zipball_url . $query, []); } catch (\Exception $e) { throw new \RuntimeException($e->getMessage()); } $tmp_dir = Admin::getTempDir() . '/Grav-' . uniqid('', false); Folder::mkdir($tmp_dir); $bad_chars = array_merge(array_map('chr', range(0, 31)), ['<', '>', ':', '"', '/', '\\', '|', '?', '*']); $filename = $package->slug . str_replace($bad_chars, '', basename($package->zipball_url)); $filename = preg_replace('/[\\\\\/:"*?&<>|]+/m', '-', $filename); file_put_contents($tmp_dir . DS . $filename . '.zip', $contents); return $tmp_dir . DS . $filename . '.zip'; } /** * @param array $package * @param string $tmp * * @return string */ private static function _downloadSelfupgrade(array $package, $tmp) { $output = Response::get($package['download'], []); Folder::mkdir($tmp); file_put_contents($tmp . DS . $package['name'], $output); return $tmp . DS . $package['name']; } /** * @return bool */ public static function selfupgrade() { $upgrader = new Upgrader(); if (!Installer::isGravInstance(GRAV_ROOT)) { return false; } if (is_link(GRAV_ROOT . DS . 'index.php')) { Installer::setError(Installer::IS_LINK); return false; } if (method_exists($upgrader, 'meetsRequirements') && method_exists($upgrader, 'minPHPVersion') && !$upgrader->meetsRequirements()) { $error = []; $error[] = '

Grav has increased the minimum PHP requirement.
'; $error[] = 'You are currently running PHP ' . phpversion() . ''; $error[] = ', but PHP ' . $upgrader->minPHPVersion() . ' is required.

'; $error[] = '

Additional information

'; Installer::setError(implode("\n", $error)); return false; } $update = $upgrader->getAssets()['grav-update']; $tmp = Admin::getTempDir() . '/Grav-' . uniqid('', false); if ($tmp) { $file = self::_downloadSelfupgrade($update, $tmp); $folder = Installer::unZip($file, $tmp . '/zip'); $keepFolder = false; } else { // If you make $tmp empty, you can install your local copy of Grav (for testing purposes only). $file = 'grav.zip'; $folder = '~/phpstorm/grav-clones/grav'; //$folder = '/home/matias/phpstorm/rockettheme/grav-devtools/grav-clones/grav'; $keepFolder = true; } static::upgradeGrav($file, $folder, $keepFolder); $errorCode = Installer::lastErrorCode(); if ($tmp) { Folder::delete($tmp); } return !(is_string($errorCode) || ($errorCode & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR))); } private static function upgradeGrav($zip, $folder, $keepFolder = false) { static $ignores = [ 'backup', 'cache', 'images', 'logs', 'tmp', 'user', '.htaccess', 'robots.txt' ]; if (!is_dir($folder)) { Installer::setError('Invalid source folder'); } try { $script = $folder . '/system/install.php'; /** Install $installer */ if ((file_exists($script) && $install = include $script) && is_callable($install)) { $install($zip); } else { Installer::install( $zip, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true, 'ignores' => $ignores], $folder, $keepFolder ); Cache::clearCache(); } } catch (\Exception $e) { Installer::setError($e->getMessage()); } } }