GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — develop (#322)
by
unknown
01:52
created

password.php ➔ password_hash()   F

Complexity

Conditions 39
Paths 1105

Size

Total Lines 128
Code Lines 95

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 39
eloc 95
nc 1105
nop 3
dl 0
loc 128
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * A Compatibility library with PHP 5.5's simplified password hashing API.
4
 *
5
 * @author Anthony Ferrara <[email protected]>
6
 * @license http://www.opensource.org/licenses/mit-license.html MIT License
7
 * @copyright 2012 The Authors
8
 */
9
10
namespace {
11
12
    if (!defined('PASSWORD_BCRYPT')) {
13
        /**
14
         * PHPUnit Process isolation caches constants, but not function declarations.
15
         * So we need to check if the constants are defined separately from 
16
         * the functions to enable supporting process isolation in userland
17
         * code.
18
         */
19
        define('PASSWORD_BCRYPT', 1);
20
        define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
21
        define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
22
    }
23
24
    if (!function_exists('password_hash')) {
25
26
        /**
27
         * Hash the password using the specified algorithm
28
         *
29
         * @param string $password The password to hash
30
         * @param int    $algo     The algorithm to use (Defined by PASSWORD_* constants)
31
         * @param array  $options  The options for the algorithm to use
32
         *
33
         * @return string|false The hashed password, or false on error.
34
         */
35
        function password_hash($password, $algo, array $options = array()) {
36
            if (!function_exists('crypt')) {
37
                trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
38
                return null;
39
            }
40
            if (is_null($password) || is_int($password)) {
41
                $password = (string) $password;
42
            }
43
            if (!is_string($password)) {
44
                trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
45
                return null;
46
            }
47
            if (!is_int($algo)) {
48
                trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
49
                return null;
50
            }
51
            $resultLength = 0;
0 ignored issues
show
Unused Code introduced by
$resultLength is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
52
            switch ($algo) {
53
                case PASSWORD_BCRYPT:
54
                    $cost = PASSWORD_BCRYPT_DEFAULT_COST;
55
                    if (isset($options['cost'])) {
56
                        $cost = $options['cost'];
57
                        if ($cost < 4 || $cost > 31) {
58
                            trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
59
                            return null;
60
                        }
61
                    }
62
                    // The length of salt to generate
63
                    $raw_salt_len = 16;
64
                    // The length required in the final serialization
65
                    $required_salt_len = 22;
66
                    $hash_format = sprintf("$2y$%02d$", $cost);
67
                    // The expected length of the final crypt() output
68
                    $resultLength = 60;
69
                    break;
70
                default:
71
                    trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
72
                    return null;
73
            }
74
            $salt_requires_encoding = false;
75
            if (isset($options['salt'])) {
76
                switch (gettype($options['salt'])) {
77
                    case 'NULL':
78
                    case 'boolean':
79
                    case 'integer':
80
                    case 'double':
81
                    case 'string':
82
                        $salt = (string) $options['salt'];
83
                        break;
84
                    case 'object':
85
                        if (method_exists($options['salt'], '__tostring')) {
86
                            $salt = (string) $options['salt'];
87
                            break;
88
                        }
89
                    case 'array':
90
                    case 'resource':
91
                    default:
92
                        trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
93
                        return null;
94
                }
95
                if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
96
                    trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
97
                    return null;
98
                } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
99
                    $salt_requires_encoding = true;
100
                }
101
            } else {
102
                $buffer = '';
103
                $buffer_valid = false;
104
                if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
105
                    $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
106
                    if ($buffer) {
107
                        $buffer_valid = true;
108
                    }
109
                }
110
                if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
111
                    $buffer = openssl_random_pseudo_bytes($raw_salt_len);
112
                    if ($buffer) {
113
                        $buffer_valid = true;
114
                    }
115
                }
116
                if (!$buffer_valid && @is_readable('/dev/urandom')) {
117
                    $f = fopen('/dev/urandom', 'r');
118
                    $read = PasswordCompat\binary\_strlen($buffer);
119
                    while ($read < $raw_salt_len) {
120
                        $buffer .= fread($f, $raw_salt_len - $read);
121
                        $read = PasswordCompat\binary\_strlen($buffer);
122
                    }
123
                    fclose($f);
124
                    if ($read >= $raw_salt_len) {
125
                        $buffer_valid = true;
126
                    }
127
                }
128
                if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
129
                    $bl = PasswordCompat\binary\_strlen($buffer);
130
                    for ($i = 0; $i < $raw_salt_len; $i++) {
131
                        if ($i < $bl) {
132
                            $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
133
                        } else {
134
                            $buffer .= chr(mt_rand(0, 255));
135
                        }
136
                    }
137
                }
138
                $salt = $buffer;
139
                $salt_requires_encoding = true;
140
            }
141
            if ($salt_requires_encoding) {
142
                // encode string with the Base64 variant used by crypt
143
                $base64_digits =
144
                    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
145
                $bcrypt64_digits =
146
                    './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
147
148
                $base64_string = base64_encode($salt);
149
                $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
150
            }
151
            $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
152
153
            $hash = $hash_format . $salt;
154
155
            $ret = crypt($password, $hash);
156
157
            if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
158
                return false;
159
            }
160
161
            return $ret;
162
        }
163
164
        /**
165
         * Get information about the password hash. Returns an array of the information
166
         * that was used to generate the password hash.
167
         *
168
         * array(
169
         *    'algo' => 1,
170
         *    'algoName' => 'bcrypt',
171
         *    'options' => array(
172
         *        'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
173
         *    ),
174
         * )
175
         *
176
         * @param string $hash The password hash to extract info from
177
         *
178
         * @return array The array of information about the hash.
179
         */
180
        function password_get_info($hash) {
181
            $return = array(
182
                'algo' => 0,
183
                'algoName' => 'unknown',
184
                'options' => array(),
185
            );
186
            if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
187
                $return['algo'] = PASSWORD_BCRYPT;
188
                $return['algoName'] = 'bcrypt';
189
                list($cost) = sscanf($hash, "$2y$%d$");
190
                $return['options']['cost'] = $cost;
191
            }
192
            return $return;
193
        }
194
195
        /**
196
         * Determine if the password hash needs to be rehashed according to the options provided
197
         *
198
         * If the answer is true, after validating the password using password_verify, rehash it.
199
         *
200
         * @param string $hash    The hash to test
201
         * @param int    $algo    The algorithm used for new password hashes
202
         * @param array  $options The options array passed to password_hash
203
         *
204
         * @return boolean True if the password needs to be rehashed.
205
         */
206
        function password_needs_rehash($hash, $algo, array $options = array()) {
207
            $info = password_get_info($hash);
208
            if ($info['algo'] != $algo) {
209
                return true;
210
            }
211
            switch ($algo) {
212
                case PASSWORD_BCRYPT:
213
                    $cost = isset($options['cost']) ? $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
214
                    if ($cost != $info['options']['cost']) {
215
                        return true;
216
                    }
217
                    break;
218
            }
219
            return false;
220
        }
221
222
        /**
223
         * Verify a password against a hash using a timing attack resistant approach
224
         *
225
         * @param string $password The password to verify
226
         * @param string $hash     The hash to verify against
227
         *
228
         * @return boolean If the password matches the hash
229
         */
230
        function password_verify($password, $hash) {
231
            if (!function_exists('crypt')) {
232
                trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
233
                return false;
234
            }
235
            $ret = crypt($password, $hash);
236
            if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
237
                return false;
238
            }
239
240
            $status = 0;
241
            for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
242
                $status |= (ord($ret[$i]) ^ ord($hash[$i]));
243
            }
244
245
            return $status === 0;
246
        }
247
    }
248
249
}
250
251
namespace PasswordCompat\binary {
252
253
    if (!function_exists('PasswordCompat\\binary\\_strlen')) {
254
255
        /**
256
         * Count the number of bytes in a string
257
         *
258
         * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
259
         * In this case, strlen() will count the number of *characters* based on the internal encoding. A
260
         * sequence of bytes might be regarded as a single multibyte character.
261
         *
262
         * @param string $binary_string The input string
263
         *
264
         * @internal
265
         * @return int The number of bytes
266
         */
267
        function _strlen($binary_string) {
268
            if (function_exists('mb_strlen')) {
269
                return mb_strlen($binary_string, '8bit');
270
            }
271
            return strlen($binary_string);
272
        }
273
274
        /**
275
         * Get a substring based on byte limits
276
         *
277
         * @see _strlen()
278
         *
279
         * @param string $binary_string The input string
280
         * @param int    $start
281
         * @param int    $length
282
         *
283
         * @internal
284
         * @return string The substring
285
         */
286
        function _substr($binary_string, $start, $length) {
287
            if (function_exists('mb_substr')) {
288
                return mb_substr($binary_string, $start, $length, '8bit');
289
            }
290
            return substr($binary_string, $start, $length);
291
        }
292
293
        /**
294
         * Check if current PHP version is compatible with the library
295
         *
296
         * @return boolean the check result
297
         */
298
        function check() {
299
            static $pass = NULL;
300
301
            if (is_null($pass)) {
302
                if (function_exists('crypt')) {
303
                    $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
304
                    $test = crypt("password", $hash);
305
                    $pass = $test == $hash;
306
                } else {
307
                    $pass = false;
308
                }
309
            }
310
            return $pass;
311
        }
312
313
    }
314
}