3v4l.org

run code in 300+ PHP versions simultaneously
<?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\Stdlib { use Traversable; /** * Utility class for testing and manipulation of PHP arrays. * * Declared abstract, as we have no need for instantiation. */ abstract class ArrayUtils { /** * Test whether an array contains one or more string keys * * @param mixed $value * @param bool $allowEmpty Should an empty array() return true * @return bool */ public static function hasStringKeys($value, $allowEmpty = false) { if (!is_array($value)) { return false; } if (!$value) { return $allowEmpty; } return count(array_filter(array_keys($value), 'is_string')) > 0; } /** * Test whether an array contains one or more integer keys * * @param mixed $value * @param bool $allowEmpty Should an empty array() return true * @return bool */ public static function hasIntegerKeys($value, $allowEmpty = false) { if (!is_array($value)) { return false; } if (!$value) { return $allowEmpty; } return count(array_filter(array_keys($value), 'is_int')) > 0; } /** * Test whether an array contains one or more numeric keys. * * A numeric key can be one of the following: * - an integer 1, * - a string with a number '20' * - a string with negative number: '-1000' * - a float: 2.2120, -78.150999 * - a string with float: '4000.99999', '-10.10' * * @param mixed $value * @param bool $allowEmpty Should an empty array() return true * @return bool */ public static function hasNumericKeys($value, $allowEmpty = false) { if (!is_array($value)) { return false; } if (!$value) { return $allowEmpty; } return count(array_filter(array_keys($value), 'is_numeric')) > 0; } /** * Test whether an array is a list * * A list is a collection of values assigned to continuous integer keys * starting at 0 and ending at count() - 1. * * For example: * <code> * $list = array('a', 'b', 'c', 'd'); * $list = array( * 0 => 'foo', * 1 => 'bar', * 2 => array('foo' => 'baz'), * ); * </code> * * @param mixed $value * @param bool $allowEmpty Is an empty list a valid list? * @return bool */ public static function isList($value, $allowEmpty = false) { if (!is_array($value)) { return false; } if (!$value) { return $allowEmpty; } return (array_values($value) === $value); } /** * Test whether an array is a hash table. * * An array is a hash table if: * * 1. Contains one or more non-integer keys, or * 2. Integer keys are non-continuous or misaligned (not starting with 0) * * For example: * <code> * $hash = array( * 'foo' => 15, * 'bar' => false, * ); * $hash = array( * 1995 => 'Birth of PHP', * 2009 => 'PHP 5.3.0', * 2012 => 'PHP 5.4.0', * ); * $hash = array( * 'formElement, * 'options' => array( 'debug' => true ), * ); * </code> * * @param mixed $value * @param bool $allowEmpty Is an empty array() a valid hash table? * @return bool */ public static function isHashTable($value, $allowEmpty = false) { if (!is_array($value)) { return false; } if (!$value) { return $allowEmpty; } return (array_values($value) !== $value); } /** * Checks if a value exists in an array. * * Due to "foo" == 0 === TRUE with in_array when strict = false, an option * has been added to prevent this. When $strict = 0/false, the most secure * non-strict check is implemented. if $strict = -1, the default in_array * non-strict behaviour is used. * * @param mixed $needle * @param array $haystack * @param int|bool $strict * @return bool */ public static function inArray($needle, array $haystack, $strict = false) { if (!$strict) { if (is_int($needle) || is_float($needle)) { $needle = (string) $needle; } if (is_string($needle)) { foreach ($haystack as &$h) { if (is_int($h) || is_float($h)) { $h = (string) $h; } } } } return in_array($needle, $haystack, $strict); } /** * Convert an iterator to an array. * * Converts an iterator to an array. The $recursive flag, on by default, * hints whether or not you want to do so recursively. * * @param array|Traversable $iterator The array or Traversable object to convert * @param bool $recursive Recursively check all nested structures * @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object * @return array */ public static function iteratorToArray($iterator, $recursive = true) { if (!is_array($iterator) && !$iterator instanceof Traversable) { throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object'); } if (!$recursive) { if (is_array($iterator)) { return $iterator; } return iterator_to_array($iterator); } if (method_exists($iterator, 'toArray')) { return $iterator->toArray(); } $array = array(); foreach ($iterator as $key => $value) { if (is_scalar($value)) { $array[$key] = $value; continue; } if ($value instanceof Traversable) { $array[$key] = static::iteratorToArray($value, $recursive); continue; } if (is_array($value)) { $array[$key] = static::iteratorToArray($value, $recursive); continue; } $array[$key] = $value; } return $array; } /** * Merge two arrays together. * * If an integer key exists in both arrays, the value from the second array * will be appended the the first array. If both values are arrays, they * are merged together, else the value of the second array overwrites the * one of the first array. * * @param array $a * @param array $b * @return array */ public static function merge(array $a, array $b) { foreach ($b as $key => $value) { if (array_key_exists($key, $a)) { if (is_int($key)) { $a[] = $value; } elseif (is_array($value) && is_array($a[$key])) { $a[$key] = static::merge($a[$key], $value); } else { $a[$key] = $value; } } else { $a[$key] = $value; } } return $a; } } } namespace Zend\Crypt\Password { interface PasswordInterface { /** * Create a password hash for a given plain text password * * @param string $password The password to hash * @return string The formatted password hash */ public function create($password); /** * Verify a password hash against a given plain text password * * @param string $password The password to hash * @param string $hash The supplied hash to validate * @return bool Does the password validate against the hash */ public function verify($password, $hash); } } /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\Math { class Exception\RuntimeException extends \Exception {} use RandomLib; /** * Pseudorandom number generator (PRNG) */ abstract class Rand { /** * Alternative random byte generator using RandomLib * * @var RandomLib\Generator */ protected static $generator = null; /** * Generate random bytes using OpenSSL or Mcrypt and mt_rand() as fallback * * @param int $length * @param bool $strong true if you need a strong random generator (cryptography) * @return string * @throws Exception\RuntimeException */ public static function getBytes($length, $strong = false) { if ($length <= 0) { return false; } $bytes = ''; if (function_exists('openssl_random_pseudo_bytes') && (version_compare(PHP_VERSION, '5.3.4') >= 0 || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') ) { $bytes = openssl_random_pseudo_bytes($length, $usable); if (true === $usable) { return $bytes; } } if (function_exists('mcrypt_create_iv') && (version_compare(PHP_VERSION, '5.3.7') >= 0 || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') ) { $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); if ($bytes !== false && strlen($bytes) === $length) { return $bytes; } } $checkAlternatives = (file_exists('/dev/urandom') && is_readable('/dev/urandom')) || class_exists('\\COM', false); if (true === $strong && false === $checkAlternatives) { throw new Exception\RuntimeException ( 'This PHP environment doesn\'t support secure random number generation. ' . 'Please consider installing the OpenSSL and/or Mcrypt extensions' ); } $generator = self::getAlternativeGenerator(); return $generator->generate($length); } /** * Retrieve a fallback/alternative RNG generator * * @return RandomLib\Generator */ public static function getAlternativeGenerator() { if (!is_null(static::$generator)) { return static::$generator; } if (!class_exists('RandomLib\\Factory')) { throw new Exception\RuntimeException( 'The RandomLib fallback pseudorandom number generator (PRNG) ' . ' must be installed in the absence of the OpenSSL and ' . 'Mcrypt extensions' ); } $factory = new RandomLib\Factory; $factory->registerSource( 'HashTiming', 'Zend\Math\Source\HashTiming' ); static::$generator = $factory->getMediumStrengthGenerator(); return static::$generator; } /** * Generate random boolean * * @param bool $strong true if you need a strong random generator (cryptography) * @return bool */ public static function getBoolean($strong = false) { $byte = static::getBytes(1, $strong); return (bool) (ord($byte) % 2); } /** * Generate a random integer between $min and $max * * @param int $min * @param int $max * @param bool $strong true if you need a strong random generator (cryptography) * @return int * @throws Exception\DomainException */ public static function getInteger($min, $max, $strong = false) { if ($min > $max) { throw new Exception\DomainException( 'The min parameter must be lower than max parameter' ); } $range = $max - $min; if ($range == 0) { return $max; } elseif ($range > PHP_INT_MAX || is_float($range)) { throw new Exception\DomainException( 'The supplied range is too great to generate' ); } $log = log($range, 2); $bytes = (int) ($log / 8) + 1; $bits = (int) $log + 1; $filter = (int) (1 << $bits) - 1; do { $rnd = hexdec(bin2hex(self::getBytes($bytes, $strong))); $rnd = $rnd & $filter; } while ($rnd > $range); return ($min + $rnd); } /** * Generate random float (0..1) * This function generates floats with platform-dependent precision * * PHP uses double precision floating-point format (64-bit) which has * 52-bits of significand precision. We gather 7 bytes of random data, * and we fix the exponent to the bias (1023). In this way we generate * a float of 1.mantissa. * * @param bool $strong true if you need a strong random generator (cryptography) * @return float */ public static function getFloat($strong = false) { $bytes = static::getBytes(7, $strong); $bytes[6] = $bytes[6] | chr(0xF0); $bytes .= chr(63); // exponent bias (1023) list(, $float) = unpack('d', $bytes); return ($float - 1); } /** * Generate a random string of specified length. * * Uses supplied character list for generating the new string. * If no character list provided - uses Base 64 character set. * * @param int $length * @param string|null $charlist * @param bool $strong true if you need a strong random generator (cryptography) * @return string * @throws Exception\DomainException */ public static function getString($length, $charlist = null, $strong = false) { if ($length < 1) { throw new Exception\DomainException('Length should be >= 1'); } // charlist is empty or not provided if (empty($charlist)) { $numBytes = ceil($length * 0.75); $bytes = static::getBytes($numBytes, $strong); return substr(rtrim(base64_encode($bytes), '='), 0, $length); } $listLen = strlen($charlist); if ($listLen == 1) { return str_repeat($charlist, $length); } $bytes = static::getBytes($length, $strong); $pos = 0; $result = ''; for ($i = 0; $i < $length; $i++) { $pos = ($pos + ord($bytes[$i])) % $listLen; $result .= $charlist[$pos]; } return $result; } } } /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\Crypt\Password { use Traversable; use Zend\Math\Rand; use Zend\Stdlib\ArrayUtils; /** * Bcrypt algorithm using crypt() function of PHP */ class Bcrypt implements PasswordInterface { const MIN_SALT_SIZE = 16; /** * @var string */ protected $cost = '14'; /** * @var string */ protected $salt; /** * @var bool */ protected $backwardCompatibility = false; /** * Constructor * * @param array|Traversable $options * @throws Exception\InvalidArgumentException */ public function __construct($options = array()) { if (!empty($options)) { if ($options instanceof Traversable) { $options = ArrayUtils::iteratorToArray($options); } elseif (!is_array($options)) { throw new Exception\InvalidArgumentException( 'The options parameter must be an array or a Traversable' ); } foreach ($options as $key => $value) { switch (strtolower($key)) { case 'salt': $this->setSalt($value); break; case 'cost': $this->setCost($value); break; } } } } /** * Bcrypt * * @param string $password * @throws Exception\RuntimeException * @return string */ public function create($password) { if (empty($this->salt)) { $salt = Rand::getBytes(self::MIN_SALT_SIZE); } else { $salt = $this->salt; } $salt64 = substr(str_replace('+', '.', base64_encode($salt)), 0, 22); /** * Check for security flaw in the bcrypt implementation used by crypt() * @see http://php.net/security/crypt_blowfish.php */ if ((version_compare(PHP_VERSION, '5.3.7') >= 0) && !$this->backwardCompatibility) { $prefix = '$2y$'; } else { $prefix = '$2a$'; // check if the password contains 8-bit character if (preg_match('/[\x80-\xFF]/', $password)) { throw new Exception\RuntimeException( 'The bcrypt implementation used by PHP can contain a security flaw ' . 'using password with 8-bit character. ' . 'We suggest to upgrade to PHP 5.3.7+ or use passwords with only 7-bit characters' ); } } $hash = crypt($password, $prefix . $this->cost . '$' . $salt64); if (strlen($hash) < 13) { throw new Exception\RuntimeException('Error during the bcrypt generation'); } return $hash; } /** * Verify if a password is correct against an hash value * * @param string $password * @param string $hash * @throws Exception\RuntimeException when the hash is unable to be processed * @return bool */ public function verify($password, $hash) { $result = crypt($password, $hash); if ($result === $hash) { return true; } if (strlen($result) <= 13) { /* This should only happen if the algorithm that generated hash is * either unsupported by this version of crypt(), or is invalid. * * An example of when this can happen, is if you generate * non-backwards-compatible hashes on 5.3.7+, and then try to verify * them on < 5.3.7. * * This is needed, because version comparisons are not possible due * to back-ported functionality by some distributions. */ throw new Exception\RuntimeException( 'The supplied password hash could not be verified. Please check ' . 'backwards compatibility settings.' ); } return false; } /** * Set the cost parameter * * @param int|string $cost * @throws Exception\InvalidArgumentException * @return Bcrypt */ public function setCost($cost) { if (!empty($cost)) { $cost = (int) $cost; if ($cost < 4 || $cost > 31) { throw new Exception\InvalidArgumentException( 'The cost parameter of bcrypt must be in range 04-31' ); } $this->cost = sprintf('%1$02d', $cost); } return $this; } /** * Get the cost parameter * * @return string */ public function getCost() { return $this->cost; } /** * Set the salt value * * @param string $salt * @throws Exception\InvalidArgumentException * @return Bcrypt */ public function setSalt($salt) { if (strlen($salt) < self::MIN_SALT_SIZE) { throw new Exception\InvalidArgumentException( 'The length of the salt must be at least ' . self::MIN_SALT_SIZE . ' bytes' ); } $this->salt = $salt; return $this; } /** * Get the salt value * * @return string */ public function getSalt() { return $this->salt; } /** * Set the backward compatibility $2a$ instead of $2y$ for PHP 5.3.7+ * * @param bool $value * @return Bcrypt */ public function setBackwardCompatibility($value) { $this->backwardCompatibility = (bool) $value; return $this; } /** * Get the backward compatibility * * @return bool */ public function getBackwardCompatibility() { return $this->backwardCompatibility; } } } namespace MyStuff { try { $key = '123456'; echo "{$key}<br />"; $crypt = new \Zend\Crypt\Password\Bcrypt(); $crypt->setCost(14); $hash = $crypt->create($key); echo "{$hash}<br />"; var_dump($crypt->verify($key, $hash)); } catch (\Exception $e) { echo $e->getMessage(); } }

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
5.4.390.0200.05018.80
5.4.380.0180.05018.80
5.4.370.0170.05718.74
5.4.360.0200.05518.76
5.4.350.0270.04318.67
5.4.340.0150.05218.63
5.4.320.0120.04615.68
5.4.310.0160.04215.54
5.4.300.0110.04515.71
5.4.290.0140.04315.71
5.4.280.0150.04815.61
5.4.270.0100.04815.62
5.4.260.0130.04615.47
5.4.250.0120.05215.63
5.4.240.0120.05114.50
5.4.230.0110.04214.54
5.4.220.0100.04714.55
5.4.210.0130.04514.55
5.4.200.0080.05213.82
5.4.190.0090.04714.47
5.4.180.0120.04414.55
5.4.170.0130.04414.54
5.4.160.0120.04014.54
5.4.150.0150.04214.44
5.4.140.0140.03913.50
5.4.130.0110.04213.49
5.4.120.0140.04713.48
5.4.110.0140.04413.53
5.4.100.0150.04213.49
5.4.90.0090.04513.45
5.4.80.0090.04913.48
5.4.70.0170.04313.45
5.4.60.0060.04313.47
5.4.50.0090.04113.53
5.4.40.0100.04813.51
5.4.30.0110.04513.50
5.4.20.0110.04913.46
5.4.10.0110.04413.47
5.4.00.0110.04012.91
5.3.290.0100.04913.80
5.3.280.0100.04713.38
5.3.270.0110.04613.38
5.3.260.0130.04513.45
5.3.250.0150.04113.39
5.3.240.0130.04413.42
5.3.230.0110.04313.41
5.3.220.0120.05113.34
5.3.210.0140.05513.38
5.3.200.0080.04913.33
5.3.190.0120.04513.37
5.3.180.0100.04313.35
5.3.170.0090.04813.34
5.3.160.0130.03913.34
5.3.150.0120.04613.38
5.3.140.0110.04513.33
5.3.130.0080.05113.32
5.3.120.0100.05113.39
5.3.110.0060.05613.38
5.3.100.0080.04712.81
5.3.90.0080.04812.86
5.3.80.0160.03712.78
5.3.70.0120.04612.81
5.3.60.0130.03912.82
5.3.50.0120.04212.71
5.3.40.0140.04712.75
5.3.30.0110.04112.74
5.3.20.0110.04112.46
5.3.10.0130.03612.41
5.3.00.0110.04312.43

preferences:
140.17 ms | 1394 KiB | 7 Q