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