PHP array_rand weird behaviour - php

I was trying to create a simple password generator and noted that array_rand() returns the same results. Here is the code:
<?php
function generatePass() {
$password = '';
$a = explode(' ', 'q w e r t y u i o p a s d f g h j k l z x c v b n m');
for($i=0; $i < rand(1,200); $i++) {
$password .= $a[array_rand($a)];
}
return $password;
}
$r = 0;
while ($r <= 10000) { #generating 10 000 passwords
$total[] = generatePass();
$r++;
}
echo '<pre>';
print_r($total);
echo '</pre>';
?>
The $total array basically contains the same results repeated over and over again; if I refresh the page, only the order of elements changes, and not their values.
The question is: is this an expected behaviour or am I doing something wrong?
Thak you for your attention.

Reseed the random number generator with srand() just prior to calling array_rand.
srand();
$password .= $a[array_rand($a)];

I think it should be your PHP version. I just copied your code into my localhost server and it worked fine. I'm using PHP 5.5.9-1ubuntu4.7, you should try it or a newer version.
By the way, if you can't update your PHP version, use this modified version of your code:
<?php
function generatePass() {
$password = '';
// Put all letters into an array.
$letters = array('q','w','e','r','t','y','u','i','o','p','a','s','d','f','g','h','j','k','l','z','x','c','v','b','n','m');
for($i=0; $i < rand(1,200); $i++) {
// Select a random letter with rand() command inside the brackets of the array.
$password .= $letters[rand(0,25)];
}
return $password;
}
$r = 0;
while ($r <= 10000) { #generating 10 000 passwords
$total[] = generatePass();
$r++;
}
echo '<pre>';
print_r($total);
echo '</pre>';
?>

Seeding the random generator isn't needed since version 4.2.0
Try using mt_rand() for a better generation.
http://php.net/manual/en/function.mt-rand.php
Edit:
I think you actually want
$a = explode(' ', 'q w e r t y u i o p a s d f g h j k l z x c v b n m');
$end = mt_rand(1,200);
$password = '';
for($i=0; $i < $end; $i++) {
$password .= $a[array_rand($a)];
}

I took the time for you and wrote the generator.
I got it to generate 10000 unique passwords and code is efficient:
<?php
function generatePass() {
$password = '';
$lib = 'q w e r t y u i o p a s d f g h j k l z x c v b n m';
$a = explode(' ', $lib);
//remove random char
for($i=0; $i < mt_rand(1,49); $i++) {
shuffle($a);
//get Random Char
$password .= $a[mt_rand(0,count($a)-1)];
}
return $password;
}
$len = 10000; // total number of numbers
$range = array();
foreach(range(0, $len - 1) as $i){
while(in_array($num = generatePass(), $range)){}
$range[] = $num;
}
echo '<pre>';
print_r($range);
echo '</pre>';

Related

Explode string by one or more spaces and new lines

How can I explode a string by one or more spaces or tabs?
Example:
A B C
D E F
G H I
J K L
M N O
I have successfully tokenize on spaces and tab's with this code:
$parts = preg_split('/\s+/', $str);
but the issue rises when there is new line.
I want to make this an array so that i can run mysqlquery as well.
If you want to get a matrix of characters, split by newline first:
<?php
$str = "A B\tC\nD E\tF";
$parts = preg_split("/\n+/", $str);
foreach($parts as $key => $line)
{
$parts[$key] = preg_split("/\s+/", $line);
}
//output
$n = count($parts);
for ($i = 0; $i < $n; ++$i)
{
$m = count($parts[$i]);
for ($j = 0; $j < $m; ++$j)
{
print $parts[$i][$j]." ";
}
print "\n";
}
Output:
A B C
D E F

Trying to display a random generated string on my page

I'm trying to display a random generated string on my page (php), but I have absolutely no idea how to do this.
I only want the following letters and digits to be used:
B C D F G H J K M P Q R T V W X Y Z 2 3 4 6 7 8 9
In the following format:
XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
Can anyone help me out, and give me a script which I can put on my page? Help would be really appreciated!
I tried this but it's not even displaying on my page for some odd reason.
$tokens = 'BCDFGHJKMPQRTVWXYZ2346789';
$serial = '';
for ($i = 0; $i < 5; $i++) {
for ($j = 0; $j < 5; $j++) {
$serial .= $tokens[rand(0, 35)];
}
if ($i < 3) {
$serial .= '-';
}
}
echo $serial;
You were almost there. Here's a few fixes to your code;
<?php
$tokens = 'BCDFGHJKMPQRTVWXYZ2346789';
$serial = '';
for ($i = 0; $i < 5; $i++) {
for ($j = 0; $j < 5; $j++) {
$serial .= $tokens[rand(0, strlen($tokens) - 1)];
}
if ($i < 4) {
$serial .= '-';
}
}
echo $serial;
?>
I can't say for sure why your page isn't showing, but in your original code you were missing <?php at the top of the page.
Edit: Here's a quick explanation of some of the changes I made to your code.
Your code had rand(0, 35). But since you may change the characters in $tokens in the future, it's better to simply calculate the length of the $tokens using strlen($tokens) - 1 (the -1 being important because strlen() starts counting at 1, whereas $tokens[INDEX] starts counting at 0).
Your code had if ($i < 3), but you actually want four dashes, so I changed it to if ($i < 4).
<?php
$charsPerGroup = 5;
$groups = 5;
$groupDelimiter = '-';
$tokens = explode(' ', 'B C D F G H J K M P Q R T V W X Y Z 2 3 4 6 7 8 9'); // from your question, format this however you want
$tokens = array_flip($tokens);
$resultArray = array();
for($i=0;$i<$groups;$i++) {
$resultArray[] = join(array_rand($tokens, $charsPerGroup));
}
echo join($groupDelimiter, $resultArray);
<?php
$enters = explode(' ', "B C D F G H J K M P Q R T V W X Y Z 2 3 4 6 7 8 9");
$entry = rand(0,count($enters)-1);
echo $enters[$entry];
$output = "";
for($i=1; $i++; $i<=25) {
$entry = rand(0,count($enters)-1);
$output .= $enters[$entry] . ($i % 5 == 0 && $i < 25 ? '-' : '' );
}
echo $output;
?>

How to find contiguous words in array

ok, this is driving me insane, the solution must be easy but I've hit the proverbial wall,
here it is:
suppose I have this Array: a, b, c, d
I want to find all the contiguous letters in the array without mixing them, such as:
a b c d
a b c
a b
b c d
b c
c d
I've done many tests, but for some reason I just can't get it right. Any hint would be greatly appreciated.
$arr = Array('a', 'b', 'c', 'd');
for ($i = 0; $i < count($arr); $i++) {
$s = '';
for ($j = $i; $j < count($arr); $j++) {
$s = $s . $arr[$j];
if (strlen($s) > 1) {
echo $s.' ';
}
}
}
OUTPUT:
ab abc abcd bc bcd cd

How to echo lines of text vertically in PHP?

I got this problem somewhere, and I want to know how to solve this using PHP. Given this text:
$str = '
PHP is a
widely-used
general-purpose
server side
scripting
language
';
How to echo the text vertically like the given below:
g
e
n
e
w r s
i a e
d l r s
P e - v c l
H l p e r a
P y u r i n
- r p g
i u p s t u
s s o i i a
e s d n g
a d e e g e
I will select the simpler and more elegant code as the answer.
As others have already demonstrated, array_map is able to do the flip over which is basically the main problem you need to solve. The rest is how you arrange the code. I think your version is very good because it's easy to understand.
If you're looking more to some other extreme, handle with care:
$str = 'PHP is a
widely-used
general-purpose
server side
scripting
language';
$eol = "\n";
$turned = function($str) use ($eol) {
$length = max(
    array_map(
        'strlen',
        $lines = explode($eol, trim($str))
    )
);
$each = function($a, $s) use ($length) {
    $a[] = str_split(
        sprintf("%' {$length}s", $s)
    );
    return $a;
};
return implode(
    $eol,
    array_map(
        function($v) {
            return implode(' ', $v);
        },
        call_user_func_array(
            'array_map',
            array_reduce($lines, $each, array(NULL))
        )
    )
);
};
echo $turned($str), $eol;
Gives you:
g
e
n
e
w r s
i a e
d l r s
P e - v c l
H l p e r a
P y u r i n
- r p g
i u p s t u
s s o i i a
e s d n g
a d e e g e
This fixes the output of the other answer, which was incorrect (now fixed).
The code below will print $str vertically.
$lines = preg_split("/\r\n/", trim($str));
$nl = count($lines);
$len = max(array_map('strlen', $lines));
foreach ($lines as $k => $line) {
$lines[$k] = str_pad($line, $len, ' ', STR_PAD_LEFT);
}
for ($i = 0; $i < $len; $i++) {
for ($j = 0; $j < $nl; $j++) {
echo $lines[$j][$i].($j == $nl-1 ? "\n" : " ");
}
}
I took some of the code from #bsdnoobz and simplified it. I'm using \n as a line break because I work on a Mac and \r\n doean work here.
$lines = preg_split("/\n/", trim($str));
$len = max(array_map('strlen', $lines));
$rows = array_fill(0,$len,'');
foreach ($lines as $k => $line) {
foreach (str_split(str_pad($line, $len, ' ', STR_PAD_LEFT)) as $row => $char){
$rows[$row] .= $char;
}
}
echo implode("\n",$rows)."\n";
$a = explode(PHP_EOL, trim($str));
$h = max(array_map('strlen', $a));
$w = count($a);
$m = array_map('str_split', array_map('sprintf', array_fill(0, $w, "%{$h}s"), $a));
$t = call_user_func_array('array_map', array_merge(array(null), $m));
echo implode(PHP_EOL, array_map('implode', array_fill(0, $h, ' '), $t)), PHP_EOL;
PHP_EOL should be replaced with "\n", "\r\n" or '<br/>' where appropriate. The whole code after the first line could easily become one big expression, only its readability would suffer a little bit ;-)
$a is the array of lines, $h is the final height, $w is the final width, $m is the matrix of characters (after padding the strings), $t is the transposed matrix.
The array_fill(0, $h, ' '), on the last line can simply be omitted if the space between columns is not needed. On the other hand, not printing trailing space characters can be achieved like this:
echo implode(PHP_EOL, array_map('rtrim', array_map('implode', array_fill(0, $h, ' '), $t))), PHP_EOL;
I have taken the question as an excercise in avoiding explicit loops (which are usually more expensive than loops inside PHP functions, although in this case the advantage could be lost). The important trick here is the matrix transposition, which I have taken from this answer by Codler
Anyhow, the complexity of the whole algorithm is O(width × height), just like the one of most algorithms on this page, except for those that repeatedly concatenate strings in order to obtain the lines, whose complexity is O(width² × height)
I'll give this a shot:
$arrlines = explode(PHP_EOL, trim($str));
$max = max(array_map('strlen', $arrlines));
foreach($arrlines as $val)
$arrlines = str_pad($val,$max," ",STR_PAD_LEFT);
for($x=0;$x<$max;$x++){
for($y=0;$y<count($arrlines);$y++)
$string .= strlen(trim($arrlines[$y][$x])) > 0 ? $arrlines[$y][$x]." ":" ";
$string .= "\n";
}
echo '<pre>'.$string.'</pre>';
Line numbers:
save the string per line in an array $arrlines separated by the PHP constant PHP_EOL
get the maximum string length and save it to $max
loop for every element of $arrlines, then
add padding to the left of the string to make its string length equal to $max
for lines 5-9, nested loop to save the $arrline[$y][$x] to $string, and line 10 outputs the result.
Result can be found here.
Here is simple code any one can understand this code
$str = '
PHP is a
widely-used
general-purpose
server side
scripting
language
';
$lines = array();
$sentences = explode("\n\n",$str);
foreach($sentences as $sentence){
if($sentence != ""){
$each_lines = explode("\n",$sentence);
foreach($each_lines as $each_line){
if($each_line != ""){
$lines[] = $each_line;
}
}
$lines[] = "\t";
}
}
$before_sort = $lines;
usort($lines, "cmp_len");
$big_length = strlen($lines[0]);
foreach($before_sort as $key=>$arr){
$this_length = strlen($arr);
if($this_length < $big_length){
$no_of_letters = $big_length - $this_length;
$text = "";
for($i=0;$i<$no_of_letters;$i++){
$text .= " ";
}
$text .= $before_sort[$key];
$before_sort[$key] = $text;
}
}
$temp = array();
echo "<table>";
for($i=0;$i<$big_length;$i++){
echo "<tr>";
foreach($before_sort as $arr){
echo "<td>";
echo str_replace("\t"," ",$arr[$i]);
echo "</td>";
}
echo "</tr>";
}
echo "</table>";
function cmp_len($a, $b){
return (strlen($a) < strlen($b));
}
Check this answer:
<?php
$str = 'PHP is a
widely-used
general-purpose
server side
scripting
language';
function getVerticalString($str){
$str = preg_split('/\r|\n/',$str);
$maxlength = 0;
$totalstr = count($str);
for($i=0;$i<$totalstr;$i++){
if($maxlength<strlen($str[$i])){
$maxlength = strlen($str[$i]);
}
}
$strings = array();
for($i=0;$i<$maxlength;$i++){
$strings[$i] = "";
for($j=0;$j<$totalstr;$j++){
$temp = strlen($str[$j])-($maxlength-$i);
if($temp>=0){
$strings[$i] .= substr($str[$j],$temp,1);
}
else{
$strings[$i] .= " ";
}
}
}
return implode("\r",$strings);
}
echo "<pre>".getVerticalString($str)."</pre>";
this outputs:
g
e
n
e
w rs
i ae
d lr s
Pe -v cl
Hl pe ra
Py ur in
- r pg
iu ps tu
ss oi ia
e sd ng
ad ee ge
As per your requirements. :)
I wouldn't really call it shorter, but line count is less ;-)
$nr_lines = count($lines = preg_split('/\r?\n/', trim($str)));
$maxlen = max($lengths = array_map('strlen', $lines)); // get line lengthts and maximum
$line_ptrs = array_fill(0, $nr_lines, 0); // last character position per line
for ($j = 0; $j != $maxlen; ++$j) {
for ($i = 0; $i != $nr_lines; ++$i) {
// $maxlen - $lengths[$i] indicates where printing start for this line
echo $j >= $maxlen - $lengths[$i] ? $lines[$i][$line_ptrs[$i]++] : ' ';
}
echo "\n";
}
It does the padding and printing in the same inner loop, aided by the $line_ptrs and $lengths array to keep track of which character to print next.
Benchmark
Based on 10,000 iterations, this code performs 19% better than the first answer.
Please note that the length of a string and the number of elements in an array are cached by PHP per variable. Calling strlen or count repeatedly has only the performance penalty of an empty function call (on subsequent calls, the length or count are not measured twice internally by PHP).
This works with a Mac (\r), Linux (\n) or Windows (\r\n) input string, and/or with an empty input string, and/or with a one line input string, and outputs with a prefered line delimiter (default is PHP_EOL):
function matrix_vertical_align_bottom($str, $strEOL=PHP_EOL)
{
$arrLines=explode("\n", $str);
$nMaxLength=max(array_map("strlen", $arrLines));
$nRotatedWidth=count($arrLines)+strlen($strEOL);
//allocate once
$strRotated=str_pad(
"",
$nRotatedWidth*$nMaxLength-strlen($strEOL),
str_repeat(" ", count($arrLines)).$strEOL
);
foreach($arrLines as $nRotatedColumnIndex=>$strLine)
{
$nRotatedVerticalPadding=$nMaxLength-strlen($strLine);
for($nColumnIndex=strlen($strLine)-1; $nColumnIndex>=0; $nColumnIndex--)
$strRotated[$nRotatedWidth*($nColumnIndex+$nRotatedVerticalPadding)+$nRotatedColumnIndex]=$strLine[$nColumnIndex];
}
return $strRotated;
}
echo matrix_vertical_align_bottom(preg_replace("/(\r\n|\r|\n)/", "\n", trim($str)));
The performance is pretty good, the above algorithm is just translating coordinates while rotating the string by 90 degrees. There is no memory re-allocation because of string expanding provoked by padding individual lines (for input strings with lots of lines, this would be a performance hit).
HTML output is not assumed, nl2br(htmlspecialchars( )) when outputting should do the trick + a mono spaced font.
It's like the old saying goes:
If it can be done without regex, try it anyway.
Some people, when confronted with a problem, think
“I know, I'll use regular expressions.” Now they have zero problems.
"I took the [road] less traveled by" - Robert Frost
With so many similar techniques on this page, I thought I'd offer a fresh perspective. Here is a technique by which the input string is consumed within a loop and the last character (if it exists) of each line is added to the output array as a space-delimited string. The loop is broken when the entire input string consists of whitespace characters. I did not benchmark it, but I would be curious to hear any comparisons if anyone is inclined to provide their findings.
Code: (Demo)
$result = [];
while (!ctype_space($string)) {
$line = [];
$string = preg_replace_callback(
"~.$|^$~m",
function($m) use(&$line) {
$line[] = $m[0] === '' ? ' ' : $m[0];
return '';
},
$string,
);
array_unshift($result, implode(' ', $line));
}
echo implode("\n", $result);
My function to rotate text without any language construct loops:
/**
* Rotates text
*
* #param string $str String to rotate
*
* #return string Rotated string
*/
function rotateText($str)
{
$lines = explode(PHP_EOL, $str);
$lengths = array_map('strlen', $lines);
$maxLength = max($lengths);
$lines = array_map(function ($line) use ($maxLength) {
return str_pad($line, $maxLength, ' ', STR_PAD_LEFT);
}, $lines);
$chars = array_map('str_split', $lines);
array_unshift($chars, null);
$rotatedLines = call_user_func_array('array_map', $chars);
$rotatedText = join(PHP_EOL, array_map('join', $rotatedLines));
return $rotatedText;
}
echo "<pre>", rotateText($str), "</pre>";
Here's my shot at it. Couldn't figure out how to do it without the nested loop.
$lines = array_map('strrev', explode("\r\n", trim($str)));
$new = array();
foreach(range(0, max(array_map('strlen', $lines))) as $i){
foreach($lines as $line){
$new[$i] .= (!empty($line[$i]) ? $line[$i] . ' ' : ' ');
}
}
echo implode("\r\n", (array_slice(array_reverse($new), 1)));
Try this one,
$str = 'PHP is a
widely-used
general-purpose
server side
scripting
language';
$strArr = explode("\r\n", $str);
$max =max(array_map('strlen', $strArr));
for($i=0; $i< $max;$i++)
{
for($x=0;$x < count($strArr); $x++)
{
$strVal = $strArr[$x];
$y = $i -($max - strlen($strVal));
$vertical .= strlen(trim($strVal[$y]))<> 0 ? $strVal[$y]." " : " ";
}
$vertical .="\n";
}
echo "<pre>".$vertical;
The best and simplest way :)
<style type="text/css">
#heading{
/* vertical text css */
width:1em;
text-transform:uppercase;
}
</style>
<h1 align="center" id="heading">h e l l o</h1>
DEMO
$a= 'HelloWorld!';
$b=strlen($a);
for($i=0;$i<$b;$i++){
echo $c=substr($a,$i,1).'<br>';
}

How to produce approximate fraction numbers from irrational number on MatLab?

I have a clumsy PHP code that I've used to get approximate fraction numbers for irrational numbers like pi, phi, square root of 2, 3 and so on. I'd like to get a formula that I can use on MatLab and get both data table and draw a plot based on approximate fraction numbers. Maybe someone already can grab from this but I'll provide PHP code to complement the case:
$n = phi(); # irrational number (imaginary/complex number?)
$x = 500; # how many numbers to check
$max = 50; # how many instances to show
$precision = 0.0001;
# check every i against every j and make a comparison how near their values are to each other
for ($i=1; $i<$x; $i++) {
for ($j=1; $j<$x; $j++) {
# compared value is stored on array. very distant numbers needs to be discarded ($precision) or array gets easily too big, limit 64k
if (($d = abs(($n - ($i/$j)))) && $d > $precision) continue;
$c[] = array($i, $j, $d);
}
}
# sort comparison chart by third index (2)
array_qsort($c, 2);
# print max best values from the sorted comparison chart
$count = count($c);
echo "closest fraction numbers for $n from $count calculated values are:<br />\n<br />\n";
$r = 0;
foreach ($c as $abc) {
$r++;
$d = $abc[0]/$abc[1];
echo $abc[0] . '/' . $abc[1] . ' = ' . $d . ' (' . round($abc[2]*(1/$precision), 10) . ')' . "<br />\n";
if ($r > $max) break;
}
There are more efficient algorithms, here is one:
function [a, b, c] = approxfrac( r, precision )
a = floor(r);
r = r - a;
if r==0,
b=0;
c=1;
return
end
p1 = 0; q1 = 1;
p2 = 1; q2 = 1;
b = p1+p2;
c = q1+q2;
while abs(r-b/c) > precision,
if r>b/c,
p1 = b; q1 = c;
else
p2 = b; q2 = c;
end
b = p1+p2;
c = q1+q2;
end
end
There's a function for that: rat

Categories