WordPressSetup.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. namespace Hestia\WebApp\Installers\Wordpress;
  3. use Hestia\System\Util;
  4. use Hestia\WebApp\Installers\BaseSetup as BaseSetup;
  5. use function Hestiacp\quoteshellarg\quoteshellarg;
  6. class WordpressSetup extends BaseSetup {
  7. protected $appInfo = [
  8. "name" => "WordPress",
  9. "group" => "cms",
  10. "enabled" => true,
  11. "version" => "latest",
  12. "thumbnail" => "wp-thumb.png",
  13. ];
  14. protected $appname = "wordpress";
  15. protected $config = [
  16. "form" => [
  17. //'protocol' => [
  18. // 'type' => 'select',
  19. // 'options' => ['http','https'],
  20. //],
  21. "site_name" => ["type" => "text", "value" => "WordPress Blog"],
  22. "wordpress_account_username" => ["value" => "wpadmin"],
  23. "wordpress_account_email" => "text",
  24. "wordpress_account_password" => "password",
  25. "install_directory" => ["type" => "text", "value" => "", "placeholder" => "/"],
  26. "language" => [
  27. "type" => "select",
  28. "value" => "en_US",
  29. "options" => [
  30. "cs_CZ" => "Czech",
  31. "de_DE" => "German",
  32. "es_ES" => "Spanish",
  33. "en_US" => "English",
  34. "fr_FR" => "French",
  35. "hu_HU" => "Hungarian",
  36. "it_IT" => "Italian",
  37. "nl_NL" => "Dutch",
  38. "pt_PT" => "Portuguese",
  39. "pt_BR" => "Portuguese (Brazil)",
  40. "sk_SK" => "Slovak",
  41. "sr_RS" => "Serbian",
  42. "tr_TR" => "Turkish",
  43. "ru_RU" => "Russian",
  44. "uk" => "Ukrainian",
  45. "zh-CN" => "Simplified Chinese (China)",
  46. "zh_TW" => "Traditional Chinese",
  47. ],
  48. ],
  49. ],
  50. "database" => true,
  51. "resources" => [
  52. "wp" => ["src" => "https://wordpress.org/latest.tar.gz"],
  53. ],
  54. "server" => [
  55. "nginx" => [
  56. "template" => "wordpress",
  57. ],
  58. "php" => [
  59. "supported" => ["7.4", "8.0", "8.1", "8.2"],
  60. ],
  61. ],
  62. ];
  63. public function install(array $options = null) {
  64. parent::setAppDirInstall($options["install_directory"]);
  65. parent::install($options);
  66. parent::setup($options);
  67. $this->appcontext->runUser(
  68. "v-open-fs-file",
  69. [$this->getDocRoot("wp-config-sample.php")],
  70. $result,
  71. );
  72. foreach ($result->raw as $line_num => $line) {
  73. if ('$table_prefix =' === substr($line, 0, 15)) {
  74. $result->raw[$line_num] =
  75. '$table_prefix = \'' .
  76. addcslashes(Util::generate_string(5, false) . "_", "\\'") .
  77. "';\r\n";
  78. continue;
  79. }
  80. if (!preg_match('/^define\(\s*\'([A-Z_]+)\',([ ]+)/', $line, $match)) {
  81. continue;
  82. }
  83. $constant = $match[1];
  84. $padding = $match[2];
  85. switch ($constant) {
  86. case "DB_NAME":
  87. $result->raw[$line_num] =
  88. "define( '" .
  89. $constant .
  90. "'," .
  91. $padding .
  92. "'" .
  93. addcslashes(
  94. $this->appcontext->user() . "_" . $options["database_name"],
  95. "\\'",
  96. ) .
  97. "' );";
  98. break;
  99. case "DB_USER":
  100. $result->raw[$line_num] =
  101. "define( '" .
  102. $constant .
  103. "'," .
  104. $padding .
  105. "'" .
  106. addcslashes(
  107. $this->appcontext->user() . "_" . $options["database_user"],
  108. "\\'",
  109. ) .
  110. "' );";
  111. break;
  112. case "DB_PASSWORD":
  113. $result->raw[$line_num] =
  114. "define( '" .
  115. $constant .
  116. "'," .
  117. $padding .
  118. "'" .
  119. addcslashes($options["database_password"], "\\'") .
  120. "' );";
  121. break;
  122. case "DB_HOST":
  123. $result->raw[$line_num] =
  124. "define( '" .
  125. $constant .
  126. "'," .
  127. $padding .
  128. "'" .
  129. addcslashes("localhost", "\\'") .
  130. "' );";
  131. break;
  132. case "DB_CHARSET":
  133. $result->raw[$line_num] =
  134. "define( '" .
  135. $constant .
  136. "'," .
  137. $padding .
  138. "'" .
  139. addcslashes("utf8mb4", "\\'") .
  140. "' );";
  141. break;
  142. case "AUTH_KEY":
  143. case "SECURE_AUTH_KEY":
  144. case "LOGGED_IN_KEY":
  145. case "NONCE_KEY":
  146. case "AUTH_SALT":
  147. case "SECURE_AUTH_SALT":
  148. case "LOGGED_IN_SALT":
  149. case "NONCE_SALT":
  150. $result->raw[$line_num] =
  151. "define( '" .
  152. $constant .
  153. "'," .
  154. $padding .
  155. "'" .
  156. Util::generate_string(64) .
  157. "' );";
  158. break;
  159. }
  160. }
  161. $tmp_configpath = $this->saveTempFile(implode("\r\n", $result->raw));
  162. if (
  163. !$this->appcontext->runUser(
  164. "v-move-fs-file",
  165. [$tmp_configpath, $this->getDocRoot("wp-config.php")],
  166. $result,
  167. )
  168. ) {
  169. throw new \Exception(
  170. "Error installing config file in: " .
  171. $tmp_configpath .
  172. " to:" .
  173. $this->getDocRoot("wp-config.php") .
  174. $result->text,
  175. );
  176. }
  177. $this->appcontext->downloadUrl(
  178. "https://raw.githubusercontent.com/roots/wp-password-bcrypt/master/wp-password-bcrypt.php",
  179. null,
  180. $plugin_output,
  181. );
  182. $this->appcontext->runUser(
  183. "v-add-fs-directory",
  184. [$this->getDocRoot("wp-content/mu-plugins/")],
  185. $result,
  186. );
  187. if (
  188. !$this->appcontext->runUser(
  189. "v-copy-fs-file",
  190. [
  191. $plugin_output->file,
  192. $this->getDocRoot("wp-content/mu-plugins/wp-password-bcrypt.php"),
  193. ],
  194. $result,
  195. )
  196. ) {
  197. throw new \Exception(
  198. "Error installing wp-password-bcrypt file in: " .
  199. $plugin_output->file .
  200. " to:" .
  201. $this->getDocRoot("wp-content/mu-plugins/wp-password-bcrypt.php") .
  202. $result->text,
  203. );
  204. }
  205. $this->appcontext->run(
  206. "v-list-web-domain",
  207. [$this->appcontext->user(), $this->domain, "json"],
  208. $status,
  209. );
  210. $sslEnabled = $status->json[$this->domain]["SSL"] == "no" ? 0 : 1;
  211. $webDomain = ($sslEnabled ? "https://" : "http://") . $this->domain . "/";
  212. $webPort = $sslEnabled ? "443" : "80";
  213. if (substr($options["install_directory"], 0, 1) == "/") {
  214. $options["install_directory"] = substr($options["install_directory"], 1);
  215. }
  216. if (substr($options["install_directory"], -1, 1) == "/") {
  217. $options["install_directory"] = substr(
  218. $options["install_directory"],
  219. 0,
  220. strlen($options["install_directory"]) - 1,
  221. );
  222. }
  223. exec(
  224. "/usr/bin/curl --location --post301 --insecure --resolve " .
  225. $this->domain .
  226. ":$webPort:" .
  227. $this->appcontext->getWebDomainIp($this->domain) .
  228. " " .
  229. quoteshellarg(
  230. $webDomain . $options["install_directory"] . "/wp-admin/install.php?step=2",
  231. ) .
  232. " -d " .
  233. quoteshellarg(
  234. "weblog_title=" .
  235. rawurlencode($options["site_name"]) .
  236. "&user_name=" .
  237. rawurlencode($options["wordpress_account_username"]) .
  238. "&admin_password=" .
  239. rawurlencode($options["wordpress_account_password"]) .
  240. "&admin_password2=" .
  241. rawurlencode($options["wordpress_account_password"]) .
  242. "&admin_email=" .
  243. rawurlencode($options["wordpress_account_email"]),
  244. ),
  245. $output,
  246. $return_var,
  247. );
  248. if (
  249. strpos(implode(PHP_EOL, $output), "Error establishing a database connection") !== false
  250. ) {
  251. throw new \Exception("Error establishing a database connection");
  252. }
  253. if ($return_var > 0) {
  254. throw new \Exception(implode(PHP_EOL, $output));
  255. }
  256. return $return_var === 0;
  257. }
  258. }