App::run()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.2
c 0
b 0
f 0
cc 4
eloc 5
nc 3
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 14 and the first side effect is on line 6.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
namespace demo\browser;
4
5
//import composer autoload file
6
require_once dirname(__DIR__) . implode(DIRECTORY_SEPARATOR, ['.', '..', 'vendor', 'autoload.php']);
7
8
use PassGenerator\Generator;
9
10
/**
11
 * @author Lachezar Mihaylov <[email protected]>
12
 * @license https://github.com/lmihaylov2512/pass-generator/blob/master/LICENSE.md MIT License
13
 */
14
class App
15
{
16
    /**
17
     * @var integer whether the app is in debug mode
18
     */
19
    const DEBUG_MODE = 0;
20
    
21
    /**
22
     * @var array options with title and description
23
     */
24
    protected static $options = [
25
        'upperCase' => [
26
            'title' => 'upper case',
27
            'desc' => 'use alphabet upper letters [A-Z]',
28
        ],
29
        'lowerCase' => [
30
            'title' => 'lower case',
31
            'desc' => 'use alphabet lower letters [a-z]',
32
        ],
33
        'digits' => [
34
            'title' => 'digits',
35
            'desc' => 'all numbers [0-9]',
36
        ],
37
        'special' => [
38
            'title' => 'special',
39
            'desc' => 'special symbols ~, !, @, #, ...'
40
        ],
41
        'brackets' => [
42
            'title' => 'brackets',
43
            'desc' => 'all kind of brackets (, ), {, }, [, ]',
44
        ],
45
        'minus' => [
46
            'title' => 'minus',
47
            'desc' => 'minus sign -',
48
        ],
49
        'underline' => [
50
            'title' => 'underline',
51
            'desc' => 'underline sign _',
52
        ],
53
        'space' => [
54
            'title' => 'space',
55
            'desc' => 'space character \' \'',
56
        ],
57
    ];
58
    /**
59
     * @var Generator password generator instance
60
     */
61
    protected static $generator;
62
    
63
    /**
64
     * Check whether the current request is ajax.
65
     * 
66
     * @return boolean the result from checking
67
     */
68
    public static function isAjaxRequest()
0 ignored issues
show
Coding Style introduced by
isAjaxRequest uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
69
    {
70
        return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
71
    }
72
    
73
    /**
74
     * Return post variable, if exists, or specific default value.
75
     * 
76
     * @param mixed $default default value, if post doesn't exist
77
     * @return mixed
78
     */
79
    public static function getPost($default = null)
0 ignored issues
show
Coding Style introduced by
getPost uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
80
    {
81
        return isset($_POST) ? $_POST : $default;
82
    }
83
    
84
    /**
85
     * Get all options array.
86
     * 
87
     * @return array options array
88
     */
89
    public static function getOptions()
90
    {
91
        return static::$options;
92
    }
93
    
94
    /**
95
     * Create password generator, if necessary and return it.
96
     * 
97
     * @return Generator password generator instance
98
     */
99
    public static function getGenerator()
100
    {
101
        if (static::$generator === null) {
102
            static::$generator = new Generator();
103
        }
104
        return static::$generator;
105
    }
106
    
107
    /**
108
     * If is ajax request and post exists, generate password and cancel script execution.
109
     * 
110
     * @return string|null if is ajax request, returns the generated password
111
     */
112
    public static function run()
113
    {
114
        if (static::isAjaxRequest() && ($data = static::getPost()) !== null) {
115
            foreach ($data as $option => $value) {
116
                static::getGenerator()->$option = $value;
117
            }
118
            
119
            return static::getGenerator()->generate();
120
        }
121
    }
122
}
123
124
//run the app
125
if (($password = App::run()) !== null) {
126
    die($password);
127
}
128
129
?>
130
<!DOCTYPE html>
131
<html>
132
<head>
133
    <meta charset="utf-8" />
134
    <meta name="viewport" content="width=device-width, initial-scale=1" />
135
    <title>Demo password generator</title>
136
    <link href="./assets/bootstrap/css/<?= App::DEBUG_MODE ? 'bootstrap.css' : 'bootstrap.min.css' ?>" rel="stylesheet" />
137
    <style>.margin-top-20{margin-top:20px}.loader{border:4px solid #eee;border-top:4px solid #337ab7;border-radius:50%;width:32px;height:32px;animation:spin 2s linear infinite;display:inline-block;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style>
138
</head>
139
<body>
140
    <nav class="navbar navbar-default">
141
        <div class="container-fluid">
142
            <div class="navbar-header">
143
                <a href="https://packagist.org/packages/lmihaylov/pass-generator" class="navbar-brand" target="_blank">Pass-Generator</a>
144
            </div>
145
        </div>
146
    </nav>
147
    <div class="container">
148
        <div class="row">
149
            <div class="col-lg-8 col-lg-offset-2">
150
                <div class="panel panel-default">
151
                    <div class="panel-body">
152
                        <div class="row">
153
                            <div class="col-lg-12">
154
                                <div class="input-group">
155
                                    <span class="input-group-addon">Password length</span>
156
                                    <input type="text" class="form-control" placeholder="Password length" value="<?= App::getGenerator()->length ?>" id="input-length">
157
                                    <span class="input-group-btn">
158
                                        <button class="btn btn-primary" type="button" id="btn-generate">Generate</button>
159
                                    </span>
160
                                </div>
161
                                <div id="password-output" class="well lead hide margin-top-20"></div>
162
                                <div class="list-group margin-top-20">
163
                                    <?php foreach (App::getOptions() as $group => $option): ?>
164
                                    <a href="#" class="list-group-item<?= App::getGenerator()->$group ? ' active' : '' ?>" data-option="<?= $group ?>">
165
                                        <h4 class="list-group-item-heading"><span class="glyphicon glyphicon-<?= App::getGenerator()->$group ? 'ok' : 'remove' ?>" aria-hidden="true"></span> <?= $option['title'] ?></h4>
166
                                        <p class="list-group-item-text"><?= $option['desc'] ?></p>
167
                                    </a>
168
                                    <?php endforeach; ?>
169
                                </div>
170
                            </div>
171
                        </div>
172
                    </div>
173
                </div>
174
            </div>
175
        </div>
176
    </div>
177
    <script src="./assets/jquery/<?= App::DEBUG_MODE ? 'jquery.js' : 'jquery.min.js' ?>"></script>
178
    <script>
179
        (function (w, d, $) {
180
            //attach click event handler on list elements
181
            $('.list-group > a').on('click', function (e) {
182
                e.preventDefault();
183
                var isActive = $(this).hasClass('active');
184
                
185
                if (isActive) {
186
                    $(this).toggleClass('active').find('span.glyphicon').removeClass('glyphicon-ok').addClass('glyphicon-remove');
187
                } else {
188
                    $(this).toggleClass('active').find('span.glyphicon').removeClass('glyphicon-remove').addClass('glyphicon-ok');
189
                }
190
            });
191
192
            //attach event handler on generate button for generating a new password string
193
            $('#btn-generate').on('click', function (e) {
194
                var data = { length: $('#input-length').val() };
195
196
                //prepare request data
197
                $('#password-output').html('<span class="loader"></span> Generating...').removeClass('hide');
198
                $('.list-group-item').each(function () {
199
                    data[$(this).data('option')] = $(this).hasClass('active') ? '1' : '';
200
                });
201
                
202
                $.ajax({
203
                    type: 'POST',
204
                    data: data,
205
                    success: function (res) {
206
                        $('#password-output').html(res === '' ? 'Please choose the at least one or more symbols types' : res);
207
                    }
208
                });
209
            });
210
        })(window, document, jQuery);
211
    </script>
212
</body>
213
</html>
214