add return to core/header (#2995)
[openemr.git] / setup.php
blob4a7f5595e38a21e12b1100f812725bd516f3a108
1 <?php
2 /**
4 * Installation script.
6 * @package OpenEMR
7 * @link https://www.open-emr.org
8 * @author Roberto Vasquez <robertogagliotta@gmail.com>
9 * @author Scott Wakefield <scott@npclinics.com.au>
10 * @author Ranganath Pathak <pathak@scrs1.org>
11 * @author Brady Miller <brady.g.miller@gmail.com>
12 * @copyright Copyright (c) 2016 Roberto Vasquez <robertogagliotta@gmail.com>
13 * @copyright Copyright (c) 2016 Scott Wakefield <scott@npclinics.com.au>
14 * @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
15 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
16 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
19 // Checks if the server's PHP version is compatible with OpenEMR:
20 require_once(dirname(__FILE__) . "/src/Common/Compatibility/Checker.php");
21 $response = OpenEMR\Common\Compatibility\Checker::checkPhpVersion();
22 if ($response !== true) {
23 die(htmlspecialchars($response));
26 // Set the maximum excution time and time limit to unlimited.
27 ini_set('max_execution_time', 0);
28 ini_set('display_errors', 0);
29 set_time_limit(0);
31 // Warning. If you set $allow_multisite_setup to true, this is a potential security vulnerability.
32 // Recommend setting it back to false (or removing this setup.php script entirely) after you
33 // are done with the multisite procedure.
34 $allow_multisite_setup = false;
36 // Warning. If you set $allow_cloning_setup to true, this is a potential security vulnerability.
37 // Recommend setting it back to false (or removing this setup.php script entirely) after you
38 // are done with the cloning setup procedure.
39 $allow_cloning_setup = false;
40 if (!$allow_cloning_setup && !empty($_REQUEST['clone_database'])) {
41 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");
44 function recursive_writable_directory_test($dir)
46 // first, collect the directory and subdirectories
47 $ri = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
48 $dirNames = array();
49 foreach ($ri as $file) {
50 if ($file->isDir()) {
51 if (!preg_match("/\.\.$/", $file->getPathname())) {
52 $dirName = realpath($file->getPathname());
53 if (!in_array($dirName, $dirNames)) {
54 $dirNames[] = $dirName;
60 // second, flag the directories that are not writable
61 $resultsNegative = array();
62 foreach ($dirNames as $value) {
63 if (!is_writable($value)) {
64 $resultsNegative[] = $value;
68 // third, send the output and return if didn't pass the test
69 if (!empty($resultsNegative)) {
70 echo "<p>";
71 $mainDirTest = "";
72 $outputs = array();
73 foreach ($resultsNegative as $failedDir) {
74 if (basename($failedDir) == basename($dir)) {
75 // need to reorder output so the main directory is at the top of the list
76 $mainDirTest = "<FONT COLOR='red'>UNABLE</FONT> to open directory '" . realpath($failedDir) . "' for writing by web server.<br />\r\n";
77 } else {
78 $outputs[] = "<FONT COLOR='red'>UNABLE</FONT> to open subdirectory '" . realpath($failedDir) . "' for writing by web server.<br />\r\n";
81 if ($mainDirTest) {
82 // need to reorder output so the main directory is at the top of the list
83 array_unshift($outputs, $mainDirTest);
85 foreach ($outputs as $output) {
86 echo $output;
88 echo "(configure directory permissions; see below for further instructions)</p>\r\n";
89 return 1;
90 } else {
91 echo "'" . realpath($dir) . "' directory and its subdirectories are <FONT COLOR='green'><b>ready</b></FONT>.<br />\r\n";
92 return 0;
96 // Include standard libraries/classes
97 require_once dirname(__FILE__) ."/vendor/autoload.php";
99 use OpenEMR\Common\Utils\RandomGenUtils;
101 $COMMAND_LINE = php_sapi_name() == 'cli';
103 $state = isset($_POST["state"]) ? ($_POST["state"]) : '';
104 $installer = new Installer($_REQUEST);
105 // Make this true for IPPF.
106 $ippf_specific = false;
108 $error_page_end = <<<EPE
109 </div>
110 </div>
111 </div><!--end of container div-->
112 </body>
113 </html>
114 EPE;
116 // If this script was invoked with no site ID, then ask for one.
117 if (!$COMMAND_LINE && empty($_REQUEST['site'])) {
118 $site_id = <<<SITEID
119 <!DOCTYPE html>
120 <html>
121 <head>
122 <title>OpenEMR Setup Tool</title>
123 <!--<link rel=stylesheet href="interface/themes/style_blue.css">-->
124 <link rel="stylesheet" href="public/assets/bootstrap/dist/css/bootstrap.min.css" type="text/css">
125 <link rel="stylesheet" href="public/assets/jquery-ui/jquery-ui.css" type="text/css">
126 <script type="text/javascript" src="public/assets/jquery/dist/jquery.min.js"></script>
127 <script type="text/javascript" src="public/assets/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
128 <link rel="stylesheet" href="public/assets/font-awesome/css/font-awesome.min.css" type="text/css">
129 <link rel="shortcut icon" href="public/images/favicon.ico" />
130 <script type="text/javascript" src="public/assets/jquery-ui/jquery-ui.js"></script>
131 <style>
132 .oe-pull-away {
133 float:right;
135 </style>
136 </head>
137 <body>
138 <div class = 'mt-4 container'>
139 <div class="row">
140 <div class="row">
141 <div class="col-sm-12">
142 <div class="mb-3 border-bottom">
143 <h2>OpenEMR Setup <a class="oe-pull-away oe-help-redirect" data-target="#myModal" data-toggle="modal" href="#" id="help-href" name="help-href" style="color:#676666" title="Click to view Help"><i class="fa fa-question-circle" aria-hidden="true"></i></a></h2>
144 </div>
145 </div>
146 </div>
147 </div>
148 <div class="row">
149 <div class="col-sm-12">
150 <fieldset>
151 <legend class="mb-3 border-bottom">Optional Site ID Selection</legend>
152 <p>Most OpenEMR installations support only one site. If that is
153 true for you then ignore the rest of this text and just click Continue.</p>
154 <p class='p-1 bg-warning'>If you are using the multisite setup module for the first time please read the
155 'Multi Site Installation' section of the help file before proceeding.</p>
156 <p>Otherwise please enter a unique Site ID here.</p>
157 <p>A Site ID is a short identifier with no spaces or special
158 characters other than periods or dashes. It is case-sensitive and we
159 suggest sticking to lower case letters for ease of use.</p>
160 <p>If each site will have its own host/domain name, then use that
161 name as the Site ID (e.g. www.example.com).</p>
162 <p>The site ID is used to identify which site you will log in to.
163 If it is a hostname then it is taken from the hostname in the URL.
164 Otherwise you must append "?site=<i>siteid</i>" to the URL used for
165 logging in.</p>
166 <p>It is OK for one of the sites to have "default" as its ID. This
167 is the ID that will be used if it cannot otherwise be determined.</p>
168 <br />
169 <form method='post'>
170 <input type='hidden' name='state' value='0'>
171 Site ID: <input type='text' name='site' value='default'>
172 <button type='submit' value='Continue'>Continue</button>
173 </form>
174 </fieldset>
175 </div>
176 </div>
177 </div><!--end of container div-->
178 SITEID;
179 echo $site_id . "\r\n";
180 $installer->setupHelpModal();
181 echo "</body>". "\r\n";
182 echo "</html>". "\r\n";
184 exit();
187 // Support "?site=siteid" in the URL, otherwise assume "default".
188 $site_id = 'default';
189 if (!$COMMAND_LINE && !empty($_REQUEST['site'])) {
190 $site_id = trim($_REQUEST['site']);
193 // Die if site ID is empty or has invalid characters.
194 if (empty($site_id) || preg_match('/[^A-Za-z0-9\\-.]/', $site_id)) {
195 die("Site ID '".htmlspecialchars($site_id, ENT_NOQUOTES)."' contains invalid characters.");
198 // If multisite is turned off, then only allow default for site.
199 if (!$allow_multisite_setup && $site_id != 'default') {
200 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");
203 //If having problems with file and directory permission
204 // checking, then can be manually disabled here.
205 $checkPermissions = true;
207 global $OE_SITE_DIR; // The Installer sets this
209 $docsDirectory = "$OE_SITE_DIR/documents";
211 //These are files and dir checked before install for
212 // correct permissions.
213 if (is_dir($OE_SITE_DIR)) {
214 $writableFileList = array($installer->conffile);
215 $writableDirList = array($docsDirectory);
216 } else {
217 $writableFileList = array();
218 $writableDirList = array($OE_SITES_BASE);
221 // Include the sqlconf file if it exists yet.
222 $config = 0;
223 if (file_exists($OE_SITE_DIR)) {
224 include_once($installer->conffile);
225 } elseif ($state > 3) {
226 // State 3 should have created the site directory if it is missing.
227 die("Internal error, site directory is missing.");
230 <html>
231 <head>
232 <title>OpenEMR Setup Tool</title>
233 <!--<link rel=stylesheet href="interface/themes/style_blue.css">-->
234 <link rel="stylesheet" href="public/assets/bootstrap/dist/css/bootstrap.min.css" type="text/css">
235 <link rel="stylesheet" href="public/assets/jquery-ui/jquery-ui.css" type="text/css">
236 <script type="text/javascript" src="public/assets/jquery/dist/jquery.min.js"></script>
237 <script type="text/javascript" src="public/assets/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
238 <script type="text/javascript" src="public/assets/jquery-ui/jquery-ui.js"></script>
239 <link rel="stylesheet" href="public/assets/font-awesome/css/font-awesome.min.css" type="text/css">
240 <link rel="shortcut icon" href="public/images/favicon.ico" />
242 <style>
243 .noclone { }
244 table.phpset {
245 border-collapse:collapse;
247 table.phpset td, table.phpset th {
248 font-size:9pt;
249 border:1px solid gray;
250 padding:2px;
252 .table.no-border tr td, .table.no-border tr th {
253 border-width: 0;
255 td {
256 font-size:10pt;
258 .inputtext {
259 padding-left:2px;
260 padding-right:2px;
263 .button {
264 font-family:sans-serif;
265 font-size:9pt;
266 font-weight:bold;
269 .label-div > a {
270 display:none;
272 .label-div:hover > a {
273 display:inline-block;
275 div[id$="_info"] {
276 background: #F7FAB3;
277 padding: 20px;
278 margin: 10px 15px 0px 15px;
280 div[id$="_info"] > a {
281 margin-left:10px;
283 .checkboxgroup {
284 display: inline-block;
285 text-align: center;
287 .checkboxgroup label {
288 display: block;
290 .oe-pull-away{
291 float:right;
293 .oe-help-x {
294 color: grey;
295 padding: 0 5px;
297 .oe-superscript {
298 position: relative;
299 top: -.5em;
300 font-size: 70%!important;
302 .oe-setup-legend{
303 background-color: WHITESMOKE;
304 padding:0 10px;
306 button {
307 font-weight:bold;
309 .button-wait {
310 color: grey;
311 cursor: not-allowed;
312 opacity: 0.6;
314 @media only screen {
315 fieldset > [class*="col-"] {
316 width: 100%;
317 text-align:left!Important;
320 </style>
321 <script language="javascript">
322 // onclick handler for "clone database" checkbox
323 function cloneClicked() {
324 var cb = document.forms[0].clone_database;
325 $('.noclone').css('display', cb.checked ? 'none' : 'block');
327 </script>
329 </head>
330 <body>
331 <div class = 'mt-4 container'>
332 <div class="row">
333 <div class="col-sm-12">
334 <div class="mb-3 border-bottom">
335 <h2>OpenEMR Setup <a class="oe-pull-away oe-help-redirect" data-target="#myModal" data-toggle="modal" href="#" id="help-href" name="help-href" style="color:#676666" title="Click to view Help"><i class="fa fa-question-circle" aria-hidden="true"></i></a></h2>
336 </div>
337 </div>
338 </div>
339 <div class="row">
340 <div class="col-sm-12">
341 <?php
342 $error = "<span class='text-danger'><b>ERROR</b></span>";
343 $caution = "<span class='text-danger'><b>CAUTION</b></span>";
344 $ok = "<span class='text-success'><b>OK</b></span>";
345 $note = "<span class='text-primary'><b>NOTE</b></span>";
347 if (strtolower(ini_get('register_globals')) != 'off' && (bool) ini_get('register_globals')) {
348 echo "$caution: It appears that you have register_globals enabled in your php.ini\n" .
349 "configuration file. This causes unacceptable security risks. You must\n" .
350 "turn it off before continuing with installation.\n";
351 exit(1);
354 if (!extension_loaded("xml")) {
355 echo "$error: PHP XML extension missing. To continue, install PHP XML extension, then restart web server.";
356 exit(1);
359 if (!(extension_loaded("mysql") || extension_loaded("mysqlnd") || extension_loaded("mysqli"))) {
360 echo "$error: PHP MySQL extension missing. To continue, install and enable MySQL extension, then restart web server.";
361 exit(1);
364 if (!(extension_loaded("mbstring") )) {
365 echo "$error: PHP mb_string extension missing. To continue, install and enable mb_string extension, then restart web server.";
366 exit(1);
369 if (!(extension_loaded("openssl") )) {
370 echo "$error: PHP openssl extension missing. To continue, install PHP openssl extension, then restart web server.";
371 exit(1);
375 <?php
376 if ($state == 8) {
379 <fieldset>
380 <legend class="mb-3 border-bottom">Final step - Success</legend>
381 <p>Congratulations! OpenEMR is now installed.</p>
383 <ul>
384 <li>Access controls (php-GACL) are installed for fine-grained security, and can be administered in
385 OpenEMR's admin->acl menu.</li>
386 <li>Reviewing <?php echo $OE_SITE_DIR; ?>/config.php is a good idea. This file
387 contains some settings that you may want to change.</li>
388 <li>There's much information and many extra tools bundled within the OpenEMR installation directory.
389 Please refer to openemr/Documentation. Many forms and other useful scripts can be found at openemr/contrib.</li>
390 <li>To ensure a consistent look and feel throughout the application,
391 <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>
392 <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>
393 <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>
394 </ul>
395 <p>We recommend you print these instructions for future reference.</p>
396 <?php
397 echo "<p> The selected theme is :</p>";
398 $installer->displayNewThemeDiv();
399 if (empty($installer->clone_database)) {
400 echo "<p><b>The initial OpenEMR user is <span class='text-primary'>'".$installer->iuser."'</span> and the password is <span class='text-primary'>'".$installer->iuserpass."'</span></b></p>";
401 } else {
402 echo "<p>The initial OpenEMR user name and password is the same as that of source site <b>'". $installer->source_site_id ."'</span></b></p>";
404 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>";
405 echo "<p>In Linux use the following command:</p>";
406 echo "<p><code>sudo apachectl -k restart</code></p>";
410 <a href='./?site=<?php echo $site_id; ?>'>Click here to start using OpenEMR. </a>
411 </p>
412 </fieldset>
413 <?php
414 $installer->setCurrentTheme();
416 $end_div = <<<ENDDIV
417 </div>
418 </div>
419 </div><!--end of container div-->
420 ENDDIV;
421 echo $end_div . "\r\n";
422 $installer->setupHelpModal();
423 echo "</body>". "\r\n";
424 echo "</html>". "\r\n";
426 exit();
430 <?php
432 $inst = isset($_POST["inst"]) ? ($_POST["inst"]) : '';
434 if (($config == 1) && ($state < 4)) {
435 echo "OpenEMR has already been installed. If you wish to force re-installation, then edit $installer->conffile (change the 'config' variable to 0), and re-run this script.<br />\n";
436 } else {
437 switch ($state) {
438 case 1:
439 $step1 = <<<STP1
440 <fieldset>
441 <legend class="mb-3 border-bottom">Step $state - Select Database Setup</legend>
442 <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.
443 <br />
444 <p class='p-1 bg-warning'>$caution: clicking on <b>Proceed to Step 2</b> may delete or cause damage to existing data on your system. Before you continue <b>please backup your data</b>.
445 <br />
446 <form method='post'>
447 <input name='state' type='hidden' value='2'>
448 <input name='site' type='hidden' value='$site_id'>
449 <label for='inst1'>
450 <input checked id='inst1' name='inst' type='radio' value='1'>Have setup create the database
451 </label><br />
452 <label for='inst2'>
453 <input id='inst2' name='inst' type='radio' value='2'>I have already created the database
454 </label><br />
455 <br />
456 <button type='submit' value='Continue'><b>Proceed to Step 2</b></button>
457 </form><br />
458 </fieldset>
459 STP1;
460 echo $step1 ."\r\n";
461 break;
463 case 2:
464 $step2top = <<<STP2TOP
465 <fieldset>
466 <legend class="mb-3 border-bottom">Step $state - Database and OpenEMR Initial User Setup Details</legend>
467 <p>Now you need to supply the MySQL server information and path information. Detailed instructions on each item can be found in the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><span STYLE='text-decoration: underline;'>'INSTALL'</span></a> manual file.
468 <br /><br />
469 <form method='post' id='myform'>
470 <input name='state' type='hidden' value='3'>
471 <input name='site' type='hidden' value='$site_id'>
472 <input name='inst' type='hidden' value='$inst'>
473 STP2TOP;
474 echo $step2top ."\r\n";
477 $step2tabletop1 = <<<STP2TBLTOP1
478 <fieldset>
479 <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>
480 <div class="ml-2 row">
481 <div class="col-sm-4">
482 <div class="clearfix form-group">
483 <div class="label-div">
484 <label class="font-weight-bold" for="server">Server Host:</label> <a href="#server_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
485 </div>
486 <div>
487 <input name='server' id='server' type='text' class='form-control' value='localhost'>
489 </div>
490 </div>
491 <div id="server_info" class="collapse">
492 <a href="#server_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
493 <p>If you run MySQL and Apache/PHP on the same computer, then leave this as 'localhost'.
494 <p>If they are on separate computers, then enter the IP address of the computer running MySQL.
496 </div>
497 </div>
498 <div class="col-sm-4">
499 <div class="clearfix form-group">
500 <div class="label-div">
501 <label class="font-weight-bold" for="port">Server Port:</label> <a href="#port_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
502 </div>
503 <div>
504 <input name='port' id='port' type='text' class='form-control' value='3306'>
505 </div>
506 </div>
507 <div id="port_info" class="collapse">
508 <a href="#port_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
509 <p>This is the MySQL port.
510 <p>The default port for MySQL is 3306.
511 </div>
512 </div>
513 <div class="col-sm-4">
514 <div class="clearfix form-group">
515 <div class="label-div">
516 <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>
517 </div>
518 <div>
519 <input name='dbname' id='dbname' type='text' class='form-control' value='openemr'>
520 </div>
521 </div>
522 <div id="dbname_info" class="collapse">
523 <a href="#dbname_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
524 <p>This will be the name of the OpenEMR database in MySQL.
525 <p>'openemr' is the recommended name.
526 <p>This database will contain patient data as well as data pertaining to the OpenEMR installation.
527 </div>
528 </div>
529 </div>
530 <div class="ml-2 row">
531 <div class="col-sm-4">
532 <div class="clearfix form-group">
533 <div class="label-div">
534 <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>
535 </div>
536 <div>
537 <input name='login' ID='login' type='text' class='form-control' value='openemr'>
539 </div>
540 </div>
541 <div id="login_info" class="collapse">
542 <a href="#login_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
543 <p>This is the name that OpenEMR will use to login to the MySQL database.
544 <p>'openemr' is the recommended name.
545 </div>
546 </div>
547 <div class="col-sm-4">
548 <div class="clearfix form-group">
549 <div class="label-div">
550 <label class="font-weight-bold" for="pass">Password:</label> <a href="#pass_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
551 </div>
552 <div>
553 <input name='pass' id='pass' class='form-control' type='password' value='' required>
554 </div>
555 </div>
556 <div id="pass_info" class="collapse">
557 <a href="#pass_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
558 <p>This is the Login Password that OpenEMR will use to accesses the MySQL database.
559 <p>It should be at least 12 characters long and composed of both numbers and letters.
560 </div>
561 </div>
562 STP2TBLTOP1;
563 echo $step2tabletop1 ."\r\n";
564 if ($inst != 2) {
565 $step2tabletop2 = <<<STP2TBLTOP2
566 <div class="col-sm-4">
567 <div class="clearfix form-group">
568 <div class="label-div">
569 <label class="font-weight-bold" for="root">Name for Root Account:</label> <a href="#root_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
570 </div>
571 <div>
572 <input name='root' id='root' type='text' class='form-control' value='root'>
573 </div>
574 </div>
575 <div id="root_info" class="collapse">
576 <a href="#root_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
577 <p>This is name for the MySQL root account.
578 <p>For localhost, it is usually ok to leave it as 'root'.
579 </div>
580 </div>
581 </div>
582 <div class="ml-2 row">
583 <div class="col-sm-4">
584 <div class="clearfix form-group">
585 <div class="label-div">
586 <label class="font-weight-bold" for="rootpass">Root Password:</label> <a href="#rootpass_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
587 </div>
588 <div>
589 <input name='rootpass' id='rootpass' type='password' class='form-control' value=''>
591 </div>
592 </div>
593 <div id="rootpass_info" class="collapse">
594 <a href="#rootpass_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
595 <p>This is your MySQL server root password.
596 </div>
597 </div>
598 <div class="col-sm-4">
599 <div class="clearfix form-group">
600 <div class="label-div">
601 <label class="font-weight-bold" for="loginhost">User Hostname:</label> <a href="#loginhost_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
602 </div>
603 <div>
604 <input name='loginhost' id='loginhost' type='text' class='form-control' value='localhost'>
605 </div>
606 </div>
607 <div id="loginhost_info" class="collapse">
608 <a href="#loginhost_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
609 <p>If you run Apache/PHP and MySQL on the same computer, then leave this as 'localhost'.
610 <p>If they are on separate computers, then enter the IP address of the computer running Apache/PHP.
611 </div>
612 </div>
613 <div class="col-sm-4">
614 <div class="clearfix form-group">
615 <div class="label-div">
616 <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>
617 </div>
618 <div>
619 <select name='collate' id=='collate' class='form-control'>
620 <option value='utf8_bin'>
622 </option>
623 <option value='utf8_czech_ci'>
624 Czech
625 </option>
626 <option value='utf8_danish_ci'>
627 Danish
628 </option>
629 <option value='utf8_esperanto_ci'>
630 Esperanto
631 </option>
632 <option value='utf8_estonian_ci'>
633 Estonian
634 </option>
635 <option selected value='utf8_general_ci'>
636 General
637 </option>
638 <option value='utf8_hungarian_ci'>
639 Hungarian
640 </option>
641 <option value='utf8_icelandic_ci'>
642 Icelandic
643 </option>
644 <option value='utf8_latvian_ci'>
645 Latvian
646 </option>
647 <option value='utf8_lithuanian_ci'>
648 Lithuanian
649 </option>
650 <option value='utf8_persian_ci'>
651 Persian
652 </option>
653 <option value='utf8_polish_ci'>
654 Polish
655 </option>
656 <option value='utf8_roman_ci'>
657 Roman
658 </option>
659 <option value='utf8_romanian_ci'>
660 Romanian
661 </option>
662 <option value='utf8_slovak_ci'>
663 Slovak
664 </option>
665 <option value='utf8_slovenian_ci'>
666 Slovenian
667 </option>
668 <option value='utf8_spanish2_ci'>
669 Spanish2 (Traditional)
670 </option>
671 <option value='utf8_spanish_ci'>
672 Spanish (Modern)
673 </option>
674 <option value='utf8_swedish_ci'>
675 Swedish
676 </option>
677 <option value='utf8_turkish_ci'>
678 Turkish
679 </option>
680 <option value='utf8_unicode_ci'>
681 Unicode (German, French, Russian, Armenian, Greek)
682 </option>
683 <option value=''>
684 None (Do not force UTF-8)
685 </option>
686 </select>
687 </div>
688 </div>
689 <div id="collate_info" class="collapse">
690 <a href="#collate_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
691 <p>This is the collation setting for MySQL.
692 <p>Collation refers to a set of rules that determine how data is sorted and compared in a database.
693 <p>Leave as 'General' if you are not sure.
694 <p>If the language you are planning to use in OpenEMR is in the menu, then you can select it.
695 <p>Otherwise, just select 'General'.
696 </div>
697 </div>
698 </div>
699 STP2TBLTOP2;
700 echo $step2tabletop2 ."\r\n";
702 // Include a "source" site ID drop-list and a checkbox to indicate
703 // if cloning its database. When checked, do not display initial user
704 // and group stuff below.
705 $dh = opendir($OE_SITES_BASE);
706 if (!$dh) {
707 die("Cannot read directory '$OE_SITES_BASE'.");
710 $siteslist = array();
711 while (false !== ($sfname = readdir($dh))) {
712 if (substr($sfname, 0, 1) == '.') {
713 continue;
716 if ($sfname == 'CVS') {
717 continue;
720 if ($sfname == $site_id) {
721 continue;
724 $sitedir = "$OE_SITES_BASE/$sfname";
725 if (!is_dir($sitedir)) {
726 continue;
729 if (!is_file("$sitedir/sqlconf.php")) {
730 continue;
733 $siteslist[$sfname] = $sfname;
736 closedir($dh);
737 // If this is not the first site...
738 if (!empty($siteslist)) {
739 ksort($siteslist);
740 $source_site_top = <<<SOURCESITETOP
741 <div class="ml-2 row">
742 <div class="col-sm-4">
743 <div class="clearfix form-group">
744 <div class="label-div">
745 <label class="font-weight-bold" for="source_site_id">Source Site:</label> <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>
746 </div>
747 <div>
748 <select name='source_site_id'id='source_site_id' class='form-control'>
749 SOURCESITETOP;
750 echo $source_site_top . "\r\n";
751 foreach ($siteslist as $sfname) {
752 echo "<option value='$sfname'";
753 if ($sfname == 'default') {
754 echo " selected";
757 echo ">$sfname</option>";
759 $source_site_bot = <<<SOURCESITEBOT
760 </select>
762 </div>
763 </div>
764 <div id="source_site_id_info" class="collapse">
765 <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>
766 <p>The site directory that will be a model for the new site.
767 </div>
768 </div>
769 <div class="col-sm-4">
770 <div class="clearfix form-group">
771 <div class="label-div">
772 <label class="font-weight-bold" for="clone_database">Clone Source Database:</label> <a href="#clone_database_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
773 </div>
774 <div>
775 <input type='checkbox' name='clone_database' id='clone_database' onclick='cloneClicked()' />
776 </div>
777 </div>
778 <div id="clone_database_info" class="collapse">
779 <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>
780 <p>Clone the source site's database instead of creating a fresh one.
781 </div>
782 </div>
783 </div>
784 SOURCESITEBOT;
785 echo $source_site_bot ."\r\n";
788 $randomusernamepre = RandomGenUtils::produceRandomString(3, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
789 $randomusernamepost = RandomGenUtils::produceRandomString(2, "0123456789");
790 $randomusername = $randomusernamepre . "-admin-" . $randomusernamepost;
792 // App Based TOTP secret
793 // Shared key (per rfc6238 and rfc4226) should be 20 bytes (160 bits) and encoded in base32, which should
794 // be 32 characters in base32
795 // Would be nice to use the OpenEMR\Common\Utils\RandomGenUtils\produceRandomBytes() function and then encode to base32,
796 // but does not appear to be a standard way to encode binary to base32 in php.
797 $randomsecret = RandomGenUtils::produceRandomString(32, "234567ABCDEFGHIJKLMNOPQRSTUVWXYZ");
798 if (empty($randomsecret) || empty($randomusernamepre) || empty($randomusernamepost)) {
799 error_log('OpenEMR Error : Random String error - exiting');
800 die();
802 $disableCheckbox = "";
803 if (empty($randomsecret)) {
804 $randomsecret = "";
805 $disableCheckbox = "disabled";
808 $step2tablebot = <<<STP2TBLBOT
809 </fieldset>
810 <br />
811 <fieldset class='noclone'>
812 <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>
813 <div class="ml-2 row">
814 <div class="col-sm-4">
815 <div class="clearfix form-group">
816 <div class="label-div">
817 <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>
818 </div>
819 <div>
820 <input name='iuser' id='iuser' type='text' class='form-control' value='$randomusername' minlength='12'>
822 </div>
823 </div>
824 <div id="iuser_info" class="collapse">
825 <a href="#iuser_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
826 <p>This is the login name of the first user that will be created for you.
827 <p>Limit this to one word with at least 12 characters and composed of both numbers and letters.
829 </div>
830 </div>
831 <div class="col-sm-4">
832 <div class="clearfix form-group">
833 <div class="label-div">
834 <label class="font-weight-bold" for="iuserpass">Initial User Password:</label> <a href="#iuserpass_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
835 </div>
836 <div>
837 <input name='iuserpass' id='iuserpass' type='password' class='form-control' value='' minlength='12'>
838 </div>
839 </div>
840 <div id="iuserpass_info" class="collapse">
841 <a href="#iuserpass_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
842 <p>This is the password for the initial user.
843 </div>
844 </div>
845 <div class="col-sm-4">
846 <div class="clearfix form-group">
847 <div class="label-div">
848 <label class="font-weight-bold" for="iufname">Initial User's First Name:</label> <a href="#iufname_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
849 </div>
850 <div>
851 <input name='iufname' id='iufname 'type='text' class='form-control' value='Administrator'>
852 </div>
853 </div>
854 <div id="iufname_info" class="collapse">
855 <a href="#iufname_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
856 <p>This is the First name of the 'initial user'.
857 </div>
858 </div>
859 </div>
860 <div class="ml-2 row">
861 <div class="col-sm-4">
862 <div class="clearfix form-group">
863 <div class="label-div">
864 <label class="font-weight-bold" for="iuname">Initial User's Last Name:</label> <a href="#iuname_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
865 </div>
866 <div>
867 <input name='iuname' id='iuname' type='text' class='form-control' value='Administrator'>
869 </div>
870 </div>
871 <div id="iuname_info" class="collapse">
872 <a href="#iuname_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
873 <p>This is the Last name of the 'initial user'.
874 </div>
875 </div>
876 <div class="col-sm-4">
877 <div class="clearfix form-group">
878 <div class="label-div">
879 <label class="font-weight-bold" for="igroup">Initial Group:</label> <a href="#igroup_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
880 </div>
881 <div>
882 <input name='igroup' id='igroup' class='form-control' type='text' value='Default'>
883 </div>
884 </div>
885 <div id="igroup_info" class="collapse">
886 <a href="#igroup_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
887 <p>This is the group that will be created for your users.
888 <p>This should be the name of your practice.
889 </div>
890 </div>
891 </div>
892 </fieldset>
893 <br />
894 <fieldset class='noclone py-2 bg-warning'>
895 <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>
896 <div class="ml-2 row">
897 <div class="col-sm-3">
898 <div class="clearfix form-group">
899 <div class="label-div">
900 <label class="font-weight-bold" for="i2fa">Configure 2FA:</label> <a href="#i2fa_info" class="info-anchor icon-tooltip" data-toggle="collapse" ><i class="fa fa-question-circle" aria-hidden="true"></i></a>
901 </div>
902 <div>
903 <input name='i2faenable' id='i2faenable' type='checkbox' $disableCheckbox/> Enable 2FA
904 <input type='hidden' name='i2fasecret' id='i2fasecret' value='$randomsecret' />
905 </div>
906 </div>
907 <div id="i2fa_info" class="collapse">
908 <a href="#i2fa_info" data-toggle="collapse" class="oe-pull-away"><i class="fa fa-times oe-help-x" aria-hidden="true"></i></a>
909 <p>If selected will allow TOTP 2 factor authentication for the initial user.</p>
910 <p>Click on the help file for more information.</p>
911 </div>
912 </div>
913 <div class="col-sm-5">
914 <div class="clearfix form-group">
915 <p class="text-danger font-weight-bold">IMPORTANT IF ENABLED</p>
916 <p>If enabled, you must have an authenticator app on your phone ready to scan the QR code displayed next.</p>
917 </div>
918 </div>
919 <div class="col-sm-4">
920 <div class="clearfix form-group">
921 <p>Example authenticator apps include:</p>
922 <ul>
923 <li>Google Auth
924 (<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>
925 <li>Authy
926 (<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>
927 </ul>
928 </div>
929 </div>
930 </div>
931 </fieldset>
932 <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>
933 <!--<p class='p-1 bg-success text-white'>Upon successful completion will automatically take you to the next step.</p>-->
934 <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>
935 <button type='submit' id='create_db_button' value='Continue' class='wait'><b>Create DB and User</b></button>
936 </form>
937 </fieldset>
938 STP2TBLBOT;
939 echo $step2tablebot ."\r\n";
940 break;
942 case 3:
943 // Form Validation
944 // (applicable if not cloning from another database)
946 $pass_step2_validation = true;
947 $error_step2_message = "$error - ";
949 if (! $installer->char_is_valid($_REQUEST['server'])) {
950 $pass_step2_validation = false;
951 $error_step2_message .= "A database server host is required <br />\n";
954 if (! $installer->char_is_valid($_REQUEST['port'])) {
955 $pass_step2_validation = false;
956 $error_step2_message .= "A database server port value is required <br />\n";
959 if (! $installer->databaseNameIsValid($_REQUEST['dbname'])) {
960 $pass_step2_validation = false;
961 $error_step2_message .= "A database name is required <br />\n";
964 if (! $installer->collateNameIsValid($_REQUEST['collate'])) {
965 $pass_step2_validation = false;
966 $error_step2_message .= "A collation name is required <br />\n";
969 if (! $installer->char_is_valid($_REQUEST['login'])) {
970 $pass_step2_validation = false;
971 $error_step2_message .= "A database login name is required <br />\n";
974 if (! $installer->char_is_valid($_REQUEST['pass'])) {
975 $pass_step2_validation = false;
976 $error_step2_message .= "A database login password is required <br />\n";
979 if (!$pass_step2_validation) {
980 $error_step2_message .= $error_page_end . "\r\n";
981 die($error_step2_message);
985 if (empty($installer->clone_database)) {
986 if (! $installer->login_is_valid()) {
987 echo "$error. Please pick a proper 'Login Name'.<br />\n";
988 echo "Click Back in browser to re-enter.<br />\n";
989 break;
992 if (! $installer->iuser_is_valid()) {
993 echo "$error. The 'Initial User' field can only contain one word and no spaces.<br />\n";
994 echo "Click Back in browser to re-enter.<br />\n";
995 break;
998 if (! $installer->user_password_is_valid()) {
999 echo "$error. Please pick a proper 'Initial User Password'.<br />\n";
1000 echo "Click Back in browser to re-enter.<br />\n";
1001 break;
1005 if (! $installer->password_is_valid()) {
1006 echo "$error. Please pick a proper 'Password'.<br />\n";
1007 echo "Click Back in browser to re-enter.<br />\n";
1008 break;
1011 echo "<fieldset>";
1012 echo "<legend class='mb-3 border-bottom'>Step $state - Creating Database and First User</legend>";
1014 // Skip below if database shell has already been created.
1015 if ($inst != 2) {
1016 echo "Connecting to MySQL Server...\n";
1017 flush();
1018 if (! $installer->root_database_connection()) {
1019 echo "$error. Check your login credentials.\n";
1020 echo $installer->error_message;
1021 break;
1022 } else {
1023 echo "$ok.<br />\n";
1024 flush();
1028 // Only pertinent if cloning another installation database
1029 if ($allow_cloning_setup && !empty($installer->clone_database)) {
1030 echo "Dumping source database...";
1031 flush();
1032 if (! $installer->create_dumpfiles()) {
1033 echo $installer->error_message;
1034 break;
1035 } else {
1036 echo "$ok.<br />\n";
1037 flush();
1041 // Only pertinent if mirroring another installation directory
1042 if (! empty($installer->source_site_id)) {
1043 echo "Creating site directory...";
1044 if (! $installer->create_site_directory()) {
1045 echo $installer->error_message;
1046 break;
1047 } else {
1048 echo "$ok.<br />";
1049 flush();
1053 // Skip below if database shell has already been created.
1054 if ($inst != 2) {
1055 echo "Creating database...\n";
1056 flush();
1057 if (! $installer->create_database()) {
1058 echo "$error. Check your login credentials.\n";
1059 echo $installer->error_message;
1060 break;
1061 } else {
1062 echo "$ok.<br />\n";
1063 flush();
1066 echo "Creating user with permissions for database...\n";
1067 flush();
1068 $user_mysql_error = true;
1069 if (! $installer->create_database_user()) {
1070 echo "$error when creating specified user.\n";
1071 echo $installer->error_message;
1072 break;
1073 } else {
1074 $user_mysql_error = false;
1076 if (! $installer->grant_privileges()) {
1077 echo "$error when granting privileges to the specified user.\n";
1078 echo $installer->error_message;
1079 break;
1080 } else {
1081 $user_mysql_error = false;
1083 if (!$user_mysql_error) {
1084 echo "$ok.<br />\n";
1085 flush();
1088 echo "Reconnecting as new user...\n";
1089 flush();
1090 $installer->disconnect();
1091 } else {
1092 echo "Connecting to MySQL Server...\n";
1095 if (! $installer->user_database_connection()) {
1096 echo "$error. Check your login credentials.\n";
1097 echo $installer->error_message;
1098 break;
1099 } else {
1100 echo "$ok.<br />\n";
1101 flush();
1104 // Load the database files
1105 $dump_results = $installer->load_dumpfiles();
1106 if (! $dump_results) {
1107 echo "$error.\n";
1108 echo $installer->error_message;
1109 break;
1110 } else {
1111 echo $dump_results;
1112 flush();
1115 echo "Writing SQL configuration...\n";
1116 flush();
1117 if (! $installer->write_configuration_file()) {
1118 echo "$error.\n";
1119 echo $installer->error_message;
1120 break;
1121 } else {
1122 echo "$ok.<br />\n";
1123 flush();
1126 // Only pertinent if not cloning another installation database
1127 if (empty($installer->clone_database)) {
1128 echo "Setting version indicators...\n";
1129 flush();
1130 if (! $installer->add_version_info()) {
1131 echo "$error.\n";
1132 echo $installer->error_message;
1134 break;
1135 } else {
1136 echo "$ok<br />\n";
1137 flush();
1140 echo "Writing global configuration defaults...\n";
1141 flush();
1142 if (! $installer->insert_globals()) {
1143 echo "$error.\n";
1144 echo $installer->error_message;
1146 break;
1147 } else {
1148 echo "$ok<br />\n";
1149 flush();
1152 echo "Adding Initial User...\n";
1153 flush();
1154 if (! $installer->add_initial_user()) {
1155 echo "$error.\n";
1156 echo $installer->error_message;
1157 break;
1160 echo "$ok<br />\n";
1161 flush();
1165 // If user has selected to set MFA App Based 2FA, display QR code to scan
1166 $qr = $installer->get_initial_user_2fa_qr();
1167 if ($qr) {
1168 $qrDisplay = <<<TOTP
1169 <br />
1170 <table>
1171 <tr>
1172 <td>
1173 <strong><font color='RED'>IMPORTANT!!</font></strong>
1174 <p><strong>You must scan the following QR code with your preferred authenticator app.</strong></p>
1175 <img src='$qr' width="150" />
1176 </td>
1177 </tr>
1178 <tr>
1179 <td>
1180 Example authenticator apps include:
1181 <ul>
1182 <li>Google Auth
1183 (<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>
1184 <li>Authy
1185 (<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>
1186 </ul>
1187 </td>
1188 </tr>
1189 </table>
1190 TOTP;
1191 echo $qrDisplay;
1194 if ($allow_cloning_setup && !empty($installer->clone_database)) {
1195 // Database was cloned, skip ACL setup.
1196 $btn_text = 'Proceed to Select a Theme';
1197 echo "<br />";
1198 echo "<p>The database was cloned, access control list exists therefore skipping ACL setup</p>";
1199 echo "<p class='p-1 bg-warning'>Click <b>$btn_text</b> for further instructions.</p>";
1200 $next_state = 7;
1201 } else {
1202 $btn_text = 'Proceed to Step 4';
1203 echo "<br />";
1204 echo "<p class='mark'>Click <b>$btn_text</b> to install and configure access controls (php-GACL). $note: This process can take a few minutes.</p>";
1205 echo "<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>";
1206 $next_state = 4;
1209 $form_top = <<<FRMTOP
1210 <form method='post'>
1211 <input name='state' type='hidden' value='$next_state'>
1212 <input name='site' type='hidden' value='$site_id'>
1213 <input name='iuser' type='hidden' value='{$installer->iuser}'>
1214 <input name='iuserpass' type='hidden' value='{$installer->iuserpass}'>
1215 <input name='iuname' type='hidden' value='{$installer->iuname}'>
1216 <input name='iufname' type='hidden' value='{$installer->iufname}'>
1217 <input name='login' type='hidden' value='{$installer->login}'>
1218 <input name='pass' type='hidden' value='{$installer->pass}'>
1219 <input name='server' type='hidden' value='{$installer->server}'>
1220 <input name='port' type='hidden' value='{$installer->port}'>
1221 <input name='loginhost' type='hidden' value='{$installer->loginhost}'>
1222 <input name='dbname' type='hidden' value='{$installer->dbname}'>
1223 FRMTOP;
1224 echo $form_top . "\r\n";
1225 if ($allow_cloning_setup) {
1226 echo "<input type='hidden' name='clone_database' value='$installer->clone_database'>";
1227 echo "<input name='source_site_id' type='hidden' value='$installer->source_site_id'>";
1229 $form_bottom = <<<FRMBOT
1230 <button type='submit' id='step-4-btn' value='Continue' class='wait'><b>$btn_text</b></button>
1231 <br />
1232 </form>
1233 </fieldset>
1234 FRMBOT;
1235 echo $form_bottom . "\r\n";
1236 break;
1237 case 4:
1238 $step4_top = <<<STP4TOP
1239 <fieldset>
1240 <legend class="mb-3 border-bottom">Step $state - Creating and Configuring Access Control List</legend>
1241 <p>Installing and Configuring Access Controls (php-GACL)...</p><br />
1242 STP4TOP;
1243 echo $step4_top . "\r\n";
1244 if (! $installer->install_gacl()) {
1245 echo "$error -.\n";
1246 echo $installer->error_message;
1247 break;
1248 } else {
1249 // display the status information for gacl setup
1250 echo $installer->debug_message;
1252 $btn_text = 'Proceed to Step 5';
1253 $step4_bottom = <<<STP4BOT
1254 <p>Gave the '{$installer->iuser}' user (password is '{$installer->iuserpass}') administrator access.</p>
1255 <p>Done installing and configuring access controls (php-gacl).</p>
1256 <p>The next step will configure php.</p>
1257 <p class='mark'>Click <strong>$btn_text</strong> to continue.</p>
1258 <br />
1259 <form method='post'>
1260 <input name='state' type='hidden' value='5'>
1261 <input name='site' type='hidden' value='$site_id'>
1262 <input name='iuser' type='hidden' value='{$installer->iuser}'>
1263 <input name='iuserpass' type='hidden' value='{$installer->iuserpass}'>
1264 <input name='login' type='hidden' value='{$installer->login}'>
1265 <input name='pass' type='hidden' value='{$installer->pass}'>
1266 <input name='server' type='hidden' value='{$installer->server}'>
1267 <input name='port' type='hidden' value='{$installer->port}'>
1268 <input name='loginhost' type='hidden' value='{$installer->loginhost}'>
1269 <input name='dbname' type='hidden' value='{$installer->dbname}'>
1270 <button type='submit' value='Continue'><b>$btn_text</b></button>
1271 </form>
1272 </fieldset>
1273 STP4BOT;
1274 echo $step4_bottom . "\r\n";
1275 break;
1277 case 5:
1278 $step5_top = <<<STP5TOP
1279 <fieldset>
1280 <legend class="mb-3 border-bottom">Step $state - Configure PHP</legend>
1281 <p>Configuration of PHP...</p><br />
1282 <p>We recommend making the following changes to your PHP installation, which can normally be done by editing the php.ini configuration file:</p>
1283 <ul>
1284 STP5TOP;
1285 echo $step5_top . "\r\n";
1287 $gotFileFlag = 0;
1288 $phpINIfile = php_ini_loaded_file();
1289 if ($phpINIfile) {
1290 echo "<li><font color='green'>Your php.ini file can be found at ".$phpINIfile."</font></li>\n";
1291 $gotFileFlag = 1;
1294 $short_tag = ini_get('short_open_tag')?'On':'Off';
1295 $display_errors = ini_get('display_errors')?'On':'Off';
1296 $register_globals = ini_get('register_globals')?'On':'Off';
1297 $max_input_vars = ini_get('max_input_vars');
1298 $max_execution_time = ini_get('max_execution_time');
1299 $max_input_time = ini_get('max_input_time');
1300 $post_max_size = ini_get('post_max_size');
1301 $memory_limit = ini_get('memory_limit');
1302 $mysqli_allow_local_infile = ini_get('mysqli.allow_local_infile')?'On':'Off';
1304 $step5_table = <<<STP5TAB
1305 <li>To ensure proper functioning of OpenEMR you must make sure that PHP settings include:
1306 <table class='phpset'>
1307 <tr>
1308 <th>Setting</th>
1309 <th>Required value</th>
1310 <th>Current value</th>
1311 </tr>
1312 <tr>
1313 <td>short_open_tag</td>
1314 <td>Off</td>
1315 <td>$short_tag</td>
1316 </tr>
1317 <tr>
1318 <td>display_errors</td>
1319 <td>Off</td>
1320 <td>$display_errors</td>
1321 </tr>
1322 <tr>
1323 <td>register_globals</td>
1324 <td>Off</td>
1325 <td>$register_globals</td>
1326 </tr>
1327 <tr>
1328 <td>max_input_vars</td>
1329 <td>at least 3000</td>
1330 <td>$max_input_vars</td>
1331 </tr>
1332 <tr>
1333 <td>max_execution_time</td>
1334 <td>at least 60</td>
1335 <td>$max_execution_time</td>
1336 </tr>
1337 <tr>
1338 <td>max_input_time</td>
1339 <td>-1</td>
1340 <td>$max_input_time</td>
1341 </tr>
1342 <tr>
1343 <td>post_max_size</td>
1344 <td>at least 30M</td>
1345 <td>$post_max_size</td>
1346 </tr>
1347 <tr>
1348 <td>memory_limit</td>
1349 <td>at least 256M</td>
1350 <td>$memory_limit</td>
1351 </tr>
1352 <tr>
1353 <td>mysqli.allow_local_infile</td>
1354 <td>On</td>
1355 <td>$mysqli_allow_local_infile</td>
1356 </tr>
1357 </table>
1358 </li>
1359 <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.
1360 </li>
1361 STP5TAB;
1362 echo $step5_table . "\r\n";
1364 if (!$gotFileFlag) {
1365 echo "<li>If you are having difficulty finding your php.ini file, then refer to the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><span STYLE='text-decoration: underline;'>'INSTALL'</span></a> manual for suggestions.</li>\n";
1368 $btn_text = 'Proceed to Step 6';
1369 $step5_bottom = <<<STP5BOT
1370 </ul>
1372 <p>We recommend you print these instructions for future reference.</p>
1373 <p>The next step will configure the Apache web server.</p>
1374 <p class='mark'>Click <strong>$btn_text</strong> to continue.</p>
1375 <br />
1376 <form method='post'>
1377 <input type='hidden' name='state' value='6'>
1378 <input type='hidden' name='site' value='$site_id'>
1379 <input type='hidden' name='iuser' value='{$installer->iuser}'>
1380 <input type='hidden' name='iuserpass' value='{$installer->iuserpass}'>
1381 <input name='login' type='hidden' value='{$installer->login}'>
1382 <input name='pass' type='hidden' value='{$installer->pass}'>
1383 <input name='server' type='hidden' value='{$installer->server}'>
1384 <input name='port' type='hidden' value='{$installer->port}'>
1385 <input name='loginhost' type='hidden' value='{$installer->loginhost}'>
1386 <input name='dbname' type='hidden' value='{$installer->dbname}'>
1387 <button type='submit' value='Continue'><b>$btn_text</b></button>
1388 </form>
1389 </fieldset>
1390 STP5BOT;
1391 echo $step5_bottom . "\r\n";
1392 break;
1394 case 6:
1395 echo "<fieldset>";
1396 echo "<legend class='mb-3 border-bottom'>Step $state - Configure Apache Web Server</legend>";
1397 echo "<p>Configuration of Apache web server...</p><br />\n";
1398 echo "The <strong>\"".preg_replace("/${site_id}/", "*", realpath($docsDirectory))."\"</strong> directory contain patient information, and
1399 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 />
1400 &nbsp;&nbsp;&lt;Directory \"".realpath(dirname(__FILE__))."\"&gt;<br />
1401 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AllowOverride FileInfo<br />
1402 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Require all granted<br />
1403 &nbsp;&nbsp;&lt;/Directory&gt;<br />
1404 &nbsp;&nbsp;&lt;Directory \"".realpath(dirname(__FILE__))."/sites\"&gt;<br />
1405 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AllowOverride None<br />
1406 &nbsp;&nbsp;&lt;/Directory&gt;<br />
1407 &nbsp;&nbsp;&lt;Directory \"".preg_replace("/${site_id}/", "*", realpath($docsDirectory))."\"&gt;<br />
1408 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Require all denied<br />
1409 &nbsp;&nbsp;&lt;/Directory&gt;<br /><br />";
1411 $btn_text = 'Proceed to Select a Theme';
1412 $step6_bottom = <<<STP6BOT
1413 <p>If you are having difficulty finding your apache configuration file, then refer to the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><span style='text-decoration: underline;'>'INSTALL'</span></a> manual for suggestions.</p>
1414 <p>We recommend you print these instructions for future reference.</p>
1415 <p class='mark'>Click <strong>'$btn_text'</strong> to select a theme.</p>
1416 <br />
1417 <form method='post'>
1418 <input type='hidden' name='state' value='7'>
1419 <input type='hidden' name='site' value='$site_id'>
1420 <input type='hidden' name='iuser' value='{$installer->iuser}'>
1421 <input type='hidden' name='iuserpass' value='{$installer->iuserpass}'>
1422 <input name='login' type='hidden' value='{$installer->login}'>
1423 <input name='pass' type='hidden' value='{$installer->pass}'>
1424 <input name='server' type='hidden' value='{$installer->server}'>
1425 <input name='port' type='hidden' value='{$installer->port}'>
1426 <input name='loginhost' type='hidden' value='{$installer->loginhost}'>
1427 <input name='dbname' type='hidden' value='{$installer->dbname}'>
1428 <button type='submit' value='Continue'><b>$btn_text</b></button>
1429 </form>
1430 <fieldset>
1431 STP6BOT;
1432 echo $step6_bottom . "\r\n";
1433 break;
1435 case 7:
1436 echo "<fieldset>";
1437 echo "<legend class='mb-3 border-bottom'>Step $state - Select a Theme</legend>";
1438 echo "<p>Select a theme for OpenEMR...</p><br />\n";
1439 $btn_text = "Proceed to Final Step";
1440 $installer->displaySelectedThemeDiv();
1441 $theme_form = <<<TMF
1442 <div class='row'>
1443 <div class="col-sm-4 offset-sm-4">
1444 <form method='post'>
1445 <input type='hidden' name='state' value='8'>
1446 <input type='hidden' name='site' value='$site_id'>
1447 <input type='hidden' name='iuser' value='{$installer->iuser}'>
1448 <input type='hidden' name='iuserpass' value='{$installer->iuserpass}'>
1449 <input name='login' type='hidden' value='{$installer->login}'>
1450 <input name='pass' type='hidden' value='{$installer->pass}'>
1451 <input name='server' type='hidden' value='{$installer->server}'>
1452 <input name='port' type='hidden' value='{$installer->port}'>
1453 <input name='loginhost' type='hidden' value='{$installer->loginhost}'>
1454 <input name='dbname' type='hidden' value='{$installer->dbname}'>
1455 <input type='hidden' name='new_theme' id = 'new_theme' value='{$installer->getCurrentTheme()}'>
1456 <input name='clone_database' type='hidden' value='{$installer->clone_database}'>
1457 <input name='source_site_id' type='hidden' value='{$installer->source_site_id}'>
1458 <h4>Select One:</h4>
1459 <div class="checkbox">
1460 <label><input type="checkbox" class="check" value="show_theme">Show More Themes</label>
1461 </div>
1462 <div class="checkbox">
1463 <label><input type="checkbox" class="check" value="keep_current">Keep Current</label>
1464 </div>
1465 <div class='hide_button' style="display:none;">
1466 <button type='submit' value='Continue' id='continue'>{$btn_text}</button>
1467 </div>
1468 </form>
1469 </div>
1470 </div>
1471 </fieldset>
1472 TMF;
1473 echo $theme_form ."\r\n";
1474 echo '<div class="row hideaway" style="display:none;">'."\r\n";
1475 echo '<div class="col-sm-12">'."\r\n";
1476 echo ' <h4>Select New Theme: <h5>(scroll down to view all)</h5></h4>'."\r\n";
1477 echo ' <br />'."\r\n";
1478 $installer->displayThemesDivs();
1479 break;
1481 case 0:
1482 default:
1483 $top = <<<TOP
1484 <fieldset>
1485 <legend class="mb-3 border-bottom">Pre Install - Checking File and Directory Permissions</legend>
1486 <p><span class="text">Welcome to OpenEMR. This utility will step you through the installation and configuration of OpenEMR for your practice.</span></p>
1487 <ul>
1488 <li><span class="text">Before proceeding, be sure that you have a properly installed and configured MySQL server available, and a PHP configured webserver.</span></li>
1489 <li><span class="mark">Detailed installation instructions can be found in the <a href='Documentation/INSTALL' rel='noopener' target='_blank'><span style='text-decoration: underline;'>'INSTALL'</span></a> manual file.</span></li>
1490 <li>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.
1491 </li>
1492 </ul>
1493 TOP;
1494 echo $top;
1495 if ($checkPermissions) {
1496 echo "<p>We will now ensure correct file and directory permissions before starting installation:</p>\n";
1497 echo "<FONT COLOR='green'>Ensuring following file is world-writable...</FONT><br />\n";
1498 $errorWritable = 0;
1499 foreach ($writableFileList as $tempFile) {
1500 if (is_writable($tempFile)) {
1501 echo "'".realpath($tempFile)."' file is <FONT COLOR='green'><b>ready</b></FONT>.<br />\n";
1502 } else {
1503 echo "<p><FONT COLOR='red'>UNABLE</FONT> to open file '".realpath($tempFile)."' for writing.<br />\n";
1504 echo "(configure file permissions; see below for further instructions)</p>\n";
1505 $errorWritable = 1;
1509 if ($errorWritable) {
1510 $check_file = <<<CHKFILE
1511 <p style="font-color:red;">You can't proceed until all above files are ready (world-writable).</p>
1512 <p>In linux, recommend changing file permissions with the <strong>'chmod 666 filename'</strong> command.</p>
1513 <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>
1514 <br />
1515 <form method='post'>
1516 <input type='hidden' name='site' value='$site_id'>
1517 <button type='submit' value='check again'><b>Check Again</b></button>
1518 </form>
1519 CHKFILE;
1520 echo $check_file . "\r\n";
1521 break;
1524 $errorWritable = 0;
1525 foreach ($writableDirList as $tempDir) {
1526 echo "<br /><FONT COLOR='green'>Ensuring the '" . realpath($tempDir) . "' directory and its subdirectories have proper permissions...</FONT><br />\n";
1527 $errorWritable = recursive_writable_directory_test($tempDir);
1530 if ($errorWritable) {
1531 $check_directory = <<<CHKDIR
1532 <p style="font-color:red;">You can't proceed until all directories and subdirectories are ready.</p>
1533 <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>
1534 <p class='p-1 bg-warning'>Fix above directory permissions and then click the <strong>'Check Again'</strong> button to re-check directories.</p>
1535 <br />
1536 <form method='post'>
1537 <input type='hidden' name='site' value='$site_id'>
1538 <button type='submit' value='check again'><b>Check Again</b></button>
1539 </form>
1540 CHKDIR;
1541 echo $check_directory . "\r\n";
1542 break;
1545 //RP_CHECK_LOGIC
1546 $form = <<<FRM
1547 <br />
1548 <p>All required files and directories have been verified.</p>
1549 <p class='mark'>Click <b>Proceed to Step 1</b> to continue with a new installation.</p>
1550 <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>
1551 <br />
1552 <form method='post'>
1553 <input name='state' type='hidden' value='1'>
1554 <input name='site' type='hidden' value='$site_id'>
1555 <button type='submit' value='Continue'><b>Proceed to Step 1</b></button>
1556 </form>
1557 FRM;
1558 echo $form ."\r\n";
1559 } else {
1560 echo "<br />Click to continue installation.<br />\n";
1564 $bot=<<<BOT
1565 </div>
1566 </div>
1567 BOT;
1568 echo $bot ."\r\n";
1572 </div><!--end of container div -->
1573 <?php $installer->setupHelpModal();?>
1574 <script>
1575 //jquery-ui tooltip
1576 $(function() {
1577 $('.icon-tooltip').prop( "title", "Click to see more information").tooltip({
1578 show: {
1579 delay: 700,
1580 duration: 0
1583 $('.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();
1584 $('.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();
1588 </script>
1589 <script type = "text/javascript" >
1590 $(function() {
1591 $("input[type='radio']").click(function() {
1592 var radioValue = $("input[name='stylesheet']:checked").val();
1593 var imgPath = "public/images/stylesheets/";
1594 var currStyle = $("#current_theme_title").text();
1595 var currStyleTitle = currStyle;
1596 currStyle = currStyle.replace(/\b\w/g, l => l.toLowerCase());
1597 currStyle = currStyle.split(" ");
1598 currStyle = currStyle.join("_");
1599 currStyle = "style_" + currStyle + ".png";
1600 if (radioValue) {
1601 var currThemeText = radioValue.split("_");
1602 currThemeText = currThemeText.join(" ");
1603 currThemeText = currThemeText.replace(/\b\w/g, l => l.toUpperCase());
1604 var styleSelected = confirm("You have selected style - " + currThemeText + "\n" + "Click OK to apply selection");
1605 if (styleSelected) {
1606 $("#current_theme").attr("src", imgPath + "style_" + radioValue + ".png");
1607 $("#current_theme_title").text(currThemeText);
1608 $("#new_theme").val("style_" + radioValue + ".css");
1609 } else {
1610 $("#current_theme").attr("src", imgPath + currStyle);
1611 $("#current_theme_title").text(currStyleTitle);
1612 $(this).prop("checked", false);
1616 $('.check').click(function() {
1617 $('.check').not(this).prop('checked', false);
1618 if($('.check:checked').val() == 'show_theme'){
1619 $(".hideaway").show();
1620 } else if($('.check:checked').val() == 'keep_current'){
1621 $(".hideaway").hide();
1624 if($('.check').filter(':checked').length > 0) {
1625 $(".hide_button").show();
1626 } else {
1627 $(".hide_button").hide();
1628 $(".hideaway").hide();
1631 $('.wait').removeClass('button-wait');
1633 $( "#create_db_button" ).hover(
1634 function() {
1635 if (($('#iuserpass' ).val().length > 11 && $('#iuser' ).val().length > 11 ) || ($('#clone_database').prop('checked'))){
1637 $("button").click(function(){
1638 $(".oe-spinner").css("visibility", "visible");
1641 $('.wait').click(function(){
1642 $('.wait').addClass('button-wait');
1648 $("#step-4-btn").click(function(){
1649 $(".oe-spinner").css("visibility", "visible");
1650 $(this).addClass('button-wait');
1653 </script>
1654 </body>
1655 </html>