/ src / views / helpers / PasswordrequirementsHelper.php
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\views\helpers;

use seekquarry\yioop\configs as C;

/**
 * Draws the "what makes an acceptable password" hint that sits next to a
 * password box on the account forms. It writes out the current rules from
 * the Security activity (the smallest length, whichever of lower-case,
 * upper-case, digit, and symbol the administrator turned on, and the
 * characters that are never allowed) both as a sentence a person can read
 * and as plain data attributes the shared register_validator.js script
 * reads. When the browser runs JavaScript that script replaces the
 * sentence with live colored feedback: green once the password meets every
 * rule, or red naming just the requirements still missing; it also stops
 * the form being submitted with an unacceptable password. When JavaScript
 * is off the sentence simply stays visible so the person still knows the
 * requirements.
 *
 * @author Chris Pollett
 */
class PasswordrequirementsHelper extends Helper
{
    /**
     * Draws the password-rule hint inline, meant to sit just after a
     * password box, together with the data attributes basic.js needs to
     * check that box.
     *
     * @param string $field_id the id of the password input these rules
     *      apply to
     * @param bool $gate whether register_validator.js should block the form
     *      from being submitted while this password breaks the rules; pass
     *      false on a form that already blocks its own submit button
     * @return void echoes the hint directly into the page
     */
    public function render($field_id, $gate = true)
    {
        $min_phrase = tl('passwordrequirements_helper_min',
            C\p('PASSWORD_MIN_LEN'));
        $short_phrase = tl('passwordrequirements_helper_short');
        $lower_phrase = C\p('PASSWORD_REQUIRE_LOWERCASE') ?
            tl('passwordrequirements_helper_lowercase') : "";
        $upper_phrase = C\p('PASSWORD_REQUIRE_UPPERCASE') ?
            tl('passwordrequirements_helper_uppercase') : "";
        $digit_phrase = C\p('PASSWORD_REQUIRE_DIGIT') ?
            tl('passwordrequirements_helper_digit') : "";
        $symbol_phrase = C\p('PASSWORD_REQUIRE_SYMBOL') ?
            tl('passwordrequirements_helper_symbol') : "";
        $forbidden_phrase = (C\PASSWORD_FORBIDDEN_CHARS !== "") ?
            tl('passwordrequirements_helper_forbidden') : "";
        $parts = [$min_phrase];
        foreach ([$lower_phrase, $upper_phrase, $digit_phrase,
            $symbol_phrase, $forbidden_phrase] as $phrase) {
            if ($phrase !== "") {
                $parts[] = $phrase;
            }
        }
        $sentence = tl('passwordrequirements_helper_intro') . " " .
            implode(", ", $parts) . ".";
        $ok_phrase = tl('passwordrequirements_helper_ok');
        $forbidden_codes = [];
        $forbidden = C\PASSWORD_FORBIDDEN_CHARS;
        $length = strlen($forbidden);
        for ($index = 0; $index < $length; $index++) {
            $forbidden_codes[] = ord($forbidden[$index]);
        }
        $forbidden_attribute = implode(" ", $forbidden_codes);
        $gate_flag = $gate ? "1" : "0";
        ?><span class="password-requirements"
            data-pw-field="<?= $field_id ?>"
            data-pw-min="<?= (int)C\p('PASSWORD_MIN_LEN') ?>"
            data-pw-max="<?= (int)C\LONG_NAME_LEN ?>"
            data-pw-lower="<?= C\p('PASSWORD_REQUIRE_LOWERCASE') ? "1" : "0" ?>"
            data-pw-upper="<?= C\p('PASSWORD_REQUIRE_UPPERCASE') ? "1" : "0" ?>"
            data-pw-digit="<?= C\p('PASSWORD_REQUIRE_DIGIT') ? "1" : "0" ?>"
            data-pw-symbol="<?= C\p('PASSWORD_REQUIRE_SYMBOL') ? "1" : "0" ?>"
            data-pw-forbidden="<?= $forbidden_attribute ?>"
            data-pw-gate="<?= $gate_flag ?>"
            data-pw-ok="<?php e($ok_phrase) ?>"
            data-pw-phrase-short="<?php e($short_phrase) ?>"
            data-pw-phrase-lower="<?php e($lower_phrase) ?>"
            data-pw-phrase-upper="<?php e($upper_phrase) ?>"
            data-pw-phrase-digit="<?php e($digit_phrase) ?>"
            data-pw-phrase-symbol="<?php e($symbol_phrase) ?>"
            data-pw-phrase-forbidden="<?php e($forbidden_phrase) ?>"><span
            class="green password-requirements-text"><?php
            e($sentence) ?></span></span><?php
    }
}
X