Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

443 Zeilen
13 KiB

  1. <?php
  2. /**
  3. * @package Grav\Plugin\Admin
  4. *
  5. * @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Plugin\Admin;
  9. use Grav\Common\Cache;
  10. use Grav\Common\Grav;
  11. use Grav\Common\GPM\GPM as GravGPM;
  12. use Grav\Common\GPM\Licenses;
  13. use Grav\Common\GPM\Installer;
  14. use Grav\Common\GPM\Upgrader;
  15. use Grav\Common\HTTP\Response;
  16. use Grav\Common\Filesystem\Folder;
  17. use Grav\Common\GPM\Common\Package;
  18. /**
  19. * Class Gpm
  20. *
  21. * @package Grav\Plugin\Admin
  22. */
  23. class Gpm
  24. {
  25. // Probably should move this to Grav DI container?
  26. /** @var GravGPM */
  27. protected static $GPM;
  28. public static function GPM()
  29. {
  30. if (!static::$GPM) {
  31. static::$GPM = new GravGPM();
  32. }
  33. return static::$GPM;
  34. }
  35. /**
  36. * Default options for the install
  37. *
  38. * @var array
  39. */
  40. protected static $options = [
  41. 'destination' => GRAV_ROOT,
  42. 'overwrite' => true,
  43. 'ignore_symlinks' => true,
  44. 'skip_invalid' => true,
  45. 'install_deps' => true,
  46. 'theme' => false
  47. ];
  48. /**
  49. * @param Package[]|string[]|string $packages
  50. * @param array $options
  51. *
  52. * @return string|bool
  53. */
  54. public static function install($packages, array $options)
  55. {
  56. $options = array_merge(self::$options, $options);
  57. if (!Installer::isGravInstance($options['destination']) || !Installer::isValidDestination($options['destination'],
  58. [Installer::EXISTS, Installer::IS_LINK])
  59. ) {
  60. return false;
  61. }
  62. $packages = is_array($packages) ? $packages : [$packages];
  63. $count = count($packages);
  64. $packages = array_filter(array_map(function ($p) {
  65. return !is_string($p) ? $p instanceof Package ? $p : false : self::GPM()->findPackage($p);
  66. }, $packages));
  67. if (!$options['skip_invalid'] && $count !== count($packages)) {
  68. return false;
  69. }
  70. $messages = '';
  71. foreach ($packages as $package) {
  72. if (isset($package->dependencies) && $options['install_deps']) {
  73. $result = static::install($package->dependencies, $options);
  74. if (!$result) {
  75. return false;
  76. }
  77. }
  78. // Check destination
  79. Installer::isValidDestination($options['destination'] . DS . $package->install_path);
  80. if (!$options['overwrite'] && Installer::lastErrorCode() === Installer::EXISTS) {
  81. return false;
  82. }
  83. if (!$options['ignore_symlinks'] && Installer::lastErrorCode() === Installer::IS_LINK) {
  84. return false;
  85. }
  86. $license = Licenses::get($package->slug);
  87. $local = static::download($package, $license);
  88. Installer::install($local, $options['destination'],
  89. ['install_path' => $package->install_path, 'theme' => $options['theme']]);
  90. Folder::delete(dirname($local));
  91. $errorCode = Installer::lastErrorCode();
  92. if ($errorCode) {
  93. $msg = Installer::lastErrorMsg();
  94. throw new \RuntimeException($msg);
  95. }
  96. if (count($packages) === 1) {
  97. $message = Installer::getMessage();
  98. if ($message) {
  99. return $message;
  100. }
  101. $messages .= $message;
  102. }
  103. }
  104. Cache::clearCache();
  105. return $messages ?: true;
  106. }
  107. /**
  108. * @param Package[]|string[]|string $packages
  109. * @param array $options
  110. *
  111. * @return string|bool
  112. */
  113. public static function update($packages, array $options)
  114. {
  115. $options['overwrite'] = true;
  116. return static::install($packages, $options);
  117. }
  118. /**
  119. * @param Package[]|string[]|string $packages
  120. * @param array $options
  121. *
  122. * @return string|bool
  123. */
  124. public static function uninstall($packages, array $options)
  125. {
  126. $options = array_merge(self::$options, $options);
  127. $packages = (array)$packages;
  128. $count = count($packages);
  129. $packages = array_filter(array_map(function ($p) {
  130. if (is_string($p)) {
  131. $p = strtolower($p);
  132. $plugin = static::GPM()->getInstalledPlugin($p);
  133. $p = $plugin ?: static::GPM()->getInstalledTheme($p);
  134. }
  135. return $p instanceof Package ? $p : false;
  136. }, $packages));
  137. if (!$options['skip_invalid'] && $count !== count($packages)) {
  138. return false;
  139. }
  140. foreach ($packages as $package) {
  141. $location = Grav::instance()['locator']->findResource($package->package_type . '://' . $package->slug);
  142. // Check destination
  143. Installer::isValidDestination($location);
  144. if (!$options['ignore_symlinks'] && Installer::lastErrorCode() === Installer::IS_LINK) {
  145. return false;
  146. }
  147. Installer::uninstall($location);
  148. $errorCode = Installer::lastErrorCode();
  149. if ($errorCode && $errorCode !== Installer::IS_LINK && $errorCode !== Installer::EXISTS) {
  150. $msg = Installer::lastErrorMsg();
  151. throw new \RuntimeException($msg);
  152. }
  153. if (count($packages) === 1) {
  154. $message = Installer::getMessage();
  155. if ($message) {
  156. return $message;
  157. }
  158. }
  159. }
  160. Cache::clearCache();
  161. return true;
  162. }
  163. /**
  164. * Direct install a file
  165. *
  166. * @param string $package_file
  167. *
  168. * @return string|bool
  169. */
  170. public static function directInstall($package_file)
  171. {
  172. if (!$package_file) {
  173. return Admin::translate('PLUGIN_ADMIN.NO_PACKAGE_NAME');
  174. }
  175. $tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
  176. $tmp_zip = $tmp_dir . '/Grav-' . uniqid('', false);
  177. if (Response::isRemote($package_file)) {
  178. $zip = GravGPM::downloadPackage($package_file, $tmp_zip);
  179. } else {
  180. $zip = GravGPM::copyPackage($package_file, $tmp_zip);
  181. }
  182. if (file_exists($zip)) {
  183. $tmp_source = $tmp_dir . '/Grav-' . uniqid('', false);
  184. $extracted = Installer::unZip($zip, $tmp_source);
  185. if (!$extracted) {
  186. Folder::delete($tmp_source);
  187. Folder::delete($tmp_zip);
  188. return Admin::translate('PLUGIN_ADMIN.PACKAGE_EXTRACTION_FAILED');
  189. }
  190. $type = GravGPM::getPackageType($extracted);
  191. if (!$type) {
  192. Folder::delete($tmp_source);
  193. Folder::delete($tmp_zip);
  194. return Admin::translate('PLUGIN_ADMIN.NOT_VALID_GRAV_PACKAGE');
  195. }
  196. if ($type === 'grav') {
  197. Installer::isValidDestination(GRAV_ROOT . '/system');
  198. if (Installer::IS_LINK === Installer::lastErrorCode()) {
  199. Folder::delete($tmp_source);
  200. Folder::delete($tmp_zip);
  201. return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS');
  202. }
  203. static::upgradeGrav($zip, $extracted);
  204. } else {
  205. $name = GravGPM::getPackageName($extracted);
  206. if (!$name) {
  207. Folder::delete($tmp_source);
  208. Folder::delete($tmp_zip);
  209. return Admin::translate('PLUGIN_ADMIN.NAME_COULD_NOT_BE_DETERMINED');
  210. }
  211. $install_path = GravGPM::getInstallPath($type, $name);
  212. $is_update = file_exists($install_path);
  213. Installer::isValidDestination(GRAV_ROOT . DS . $install_path);
  214. if (Installer::lastErrorCode() === Installer::IS_LINK) {
  215. Folder::delete($tmp_source);
  216. Folder::delete($tmp_zip);
  217. return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS');
  218. }
  219. Installer::install($zip, GRAV_ROOT,
  220. ['install_path' => $install_path, 'theme' => $type === 'theme', 'is_update' => $is_update],
  221. $extracted);
  222. }
  223. Folder::delete($tmp_source);
  224. if (Installer::lastErrorCode()) {
  225. return Installer::lastErrorMsg();
  226. }
  227. } else {
  228. return Admin::translate('PLUGIN_ADMIN.ZIP_PACKAGE_NOT_FOUND');
  229. }
  230. Folder::delete($tmp_zip);
  231. Cache::clearCache();
  232. return true;
  233. }
  234. /**
  235. * @param Package $package
  236. *
  237. * @return string
  238. */
  239. private static function download(Package $package, $license = null)
  240. {
  241. $query = '';
  242. if ($package->premium) {
  243. $query = \json_encode(array_merge($package->premium, [
  244. 'slug' => $package->slug,
  245. 'license_key' => $license,
  246. 'sid' => md5(GRAV_ROOT)
  247. ]));
  248. $query = '?d=' . base64_encode($query);
  249. }
  250. try {
  251. $contents = Response::get($package->zipball_url . $query, []);
  252. } catch (\Exception $e) {
  253. throw new \RuntimeException($e->getMessage());
  254. }
  255. $tmp_dir = Admin::getTempDir() . '/Grav-' . uniqid('', false);
  256. Folder::mkdir($tmp_dir);
  257. $bad_chars = array_merge(array_map('chr', range(0, 31)), ['<', '>', ':', '"', '/', '\\', '|', '?', '*']);
  258. $filename = $package->slug . str_replace($bad_chars, '', \Grav\Common\Utils::basename($package->zipball_url));
  259. $filename = preg_replace('/[\\\\\/:"*?&<>|]+/m', '-', $filename);
  260. file_put_contents($tmp_dir . DS . $filename . '.zip', $contents);
  261. return $tmp_dir . DS . $filename . '.zip';
  262. }
  263. /**
  264. * @param array $package
  265. * @param string $tmp
  266. *
  267. * @return string
  268. */
  269. private static function _downloadSelfupgrade(array $package, $tmp)
  270. {
  271. $output = Response::get($package['download'], []);
  272. Folder::mkdir($tmp);
  273. file_put_contents($tmp . DS . $package['name'], $output);
  274. return $tmp . DS . $package['name'];
  275. }
  276. /**
  277. * @return bool
  278. */
  279. public static function selfupgrade()
  280. {
  281. $upgrader = new Upgrader();
  282. if (!Installer::isGravInstance(GRAV_ROOT)) {
  283. return false;
  284. }
  285. if (is_link(GRAV_ROOT . DS . 'index.php')) {
  286. Installer::setError(Installer::IS_LINK);
  287. return false;
  288. }
  289. if (method_exists($upgrader, 'meetsRequirements') &&
  290. method_exists($upgrader, 'minPHPVersion') &&
  291. !$upgrader->meetsRequirements()) {
  292. $error = [];
  293. $error[] = '<p>Grav has increased the minimum PHP requirement.<br />';
  294. $error[] = 'You are currently running PHP <strong>' . phpversion() . '</strong>';
  295. $error[] = ', but PHP <strong>' . $upgrader->minPHPVersion() . '</strong> is required.</p>';
  296. $error[] = '<p><a href="https://getgrav.org/blog/changing-php-requirements-to-5.5" class="button button-small secondary">Additional information</a></p>';
  297. Installer::setError(implode("\n", $error));
  298. return false;
  299. }
  300. $update = $upgrader->getAssets()['grav-update'];
  301. $tmp = Admin::getTempDir() . '/Grav-' . uniqid('', false);
  302. if ($tmp) {
  303. $file = self::_downloadSelfupgrade($update, $tmp);
  304. $folder = Installer::unZip($file, $tmp . '/zip');
  305. $keepFolder = false;
  306. } else {
  307. // If you make $tmp empty, you can install your local copy of Grav (for testing purposes only).
  308. $file = 'grav.zip';
  309. $folder = '~/phpstorm/grav-clones/grav';
  310. //$folder = '/home/matias/phpstorm/rockettheme/grav-devtools/grav-clones/grav';
  311. $keepFolder = true;
  312. }
  313. static::upgradeGrav($file, $folder, $keepFolder);
  314. $errorCode = Installer::lastErrorCode();
  315. if ($tmp) {
  316. Folder::delete($tmp);
  317. }
  318. return !(is_string($errorCode) || ($errorCode & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR)));
  319. }
  320. private static function upgradeGrav($zip, $folder, $keepFolder = false)
  321. {
  322. static $ignores = [
  323. 'backup',
  324. 'cache',
  325. 'images',
  326. 'logs',
  327. 'tmp',
  328. 'user',
  329. '.htaccess',
  330. 'robots.txt'
  331. ];
  332. if (!is_dir($folder)) {
  333. Installer::setError('Invalid source folder');
  334. }
  335. try {
  336. $script = $folder . '/system/install.php';
  337. /** Install $installer */
  338. if ((file_exists($script) && $install = include $script) && is_callable($install)) {
  339. $install($zip);
  340. } else {
  341. Installer::install(
  342. $zip,
  343. GRAV_ROOT,
  344. ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true, 'ignores' => $ignores],
  345. $folder,
  346. $keepFolder
  347. );
  348. Cache::clearCache();
  349. }
  350. } catch (\Exception $e) {
  351. Installer::setError($e->getMessage());
  352. }
  353. }
  354. }