regain constant pseudo-random in PHP 5.2 - php

I am including the same "random.inc" in foo.php and bar.php. For each, I want reproducible "random" results.
So in foo.php I always want one set of numbers and/or keywords. In bar.php another. Which shouldn't change on reload. That's what I mean by contant pseudo-random. And that's why I seeding on the url. However I still get different results for individual numbers as well as for array pickson every reload. This is the full php file:
<?
header('Content-Type: text/plain');
$seed = crc32( $_SERVER['REQUEST_URI'] );
echo "phpversion: ".phpversion()."\nseed: $seed\n";
srand( $seed ); // (seed verified to be contant as expected)
// neither single values nor array pics turn out deterministic
echo ''.rand(0,100).' '.rand(0,100).' '.rand(0,100)."\n";
$values = array( '0'=>21,'1'=>89,'2'=>96,'3'=>47,'4'=>88 );
print_r( array_rand( $values, 3 ) );
?>
In the days of PHP4.1 it was (verified) possible to achieve constant pseudo-random like this. array_rand API documentation describes as a feature that since 4.2 initialization happens automatically. Perhaps this is overriding any explicit seeding? (if so, perhaps explicit seeding should raise an internal PHP flag, preventing automatic seeding?). Btw: mt_srand() and srand() are equally not working.
I would really like to get my deterministic / constant pseudo-random back...
Update: Solution below (Windows and/or version 5.2 's fault)

Works for me (PHP/5.3.6):
<?php
$data = range(1, 100);
srand(1);
print_r(array_rand($data, 3));
... always prints:
Array
(
[0] => 21
[1] => 89
[2] => 95
)
... in my machine. Apparently, the exact numbers differ depending on the exact environment but they're reproducible.

Guys, you are all correct! (Sorry, I answer it myself now)
my web hoster runs 5.2.17 under Linux 2.6.36, and above problem exists.
under Win x64 5.3.0 everything works as expected.
So it's everyone's guess if that's an OS related bug and/or a PHP bug, fixed in 5.3.0.
Given that random constant seeding worked before, I am guessing they fixed in 5.3 the bug that came with the autoseed feature enhancement in 4.2. Anyway, Thanx again, at least there's clarity now.

The seeding functions are still available, and should still work; it's just since PHP 4.2 they are automatically seeded with the time on page load; but you can still call them to reset the random sequence to a known starting point.
[edit] I have just done a quick test program to make sure I wasn't imagining it!
mt_srand(50000);
print "rand="+mt_rand(0,10000);
Using PHP 5.2, this always results in the same value being printed (1749).
[EDIT]
As noted by #cwd and in the accepted answer to this question, there appears to be a discrepancy in PHP 5.2's behaviour with random number seeding between the Linux and Windows versions. In PHP 5.2 on Linux, the above technique does not appear to work.
Fortunately, the bug seems to have been fixed in PHP 5.3, so the solution to this problem is simply to upgrade. (PHP 5.2 is not supported any longer, so you should upgrade anyway)

Btw, if anyone else wants "constant windows-pre-5.3 pseudo-random" (of low quality, e.g. for stuff like SEO buzzwording) this is a tested workaround:
$r = abs(crc32($URL))%20; // a number between 0 and 19, based on URL

In PHP 5.2.17 and probably on all versions of PHP 5.2, (not sure about windows), we lose the capability of generating random numbers based on a seed as PHP changes the algorithm used for random numbers.
rand and mt_rand are "broken" not only because they will not give one random number, but they will also not give a same sequence of random numbers - even when using a seed!
At first the PHP developers tried to argue that this is the way that it "should" work, but we can guess they caught enough grief about the problem that they have reverted the way that it works with PHP 5.3.
See the php mt_rand page and the bug tracker to learn about this issue.

Related

perl unary ~ gives not the expected result

I'm trying to port a php algorithm to perl but I struggle with one bit operator I'm not familiar with...
so the php code looks like this:
...
$var = '348492634';
print ~$var;
...
result: -348492635
doing the exact same thing in perl:
...
$var = '348492634';
print ~$var;
...
result: 18446744073361058981
I read a lot about the integer size depending on the architecture of the cpu, but I never found a working solution. Maybe I'm just using the wrong function in perl...
It's necessary for the logic to get same result as in the php script.
Thanks in advance
Seems that on your setup, PHP ints are 32bit signed while perl ints are 64bit unsigned.
This will probably do what you need on the given system but it is not guaranteed to work the same if you use it on another installation of perl.
$var = '348492634'; #hex!
print ~($var - 2**32) - 2**32;
The following will do for both $var='348492634' (which you claim to have) and $var=348492634 (which you did have):
unpack('l', ~pack('l', $var))
The quick and dirty conversion is:
print -($var+1); # like ~$var in PHP
If your perl is using 64-bit integers, this will only fail for $var=-18446744073709551616
(0x8000000000000000), which is a value you wouldn't use in 32-bit PHP anyway.

PHP SHA3 functionality

Is there a framework or function that allows me to use SHA3-512?
I don't want a extension like Strawbrary
Yes sure simply you can use hash function in php
<?php
echo hash('sha3-512' , 'String you want to hash');
It's possible.
Maybe too late, but I've worked on a pure-PHP implementation here:
SHA3-224/256/384/512
SHAKE128/256 (arbitrary output size)
LGPL 3+
Works in PHP 5.2+ (considerably slower on older PHP)
No extensions required.
Moderately well tested.
Based on the (public domain) reference implementation in C.
Arbitrary input size.
It is a simple and fast implementation in PHP (which means far slower than C). Since this is purely "CPU-bound", PHP 7.0 runs 4x faster than PHP 5.6. (55kB/s here)
Fine with a small input. Correctly handles a huge input, just hogs CPU for minutes.
I hope it helps.
For those coming to this later (after this post) PHP 7.1.0 has support for SHA3-512.
Per the PHP Manual (http://php.net/manual/en/function.hash-algos.php) the hash_algos() function will output your system's available hash algorithms. The following code will output your system's available hash algorithms:
<?php
echo "<pre>";
print_r (hash_algos());
echo "</pre>";
?>
My output looks something like this:
Array
(
[0] => md2
[1] => md4
[2] => md5
...
)
PHP 5.3.2 added SHA-256 and SHA-512 to the crypt() function. This might be somewhat similar to what your looking for
http://us3.php.net/crypt

Memcached bug in PHP - binary protocol

I came across a bug using Memcached in PHP. Here's my piece of code:
<?php
$mc = new \Memcached();
$mc->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
$mc->addServer("127.0.0.1", 11211);
$mc->touch("key", time() + 600);
$touchResult = $mc->getResultCode();
$mc->set("key", 1, time() + 600);
$setResult = $mc->getResultCode();
echo "<pre>";
echo "Touch result: $touchResult\n";
echo "Set result: $setResult\n";
echo "</pre>";
When you run this for the first time, this is the output:
Touch result: 16
Set result: 0
And for the second time forth:
Touch result: 0
Set result: 5
Correct me if I'm wrong but this is a bug right? Does anyone know a workaround for this?
Here are the versions I use:
Ubuntu 12.04 64bit
PHP 5.3.14
memcached 2.1.0 (PECL module)
libmemcached 1.0.8
Memcached sever 1.4.13
PS. If you wonder what the result codes mean, here they are:
0 RES_SUCCESS
5 RES_WRITE_FAILURE
16 RES_NOTFOUND
[UPDATE]
I played a little more with the code and found something even more interesting. This bug happens regardless of the key that touch and set are working on. As long as the touch operation returns 0 (which means it was successful) the set operation will fail.
[UPDATE]
I managed to produce some other errors as well. e.g. acquiring some key from server and then adding some other will also lead to nasty problems (RES_END code). I believe all these problems are somehow related to binary protocol. It seems to me as if binary protocol's implementation is hardly near stable. Operations which can work without binary protocol will do just fine but once the protocol is set to binary, they will result in blocking problems.
All right.
In first time, you touch not existed key - result is RES_NOTFOUND. When you do set - you write value success - RES_SUCCESS.
In next time you touch existed key (you set it in first linch) and get result of operation RES_SUCCESS, next you try set value for existed key - result false. All right.
If you want change existing value you must use Memcached::replace() method instead of "set"

Php rand vs Perl rand

I am trying to port a piece of code from perl to php. The perl code snippet is part of akamai's video on demand link generation script. The script generates seed based on the location / URL of the video file (which will always be constant for a single URL). And then it is used in generating serial ID for stream (which is basically a random number between 1 and 2000 using the seed). Here is the perl code.$seed=6718;
srand($seed);
print(int(rand(1999)) + 1); // return 442 every time And the converted PHP code is:$seed=6718;
srand($seed);
echo(rand(0, 1999) + 1); //returns 155 every time
Does php rand behaves differently than perl one?
Yes. You can't depend on their algorithms being the same. For perl, which rand is used depends on what platform your perl was built for.
You may have more luck using a particular algorithm; for instance, Mersenne Twister looks to be available for both PHP and Perl.
Update: trying it produces different results, so that one at least won't do the trick.
Update 2: From the perl numbers you show, your perl is using the drand48 library; I don't know whether that's available for PHP at all, and google isn't helping.
[clippy]It looks like your trying to hash a number, maybe you want to use a hash function?[/clippy]
Hash functions are designed to take an input and produce a consistently repeatable value, that is in appearance random. As a bonus they often have cross language implementations.
Using srand() with rand() to get what is basically a hash value is a fairly bad idea. Different languages use different algorithms, some just use system libraries. Changing (or upgrading) the OS, standard C library, or language can result in wildly different results.
Using SHA1 to get a number between 1 and 2000 is a bit overkill, but you can at least be sure that you could port the code to nearly any language and still get the same result.
use Digest::SHA1;
# get a integer hash value from $in between $min (inclusive) and $max (exclusive)
sub get_int_hash {
my ($in, $min, $max) = #_;
# calculate the SHA1 of $in, note $in is converted to a string.
my $sha = Digest::SHA1->new;
$sha->add( "$in" );
my $digest = $sha->hexdigest;
# use the last 7 characters of the digest (28 bits) for an effective range of 0 - 268,435,455.
my $value = hex substr $digest, -7;
# scale and shift the value to the desired range.
my $out = int( $value / 0x10000000 * ( $max - $min ) ) + $min;
return $out;
}
print get_int_hash(6718, 1, 2000); #this should print 812 for any SHA1 implementation.
Just seeing this snippet of code it is impossible to say if it is the same.
At first you need to knew that even a random generator like the rand() function is not really random. It calculates a new value with a mathematical formula from the previous number. With the srand() function you can set the start value.
Calling srand() with the same argument each time means that the program always returns the same numbers in the same order.
If you really want random numbers, in Perl you should remove the initialization of srand(). Because Perl automatically sets srand() to a better (random) value when you first call the rand() function.
If your program really wants random numbers, then it should also be okay for PHP. But even in PHP i would look if srand() is automatically set and set to a more random value.
If your program don't work with random numbers and instead really want a stream of numbers that is always the same, then the snipet of code are probably not identical. Even if you do the same initialization with srand() it could be that PHP uses another formula to calculate the next "random" number.
So you need to look at your surrounding code if you code really wants random numbers, if yes you can use this code. But even then you should look for a better initialization for srand().

Broken Random PHP

I have been using mt_rand(10,100) to get a random number between 10 and 100 but it gives me 74 every time.
Heres what im working with
$success=mt_rand(10,100);
Any ideas ? Do i need to seed somehow ? Thanks in advance.
---EDIT---
I have just tried this
srand(microtime());
$success=rand(10,100);
Still gives same answer every time, 47.
---EDIT---
this is the whole thing
srand(microtime());
$success=rand(10,100);
echo $success;
if ($success == 100) {
$displayline="You succeeded";
session_register("displayline");
header("location:userhome.php");
}
What version of PHP are you running? In 4.2.0, mt_rand() was changed to be seeded automatically.
You can seed it with mt_srand($seed), providing a seed value. I use the output of the microtime() function.
edit: Since you are on 5.2, check your code to see if mt_srand() is being called and comment out all such calls.
That's odd. If you do just mt_rand() what do you get? What's the value for mt_getrandmax()?
Try seeding it with mt_srand()
It seeds on itself.
http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/
Guess you should check your PHP version
Remove all the seeding functions and don't add them back in. Then restart your server.
Also, I found this PHP bug, which occurs on Windows systems with some versions of the php.ini file.

Categories