more package updates to continue to prep for php 8.1 (#4731)
[openemr.git] / setup.php
blob705e2f74f8d7107dfa7a801fc1eeab93c3d6b6e7
1 <?php
3 /**
5 * Installation script.
7 * @package OpenEMR
8 * @link https://www.open-emr.org
9 * @author Roberto Vasquez <robertogagliotta@gmail.com>
10 * @author Scott Wakefield <scott@npclinics.com.au>
11 * @author Ranganath Pathak <pathak@scrs1.org>
12 * @author Brady Miller <brady.g.miller@gmail.com>
13 * @copyright Copyright (c) 2016 Roberto Vasquez <robertogagliotta@gmail.com>
14 * @copyright Copyright (c) 2016 Scott Wakefield <scott@npclinics.com.au>
15 * @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
16 * @copyright Copyright (c) 2019-2021 Brady Miller <brady.g.miller@gmail.com>
17 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
20 // Checks if the server's PHP version is compatible with OpenEMR:
21 require_once(dirname(__FILE__) . "/src/Common/Compatibility/Checker.php");
22 $response = OpenEMR\Common\Compatibility\Checker::checkPhpVersion();
23 if ($response !== true) {
24 die(htmlspecialchars($response));
27 // Set the maximum excution time and time limit to unlimited.
28 ini_set('max_execution_time', 0);
29 ini_set('display_errors', 0);
30 set_time_limit(0);
32 // Warning. If you set $allow_multisite_setup to true, this is a potential security vulnerability.
33 // Recommend setting it back to false (or removing this setup.php script entirely) after you
34 // are done with the multisite procedure.
35 $allow_multisite_setup = false;
37 // Warning. If you set $allow_cloning_setup to true, this is a potential security vulnerability.
38 // Recommend setting it back to false (or removing this setup.php script entirely) after you
39 // are done with the cloning setup procedure.
40 $allow_cloning_setup = false;
41 if (!$allow_cloning_setup && !empty($_REQUEST['clone_database'])) {
42 die("To turn on support for cloning setup, need to edit this script and change \$allow_cloning_setup to true. After you are done setting up the cloning, ensure you change \$allow_cloning_setup back to false or remove this script altogether");
45 function recursive_writable_directory_test($dir)
47 // first, collect the directory and subdirectories
48 $ri = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
49 $dirNames = array();
50 foreach ($ri as $file) {
51 if ($file->isDir()) {
52 if (!preg_match("/\.\.$/", $file->getPathname())) {
53 $dirName = realpath($file->getPathname());
54 if (!in_array($dirName, $dirNames)) {
55 $dirNames[] = $dirName;
61 // second, flag the directories that are not writable
62 $resultsNegative = array();
63 foreach ($dirNames as $value) {
64 if (!is_writable($value)) {
65 $resultsNegative[] = $value;
69 // third, send the output and return if didn't pass the test
70 if (!empty($resultsNegative)) {
71 echo "<p>";
72 $mainDirTest = "";
73 $outputs = array();
74 foreach ($resultsNegative as $failedDir) {
75 if (basename($failedDir) == basename($dir)) {
76 // need to reorder output so the main directory is at the top of the list
77 $mainDirTest = "<span class='text-danger'>UNABLE</span> to open directory '" . text(realpath($failedDir)) . "' for writing by web server.<br />\r\n";
78 } else {
79 $outputs[] = "<span class='text-danger'>UNABLE</span> to open subdirectory '" . text(realpath($failedDir)) . "' for writing by web server.<br />\r\n";
82 if ($mainDirTest) {
83 // need to reorder output so the main directory is at the top of the list
84 array_unshift($outputs, $mainDirTest);
86 foreach ($outputs as $output) {
87 echo $output;
89 echo "(configure directory permissions; see below for further instructions)</p>\r\n";
90 return 1;
91 } else {
92 echo "<code class='ml-5'>" . text(realpath($dir)) . "</code> directory and its subdirectories are <span class='text-success font-weight-bold'>ready</span>.<br /><br />\r\n";
93 return 0;
97 // Include standard libraries/classes
98 require_once dirname(__FILE__) . "/vendor/autoload.php";
100 use OpenEMR\Common\Utils\RandomGenUtils;
102 $COMMAND_LINE = php_sapi_name() == 'cli';
104 $state = isset($_POST["state"]) ? ($_POST["state"]) : '';
105 $installer = new Installer($_REQUEST);
106 // Make this true for IPPF.
107 $ippf_specific = false;
109 $error_page_end = <<<EPE
110 </div>
111 </div>
112 </div><!--end of container div-->
113 </body>
114 </html>
115 EPE;
117 // If this script was invoked with no site ID, then ask for one.
118 if (!$COMMAND_LINE && empty($_REQUEST['site'])) {
119 $site_id = <<<SITEID
120 <!DOCTYPE html>
121 <html>
122 <head>
123 <title>OpenEMR Setup Tool</title>
124 <link rel="stylesheet" href="public/assets/bootstrap/dist/css/bootstrap.min.css">
125 <script src="public/assets/jquery/dist/jquery.min.js"></script>
126 <script src="public/assets/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
127 <link rel="stylesheet" href="public/assets/@fortawesome/fontawesome-free/css/all.min.css">
128 <link rel="shortcut icon" href="public/images/favicon.ico" />
129 <style>
130 .oe-pull-away {
131 float:right;
133 </style>
134 </head>
135 <body>
136 <nav class="navbar navbar-expand navbar-light bg-light">
137 <div class="container">
138 <a class="navbar-brand" href="#">OpenEMR Setup</a>
139 <div class="collapse navbar-collapse justify-content-end">
140 <ul class="navbar-nav">
141 <li class="nav-item active">
142 <a class="nav-link" href="#" data-target="#myModal" data-toggle="modal" href="#" id="help-href" name="help-href" title="Click to view Help">Help</span></a>
143 </li>
144 </ul>
145 </div>
146 </div>
147 </nav>
149 <div class='container mt-3'>
150 <div class="row">
151 <div class="col-12">
152 <h3 class="mb-3 border-bottom">Optional Site ID Selection</h3>
153 <div class="jumbotron p-5">
155 Most OpenEMR installations support only one site. If that is
156 true for you then ignore the rest of this text and just click Continue.
157 </p>
158 <p class='p-2 bg-warning'>
159 If you are using the multisite setup module for the first time please read the
160 'Multi Site Installation' section of the help file before proceeding.
161 </p>
163 Otherwise please enter a unique Site ID here.
164 </p>
166 A Site ID is a short identifier with no spaces or special
167 characters other than periods or dashes. It is case-sensitive and we
168 suggest sticking to lower case letters for ease of use.
169 </p>
171 If each site will have its own host/domain name, then use that
172 name as the Site ID (e.g. www.example.com).
173 </p>
175 The site ID is used to identify which site you will log in to.
176 If it is a hostname then it is taken from the hostname in the URL.
177 Otherwise you must append "?site=<i>siteid</i>" to the URL used for
178 logging in.
179 </p>
181 It is OK for one of the sites to have "default" as its ID. This
182 is the ID that will be used if it cannot otherwise be determined.
183 </p>
184 <br />
185 <form method='post'>
186 <input type='hidden' name='state' value='0' />
187 <div class="form-row">
188 <div class="col-auto">
189 Site ID:
190 </div>
191 <div class="col">
192 <input type='text' class='form-control' name='site' value='default'>
193 </div>
194 <div class="col-12 mt-3">
195 <button type='submit' class='btn btn-primary' value='Continue'><i class="fas fa-chevron-right"></i> Continue</button>
196 </div>
197 </div>
198 </form>
199 </div>
200 </div>
201 </div>
202 </div><!--end of container div-->
203 SITEID;
204 echo $site_id . "\r\n";
205 $installer->setupHelpModal();
206 echo "</body>" . "\r\n";
207 echo "</html>" . "\r\n";
209 exit();
212 // Support "?site=siteid" in the URL, otherwise assume "default".
213 $site_id = 'default';
214 if (!$COMMAND_LINE && !empty($_REQUEST['site'])) {
215 $site_id = trim($_REQUEST['site']);
218 // Die if site ID is empty or has invalid characters.
219 if (empty($site_id) || preg_match('/[^A-Za-z0-9\\-.]/', $site_id)) {
220 die("Site ID '" . text($site_id) . "' contains invalid characters.");
223 // If multisite is turned off, then only allow default for site.
224 if (!$allow_multisite_setup && $site_id != 'default') {
225 die("To turn on support for multisite setup, need to edit this script and change \$allow_multisite_setup to true. After you are done setting up the cloning, ensure you change \$allow_multisite_setup back to false or remove this script altogether");
228 // Disable file and directory permissions check by setting to false
229 $checkPermissions = true;
231 global $OE_SITE_DIR; // The Installer sets this
233 $docsDirectory = "$OE_SITE_DIR/documents";
235 //These are files and dir checked before install for
236 // correct permissions.
237 if (is_dir($OE_SITE_DIR)) {
238 $writableFileList = array($installer->conffile);
239 $writableDirList = array($docsDirectory);
240 } else {
241 $writableFileList = array();
242 $writableDirList = array($OE_SITES_BASE);
245 // Include the sqlconf file if it exists yet.
246 $config = 0;
247 if (file_exists($OE_SITE_DIR)) {
248 include_once($installer->conffile);
249 } elseif ($state > 3) {
250 // State 3 should have created the site directory if it is missing.
251 die("Internal error, site directory is missing.");
254 <html>
255 <head>
256 <title>OpenEMR Setup Tool</title>
257 <!--<link rel=stylesheet href="interface/themes/style_blue.css">-->
258 <link rel="stylesheet" href="public/assets/bootstrap/dist/css/bootstrap.min.css">
259 <script src="public/assets/jquery/dist/jquery.min.js"></script>
260 <script src="public/assets/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
261 <link rel="stylesheet" href="public/assets/@fortawesome/fontawesome-free/css/all.min.css">
262 <link rel="shortcut icon" href="public/images/favicon.ico" />
264 <style>
265 .noclone { }
266 table.phpset {
267 border-collapse:collapse;
269 table.phpset td, table.phpset th {
270 font-size:9pt;
271 border:1px solid gray;
272 padding:2px;
274 .table.no-border tr td, .table.no-border tr th {
275 border-width: 0;
277 td {
278 font-size:10pt;
280 .inputtext {
281 padding-left:2px;
282 padding-right:2px;
285 .button {
286 font-family:sans-serif;
287 font-size:9pt;
288 font-weight:bold;
291 .label-div > a {
292 display:none;
294 .label-div:hover > a {
295 display:inline-block;
297 div[id$="_info"] {
298 background: #F7FAB3;
299 padding: 20px;
300 margin: 10px 15px 0px 15px;
302 div[id$="_info"] > a {
303 margin-left:10px;
305 .checkboxgroup {
306 display: inline-block;
307 text-align: center;
309 .checkboxgroup label {
310 display: block;
312 .oe-pull-away{
313 float:right;
315 .oe-help-x {
316 color: grey;
317 padding: 0 5px;
319 .oe-superscript {
320 position: relative;
321 top: -.5em;
322 font-size: 70%!important;
324 .oe-setup-legend{
325 background-color: #f5f5f5;
326 padding:0 10px;
328 .button-wait {
329 color: grey;
330 cursor: not-allowed;
331 opacity: 0.6;
333 @media only screen {
334 fieldset > [class*="col-"] {
335 width: 100%;
336 text-align:left!Important;
339 </style>
340 <script>
341 // onclick handler for "clone database" checkbox
342 function cloneClicked() {
343 var cb = document.forms[0].clone_database;
344 $('.noclone').css('display', cb.checked ? 'none' : 'block');
346 </script>
348 </head>
349 <body>
350 <nav class="navbar navbar-expand navbar-light bg-light">
351 <div class="container">
352 <a class="navbar-brand" href="#">OpenEMR Setup</a>
353 <div class="collapse navbar-collapse justify-content-end">
354 <ul class="navbar-nav">
355 <li class="nav-item active">
356 <a class="nav-link" href="#" data-target="#myModal" data-toggle="modal" href="#" id="help-href" name="help-href" title="Click to view Help">Help</span></a>
357 </li>
358 </ul>
359 </div>
360 </div>
361 </nav>
362 <div class='mt-3 container'>
363 <div class="row">
364 <div class="col-12">
365 <?php
366 $error = "<span class='text-danger font-weight-bold'>ERROR</span>";
367 $caution = "<span class='text-danger font-weight-bold'>CAUTION</span>";
368 $ok = "<span class='text-success font-weight-bold'>OK</span>";
369 $note = "<span class='text-primary font-weight-bold'>NOTE</span>";
371 if (strtolower(ini_get('register_globals')) != 'off' && (bool) ini_get('register_globals')) {
372 echo "$caution: It appears that you have register_globals enabled in your php.ini\n" .
373 "configuration file. This causes unacceptable security risks. You must\n" .
374 "turn it off before continuing with installation.\n";
375 exit(1);
378 if (!extension_loaded("xml")) {
379 echo "$error: PHP XML extension missing. To continue, install PHP XML extension, then restart web server.";
380 exit(1);
383 if (!(extension_loaded("mysql") || extension_loaded("mysqlnd") || extension_loaded("mysqli"))) {
384 echo "$error: PHP MySQL extension missing. To continue, install and enable MySQL extension, then restart web server.";
385 exit(1);
388 if (!(extension_loaded("mbstring") )) {
389 echo "$error: PHP mb_string extension missing. To continue, install and enable mb_string extension, then restart web server.";
390 exit(1);
393 if (!(extension_loaded("openssl") )) {
394 echo "$error: PHP openssl extension missing. To continue, install PHP openssl extension, then restart web server.";
395 exit(1);
399 <?php
400 if ($state == 7) {
402 <h3 class="mb-3 border-bottom">Final step - Success</h3>
403 <div class="jumbotron p-5">
404 <p>Congratulations! OpenEMR is now installed.</p>
405 <ul>
406 <li>Access controls (php-GACL) are installed for fine-grained security, and can be administered in
407 OpenEMR's admin->acl menu.</li>
408 <li>Reviewing <code> <?php echo text($OE_SITE_DIR); ?>/config.php </code> is a good idea. This file
409 contains some settings that you may want to change.</li>
410 <li>There's much information and many extra tools bundled within the OpenEMR installation directory.
411 Please refer to openemr/Documentation. Many forms and other useful scripts can be found at openemr/contrib.</li>
412 <li>To ensure a consistent look and feel throughout the application,
413 <a href='http://www.mozilla.org/products/firefox/'>Firefox</a> and <a href="https://www.google.com/chrome/browser/desktop/index.html">Chrome</a> are recommended. The OpenEMR development team exclusively tests with modern versions of these browsers.</li>
414 <li>The OpenEMR project home page, documentation, and forums can be found at <a href = "https://www.open-emr.org" rel='noopener' target="_blank">https://www.open-emr.org</a></li>
415 <li>We pursue grants to help fund the future development of OpenEMR. To apply for these grants, we need to estimate how many times this program is installed and how many practices are evaluating or using this software. It would be awesome if you would email us at <a href="mailto:hello@open-emr.org">hello@open-emr.org</a> if you have installed this software. The more details about your plans with this software, the better, but even just sending us an email stating you just installed it is very helpful.</li>
416 </ul>
417 <p>We recommend you print these instructions for future reference.</p>
418 <?php
419 echo "<p> The selected theme is :</p>";
420 $installer->displayNewThemeDiv();
421 if (empty($installer->clone_database)) {
422 echo "<p><b>The initial OpenEMR user is <span class='text-primary'>'" . text($installer->iuser) . "'</span> and the password is <span class='text-primary'>'" . text($installer->iuserpass) . "'</span></b></p>";
423 } else {
424 echo "<p>The initial OpenEMR user name and password is the same as that of source site <b>'" . text($installer->source_site_id) . "'</span></b></p>";
426 echo "<p>If you edited the PHP or Apache configuration files during this installation process, then we recommend you restart your Apache server before following below OpenEMR link.</p>";
427 echo "<p>In Linux use the following command:</p>";
428 echo "<p><code>sudo apachectl -k restart</code></p>";
431 <p>Click to start using OpenEMR.</p>
432 <div class="row">
433 <div class="col-12">
434 <a href='./?site=<?php echo attr_url($site_id); ?>' class='btn btn-primary'>
435 <i class="fas fa-chevron-right"></i> Start
436 </a>
437 </div>
438 </div>
440 </div>
441 <?php
442 $installer->setCurrentTheme();
444 $end_div = <<<ENDDIV
445 </div>
446 </div>
447 </div><!--end of container div-->
448 ENDDIV;
449 echo $end_div . "\r\n";
450 $installer->setupHelpModal();
451 echo "</body>" . "\r\n";
452 echo "</html>" . "\r\n";
454 exit();
458 <?php
460 $inst = isset($_POST["inst"]) ? ($_POST["inst"]) : '';
462 if (($config == 1) && ($state < 4)) {
463 echo "OpenEMR has already been installed. If you wish to force re-installation, then edit " . text($installer->conffile) . " (change the 'config' variable to 0), and re-run this script.<br />\n";
464 } else {
465 switch ($state) {
466 case 1:
467 $state_esc = text($state);
468 $site_id_esc = attr($site_id);
469 $step1 = <<<STP1
470 <h3 class="mb-3 border-bottom">Step $state_esc - Select Database Setup</h3>
471 <div class="jumbotron p-5">
472 <p>Now I need to know whether you want me to create the database on my own or if you have already created the database for me to use. For me to create the database, you will need to supply the MySQL root password.</p>
473 <br />
474 <p class='p-1 bg-warning'>$caution: clicking on <span class="font-weight-bold">Proceed to Step 2</span> may delete or cause damage to existing data on your system. Before you continue <span class="font-weight-bold">please backup your data</span>.</p>
475 <br />
476 <form method='post'>
477 <input name='state' type='hidden' value='2' />
478 <input name='site' type='hidden' value='$site_id_esc' />
479 <div class="form-check">
480 <input checked class='form-check-input' id='inst1' name='inst' type='radio' value='1' />
481 <label class="form-check-label" for="inst1">
482 Have setup create the database
483 </label>
484 </div>
485 <br />
486 <div class="form-check">
487 <input id='inst2' class='form-check-input' name='inst' type='radio' value='2' />
488 <label class="form-check-label" for="inst2">
489 I have already created the database
490 </label>
491 </div>
492 <div class="form-group">
493 <div class="col mt-3">
494 <button type='submit' class='btn btn-primary' value='Continue'>
495 <i class="fas fa-chevron-right"></i> Proceed to Step 2
496 </button>
497 </div>
498 </div>
499 </form>
500 <br />
501 </div>
502 STP1;
503 echo $step1 . "\r\n";
504 break;
506 case 2:
507 $state_esc = text($state);
508 $site_id_esc = attr($site_id);
509 $inst_esc = attr($inst);
510 $step2top = <<<STP2TOP
511 <h3 class="mb-3 border-bottom">Step $state_esc - Database and OpenEMR Initial User Setup Details</h3>
512 <div class="jumbotron p-5">
513 <p>Now you need to supply the MySQL server information and path information. Detailed instructions on each item can be found in the
514 <a href='Documentation/INSTALL' rel='noopener' target='_blank'><u>'INSTALL'</u>
515 </a> manual file.
516 </p>
517 <form method='post' id='myform'>
518 <input name='state' type='hidden' value='3' />
519 <input name='site' type='hidden' value='$site_id_esc' />
520 <input name='inst' type='hidden' value='$inst_esc' />
521 STP2TOP;
522 echo $step2top . "\r\n";
525 $step2tabletop1 = <<<STP2TBLTOP1
526 <fieldset>
527 <legend name="form_legend" id="form_legend" class='oe-setup-legend'>MySQL Server Details<i id="enter-details-tooltip" class="fa fa-info-circle oe-text-black oe-superscript enter-details-tooltip" aria-hidden="true"></i></legend>
528 <div class="ml-2 row">
529 <div class="col-sm-4">
530 <div class="clearfix form-group">
531 <div class="label-div">
532 <label class="font-weight-bold" for="server">Server Host:</label>
533 <a href="#server_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
534 </div>
535 <div>
536 <input name='server' id='server' type='text' class='form-control' value='localhost' />
537 </div>
538 </div>
539 <div id="server_info" class="collapse">
540 <a href="#server_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
541 <p>If you run MySQL and Apache/PHP on the same computer, then leave this as 'localhost'.</p>
542 <p>If they are on separate computers, then enter the IP address of the computer running MySQL.</p>
543 </div>
544 </div>
545 <div class="col-sm-4">
546 <div class="clearfix form-group">
547 <div class="label-div">
548 <label class="font-weight-bold" for="port">Server Port:</label>
549 <a href="#port_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
550 </div>
551 <div>
552 <input name='port' id='port' type='text' class='form-control' value='3306' />
553 </div>
554 </div>
555 <div id="port_info" class="collapse">
556 <a href="#port_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
557 <p>This is the MySQL port.</p>
558 <p>The default port for MySQL is 3306.</p>
559 </div>
560 </div>
561 <div class="col-sm-4">
562 <div class="clearfix form-group">
563 <div class="label-div">
564 <label class="font-weight-bold" for="dbname">Database Name:</label> <a href="#dbname_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
565 </div>
566 <div>
567 <input name='dbname' id='dbname' type='text' class='form-control' value='openemr' />
568 </div>
569 </div>
570 <div id="dbname_info" class="collapse">
571 <a href="#dbname_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
572 <p>This will be the name of the OpenEMR database in MySQL.</p>
573 <p>'openemr' is the recommended name.</p>
574 <p>This database will contain patient data as well as data pertaining to the OpenEMR installation.</p>
575 </div>
576 </div>
577 </div>
578 <div class="ml-2 row">
579 <div class="col-sm-4">
580 <div class="clearfix form-group">
581 <div class="label-div">
582 <label class="font-weight-bold" for="login">Login Name:</label> <a href="#login_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
583 </div>
584 <div>
585 <input name='login' ID='login' type='text' class='form-control' value='openemr' />
586 </div>
587 </div>
588 <div id="login_info" class="collapse">
589 <a href="#login_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
590 <p>This is the name that OpenEMR will use to login to the MySQL database.</p>
591 <p>'openemr' is the recommended name.</p>
592 </div>
593 </div>
594 <div class="col-sm-4">
595 <div class="clearfix form-group">
596 <div class="label-div">
597 <label class="font-weight-bold" for="pass">Password:</label>
598 <a href="#pass_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
599 </div>
600 <div>
601 <input name='pass' id='pass' class='form-control' type='password' value='' required />
602 </div>
603 </div>
604 <div id="pass_info" class="collapse">
605 <a href="#pass_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
606 <p>This is the Login Password that OpenEMR will use to accesses the MySQL database.</p>
607 <p>It should be at least 12 characters long and composed of both numbers and letters.</p>
608 </div>
609 </div>
610 STP2TBLTOP1;
611 echo $step2tabletop1 . "\r\n";
612 if ($inst != 2) {
613 $step2tabletop2 = <<<STP2TBLTOP2
614 <div class="col-sm-4">
615 <div class="clearfix form-group">
616 <div class="label-div">
617 <label class="font-weight-bold" for="root">Name for Root Account:</label>
618 <a href="#root_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
619 </div>
620 <div>
621 <input name='root' id='root' type='text' class='form-control' value='root' />
622 </div>
623 </div>
624 <div id="root_info" class="collapse">
625 <a href="#root_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
626 <p>This is name for the MySQL root account.</p>
627 <p>For localhost, it is usually ok to leave it as 'root'.</p>
628 </div>
629 </div>
630 </div>
631 <div class="ml-2 row">
632 <div class="col-sm-4">
633 <div class="clearfix form-group">
634 <div class="label-div">
635 <label class="font-weight-bold" for="rootpass">Root Password:</label>
636 <a href="#rootpass_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
637 </div>
638 <div>
639 <input name='rootpass' id='rootpass' type='password' class='form-control' value='' />
640 </div>
641 </div>
642 <div id="rootpass_info" class="collapse">
643 <a href="#rootpass_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
644 <p>This is your MySQL server root password.</p>
645 </div>
646 </div>
647 <div class="col-sm-4">
648 <div class="clearfix form-group">
649 <div class="label-div">
650 <label class="font-weight-bold" for="loginhost">User Hostname:</label>
651 <a href="#loginhost_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
652 </div>
653 <div>
654 <input name='loginhost' id='loginhost' type='text' class='form-control' value='localhost' />
655 </div>
656 </div>
657 <div id="loginhost_info" class="collapse">
658 <a href="#loginhost_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
659 <p>If you run Apache/PHP and MySQL on the same computer, then leave this as 'localhost'.</p>
660 <p>If they are on separate computers, then enter the IP address of the computer running Apache/PHP.</p>
661 </div>
662 </div>
663 <div class="col-sm-4">
664 <div class="clearfix form-group">
665 <div class="label-div">
666 <label class="font-weight-bold" for="collate">UTF-8 Collation:</label> <a href="#collate_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
667 </div>
668 <div>
669 <select name='collate' id=='collate' class='form-control'>
670 <option selected value='utf8mb4_general_ci'>
671 General (Recommended)
672 </option>
673 <option value='utf8mb4_unicode_ci'>
674 Unicode
675 </option>
676 <option value='utf8mb4_roman_ci'>
677 Classical Latin
678 </option>
679 <option value='utf8mb4_croatian_ci'>
680 Croatian
681 </option>
682 <option value='utf8mb4_czech_ci'>
683 Czech
684 </option>
685 <option value='utf8mb4_danish_ci'>
686 Danish
687 </option>
688 <option value='utf8mb4_esperanto_ci'>
689 Esperanto
690 </option>
691 <option value='utf8mb4_estonian_ci'>
692 Estonian
693 </option>
694 <option value='utf8mb4_german2_ci'>
695 German
696 </option>
697 <option value='utf8mb4_hungarian_ci'>
698 Hungarian
699 </option>
700 <option value='utf8mb4_icelandic_ci'>
701 Icelandic
702 </option>
703 <option value='utf8mb4_latvian_ci'>
704 Latvian
705 </option>
706 <option value='utf8mb4_lithuanian_ci'>
707 Lithuanian
708 </option>
709 <option value='utf8mb4_persian_ci'>
710 Persian
711 </option>
712 <option value='utf8mb4_polish_ci'>
713 Polish
714 </option>
715 <option value='utf8mb4_romanian_ci'>
716 Romanian
717 </option>
718 <option value='utf8mb4_sinhala_ci'>
719 Sinhala
720 </option>
721 <option value='utf8mb4_slovak_ci'>
722 Slovak
723 </option>
724 <option value='utf8mb4_slovenian_ci'>
725 Slovenian
726 </option>
727 <option value='utf8mb4_spanish_ci'>
728 Spanish (Modern)
729 </option>
730 <option value='utf8mb4_spanish2_ci'>
731 Spanish (Traditional)
732 </option>
733 <option value='utf8mb4_swedish_ci'>
734 Swedish
735 </option>
736 <option value='utf8mb4_turkish_ci'>
737 Turkish
738 </option>
739 <option value='utf8mb4_vietnamese_ci'>
740 Vietnamese
741 </option>
742 </select>
743 </div>
744 </div>
745 <div id="collate_info" class="collapse">
746 <a href="#collate_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
747 <p>This is the collation setting for MySQL.</p>
748 <p>Collation refers to a set of rules that determine how data is sorted and compared in a database.</p>
749 <p>Leave as 'General' if you are not sure.</p>
750 <p>If the language you are planning to use in OpenEMR is in the menu, then you can select it.</p>
751 <p>Otherwise, just select 'General'.</p>
752 </div>
753 </div>
754 </div>
755 STP2TBLTOP2;
756 echo $step2tabletop2 . "\r\n";
758 // Include a "source" site ID drop-list and a checkbox to indicate
759 // if cloning its database. When checked, do not display initial user
760 // and group stuff below.
761 $dh = opendir($OE_SITES_BASE);
762 if (!$dh) {
763 die("Cannot read directory '" . text($OE_SITES_BASE) . "'.");
766 $siteslist = array();
767 while (false !== ($sfname = readdir($dh))) {
768 if (substr($sfname, 0, 1) == '.') {
769 continue;
772 if ($sfname == 'CVS') {
773 continue;
776 if ($sfname == $site_id) {
777 continue;
780 $sitedir = "$OE_SITES_BASE/$sfname";
781 if (!is_dir($sitedir)) {
782 continue;
785 if (!is_file("$sitedir/sqlconf.php")) {
786 continue;
789 $siteslist[$sfname] = $sfname;
792 closedir($dh);
793 // If this is not the first site...
794 if (!empty($siteslist)) {
795 ksort($siteslist);
796 $source_site_top = <<<SOURCESITETOP
797 <div class="ml-2 row">
798 <div class="col-sm-4">
799 <div class="clearfix form-group">
800 <div class="label-div">
801 <label class="font-weight-bold" for="source_site_id">Source Site:</label>
802 <a href="#source_site_id_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
803 </div>
804 <div>
805 <select name='source_site_id'id='source_site_id' class='form-control'>
806 SOURCESITETOP;
807 echo $source_site_top . "\r\n";
808 foreach ($siteslist as $sfname) {
809 echo "<option value='" . attr($sfname) . "'";
810 if ($sfname == 'default') {
811 echo " selected";
814 echo ">" . text($sfname) . "</option>";
816 $source_site_bot = <<<SOURCESITEBOT
817 </select>
819 </div>
820 </div>
821 <div id="source_site_id_info" class="collapse">
822 <a href="#source_site_id_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
823 <p>The site directory that will be a model for the new site.</p>
824 </div>
825 </div>
826 <div class="col-sm-4">
827 <div class="clearfix form-group">
828 <div class="label-div">
829 <label class="font-weight-bold" for="clone_database">Clone Source Database:</label>
830 <a href="#clone_database_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
831 </div>
832 <div>
833 <input type='checkbox' name='clone_database' id='clone_database' onclick='cloneClicked()' />
834 </div>
835 </div>
836 <div id="clone_database_info" class="collapse">
837 <a href="#clone_database_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
838 <p>Clone the source site's database instead of creating a fresh one.</p>
839 </div>
840 </div>
841 </div>
842 SOURCESITEBOT;
843 echo $source_site_bot . "\r\n";
846 $randomusernamepre = RandomGenUtils::produceRandomString(3, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
847 $randomusernamepost = RandomGenUtils::produceRandomString(2, "0123456789");
848 $randomusername = $randomusernamepre . "-admin-" . $randomusernamepost;
850 // App Based TOTP secret
851 // Shared key (per rfc6238 and rfc4226) should be 20 bytes (160 bits) and encoded in base32, which should
852 // be 32 characters in base32
853 // Would be nice to use the OpenEMR\Common\Utils\RandomGenUtils\produceRandomBytes() function and then encode to base32,
854 // but does not appear to be a standard way to encode binary to base32 in php.
855 $randomsecret = RandomGenUtils::produceRandomString(32, "234567ABCDEFGHIJKLMNOPQRSTUVWXYZ");
856 if (empty($randomsecret) || empty($randomusernamepre) || empty($randomusernamepost)) {
857 error_log('OpenEMR Error : Random String error - exiting');
858 die();
860 $disableCheckbox = "";
861 if (empty($randomsecret)) {
862 $randomsecret = "";
863 $disableCheckbox = "disabled";
866 $randomsecret_esc = attr($randomsecret);
867 $randomusername_esc = attr($randomusername);
868 $step2tablebot = <<<STP2TBLBOT
869 </fieldset>
870 <br />
871 <fieldset class='noclone'>
872 <legend name="form_legend" id="form_legend" class='oe-setup-legend'>OpenEMR Initial User Details<i id="enter-details-tooltip" class="fa fa-info-circle oe-text-black oe-superscript enter-details-tooltip" aria-hidden="true"></i></legend>
873 <div class="ml-2 row">
874 <div class="col-sm-4">
875 <div class="clearfix form-group">
876 <div class="label-div">
877 <label class="font-weight-bold" for="iuser">Initial User Login Name:</label> <a href="#iuser_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
878 </div>
879 <div>
880 <input name='iuser' id='iuser' type='text' class='form-control' value='$randomusername_esc' minlength='12' />
881 </div>
882 </div>
883 <div id="iuser_info" class="collapse">
884 <a href="#iuser_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
885 <p>This is the login name of the first user that will be created for you.</p>
886 <p>Limit this to one word with at least 12 characters and composed of both numbers and letters.</p>
887 </div>
888 </div>
889 <div class="col-sm-4">
890 <div class="clearfix form-group">
891 <div class="label-div">
892 <label class="font-weight-bold" for="iuserpass">Initial User Password:</label>
893 <a href="#iuserpass_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
894 </div>
895 <div>
896 <input name='iuserpass' id='iuserpass' type='password' class='form-control' value='' minlength='12' />
897 </div>
898 </div>
899 <div id="iuserpass_info" class="collapse">
900 <a href="#iuserpass_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
901 <p>This is the password for the initial user.
902 </div>
903 </div>
904 <div class="col-sm-4">
905 <div class="clearfix form-group">
906 <div class="label-div">
907 <label class="font-weight-bold" for="iufname">Initial User's First Name:</label>
908 <a href="#iufname_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
909 </div>
910 <div>
911 <input name='iufname' id='iufname 'type='text' class='form-control' value='Administrator' />
912 </div>
913 </div>
914 <div id="iufname_info" class="collapse">
915 <a href="#iufname_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
916 <p>This is the First name of the 'initial user'.</p>
917 </div>
918 </div>
919 </div>
920 <div class="ml-2 row">
921 <div class="col-sm-4">
922 <div class="clearfix form-group">
923 <div class="label-div">
924 <label class="font-weight-bold" for="iuname">Initial User's Last Name:</label>
925 <a href="#iuname_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
926 </div>
927 <div>
928 <input name='iuname' id='iuname' type='text' class='form-control' value='Administrator' />
929 </div>
930 </div>
931 <div id="iuname_info" class="collapse">
932 <a href="#iuname_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
933 <p>This is the Last name of the 'initial user'.</p>
934 </div>
935 </div>
936 <div class="col-sm-4">
937 <div class="clearfix form-group">
938 <div class="label-div">
939 <label class="font-weight-bold" for="igroup">Initial Group:</label>
940 <a href="#igroup_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
941 </div>
942 <div>
943 <input name='igroup' id='igroup' class='form-control' type='text' value='Default' />
944 </div>
945 </div>
946 <div id="igroup_info" class="collapse">
947 <a href="#igroup_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
948 <p>This is the group that will be created for your users.</p>
949 <p>This should be the name of your practice.</p>
950 </div>
951 </div>
952 </div>
953 </fieldset>
954 <br />
955 <fieldset class='noclone py-2 bg-warning'>
956 <legend name="form_legend" id="form_legend" class='oe-setup-legend text-danger'>Enable 2 Factor Authentication for Initial User (more secure - optional) <i id="2fa-section" class="fa fa-info-circle oe-text-black oe-superscript 2fa-section-tooltip" aria-hidden="true"></i></legend>
957 <div class="ml-2 row">
958 <div class="col-sm-3">
959 <div class="clearfix form-group">
960 <div class="label-div">
961 <label class="font-weight-bold" for="i2fa">Configure 2FA:</label>
962 <a href="#i2fa_info" class="info-anchor icon-tooltip" data-toggle="collapse"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
963 </div>
964 <div>
965 <input name='i2faenable' id='i2faenable' type='checkbox' $disableCheckbox/> Enable 2FA
966 <input type='hidden' name='i2fasecret' id='i2fasecret' value='$randomsecret_esc' />
967 </div>
968 </div>
969 <div id="i2fa_info" class="collapse">
970 <a href="#i2fa_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
971 <p>If selected will allow TOTP 2 factor authentication for the initial user.</p>
972 <p>Click on the help file for more information.</p>
973 </div>
974 </div>
975 <div class="col-sm-5">
976 <div class="clearfix form-group">
977 <p class="text-danger font-weight-bold">IMPORTANT IF ENABLED</p>
978 <p>If enabled, you must have an authenticator app on your phone ready to scan the QR code displayed next.</p>
979 </div>
980 </div>
981 <div class="col-sm-4">
982 <div class="clearfix form-group">
983 <p>Example authenticator apps include:</p>
984 <ul>
985 <li>Google Auth
986 (<a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8" target="_blank">iOS</a>, <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&amp;hl=en">Android</a>)</li>
987 <li>Authy
988 (<a href="https://itunes.apple.com/us/app/authy/id494168017?mt=8">iOS</a>, <a href="https://play.google.com/store/apps/details?id=com.authy.authy&amp;hl=en">Android</a>)</li>
989 </ul>
990 </div>
991 </div>
992 </div>
993 </fieldset>
994 <p class='mt-4 mark'>Click the <b>Create DB and User</b> button below to create the database and first user <a href='#create_db_button' title='Click me'><i class="fa fa-arrow-circle-down" aria-hidden="true"></i></a>. $note: This process will take a few minutes.</p>
995 <p class='p-1 bg-success text-white oe-spinner' style='visibility:hidden;'>Upon successful completion will automatically take you to the next step.<i class='fa fa-spinner fa-pulse fa-fw'></i></p>
996 <div class="form-row">
997 <div class="col-12">
998 <button type='submit' id='create_db_button' value='Continue' class='wait btn btn-primary'>
999 <i class="fas fa-chevron-right"></i> Create DB and User
1000 </button>
1001 </div>
1002 </div>
1003 </form>
1004 </div>
1005 STP2TBLBOT;
1006 echo $step2tablebot . "\r\n";
1007 break;
1009 case 3:
1010 // Form Validation
1011 // (applicable if not cloning from another database)
1013 $pass_step2_validation = true;
1014 $error_step2_message = "$error - ";
1016 if (! $installer->char_is_valid($_REQUEST['server'])) {
1017 $pass_step2_validation = false;
1018 $error_step2_message .= "A database server host is required <br />\n";
1021 if (! $installer->char_is_valid($_REQUEST['port'])) {
1022 $pass_step2_validation = false;
1023 $error_step2_message .= "A database server port value is required <br />\n";
1026 if (! $installer->databaseNameIsValid($_REQUEST['dbname'])) {
1027 $pass_step2_validation = false;
1028 $error_step2_message .= "A database name is required <br />\n";
1031 if (! $installer->collateNameIsValid($_REQUEST['collate'])) {
1032 $pass_step2_validation = false;
1033 $error_step2_message .= "A collation name is required <br />\n";
1036 if (! $installer->char_is_valid($_REQUEST['login'])) {
1037 $pass_step2_validation = false;
1038 $error_step2_message .= "A database login name is required <br />\n";
1041 if (! $installer->char_is_valid($_REQUEST['pass'])) {
1042 $pass_step2_validation = false;
1043 $error_step2_message .= "A database login password is required <br />\n";
1046 if (!$pass_step2_validation) {
1047 $error_step2_message .= $error_page_end . "\r\n";
1048 die($error_step2_message);
1052 if (empty($installer->clone_database)) {
1053 if (! $installer->login_is_valid()) {
1054 echo "$error. Please pick a proper 'Login Name'.<br />\n";
1055 echo "Click Back in browser to re-enter.<br />\n";
1056 break;
1059 if (! $installer->iuser_is_valid()) {
1060 echo "$error. The 'Initial User' field can only contain one word and no spaces.<br />\n";
1061 echo "Click Back in browser to re-enter.<br />\n";
1062 break;
1065 if (! $installer->user_password_is_valid()) {
1066 echo "$error. Please pick a proper 'Initial User Password'.<br />\n";
1067 echo "Click Back in browser to re-enter.<br />\n";
1068 break;
1072 if (! $installer->password_is_valid()) {
1073 echo "$error. Please pick a proper 'Password'.<br />\n";
1074 echo "Click Back in browser to re-enter.<br />\n";
1075 break;
1078 echo "<h3 class='mb-3 border-bottom'>Step " . text($state) . " - Creating Database and First User</h3>";
1079 echo "<div class='jumbotron p-5'>";
1081 // Skip below if database shell has already been created.
1082 if ($inst != 2) {
1083 echo "Connecting to MySQL Server...\n";
1084 flush();
1085 if (! $installer->root_database_connection()) {
1086 echo "$error. Check your login credentials.\n";
1087 echo text($installer->error_message);
1088 break;
1089 } else {
1090 echo "$ok.<br />\n";
1091 flush();
1095 // Only pertinent if cloning another installation database
1096 if ($allow_cloning_setup && !empty($installer->clone_database)) {
1097 echo "Dumping source database...";
1098 flush();
1099 if (! $installer->create_dumpfiles()) {
1100 echo text($installer->error_message);
1101 break;
1102 } else {
1103 echo "$ok.<br />\n";
1104 flush();
1108 // Only pertinent if mirroring another installation directory
1109 if (! empty($installer->source_site_id)) {
1110 echo "Creating site directory...";
1111 if (! $installer->create_site_directory()) {
1112 echo text($installer->error_message);
1113 break;
1114 } else {
1115 echo "$ok.<br />";
1116 flush();
1120 // Skip below if database shell has already been created.
1121 if ($inst != 2) {
1122 echo "Creating database...\n";
1123 flush();
1124 if (! $installer->create_database()) {
1125 echo "$error. Check your login credentials.\n";
1126 echo text($installer->error_message);
1127 break;
1128 } else {
1129 echo "$ok.<br />\n";
1130 flush();
1133 echo "Creating user with permissions for database...\n";
1134 flush();
1135 $user_mysql_error = true;
1136 if (! $installer->create_database_user()) {
1137 echo "$error when creating specified user.\n";
1138 echo text($installer->error_message);
1139 break;
1140 } else {
1141 $user_mysql_error = false;
1143 if (! $installer->grant_privileges()) {
1144 echo "$error when granting privileges to the specified user.\n";
1145 echo text($installer->error_message);
1146 break;
1147 } else {
1148 $user_mysql_error = false;
1150 if (!$user_mysql_error) {
1151 echo "$ok.<br />\n";
1152 flush();
1155 echo "Reconnecting as new user...\n";
1156 flush();
1157 $installer->disconnect();
1158 } else {
1159 echo "Connecting to MySQL Server...\n";
1162 if (! $installer->user_database_connection()) {
1163 echo "$error. Check your login credentials.\n";
1164 echo text($installer->error_message);
1165 break;
1166 } else {
1167 echo "$ok.<br />\n";
1168 flush();
1171 // Load the database files
1172 $dump_results = $installer->load_dumpfiles();
1173 if (! $dump_results) {
1174 echo "$error.\n";
1175 echo text($installer->error_message);
1176 break;
1177 } else {
1178 echo $dump_results;
1179 flush();
1182 echo "Writing SQL configuration...\n";
1183 flush();
1184 if (! $installer->write_configuration_file()) {
1185 echo "$error.\n";
1186 echo text($installer->error_message);
1187 break;
1188 } else {
1189 echo "$ok.<br />\n";
1190 flush();
1193 // Only pertinent if not cloning another installation database
1194 if (empty($installer->clone_database)) {
1195 echo "Setting version indicators...\n";
1196 flush();
1197 if (! $installer->add_version_info()) {
1198 echo "$error.\n";
1199 echo text($installer->error_message);
1201 break;
1202 } else {
1203 echo "$ok<br />\n";
1204 flush();
1207 echo "Writing global configuration defaults...\n";
1208 flush();
1209 if (! $installer->insert_globals()) {
1210 echo "$error.\n";
1211 echo text($installer->error_message);
1213 break;
1214 } else {
1215 echo "$ok<br />\n";
1216 flush();
1219 echo "Setting up Access Controls...\n";
1220 require("$OE_SITE_DIR/sqlconf.php");
1221 if (! $installer->install_gacl()) {
1222 echo "$error -.\n";
1223 echo text($installer->error_message);
1224 break;
1225 } else {
1226 echo "$ok<br />\n";
1227 flush();
1231 echo "Adding Initial User...\n";
1232 flush();
1233 if (! $installer->add_initial_user()) {
1234 echo "$error.\n";
1235 echo text($installer->error_message);
1236 break;
1238 echo "$ok<br />\n";
1239 flush();
1241 echo "Adding Additional Users...\n";
1242 flush();
1243 if (! $installer->install_additional_users()) {
1244 echo "$error.\n";
1245 echo text($installer->error_message);
1246 break;
1248 echo "$ok<br />\n";
1249 flush();
1251 echo "Configuring Care Coordination Module...\n";
1252 flush();
1253 if (! $installer->on_care_coordination()) {
1254 echo "$error.\n";
1255 echo text($installer->error_message);
1256 break;
1258 echo "$ok<br />\n";
1259 flush();
1262 // If user has selected to set MFA App Based 2FA, display QR code to scan
1263 $qr = $installer->get_initial_user_2fa_qr();
1264 $qr_esc = attr($qr);
1265 if ($qr) {
1266 $qrDisplay = <<<TOTP
1267 <br />
1268 <table>
1269 <tr>
1270 <td>
1271 <strong class='text-danger'>IMPORTANT!!</strong>
1272 <p><strong>You must scan the following QR code with your preferred authenticator app.</strong></p>
1273 <img src='$qr_esc' width="150" />
1274 </td>
1275 </tr>
1276 <tr>
1277 <td>
1278 Example authenticator apps include:
1279 <ul>
1280 <li>Google Auth
1281 (<a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8">iOS</a>, <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en">Android</a>)</li>
1282 <li>Authy
1283 (<a href="https://itunes.apple.com/us/app/authy/id494168017?mt=8">iOS</a>, <a href="https://play.google.com/store/apps/details?id=com.authy.authy&hl=en">Android</a>)</li>
1284 </ul>
1285 </td>
1286 </tr>
1287 </table>
1288 TOTP;
1289 echo $qrDisplay;
1292 if ($allow_cloning_setup && !empty($installer->clone_database)) {
1293 // Database was cloned, skip ACL setup.
1294 $btn_text = 'Proceed to Select a Theme';
1295 echo "<br />";
1296 echo "<p>The database was cloned, access control list exists therefore skipping ACL setup</p>";
1297 echo "<p class='p-1 bg-warning'>Click <b>" . text($btn_text) . "</b> for further instructions.</p>";
1298 $next_state = 7;
1299 } else {
1300 $btn_text = 'Proceed to Step 4';
1301 echo "<br />";
1302 echo "<p><b>Granted user <span class='text-primary'>" . text($installer->iuser) . "</span> administrator access control (password is <span class='text-primary'>" . text($installer->iuserpass) . "</span>).</b></p>";
1303 echo "<p>The next step will configure php.</p>";
1304 echo "<p class='mark'>Click <strong>" . text($btn_text) . "</strong> to continue.</p>";
1305 $next_state = 4;
1308 echo "<form method='post'>
1309 <input name='state' type='hidden' value='" . attr($next_state) . "' />
1310 <input name='site' type='hidden' value='" . attr($site_id) . "' />
1311 <input name='iuser' type='hidden' value='" . attr($installer->iuser) . "' />
1312 <input name='iuserpass' type='hidden' value='" . attr($installer->iuserpass) . "' />
1313 <input name='iuname' type='hidden' value='" . attr($installer->iuname) . "' />
1314 <input name='iufname' type='hidden' value='" . attr($installer->iufname) . "' />
1315 <input name='login' type='hidden' value='" . attr($installer->login) . "' />
1316 <input name='pass' type='hidden' value='" . attr($installer->pass) . "' />
1317 <input name='server' type='hidden' value='" . attr($installer->server) . "' />
1318 <input name='port' type='hidden' value='" . attr($installer->port) . "' />
1319 <input name='loginhost' type='hidden' value='" . attr($installer->loginhost) . "' />
1320 <input name='dbname' type='hidden' value='" . attr($installer->dbname) . "' />\r\n";
1322 if ($allow_cloning_setup) {
1323 echo "<input type='hidden' name='clone_database' value='" . attr($installer->clone_database) . "' />";
1324 echo "<input name='source_site_id' type='hidden' value='" . attr($installer->source_site_id) . "' />";
1326 $btn_text_esc = text($btn_text);
1327 $form_bottom = <<<FRMBOT
1328 <div class="form-row">
1329 <div class="col-12">
1330 <button type='submit' id='step-4-btn' class="btn btn-primary" value='Continue'>
1331 <i class="fas fa-chevron-right"></i> $btn_text_esc
1332 </button>
1333 </div>
1334 </div>
1335 </form>
1336 </div>
1337 FRMBOT;
1338 echo $form_bottom . "\r\n";
1339 break;
1341 case 4:
1342 $state_esc = text($state);
1343 $step4_top = <<<STP4TOP
1344 <h3 class="mb-3 border-bottom">Step $state_esc - Configure PHP</h3>
1345 <div class="jumbotron p-5">
1346 <p>Configuration of PHP...</p>
1347 <p>We recommend making the following changes to your PHP installation, which can normally be done by editing the php.ini configuration file:</p>
1348 <ul>
1349 STP4TOP;
1350 echo $step4_top . "\r\n";
1352 $gotFileFlag = 0;
1353 $phpINIfile = php_ini_loaded_file();
1354 if ($phpINIfile) {
1355 echo "<li><span class='text-success'>Your php.ini file can be found at " . text($phpINIfile) . "</span></li>\n";
1356 $gotFileFlag = 1;
1359 $short_tag = ini_get('short_open_tag') ? 'On' : 'Off';
1360 $short_tag_style = (strcmp($short_tag, 'Off') === 0) ? '' : 'text-danger';
1361 $display_errors = ini_get('display_errors') ? 'On' : 'Off';
1362 $display_errors_style = (strcmp($display_errors, "Off") === 0) ? '' : 'text-danger';
1363 $register_globals = ini_get('register_globals') ? 'On' : 'Off';
1364 $register_globals_style = (strcmp($register_globals, 'Off') === 0) ? '' : 'text-danger';
1365 $max_input_vars = ini_get('max_input_vars');
1366 $max_input_vars_style = $max_input_vars < 3000 ? 'text-danger' : '';
1367 $max_execution_time = (int)ini_get('max_execution_time');
1368 $max_execution_time_style = $max_execution_time >= 60 || $max_execution_time === 0 ? '' : 'text-danger';
1369 $max_input_time = ini_get('max_input_time');
1370 $max_input_time_style = (strcmp($max_input_time, '-1') === 0) ? '' : 'text-danger';
1371 $post_max_size = ini_get('post_max_size');
1372 $post_max_size_style = $post_max_size < 30 ? 'text-danger' : '';
1373 $memory_limit = ini_get('memory_limit');
1374 $memory_limit_style = $memory_limit < 256 ? 'text-danger' : '';
1375 $mysqli_allow_local_infile = ini_get('mysqli.allow_local_infile') ? 'On' : 'Off';
1376 $mysqli_allow_local_infile_style = (strcmp($mysqli_allow_local_infile, 'On') === 0) ? '' : 'text-danger';
1378 echo "<li>To ensure proper functioning of OpenEMR you must make sure that PHP settings include:
1379 <table class='phpset'>
1380 <tr>
1381 <th>Setting</th>
1382 <th>Required value</th>
1383 <th>Current value</th>
1384 </tr>
1385 <tr>
1386 <td>short_open_tag</td>
1387 <td>Off</td>
1388 <td class='" . attr($short_tag_style) . "'>" . text($short_tag) . "</td>
1389 </tr>
1390 <tr>
1391 <td>display_errors</td>
1392 <td>Off</td>
1393 <td class='" . attr($display_errors_style) . "'>" . text($display_errors) . "</td>
1394 </tr>
1395 <tr>
1396 <td>register_globals</td>
1397 <td>Off</td>
1398 <td class='" . attr($register_globals_style) . "'>" . text($register_globals) . "</td>
1399 </tr>
1400 <tr>
1401 <td>max_input_vars</td>
1402 <td>at least 3000</td>
1403 <td class='" . attr($max_input_vars_style) . "'>" . text($max_input_vars) . "</td>
1404 </tr>
1405 <tr>
1406 <td>max_execution_time</td>
1407 <td>at least 60</td>
1408 <td class='" . attr($max_execution_time_style) . "'>" . text($max_execution_time) . "</td>
1409 </tr>
1410 <tr>
1411 <td>max_input_time</td>
1412 <td>-1</td>
1413 <td class='" . attr($max_input_time_style) . "'>" . text($max_input_time) . "</td>
1414 </tr>
1415 <tr>
1416 <td>post_max_size</td>
1417 <td>at least 30M</td>
1418 <td class='" . attr($post_max_size_style) . "'>" . text($post_max_size) . "</td>
1419 </tr>
1420 <tr>
1421 <td>memory_limit</td>
1422 <td>at least 256M</td>
1423 <td class='" . attr($memory_limit_style) . "'>" . text($memory_limit) . "</td>
1424 </tr>
1425 <tr>
1426 <td>mysqli.allow_local_infile</td>
1427 <td>On</td>
1428 <td class='" . attr($mysqli_allow_local_infile_style) . "'>" . text($mysqli_allow_local_infile) . "</td>
1429 </tr>
1430 </table>
1431 </li>
1432 <li>In order to take full advantage of the patient documents capability you must make sure that settings in php.ini file include \"file_uploads = On\", that \"upload_max_filesize\" is appropriate for your use and that \"upload_tmp_dir\" is set to a correct value that will work on your system.
1433 </li>\r\n";
1435 if (!$gotFileFlag) {
1436 echo "<li>If you are having difficulty finding your php.ini file, then refer to the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><u>'INSTALL'</u></a> manual for suggestions.</li>\n";
1439 $btn_text = 'Proceed to Step 5';
1440 echo "</ul>
1442 <p>We recommend you print these instructions for future reference.</p>
1443 <p>The next step will configure the Apache web server.</p>
1444 <p class='mark'>Click <strong>" . text($btn_text) . "</strong> to continue.</p>
1445 <br />
1446 <form method='post'>
1447 <input type='hidden' name='state' value='5' />
1448 <input type='hidden' name='site' value='" . attr($site_id) . "' />
1449 <input type='hidden' name='iuser' value='" . attr($installer->iuser) . "' />
1450 <input type='hidden' name='iuserpass' value='" . attr($installer->iuserpass) . "' />
1451 <input name='login' type='hidden' value='" . attr($installer->login) . "' />
1452 <input name='pass' type='hidden' value='" . attr($installer->pass) . "' />
1453 <input name='server' type='hidden' value='" . attr($installer->server) . "' />
1454 <input name='port' type='hidden' value='" . attr($installer->port) . "' />
1455 <input name='loginhost' type='hidden' value='" . attr($installer->loginhost) . "' />
1456 <input name='dbname' type='hidden' value='" . attr($installer->dbname) . "' />
1457 <div class='form-row'>
1458 <div class='col-12'>
1459 <button type='submit' class='btn btn-primary' value='Continue'>
1460 <i class='fas fa-chevron-right'></i> " . text($btn_text) . "
1461 </button>
1462 </div>
1463 </div>
1464 </form>
1465 </div>\r\n";
1466 break;
1468 case 5:
1469 echo "<h3 class='mb-3 border-bottom'>Step " . text($state) . " - Configure Apache Web Server</h3>";
1470 echo "<div class='jumbotron p-5'>";
1471 echo "<p>Configuration of Apache web server...</p><br />\n";
1472 echo "The <code>\"" . text(preg_replace("/${site_id}/", "*", realpath($docsDirectory))) . "\"</code> directory contain patient information, and
1473 it is important to secure these directories. Additionally, some settings are required for the Zend Framework to work in OpenEMR. This can be done by pasting the below to end of your apache configuration file:<br /><br />
1474 &nbsp;&nbsp;<code>&lt;Directory \"" . text(realpath(dirname(__FILE__))) . "\"&gt;<br />
1475 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AllowOverride FileInfo<br />
1476 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Require all granted<br />
1477 &nbsp;&nbsp;<code>&lt;/Directory&gt;</code><br />
1478 &nbsp;&nbsp;&lt;Directory \"" . text(realpath(dirname(__FILE__))) . "/sites\"&gt;<br />
1479 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AllowOverride None<br />
1480 &nbsp;&nbsp;&lt;/Directory&gt;</code><br />
1481 &nbsp;&nbsp;<code>&lt;Directory \"" . text(preg_replace("/${site_id}/", "*", realpath($docsDirectory))) . "\"&gt;<br />
1482 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Require all denied<br />
1483 &nbsp;&nbsp;&lt;/Directory&gt;</code><br /><br />";
1485 $btn_text = 'Proceed to Select a Theme';
1486 echo "<p>If you are having difficulty finding your apache configuration file, then refer to the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><u>'INSTALL'</u></a> manual for suggestions.</p>
1487 <p>We recommend you print these instructions for future reference.</p>
1488 <p class='mark'>Click <strong>'" . text($btn_text) . "'</strong> to select a theme.</p>
1489 <br />
1490 <form method='post'>
1491 <input type='hidden' name='state' value='6' />
1492 <input type='hidden' name='site' value='" . attr($site_id) . "' />
1493 <input type='hidden' name='iuser' value='" . attr($installer->iuser) . "' />
1494 <input type='hidden' name='iuserpass' value='" . attr($installer->iuserpass) . "' />
1495 <input name='login' type='hidden' value='" . attr($installer->login) . "' />
1496 <input name='pass' type='hidden' value='" . attr($installer->pass) . "' />
1497 <input name='server' type='hidden' value='" . attr($installer->server) . "' />
1498 <input name='port' type='hidden' value='" . attr($installer->port) . "' />
1499 <input name='loginhost' type='hidden' value='" . attr($installer->loginhost) . "' />
1500 <input name='dbname' type='hidden' value='" . attr($installer->dbname) . "' />
1501 <div class='form-row'>
1502 <div class='col-12'>
1503 <button type='submit' class='btn btn-primary' value='Continue'>
1504 <i class='fas fa-chevron-right'></i> " . text($btn_text) . "
1505 </button>
1506 </div>
1507 </div>
1508 </form>
1509 <div>\r\n";
1510 break;
1512 case 6:
1513 echo "<h3 class='mb-3 border-bottom'>Step " . text($state) . " - Select a Theme</h3>";
1514 echo "<div class='jumbotron p-5'>";
1515 echo "<p>Select a theme for OpenEMR...</p>\n";
1516 $btn_text = "Proceed to Final Step";
1517 $installer->displaySelectedThemeDiv();
1518 echo "<div class='row'>
1519 <div class='col-12'>
1520 <form method='post'>
1521 <input type='hidden' name='state' value='7' />
1522 <input type='hidden' name='site' value='" . attr($site_id) . "' />
1523 <input type='hidden' name='iuser' value='" . attr($installer->iuser) . "' />
1524 <input type='hidden' name='iuserpass' value='" . attr($installer->iuserpass) . "' />
1525 <input name='login' type='hidden' value='" . attr($installer->login) . "' />
1526 <input name='pass' type='hidden' value='" . attr($installer->pass) . "' />
1527 <input name='server' type='hidden' value='" . attr($installer->server) . "' />
1528 <input name='port' type='hidden' value='" . attr($installer->port) . "' />
1529 <input name='loginhost' type='hidden' value='" . attr($installer->loginhost) . "' />
1530 <input name='dbname' type='hidden' value='" . attr($installer->dbname) . "' />
1531 <input type='hidden' name='new_theme' id = 'new_theme' value='" . attr($installer->getCurrentTheme()) . "' />
1532 <input name='clone_database' type='hidden' value='" . attr($installer->clone_database) . "' />
1533 <input name='source_site_id' type='hidden' value='" . attr($installer->source_site_id) . "' />
1534 <h4>Select One:</h4>
1535 <div class='checkbox'>
1536 <label><input type='checkbox' class='check' value='show_theme' />Show More Themes</label>
1537 </div>
1538 <div class='checkbox'>
1539 <label><input type='checkbox' class='check' value='keep_current' />Keep Current</label>
1540 </div>
1541 <div class='hide_button' style='display:none;'>
1542 <button type='submit' class='btn btn-primary' value='Continue' id='continue'>
1543 <i class='fas fa-chevron-right'></i> " . text($btn_text) . "
1544 </button>
1545 </div>
1546 </form>
1547 </div>
1548 </div>\r\n";
1549 echo '<div class="row hideaway" style="display:none;">' . "\r\n";
1550 echo '<div class="col-12">' . "\r\n";
1551 echo ' <h4>Select New Theme: <h5>(scroll down to view all)</h5></h4>' . "\r\n";
1552 echo ' <br />' . "\r\n";
1553 $installer->displayThemesDivs();
1554 echo "</div>";
1555 break;
1557 case 0:
1558 default:
1559 $top = <<<TOP
1560 <h3 class="mb-3 border-bottom">Pre Install - Checking File and Directory Permissions</h3>
1561 <div class="jumbotron p-5">
1563 Welcome to OpenEMR. This utility will step you through the installation and configuration of OpenEMR for your practice.
1564 </p>
1565 <ul>
1566 <li>
1567 Before proceeding, be sure that you have a properly installed and configured MySQL server available, and a PHP configured webserver.
1568 </li>
1569 <li>
1570 <span class="text-highlight">Detailed installation instructions can be found in the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><u>'INSTALL'</u></a> manual file.</span>
1571 </li>
1572 <li>
1573 If you are upgrading from a previous version, <strong>DO NOT</strong> use this script. Please read the <strong>'Upgrading'</strong> section found in the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><u>'INSTALL'</u></a> manual file.
1574 </li>
1575 </ul>
1576 TOP;
1577 echo $top;
1578 if ($checkPermissions) {
1579 echo "<p>We will now ensure correct file and directory permissions before starting installation:</p>\n";
1580 echo "<p class='text-success m-0'>Ensuring following file is world-writable...</p>\n";
1581 $errorWritable = 0;
1582 foreach ($writableFileList as $tempFile) {
1583 if (is_writable($tempFile)) {
1584 echo "<code class='ml-5'>" . text(realpath($tempFile)) . "</code> file is <span class='text-success font-weight-bold'>ready</span><br /><br />\n";
1585 } else {
1586 echo "<p><span class='text-danger'>UNABLE</span> to open file '" . text(realpath($tempFile)) . "' for writing.<br />\n";
1587 echo "(configure file permissions; see below for further instructions)</p>\n";
1588 $errorWritable = 1;
1592 if ($errorWritable) {
1593 $site_id_esc = attr($site_id);
1594 $check_file = <<<CHKFILE
1595 <p class="text-danger">You can't proceed until all above files are ready (world-writable).</p>
1596 <p>In linux, recommend changing file permissions with the <strong>'chmod 666 filename'</strong> command.</p>
1597 <p class='p-1 bg-danger text-white'>Fix above file permissions and then click the <strong>'Check Again'</strong> button to re-check files.</p>
1598 <br />
1599 <form method='post'>
1600 <input type='hidden' name='site' value='$site_id_esc' />
1601 <button type='submit' class='btn btn-primary' value='check again'>Check Again</button>
1602 </form>
1603 CHKFILE;
1604 echo $check_file . "\r\n";
1605 break;
1608 $errorWritable = 0;
1609 foreach ($writableDirList as $tempDir) {
1610 echo "<p class='text-success m-0'>Ensuring the <code>" . text(realpath($tempDir)) . "</code> directory and its subdirectories have proper permissions...</p>\n";
1611 $errorWritable = recursive_writable_directory_test($tempDir);
1614 if ($errorWritable) {
1615 $site_id_esc = attr($site_id);
1616 $check_directory = <<<CHKDIR
1617 <p class="text-danger">You can't proceed until all directories and subdirectories are ready.</p>
1618 <p>In linux, recommend changing owners of these directories to the web server. For example, in many linux OS's the web server user is 'apache', 'nobody', or 'www-data'. So if 'apache' were the web server user name, could use the command <strong>'chown -R apache:apache directory_name'</strong> command.</p>
1619 <p class='p-1 bg-warning'>Fix above directory permissions and then click the <strong>'Check Again'</strong> button to re-check directories.</p>
1620 <br />
1621 <form method='post'>
1622 <input type='hidden' name='site' value='$site_id_esc' />
1623 <button type='submit' value='check again'><b>Check Again</b></button>
1624 </form>
1625 CHKDIR;
1626 echo $check_directory . "\r\n";
1627 break;
1630 //RP_CHECK_LOGIC
1631 $site_id_esc = attr($site_id);
1632 $form = <<<FRM
1633 <p>All required files and directories have been verified.</p>
1634 <p class='mark'>Click <span class="font-weight-bold">Proceed to Step 1</span> to continue with a new installation.</p>
1635 <p class='p-1 bg-warning'>$caution: If you are upgrading from a previous version, <strong>DO NOT</strong> use this script. Please read the <strong>'Upgrading'</strong> section found in the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><u>'INSTALL'</u></a> manual file.</p>
1636 <br />
1637 <form method='post'>
1638 <input name='state' type='hidden' value='1' />
1639 <input name='site' type='hidden' value='$site_id_esc' />
1640 <div class="form-group">
1641 <div class="col">
1642 <button type='submit' class='btn btn-primary' value='Continue'>
1643 <i class="fas fa-chevron-right"></i> Proceed to Step 1
1644 </button>
1645 </div>
1646 </div>
1647 </form>
1648 FRM;
1649 echo $form . "\r\n";
1650 } else {
1651 $site_id_esc = attr($site_id);
1652 $form = <<<FRM
1653 <br />
1654 <p class='p-1 bg-warning'>$caution: Permisssions checking has been disabled. All required files and directories have NOT been verified, please manually verify sites/$site_id_esc .</p>
1655 <p class='mark'>Click <b>Proceed to Step 1</b> to continue with a new installation.</p>
1656 <p class='p-1 bg-warning'>$caution: If you are upgrading from a previous version, <strong>DO NOT</strong> use this script. Please read the <strong>'Upgrading'</strong> section found in the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><span style='text-decoration: underline;'>'INSTALL'</span></a> manual file.</p>
1657 <br />
1658 <form method='post'>
1659 <input name='state' type='hidden' value='1'>
1660 <input name='site' type='hidden' value='$site_id_esc'>
1661 <button type='submit' value='Continue'><b>Proceed to Step 1</b></button>
1662 </form>
1663 FRM;
1664 echo $form . "\r\n"; }
1667 $bot = <<<BOT
1668 </div>
1669 </div>
1670 </div>
1671 BOT;
1672 echo $bot . "\r\n";
1676 </div><!--end of container div -->
1677 <?php $installer->setupHelpModal();?>
1678 <script>
1679 //jquery-ui tooltip
1680 $(function () {
1681 $('.icon-tooltip').prop( "title", "Click to see more information").tooltip({
1682 show: {
1683 delay: 700,
1684 duration: 0
1687 $('.enter-details-tooltip').prop( "title", "Additional help to fill out this form is available by hovering over labels of each box and clicking on the dark blue help ? icon that is revealed. On mobile devices tap once on the label to reveal the help icon and tap on the icon to show the help section").tooltip();
1688 $('.2fa-section-tooltip').prop( "title", "Two factor authentication prevents unauthorized access to openEMR thus improves security. It is optional. More information is available in the help file under Step 2 Database and OpenEMR Initial User Setup Details.").tooltip();
1692 </script>
1693 <script>
1694 $(function () {
1695 $("input[type='radio']").click(function() {
1696 var radioValue = $("input[name='stylesheet']:checked").val();
1697 var imgPath = "public/images/stylesheets/";
1698 var currStyle = $("#current_theme_title").text();
1699 var currStyleTitle = currStyle;
1700 currStyle = currStyle.replace(/\b\w/g, l => l.toLowerCase());
1701 currStyle = currStyle.split(" ");
1702 currStyle = currStyle.join("_");
1703 currStyle = "style_" + currStyle + ".png";
1704 if (radioValue) {
1705 var currThemeText = radioValue.split("_");
1706 currThemeText = currThemeText.join(" ");
1707 currThemeText = currThemeText.replace(/\b\w/g, l => l.toUpperCase());
1708 var styleSelected = confirm("You have selected style - " + currThemeText + "\n" + "Click OK to apply selection");
1709 if (styleSelected) {
1710 $("#current_theme").attr("src", imgPath + "style_" + radioValue + ".png");
1711 $("#current_theme_title").text(currThemeText);
1712 $("#new_theme").val("style_" + radioValue + ".css");
1713 } else {
1714 $("#current_theme").attr("src", imgPath + currStyle);
1715 $("#current_theme_title").text(currStyleTitle);
1716 $(this).prop("checked", false);
1720 $('.check').click(function() {
1721 $('.check').not(this).prop('checked', false);
1722 if($('.check:checked').val() == 'show_theme'){
1723 $(".hideaway").show();
1724 } else if($('.check:checked').val() == 'keep_current'){
1725 $(".hideaway").hide();
1728 if($('.check').filter(':checked').length > 0) {
1729 $(".hide_button").show();
1730 } else {
1731 $(".hide_button").hide();
1732 $(".hideaway").hide();
1735 $('.wait').removeClass('button-wait');
1737 $( "#create_db_button" ).hover(
1738 function() {
1739 if (($('#iuserpass' ).val().length > 11 && $('#iuser' ).val().length > 11 ) || ($('#clone_database').prop('checked'))){
1741 $("button").click(function(){
1742 $(".oe-spinner").css("visibility", "visible");
1745 $('.wait').click(function(){
1746 $('.wait').addClass('button-wait');
1752 $("#step-4-btn").click(function(){
1753 $(".oe-spinner").css("visibility", "visible");
1754 $(this).addClass('button-wait');
1757 </script>
1758 </body>
1759 </html>