1: | <?php |
2: | declare(strict_types=1); |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | |
9: | |
10: | |
11: | |
12: | |
13: | |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: | class Magento_Module extends \Module\Support\Webapps\Magento |
23: | { |
24: | const APP_NAME = 'Magento'; |
25: | |
26: | const MAGENTO_CLI = '/usr/share/pear/n98-magerun.phar'; |
27: | const MAGENTO2_CLI = '/usr/share/pear/n98-magerun2.phar'; |
28: | |
29: | const MAGENTO_CLI_URL = 'https://files.magerun.net/n98-magerun.phar'; |
30: | const MAGENTO2_CLI_URL = 'https://files.magerun.net/n98-magerun2.phar'; |
31: | |
32: | const VERSION_CHECK_URL = 'http://mirror.apisnetworks.com/magento'; |
33: | const ADMIN_URL = '/admin'; |
34: | |
35: | const DEFAULT_VERSION_LOCK = 'major'; |
36: | |
37: | protected $aclList = array( |
38: | 'min' => array( |
39: | 'media', |
40: | 'var', |
41: | 'downloader', |
42: | 'generated', |
43: | 'pub/static' |
44: | ), |
45: | 'max' => array( |
46: | 'media/downloadable', |
47: | 'downloader', |
48: | 'var/cache', |
49: | 'var/session', |
50: | 'var/page_cache', |
51: | 'var/log', |
52: | 'generated/code', |
53: | 'generated/metadata', |
54: | 'pub/static' |
55: | ) |
56: | ); |
57: | |
58: | |
59: | |
60: | |
61: | |
62: | |
63: | public function __construct() |
64: | { |
65: | |
66: | parent::__construct(); |
67: | } |
68: | |
69: | |
70: | |
71: | |
72: | |
73: | |
74: | |
75: | |
76: | |
77: | public function install(string $hostname, string $path = '', array $opts = array()): bool |
78: | { |
79: | if (!$this->mysql_enabled()) { |
80: | return error('%(what)s must be enabled to install %(app)s', |
81: | ['what' => 'MySQL', 'app' => static::APP_NAME]); |
82: | } |
83: | $docroot = $this->getAppRoot($hostname, $path); |
84: | if (!$docroot) { |
85: | return error('failed to install Magento'); |
86: | } |
87: | |
88: | if (!$this->parseInstallOptions($opts, $hostname, $path)) { |
89: | return false; |
90: | } |
91: | |
92: | if (!is_debug() && !$this->ssl_permitted()) { |
93: | return error('Account requires SSL enabled on account to manage a Magento store'); |
94: | } |
95: | if (empty($opts['ssl'])) { |
96: | return error('Magento requires SSL to operate'); |
97: | } |
98: | |
99: | $version = $opts['version']; |
100: | $args = array(); |
101: | |
102: | $vercap = !empty($args['version']) && $args['version'][0] === 2 && $this->mysql_version() < 50600; |
103: | if (!$vercap && !\Opcenter\Php::extensionEnabled('intl')) { |
104: | warn('intl extension missing - Magento capped to 1.x branch'); |
105: | $vercap = true; |
106: | } |
107: | if (version_compare(Opcenter\Php::version(), '7.1', '<')) { |
108: | warn('Magento 2.x requires PHP 7.1+. Capping to 1.x'); |
109: | $version = $this->getLatestVersion('1'); |
110: | } else if (null !== $version) { |
111: | if (!$this->_versionValid($version)) { |
112: | return error("unknown Magento version `%s'", $version); |
113: | } |
114: | if ($vercap) { |
115: | warn('capping magento version to 1.x'); |
116: | $version = $this->getLatestVersion('1'); |
117: | } |
118: | } else { |
119: | $version = $this->getLatestVersion($vercap ? '1' : null); |
120: | } |
121: | $args['version'] = $version; |
122: | |
123: | if (version_compare($args['version'], '2', '>=')) { |
124: | if (version_compare($args['version'], '2.2', '>=') && version_compare(Opcenter\Php::version(), '7.1', |
125: | '<')) { |
126: | return error('Magento 2.2+ required for PHP 7.1'); |
127: | } |
128: | $args['vername'] = 'magento-ce-' . $args['version']; |
129: | } else { |
130: | |
131: | $args['vername'] = 'apnscp-mirror-' . $args['version']; |
132: | } |
133: | if (!$this->get_key() && version_compare($args['version'], '2.0', '>=')) { |
134: | return error('Magento Connect key must be setup first, do so via Account > Settings'); |
135: | } |
136: | $fqdn = $this->web_normalize_hostname($hostname); |
137: | $args['baseurl'] = 'http://' . $fqdn; |
138: | if ($path) { |
139: | $args['baseurl'] .= '/' . $path; |
140: | } |
141: | |
142: | $db = \Module\Support\Webapps\DatabaseGenerator::mysql($this->getAuthContext(), $hostname); |
143: | if (!$db->create()) { |
144: | return false; |
145: | } |
146: | |
147: | $args['dbuser'] = $db->username; |
148: | $args['dbpass'] = $db->password; |
149: | $args['dbname'] = $db->database; |
150: | $args['dbhost'] = $db->hostname; |
151: | $args['docroot'] = $docroot; |
152: | $magerunver = 1; |
153: | if (version_compare($args['version'], '2.0', '>=')) { |
154: | $magerunver = 2; |
155: | } |
156: | |
157: | |
158: | $magerunconf = $this->_copyMagerunConfig($magerunver); |
159: | |
160: | $cmd = 'install -n --installationFolder=%(docroot)s --dbHost=%(dbhost)s --baseUrl=%(baseurl)s ' . |
161: | '--dbUser=%(dbuser)s --dbPass=%(dbpass)s --installSampleData=no --dbName=%(dbname)s --magentoVersionByName=' . |
162: | '%(vername)s'; |
163: | $ret = $this->_exec($docroot, $cmd, $args, $magerunver); |
164: | if ($magerunconf && $this->file_exists($magerunconf)) { |
165: | $this->file_delete($magerunconf); |
166: | } |
167: | if (!$ret['success']) { |
168: | info('removing temporary files'); |
169: | $this->file_delete($docroot, true); |
170: | $db->rollback(); |
171: | if (false !== strpos($ret['stderr'], 'to locate Magento version')) { |
172: | return error("failed to install magento: unknown Magento version `%s'", |
173: | $args['version'] |
174: | ); |
175: | } |
176: | |
177: | return error('failed to install magento: %s', coalesce($ret['stderr'], $ret['stdout'])); |
178: | } |
179: | |
180: | |
181: | $ret = $this->_exec($docroot, 'admin:user:delete -f admin'); |
182: | if (!$ret['success']) { |
183: | warn('failed to delete placeholder admin'); |
184: | } |
185: | $this->_exec($docroot, 'cache:enable'); |
186: | |
187: | $autogenpw = false; |
188: | if (!isset($opts['password'])) { |
189: | $autogenpw = true; |
190: | $opts['password'] = \Opcenter\Auth\Password::generate(10); |
191: | info("autogenerated password `%s'", $opts['password']); |
192: | } |
193: | |
194: | info("setting admin user to `%s'", $opts['username']); |
195: | |
196: | $args = array( |
197: | 'email' => $opts['email'], |
198: | 'user' => $opts['user'], |
199: | 'password' => $opts['password'] |
200: | ); |
201: | if ($magerunver === 1) { |
202: | $this->_exec($docroot, 'admin:user:create %(user)s %(email)s %(password)s Store Admin', $args); |
203: | } else { |
204: | $this->_exec($docroot, 'admin:user:create --admin-user %(user)s --admin-email %(email)s ' . |
205: | '--admin-password %(password)s --admin-firstname Store --admin-lastname Admin', $args); |
206: | } |
207: | if (!$ret['success']) { |
208: | info('removing temporary files'); |
209: | $this->file_delete($docroot, true); |
210: | $db->rollback(); |
211: | |
212: | return error('failed to create admin user: %s', $ret['stdout']); |
213: | } |
214: | |
215: | |
216: | |
217: | $this->file_touch($docroot . '/.htaccess'); |
218: | parent::fixRewriteBase($docroot, $path); |
219: | parent::fixSymlinkTraversal($docroot); |
220: | if ($magerunver === 2) { |
221: | parent::fixRewriteBase($docroot . '/pub', rtrim($path, '/') . '/'); |
222: | parent::fixRewriteBase($docroot . '/pub/static', rtrim($path, '/') . '/static'); |
223: | } |
224: | |
225: | |
226: | $version = $this->get_version($hostname, $path); |
227: | $params = array( |
228: | 'version' => $version, |
229: | 'hostname' => $hostname, |
230: | 'path' => $path, |
231: | 'autoupdate' => (bool)$opts['autoupdate'], |
232: | ); |
233: | $this->map('add', $docroot, $params); |
234: | $this->fortify($hostname, $path, 'max'); |
235: | if ($this->guessMajor($docroot) === 1) { |
236: | $this->file_chmod($docroot . '/app/etc/local.xml', 644); |
237: | $this->_fixModelPHP7($docroot); |
238: | } |
239: | $this->_fixConnectConfig($docroot); |
240: | $url = 'https://' . $fqdn . '/' . $path . '/'; |
241: | $args = array( |
242: | 'path' => 'web/secure/base_url', |
243: | 'url' => rtrim($url, '/') . '/' |
244: | ); |
245: | $this->_exec($docroot, 'config:set %(path)s %(url)s', $args); |
246: | if ($magerunver === 2) { |
247: | $this->_exec($docroot, 'config:set web/secure/use_in_frontend 1'); |
248: | } |
249: | $this->_exec($docroot, 'cache:flush'); |
250: | |
251: | |
252: | |
253: | |
254: | |
255: | |
256: | if ($magerunver === 1) { |
257: | $this->_fixModelPHP7($docroot); |
258: | } |
259: | |
260: | if (array_get($opts, 'notify', true)) { |
261: | $msg = 'Hello!' . "\r\n" . |
262: | 'This is a confirmation that Magento has been installed under ' . $docroot . |
263: | '. You may access Magento via ' . $url . '. Access the administrative ' . |
264: | 'panel at ' . rtrim($url, '/') . self::ADMIN_URL . ' using the following details:' . "\r\n\r\n" . |
265: | 'Username: ' . $opts['user'] . "\r\n" . |
266: | ($autogenpw ? 'Password: ' . $opts['password'] . "\r\n" : ''); |
267: | $msg .= "\r\nWhen installing plugins or themes, you will need to use your " . |
268: | 'control panel password!'; |
269: | $hdrs = 'From: ' . Crm_Module::FROM_NAME . ' <' . |
270: | Crm_Module::FROM_ADDRESS . ">\r\nReply-To: " . Crm_Module::REPLY_ADDRESS; |
271: | Mail::send($opts['email'], 'Magento Installed', $msg, $hdrs); |
272: | } |
273: | |
274: | return info('%(app)s installed - confirmation email with login info sent to %(email)s', |
275: | ['app' => static::APP_NAME, 'email' => $opts['email']]); |
276: | } |
277: | |
278: | protected function getAppRoot(string $hostname, string $path = ''): ?string |
279: | { |
280: | return parent::getAppRoot($hostname, $path); |
281: | } |
282: | |
283: | |
284: | |
285: | |
286: | |
287: | |
288: | |
289: | private function _versionValid($version): bool |
290: | { |
291: | $versions = $this->_getVersions(); |
292: | |
293: | return in_array($version, $versions); |
294: | } |
295: | |
296: | |
297: | |
298: | |
299: | |
300: | |
301: | protected function _getVersions(): array |
302: | { |
303: | $key = 'magento.versions'; |
304: | $cache = Cache_Super_Global::spawn(); |
305: | |
306: | |
307: | if (false !== ($vers = $cache->get($key))) { |
308: | return $vers; |
309: | } |
310: | |
311: | $req = file_get_contents(self::VERSION_CHECK_URL . '?all'); |
312: | if (!$req) { |
313: | return array(); |
314: | } |
315: | $req = json_decode($req); |
316: | $cache->set($key, $req, 43200); |
317: | |
318: | return $req; |
319: | } |
320: | |
321: | |
322: | |
323: | |
324: | |
325: | |
326: | public function get_key() |
327: | { |
328: | $file = $this->_keyAuthFile(); |
329: | if (!$this->file_exists($file)) { |
330: | return null; |
331: | } |
332: | $contents = json_decode($this->file_get_file_contents($file), true); |
333: | if (!isset($contents['http-basic']['repo.magento.com'])) { |
334: | return null; |
335: | } |
336: | $tmp = $contents['http-basic']['repo.magento.com']; |
337: | |
338: | return array($tmp['username'], $tmp['password']); |
339: | } |
340: | |
341: | private function _keyAuthFile() |
342: | { |
343: | $home = $this->user_get_home(); |
344: | |
345: | return $home . '/.composer/auth.json'; |
346: | } |
347: | |
348: | private function _copyMagerunConfig($version = 1) |
349: | { |
350: | $f = resource_path('storehouse/magento/magento' . $version . '.yaml'); |
351: | if (!file_exists($f)) { |
352: | return error('failed to locate magento download YAML'); |
353: | } |
354: | $filename = '.n98-magerun' . ($version > 1 ? $version : '') . '.yaml'; |
355: | copy($f, $this->domain_fs_path() . '/tmp/' . $filename); |
356: | $dest = $this->user_get_home() . '/' . $filename; |
357: | $this->file_copy('/tmp/' . $filename, $dest); |
358: | unlink($this->domain_fs_path() . '/tmp/' . $filename); |
359: | |
360: | return $dest; |
361: | } |
362: | |
363: | private function _exec(string $path = null, $cmd, array $args = array(), $ver = null) |
364: | { |
365: | |
366: | if ($path && null === $ver) { |
367: | $ver = $this->guessMajor($path); |
368: | } |
369: | |
370: | $magerun = $ver === 1 ? self::MAGENTO_CLI : self::MAGENTO2_CLI; |
371: | |
372: | $tz = date_default_timezone_get(); |
373: | $cli = 'php -d pdo_mysql.default_socket=' . escapeshellarg(ini_get('mysqli.default_socket')) . |
374: | ' -d date.timezone=' . $tz . ' -d memory_limit=192m ' . $magerun . ''; |
375: | |
376: | if (!is_array($args)) { |
377: | $args = func_get_args(); |
378: | array_shift($args); |
379: | } |
380: | $user = $this->username; |
381: | if ($path) { |
382: | $cli = 'cd %(path)s && ' . $cli; |
383: | $args['path'] = $path; |
384: | $stat = $this->file_stat($path); |
385: | $user = !empty($stat['owner']) && $stat['uid'] >= \a23r::get_class_from_module('user')::MIN_UID ? |
386: | $stat['owner'] : $this->username; |
387: | } |
388: | $cmd = $cli . ' ' . $cmd; |
389: | $ret = $this->pman_run($cmd, $args, null, ['user' => $user]); |
390: | if (!$ret['success'] && $ret['stderr']) { |
391: | $ret['stderr'] = $ret['stdout']; |
392: | } |
393: | |
394: | return $ret; |
395: | } |
396: | |
397: | |
398: | |
399: | |
400: | |
401: | |
402: | |
403: | |
404: | public function get_version(string $hostname, string $path = ''): ?string |
405: | { |
406: | if (!$this->valid($hostname, $path)) { |
407: | return null; |
408: | } |
409: | |
410: | $approot = $this->getAppRoot($hostname, $path); |
411: | |
412: | $ret = $this->_exec($approot, 'sys:info --format=json', []); |
413: | |
414: | if (!$ret['success']) { |
415: | return null; |
416: | } |
417: | $info = json_decode($ret['stdout'], true); |
418: | foreach ($info as $el) { |
419: | if (strtolower($el['name']) === 'version') { |
420: | return $el['value']; |
421: | } |
422: | } |
423: | |
424: | return null; |
425: | |
426: | } |
427: | |
428: | |
429: | |
430: | |
431: | |
432: | |
433: | |
434: | |
435: | public function valid(string $hostname, string $path = ''): bool |
436: | { |
437: | if ($hostname[0] == '/') { |
438: | $docroot = $hostname; |
439: | } else { |
440: | $docroot = $this->getAppRoot($hostname, $path); |
441: | if (!$docroot) { |
442: | return false; |
443: | } |
444: | } |
445: | |
446: | return $this->guessMajor($docroot) !== null; |
447: | } |
448: | |
449: | private function _fixModelPHP7($docroot) |
450: | { |
451: | |
452: | |
453: | if (version_compare(platform_version(), '6.5', '<')) { |
454: | return true; |
455: | } |
456: | $f = $docroot . '/app/code/core/Mage/Core/Model/Layout.php'; |
457: | $contents = $this->file_get_file_contents($f); |
458: | $old = '$out .= $this->getBlock($callback[0])->$callback[1]();'; |
459: | $new = '$out .= $this->getBlock($callback[0])->{$callback[1]}();'; |
460: | $replacement = str_replace($old, $new, $contents); |
461: | |
462: | return $this->file_put_file_contents($f, $replacement); |
463: | } |
464: | |
465: | private function _fixConnectConfig($docroot) |
466: | { |
467: | $file = $docroot . '/downloader/connect.cfg'; |
468: | $preamble = '::ConnectConfig::v::1.0::'; |
469: | if ($this->file_exists($file)) { |
470: | $raw = $this->file_get_file_contents($file); |
471: | if (!preg_match('/^((?:::[[[:alnum:].]*]*)+?)([sibNaO]:.*)$/mi', $raw, $preamble)) { |
472: | return error('cannot set Magento Connect FTP login information, ' . |
473: | 'config is malformed: %s', $raw); |
474: | } |
475: | $contents = \Util_PHP::unserialize($preamble[2]); |
476: | $preamble = $preamble[1]; |
477: | } else { |
478: | $contents = array(); |
479: | } |
480: | $contents['remote_config'] = 'ftp://' . $this->username . '@' . $this->domain . ':debug@localhost'; |
481: | $contents['downloader_path'] = $this->domain_fs_path() . $docroot . '/downloader'; |
482: | $contents['magento_root'] = $this->domain_fs_path() . $docroot; |
483: | $newdata = $preamble . serialize($contents); |
484: | |
485: | return $this->file_put_file_contents($file, $newdata); |
486: | } |
487: | |
488: | |
489: | |
490: | |
491: | |
492: | |
493: | |
494: | |
495: | |
496: | |
497: | public function install_plugin( |
498: | string $hostname, |
499: | string $path, |
500: | string $plugin, |
501: | string $version = 'stable' |
502: | ): bool { |
503: | $docroot = $this->getAppRoot($hostname, $path); |
504: | if (!$docroot) { |
505: | return error('invalid WP location'); |
506: | } |
507: | |
508: | return info('not implemented'); |
509: | } |
510: | |
511: | |
512: | |
513: | |
514: | |
515: | |
516: | |
517: | |
518: | |
519: | |
520: | public function uninstall_plugin(string $hostname, string $path, string $plugin, bool $force = false): bool |
521: | { |
522: | $docroot = $this->getAppRoot($hostname, $path); |
523: | if (!$docroot) { |
524: | return error('invalid Magento location'); |
525: | } |
526: | |
527: | return info('not implemented'); |
528: | } |
529: | |
530: | |
531: | |
532: | |
533: | |
534: | |
535: | |
536: | |
537: | public function disable_all_plugins(string $hostname, string $path = ''): bool |
538: | { |
539: | $docroot = $this->getAppRoot($hostname, $path); |
540: | if (!$docroot) { |
541: | return error('failed to determine path'); |
542: | } |
543: | |
544: | return info('not implemented'); |
545: | } |
546: | |
547: | |
548: | |
549: | |
550: | |
551: | |
552: | |
553: | |
554: | |
555: | public function uninstall(string $hostname, string $path = '', string $delete = 'all'): bool |
556: | { |
557: | |
558: | |
559: | |
560: | return parent::uninstall($hostname, $path, $delete); |
561: | } |
562: | |
563: | |
564: | |
565: | |
566: | |
567: | |
568: | |
569: | |
570: | public function db_config(string $hostname, string $path = '') |
571: | { |
572: | $docroot = $this->getAppRoot($hostname, $path); |
573: | if (!$docroot) { |
574: | return error('failed to determine Magento'); |
575: | } |
576: | if ($this->guessMajor($docroot) === 1) { |
577: | $file = $this->domain_fs_path() . $docroot . '/app/etc/local.xml'; |
578: | $code = simplexml_load_string(file_get_contents($file, false), 'SimpleXMLElement', LIBXML_NOCDATA); |
579: | $conn = $code->xpath('//connection'); |
580: | if (!$conn) { |
581: | return error("failed to obtain Magento configuration for `%s'", $docroot); |
582: | } |
583: | $conn = array_pop($conn); |
584: | |
585: | return array( |
586: | 'user' => (string)$conn->username, |
587: | 'host' => (string)$conn->host, |
588: | 'db' => (string)$conn->dbname, |
589: | 'password' => (string)$conn->password, |
590: | 'prefix' => (string)$conn->prefix |
591: | ); |
592: | } |
593: | $file = \dirname($docroot) . '/app/etc/env.php'; |
594: | $fstfile = $this->domain_fs_path() . $file; |
595: | |
596: | if (!file_exists($fstfile)) { |
597: | return error("failed to obtain Magento configuration for `%s'", $docroot); |
598: | } |
599: | |
600: | $ret = $this->pman_run('cd %s && php -r %s', [ |
601: | \dirname($docroot), |
602: | 'echo json_encode(include "' . $file . '", true);' |
603: | ], [], ['user' => $this->getDocrootUser($docroot)]); |
604: | |
605: | if (!$ret['success']) { |
606: | warn("Failed to parse `%s'", $file); |
607: | return []; |
608: | } |
609: | |
610: | $conn = json_decode($ret['stdout'], true); |
611: | return [ |
612: | 'user' => array_get($conn, 'connection.default.username'), |
613: | 'host' => array_get($conn, 'connection.default.host'), |
614: | 'db' => array_get($conn, 'connection.default.dbname'), |
615: | 'password' => array_get($conn, 'connection.default.password'), |
616: | 'prefix' => array_get($conn, 'table_prefix'), |
617: | ]; |
618: | } |
619: | |
620: | |
621: | |
622: | |
623: | |
624: | |
625: | |
626: | |
627: | public function is_current(string $version = null, string $branchcomp = null) |
628: | { |
629: | return parent::is_current($version, $branchcomp); |
630: | } |
631: | |
632: | |
633: | |
634: | |
635: | |
636: | |
637: | |
638: | |
639: | |
640: | |
641: | |
642: | public function change_admin(string $hostname, string $path, array $fields): bool |
643: | { |
644: | $approot = $this->getAppRoot($hostname, $path); |
645: | if (!$approot) { |
646: | return warn('failed to change administrator information'); |
647: | } |
648: | $admin = $this->get_admin($hostname, $path); |
649: | |
650: | if (!$admin) { |
651: | return error('cannot determine admin of Magento install'); |
652: | } |
653: | $args = array( |
654: | 'username' => $admin |
655: | ); |
656: | if (isset($fields['password'])) { |
657: | $args['password'] = $fields['password']; |
658: | $ret = $this->_exec($approot, 'admin:user:change-password %(username)s %(password)s', $args); |
659: | if (!$ret['success']) { |
660: | return error("failed to change admin password, `%s'", $ret['stderr']); |
661: | } |
662: | } else { |
663: | return warn('no other fields besides password implemented'); |
664: | } |
665: | |
666: | return true; |
667: | |
668: | } |
669: | |
670: | |
671: | |
672: | |
673: | |
674: | |
675: | |
676: | |
677: | public function get_admin(string $hostname, string $path = ''): ?string |
678: | { |
679: | $approot = $this->getAppRoot($hostname, $path); |
680: | $ret = $this->_exec($approot, 'admin:user:list --format=json'); |
681: | if (!$ret['success']) { |
682: | warn('failed to enumerate administrative users'); |
683: | |
684: | return null; |
685: | } |
686: | $users = json_decode($ret['stdout'], true); |
687: | if (!$users) { |
688: | error('no administrative users found'); |
689: | |
690: | return null; |
691: | } |
692: | foreach ($users as $user) { |
693: | if ($user['status'] === 'active') { |
694: | break; |
695: | } |
696: | } |
697: | |
698: | return $user['username']; |
699: | } |
700: | |
701: | |
702: | |
703: | |
704: | public function has_fortification(string $hostname, string $path = '', string $mode = null): bool |
705: | { |
706: | return parent::has_fortification($hostname, $path, $mode); |
707: | } |
708: | |
709: | |
710: | |
711: | |
712: | public function fortification_modes(string $hostname, string $path = ''): array |
713: | { |
714: | return parent::fortification_modes($hostname, $path); |
715: | } |
716: | |
717: | |
718: | |
719: | |
720: | |
721: | |
722: | |
723: | |
724: | public function fortify(string $hostname, string $path = '', string $mode = 'max', $args = []): bool |
725: | { |
726: | return parent::fortify($hostname, $path, $mode); |
727: | } |
728: | |
729: | |
730: | |
731: | |
732: | |
733: | |
734: | |
735: | |
736: | public function unfortify(string $hostname, string $path = ''): bool |
737: | { |
738: | return parent::unfortify($hostname, $path); |
739: | } |
740: | |
741: | |
742: | |
743: | |
744: | |
745: | |
746: | |
747: | |
748: | |
749: | public function update_all(string $hostname, string $path = '', string $version = null): bool |
750: | { |
751: | $ret = ($this->update($hostname, $path, $version) && $this->update_plugins($hostname, $path) && |
752: | $this->update_themes($hostname, $path)) || error('failed to update all components'); |
753: | |
754: | parent::setInfo($this->getDocumentRoot($hostname, $path), [ |
755: | 'version' => $this->get_version($hostname, $path), |
756: | 'failed' => !$ret |
757: | ]); |
758: | |
759: | return $ret; |
760: | } |
761: | |
762: | |
763: | |
764: | |
765: | |
766: | |
767: | |
768: | |
769: | |
770: | public function update(string $hostname, string $path = '', string $version = null): bool |
771: | { |
772: | $docroot = $this->getAppRoot($hostname, $path); |
773: | if (!$docroot) { |
774: | return error('update failed'); |
775: | } |
776: | |
777: | return error('Magento updates not supported yet'); |
778: | } |
779: | |
780: | |
781: | |
782: | |
783: | |
784: | |
785: | |
786: | |
787: | |
788: | public function update_plugins(string $hostname, string $path = '', array $plugins = array()): bool |
789: | { |
790: | $docroot = $this->getAppRoot($hostname, $path); |
791: | if (!$docroot) { |
792: | return error('update failed'); |
793: | } |
794: | |
795: | return info('to-do'); |
796: | } |
797: | |
798: | |
799: | |
800: | |
801: | |
802: | |
803: | |
804: | |
805: | |
806: | public function update_themes(string $hostname, string $path = '', array $themes = array()): bool |
807: | { |
808: | $docroot = $this->getAppRoot($hostname, $path); |
809: | if (!$docroot) { |
810: | return error('update failed'); |
811: | } |
812: | |
813: | return info('not implemented'); |
814: | } |
815: | |
816: | public function delete_key() |
817: | { |
818: | $file = $this->_keyAuthFile(); |
819: | if (!$this->file_exists($file)) { |
820: | return error("failed to get Magento key file `%s'", $file); |
821: | } |
822: | $contents = json_decode($this->file_get_file_contents($file), true); |
823: | if (!isset($contents['http-basic'])) { |
824: | return true; |
825: | } |
826: | unset($contents['http-basic']['repo.magento.com']); |
827: | |
828: | return $this->file_put_file_contents($file, json_encode($contents)); |
829: | } |
830: | |
831: | public function set_key($publickey, $privatekey) |
832: | { |
833: | if (!ctype_alnum($publickey) || !ctype_alnum($privatekey)) { |
834: | return error('invalid public and/or private magento key'); |
835: | } |
836: | $file = $this->_keyAuthFile(); |
837: | $contents = array(); |
838: | if ($this->file_exists($file)) { |
839: | $contents = $this->file_get_file_contents($file); |
840: | $contents = json_decode($contents, true); |
841: | } else if (!$this->file_exists(dirname($file))) { |
842: | $this->file_create_directory(dirname($file), 0755, true); |
843: | } |
844: | if (!isset($contents['http-basic'])) { |
845: | $contents['http-basic'] = array(); |
846: | } |
847: | $contents['http-basic']['repo.magento.com'] = array( |
848: | 'username' => $publickey, |
849: | 'password' => $privatekey |
850: | ); |
851: | |
852: | return $this->file_put_file_contents($file, json_encode($contents), true); |
853: | } |
854: | |
855: | |
856: | |
857: | |
858: | |
859: | |
860: | |
861: | public function _housekeeping(): bool |
862: | { |
863: | $clis = array( |
864: | self::MAGENTO_CLI => self::MAGENTO_CLI_URL, |
865: | self::MAGENTO2_CLI => self::MAGENTO2_CLI_URL |
866: | ); |
867: | foreach ($clis as $cli => $url) { |
868: | if (!file_exists($cli)) { |
869: | $res = Util_HTTP::download($url, $cli); |
870: | if (!$res) { |
871: | return error('failed to install magento cli'); |
872: | } |
873: | info('downloaded %s', basename($cli)); |
874: | } |
875: | |
876: | $local = $this->service_template_path('siteinfo') . '/' . $cli; |
877: | if (!file_exists($local)) { |
878: | return copy($cli, $local); |
879: | } |
880: | } |
881: | |
882: | return true; |
883: | } |
884: | |
885: | |
886: | |
887: | |
888: | |
889: | |
890: | |
891: | |
892: | |
893: | public function plugin_status(string $hostname, string $path = '', string $plugin = null) |
894: | { |
895: | return error('not implemented yet'); |
896: | } |
897: | |
898: | |
899: | |
900: | |
901: | |
902: | |
903: | public function get_versions(): array |
904: | { |
905: | return $this->_getVersions(); |
906: | } |
907: | |
908: | public function next_version(string $version, string $maximalbranch = '99999999.99999999.99999999'): ?string |
909: | { |
910: | return parent::next_version($version, $maximalbranch); |
911: | } |
912: | |
913: | public function theme_status(string $hostname, string $path = '', string $theme = null) |
914: | { |
915: | return parent::theme_status($hostname, $path, $theme); |
916: | } |
917: | |
918: | public function install_theme(string $hostname, string $path, string $theme, string $version = null): bool |
919: | { |
920: | return parent::install_theme($hostname, $path, $theme, $version); |
921: | } |
922: | |
923: | |
924: | |
925: | |
926: | public function reconfigure(string $hostname, string $path, $param, $value = null): bool |
927: | { |
928: | return parent::reconfigure($hostname, $path, $param, $value); |
929: | } |
930: | |
931: | |
932: | |
933: | |
934: | public function reconfigurables(string $hostname, string $path = ''): array |
935: | { |
936: | return parent::reconfigurables($hostname, $path); |
937: | } |
938: | } |
939: | |