7 * @link http://www.open-emr.org
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Kevin Yeh <kevin.y@integralemr.com>
11 * @author Scott Wakefield <scott.wakefield@gmail.com>
12 * @author ViCarePlus <visolve_emr@visolve.com>
13 * @author Julia Longtin <julialongtin@diasp.org>
16 * @author Tyler Wrenn <tyler@tylerwrenn.com>
17 * @author Ken Chapple <ken@mi-squared.com>
18 * @author Daniel Pflieger <daniel@mi-squared.com> <daniel@growlingflea.com>
19 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
20 * @copyright Copyright (c) 2020 Tyler Wrenn <tyler@tylerwrenn.com>
21 * @copyright Copyright (c) 2021 Ken Chapple <ken@mi-squared.com>
22 * @copyright Copyright (c) 2021 Daniel Pflieger <daniel@mi-squared.com> <daniel@growlingflea.com>
23 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
26 use OpenEMR\Core\Header
;
27 use OpenEMR\Services\FacilityService
;
30 // Set $sessionAllowWrite to true to prevent session concurrency issues during authorization related code
31 $sessionAllowWrite = true;
32 require_once("../globals.php");
34 // mdsupport - Add 'App' functionality for user interfaces without standard menu and frames
35 // If this script is called with app parameter, validate it without showing other apps.
37 // Build a list of valid entries
40 "SELECT option_id, title,is_default FROM list_options
41 WHERE list_id=? and activity=1 ORDER BY seq, option_id",
44 if (sqlNumRows($rs)) {
45 while ($app = sqlFetchArray($rs)) {
46 $app_req = explode('?', trim($app['title']));
47 if (! file_exists('../' . $app_req[0])) {
51 $emr_app [trim($app ['option_id'])] = trim($app ['title']);
52 if ($app ['is_default']) {
53 $emr_app_def = $app ['option_id'];
59 if (count($emr_app)) {
60 // Standard app must exist
61 $std_app = 'main/main_screen.php';
62 if (!in_array($std_app, $emr_app)) {
63 $emr_app['*OpenEMR'] = $std_app;
66 if (isset($_REQUEST['app']) && $emr_app[$_REQUEST['app']]) {
67 $div_app = sprintf('<input type="hidden" name="appChoice" value="%s">', attr($_REQUEST['app']));
69 foreach ($emr_app as $opt_disp => $opt_value) {
71 '<option value="%s" %s>%s</option>\n',
73 ($opt_disp == $opt_default ?
'selected="selected"' : ''),
74 text(xl_list_label($opt_disp))
80 <div id="divApp" class="form-group">
81 <label for="appChoice" class="text-right">%s:</label>
83 <select class="form-control" id="selApp" name="appChoice" size="1">%s</select>
92 // This code allows configurable positioning in the login page
93 $loginrow = "row login-row align-items-center m-5";
95 if ($GLOBALS['login_page_layout'] == 'left') {
96 $logoarea = "col-md-6 login-bg-left py-3 px-5 py-md-login order-1 order-md-2";
97 $formarea = "col-md-6 p-5 login-area-left order-2 order-md-1";
98 } elseif ($GLOBALS['login_page_layout'] == 'right') {
99 $logoarea = "col-md-6 login-bg-right py-3 px-5 py-md-login order-1 order-md-1";
100 $formarea = "col-md-6 p-5 login-area-right order-2 order-md-2";
102 $logoarea = "col-12 login-bg-center py-3 px-5 order-1";
103 $formarea = "col-12 p-5 login-area-center order-2";
104 $loginrow = "row login-row login-row-center align-items-center";
110 <?php Header
::setupHeader(); ?
>
112 <title
><?php
echo text($openemr_name) . " " . xlt('Login'); ?
></title
>
115 if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) { ?
>
116 <meta name
="google-signin-client_id" content
="<?php echo $GLOBALS['google_signin_client_id']; ?>">
119 var registrationTranslations
= <?php
echo json_encode(array(
120 'title' => xla('OpenEMR Product Registration'),
121 'pleaseProvideValidEmail' => xla('Please provide a valid email address'),
122 'success' => xla('Success'),
123 'registeredSuccess' => xla('Your installation of OpenEMR has been registered'),
124 'submit' => xla('Submit'),
125 'noThanks' => xla('No Thanks'),
126 'registeredEmail' => xla('Registered email'),
127 'registeredId' => xla('Registered id'),
128 'genericError' => xla('Error. Try again later'),
132 var registrationConstants
= <?php
echo json_encode(array(
133 'webroot' => $GLOBALS['webroot']
137 <script src
="<?php echo $webroot ?>/interface/product_registration/product_registration_service.js?v=<?php echo $v_js_includes; ?>"></script
>
138 <script src
="<?php echo $webroot ?>/interface/product_registration/product_registration_controller.js?v=<?php echo $v_js_includes; ?>"></script
>
144 var productRegistrationController
= new ProductRegistrationController();
145 productRegistrationController
.getProductRegistrationStatus(function(err
, data
) {
148 if (data
.statusAsString
=== 'UNREGISTERED') {
149 productRegistrationController
.showProductRegistrationModal();
155 $
("#authUser").focus();
158 function transmit_form(element
) {
159 // disable submit button to insert a notification of working
160 element
.disabled
= true;
161 // nothing fancy. mainly for mobile.
162 element
.innerHTML
= '<i class="fa fa-sync fa-spin"></i> ' +
jsText(<?php
echo xlj("Authenticating"); ?
>);
163 <?php
if (session_name()) { ?
>
164 <?php
$scparams = session_get_cookie_params(); ?
>
165 // Delete the session cookie by setting its expiration date in the past.
166 // This forces the server to create a new session ID.
167 var olddate
= new Date();
168 olddate
.setFullYear(olddate
.getFullYear() - 1);
169 var mycookie
= <?php
echo json_encode(urlencode(session_name())); ?
> +
'=' +
<?php
echo json_encode(urlencode(session_id())); ?
> +
170 '; path=' +
<?php
echo json_encode($scparams['path']); ?
> +
171 '; domain=' +
<?php
echo json_encode($scparams['domain']); ?
> +
172 '; expires=' + olddate
.toGMTString();
173 var samesite
= <?php
echo json_encode(empty($scparams['samesite']) ?
'' : $scparams['samesite']); ?
>;
175 mycookie +
= '; SameSite=' + samesite
;
177 document
.cookie
= mycookie
;
179 document
.forms
[0].submit();
185 <form method
="POST" id
="login_form" autocomplete
="off" action
="../main/main_screen.php?auth=login&site=<?php echo attr($_SESSION['site_id']); ?>" target
="_top" name
="login_form">
186 <div
class="<?php echo $loginrow; ?>">
187 <div
class="<?php echo $formarea; ?>">
188 <input type
='hidden' name
='new_login_session_management' value
='1' />
191 // collect default language id
192 $res2 = sqlStatement("select * from lang_languages where lang_description = ?", array($GLOBALS['language_default']));
193 for ($iter = 0; $row = sqlFetchArray($res2); $iter++
) {
194 $result2[$iter] = $row;
197 if (count($result2) == 1) {
198 $defaultLangID = $result2[0]["lang_id"];
199 $defaultLangName = $result2[0]["lang_description"];
201 //default to english if any problems
203 $defaultLangName = "English";
206 // set session variable to default so login information appears in default language
207 $_SESSION['language_choice'] = $defaultLangID;
208 // collect languages if showing language menu
209 if ($GLOBALS['language_menu_login']) {
210 // sorting order of language titles depends on language translation options.
211 $mainLangID = empty($_SESSION['language_choice']) ?
'1' : $_SESSION['language_choice'];
212 // Use and sort by the translated language name.
213 $sql = "SELECT ll.lang_id, " .
214 "IF(LENGTH(ld.definition),ld.definition,ll.lang_description) AS trans_lang_description, " .
215 "ll.lang_description " .
216 "FROM lang_languages AS ll " .
217 "LEFT JOIN lang_constants AS lc ON lc.constant_name = ll.lang_description " .
218 "LEFT JOIN lang_definitions AS ld ON ld.cons_id = lc.cons_id AND " .
220 "ORDER BY IF(LENGTH(ld.definition),ld.definition,ll.lang_description), ll.lang_id";
221 $res3 = SqlStatement($sql, array($mainLangID));
223 for ($iter = 0; $row = sqlFetchArray($res3); $iter++
) {
224 $result3[$iter] = $row;
227 if (count($result3) == 1) {
228 //default to english if only return one language
229 echo "<input type='hidden' name='languageChoice' value='1' />\n";
232 echo "<input type='hidden' name='languageChoice' value='" . attr($defaultLangID) . "' />\n";
235 if ($GLOBALS['login_into_facility']) {
236 $facilityService = new FacilityService();
237 $facilities = $facilityService->getAllFacility();
238 $facilitySelected = ($GLOBALS['set_facility_cookie'] && isset($_COOKIE['pc_facility'])) ?
$_COOKIE['pc_facility'] : null;
241 <?php
if (isset($_SESSION['relogin']) && ($_SESSION['relogin'] == 1)) { // Begin relogin dialog ?>
242 <div
class="alert alert-info m-1 font-weight-bold">
243 <?php
echo xlt('Password security has recently been upgraded.') . ' ' . xlt('Please login again.'); ?
>
245 <?php
unset($_SESSION['relogin']);
247 if (isset($_SESSION['loginfailure']) && ($_SESSION['loginfailure'] == 1)) { // Begin login failure block ?>
248 <div
class="alert alert-danger login-failure m-1">
249 <?php
echo xlt('Invalid username or password'); ?
>
251 <?php
} // End login failure block ?>
252 <div id
="standard-auth-username" class="form-group">
253 <label
for="authUser" class="text-right"><?php
echo xlt('Username:'); ?
></label
>
254 <input type
="text" class="form-control" id
="authUser" name
="authUser" placeholder
="<?php echo xla('Username:'); ?>" />
256 <div id
="standard-auth-password" class="form-group">
257 <label
for="clearPass" class="text-right"><?php
echo xlt('Password:'); ?
></label
>
258 <input type
="password" class="form-control" id
="clearPass" name
="clearPass" placeholder
="<?php echo xla('Password:'); ?>" />
260 <?php
echo $div_app; ?
>
261 <?php
if ($GLOBALS['language_menu_login'] && (count($result3) != 1)) : // Begin language menu block ?>
262 <div
class="form-group">
263 <label
for="language" class="text-right"><?php
echo xlt('Language'); ?
>:</label
>
265 <select
class="form-control" name
="languageChoice" size
="1">
267 echo "<option selected='selected' value='" . attr($defaultLangID) . "'>" . xlt('Default') . " - " . xlt($defaultLangName) . "</option>\n";
268 foreach ($result3 as $iter) :
269 if ($GLOBALS['language_menu_showall']) {
270 if (!$GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
271 continue; // skip the dummy language
274 echo "<option value='" . attr($iter['lang_id']) . "'>" . text($iter['trans_lang_description']) . "</option>\n";
276 if (in_array($iter['lang_description'], $GLOBALS['language_menu_show'])) {
277 if (!$GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
278 continue; // skip the dummy language
281 echo "<option value='" . attr($iter['lang_id']) . "'>" . text($iter['trans_lang_description']) . "</option>\n";
288 <?php
endif; // End language menu block ?>
289 <?php
if ($GLOBALS['login_into_facility']) { // Begin facilities menu block ?>
290 <div
class="form-group">
291 <label
for="facility" class="text-right"><?php
echo xlt('Facility'); ?
>:</label
>
293 <select
class="form-control" name
="facility" size
="1">
294 <option value
="user_default"><?php
echo xlt('My default facility'); ?
></option
>
295 <?php
foreach ($facilities as $facility) { ?
>
296 <?php
if (!is_null($facilitySelected) && $facilitySelected == $facility['id']) { ?
>
297 <option value
="<?php echo attr($facility['id']);?>" selected
><?php
echo text($facility['name']);?
></option
>
299 <option value
="<?php echo attr($facility['id']);?>"><?php
echo text($facility['name']);?
></option
>
305 <?php
} // End facilities menu block ?>
306 <div
class="form-group oe-pull-away">
307 <button id
="login-button" type
="submit" class="btn btn-login btn-lg" onClick
="transmit_form(this)"><i
class="fa fa-sign-in-alt"></i
> 
; 
;<?php
echo xlt('Login');?
></button
>
309 <div
class="form-group">
310 <?php
if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) { ?
>
311 <input type
="hidden" id
="used-google-signin" name
="used_google_signin" value
="">
312 <input type
="hidden" id
="google-signin-token" name
="google_signin_token" value
="">
313 <div id
="google-signin" onclick
="return do_google_signin();">
314 <!-- This message is displayed
if the google platform API cannot render the button
-->
315 <span id
="google-signin-service-unreachable-alert" style
="display:none;"><?php
echo xlt('Google Sign-In is enabled but the service is unreachable.'); ?
></span
>
317 <div id
="google-signout">
318 <a href
="#" onclick
="signOut();"><?php
echo xlt('Sign out'); ?
></a
>
323 <div
class="<?php echo $logoarea; ?>">
324 <?php
$extraLogo = $GLOBALS['extra_logo_login']; ?
>
325 <?php
if ($extraLogo) { ?
>
326 <div
class="text-center">
327 <span
class="d-inline-block w-40"><?php
echo file_get_contents($GLOBALS['images_static_absolute'] . "/login-logo.svg"); ?
></span
>
328 <span
class="d-inline-block w-15 login-bg-text-color"><i
class="fas fa-plus fa-2x"></i
></span
>
329 <span
class="d-inline-block w-40"><?php
echo $logocode; ?
></span
>
332 <div
class="mx-auto m-4 w-75">
333 <?php
echo file_get_contents($GLOBALS['images_static_absolute'] . "/login-logo.svg"); ?
>
336 <div
class="text-center login-title-label">
337 <?php
if ($GLOBALS['show_label_login']) { ?
>
338 <?php
echo text($openemr_name); ?
>
342 // Figure out how to display the tiny logos
343 $t1 = $GLOBALS['tiny_logo_1'];
344 $t2 = $GLOBALS['tiny_logo_2'];
349 } if ($t1 && $t2) { ?
>
350 <div
class="row mb-3">
351 <div
class="col-sm-6"><?php
echo $tinylogocode1;?
></div
>
352 <div
class="col-sm-6"><?php
echo $tinylogocode2;?
></div
>
355 <p
class="text-center lead font-weight-normal login-bg-text-color"><?php
echo xlt('The most popular open-source Electronic Health Record and Medical Practice Management solution.'); ?
></p
>
356 <p
class="text-center small"><a href
="../../acknowledge_license_cert.html" class="login-bg-text-color" target
="main"><?php
echo xlt('Acknowledgments, Licensing and Certification'); ?
></a
></p
>
359 <div
class="product-registration-modal modal fade">
360 <div
class="modal-dialog modal-dialog-centered">
361 <div
class="modal-content">
362 <div
class="modal-header"></div
>
363 <div
class="modal-body">
364 <p
class="context"><?php
echo xlt("Register your installation with OEMR to receive important notifications, such as security fixes and new release announcements."); ?
></p
>
365 <input placeholder
="<?php echo xlt('email'); ?>" type
="email" class="email w-100 text-body form-control" />
366 <p
class="message font-italic"></p
>
368 <div
class="modal-footer">
369 <button type
="button" class="btn btn-secondary submit"><?php
echo xlt("Submit"); ?
></button
>
370 <button type
="button" class="btn btn-secondary nothanks"><?php
echo xlt("No Thanks"); ?
></button
>
378 <?php
if (!empty($GLOBALS['google_signin_enabled']) && !empty($GLOBALS['google_signin_client_id'])) { ?
>
379 <script type
="text/javascript">
381 // This variable controls whether we should login to OpenEMR
382 // so we only login if "Sign in with Google button" was clicked
383 let google_signin
= false;
385 // Hide the google signout link unless we are signed-in
386 // This isn't really ever displayed, because once we sign-in with google,
387 // we automatically log into the app
388 $
('#google-signout').hide();
390 // Click-handler for signin button
391 function do_google_signin() {
392 google_signin
= true;
395 // When Google sign-in successful, sign in to the app, but only
396 // if the button was clicked (otherwise we would automatically login)
397 function onSignInSuccess(googleUser
) {
398 if (google_signin
=== true) {
399 const auth_response
= googleUser
.getAuthResponse();
400 const id_token
= auth_response
.id_token
;
401 $
('.login-failure').hide();
402 $
('#used-google-signin').val(true);
403 $
('#google-signin-token').val(id_token
);
404 $
('#google-signout').show();
405 $
('#standard-auth-username, #standard-auth-password').hide();
406 var element
= document
.getElementById('login-button');
407 transmit_form(element
);
411 function onSignInFailure(error
) {
412 $
('.login-failure').show();
415 function renderButton() {
416 gapi
.signin2
.render('google-signin', {
417 'prompt': 'select_account',
418 'scope': 'profile email',
423 'onsuccess': onSignInSuccess
,
424 'onfailure': onSignInFailure
429 google_signin
= false;
430 const auth2
= gapi
.auth2
.getAuthInstance();
431 auth2
.signOut().then(function () {
432 $
('#used-google-signin').val('');
433 $
('#google-signin-token').val('');
434 $
('#google-signout').hide();
435 $
('#standard-auth-username, #standard-auth-password').show();
439 $
.getScript('https://apis.google.com/js/platform.js', function(data
, textStatus
, jqxh
) {
440 // When the auth2 library is loaded, log out so the user has to sign into google
441 gapi
.load('auth2', function() {
442 gapi
.auth2
.init().then(function () {
447 // Render the "Sign in with Google" button
449 }).fail(function (jqxhr
, settings
, exception
) {
450 $
('#google-signin-service-unreachable-alert').show();